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 { 68*9c416582SFiona Ebner uint32_t type; 691b17f1e9SMarc-André Lureau QemuClipboardNotify notify = { 701b17f1e9SMarc-André Lureau .type = QEMU_CLIPBOARD_UPDATE_INFO, 711b17f1e9SMarc-André Lureau .info = info, 721b17f1e9SMarc-André Lureau }; 73684e64d3SMarc-André Lureau assert(info->selection < QEMU_CLIPBOARD_SELECTION__COUNT); 74684e64d3SMarc-André Lureau 75*9c416582SFiona Ebner for (type = 0; type < QEMU_CLIPBOARD_TYPE__COUNT; type++) { 76*9c416582SFiona Ebner /* 77*9c416582SFiona Ebner * If data is missing, the clipboard owner's 'request' callback needs to 78*9c416582SFiona Ebner * be set. Otherwise, there is no way to get the clipboard data and 79*9c416582SFiona Ebner * qemu_clipboard_request() cannot be called. 80*9c416582SFiona Ebner */ 81*9c416582SFiona Ebner if (info->types[type].available && !info->types[type].data) { 82*9c416582SFiona Ebner assert(info->owner && info->owner->request); 83*9c416582SFiona Ebner } 84*9c416582SFiona Ebner } 85*9c416582SFiona Ebner 861b17f1e9SMarc-André Lureau notifier_list_notify(&clipboard_notifiers, ¬ify); 87684e64d3SMarc-André Lureau 8802a8ee2eSMarc-André Lureau if (cbinfo[info->selection] != info) { 8970a54b01SDaniel P. Berrangé qemu_clipboard_info_unref(cbinfo[info->selection]); 90684e64d3SMarc-André Lureau cbinfo[info->selection] = qemu_clipboard_info_ref(info); 91684e64d3SMarc-André Lureau } 9202a8ee2eSMarc-André Lureau } 93684e64d3SMarc-André Lureau 94684e64d3SMarc-André Lureau QemuClipboardInfo *qemu_clipboard_info(QemuClipboardSelection selection) 95684e64d3SMarc-André Lureau { 96684e64d3SMarc-André Lureau assert(selection < QEMU_CLIPBOARD_SELECTION__COUNT); 97684e64d3SMarc-André Lureau 98684e64d3SMarc-André Lureau return cbinfo[selection]; 99660e8d0fSGerd Hoffmann } 100660e8d0fSGerd Hoffmann 101660e8d0fSGerd Hoffmann QemuClipboardInfo *qemu_clipboard_info_new(QemuClipboardPeer *owner, 102660e8d0fSGerd Hoffmann QemuClipboardSelection selection) 103660e8d0fSGerd Hoffmann { 104660e8d0fSGerd Hoffmann QemuClipboardInfo *info = g_new0(QemuClipboardInfo, 1); 105660e8d0fSGerd Hoffmann 106660e8d0fSGerd Hoffmann info->owner = owner; 107660e8d0fSGerd Hoffmann info->selection = selection; 108660e8d0fSGerd Hoffmann info->refcount = 1; 109660e8d0fSGerd Hoffmann 110660e8d0fSGerd Hoffmann return info; 111660e8d0fSGerd Hoffmann } 112660e8d0fSGerd Hoffmann 113660e8d0fSGerd Hoffmann QemuClipboardInfo *qemu_clipboard_info_ref(QemuClipboardInfo *info) 114660e8d0fSGerd Hoffmann { 115660e8d0fSGerd Hoffmann info->refcount++; 116660e8d0fSGerd Hoffmann return info; 117660e8d0fSGerd Hoffmann } 118660e8d0fSGerd Hoffmann 119660e8d0fSGerd Hoffmann void qemu_clipboard_info_unref(QemuClipboardInfo *info) 120660e8d0fSGerd Hoffmann { 121660e8d0fSGerd Hoffmann uint32_t type; 122660e8d0fSGerd Hoffmann 123660e8d0fSGerd Hoffmann if (!info) { 124660e8d0fSGerd Hoffmann return; 125660e8d0fSGerd Hoffmann } 126660e8d0fSGerd Hoffmann 127660e8d0fSGerd Hoffmann info->refcount--; 128660e8d0fSGerd Hoffmann if (info->refcount > 0) { 129660e8d0fSGerd Hoffmann return; 130660e8d0fSGerd Hoffmann } 131660e8d0fSGerd Hoffmann 132660e8d0fSGerd Hoffmann for (type = 0; type < QEMU_CLIPBOARD_TYPE__COUNT; type++) { 133660e8d0fSGerd Hoffmann g_free(info->types[type].data); 134660e8d0fSGerd Hoffmann } 135660e8d0fSGerd Hoffmann g_free(info); 136660e8d0fSGerd Hoffmann } 137660e8d0fSGerd Hoffmann 138660e8d0fSGerd Hoffmann void qemu_clipboard_request(QemuClipboardInfo *info, 139660e8d0fSGerd Hoffmann QemuClipboardType type) 140660e8d0fSGerd Hoffmann { 141660e8d0fSGerd Hoffmann if (info->types[type].data || 142660e8d0fSGerd Hoffmann info->types[type].requested || 143660e8d0fSGerd Hoffmann !info->types[type].available || 144660e8d0fSGerd Hoffmann !info->owner) 145660e8d0fSGerd Hoffmann return; 146660e8d0fSGerd Hoffmann 147*9c416582SFiona Ebner assert(info->owner->request); 148*9c416582SFiona Ebner 149660e8d0fSGerd Hoffmann info->types[type].requested = true; 150660e8d0fSGerd Hoffmann info->owner->request(info, type); 151660e8d0fSGerd Hoffmann } 152660e8d0fSGerd Hoffmann 153505dbf9bSMarc-André Lureau void qemu_clipboard_reset_serial(void) 154505dbf9bSMarc-André Lureau { 155505dbf9bSMarc-André Lureau QemuClipboardNotify notify = { .type = QEMU_CLIPBOARD_RESET_SERIAL }; 15672ce36f7SMarc-André Lureau int i; 157505dbf9bSMarc-André Lureau 15872ce36f7SMarc-André Lureau for (i = 0; i < QEMU_CLIPBOARD_SELECTION__COUNT; i++) { 15972ce36f7SMarc-André Lureau QemuClipboardInfo *info = qemu_clipboard_info(i); 16072ce36f7SMarc-André Lureau if (info) { 16172ce36f7SMarc-André Lureau info->serial = 0; 16272ce36f7SMarc-André Lureau } 16372ce36f7SMarc-André Lureau } 164505dbf9bSMarc-André Lureau notifier_list_notify(&clipboard_notifiers, ¬ify); 165505dbf9bSMarc-André Lureau } 166505dbf9bSMarc-André Lureau 167660e8d0fSGerd Hoffmann void qemu_clipboard_set_data(QemuClipboardPeer *peer, 168660e8d0fSGerd Hoffmann QemuClipboardInfo *info, 169660e8d0fSGerd Hoffmann QemuClipboardType type, 170660e8d0fSGerd Hoffmann uint32_t size, 1717e3e20d8SAkihiko Odaki const void *data, 172660e8d0fSGerd Hoffmann bool update) 173660e8d0fSGerd Hoffmann { 174660e8d0fSGerd Hoffmann if (!info || 175660e8d0fSGerd Hoffmann info->owner != peer) { 176660e8d0fSGerd Hoffmann return; 177660e8d0fSGerd Hoffmann } 178660e8d0fSGerd Hoffmann 179660e8d0fSGerd Hoffmann g_free(info->types[type].data); 180405484b2SFiona Ebner if (size) { 181405484b2SFiona Ebner info->types[type].data = g_memdup2(data, size); 182660e8d0fSGerd Hoffmann info->types[type].size = size; 183660e8d0fSGerd Hoffmann info->types[type].available = true; 184405484b2SFiona Ebner } else { 185405484b2SFiona Ebner info->types[type].data = NULL; 186405484b2SFiona Ebner info->types[type].size = 0; 187405484b2SFiona Ebner info->types[type].available = false; 188405484b2SFiona Ebner } 189660e8d0fSGerd Hoffmann 190660e8d0fSGerd Hoffmann if (update) { 191660e8d0fSGerd Hoffmann qemu_clipboard_update(info); 192660e8d0fSGerd Hoffmann } 193660e8d0fSGerd Hoffmann } 194