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