Commit e5ef268596 for qemu.org

commit e5ef268596c33db43bf7ddedf23974af81d7315b
Author: GuoHan Zhao <zhaoguohan@kylinos.cn>
Date:   Mon Mar 30 17:13:10 2026 +0800

    ui/dbus: tear down clipboard callbacks on display finalize

    The clipboard D-Bus teardown path currently runs when the peer
    disappears, but not when DBusDisplay itself is finalized.

    That leaves pending clipboard requests and signal handlers associated
    with the clipboard proxy active past display teardown.

    Add an explicit clipboard fini hook and invoke it from
    dbus_display_finalize() so the clipboard teardown also runs during
    display destruction.

    bixes: ff1a5810f61f ("ui/dbus: add clipboard interface")
    Signed-off-by: GuoHan Zhao <zhaoguohan@kylinos.cn>
    Message-ID: <20260330091310.42868-1-zhaoguohan@kylinos.cn>
    [ Marc-André - Move clipobard finalization to the function]
    Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>

diff --git a/ui/dbus-clipboard.c b/ui/dbus-clipboard.c
index 6787a77668..935b6b1a2a 100644
--- a/ui/dbus-clipboard.c
+++ b/ui/dbus-clipboard.c
@@ -191,6 +191,7 @@ static void
 dbus_clipboard_unregister_proxy(DBusDisplay *dpy)
 {
     const char *name = NULL;
+    GDBusConnection *connection = NULL;
     int i;

     for (i = 0; i < G_N_ELEMENTS(dpy->clipboard_request); ++i) {
@@ -201,6 +202,13 @@ dbus_clipboard_unregister_proxy(DBusDisplay *dpy)
         return;
     }

+    connection = g_dbus_proxy_get_connection(
+        G_DBUS_PROXY(dpy->clipboard_proxy));
+    if (connection) {
+        g_signal_handlers_disconnect_by_data(connection, dpy);
+    }
+    g_signal_handlers_disconnect_by_data(dpy->clipboard_proxy, dpy);
+
     name = g_dbus_proxy_get_name(G_DBUS_PROXY(dpy->clipboard_proxy));
     trace_dbus_clipboard_unregister(name);
     g_clear_object(&dpy->clipboard_proxy);
@@ -425,6 +433,14 @@ dbus_clipboard_request(
     return DBUS_METHOD_INVOCATION_HANDLED;
 }

+void
+dbus_clipboard_fini(DBusDisplay *dpy)
+{
+    dbus_clipboard_unregister_proxy(dpy);
+    qemu_clipboard_peer_unregister(&dpy->clipboard_peer);
+    g_clear_object(&dpy->clipboard);
+}
+
 void
 dbus_clipboard_init(DBusDisplay *dpy)
 {
diff --git a/ui/dbus.c b/ui/dbus.c
index 7c54b6a502..794b65c4ad 100644
--- a/ui/dbus.c
+++ b/ui/dbus.c
@@ -145,8 +145,7 @@ dbus_display_finalize(Object *o)
         dbus_display_notifier_remove(&dd->notifier);
     }

-    qemu_clipboard_peer_unregister(&dd->clipboard_peer);
-    g_clear_object(&dd->clipboard);
+    dbus_clipboard_fini(dd);

     g_clear_object(&dd->server);
     g_clear_pointer(&dd->consoles, g_ptr_array_unref);
diff --git a/ui/dbus.h b/ui/dbus.h
index 1e8c24a48e..986d777460 100644
--- a/ui/dbus.h
+++ b/ui/dbus.h
@@ -150,5 +150,6 @@ void dbus_display_notify(DBusDisplayEvent *event);
 void dbus_chardev_init(DBusDisplay *dpy);

 void dbus_clipboard_init(DBusDisplay *dpy);
+void dbus_clipboard_fini(DBusDisplay *dpy);

 #endif /* UI_DBUS_H */