-----BEGIN PGP SIGNATURE-----
iQJQBAABCAA6FiEEh6m9kz+HxgbSdvYt2ujhCXWWnOUFAmEuLrccHG1hcmNhbmRy ZS5sdXJlYXVAcmVkaGF0LmNvbQAKCRDa6OEJdZac5cmyD/0ebOdpSFpCqTMDSLzS YGtM00EEUVtzM7SRgXdhqagih1jeukXze3jq7pQDneoOZgFEOU4sbJ5BQ0mPSzQc MgFq36oqnjcXQiCw2bfAUExmPEdL5UsBRzzr91nb0VUF9tfAezYqf8CY8fbgu1bZ cwk9KbrlfwR1trtxvbvhUhVbZfhO+9/gSu8e3WEr3fuSPYsy+nMcf0AG8m6bfVg5 IISchT1OCiJ/9BSRITjLUko5qcyxLBAnnA9qVOMnHXokQzvMaoATOi5vXNtRm/TC yqni2Ls/Oh03oSA33JEnS+vh/wOO+Eruiuxh7k4UzTUt9PBs4J9Z7JPmCQfbL+6+ Fb7VH3KsKhTDHW6U88Ux+pf4tWN8ajZm8JnammWNquiJ8AmvPdJQG+9hXPWGEWNS a9cA302o8/VF4bolboAqEc0ETpwAxhA7uytdgUOXCiCAusEXS+EZg+P4Wc1KBxwq N754+Taw/+0xI1JXnjq1+YF1CFM3rag/rY4PJiqwuBlTHNI9KoIk++7AqS7umGXg 2OaLoWXFtwOLrOqNjtT3LjQBT9PlqoDBrjP8Ntd3x+BhgYTYRh2TxHNusTnfINcZ ave8Zv3ChePt4v4qRXJo3XKBddnHiq3jD37VhOLowtUtjhGd2BFHR29fLZ6f6z3C vVGGT0r4PmLuTNhOkaEdb76qyA== =N/L8 -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/marcandre/tags/clip-pull-request' into staging # gpg: Signature made Tue 31 Aug 2021 14:29:27 BST # gpg: using RSA key 87A9BD933F87C606D276F62DDAE8E10975969CE5 # gpg: issuer "marcandre.lureau@redhat.com" # gpg: Good signature from "Marc-André Lureau <marcandre.lureau@redhat.com>" [full] # gpg: aka "Marc-André Lureau <marcandre.lureau@gmail.com>" [full] # Primary key fingerprint: 87A9 BD93 3F87 C606 D276 F62D DAE8 E109 7596 9CE5 * remotes/marcandre/tags/clip-pull-request: ui/vdagent: add a migration blocker ui/gtk-clipboard: emit release clipboard events ui/vdagent: send release when no clipboard owner ui/gtk-clipboard: use qemu_clipboard_info helper ui/vdagent: send empty clipboard when unhandled ui/vdagent: use qemu_clipboard_info helper ui/vdagent: use qemu_clipboard_peer_release helper ui/vdagent: split clipboard recv message handling ui/vdagent: reset outbuf on disconnect ui/vdagent: disconnect handlers and reset state on finalize ui/clipboard: release owned grabs on unregister ui/clipboard: add qemu_clipboard_peer_release() helper ui/clipboard: add qemu_clipboard_peer_owns() helper ui/clipboard: add helper to retrieve current clipboard ui/gtk-clipboard: fix clipboard enum typo ui/gtk-clipboard: use existing macros ui/vdagent: remove copy-pasta comment ui/vdagent: fix leak on error path Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
d52dff5d80
@ -109,6 +109,37 @@ void qemu_clipboard_peer_register(QemuClipboardPeer *peer);
|
||||
*/
|
||||
void qemu_clipboard_peer_unregister(QemuClipboardPeer *peer);
|
||||
|
||||
/**
|
||||
* qemu_clipboard_peer_owns
|
||||
*
|
||||
* @peer: peer information.
|
||||
* @selection: clipboard selection.
|
||||
*
|
||||
* Return TRUE if the peer owns the clipboard.
|
||||
*/
|
||||
bool qemu_clipboard_peer_owns(QemuClipboardPeer *peer,
|
||||
QemuClipboardSelection selection);
|
||||
|
||||
/**
|
||||
* qemu_clipboard_peer_release
|
||||
*
|
||||
* @peer: peer information.
|
||||
* @selection: clipboard selection.
|
||||
*
|
||||
* If the peer owns the clipboard, release it.
|
||||
*/
|
||||
void qemu_clipboard_peer_release(QemuClipboardPeer *peer,
|
||||
QemuClipboardSelection selection);
|
||||
|
||||
/**
|
||||
* qemu_clipboard_info
|
||||
*
|
||||
* @selection: clipboard selection.
|
||||
*
|
||||
* Return the current clipboard data & owner informations.
|
||||
*/
|
||||
QemuClipboardInfo *qemu_clipboard_info(QemuClipboardSelection selection);
|
||||
|
||||
/**
|
||||
* qemu_clipboard_info_new
|
||||
*
|
||||
@ -190,4 +221,6 @@ void qemu_clipboard_set_data(QemuClipboardPeer *peer,
|
||||
const void *data,
|
||||
bool update);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(QemuClipboardInfo, qemu_clipboard_info_unref)
|
||||
|
||||
#endif /* QEMU_CLIPBOARD_H */
|
||||
|
@ -143,7 +143,6 @@ struct GtkDisplayState {
|
||||
bool external_pause_update;
|
||||
|
||||
QemuClipboardPeer cbpeer;
|
||||
QemuClipboardInfo *cbinfo[QEMU_CLIPBOARD_SELECTION__COUNT];
|
||||
uint32_t cbpending[QEMU_CLIPBOARD_SELECTION__COUNT];
|
||||
GtkClipboard *gtkcb[QEMU_CLIPBOARD_SELECTION__COUNT];
|
||||
bool cbowner[QEMU_CLIPBOARD_SELECTION__COUNT];
|
||||
|
@ -4,6 +4,8 @@
|
||||
static NotifierList clipboard_notifiers =
|
||||
NOTIFIER_LIST_INITIALIZER(clipboard_notifiers);
|
||||
|
||||
static QemuClipboardInfo *cbinfo[QEMU_CLIPBOARD_SELECTION__COUNT];
|
||||
|
||||
void qemu_clipboard_peer_register(QemuClipboardPeer *peer)
|
||||
{
|
||||
notifier_list_add(&clipboard_notifiers, &peer->update);
|
||||
@ -11,12 +13,51 @@ void qemu_clipboard_peer_register(QemuClipboardPeer *peer)
|
||||
|
||||
void qemu_clipboard_peer_unregister(QemuClipboardPeer *peer)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < QEMU_CLIPBOARD_SELECTION__COUNT; i++) {
|
||||
qemu_clipboard_peer_release(peer, i);
|
||||
}
|
||||
|
||||
notifier_remove(&peer->update);
|
||||
}
|
||||
|
||||
bool qemu_clipboard_peer_owns(QemuClipboardPeer *peer,
|
||||
QemuClipboardSelection selection)
|
||||
{
|
||||
QemuClipboardInfo *info = qemu_clipboard_info(selection);
|
||||
|
||||
return info && info->owner == peer;
|
||||
}
|
||||
|
||||
void qemu_clipboard_peer_release(QemuClipboardPeer *peer,
|
||||
QemuClipboardSelection selection)
|
||||
{
|
||||
g_autoptr(QemuClipboardInfo) info = NULL;
|
||||
|
||||
if (qemu_clipboard_peer_owns(peer, selection)) {
|
||||
/* set empty clipboard info */
|
||||
info = qemu_clipboard_info_new(NULL, selection);
|
||||
qemu_clipboard_update(info);
|
||||
}
|
||||
}
|
||||
|
||||
void qemu_clipboard_update(QemuClipboardInfo *info)
|
||||
{
|
||||
g_autoptr(QemuClipboardInfo) old = NULL;
|
||||
assert(info->selection < QEMU_CLIPBOARD_SELECTION__COUNT);
|
||||
|
||||
notifier_list_notify(&clipboard_notifiers, info);
|
||||
|
||||
old = cbinfo[info->selection];
|
||||
cbinfo[info->selection] = qemu_clipboard_info_ref(info);
|
||||
}
|
||||
|
||||
QemuClipboardInfo *qemu_clipboard_info(QemuClipboardSelection selection)
|
||||
{
|
||||
assert(selection < QEMU_CLIPBOARD_SELECTION__COUNT);
|
||||
|
||||
return cbinfo[selection];
|
||||
}
|
||||
|
||||
QemuClipboardInfo *qemu_clipboard_info_new(QemuClipboardPeer *owner,
|
||||
|
@ -45,24 +45,24 @@ static void gd_clipboard_get_data(GtkClipboard *clipboard,
|
||||
GtkDisplayState *gd = data;
|
||||
QemuClipboardSelection s = gd_find_selection(gd, clipboard);
|
||||
QemuClipboardType type = QEMU_CLIPBOARD_TYPE_TEXT;
|
||||
QemuClipboardInfo *info = qemu_clipboard_info_ref(gd->cbinfo[s]);
|
||||
g_autoptr(QemuClipboardInfo) info = NULL;
|
||||
|
||||
info = qemu_clipboard_info_ref(qemu_clipboard_info(s));
|
||||
|
||||
qemu_clipboard_request(info, type);
|
||||
while (info == gd->cbinfo[s] &&
|
||||
while (info == qemu_clipboard_info(s) &&
|
||||
info->types[type].available &&
|
||||
info->types[type].data == NULL) {
|
||||
main_loop_wait(false);
|
||||
}
|
||||
|
||||
if (info == gd->cbinfo[s] && gd->cbowner[s]) {
|
||||
if (info == qemu_clipboard_info(s) && gd->cbowner[s]) {
|
||||
gtk_selection_data_set_text(selection_data,
|
||||
info->types[type].data,
|
||||
info->types[type].size);
|
||||
} else {
|
||||
/* clipboard owner changed while waiting for the data */
|
||||
}
|
||||
|
||||
qemu_clipboard_info_unref(info);
|
||||
}
|
||||
|
||||
static void gd_clipboard_clear(GtkClipboard *clipboard,
|
||||
@ -81,9 +81,7 @@ static void gd_clipboard_notify(Notifier *notifier, void *data)
|
||||
QemuClipboardSelection s = info->selection;
|
||||
bool self_update = info->owner == &gd->cbpeer;
|
||||
|
||||
if (info != gd->cbinfo[s]) {
|
||||
qemu_clipboard_info_unref(gd->cbinfo[s]);
|
||||
gd->cbinfo[s] = qemu_clipboard_info_ref(info);
|
||||
if (info != qemu_clipboard_info(s)) {
|
||||
gd->cbpending[s] = 0;
|
||||
if (!self_update) {
|
||||
GtkTargetList *list;
|
||||
@ -155,7 +153,7 @@ static void gd_owner_change(GtkClipboard *clipboard,
|
||||
|
||||
|
||||
switch (event->owner_change.reason) {
|
||||
case GDK_SETTING_ACTION_NEW:
|
||||
case GDK_OWNER_CHANGE_NEW_OWNER:
|
||||
info = qemu_clipboard_info_new(&gd->cbpeer, s);
|
||||
if (gtk_clipboard_wait_is_text_available(clipboard)) {
|
||||
info->types[QEMU_CLIPBOARD_TYPE_TEXT].available = true;
|
||||
@ -165,6 +163,8 @@ static void gd_owner_change(GtkClipboard *clipboard,
|
||||
qemu_clipboard_info_unref(info);
|
||||
break;
|
||||
default:
|
||||
qemu_clipboard_peer_release(&gd->cbpeer, s);
|
||||
gd->cbowner[s] = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -177,11 +177,11 @@ void gd_clipboard_init(GtkDisplayState *gd)
|
||||
qemu_clipboard_peer_register(&gd->cbpeer);
|
||||
|
||||
gd->gtkcb[QEMU_CLIPBOARD_SELECTION_CLIPBOARD] =
|
||||
gtk_clipboard_get(gdk_atom_intern("CLIPBOARD", FALSE));
|
||||
gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
|
||||
gd->gtkcb[QEMU_CLIPBOARD_SELECTION_PRIMARY] =
|
||||
gtk_clipboard_get(gdk_atom_intern("PRIMARY", FALSE));
|
||||
gtk_clipboard_get(GDK_SELECTION_PRIMARY);
|
||||
gd->gtkcb[QEMU_CLIPBOARD_SELECTION_SECONDARY] =
|
||||
gtk_clipboard_get(gdk_atom_intern("SECONDARY", FALSE));
|
||||
gtk_clipboard_get(GDK_SELECTION_SECONDARY);
|
||||
|
||||
g_signal_connect(gd->gtkcb[QEMU_CLIPBOARD_SELECTION_CLIPBOARD],
|
||||
"owner-change", G_CALLBACK(gd_owner_change), gd);
|
||||
|
@ -129,6 +129,7 @@ xkeymap_keymap(const char *name) "keymap '%s'"
|
||||
vdagent_open(void) ""
|
||||
vdagent_close(void) ""
|
||||
vdagent_send(const char *name) "msg %s"
|
||||
vdagent_send_empty_clipboard(void) ""
|
||||
vdagent_recv_chunk(uint32_t size) "size %d"
|
||||
vdagent_recv_msg(const char *name, uint32_t size) "msg %s, size %d"
|
||||
vdagent_peer_cap(const char *name) "cap %s"
|
||||
|
240
ui/vdagent.c
240
ui/vdagent.c
@ -6,6 +6,7 @@
|
||||
#include "qemu/option.h"
|
||||
#include "qemu/units.h"
|
||||
#include "hw/qdev-core.h"
|
||||
#include "migration/blocker.h"
|
||||
#include "ui/clipboard.h"
|
||||
#include "ui/console.h"
|
||||
#include "ui/input.h"
|
||||
@ -23,6 +24,9 @@
|
||||
struct VDAgentChardev {
|
||||
Chardev parent;
|
||||
|
||||
/* TODO: migration isn't yet supported */
|
||||
Error *migration_blocker;
|
||||
|
||||
/* config */
|
||||
bool mouse;
|
||||
bool clipboard;
|
||||
@ -47,7 +51,6 @@ struct VDAgentChardev {
|
||||
|
||||
/* clipboard */
|
||||
QemuClipboardPeer cbpeer;
|
||||
QemuClipboardInfo *cbinfo[QEMU_CLIPBOARD_SELECTION__COUNT];
|
||||
uint32_t cbpending[QEMU_CLIPBOARD_SELECTION__COUNT];
|
||||
};
|
||||
typedef struct VDAgentChardev VDAgentChardev;
|
||||
@ -346,6 +349,24 @@ static void vdagent_send_clipboard_grab(VDAgentChardev *vd,
|
||||
vdagent_send_msg(vd, msg);
|
||||
}
|
||||
|
||||
static void vdagent_send_clipboard_release(VDAgentChardev *vd,
|
||||
QemuClipboardInfo *info)
|
||||
{
|
||||
g_autofree VDAgentMessage *msg = g_malloc0(sizeof(VDAgentMessage) +
|
||||
sizeof(uint32_t));
|
||||
|
||||
if (have_selection(vd)) {
|
||||
uint8_t *s = msg->data;
|
||||
*s = info->selection;
|
||||
msg->size += sizeof(uint32_t);
|
||||
} else if (info->selection != QEMU_CLIPBOARD_SELECTION_CLIPBOARD) {
|
||||
return;
|
||||
}
|
||||
|
||||
msg->type = VD_AGENT_CLIPBOARD_RELEASE;
|
||||
vdagent_send_msg(vd, msg);
|
||||
}
|
||||
|
||||
static void vdagent_send_clipboard_data(VDAgentChardev *vd,
|
||||
QemuClipboardInfo *info,
|
||||
QemuClipboardType type)
|
||||
@ -376,6 +397,16 @@ static void vdagent_send_clipboard_data(VDAgentChardev *vd,
|
||||
vdagent_send_msg(vd, msg);
|
||||
}
|
||||
|
||||
static void vdagent_send_empty_clipboard_data(VDAgentChardev *vd,
|
||||
QemuClipboardSelection selection,
|
||||
QemuClipboardType type)
|
||||
{
|
||||
g_autoptr(QemuClipboardInfo) info = qemu_clipboard_info_new(&vd->cbpeer, selection);
|
||||
|
||||
trace_vdagent_send_empty_clipboard();
|
||||
vdagent_send_clipboard_data(vd, info, type);
|
||||
}
|
||||
|
||||
static void vdagent_clipboard_notify(Notifier *notifier, void *data)
|
||||
{
|
||||
VDAgentChardev *vd = container_of(notifier, VDAgentChardev, cbpeer.update);
|
||||
@ -384,12 +415,14 @@ static void vdagent_clipboard_notify(Notifier *notifier, void *data)
|
||||
QemuClipboardType type;
|
||||
bool self_update = info->owner == &vd->cbpeer;
|
||||
|
||||
if (info != vd->cbinfo[s]) {
|
||||
qemu_clipboard_info_unref(vd->cbinfo[s]);
|
||||
vd->cbinfo[s] = qemu_clipboard_info_ref(info);
|
||||
if (info != qemu_clipboard_info(s)) {
|
||||
vd->cbpending[s] = 0;
|
||||
if (!self_update) {
|
||||
vdagent_send_clipboard_grab(vd, info);
|
||||
if (info->owner) {
|
||||
vdagent_send_clipboard_grab(vd, info);
|
||||
} else {
|
||||
vdagent_send_clipboard_release(vd, info);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -433,13 +466,96 @@ static void vdagent_clipboard_request(QemuClipboardInfo *info,
|
||||
vdagent_send_msg(vd, msg);
|
||||
}
|
||||
|
||||
static void vdagent_clipboard_recv_grab(VDAgentChardev *vd, uint8_t s, uint32_t size, void *data)
|
||||
{
|
||||
g_autoptr(QemuClipboardInfo) info = NULL;
|
||||
|
||||
trace_vdagent_cb_grab_selection(GET_NAME(sel_name, s));
|
||||
info = qemu_clipboard_info_new(&vd->cbpeer, s);
|
||||
if (size > sizeof(uint32_t) * 10) {
|
||||
/*
|
||||
* spice has 6 types as of 2021. Limiting to 10 entries
|
||||
* so we we have some wiggle room.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
while (size >= sizeof(uint32_t)) {
|
||||
trace_vdagent_cb_grab_type(GET_NAME(type_name, *(uint32_t *)data));
|
||||
switch (*(uint32_t *)data) {
|
||||
case VD_AGENT_CLIPBOARD_UTF8_TEXT:
|
||||
info->types[QEMU_CLIPBOARD_TYPE_TEXT].available = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
data += sizeof(uint32_t);
|
||||
size -= sizeof(uint32_t);
|
||||
}
|
||||
qemu_clipboard_update(info);
|
||||
}
|
||||
|
||||
static void vdagent_clipboard_recv_request(VDAgentChardev *vd, uint8_t s, uint32_t size, void *data)
|
||||
{
|
||||
QemuClipboardType type;
|
||||
QemuClipboardInfo *info;
|
||||
|
||||
if (size < sizeof(uint32_t)) {
|
||||
return;
|
||||
}
|
||||
switch (*(uint32_t *)data) {
|
||||
case VD_AGENT_CLIPBOARD_UTF8_TEXT:
|
||||
type = QEMU_CLIPBOARD_TYPE_TEXT;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
info = qemu_clipboard_info(s);
|
||||
if (info && info->types[type].available && info->owner != &vd->cbpeer) {
|
||||
if (info->types[type].data) {
|
||||
vdagent_send_clipboard_data(vd, info, type);
|
||||
} else {
|
||||
vd->cbpending[s] |= (1 << type);
|
||||
qemu_clipboard_request(info, type);
|
||||
}
|
||||
} else {
|
||||
vdagent_send_empty_clipboard_data(vd, s, type);
|
||||
}
|
||||
}
|
||||
|
||||
static void vdagent_clipboard_recv_data(VDAgentChardev *vd, uint8_t s, uint32_t size, void *data)
|
||||
{
|
||||
QemuClipboardType type;
|
||||
|
||||
if (size < sizeof(uint32_t)) {
|
||||
return;
|
||||
}
|
||||
switch (*(uint32_t *)data) {
|
||||
case VD_AGENT_CLIPBOARD_UTF8_TEXT:
|
||||
type = QEMU_CLIPBOARD_TYPE_TEXT;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
data += 4;
|
||||
size -= 4;
|
||||
|
||||
if (qemu_clipboard_peer_owns(&vd->cbpeer, s)) {
|
||||
qemu_clipboard_set_data(&vd->cbpeer, qemu_clipboard_info(s),
|
||||
type, size, data, true);
|
||||
}
|
||||
}
|
||||
|
||||
static void vdagent_clipboard_recv_release(VDAgentChardev *vd, uint8_t s)
|
||||
{
|
||||
qemu_clipboard_peer_release(&vd->cbpeer, s);
|
||||
}
|
||||
|
||||
static void vdagent_chr_recv_clipboard(VDAgentChardev *vd, VDAgentMessage *msg)
|
||||
{
|
||||
uint8_t s = VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD;
|
||||
uint32_t size = msg->size;
|
||||
void *data = msg->data;
|
||||
QemuClipboardInfo *info;
|
||||
QemuClipboardType type;
|
||||
|
||||
if (have_selection(vd)) {
|
||||
if (size < 4) {
|
||||
@ -455,77 +571,15 @@ static void vdagent_chr_recv_clipboard(VDAgentChardev *vd, VDAgentMessage *msg)
|
||||
|
||||
switch (msg->type) {
|
||||
case VD_AGENT_CLIPBOARD_GRAB:
|
||||
trace_vdagent_cb_grab_selection(GET_NAME(sel_name, s));
|
||||
info = qemu_clipboard_info_new(&vd->cbpeer, s);
|
||||
if (size > sizeof(uint32_t) * 10) {
|
||||
/*
|
||||
* spice has 6 types as of 2021. Limiting to 10 entries
|
||||
* so we we have some wiggle room.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
while (size >= sizeof(uint32_t)) {
|
||||
trace_vdagent_cb_grab_type(GET_NAME(type_name, *(uint32_t *)data));
|
||||
switch (*(uint32_t *)data) {
|
||||
case VD_AGENT_CLIPBOARD_UTF8_TEXT:
|
||||
info->types[QEMU_CLIPBOARD_TYPE_TEXT].available = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
data += sizeof(uint32_t);
|
||||
size -= sizeof(uint32_t);
|
||||
}
|
||||
qemu_clipboard_update(info);
|
||||
qemu_clipboard_info_unref(info);
|
||||
break;
|
||||
return vdagent_clipboard_recv_grab(vd, s, size, data);
|
||||
case VD_AGENT_CLIPBOARD_REQUEST:
|
||||
if (size < sizeof(uint32_t)) {
|
||||
return;
|
||||
}
|
||||
switch (*(uint32_t *)data) {
|
||||
case VD_AGENT_CLIPBOARD_UTF8_TEXT:
|
||||
type = QEMU_CLIPBOARD_TYPE_TEXT;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
if (vd->cbinfo[s] &&
|
||||
vd->cbinfo[s]->types[type].available &&
|
||||
vd->cbinfo[s]->owner != &vd->cbpeer) {
|
||||
if (vd->cbinfo[s]->types[type].data) {
|
||||
vdagent_send_clipboard_data(vd, vd->cbinfo[s], type);
|
||||
} else {
|
||||
vd->cbpending[s] |= (1 << type);
|
||||
qemu_clipboard_request(vd->cbinfo[s], type);
|
||||
}
|
||||
}
|
||||
break;
|
||||
return vdagent_clipboard_recv_request(vd, s, size, data);
|
||||
case VD_AGENT_CLIPBOARD: /* data */
|
||||
if (size < sizeof(uint32_t)) {
|
||||
return;
|
||||
}
|
||||
switch (*(uint32_t *)data) {
|
||||
case VD_AGENT_CLIPBOARD_UTF8_TEXT:
|
||||
type = QEMU_CLIPBOARD_TYPE_TEXT;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
data += 4;
|
||||
size -= 4;
|
||||
qemu_clipboard_set_data(&vd->cbpeer, vd->cbinfo[s], type,
|
||||
size, data, true);
|
||||
break;
|
||||
case VD_AGENT_CLIPBOARD_RELEASE: /* data */
|
||||
if (vd->cbinfo[s] &&
|
||||
vd->cbinfo[s]->owner == &vd->cbpeer) {
|
||||
/* set empty clipboard info */
|
||||
info = qemu_clipboard_info_new(NULL, s);
|
||||
qemu_clipboard_update(info);
|
||||
qemu_clipboard_info_unref(info);
|
||||
}
|
||||
break;
|
||||
return vdagent_clipboard_recv_data(vd, s, size, data);
|
||||
case VD_AGENT_CLIPBOARD_RELEASE:
|
||||
return vdagent_clipboard_recv_release(vd, s);
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
@ -549,6 +603,10 @@ static void vdagent_chr_open(Chardev *chr,
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (migrate_add_blocker(vd->migration_blocker, errp) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
vd->mouse = VDAGENT_MOUSE_DEFAULT;
|
||||
if (cfg->has_mouse) {
|
||||
vd->mouse = cfg->mouse;
|
||||
@ -723,22 +781,27 @@ static void vdagent_chr_accept_input(Chardev *chr)
|
||||
vdagent_send_buf(vd);
|
||||
}
|
||||
|
||||
static void vdagent_disconnect(VDAgentChardev *vd)
|
||||
{
|
||||
buffer_reset(&vd->outbuf);
|
||||
vdagent_reset_bufs(vd);
|
||||
vd->caps = 0;
|
||||
if (vd->mouse_hs) {
|
||||
qemu_input_handler_deactivate(vd->mouse_hs);
|
||||
}
|
||||
if (vd->cbpeer.update.notify) {
|
||||
qemu_clipboard_peer_unregister(&vd->cbpeer);
|
||||
memset(&vd->cbpeer, 0, sizeof(vd->cbpeer));
|
||||
}
|
||||
}
|
||||
|
||||
static void vdagent_chr_set_fe_open(struct Chardev *chr, int fe_open)
|
||||
{
|
||||
VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(chr);
|
||||
|
||||
if (!fe_open) {
|
||||
trace_vdagent_close();
|
||||
/* reset state */
|
||||
vdagent_reset_bufs(vd);
|
||||
vd->caps = 0;
|
||||
if (vd->mouse_hs) {
|
||||
qemu_input_handler_deactivate(vd->mouse_hs);
|
||||
}
|
||||
if (vd->cbpeer.update.notify) {
|
||||
qemu_clipboard_peer_unregister(&vd->cbpeer);
|
||||
memset(&vd->cbpeer, 0, sizeof(vd->cbpeer));
|
||||
}
|
||||
vdagent_disconnect(vd);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -777,13 +840,18 @@ static void vdagent_chr_init(Object *obj)
|
||||
VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(obj);
|
||||
|
||||
buffer_init(&vd->outbuf, "vdagent-outbuf");
|
||||
error_setg(&vd->migration_blocker,
|
||||
"The vdagent chardev doesn't yet support migration");
|
||||
}
|
||||
|
||||
static void vdagent_chr_fini(Object *obj)
|
||||
{
|
||||
VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(obj);
|
||||
|
||||
migrate_del_blocker(vd->migration_blocker);
|
||||
vdagent_disconnect(vd);
|
||||
buffer_free(&vd->outbuf);
|
||||
error_free(vd->migration_blocker);
|
||||
}
|
||||
|
||||
static const TypeInfo vdagent_chr_type_info = {
|
||||
|
Loading…
Reference in New Issue
Block a user