xref: /openbmc/qemu/ui/clipboard.c (revision 72ce36f77ca6fe8cf9aae5ed28d7c3c865ef887d)
1660e8d0fSGerd Hoffmann #include "qemu/osdep.h"
2660e8d0fSGerd Hoffmann #include "ui/clipboard.h"
3410840cdSMarc-André Lureau #include "trace.h"
4660e8d0fSGerd Hoffmann 
5660e8d0fSGerd Hoffmann static NotifierList clipboard_notifiers =
6660e8d0fSGerd Hoffmann     NOTIFIER_LIST_INITIALIZER(clipboard_notifiers);
7660e8d0fSGerd Hoffmann 
8684e64d3SMarc-André Lureau static QemuClipboardInfo *cbinfo[QEMU_CLIPBOARD_SELECTION__COUNT];
9684e64d3SMarc-André Lureau 
10660e8d0fSGerd Hoffmann void qemu_clipboard_peer_register(QemuClipboardPeer *peer)
11660e8d0fSGerd Hoffmann {
121b17f1e9SMarc-André Lureau     notifier_list_add(&clipboard_notifiers, &peer->notifier);
13660e8d0fSGerd Hoffmann }
14660e8d0fSGerd Hoffmann 
15660e8d0fSGerd Hoffmann void qemu_clipboard_peer_unregister(QemuClipboardPeer *peer)
16660e8d0fSGerd Hoffmann {
177424bfaaSMarc-André Lureau     int i;
187424bfaaSMarc-André Lureau 
197424bfaaSMarc-André Lureau     for (i = 0; i < QEMU_CLIPBOARD_SELECTION__COUNT; i++) {
207424bfaaSMarc-André Lureau         qemu_clipboard_peer_release(peer, i);
217424bfaaSMarc-André Lureau     }
221b17f1e9SMarc-André Lureau     notifier_remove(&peer->notifier);
23660e8d0fSGerd Hoffmann }
24660e8d0fSGerd Hoffmann 
25482bbaf4SMarc-André Lureau bool qemu_clipboard_peer_owns(QemuClipboardPeer *peer,
26482bbaf4SMarc-André Lureau                               QemuClipboardSelection selection)
27482bbaf4SMarc-André Lureau {
28482bbaf4SMarc-André Lureau     QemuClipboardInfo *info = qemu_clipboard_info(selection);
29482bbaf4SMarc-André Lureau 
30482bbaf4SMarc-André Lureau     return info && info->owner == peer;
31482bbaf4SMarc-André Lureau }
32482bbaf4SMarc-André Lureau 
331387865eSMarc-André Lureau void qemu_clipboard_peer_release(QemuClipboardPeer *peer,
341387865eSMarc-André Lureau                                  QemuClipboardSelection selection)
351387865eSMarc-André Lureau {
361387865eSMarc-André Lureau     g_autoptr(QemuClipboardInfo) info = NULL;
371387865eSMarc-André Lureau 
381387865eSMarc-André Lureau     if (qemu_clipboard_peer_owns(peer, selection)) {
391387865eSMarc-André Lureau         /* set empty clipboard info */
401387865eSMarc-André Lureau         info = qemu_clipboard_info_new(NULL, selection);
411387865eSMarc-André Lureau         qemu_clipboard_update(info);
421387865eSMarc-André Lureau     }
431387865eSMarc-André Lureau }
441387865eSMarc-André Lureau 
45349504e5SMarc-André Lureau bool qemu_clipboard_check_serial(QemuClipboardInfo *info, bool client)
46349504e5SMarc-André Lureau {
47410840cdSMarc-André Lureau     bool ok;
48410840cdSMarc-André Lureau 
49349504e5SMarc-André Lureau     if (!info->has_serial ||
50349504e5SMarc-André Lureau         !cbinfo[info->selection] ||
51349504e5SMarc-André Lureau         !cbinfo[info->selection]->has_serial) {
52410840cdSMarc-André Lureau         trace_clipboard_check_serial(-1, -1, true);
53349504e5SMarc-André Lureau         return true;
54349504e5SMarc-André Lureau     }
55349504e5SMarc-André Lureau 
56349504e5SMarc-André Lureau     if (client) {
570e23ae9cSMarc-André Lureau         ok = info->serial >= cbinfo[info->selection]->serial;
58349504e5SMarc-André Lureau     } else {
590e23ae9cSMarc-André Lureau         ok = info->serial > cbinfo[info->selection]->serial;
60349504e5SMarc-André Lureau     }
61410840cdSMarc-André Lureau 
62410840cdSMarc-André Lureau     trace_clipboard_check_serial(cbinfo[info->selection]->serial, info->serial, ok);
63410840cdSMarc-André Lureau     return ok;
64349504e5SMarc-André Lureau }
65349504e5SMarc-André Lureau 
66660e8d0fSGerd Hoffmann void qemu_clipboard_update(QemuClipboardInfo *info)
67660e8d0fSGerd Hoffmann {
681b17f1e9SMarc-André Lureau     QemuClipboardNotify notify = {
691b17f1e9SMarc-André Lureau         .type = QEMU_CLIPBOARD_UPDATE_INFO,
701b17f1e9SMarc-André Lureau         .info = info,
711b17f1e9SMarc-André Lureau     };
72684e64d3SMarc-André Lureau     assert(info->selection < QEMU_CLIPBOARD_SELECTION__COUNT);
73684e64d3SMarc-André Lureau 
741b17f1e9SMarc-André Lureau     notifier_list_notify(&clipboard_notifiers, &notify);
75684e64d3SMarc-André Lureau 
7602a8ee2eSMarc-André Lureau     if (cbinfo[info->selection] != info) {
7770a54b01SDaniel P. Berrangé         qemu_clipboard_info_unref(cbinfo[info->selection]);
78684e64d3SMarc-André Lureau         cbinfo[info->selection] = qemu_clipboard_info_ref(info);
79684e64d3SMarc-André Lureau     }
8002a8ee2eSMarc-André Lureau }
81684e64d3SMarc-André Lureau 
82684e64d3SMarc-André Lureau QemuClipboardInfo *qemu_clipboard_info(QemuClipboardSelection selection)
83684e64d3SMarc-André Lureau {
84684e64d3SMarc-André Lureau     assert(selection < QEMU_CLIPBOARD_SELECTION__COUNT);
85684e64d3SMarc-André Lureau 
86684e64d3SMarc-André Lureau     return cbinfo[selection];
87660e8d0fSGerd Hoffmann }
88660e8d0fSGerd Hoffmann 
89660e8d0fSGerd Hoffmann QemuClipboardInfo *qemu_clipboard_info_new(QemuClipboardPeer *owner,
90660e8d0fSGerd Hoffmann                                            QemuClipboardSelection selection)
91660e8d0fSGerd Hoffmann {
92660e8d0fSGerd Hoffmann     QemuClipboardInfo *info = g_new0(QemuClipboardInfo, 1);
93660e8d0fSGerd Hoffmann 
94660e8d0fSGerd Hoffmann     info->owner = owner;
95660e8d0fSGerd Hoffmann     info->selection = selection;
96660e8d0fSGerd Hoffmann     info->refcount = 1;
97660e8d0fSGerd Hoffmann 
98660e8d0fSGerd Hoffmann     return info;
99660e8d0fSGerd Hoffmann }
100660e8d0fSGerd Hoffmann 
101660e8d0fSGerd Hoffmann QemuClipboardInfo *qemu_clipboard_info_ref(QemuClipboardInfo *info)
102660e8d0fSGerd Hoffmann {
103660e8d0fSGerd Hoffmann     info->refcount++;
104660e8d0fSGerd Hoffmann     return info;
105660e8d0fSGerd Hoffmann }
106660e8d0fSGerd Hoffmann 
107660e8d0fSGerd Hoffmann void qemu_clipboard_info_unref(QemuClipboardInfo *info)
108660e8d0fSGerd Hoffmann {
109660e8d0fSGerd Hoffmann     uint32_t type;
110660e8d0fSGerd Hoffmann 
111660e8d0fSGerd Hoffmann     if (!info) {
112660e8d0fSGerd Hoffmann         return;
113660e8d0fSGerd Hoffmann     }
114660e8d0fSGerd Hoffmann 
115660e8d0fSGerd Hoffmann     info->refcount--;
116660e8d0fSGerd Hoffmann     if (info->refcount > 0) {
117660e8d0fSGerd Hoffmann         return;
118660e8d0fSGerd Hoffmann     }
119660e8d0fSGerd Hoffmann 
120660e8d0fSGerd Hoffmann     for (type = 0; type < QEMU_CLIPBOARD_TYPE__COUNT; type++) {
121660e8d0fSGerd Hoffmann         g_free(info->types[type].data);
122660e8d0fSGerd Hoffmann     }
123660e8d0fSGerd Hoffmann     g_free(info);
124660e8d0fSGerd Hoffmann }
125660e8d0fSGerd Hoffmann 
126660e8d0fSGerd Hoffmann void qemu_clipboard_request(QemuClipboardInfo *info,
127660e8d0fSGerd Hoffmann                             QemuClipboardType type)
128660e8d0fSGerd Hoffmann {
129660e8d0fSGerd Hoffmann     if (info->types[type].data ||
130660e8d0fSGerd Hoffmann         info->types[type].requested ||
131660e8d0fSGerd Hoffmann         !info->types[type].available ||
132660e8d0fSGerd Hoffmann         !info->owner)
133660e8d0fSGerd Hoffmann         return;
134660e8d0fSGerd Hoffmann 
135660e8d0fSGerd Hoffmann     info->types[type].requested = true;
136660e8d0fSGerd Hoffmann     info->owner->request(info, type);
137660e8d0fSGerd Hoffmann }
138660e8d0fSGerd Hoffmann 
139505dbf9bSMarc-André Lureau void qemu_clipboard_reset_serial(void)
140505dbf9bSMarc-André Lureau {
141505dbf9bSMarc-André Lureau     QemuClipboardNotify notify = { .type = QEMU_CLIPBOARD_RESET_SERIAL };
142*72ce36f7SMarc-André Lureau     int i;
143505dbf9bSMarc-André Lureau 
144*72ce36f7SMarc-André Lureau     for (i = 0; i < QEMU_CLIPBOARD_SELECTION__COUNT; i++) {
145*72ce36f7SMarc-André Lureau         QemuClipboardInfo *info = qemu_clipboard_info(i);
146*72ce36f7SMarc-André Lureau         if (info) {
147*72ce36f7SMarc-André Lureau             info->serial = 0;
148*72ce36f7SMarc-André Lureau         }
149*72ce36f7SMarc-André Lureau     }
150505dbf9bSMarc-André Lureau     notifier_list_notify(&clipboard_notifiers, &notify);
151505dbf9bSMarc-André Lureau }
152505dbf9bSMarc-André Lureau 
153660e8d0fSGerd Hoffmann void qemu_clipboard_set_data(QemuClipboardPeer *peer,
154660e8d0fSGerd Hoffmann                              QemuClipboardInfo *info,
155660e8d0fSGerd Hoffmann                              QemuClipboardType type,
156660e8d0fSGerd Hoffmann                              uint32_t size,
1577e3e20d8SAkihiko Odaki                              const void *data,
158660e8d0fSGerd Hoffmann                              bool update)
159660e8d0fSGerd Hoffmann {
160660e8d0fSGerd Hoffmann     if (!info ||
161660e8d0fSGerd Hoffmann         info->owner != peer) {
162660e8d0fSGerd Hoffmann         return;
163660e8d0fSGerd Hoffmann     }
164660e8d0fSGerd Hoffmann 
165660e8d0fSGerd Hoffmann     g_free(info->types[type].data);
166660e8d0fSGerd Hoffmann     info->types[type].data = g_memdup(data, size);
167660e8d0fSGerd Hoffmann     info->types[type].size = size;
168660e8d0fSGerd Hoffmann     info->types[type].available = true;
169660e8d0fSGerd Hoffmann 
170660e8d0fSGerd Hoffmann     if (update) {
171660e8d0fSGerd Hoffmann         qemu_clipboard_update(info);
172660e8d0fSGerd Hoffmann     }
173660e8d0fSGerd Hoffmann }
174