From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.5 required=3.0 tests=BAYES_00,DKIM_ADSP_CUSTOM_MED, DKIM_INVALID,DKIM_SIGNED,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,HTML_MESSAGE,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=no autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8F271C433DB for ; Thu, 25 Feb 2021 19:48:26 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 8E43C60235 for ; Thu, 25 Feb 2021 19:48:25 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 8E43C60235 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:55910 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lFMca-0006TQ-6m for qemu-devel@archiver.kernel.org; Thu, 25 Feb 2021 14:48:24 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:34246) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lFMZe-0004cy-Nz for qemu-devel@nongnu.org; Thu, 25 Feb 2021 14:45:23 -0500 Received: from mail-ed1-x532.google.com ([2a00:1450:4864:20::532]:33144) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1lFMZZ-0004BN-Or for qemu-devel@nongnu.org; Thu, 25 Feb 2021 14:45:22 -0500 Received: by mail-ed1-x532.google.com with SMTP id c6so8442630ede.0 for ; Thu, 25 Feb 2021 11:45:16 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=9mwRLNIn92SdH/1W7fkQ5zYQ+X4mfq1llP3yUn2+3Sc=; b=U8+TPUQGDjXqCkH4WJPcGgphyNcW2ULF5l18O439hJxrLgo/cYuf3lGlUsPB6VM5qI 5VvI7l7K1wn0zbHzF6f33BrtK9WR0YPWvGo6iyAsfevgnKt3x61Z0rs5CObJqHSRMMpI n4RwwzqcbMj8qEVMIWmoZCRPOvX7J8KOnx4uxhQUUbbkiqiwLFxpqe1gRURHIsP/OLnE 3olbdZASaiP5pqucBtpqTy+Hz2eZQa/uwd6Aik3NWB+z1thrQcIxWgGCvPFdhfvzE5rz UkBWhyv4shDpKuQHWDLzA0PGtZUlb3LY+WdsyeYaYnVSe/P3w9jidxVMVWr7IJumvJj4 V0jg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=9mwRLNIn92SdH/1W7fkQ5zYQ+X4mfq1llP3yUn2+3Sc=; b=VClneNbVU7xj88YCvoB1eTXoaKtOwnrYCL/202jx5mmRHjVAXTdv4INphNQDXn9Lz7 6SYfYm7K8l7UlkjNoCpdiDvFbKIk3FHpDcknwJSvv8R7eATBn8eIumOnzwVhdtdnpAed po0CAPHTGZzzf6wutdh6RIotJECLTi8tb2xxrnND40dk2BhYHePsbAfPe9cqAsaGqMpM vZeE4Cwg6SwNjePAJcBawP/xprBmWFOYll+GPwwF+M0YvA7OikRFxvbfDZlPbE1UXJ4+ QOgoLmrzj5QimlivyNpX3eZJmvl9HXaEHQ4pnD58aHk9Vr78OwGy2DxNahbq6IE6n1V2 InRw== X-Gm-Message-State: AOAM533hwonr0gDMXOcIAVvP57IA6Z0oqSYxkMIzmnTY8LhzzVkmoWVu 8yRk2vkbOISS9ZQb+jDMGaQetkseW1GSnTyMbaM= X-Google-Smtp-Source: ABdhPJx23WBllSiY7P+w8dEXABZzVzuJ4oI9GODwA382Ie+dXIDk+OPiClogOKqmj9pBBMXbjsCaFB2XNqzzXfz6EiA= X-Received: by 2002:aa7:cd94:: with SMTP id x20mr4863322edv.53.1614282315621; Thu, 25 Feb 2021 11:45:15 -0800 (PST) MIME-Version: 1.0 References: <20210219131349.3993192-1-kraxel@redhat.com> <20210219131349.3993192-8-kraxel@redhat.com> In-Reply-To: <20210219131349.3993192-8-kraxel@redhat.com> From: =?UTF-8?B?TWFyYy1BbmRyw6kgTHVyZWF1?= Date: Thu, 25 Feb 2021 23:45:03 +0400 Message-ID: Subject: Re: [PATCH 7/7] ui/gtk: add clipboard support To: Gerd Hoffmann Content-Type: multipart/alternative; boundary="000000000000fd69ed05bc2e637a" Received-SPF: pass client-ip=2a00:1450:4864:20::532; envelope-from=marcandre.lureau@gmail.com; helo=mail-ed1-x532.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, HTML_MESSAGE=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Paolo Bonzini , QEMU , Markus Armbruster Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" --000000000000fd69ed05bc2e637a Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Fri, Feb 19, 2021 at 5:29 PM Gerd Hoffmann wrote: > This patch adds clipboard support to the qemu gtk ui. > > Signed-off-by: Gerd Hoffmann > --- > include/ui/gtk.h | 9 ++++ > ui/gtk-clipboard.c | 124 +++++++++++++++++++++++++++++++++++++++++++++ > ui/gtk.c | 1 + > ui/meson.build | 2 +- > 4 files changed, 135 insertions(+), 1 deletion(-) > create mode 100644 ui/gtk-clipboard.c > > diff --git a/include/ui/gtk.h b/include/ui/gtk.h > index 55319843758d..08999f8835e6 100644 > --- a/include/ui/gtk.h > +++ b/include/ui/gtk.h > @@ -18,6 +18,7 @@ > #include > #endif > > +#include "ui/clipboard.h" > #include "ui/console.h" > #include "ui/kbd-state.h" > #if defined(CONFIG_OPENGL) > @@ -137,6 +138,11 @@ 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]; > + > DisplayOptions *opts; > }; > > @@ -208,4 +214,7 @@ QEMUGLContext > gd_gl_area_get_current_context(DisplayChangeListener *dcl); > int gd_gl_area_make_current(DisplayChangeListener *dcl, > QEMUGLContext ctx); > > +/* gtk-clipboard.c */ > +void gd_clipboard_init(GtkDisplayState *gd); > + > #endif /* UI_GTK_H */ > diff --git a/ui/gtk-clipboard.c b/ui/gtk-clipboard.c > new file mode 100644 > index 000000000000..4a7f44b25818 > --- /dev/null > +++ b/ui/gtk-clipboard.c > @@ -0,0 +1,124 @@ > +/* > + * GTK UI -- clipboard support > + * > + * Copyright (C) 2021 Gerd Hoffmann > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, see . > + * > + */ > + > +#include "qemu/osdep.h" > +#include "qemu-common.h" > + > +#include "ui/gtk.h" > + > +static void gd_clipboard_notify(Notifier *notifier, void *data) > +{ > + GtkDisplayState *gd =3D container_of(notifier, GtkDisplayState, > cbpeer.update); > + QemuClipboardInfo *info =3D data; > + QemuClipboardSelection s =3D info->selection; > + bool self_update =3D info->owner =3D=3D &gd->cbpeer; > + > + if (info !=3D gd->cbinfo[s]) { > + qemu_clipboard_info_put(gd->cbinfo[s]); > + gd->cbinfo[s] =3D qemu_clipboard_info_get(info); > + gd->cbpending[s] =3D 0; > + if (!self_update) { > + if (info->types[QEMU_CLIPBOARD_TYPE_TEXT].available) { > + qemu_clipboard_request(info, QEMU_CLIPBOARD_TYPE_TEXT); > Always requesting the clipboard is a bit harsh, isn't it? + } > + } > + return; > + } > + > + if (self_update) { > + return; > + } > + > + if (info->types[QEMU_CLIPBOARD_TYPE_TEXT].available && > + info->types[QEMU_CLIPBOARD_TYPE_TEXT].data) { > + gtk_clipboard_set_text(gd->gtkcb[s], > + info->types[QEMU_CLIPBOARD_TYPE_TEXT].dat= a, > + > info->types[QEMU_CLIPBOARD_TYPE_TEXT].size); > + } > +} > + > +static void gd_clipboard_request(QemuClipboardInfo *info, > + QemuClipboardType type) > +{ > + GtkDisplayState *gd =3D container_of(info->owner, GtkDisplayState, > cbpeer); > + char *text; > + > + switch (type) { > + case QEMU_CLIPBOARD_TYPE_TEXT: > + text =3D gtk_clipboard_wait_for_text(gd->gtkcb[info->selection])= ; > + qemu_clipboard_set_data(&gd->cbpeer, info, type, > + strlen(text), text, true); > text might be NULL if it failed. And you must free it. + break; > + default: > + break; > + } > +} > + > +static QemuClipboardSelection gd_find_selection(GtkDisplayState *gd, > + GtkClipboard *clipboard) > +{ > + QemuClipboardSelection s; > + > + for (s =3D 0; s < QEMU_CLIPBOARD_SELECTION__COUNT; s++) { > + if (gd->gtkcb[s] =3D=3D clipboard) { > + return s; > + } > + } > + return QEMU_CLIPBOARD_SELECTION_CLIPBOARD; > +} > + > +static void gd_owner_change(GtkClipboard *clipboard, > + GdkEvent *event, > + gpointer data) > +{ > + GtkDisplayState *gd =3D data; > + QemuClipboardSelection s =3D gd_find_selection(gd, clipboard); > + QemuClipboardInfo *info; > + > + info =3D qemu_clipboard_info_new(&gd->cbpeer, s); > + if (gtk_clipboard_wait_is_text_available(clipboard)) { > + info->types[QEMU_CLIPBOARD_TYPE_TEXT].available =3D true; > + } > Hmm, so after gtk_clipboard_set_text() the client side is actually taking the ownership away from the guest clipboard I presume. That might have some weird interaction issues. Hopefully the other side isn't playing the same game... + > + qemu_clipboard_update(info); > + qemu_clipboard_info_put(info); > +} > + > +void gd_clipboard_init(GtkDisplayState *gd) > +{ > + gd->cbpeer.name =3D "gtk"; > + gd->cbpeer.update.notify =3D gd_clipboard_notify; > + gd->cbpeer.request =3D gd_clipboard_request; > + qemu_clipboard_peer_register(&gd->cbpeer); > + > + gd->gtkcb[QEMU_CLIPBOARD_SELECTION_CLIPBOARD] =3D > + gtk_clipboard_get(gdk_atom_intern("CLIPBOARD", FALSE)); > GDK_SELECTION_CLIPBOARD > + gd->gtkcb[QEMU_CLIPBOARD_SELECTION_PRIMARY] =3D > + gtk_clipboard_get(gdk_atom_intern("PRIMARY", FALSE)); > GDK_SELECTION_PRIMARY + gd->gtkcb[QEMU_CLIPBOARD_SELECTION_SECONDARY] =3D > + gtk_clipboard_get(gdk_atom_intern("SECONDARY", FALSE)); > GDK_SELECTION_SECONDARY > + > + g_signal_connect(gd->gtkcb[QEMU_CLIPBOARD_SELECTION_CLIPBOARD], > + "owner-change", G_CALLBACK(gd_owner_change), gd); > + g_signal_connect(gd->gtkcb[QEMU_CLIPBOARD_SELECTION_PRIMARY], > + "owner-change", G_CALLBACK(gd_owner_change), gd); > + g_signal_connect(gd->gtkcb[QEMU_CLIPBOARD_SELECTION_SECONDARY], > + "owner-change", G_CALLBACK(gd_owner_change), gd); > Might be worth having a deinit for signals, peer registration etc, even if nothing is hooked yet in gtk.c.. Overall, calling wait & set variants of clipboard functions makes things quite simpler to deal with. Hopefully it can stay that way... +} > diff --git a/ui/gtk.c b/ui/gtk.c > index 7b412dd4fe0b..0ae3ec20f594 100644 > --- a/ui/gtk.c > +++ b/ui/gtk.c > @@ -2252,6 +2252,7 @@ static void gtk_display_init(DisplayState *ds, > DisplayOptions *opts) > opts->u.gtk.grab_on_hover) { > gtk_menu_item_activate(GTK_MENU_ITEM(s->grab_on_hover_item)); > } > + gd_clipboard_init(s); > } > > static void early_gtk_display_init(DisplayOptions *opts) > diff --git a/ui/meson.build b/ui/meson.build > index a98f89b48978..3ea969a6210b 100644 > --- a/ui/meson.build > +++ b/ui/meson.build > @@ -64,7 +64,7 @@ if gtk.found() > softmmu_ss.add(when: 'CONFIG_WIN32', if_true: files('win32-kbd-hook.c'= )) > > gtk_ss =3D ss.source_set() > - gtk_ss.add(gtk, vte, pixman, files('gtk.c')) > + gtk_ss.add(gtk, vte, pixman, files('gtk.c', 'gtk-clipboard.c')) > gtk_ss.add(when: x11, if_true: files('x_keymap.c')) > gtk_ss.add(when: [opengl, 'CONFIG_OPENGL'], if_true: files('gtk-egl.c'= , > 'gtk-gl-area.c')) > ui_modules +=3D {'gtk' : gtk_ss} > -- > 2.29.2 > > > --=20 Marc-Andr=C3=A9 Lureau --000000000000fd69ed05bc2e637a Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable


