:p
atchew
Login
The following patches change blocking clipboard retrieval function calls in gtk-clipboard.c to non-blocking variants using callbacks to avoid UI lockup. It is a follow-up to the patch proposed in the GitLab issue https://gitlab.com/qemu-project/qemu/-/work_items/1150 This version adds a similar change to gd_clipboard_request that also uses the blocking clipboard API. The second patch removes the gtk-clipboard flag, keeping the GTK clipboard always enabled. Signed-off-by: Jindrich Makovicka <makovick@gmail.com> --- Changes in v2: - Removed forgotten gtk-clipboard comment in meson_options.txt - Link to v1: https://lore.kernel.org/qemu-devel/20260425-gtk-clipboard-v1-0-6bd99e708e14@gmail.com --- Jindřich Makovička (2): ui/gtk: Use non-blocking clipboard retrieval ui/gtk: Keep GTK clipboard enabled meson.build | 4 ---- meson_options.txt | 7 ------- ui/gtk-clipboard.c | 47 ++++++++++++++++++++++++++++++++++------------- ui/gtk.c | 2 -- ui/meson.build | 4 +--- 5 files changed, 35 insertions(+), 29 deletions(-) --- base-commit: 4bde339ecb41b16e90810233ba5ee2fa87bd443f change-id: 20260425-gtk-clipboard-fdf99db13ac0 Best regards, -- Jindrich Makovicka
Signed-off-by: Jindrich Makovicka <makovick@gmail.com> --- ui/gtk-clipboard.c | 47 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/ui/gtk-clipboard.c b/ui/gtk-clipboard.c index XXXXXXX..XXXXXXX 100644 --- a/ui/gtk-clipboard.c +++ b/ui/gtk-clipboard.c @@ -XXX,XX +XXX,XX @@ static void gd_clipboard_notify(Notifier *notifier, void *data) } } +static void +gd_clipboard_request_text_received_callback(GtkClipboard *clipboard, + const gchar *text, + gpointer data) +{ + QemuClipboardInfo *info = (QemuClipboardInfo *)data; + if (text) { + qemu_clipboard_set_data(info->owner, info, QEMU_CLIPBOARD_TYPE_TEXT, + strlen(text), text, true); + } + qemu_clipboard_info_unref(info); +} + static void gd_clipboard_request(QemuClipboardInfo *info, QemuClipboardType type) { GtkDisplayState *gd = container_of(info->owner, GtkDisplayState, cbpeer); - char *text; switch (type) { case QEMU_CLIPBOARD_TYPE_TEXT: - text = gtk_clipboard_wait_for_text(gd->gtkcb[info->selection]); - if (text) { - qemu_clipboard_set_data(&gd->cbpeer, info, type, - strlen(text), text, true); - g_free(text); - } + qemu_clipboard_info_ref(info); + gtk_clipboard_request_text(gd->gtkcb[info->selection], + gd_clipboard_request_text_received_callback, + info); break; default: break; } } +static void +gd_clipboard_owner_change_text_received_callback(GtkClipboard *clipboard, + const gchar *text, + gpointer data) +{ + QemuClipboardInfo *info = (QemuClipboardInfo *)data; + if (text) { + info->types[QEMU_CLIPBOARD_TYPE_TEXT].available = true; + } + + qemu_clipboard_update(info); + qemu_clipboard_info_unref(info); +} + static void gd_owner_change(GtkClipboard *clipboard, GdkEvent *event, gpointer data) @@ -XXX,XX +XXX,XX @@ static void gd_owner_change(GtkClipboard *clipboard, switch (event->owner_change.reason) { 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; - } - - qemu_clipboard_update(info); - qemu_clipboard_info_unref(info); + gtk_clipboard_request_text(clipboard, + gd_clipboard_owner_change_text_received_callback, + info); break; default: qemu_clipboard_peer_release(&gd->cbpeer, s); -- 2.53.0
Signed-off-by: Jindrich Makovicka <makovick@gmail.com> --- meson.build | 4 ---- meson_options.txt | 7 ------- ui/gtk.c | 2 -- ui/meson.build | 4 +--- 4 files changed, 1 insertion(+), 16 deletions(-) diff --git a/meson.build b/meson.build index XXXXXXX..XXXXXXX 100644 --- a/meson.build +++ b/meson.build @@ -XXX,XX +XXX,XX @@ endif gtk = not_found gtkx11 = not_found vte = not_found -have_gtk_clipboard = get_option('gtk_clipboard').enabled() if get_option('gtk') \ .disable_auto_if(not have_system) \ @@ -XXX,XX +XXX,XX @@ if get_option('gtk') \ method: 'pkg-config', required: get_option('vte')) endif - elif have_gtk_clipboard - error('GTK clipboard requested, but GTK not found') endif endif @@ -XXX,XX +XXX,XX @@ if glusterfs.found() endif config_host_data.set('CONFIG_GTK', gtk.found()) config_host_data.set('CONFIG_VTE', vte.found()) -config_host_data.set('CONFIG_GTK_CLIPBOARD', have_gtk_clipboard) config_host_data.set('CONFIG_HEXAGON_IDEF_PARSER', get_option('hexagon_idef_parser')) config_host_data.set('CONFIG_LIBATTR', have_old_libattr) config_host_data.set('CONFIG_LIBCAP_NG', libcap_ng.found()) diff --git a/meson_options.txt b/meson_options.txt index XXXXXXX..XXXXXXX 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -XXX,XX +XXX,XX @@ option('vnc_sasl', type : 'feature', value : 'auto', description: 'SASL authentication for VNC server') option('vte', type : 'feature', value : 'auto', description: 'vte support for the gtk UI') - -# GTK Clipboard implementation is disabled by default, since it may cause hangs -# of the guest VCPUs. See gitlab issue 1150: -# https://gitlab.com/qemu-project/qemu/-/issues/1150 - -option('gtk_clipboard', type: 'feature', value : 'disabled', - description: 'clipboard support for the gtk UI (EXPERIMENTAL, MAY HANG)') option('xkbcommon', type : 'feature', value : 'auto', description: 'xkbcommon support') option('zstd', type : 'feature', value : 'auto', diff --git a/ui/gtk.c b/ui/gtk.c index XXXXXXX..XXXXXXX 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -XXX,XX +XXX,XX @@ static void gtk_display_init(DisplayState *ds, DisplayOptions *opts) opts->u.gtk.show_tabs) { gtk_menu_item_activate(GTK_MENU_ITEM(s->show_tabs_item)); } -#ifdef CONFIG_GTK_CLIPBOARD gd_clipboard_init(s); -#endif /* CONFIG_GTK_CLIPBOARD */ /* GTK's event polling must happen on the main thread. */ qemu_main = NULL; diff --git a/ui/meson.build b/ui/meson.build index XXXXXXX..XXXXXXX 100644 --- a/ui/meson.build +++ b/ui/meson.build @@ -XXX,XX +XXX,XX @@ if gtk.found() gtk_ss = ss.source_set() gtk_ss.add(gtk, vte, pixman, files('gtk.c')) - if have_gtk_clipboard - gtk_ss.add(files('gtk-clipboard.c')) - endif + gtk_ss.add(files('gtk-clipboard.c')) gtk_ss.add(when: x11, if_true: files('x_keymap.c')) gtk_ss.add(when: opengl, if_true: files('gtk-gl-area.c')) gtk_ss.add(when: [x11, opengl], if_true: files('gtk-egl.c')) -- 2.53.0
The following patches change blocking clipboard retrieval function calls in gtk-clipboard.c to non-blocking variants using callbacks to avoid UI lockup. It is a follow-up to the patch proposed in the GitLab issue https://gitlab.com/qemu-project/qemu/-/work_items/1150 This version adds a similar change to gd_clipboard_request that also uses the blocking clipboard API. The second patch removes the gtk-clipboard flag, keeping the GTK clipboard always enabled. Signed-off-by: Jindrich Makovicka <makovick@gmail.com> --- Changes in v3: - Use gtk_clipboard_request_contents to avoid text conversion when we only need to check if the text is available. - Link to v2: https://lore.kernel.org/qemu-devel/20260425-gtk-clipboard-v2-0-b098f3cf69cc@gmail.com Changes in v2: - Removed forgotten gtk-clipboard comment in meson_options.txt - Link to v1: https://lore.kernel.org/qemu-devel/20260425-gtk-clipboard-v1-0-6bd99e708e14@gmail.com --- Jindřich Makovička (2): ui/gtk: Use non-blocking clipboard retrieval ui/gtk: Keep GTK clipboard enabled meson.build | 4 ---- meson_options.txt | 7 ------- ui/gtk-clipboard.c | 52 +++++++++++++++++++++++++++++++++++++++------------- ui/gtk.c | 2 -- ui/meson.build | 4 +--- 5 files changed, 40 insertions(+), 29 deletions(-) --- base-commit: aa15257174da180c6a8a9d58f87319cfe61c5520 change-id: 20260425-gtk-clipboard-fdf99db13ac0 Best regards, -- Jindrich Makovicka
Signed-off-by: Jindrich Makovicka <makovick@gmail.com> --- ui/gtk-clipboard.c | 52 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/ui/gtk-clipboard.c b/ui/gtk-clipboard.c index XXXXXXX..XXXXXXX 100644 --- a/ui/gtk-clipboard.c +++ b/ui/gtk-clipboard.c @@ -XXX,XX +XXX,XX @@ static void gd_clipboard_notify(Notifier *notifier, void *data) } } +static void +gd_clipboard_request_text_received_callback(GtkClipboard *clipboard, + const gchar *text, + gpointer data) +{ + QemuClipboardInfo *info = (QemuClipboardInfo *)data; + + if (text) { + qemu_clipboard_set_data(info->owner, info, QEMU_CLIPBOARD_TYPE_TEXT, + strlen(text), text, true); + } + qemu_clipboard_info_unref(info); +} + static void gd_clipboard_request(QemuClipboardInfo *info, QemuClipboardType type) { GtkDisplayState *gd = container_of(info->owner, GtkDisplayState, cbpeer); - char *text; switch (type) { case QEMU_CLIPBOARD_TYPE_TEXT: - text = gtk_clipboard_wait_for_text(gd->gtkcb[info->selection]); - if (text) { - qemu_clipboard_set_data(&gd->cbpeer, info, type, - strlen(text), text, true); - g_free(text); - } + qemu_clipboard_info_ref(info); + gtk_clipboard_request_text(gd->gtkcb[info->selection], + gd_clipboard_request_text_received_callback, + info); break; default: break; } } +static void gd_clipboard_owner_change_contents_received_callback( + GtkClipboard *clipboard, + GtkSelectionData *selection_data, + gpointer data) +{ + QemuClipboardInfo *info = (QemuClipboardInfo *)data; + + if (selection_data) { + if (gtk_selection_data_targets_include_text(selection_data)) { + info->types[QEMU_CLIPBOARD_TYPE_TEXT].available = true; + } + } + + qemu_clipboard_update(info); + qemu_clipboard_info_unref(info); +} + static void gd_owner_change(GtkClipboard *clipboard, GdkEvent *event, gpointer data) @@ -XXX,XX +XXX,XX @@ static void gd_owner_change(GtkClipboard *clipboard, switch (event->owner_change.reason) { 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; - } - - qemu_clipboard_update(info); - qemu_clipboard_info_unref(info); + gtk_clipboard_request_contents( + clipboard, gdk_atom_intern_static_string("TARGETS"), + gd_clipboard_owner_change_contents_received_callback, + info); break; default: qemu_clipboard_peer_release(&gd->cbpeer, s); -- 2.53.0
Signed-off-by: Jindrich Makovicka <makovick@gmail.com> --- meson.build | 4 ---- meson_options.txt | 7 ------- ui/gtk.c | 2 -- ui/meson.build | 4 +--- 4 files changed, 1 insertion(+), 16 deletions(-) diff --git a/meson.build b/meson.build index XXXXXXX..XXXXXXX 100644 --- a/meson.build +++ b/meson.build @@ -XXX,XX +XXX,XX @@ endif gtk = not_found gtkx11 = not_found vte = not_found -have_gtk_clipboard = get_option('gtk_clipboard').enabled() if get_option('gtk') \ .disable_auto_if(not have_system) \ @@ -XXX,XX +XXX,XX @@ if get_option('gtk') \ method: 'pkg-config', required: get_option('vte')) endif - elif have_gtk_clipboard - error('GTK clipboard requested, but GTK not found') endif endif @@ -XXX,XX +XXX,XX @@ if glusterfs.found() endif config_host_data.set('CONFIG_GTK', gtk.found()) config_host_data.set('CONFIG_VTE', vte.found()) -config_host_data.set('CONFIG_GTK_CLIPBOARD', have_gtk_clipboard) config_host_data.set('CONFIG_HEXAGON_IDEF_PARSER', get_option('hexagon_idef_parser')) config_host_data.set('CONFIG_LIBATTR', have_old_libattr) config_host_data.set('CONFIG_LIBCAP_NG', libcap_ng.found()) diff --git a/meson_options.txt b/meson_options.txt index XXXXXXX..XXXXXXX 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -XXX,XX +XXX,XX @@ option('vnc_sasl', type : 'feature', value : 'auto', description: 'SASL authentication for VNC server') option('vte', type : 'feature', value : 'auto', description: 'vte support for the gtk UI') - -# GTK Clipboard implementation is disabled by default, since it may cause hangs -# of the guest VCPUs. See gitlab issue 1150: -# https://gitlab.com/qemu-project/qemu/-/issues/1150 - -option('gtk_clipboard', type: 'feature', value : 'disabled', - description: 'clipboard support for the gtk UI (EXPERIMENTAL, MAY HANG)') option('xkbcommon', type : 'feature', value : 'auto', description: 'xkbcommon support') option('zstd', type : 'feature', value : 'auto', diff --git a/ui/gtk.c b/ui/gtk.c index XXXXXXX..XXXXXXX 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -XXX,XX +XXX,XX @@ static void gtk_display_init(DisplayState *ds, DisplayOptions *opts) opts->u.gtk.show_tabs) { gtk_menu_item_activate(GTK_MENU_ITEM(s->show_tabs_item)); } -#ifdef CONFIG_GTK_CLIPBOARD gd_clipboard_init(s); -#endif /* CONFIG_GTK_CLIPBOARD */ /* GTK's event polling must happen on the main thread. */ qemu_main = NULL; diff --git a/ui/meson.build b/ui/meson.build index XXXXXXX..XXXXXXX 100644 --- a/ui/meson.build +++ b/ui/meson.build @@ -XXX,XX +XXX,XX @@ if gtk.found() gtk_ss = ss.source_set() gtk_ss.add(gtk, vte, pixman, files('gtk.c')) - if have_gtk_clipboard - gtk_ss.add(files('gtk-clipboard.c')) - endif + gtk_ss.add(files('gtk-clipboard.c')) gtk_ss.add(when: x11, if_true: files('x_keymap.c')) gtk_ss.add(when: opengl, if_true: files('gtk-gl-area.c')) gtk_ss.add(when: [x11, opengl], if_true: files('gtk-egl.c')) -- 2.53.0