void VDAgent::on_clipboard_grab() { uint32_t types[clipboard_formats_count * VD_CLIPBOARD_FORMAT_MAX_TYPES]; int count = 0; if (!VD_AGENT_HAS_CAPABILITY(_client_caps, _client_caps_size, VD_AGENT_CAP_CLIPBOARD_BY_DEMAND)) { return; } if (CountClipboardFormats() == 0) { return; } for (unsigned int i = 0; i < clipboard_formats_count; i++) { if (IsClipboardFormatAvailable(clipboard_formats[i].format)) { for (uint32_t* ptype = clipboard_formats[i].types; *ptype; ptype++) { types[count++] = *ptype; } } } if (count) { write_message(VD_AGENT_CLIPBOARD_GRAB, count * sizeof(types[0]), types); set_clipboard_owner(owner_guest); } else { UINT format = 0; while ((format = EnumClipboardFormats(format))) { vd_printf("Unsupported clipboard format %u", format); } } }
void RedClient::send_agent_clipboard_notify_message(uint32_t type, uint8_t *data, uint32_t size) { ASSERT(data || !size); if (!_agent_connected) { return; } if (!VD_AGENT_HAS_CAPABILITY(_agent_caps, _agent_caps_size, VD_AGENT_CAP_CLIPBOARD_BY_DEMAND)) return; if (_agent_out_msg) { 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]; _agent_out_msg->protocol = VD_AGENT_PROTOCOL; _agent_out_msg->type = VD_AGENT_CLIPBOARD; _agent_out_msg->opaque = 0; _agent_out_msg->size = sizeof(VDAgentClipboard) + size; VDAgentClipboard* clipboard = (VDAgentClipboard*)_agent_out_msg->data; clipboard->type = type; memcpy(clipboard->data, data, size); if (_agent_tokens) { do_send_agent_clipboard(); } }
void RedClient::on_agent_announce_capabilities( VDAgentAnnounceCapabilities* caps, uint32_t msg_size) { uint32_t caps_size = VD_AGENT_CAPS_SIZE_FROM_MSG_SIZE(msg_size); if (_agent_caps_size != caps_size) { delete[] _agent_caps; _agent_caps = new uint32_t[caps_size]; ASSERT(_agent_caps != NULL); _agent_caps_size = caps_size; } memcpy(_agent_caps, caps->caps, sizeof(_agent_caps[0]) * caps_size); if (caps->request) { send_agent_announce_capabilities(false); } if (VD_AGENT_HAS_CAPABILITY(caps->caps, caps_size, VD_AGENT_CAP_DISPLAY_CONFIG) && !_agent_disp_config_sent) { // not sending the color depth through send_agent_monitors_config, since // it applies only for attached screens. send_agent_display_config(); } else if (!_auto_display_res) { /* some agents don't support monitors/displays agent messages, so * we'll never reach on_agent_reply which sends this * ATTACH_CHANNELS message which is needed for client startup to go * on. */ if (!_display_setting.is_empty()) { LOG_WARN("display options have been requested, but the agent doesn't support these options"); } send_main_attach_channels(); _application.deactivate_interval_timer(*_agent_timer); } }
void VDAgent::on_clipboard_release() { if (!VD_AGENT_HAS_CAPABILITY(_client_caps, _client_caps_size, VD_AGENT_CAP_CLIPBOARD_BY_DEMAND)) { return; } if (_clipboard_owner == owner_guest) { write_message(VD_AGENT_CLIPBOARD_RELEASE, 0, NULL); } }
static void do_client_clipboard(struct vdagent_virtio_port *vport, VDAgentMessage *message_header, uint8_t *data) { uint32_t msg_type = 0, data_type = 0, size = message_header->size; uint8_t selection = VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD; if (!active_session_conn) { syslog(LOG_WARNING, "Could not find an agent connection belonging to the " "active session, ignoring client clipboard request"); return; } if (VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size, VD_AGENT_CAP_CLIPBOARD_SELECTION)) { selection = data[0]; data += 4; size -= 4; } switch (message_header->type) { case VD_AGENT_CLIPBOARD_GRAB: msg_type = VDAGENTD_CLIPBOARD_GRAB; agent_owns_clipboard[selection] = 0; break; case VD_AGENT_CLIPBOARD_REQUEST: { VDAgentClipboardRequest *req = (VDAgentClipboardRequest *)data; msg_type = VDAGENTD_CLIPBOARD_REQUEST; data_type = req->type; data = NULL; size = 0; break; } case VD_AGENT_CLIPBOARD: { VDAgentClipboard *clipboard = (VDAgentClipboard *)data; msg_type = VDAGENTD_CLIPBOARD_DATA; data_type = clipboard->type; size = size - sizeof(VDAgentClipboard); data = clipboard->data; break; } case VD_AGENT_CLIPBOARD_RELEASE: msg_type = VDAGENTD_CLIPBOARD_RELEASE; data = NULL; size = 0; break; } udscs_write(active_session_conn, msg_type, selection, data_type, data, size); }
void RedClient::send_agent_clipboard_message(uint32_t message_type, uint32_t size, void* data) { if (!_agent_connected) return; if (!VD_AGENT_HAS_CAPABILITY(_agent_caps, _agent_caps_size, VD_AGENT_CAP_CLIPBOARD_BY_DEMAND)) return; Message* message = new Message(SPICE_MSGC_MAIN_AGENT_DATA); VDAgentMessage* msg = (VDAgentMessage*) spice_marshaller_reserve_space(message->marshaller(), sizeof(VDAgentMessage) + size); msg->protocol = VD_AGENT_PROTOCOL; msg->type = message_type; msg->opaque = 0; msg->size = size; if (size && data) { memcpy(msg->data, data, size); } ASSERT(_agent_tokens) _agent_tokens--; post_message(message); }
// In delayed rendering, Windows requires us to SetClipboardData before we return from // handling WM_RENDERFORMAT. Therefore, we try our best by sending CLIPBOARD_REQUEST to the // agent, while waiting alertably for a while (hoping for good) for receiving CLIPBOARD data // or CLIPBOARD_RELEASE from the agent, which both will signal clipboard_event. // In case of unsupported format, wrong clipboard owner or no clipboard capability, we do nothing in // WM_RENDERFORMAT and return immediately. // FIXME: need to be handled using request queue void VDAgent::on_clipboard_request(UINT format) { uint32_t type; if (_clipboard_owner != owner_client) { vd_printf("Received render request event for format %u" "while clipboard is not owned by client", format); return; } if (!(type = get_clipboard_type(format))) { vd_printf("Unsupported clipboard format %u", format); return; } if (!VD_AGENT_HAS_CAPABILITY(_client_caps, _client_caps_size, VD_AGENT_CAP_CLIPBOARD_BY_DEMAND)) { return; } VDAgentClipboardRequest request = {type}; if (!write_message(VD_AGENT_CLIPBOARD_REQUEST, sizeof(request), &request)) { return; } _clipboard_tick = GetTickCount(); while (_running && _clipboard_tick && GetTickCount() < _clipboard_tick + VD_CLIPBOARD_TIMEOUT_MS) { event_dispatcher(VD_CLIPBOARD_TIMEOUT_MS, 0); } if (_clipboard_tick) { vd_printf("Clipboard wait timeout"); _clipboard_tick = 0; } else { // reset incoming message state only upon completion (even after timeout) cleanup_in_msg(); } }