select.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. /*
  2. * Copyright © 2002 Keith Packard
  3. *
  4. * Permission to use, copy, modify, distribute, and sell this software and its
  5. * documentation for any purpose is hereby granted without fee, provided that
  6. * the above copyright notice appear in all copies and that both that
  7. * copyright notice and this permission notice appear in supporting
  8. * documentation, and that the name of Keith Packard not be used in
  9. * advertising or publicity pertaining to distribution of the software without
  10. * specific, written prior permission. Keith Packard makes no
  11. * representations about the suitability of this software for any purpose. It
  12. * is provided "as is" without express or implied warranty.
  13. *
  14. * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  15. * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
  16. * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  17. * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
  18. * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  19. * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  20. * PERFORMANCE OF THIS SOFTWARE.
  21. */
  22. #ifdef HAVE_DIX_CONFIG_H
  23. #include <dix-config.h>
  24. #endif
  25. #include "xfixesint.h"
  26. static RESTYPE SelectionClientType, SelectionWindowType;
  27. static Bool SelectionCallbackRegistered = FALSE;
  28. /*
  29. * There is a global list of windows selecting for selection events
  30. * on every selection. This should be plenty efficient for the
  31. * expected usage, if it does become a problem, it should be easily
  32. * replaced with a hash table of some kind keyed off the selection atom
  33. */
  34. typedef struct _SelectionEvent *SelectionEventPtr;
  35. typedef struct _SelectionEvent {
  36. SelectionEventPtr next;
  37. Atom selection;
  38. CARD32 eventMask;
  39. ClientPtr pClient;
  40. WindowPtr pWindow;
  41. XID clientResource;
  42. } SelectionEventRec;
  43. static SelectionEventPtr selectionEvents;
  44. static void
  45. XFixesSelectionCallback(CallbackListPtr *callbacks, pointer data, pointer args)
  46. {
  47. SelectionEventPtr e;
  48. SelectionInfoRec *info = (SelectionInfoRec *) args;
  49. Selection *selection = info->selection;
  50. int subtype;
  51. CARD32 eventMask;
  52. switch (info->kind) {
  53. case SelectionSetOwner:
  54. subtype = XFixesSetSelectionOwnerNotify;
  55. eventMask = XFixesSetSelectionOwnerNotifyMask;
  56. break;
  57. case SelectionWindowDestroy:
  58. subtype = XFixesSelectionWindowDestroyNotify;
  59. eventMask = XFixesSelectionWindowDestroyNotifyMask;
  60. break;
  61. case SelectionClientClose:
  62. subtype = XFixesSelectionClientCloseNotify;
  63. eventMask = XFixesSelectionClientCloseNotifyMask;
  64. break;
  65. default:
  66. return;
  67. }
  68. for (e = selectionEvents; e; e = e->next) {
  69. if (e->selection == selection->selection && (e->eventMask & eventMask)) {
  70. xXFixesSelectionNotifyEvent ev;
  71. ev.type = XFixesEventBase + XFixesSelectionNotify;
  72. ev.subtype = subtype;
  73. ev.window = e->pWindow->drawable.id;
  74. if (subtype == XFixesSetSelectionOwnerNotify)
  75. ev.owner = selection->window;
  76. else
  77. ev.owner = 0;
  78. ev.selection = e->selection;
  79. ev.timestamp = currentTime.milliseconds;
  80. ev.selectionTimestamp = selection->lastTimeChanged.milliseconds;
  81. WriteEventsToClient(e->pClient, 1, (xEvent *) &ev);
  82. }
  83. }
  84. }
  85. static Bool
  86. CheckSelectionCallback(void)
  87. {
  88. if (selectionEvents) {
  89. if (!SelectionCallbackRegistered) {
  90. if (!AddCallback(&SelectionCallback, XFixesSelectionCallback, NULL))
  91. return FALSE;
  92. SelectionCallbackRegistered = TRUE;
  93. }
  94. }
  95. else {
  96. if (SelectionCallbackRegistered) {
  97. DeleteCallback(&SelectionCallback, XFixesSelectionCallback, NULL);
  98. SelectionCallbackRegistered = FALSE;
  99. }
  100. }
  101. return TRUE;
  102. }
  103. #define SelectionAllEvents (XFixesSetSelectionOwnerNotifyMask |\
  104. XFixesSelectionWindowDestroyNotifyMask |\
  105. XFixesSelectionClientCloseNotifyMask)
  106. static int
  107. XFixesSelectSelectionInput(ClientPtr pClient,
  108. Atom selection, WindowPtr pWindow, CARD32 eventMask)
  109. {
  110. SelectionEventPtr *prev, e;
  111. for (prev = &selectionEvents; (e = *prev); prev = &e->next) {
  112. if (e->selection == selection &&
  113. e->pClient == pClient && e->pWindow == pWindow) {
  114. break;
  115. }
  116. }
  117. if (!eventMask) {
  118. if (e) {
  119. FreeResource(e->clientResource, 0);
  120. }
  121. return Success;
  122. }
  123. if (!e) {
  124. e = malloc(sizeof(SelectionEventRec));
  125. if (!e)
  126. return BadAlloc;
  127. e->next = 0;
  128. e->selection = selection;
  129. e->pClient = pClient;
  130. e->pWindow = pWindow;
  131. e->clientResource = FakeClientID(pClient->index);
  132. /*
  133. * Add a resource hanging from the window to
  134. * catch window destroy
  135. */
  136. if (!LookupIDByType(pWindow->drawable.id, SelectionWindowType))
  137. if (!AddResource(pWindow->drawable.id, SelectionWindowType,
  138. (pointer) pWindow)) {
  139. free(e);
  140. return BadAlloc;
  141. }
  142. if (!AddResource(e->clientResource, SelectionClientType, (pointer) e))
  143. return BadAlloc;
  144. *prev = e;
  145. if (!CheckSelectionCallback()) {
  146. FreeResource(e->clientResource, 0);
  147. return BadAlloc;
  148. }
  149. }
  150. e->eventMask = eventMask;
  151. return Success;
  152. }
  153. int
  154. ProcXFixesSelectSelectionInput(ClientPtr client)
  155. {
  156. REQUEST(xXFixesSelectSelectionInputReq);
  157. WindowPtr pWin;
  158. REQUEST_SIZE_MATCH(xXFixesSelectSelectionInputReq);
  159. pWin = (WindowPtr) SecurityLookupWindow(stuff->window, client,
  160. SecurityReadAccess);
  161. if (!pWin)
  162. return (BadWindow);
  163. if (stuff->eventMask & ~SelectionAllEvents) {
  164. client->errorValue = stuff->eventMask;
  165. return (BadValue);
  166. }
  167. return XFixesSelectSelectionInput(client, stuff->selection,
  168. pWin, stuff->eventMask);
  169. }
  170. int
  171. SProcXFixesSelectSelectionInput(ClientPtr client)
  172. {
  173. REQUEST(xXFixesSelectSelectionInputReq);
  174. swaps(&stuff->length);
  175. swapl(&stuff->window);
  176. swapl(&stuff->selection);
  177. swapl(&stuff->eventMask);
  178. return ProcXFixesSelectSelectionInput(client);
  179. }
  180. void
  181. SXFixesSelectionNotifyEvent(xXFixesSelectionNotifyEvent * from,
  182. xXFixesSelectionNotifyEvent * to)
  183. {
  184. to->type = from->type;
  185. cpswaps(from->sequenceNumber, to->sequenceNumber);
  186. cpswapl(from->window, to->window);
  187. cpswapl(from->owner, to->owner);
  188. cpswapl(from->selection, to->selection);
  189. cpswapl(from->timestamp, to->timestamp);
  190. cpswapl(from->selectionTimestamp, to->selectionTimestamp);
  191. }
  192. static int
  193. SelectionFreeClient(pointer data, XID id)
  194. {
  195. SelectionEventPtr old = (SelectionEventPtr) data;
  196. SelectionEventPtr *prev, e;
  197. for (prev = &selectionEvents; (e = *prev); prev = &e->next) {
  198. if (e == old) {
  199. *prev = e->next;
  200. free(e);
  201. CheckSelectionCallback();
  202. break;
  203. }
  204. }
  205. return 1;
  206. }
  207. static int
  208. SelectionFreeWindow(pointer data, XID id)
  209. {
  210. WindowPtr pWindow = (WindowPtr) data;
  211. SelectionEventPtr e, next;
  212. for (e = selectionEvents; e; e = next) {
  213. next = e->next;
  214. if (e->pWindow == pWindow) {
  215. FreeResource(e->clientResource, 0);
  216. }
  217. }
  218. return 1;
  219. }
  220. Bool
  221. XFixesSelectionInit(void)
  222. {
  223. SelectionClientType = CreateNewResourceType(SelectionFreeClient);
  224. SelectionWindowType = CreateNewResourceType(SelectionFreeWindow);
  225. return SelectionClientType && SelectionWindowType;
  226. }