select.c (8351B)
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 23 #ifdef HAVE_DIX_CONFIG_H 24 #include <dix-config.h> 25 #endif 26 27 #include "xfixesint.h" 28 #include "xace.h" 29 30 static RESTYPE SelectionClientType, SelectionWindowType; 31 static Bool SelectionCallbackRegistered = FALSE; 32 33 /* 34 * There is a global list of windows selecting for selection events 35 * on every selection. This should be plenty efficient for the 36 * expected usage, if it does become a problem, it should be easily 37 * replaced with a hash table of some kind keyed off the selection atom 38 */ 39 40 typedef struct _SelectionEvent *SelectionEventPtr; 41 42 typedef struct _SelectionEvent { 43 SelectionEventPtr next; 44 Atom selection; 45 CARD32 eventMask; 46 ClientPtr pClient; 47 WindowPtr pWindow; 48 XID clientResource; 49 } SelectionEventRec; 50 51 static SelectionEventPtr selectionEvents; 52 53 static void 54 XFixesSelectionCallback(CallbackListPtr *callbacks, void *data, void *args) 55 { 56 SelectionEventPtr e; 57 SelectionInfoRec *info = (SelectionInfoRec *) args; 58 Selection *selection = info->selection; 59 int subtype; 60 CARD32 eventMask; 61 62 switch (info->kind) { 63 case SelectionSetOwner: 64 subtype = XFixesSetSelectionOwnerNotify; 65 eventMask = XFixesSetSelectionOwnerNotifyMask; 66 break; 67 case SelectionWindowDestroy: 68 subtype = XFixesSelectionWindowDestroyNotify; 69 eventMask = XFixesSelectionWindowDestroyNotifyMask; 70 break; 71 case SelectionClientClose: 72 subtype = XFixesSelectionClientCloseNotify; 73 eventMask = XFixesSelectionClientCloseNotifyMask; 74 break; 75 default: 76 return; 77 } 78 UpdateCurrentTimeIf(); 79 for (e = selectionEvents; e; e = e->next) { 80 if (e->selection == selection->selection && (e->eventMask & eventMask)) { 81 xXFixesSelectionNotifyEvent ev = { 82 .type = XFixesEventBase + XFixesSelectionNotify, 83 .subtype = subtype, 84 .window = e->pWindow->drawable.id, 85 .owner = (subtype == XFixesSetSelectionOwnerNotify) ? 86 selection->window : 0, 87 .selection = e->selection, 88 .timestamp = currentTime.milliseconds, 89 .selectionTimestamp = selection->lastTimeChanged.milliseconds 90 }; 91 WriteEventsToClient(e->pClient, 1, (xEvent *) &ev); 92 } 93 } 94 } 95 96 static Bool 97 CheckSelectionCallback(void) 98 { 99 if (selectionEvents) { 100 if (!SelectionCallbackRegistered) { 101 if (!AddCallback(&SelectionCallback, XFixesSelectionCallback, NULL)) 102 return FALSE; 103 SelectionCallbackRegistered = TRUE; 104 } 105 } 106 else { 107 if (SelectionCallbackRegistered) { 108 DeleteCallback(&SelectionCallback, XFixesSelectionCallback, NULL); 109 SelectionCallbackRegistered = FALSE; 110 } 111 } 112 return TRUE; 113 } 114 115 #define SelectionAllEvents (XFixesSetSelectionOwnerNotifyMask |\ 116 XFixesSelectionWindowDestroyNotifyMask |\ 117 XFixesSelectionClientCloseNotifyMask) 118 119 static int 120 XFixesSelectSelectionInput(ClientPtr pClient, 121 Atom selection, WindowPtr pWindow, CARD32 eventMask) 122 { 123 void *val; 124 int rc; 125 SelectionEventPtr *prev, e; 126 127 rc = XaceHook(XACE_SELECTION_ACCESS, pClient, selection, DixGetAttrAccess); 128 if (rc != Success) 129 return rc; 130 131 for (prev = &selectionEvents; (e = *prev); prev = &e->next) { 132 if (e->selection == selection && 133 e->pClient == pClient && e->pWindow == pWindow) { 134 break; 135 } 136 } 137 if (!eventMask) { 138 if (e) { 139 FreeResource(e->clientResource, 0); 140 } 141 return Success; 142 } 143 if (!e) { 144 e = (SelectionEventPtr) malloc(sizeof(SelectionEventRec)); 145 if (!e) 146 return BadAlloc; 147 148 e->next = 0; 149 e->selection = selection; 150 e->pClient = pClient; 151 e->pWindow = pWindow; 152 e->clientResource = FakeClientID(pClient->index); 153 154 /* 155 * Add a resource hanging from the window to 156 * catch window destroy 157 */ 158 rc = dixLookupResourceByType(&val, pWindow->drawable.id, 159 SelectionWindowType, serverClient, 160 DixGetAttrAccess); 161 if (rc != Success) 162 if (!AddResource(pWindow->drawable.id, SelectionWindowType, 163 (void *) pWindow)) { 164 free(e); 165 return BadAlloc; 166 } 167 168 if (!AddResource(e->clientResource, SelectionClientType, (void *) e)) 169 return BadAlloc; 170 171 *prev = e; 172 if (!CheckSelectionCallback()) { 173 FreeResource(e->clientResource, 0); 174 return BadAlloc; 175 } 176 } 177 e->eventMask = eventMask; 178 return Success; 179 } 180 181 int 182 ProcXFixesSelectSelectionInput(ClientPtr client) 183 { 184 REQUEST(xXFixesSelectSelectionInputReq); 185 WindowPtr pWin; 186 int rc; 187 188 REQUEST_SIZE_MATCH(xXFixesSelectSelectionInputReq); 189 rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); 190 if (rc != Success) 191 return rc; 192 if (stuff->eventMask & ~SelectionAllEvents) { 193 client->errorValue = stuff->eventMask; 194 return BadValue; 195 } 196 return XFixesSelectSelectionInput(client, stuff->selection, 197 pWin, stuff->eventMask); 198 } 199 200 int _X_COLD 201 SProcXFixesSelectSelectionInput(ClientPtr client) 202 { 203 REQUEST(xXFixesSelectSelectionInputReq); 204 205 REQUEST_SIZE_MATCH(xXFixesSelectSelectionInputReq); 206 swaps(&stuff->length); 207 swapl(&stuff->window); 208 swapl(&stuff->selection); 209 swapl(&stuff->eventMask); 210 return (*ProcXFixesVector[stuff->xfixesReqType]) (client); 211 } 212 213 void _X_COLD 214 SXFixesSelectionNotifyEvent(xXFixesSelectionNotifyEvent * from, 215 xXFixesSelectionNotifyEvent * to) 216 { 217 to->type = from->type; 218 cpswaps(from->sequenceNumber, to->sequenceNumber); 219 cpswapl(from->window, to->window); 220 cpswapl(from->owner, to->owner); 221 cpswapl(from->selection, to->selection); 222 cpswapl(from->timestamp, to->timestamp); 223 cpswapl(from->selectionTimestamp, to->selectionTimestamp); 224 } 225 226 static int 227 SelectionFreeClient(void *data, XID id) 228 { 229 SelectionEventPtr old = (SelectionEventPtr) data; 230 SelectionEventPtr *prev, e; 231 232 for (prev = &selectionEvents; (e = *prev); prev = &e->next) { 233 if (e == old) { 234 *prev = e->next; 235 free(e); 236 CheckSelectionCallback(); 237 break; 238 } 239 } 240 return 1; 241 } 242 243 static int 244 SelectionFreeWindow(void *data, XID id) 245 { 246 WindowPtr pWindow = (WindowPtr) data; 247 SelectionEventPtr e, next; 248 249 for (e = selectionEvents; e; e = next) { 250 next = e->next; 251 if (e->pWindow == pWindow) { 252 FreeResource(e->clientResource, 0); 253 } 254 } 255 return 1; 256 } 257 258 Bool 259 XFixesSelectionInit(void) 260 { 261 SelectionClientType = CreateNewResourceType(SelectionFreeClient, 262 "XFixesSelectionClient"); 263 SelectionWindowType = CreateNewResourceType(SelectionFreeWindow, 264 "XFixesSelectionWindow"); 265 return SelectionClientType && SelectionWindowType; 266 }