=
On Fri, Feb 19, 2021 at 5:29 PM Gerd = Hoffmann <kraxel@redhat.com>= wrote:
This pat= ch adds clipboard support to the qemu gtk ui.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
=C2=A0include/ui/gtk.h=C2=A0 =C2=A0|=C2=A0 =C2=A09 ++++
=C2=A0ui/gtk-clipboard.c | 124 ++++++++++++++++++++++++++++++++++++++++++++= +
=C2=A0ui/gtk.c=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0|=C2=A0 =C2=A01 + =C2=A0ui/meson.build=C2=A0 =C2=A0 =C2=A0|=C2=A0 =C2=A02 +-
=C2=A04 files changed, 135 insertions(+), 1 deletion(-)
=C2=A0create mode 100644 ui/gtk-clipboard.c

diff --git a/include/ui/gtk.h b/include/ui/gtk.h
index 55319843758d..08999f8835e6 100644
--- a/include/ui/gtk.h
+++ b/include/ui/gtk.h
@@ -18,6 +18,7 @@
=C2=A0#include <gdk/gdkwayland.h>
=C2=A0#endif

+#include "ui/clipboard.h"
=C2=A0#include "ui/console.h"
=C2=A0#include "ui/kbd-state.h"
=C2=A0#if defined(CONFIG_OPENGL)
@@ -137,6 +138,11 @@ struct GtkDisplayState {

=C2=A0 =C2=A0 =C2=A0bool external_pause_update;

+=C2=A0 =C2=A0 QemuClipboardPeer cbpeer;
+=C2=A0 =C2=A0 QemuClipboardInfo *cbinfo[QEMU_CLIPBOARD_SELECTION__COUNT];<= br> +=C2=A0 =C2=A0 uint32_t cbpending[QEMU_CLIPBOARD_SELECTION__COUNT];
+=C2=A0 =C2=A0 GtkClipboard *gtkcb[QEMU_CLIPBOARD_SELECTION__COUNT];
+
=C2=A0 =C2=A0 =C2=A0DisplayOptions *opts;
=C2=A0};

