mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/spice
synced 2026-01-11 16:55:33 +00:00
Keep track of clipboard ownership
Given that all clipboard handling is async, it is possible to for example receive a request for clipboard data from the agent while the client no longer owns the clipboard (ie a VD_AGENT_CLIPBOARD_RELEASE message is in transit to the agent). Thus it is necessary to keep track of our notion of clipboard ownership and check received clipboard messages (both from other apps on the client machine and from the agent) to see if they match our notion and if not drop, or in case were a counter message is expected nack the clipboard message.
This commit is contained in:
parent
deb849dfd5
commit
8a160078d0
@ -125,6 +125,14 @@ public:
|
||||
static bool on_clipboard_notify(uint32_t type, const uint8_t* data, int32_t size);
|
||||
static bool on_clipboard_request(uint32_t type);
|
||||
static void on_clipboard_release();
|
||||
|
||||
enum { owner_none, owner_guest, owner_client };
|
||||
|
||||
static void set_clipboard_owner(int new_owner);
|
||||
static int get_clipboard_owner() { return _clipboard_owner; }
|
||||
|
||||
private:
|
||||
static int _clipboard_owner;
|
||||
};
|
||||
|
||||
class Platform::EventListener {
|
||||
@ -141,6 +149,7 @@ public:
|
||||
virtual void on_clipboard_grab(uint32_t *types, uint32_t type_count) = 0;
|
||||
virtual void on_clipboard_request(uint32_t type) = 0;
|
||||
virtual void on_clipboard_notify(uint32_t type, uint8_t* data, int32_t size) = 0;
|
||||
virtual void on_clipboard_release() = 0;
|
||||
};
|
||||
|
||||
class Platform::RecordClient {
|
||||
|
||||
@ -85,10 +85,17 @@ void ClipboardGrabEvent::response(AbstractProcessLoop& events_loop)
|
||||
{
|
||||
static_cast<RedClient*>(events_loop.get_owner())->send_agent_clipboard_message(
|
||||
VD_AGENT_CLIPBOARD_GRAB, _type_count * sizeof(uint32_t), _types);
|
||||
Platform::set_clipboard_owner(Platform::owner_client);
|
||||
}
|
||||
|
||||
void ClipboardRequestEvent::response(AbstractProcessLoop& events_loop)
|
||||
{
|
||||
if (Platform::get_clipboard_owner() != Platform::owner_guest) {
|
||||
LOG_WARN("received clipboard req from client while clipboard is not owned by guest");
|
||||
Platform::on_clipboard_notify(VD_AGENT_CLIPBOARD_NONE, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
VDAgentClipboardRequest request = {_type};
|
||||
static_cast<RedClient*>(events_loop.get_owner())->send_agent_clipboard_message(
|
||||
VD_AGENT_CLIPBOARD_REQUEST, sizeof(request), &request);
|
||||
@ -865,6 +872,11 @@ void RedClient::on_clipboard_notify(uint32_t type, uint8_t* data, int32_t size)
|
||||
DBG(0, "clipboard change is already pending");
|
||||
return;
|
||||
}
|
||||
if (Platform::get_clipboard_owner() != Platform::owner_client) {
|
||||
LOG_WARN("received clipboard data from client while clipboard is not owned by client");
|
||||
type = VD_AGENT_CLIPBOARD_NONE;
|
||||
size = 0;
|
||||
}
|
||||
_agent_out_msg_pos = 0;
|
||||
_agent_out_msg_size = sizeof(VDAgentMessage) + sizeof(VDAgentClipboard) + size;
|
||||
_agent_out_msg = (VDAgentMessage*)new uint8_t[_agent_out_msg_size];
|
||||
@ -880,6 +892,12 @@ void RedClient::on_clipboard_notify(uint32_t type, uint8_t* data, int32_t size)
|
||||
}
|
||||
}
|
||||
|
||||
void RedClient::on_clipboard_release()
|
||||
{
|
||||
if (Platform::get_clipboard_owner() == Platform::owner_client)
|
||||
send_agent_clipboard_message(VD_AGENT_CLIPBOARD_RELEASE, 0, NULL);
|
||||
}
|
||||
|
||||
void RedClient::set_mouse_mode(uint32_t supported_modes, uint32_t current_mode)
|
||||
{
|
||||
if (current_mode != _mouse_mode) {
|
||||
@ -1086,6 +1104,12 @@ void RedClient::dispatch_agent_message(VDAgentMessage* msg, void* data)
|
||||
break;
|
||||
}
|
||||
case VD_AGENT_CLIPBOARD: {
|
||||
if (Platform::get_clipboard_owner() != Platform::owner_guest) {
|
||||
LOG_WARN("received clipboard data from guest while clipboard is not owned by guest");
|
||||
Platform::on_clipboard_notify(VD_AGENT_CLIPBOARD_NONE, NULL, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
VDAgentClipboard* clipboard = (VDAgentClipboard*)data;
|
||||
Platform::on_clipboard_notify(clipboard->type, clipboard->data,
|
||||
msg->size - sizeof(VDAgentClipboard));
|
||||
@ -1094,14 +1118,27 @@ void RedClient::dispatch_agent_message(VDAgentMessage* msg, void* data)
|
||||
case VD_AGENT_CLIPBOARD_GRAB:
|
||||
Platform::on_clipboard_grab((uint32_t *)data,
|
||||
msg->size / sizeof(uint32_t));
|
||||
Platform::set_clipboard_owner(Platform::owner_guest);
|
||||
break;
|
||||
case VD_AGENT_CLIPBOARD_REQUEST:
|
||||
if (Platform::get_clipboard_owner() != Platform::owner_client) {
|
||||
LOG_WARN("received clipboard req from guest while clipboard is not owned by client");
|
||||
on_clipboard_notify(VD_AGENT_CLIPBOARD_NONE, NULL, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!Platform::on_clipboard_request(((VDAgentClipboardRequest*)data)->type)) {
|
||||
on_clipboard_notify(VD_AGENT_CLIPBOARD_NONE, NULL, 0);
|
||||
}
|
||||
break;
|
||||
case VD_AGENT_CLIPBOARD_RELEASE:
|
||||
if (Platform::get_clipboard_owner() != Platform::owner_guest) {
|
||||
LOG_WARN("received clipboard release from guest while clipboard is not owned by guest");
|
||||
break;
|
||||
}
|
||||
|
||||
Platform::on_clipboard_release();
|
||||
Platform::set_clipboard_owner(Platform::owner_none);
|
||||
break;
|
||||
default:
|
||||
DBG(0, "Unsupported message type %u size %u", msg->type, msg->size);
|
||||
|
||||
@ -221,6 +221,7 @@ public:
|
||||
void on_clipboard_grab(uint32_t *types, uint32_t type_count);
|
||||
void on_clipboard_request(uint32_t type);
|
||||
void on_clipboard_notify(uint32_t type, uint8_t* data, int32_t size);
|
||||
void on_clipboard_release();
|
||||
|
||||
void for_each_channel(ForEachChannelFunc& func);
|
||||
void on_mouse_capture_trigger(RedScreen& screen);
|
||||
|
||||
@ -54,6 +54,7 @@ public:
|
||||
virtual void on_clipboard_grab(uint32_t *types, uint32_t type_count) {}
|
||||
virtual void on_clipboard_request(uint32_t type) {}
|
||||
virtual void on_clipboard_notify(uint32_t type, uint8_t* data, int32_t size) {}
|
||||
virtual void on_clipboard_release() {}
|
||||
};
|
||||
|
||||
static DefaultClipboardListener default_clipboard_listener;
|
||||
@ -856,6 +857,18 @@ void WinPlatform::exit_modal_loop()
|
||||
modal_loop_active = false;
|
||||
}
|
||||
|
||||
int Platform::_clipboard_owner = Platform::owner_none;
|
||||
|
||||
void Platform::set_clipboard_owner(int new_owner)
|
||||
{
|
||||
if (new_owner == owner_none) {
|
||||
clipboard_listener->on_clipboard_release();
|
||||
|
||||
/* FIXME clear cached clipboard type info and data */
|
||||
}
|
||||
_clipboard_owner = new_owner;
|
||||
}
|
||||
|
||||
bool Platform::on_clipboard_grab(uint32_t *types, uint32_t type_count)
|
||||
{
|
||||
/* FIXME use all types rather then just the first one */
|
||||
|
||||
@ -154,6 +154,7 @@ public:
|
||||
void on_clipboard_grab(uint32_t *types, uint32_t type_count) {}
|
||||
void on_clipboard_request(uint32_t type) {}
|
||||
void on_clipboard_notify(uint32_t type, uint8_t* data, int32_t size) {}
|
||||
void on_clipboard_release() {}
|
||||
};
|
||||
|
||||
static DefaultClipboardListener default_clipboard_listener;
|
||||
@ -3161,6 +3162,18 @@ bool Platform::on_clipboard_grab(uint32_t *types, uint32_t type_count)
|
||||
return true;
|
||||
}
|
||||
|
||||
int Platform::_clipboard_owner = Platform::owner_none;
|
||||
|
||||
void Platform::set_clipboard_owner(int new_owner)
|
||||
{
|
||||
if (new_owner == owner_none) {
|
||||
clipboard_listener->on_clipboard_release();
|
||||
|
||||
/* FIXME clear cached clipboard type info and data */
|
||||
}
|
||||
_clipboard_owner = new_owner;
|
||||
}
|
||||
|
||||
void Platform::set_clipboard_listener(ClipboardListener* listener)
|
||||
{
|
||||
clipboard_listener = listener ? listener : &default_clipboard_listener;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user