select.c revision 6747b715
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 swaps(&stuff->length, n); 227 swapl(&stuff->window, n); 228 swapl(&stuff->selection, n); 229 swapl(&stuff->eventMask, n); 230 return (*ProcXFixesVector[stuff->xfixesReqType])(client); 231} 232 233void 234SXFixesSelectionNotifyEvent (xXFixesSelectionNotifyEvent *from, 235 xXFixesSelectionNotifyEvent *to) 236{ 237 to->type = from->type; 238 cpswaps (from->sequenceNumber, to->sequenceNumber); 239 cpswapl (from->window, to->window); 240 cpswapl (from->owner, to->owner); 241 cpswapl (from->selection, to->selection); 242 cpswapl (from->timestamp, to->timestamp); 243 cpswapl (from->selectionTimestamp, to->selectionTimestamp); 244} 245 246static int 247SelectionFreeClient (pointer data, XID id) 248{ 249 SelectionEventPtr old = (SelectionEventPtr) data; 250 SelectionEventPtr *prev, e; 251 252 for (prev = &selectionEvents; (e = *prev); prev = &e->next) 253 { 254 if (e == old) 255 { 256 *prev = e->next; 257 free(e); 258 CheckSelectionCallback (); 259 break; 260 } 261 } 262 return 1; 263} 264 265static int 266SelectionFreeWindow (pointer data, XID id) 267{ 268 WindowPtr pWindow = (WindowPtr) data; 269 SelectionEventPtr e, next; 270 271 for (e = selectionEvents; e; e = next) 272 { 273 next = e->next; 274 if (e->pWindow == pWindow) 275 { 276 FreeResource (e->clientResource, 0); 277 } 278 } 279 return 1; 280} 281 282Bool 283XFixesSelectionInit (void) 284{ 285 SelectionClientType = CreateNewResourceType(SelectionFreeClient, 286 "XFixesSelectionClient"); 287 SelectionWindowType = CreateNewResourceType(SelectionFreeWindow, 288 "XFixesSelectionWindow"); 289 return SelectionClientType && SelectionWindowType; 290} 291