clipboard.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  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. QemuClipboardNotify notify = {
  55. .type = QEMU_CLIPBOARD_UPDATE_INFO,
  56. .info = info,
  57. };
  58. assert(info->selection < QEMU_CLIPBOARD_SELECTION__COUNT);
  59. notifier_list_notify(&clipboard_notifiers, &notify);
  60. if (cbinfo[info->selection] != info) {
  61. qemu_clipboard_info_unref(cbinfo[info->selection]);
  62. cbinfo[info->selection] = qemu_clipboard_info_ref(info);
  63. }
  64. }
  65. QemuClipboardInfo *qemu_clipboard_info(QemuClipboardSelection selection)
  66. {
  67. assert(selection < QEMU_CLIPBOARD_SELECTION__COUNT);
  68. return cbinfo[selection];
  69. }
  70. QemuClipboardInfo *qemu_clipboard_info_new(QemuClipboardPeer *owner,
  71. QemuClipboardSelection selection)
  72. {
  73. QemuClipboardInfo *info = g_new0(QemuClipboardInfo, 1);
  74. info->owner = owner;
  75. info->selection = selection;
  76. info->refcount = 1;
  77. return info;
  78. }
  79. QemuClipboardInfo *qemu_clipboard_info_ref(QemuClipboardInfo *info)
  80. {
  81. info->refcount++;
  82. return info;
  83. }
  84. void qemu_clipboard_info_unref(QemuClipboardInfo *info)
  85. {
  86. uint32_t type;
  87. if (!info) {
  88. return;
  89. }
  90. info->refcount--;
  91. if (info->refcount > 0) {
  92. return;
  93. }
  94. for (type = 0; type < QEMU_CLIPBOARD_TYPE__COUNT; type++) {
  95. g_free(info->types[type].data);
  96. }
  97. g_free(info);
  98. }
  99. void qemu_clipboard_request(QemuClipboardInfo *info,
  100. QemuClipboardType type)
  101. {
  102. if (info->types[type].data ||
  103. info->types[type].requested ||
  104. !info->types[type].available ||
  105. !info->owner)
  106. return;
  107. info->types[type].requested = true;
  108. info->owner->request(info, type);
  109. }
  110. void qemu_clipboard_reset_serial(void)
  111. {
  112. QemuClipboardNotify notify = { .type = QEMU_CLIPBOARD_RESET_SERIAL };
  113. int i;
  114. for (i = 0; i < QEMU_CLIPBOARD_SELECTION__COUNT; i++) {
  115. QemuClipboardInfo *info = qemu_clipboard_info(i);
  116. if (info) {
  117. info->serial = 0;
  118. }
  119. }
  120. notifier_list_notify(&clipboard_notifiers, &notify);
  121. }
  122. void qemu_clipboard_set_data(QemuClipboardPeer *peer,
  123. QemuClipboardInfo *info,
  124. QemuClipboardType type,
  125. uint32_t size,
  126. const void *data,
  127. bool update)
  128. {
  129. if (!info ||
  130. info->owner != peer) {
  131. return;
  132. }
  133. g_free(info->types[type].data);
  134. info->types[type].data = g_memdup(data, size);
  135. info->types[type].size = size;
  136. info->types[type].available = true;
  137. if (update) {
  138. qemu_clipboard_update(info);
  139. }
  140. }