@@ -208,4 +214,7 @@ QEMUGLContext gd_gl_area_get_current_context(DisplayCha= ngeListener *dcl);
=C2=A0int gd_gl_area_make_current(DisplayChangeListener *dcl,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0QEMUGLContext ctx);

+/* gtk-clipboard.c */
+void gd_clipboard_init(GtkDisplayState *gd);
+
=C2=A0#endif /* UI_GTK_H */
diff --git a/ui/gtk-clipboard.c b/ui/gtk-clipboard.c
new file mode 100644
index 000000000000..4a7f44b25818
--- /dev/null
+++ b/ui/gtk-clipboard.c
@@ -0,0 +1,124 @@
+/*
+ * GTK UI -- clipboard support
+ *
+ * Copyright (C) 2021 Gerd Hoffmann <kraxel@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.=C2=A0 See the GNU<= br> + * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses= />.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+
+#include "ui/gtk.h"
+
+static void gd_clipboard_notify(Notifier *notifier, void *data)
+{
+=C2=A0 =C2=A0 GtkDisplayState *gd =3D container_of(notifier, GtkDisplaySta= te, cbpeer.update);
+=C2=A0 =C2=A0 QemuClipboardInfo *info =3D data;
+=C2=A0 =C2=A0 QemuClipboardSelection s =3D info->selection;
+=C2=A0 =C2=A0 bool self_update =3D info->owner =3D=3D &gd->cbpee= r;
+
+=C2=A0 =C2=A0 if (info !=3D gd->cbinfo[s]) {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 qemu_clipboard_info_put(gd->cbinfo[s]);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 gd->cbinfo[s] =3D qemu_clipboard_info_get(i= nfo);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 gd->cbpending[s] =3D 0;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 if (!self_update) {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (info->types[QEMU_CLIPBOAR= D_TYPE_TEXT].available) {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 qemu_clipboard_req= uest(info, QEMU_CLIPBOARD_TYPE_TEXT);

A= lways requesting the clipboard is a bit harsh, isn't it?
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 }
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 }
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 return;
+=C2=A0 =C2=A0 }
+
+=C2=A0 =C2=A0 if (self_update) {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 return;
+=C2=A0 =C2=A0 }
+
+=C2=A0 =C2=A0 if (info->types[QEMU_CLIPBOARD_TYPE_TEXT].available &= &
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 info->types[QEMU_CLIPBOARD_TYPE_TEXT].data)= {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 gtk_clipboard_set_text(gd->gtkcb[s],
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0info->types[QEMU_CLIPBOARD_TYPE_TE= XT].data,
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0info->types[QEMU_CLIPBOARD_TYPE_TE= XT].size);
+=C2=A0 =C2=A0 }
+}
+
+static void gd_clipboard_request(QemuClipboardInfo *info,
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0QemuClipboardType type)
+{
+=C2=A0 =C2=A0 GtkDisplayState *gd =3D container_of(info->owner, GtkDisp= layState, cbpeer);
+=C2=A0 =C2=A0 char *text;
+
+=C2=A0 =C2=A0 switch (type) {
+=C2=A0 =C2=A0 case QEMU_CLIPBOARD_TYPE_TEXT:
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 text =3D gtk_clipboard_wait_for_text(gd->gt= kcb[info->selection]);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 qemu_clipboard_set_data(&gd->cbpeer, in= fo, type,
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 strlen(text), text, true);

text might be NULL if it failed.

<= /div>
And you must free it.

+=C2=A0 =C2=A0 =C2=A0 =C2=A0 break;
+=C2=A0 =C2=A0 default:
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 break;
+=C2=A0 =C2=A0 }
+}
+
+static QemuClipboardSelection gd_find_selection(GtkDisplayState *gd,
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 GtkClipboard *clipboard)
+{
+=C2=A0 =C2=A0 QemuClipboardSelection s;
+
+=C2=A0 =C2=A0 for (s =3D 0; s < QEMU_CLIPBOARD_SELECTION__COUNT; s++) {=
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 if (gd->gtkcb[s] =3D=3D clipboard) {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return s;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 }
+=C2=A0 =C2=A0 }
+=C2=A0 =C2=A0 return QEMU_CLIPBOARD_SELECTION_CLIPBOARD;
+}
+
+static void gd_owner_change(GtkClipboard *clipboard,
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 GdkEvent *event,
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 gpointer data)
+{
+=C2=A0 =C2=A0 GtkDisplayState *gd =3D data;
+=C2=A0 =C2=A0 QemuClipboardSelection s =3D gd_find_selection(gd, clipboard= );
+=C2=A0 =C2=A0 QemuClipboardInfo *info;
+
+=C2=A0 =C2=A0 info =3D qemu_clipboard_info_new(&gd->cbpeer, s);
+=C2=A0 =C2=A0 if (gtk_clipboard_wait_is_text_available(clipboard)) {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 info->types[QEMU_CLIPBOARD_TYPE_TEXT].avail= able =3D true;
+=C2=A0 =C2=A0 }

Hmm, so after gtk_clipboard= _set_text() the client side is actually taking the ownership away from the = guest clipboard I presume. That might have some weird interaction issues. H= opefully the other side isn't playing the same game...

+
+=C2=A0 =C2=A0 qemu_clipboard_update(info);
+=C2=A0 =C2=A0 qemu_clipboard_info_put(info);
+}
+
+void gd_clipboard_init(GtkDisplayState *gd)
+{
+=C2=A0 =C2=A0 gd->cbpeer.name =3D "gtk";
+=C2=A0 =C2=A0 gd->cbpeer.update.notify =3D gd_clipboard_notify;
+=C2=A0 =C2=A0 gd->cbpeer.request =3D gd_clipboard_request;
+=C2=A0 =C2=A0 qemu_clipboard_peer_register(&gd->cbpeer);
+
+=C2=A0 =C2=A0 gd->gtkcb[QEMU_CLIPBOARD_SELECTION_CLIPBOARD] =3D
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 gtk_clipboard_get(gdk_atom_intern("CLIPBO= ARD", FALSE));

GDK_SELECTION_CLIPB= OARD
=C2=A0
+
+=C2=A0 =C2=A0 g_signal_connect(gd->gtkcb[QEMU_CLIPBOARD_SELECTION_CLIPB= OARD],
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0"owner-change", G_CALLBACK(gd_owner_change), gd);
+=C2=A0 =C2=A0 g_signal_connect(gd->gtkcb[QEMU_CLIPBOARD_SELECTION_PRIMA= RY],
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0"owner-change", G_CALLBACK(gd_owner_change), gd);
+=C2=A0 =C2=A0 g_signal_connect(gd->gtkcb[QEMU_CLIPBOARD_SELECTION_SECON= DARY],
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0"owner-change", G_CALLBACK(gd_owner_change), gd);


Might be worth having a d= einit for signals, peer registration etc, even if nothing is hooked yet in = gtk.c..

Overall, calling wait & set variants o= f clipboard functions makes things quite simpler to deal with. Hopefully it= can stay that way...

+}
diff --git a/ui/gtk.c b/ui/gtk.c
index 7b412dd4fe0b..0ae3ec20f594 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -2252,6 +2252,7 @@ static void gtk_display_init(DisplayState *ds, Displa= yOptions *opts)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0opts->u.gtk.grab_on_hover) {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0gtk_menu_item_activate(GTK_MENU_ITEM(s-&g= t;grab_on_hover_item));
=C2=A0 =C2=A0 =C2=A0}
+=C2=A0 =C2=A0 gd_clipboard_init(s);
=C2=A0}

=C2=A0static void early_gtk_display_init(DisplayOptions *opts)
diff --git a/ui/meson.build b/ui/meson.build
index a98f89b48978..3ea969a6210b 100644
--- a/ui/meson.build
+++ b/ui/meson.build
@@ -64,7 +64,7 @@ if gtk.found()
=C2=A0 =C2=A0softmmu_ss.add(when: 'CONFIG_WIN32', if_true: files(&#= 39;win32-kbd-hook.c'))

=C2=A0 =C2=A0gtk_ss =3D ss.source_set()
-=C2=A0 gtk_ss.add(gtk, vte, pixman, files('gtk.c'))
+=C2=A0 gtk_ss.add(gtk, vte, pixman, files('gtk.c', 'gtk-clipbo= ard.c'))
=C2=A0 =C2=A0gtk_ss.add(when: x11, if_true: files('x_keymap.c')) =C2=A0 =C2=A0gtk_ss.add(when: [opengl, 'CONFIG_OPENGL'], if_true: f= iles('gtk-egl.c', 'gtk-gl-area.c'))
=C2=A0 =C2=A0ui_modules +=3D {'gtk' : gtk_ss}
--
2.29.2




--
Marc-Andr=C3=A9 Lureau
--000000000000fd69ed05bc2e637a--