diff --git a/include/ui/clipboard.h b/include/ui/clipboard.h
index 6298986b15..d82cf31481 100644
--- a/include/ui/clipboard.h
+++ b/include/ui/clipboard.h
@@ -20,8 +20,10 @@
  */
 
 typedef enum QemuClipboardType QemuClipboardType;
+typedef enum QemuClipboardNotifyType QemuClipboardNotifyType;
 typedef enum QemuClipboardSelection QemuClipboardSelection;
 typedef struct QemuClipboardPeer QemuClipboardPeer;
+typedef struct QemuClipboardNotify QemuClipboardNotify;
 typedef struct QemuClipboardInfo QemuClipboardInfo;
 
 /**
@@ -55,18 +57,44 @@ enum QemuClipboardSelection {
  * struct QemuClipboardPeer
  *
  * @name: peer name.
- * @update: notifier for clipboard updates.
+ * @notifier: notifier for clipboard updates.
  * @request: callback for clipboard data requests.
  *
  * Clipboard peer description.
  */
 struct QemuClipboardPeer {
     const char *name;
-    Notifier update;
+    Notifier notifier;
     void (*request)(QemuClipboardInfo *info,
                     QemuClipboardType type);
 };
 
+/**
+ * enum QemuClipboardNotifyType
+ *
+ * @QEMU_CLIPBOARD_UPDATE_INFO: clipboard info update
+ *
+ * Clipboard notify type.
+ */
+enum QemuClipboardNotifyType {
+    QEMU_CLIPBOARD_UPDATE_INFO,
+};
+
+/**
+ * struct QemuClipboardNotify
+ *
+ * @type: the type of event.
+ * @info: a QemuClipboardInfo event.
+ *
+ * Clipboard notify data.
+ */
+struct QemuClipboardNotify {
+    QemuClipboardNotifyType type;
+    union {
+        QemuClipboardInfo *info;
+    };
+};
+
 /**
  * struct QemuClipboardInfo
  *
diff --git a/ui/clipboard.c b/ui/clipboard.c
index d7b008d62a..743b39edf4 100644
--- a/ui/clipboard.c
+++ b/ui/clipboard.c
@@ -8,7 +8,7 @@ static QemuClipboardInfo *cbinfo[QEMU_CLIPBOARD_SELECTION__COUNT];
 
 void qemu_clipboard_peer_register(QemuClipboardPeer *peer)
 {
-    notifier_list_add(&clipboard_notifiers, &peer->update);
+    notifier_list_add(&clipboard_notifiers, &peer->notifier);
 }
 
 void qemu_clipboard_peer_unregister(QemuClipboardPeer *peer)
@@ -18,8 +18,7 @@ void qemu_clipboard_peer_unregister(QemuClipboardPeer *peer)
     for (i = 0; i < QEMU_CLIPBOARD_SELECTION__COUNT; i++) {
         qemu_clipboard_peer_release(peer, i);
     }
-
-    notifier_remove(&peer->update);
+    notifier_remove(&peer->notifier);
 }
 
 bool qemu_clipboard_peer_owns(QemuClipboardPeer *peer,
@@ -44,10 +43,15 @@ void qemu_clipboard_peer_release(QemuClipboardPeer *peer,
 
 void qemu_clipboard_update(QemuClipboardInfo *info)
 {
+    QemuClipboardNotify notify = {
+        .type = QEMU_CLIPBOARD_UPDATE_INFO,
+        .info = info,
+    };
     g_autoptr(QemuClipboardInfo) old = NULL;
+
     assert(info->selection < QEMU_CLIPBOARD_SELECTION__COUNT);
 
-    notifier_list_notify(&clipboard_notifiers, info);
+    notifier_list_notify(&clipboard_notifiers, &notify);
 
     old = cbinfo[info->selection];
     cbinfo[info->selection] = qemu_clipboard_info_ref(info);
diff --git a/ui/gtk-clipboard.c b/ui/gtk-clipboard.c
index 35b7a2c228..44ff810234 100644
--- a/ui/gtk-clipboard.c
+++ b/ui/gtk-clipboard.c
@@ -74,10 +74,9 @@ static void gd_clipboard_clear(GtkClipboard *clipboard,
     gd->cbowner[s] = false;
 }
 
-static void gd_clipboard_notify(Notifier *notifier, void *data)
+static void gd_clipboard_update_info(GtkDisplayState *gd,
+                                     QemuClipboardInfo *info)
 {
-    GtkDisplayState *gd = container_of(notifier, GtkDisplayState, cbpeer.update);
-    QemuClipboardInfo *info = data;
     QemuClipboardSelection s = info->selection;
     bool self_update = info->owner == &gd->cbpeer;
 
@@ -118,6 +117,19 @@ static void gd_clipboard_notify(Notifier *notifier, void *data)
      */
 }
 
