2
0

clipboard.c 5.0 KB

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