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