+static void gd_clipboard_notify(Notifier *notifier, void *data)
+{
+    GtkDisplayState *gd =
+        container_of(notifier, GtkDisplayState, cbpeer.notifier);
+    QemuClipboardNotify *notify = data;
+
+    switch (notify->type) {
+    case QEMU_CLIPBOARD_UPDATE_INFO:
+        gd_clipboard_update_info(gd, notify->info);
+        return;
+    }
+}
+
 static void gd_clipboard_request(QemuClipboardInfo *info,
                                  QemuClipboardType type)
 {
@@ -172,7 +184,7 @@ static void gd_owner_change(GtkClipboard *clipboard,
 void gd_clipboard_init(GtkDisplayState *gd)
 {
     gd->cbpeer.name = "gtk";
-    gd->cbpeer.update.notify = gd_clipboard_notify;
+    gd->cbpeer.notifier.notify = gd_clipboard_notify;
     gd->cbpeer.request = gd_clipboard_request;
     qemu_clipboard_peer_register(&gd->cbpeer);
 
diff --git a/ui/vdagent.c b/ui/vdagent.c
index 64e0017001..de827aad27 100644
--- a/ui/vdagent.c
+++ b/ui/vdagent.c
@@ -417,10 +417,9 @@ static void vdagent_send_empty_clipboard_data(VDAgentChardev *vd,
     vdagent_send_clipboard_data(vd, info, type);
 }
 
-static void vdagent_clipboard_notify(Notifier *notifier, void *data)
+static void vdagent_clipboard_update_info(VDAgentChardev *vd,
+                                          QemuClipboardInfo *info)
 {
-    VDAgentChardev *vd = container_of(notifier, VDAgentChardev, cbpeer.update);
-    QemuClipboardInfo *info = data;
     QemuClipboardSelection s = info->selection;
     QemuClipboardType type;
     bool self_update = info->owner == &vd->cbpeer;
@@ -449,6 +448,19 @@ static void vdagent_clipboard_notify(Notifier *notifier, void *data)
     }
 }
 
+static void vdagent_clipboard_notify(Notifier *notifier, void *data)
+{
+    VDAgentChardev *vd =
+        container_of(notifier, VDAgentChardev, cbpeer.notifier);
+    QemuClipboardNotify *notify = data;
+
+    switch (notify->type) {
+    case QEMU_CLIPBOARD_UPDATE_INFO:
+        vdagent_clipboard_update_info(vd, notify->info);
+        return;
+    }
+}
+
 static void vdagent_clipboard_request(QemuClipboardInfo *info,
                                       QemuClipboardType qtype)
 {
@@ -658,9 +670,9 @@ static void vdagent_chr_recv_caps(VDAgentChardev *vd, VDAgentMessage *msg)
     if (have_mouse(vd) && vd->mouse_hs) {
         qemu_input_handler_activate(vd->mouse_hs);
     }
-    if (have_clipboard(vd) && vd->cbpeer.update.notify == NULL) {
+    if (have_clipboard(vd) && vd->cbpeer.notifier.notify == NULL) {
         vd->cbpeer.name = "vdagent";
-        vd->cbpeer.update.notify = vdagent_clipboard_notify;
+        vd->cbpeer.notifier.notify = vdagent_clipboard_notify;
         vd->cbpeer.request = vdagent_clipboard_request;
         qemu_clipboard_peer_register(&vd->cbpeer);
     }
@@ -799,7 +811,7 @@ static void vdagent_disconnect(VDAgentChardev *vd)
     if (vd->mouse_hs) {
         qemu_input_handler_deactivate(vd->mouse_hs);
     }
-    if (vd->cbpeer.update.notify) {
+    if (vd->cbpeer.notifier.notify) {
         qemu_clipboard_peer_unregister(&vd->cbpeer);
         memset(&vd->cbpeer, 0, sizeof(vd->cbpeer));
     }
@@ -807,11 +819,8 @@ static void vdagent_disconnect(VDAgentChardev *vd)
 
 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();
-        vdagent_disconnect(vd);
         return;
     }
 
diff --git a/ui/vnc-clipboard.c b/ui/vnc-clipboard.c
index 9f077965d0..41aeff1085 100644
--- a/ui/vnc-clipboard.c
+++ b/ui/vnc-clipboard.c
@@ -189,10 +189,8 @@ static void vnc_clipboard_provide(VncState *vs,
     vnc_flush(vs);
 }
 
-static void vnc_clipboard_notify(Notifier *notifier, void *data)
+static void vnc_clipboard_update_info(VncState *vs, QemuClipboardInfo *info)
 {
-    VncState *vs = container_of(notifier, VncState, cbpeer.update);
-    QemuClipboardInfo *info = data;
     QemuClipboardType type;
     bool self_update = info->owner == &vs->cbpeer;
     uint32_t flags = 0;
@@ -223,6 +221,18 @@ static void vnc_clipboard_notify(Notifier *notifier, void *data)
     }
 }
 
+static void vnc_clipboard_notify(Notifier *notifier, void *data)
+{
+    VncState *vs = container_of(notifier, VncState, cbpeer.notifier);
+    QemuClipboardNotify *notify = data;
+
+    switch (notify->type) {
+    case QEMU_CLIPBOARD_UPDATE_INFO:
+        vnc_clipboard_update_info(vs, notify->info);
+        return;
+    }
+}
+
 static void vnc_clipboard_request(QemuClipboardInfo *info,
                                   QemuClipboardType type)
 {
@@ -317,7 +327,7 @@ void vnc_server_cut_text_caps(VncState *vs)
     vnc_clipboard_send(vs, 2, caps);
 
     vs->cbpeer.name = "vnc";
-    vs->cbpeer.update.notify = vnc_clipboard_notify;
+    vs->cbpeer.notifier.notify = vnc_clipboard_notify;
     vs->cbpeer.request = vnc_clipboard_request;
     qemu_clipboard_peer_register(&vs->cbpeer);
 }
diff --git a/ui/vnc.c b/ui/vnc.c
index af02522e84..9b603382e7 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -1354,7 +1354,7 @@ void vnc_disconnect_finish(VncState *vs)
         /* last client gone */
         vnc_update_server_surface(vs->vd);
     }
-    if (vs->cbpeer.update.notify) {
+    if (vs->cbpeer.notifier.notify) {
         qemu_clipboard_peer_unregister(&vs->cbpeer);
     }
 
diff --git a/ui/cocoa.m b/ui/cocoa.m
index 68a6302184..6745e3fc8c 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -1808,14 +1808,12 @@ static void cocoa_clipboard_request(QemuClipboardInfo *info,
 
 static QemuClipboardPeer cbpeer = {
     .name = "cocoa",
-    .update = { .notify = cocoa_clipboard_notify },
+    .notifier = { .notify = cocoa_clipboard_notify },
     .request = cocoa_clipboard_request
 };
 
-static void cocoa_clipboard_notify(Notifier *notifier, void *data)
+static void cocoa_clipboard_update_info(QemuClipboardInfo *info)
 {
-    QemuClipboardInfo *info = data;
-
     if (info->owner == &cbpeer || info->selection != QEMU_CLIPBOARD_SELECTION_CLIPBOARD) {
         return;
     }
@@ -1831,6 +1829,17 @@ static void cocoa_clipboard_notify(Notifier *notifier, void *data)
     qemu_event_set(&cbevent);
 }
 
+static void cocoa_clipboard_notify(Notifier *notifier, void *data)
+{
+    QemuClipboardNotify *notify = data;
+
+    switch (notify->event) {
+    case QEMU_CLIPBOARD_UPDATE_INFO:
+        cocoa_clipboard_update_info(notify->info);
+        return;
+    }
+}
+
 static void cocoa_clipboard_request(QemuClipboardInfo *info,
                                     QemuClipboardType type)
 {
