Commit bcd94dccb1 for qemu.org

commit bcd94dccb1aab3416981bff89dc97a4f60d4e9ee
Author: Lukasz Kornicki <lucas.kornicki@nutanix.com>
Date:   Fri Oct 30 15:14:40 2026 +0100

    ui/clipboard: keep track of clipboard peer side

    Add a "guest" flag to QemuClipboardPeer and set it on vdagent peer.

    Use the flag to keep track of number of registered guest peers and
    allow to query for their presence with
    qemu_clipboard_guest_peer_present().

    This change makes it possible for a clipboard peer to determine if
    any guest side peers are present so they can tell whether a guest is
    actually able to participate in clipboard exchange.

    Signed-off-by: Lukasz Kornicki <lucas.kornicki@nutanix.com>
    Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
    Message-ID: <20261030141442.264308-3-lucas.kornicki@nutanix.com>

diff --git a/include/ui/clipboard.h b/include/ui/clipboard.h
index 6166af5139..250f1d8ea5 100644
--- a/include/ui/clipboard.h
+++ b/include/ui/clipboard.h
@@ -62,6 +62,7 @@ enum QemuClipboardSelection {
  * struct QemuClipboardPeer
  *
  * @name: peer name.
+ * @guest: is peer guest side.
  * @notifier: notifier for clipboard updates.
  * @request: callback for clipboard data requests.
  *
@@ -69,6 +70,7 @@ enum QemuClipboardSelection {
  */
 struct QemuClipboardPeer {
     const char *name;
+    bool guest;
     Notifier notifier;
     void (*request)(QemuClipboardInfo *info,
                     QemuClipboardType type);
@@ -179,6 +181,13 @@ void qemu_clipboard_peer_register(QemuClipboardPeer *peer);
  */
 void qemu_clipboard_peer_unregister(QemuClipboardPeer *peer);

+/**
+ * qemu_clipboard_guest_peer_present
+ *
+ * Return TRUE if a guest side clipboard peer is currently registered.
+ */
+bool qemu_clipboard_guest_peer_present(void);
+
 /**
  * qemu_clipboard_peer_owns
  *
diff --git a/ui/clipboard.c b/ui/clipboard.c
index 3d8f58a855..f750b494eb 100644
--- a/ui/clipboard.c
+++ b/ui/clipboard.c
@@ -12,6 +12,8 @@ static VMChangeStateEntry *cb_change_state_entry = NULL;

 static bool cb_reset_serial_on_resume = false;

+static int guest_peer_count;
+
 static const VMStateDescription vmstate_cbcontent = {
     .name = "clipboard/content",
     .version_id = 0,
@@ -80,6 +82,10 @@ void qemu_clipboard_peer_register(QemuClipboardPeer *peer)
         cb_change_state_entry = qemu_add_vm_change_state_handler(qemu_clipboard_change_state, NULL);
     }

+    if (peer->guest) {
+        guest_peer_count++;
+    }
+
     notifier_list_add(&clipboard_notifiers, &peer->notifier);
     qemu_clipboard_notify_peer_update(peer, true);
 }
@@ -92,6 +98,12 @@ void qemu_clipboard_peer_unregister(QemuClipboardPeer *peer)
         qemu_clipboard_peer_release(peer, i);
     }
     notifier_remove(&peer->notifier);
+
+    if (peer->guest) {
+        assert(guest_peer_count > 0);
+        guest_peer_count--;
+    }
+
     qemu_clipboard_notify_peer_update(peer, false);

     if (QLIST_EMPTY(&clipboard_notifiers.notifiers)) {
@@ -100,6 +112,11 @@ void qemu_clipboard_peer_unregister(QemuClipboardPeer *peer)
     }
 }

+bool qemu_clipboard_guest_peer_present(void)
+{
+    return guest_peer_count > 0;
+}
+
 bool qemu_clipboard_peer_owns(QemuClipboardPeer *peer,
                               QemuClipboardSelection selection)
 {
diff --git a/ui/vdagent.c b/ui/vdagent.c
index cc32a94fb9..cdd4cedad2 100644
--- a/ui/vdagent.c
+++ b/ui/vdagent.c
@@ -695,6 +695,7 @@ static void vdagent_clipboard_peer_register(VDAgentChardev *vd)
     }

     vd->cbpeer.name = "vdagent";
+    vd->cbpeer.guest = true;
     vd->cbpeer.notifier.notify = vdagent_clipboard_notify;
     vd->cbpeer.request = vdagent_clipboard_request;
     qemu_clipboard_peer_register(&vd->cbpeer);