select.c revision 0b0d8713
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 30static RESTYPE SelectionClientType, SelectionWindowType; 31static 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 40typedef struct _SelectionEvent *SelectionEventPtr; 41 42typedef struct _SelectionEvent { 43 SelectionEventPtr next; 44 Atom selection; 45 CARD32 eventMask; 46 ClientPtr pClient; 47 WindowPtr pWindow; 48 XID clientResource; 49} SelectionEventRec; 50 51static SelectionEventPtr selectionEvents; 52 53static void 54XFixesSelectionCallback (CallbackListPtr *callbacks, pointer data, pointer 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 for (e = selectionEvents; e; e = e->next) 79 { 80 if (e->selection == selection->selection && 81 (e->eventMask & eventMask)) 82 { 83 xXFixesSelectionNotifyEvent ev; 84 85 memset(&ev, 0, sizeof(xXFixesSelectionNotifyEvent)); 86 ev.type = XFixesEventBase + XFixesSelectionNotify; 87 ev.subtype = subtype; 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 pointer val; 135 int rc; 136 SelectionEventPtr *prev, e; 137 138 rc = XaceHook(XACE_SELECTION_ACCESS, pClient, selection, DixGetAttrAccess); 139 if (rc != Success) 140 return rc; 141 142 for (prev = &selectionEvents; (e = *prev); prev = &e->next) 143 { 144 if (e->selection == selection && 145 e->pClient == pClient && 146 e->pWindow == pWindow) 147 { 148 break; 149 } 150 } 151 if (!eventMask) 152 { 153 if (e) 154 { 155 FreeResource (e->clientResource, 0); 156 } 157 return Success; 158 } 159 if (!e) 160 { 161 e = (SelectionEventPtr) malloc(sizeof (SelectionEventRec)); 162 if (!e) 163 return BadAlloc; 164 165 e->next = 0; 166 e->selection = selection; 167 e->pClient = pClient; 168 e->pWindow = pWindow; 169 e->clientResource = FakeClientID(pClient->index); 170 171 /* 172 * Add a resource hanging from the window to 173 * catch window destroy 174 */ 175 rc = dixLookupResourceByType (&val, pWindow->drawable.id, 176 SelectionWindowType, serverClient, 177 DixGetAttrAccess); 178 if (rc != Success) 179 if (!AddResource (pWindow->drawable.id, SelectionWindowType, 180 (pointer) pWindow)) 181 { 182 free(e); 183 return BadAlloc; 184 } 185 186 if (!AddResource (e->clientResource, SelectionClientType, (pointer) e)) 187 return BadAlloc; 188 189 *prev = e; 190 if (!CheckSelectionCallback ()) 191 { 192 FreeResource (e->clientResource, 0); 193 return BadAlloc; 194 } 195 } 196 e->eventMask = eventMask; 197 return Success; 198} 199 200int 201ProcXFixesSelectSelectionInput (ClientPtr client) 202{ 203 REQUEST (xXFixesSelectSelectionInputReq); 204 WindowPtr pWin; 205 int rc; 206 207 REQUEST_SIZE_MATCH (xXFixesSelectSelectionInputReq); 208 rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); 209 if (rc != Success) 210 return rc; 211 if (stuff->eventMask & ~SelectionAllEvents) 212 { 213 client->errorValue = stuff->eventMask; 214 return BadValue; 215 } 216 return XFixesSelectSelectionInput (client, stuff->selection, 217 pWin, stuff->eventMask); 218} 219 220int 221SProcXFixesSelectSelectionInput (ClientPtr client) 222{ 223 register int n; 224 REQUEST(xXFixesSelectSelectionInputReq); 225 226 REQUEST_SIZE_MATCH(xXFixesSelectSelectionInputReq); 227 swaps(&stuff->length, n); 228 swapl(&stuff->window, n); 229 swapl(&stuff->selection, n); 230 swapl(&stuff->eventMask, n); 231 return (*ProcXFixesVector[stuff->xfixesReqType])(client); 232} 233 234void 235SXFixesSelectionNotifyEvent (xXFixesSelectionNotifyEvent *from, 236 xXFixesSelectionNotifyEvent *to) 237{ 238 to->type = from->type; 239 cpswaps (from->sequenceNumber, to->sequenceNumber); 240 cpswapl (from->window, to->window); 241 cpswapl (from->owner, to->owner); 242 cpswapl (from->selection, to->selection); 243 cpswapl (from->timestamp, to->timestamp); 244 cpswapl (from->selectionTimestamp, to->selectionTimestamp); 245} 246 247static int 248SelectionFreeClient (pointer data, XID id) 249{ 250 SelectionEventPtr old = (SelectionEventPtr) data; 251 SelectionEventPtr *prev, e; 252 253 for (prev = &selectionEvents; (e = *prev); prev = &e->next) 254 { 255 if (e == old) 256 { 257 *prev = e->next; 258 free(e); 259 CheckSelectionCallback (); 260 break; 261 } 262 } 263 return 1; 264} 265 266static int 267SelectionFreeWindow (pointer data, XID id) 268{ 269 WindowPtr pWindow = (WindowPtr) data; 270 SelectionEventPtr e, next; 271 272 for (e = selectionEvents; e; e = next) 273 { 274 next = e->next; 275 if (e->pWindow == pWindow) 276 { 277 FreeResource (e->clientResource, 0); 278 } 279 } 280 return 1; 281} 282 283Bool 284XFixesSelectionInit (void) 285{ 286 SelectionClientType = CreateNewResourceType(SelectionFreeClient, 287 "XFixesSelectionClient"); 288 SelectionWindowType = CreateNewResourceType(SelectionFreeWindow, 289 "XFixesSelectionWindow"); 290 return SelectionClientType && SelectionWindowType; 291} 292