1 #include "qemu/osdep.h" 2 #include "ui/clipboard.h" 3 4 static NotifierList clipboard_notifiers = 5 NOTIFIER_LIST_INITIALIZER(clipboard_notifiers); 6 7 static QemuClipboardInfo *cbinfo[QEMU_CLIPBOARD_SELECTION__COUNT]; 8 9 void qemu_clipboard_peer_register(QemuClipboardPeer *peer) 10 { 11 notifier_list_add(&clipboard_notifiers, &peer->notifier); 12 } 13 14 void qemu_clipboard_peer_unregister(QemuClipboardPeer *peer) 15 { 16 int i; 17 18 for (i = 0; i < QEMU_CLIPBOARD_SELECTION__COUNT; i++) { 19 qemu_clipboard_peer_release(peer, i); 20 } 21 notifier_remove(&peer->notifier); 22 } 23 24 bool qemu_clipboard_peer_owns(QemuClipboardPeer *peer, 25 QemuClipboardSelection selection) 26 { 27 QemuClipboardInfo *info = qemu_clipboard_info(selection); 28 29 return info && info->owner == peer; 30 } 31 32 void qemu_clipboard_peer_release(QemuClipboardPeer *peer, 33 QemuClipboardSelection selection) 34 { 35 g_autoptr(QemuClipboardInfo) info = NULL; 36 37 if (qemu_clipboard_peer_owns(peer, selection)) { 38 /* set empty clipboard info */ 39 info = qemu_clipboard_info_new(NULL, selection); 40 qemu_clipboard_update(info); 41 } 42 } 43 44 bool qemu_clipboard_check_serial(QemuClipboardInfo *info, bool client) 45 { 46 if (!info->has_serial || 47 !cbinfo[info->selection] || 48 !cbinfo[info->selection]->has_serial) { 49 return true; 50 } 51 52 if (client) { 53 return cbinfo[info->selection]->serial >= info->serial; 54 } else { 55 return cbinfo[info->selection]->serial > info->serial; 56 } 57 } 58 59 void qemu_clipboard_update(QemuClipboardInfo *info) 60 { 61 QemuClipboardNotify notify = { 62 .type = QEMU_CLIPBOARD_UPDATE_INFO, 63 .info = info, 64 }; 65 g_autoptr(QemuClipboardInfo) old = NULL; 66 67 assert(info->selection < QEMU_CLIPBOARD_SELECTION__COUNT); 68 69 notifier_list_notify(&clipboard_notifiers, ¬ify); 70 71 old = cbinfo[info->selection]; 72 cbinfo[info->selection] = qemu_clipboard_info_ref(info); 73 } 74 75 QemuClipboardInfo *qemu_clipboard_info(QemuClipboardSelection selection) 76 { 77 assert(selection < QEMU_CLIPBOARD_SELECTION__COUNT); 78 79 return cbinfo[selection]; 80 } 81 82 QemuClipboardInfo *qemu_clipboard_info_new(QemuClipboardPeer *owner, 83 QemuClipboardSelection selection) 84 { 85 QemuClipboardInfo *info = g_new0(QemuClipboardInfo, 1); 86 87 info->owner = owner; 88 info->selection = selection; 89 info->refcount = 1; 90 91 return info; 92 } 93 94 QemuClipboardInfo *qemu_clipboard_info_ref(QemuClipboardInfo *info) 95 { 96 info->refcount++; 97 return info; 98 } 99 100 void qemu_clipboard_info_unref(QemuClipboardInfo *info) 101 { 102 uint32_t type; 103 104 if (!info) { 105 return; 106 } 107 108 info->refcount--; 109 if (info->refcount > 0) { 110 return; 111 } 112 113 for (type = 0; type < QEMU_CLIPBOARD_TYPE__COUNT; type++) { 114 g_free(info->types[type].data); 115 } 116 g_free(info); 117 } 118 119 void qemu_clipboard_request(QemuClipboardInfo *info, 120 QemuClipboardType type) 121 { 122 if (info->types[type].data || 123 info->types[type].requested || 124 !info->types[type].available || 125 !info->owner) 126 return; 127 128 info->types[type].requested = true; 129 info->owner->request(info, type); 130 } 131 132 void qemu_clipboard_reset_serial(void) 133 { 134 QemuClipboardNotify notify = { .type = QEMU_CLIPBOARD_RESET_SERIAL }; 135 136 notifier_list_notify(&clipboard_notifiers, ¬ify); 137 } 138 139 void qemu_clipboard_set_data(QemuClipboardPeer *peer, 140 QemuClipboardInfo *info, 141 QemuClipboardType type, 142 uint32_t size, 143 const void *data, 144 bool update) 145 { 146 if (!info || 147 info->owner != peer) { 148 return; 149 } 150 151 g_free(info->types[type].data); 152 info->types[type].data = g_memdup(data, size); 153 info->types[type].size = size; 154 info->types[type].available = true; 155 156 if (update) { 157 qemu_clipboard_update(info); 158 } 159 } 160