1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 00:27:45 +00:00

WindowServer+LibGUI: Store a "data type" with the clipboard content

This will allow us to distinguish between different types of data
stored on the clipboard.
This commit is contained in:
Andreas Kling 2019-09-14 09:19:05 +02:00
parent 9d2c4d223a
commit c543ee5c5b
10 changed files with 94 additions and 15 deletions

View file

@ -112,6 +112,7 @@ struct WSAPI_ServerMessage {
DidSetResolution,
DidSetWindowHasAlphaChannel,
ScreenRectChanged,
ClipboardContentsChanged,
__Begin_WM_Events__,
WM_WindowRemoved,

View file

@ -87,6 +87,19 @@ void WSClientConnection::notify_about_new_screen_rect(const Rect& rect)
post_message(message);
}
void WSClientConnection::notify_about_clipboard_contents_changed()
{
auto& clipboard = WSClipboard::the();
WSAPI_ServerMessage message;
message.type = WSAPI_ServerMessage::Type::ClipboardContentsChanged;
message.clipboard.shared_buffer_id = -1;
message.clipboard.contents_size = -1;
ASSERT(clipboard.data_type().length() < (ssize_t)sizeof(message.text));
strcpy(message.text, clipboard.data_type().characters());
message.text_length = clipboard.data_type().length();
post_message(message);
}
void WSClientConnection::event(CEvent& event)
{
if (static_cast<WSEvent&>(event).is_client_request()) {
@ -247,7 +260,11 @@ bool WSClientConnection::handle_message(const WSAPI_ClientMessage& message, cons
CEventLoop::current().post_event(*this, make<WSAPIGetWindowRectRequest>(client_id(), message.window_id));
break;
case WSAPI_ClientMessage::Type::SetClipboardContents:
CEventLoop::current().post_event(*this, make<WSAPISetClipboardContentsRequest>(client_id(), message.clipboard.shared_buffer_id, message.clipboard.contents_size));
if (message.text_length > (int)sizeof(message.text)) {
did_misbehave();
return false;
}
CEventLoop::current().post_event(*this, make<WSAPISetClipboardContentsRequest>(client_id(), message.clipboard.shared_buffer_id, message.clipboard.contents_size, String(message.text, message.text_length)));
break;
case WSAPI_ClientMessage::Type::GetClipboardContents:
CEventLoop::current().post_event(*this, make<WSAPIGetClipboardContentsRequest>(client_id()));
@ -661,7 +678,7 @@ void WSClientConnection::handle_request(const WSAPISetClipboardContentsRequest&
post_error("WSAPISetClipboardContentsRequest: Bad shared buffer ID");
return;
}
WSClipboard::the().set_data(*shared_buffer, request.size());
WSClipboard::the().set_data(*shared_buffer, request.size(), request.data_type());
WSAPI_ServerMessage response;
response.type = WSAPI_ServerMessage::Type::DidSetClipboardContents;
response.clipboard.shared_buffer_id = shared_buffer->shared_buffer_id();
@ -670,26 +687,31 @@ void WSClientConnection::handle_request(const WSAPISetClipboardContentsRequest&
void WSClientConnection::handle_request(const WSAPIGetClipboardContentsRequest&)
{
auto& clipboard = WSClipboard::the();
WSAPI_ServerMessage response;
response.type = WSAPI_ServerMessage::Type::DidGetClipboardContents;
response.clipboard.shared_buffer_id = -1;
response.clipboard.contents_size = 0;
if (WSClipboard::the().size()) {
if (clipboard.size()) {
// FIXME: Optimize case where an app is copy/pasting within itself.
// We can just reuse the SharedBuffer then, since it will have the same peer PID.
// It would be even nicer if a SharedBuffer could have an arbitrary number of clients..
RefPtr<SharedBuffer> shared_buffer = SharedBuffer::create_with_size(WSClipboard::the().size());
RefPtr<SharedBuffer> shared_buffer = SharedBuffer::create_with_size(clipboard.size());
ASSERT(shared_buffer);
memcpy(shared_buffer->data(), WSClipboard::the().data(), WSClipboard::the().size());
memcpy(shared_buffer->data(), clipboard.data(), clipboard.size());
shared_buffer->seal();
shared_buffer->share_with(client_pid());
response.clipboard.shared_buffer_id = shared_buffer->shared_buffer_id();
response.clipboard.contents_size = WSClipboard::the().size();
response.clipboard.contents_size = clipboard.size();
// FIXME: This is a workaround for the fact that SharedBuffers will go away if neither side is retaining them.
// After we respond to GetClipboardContents, we have to wait for the client to ref the buffer on his side.
m_last_sent_clipboard_content = move(shared_buffer);
}
ASSERT(clipboard.data_type().length() < (ssize_t)sizeof(response.text));
if (!clipboard.data_type().is_null())
strcpy(response.text, clipboard.data_type().characters());
response.text_length = clipboard.data_type().length();
post_message(response);
}

View file

@ -35,6 +35,7 @@ public:
void for_each_window(Callback);
void notify_about_new_screen_rect(const Rect&);
void notify_about_clipboard_contents_changed();
void post_paint_message(WSWindow&);
WSMenu* find_menu_by_id(int menu_id)

View file

@ -36,9 +36,13 @@ void WSClipboard::clear()
m_contents_size = 0;
}
void WSClipboard::set_data(NonnullRefPtr<SharedBuffer>&& data, int contents_size)
void WSClipboard::set_data(NonnullRefPtr<SharedBuffer>&& data, int contents_size, const String& data_type)
{
dbgprintf("WSClipboard::set_data <- %p (%u bytes)\n", data->data(), contents_size);
dbg() << "WSClipboard::set_data <- [" << data_type << "] " << data->data() << " (" << contents_size << " bytes)";
m_shared_buffer = move(data);
m_contents_size = contents_size;
m_data_type = data_type;
if (on_content_change)
on_content_change();
}

View file

@ -1,5 +1,6 @@
#pragma once
#include <AK/Function.h>
#include <AK/String.h>
#include <SharedBuffer.h>
@ -13,15 +14,19 @@ public:
return m_shared_buffer;
}
const String& data_type() const { return m_data_type; }
const u8* data() const;
int size() const;
void clear();
void set_data(NonnullRefPtr<SharedBuffer>&&, int contents_size);
void set_data(NonnullRefPtr<SharedBuffer>&&, int contents_size, const String& data_type);
Function<void()> on_content_change;
private:
WSClipboard();
String m_data_type;
RefPtr<SharedBuffer> m_shared_buffer;
int m_contents_size { 0 };
};

View file

@ -504,19 +504,22 @@ private:
class WSAPISetClipboardContentsRequest final : public WSAPIClientRequest {
public:
explicit WSAPISetClipboardContentsRequest(int client_id, int shared_buffer_id, int size)
explicit WSAPISetClipboardContentsRequest(int client_id, int shared_buffer_id, int size, const String& data_type)
: WSAPIClientRequest(WSEvent::APISetClipboardContentsRequest, client_id)
, m_shared_buffer_id(shared_buffer_id)
, m_size(size)
, m_data_type(data_type)
{
}
int shared_buffer_id() const { return m_shared_buffer_id; }
int size() const { return m_size; }
const String& data_type() const { return m_data_type; }
private:
int m_shared_buffer_id { 0 };
int m_size { 0 };
String m_data_type;
};
class WSAPIGetClipboardContentsRequest final : public WSAPIClientRequest {

View file

@ -1,3 +1,4 @@
#include "WSClipboard.h"
#include <Kernel/KeyCode.h>
#include <Kernel/MousePacket.h>
#include <LibCore/CLocalSocket.h>
@ -47,6 +48,12 @@ WSEventLoop::WSEventLoop()
m_mouse_notifier = make<CNotifier>(m_mouse_fd, CNotifier::Read);
m_mouse_notifier->on_ready_to_read = [this] { drain_mouse(); };
WSClipboard::the().on_content_change = [&] {
WSClientConnection::for_each_client([&](auto& client) {
client.notify_about_clipboard_contents_changed();
});
};
}
WSEventLoop::~WSEventLoop()