select.c revision f7df2e56
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, 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 for (e = selectionEvents; e; e = e->next) { 79 if (e->selection == selection->selection && (e->eventMask & eventMask)) { 80 xXFixesSelectionNotifyEvent ev = { 81 .type = XFixesEventBase + XFixesSelectionNotify, 82 .subtype = subtype, 83 .window = e->pWindow->drawable.id, 84 .owner = (subtype == XFixesSetSelectionOwnerNotify) ? 85 selection->window : 0, 86 .selection = e->selection, 87 .timestamp = currentTime.milliseconds, 88 .selectionTimestamp = selection->lastTimeChanged.milliseconds 89 }; 90 WriteEventsToClient(e->pClient, 1, (xEvent *) &ev); 91 } 92 } 93} 94 95static Bool 96CheckSelectionCallback(void) 97{ 98 if (selectionEvents) { 99 if (!SelectionCallbackRegistered) { 100 if (!AddCallback(&SelectionCallback, XFixesSelectionCallback, NULL)) 101 return FALSE; 102 SelectionCallbackRegistered = TRUE; 103 } 104 } 105 else { 106 if (SelectionCallbackRegistered) { 107 DeleteCallback(&SelectionCallback, XFixesSelectionCallback, NULL); 108 SelectionCallbackRegistered = FALSE; 109 } 110 } 111 return TRUE; 112} 113 114#define SelectionAllEvents (XFixesSetSelectionOwnerNotifyMask |\ 115 XFixesSelectionWindowDestroyNotifyMask |\ 116 XFixesSelectionClientCloseNotifyMask) 117 118static int 119XFixesSelectSelectionInput(ClientPtr pClient, 120 Atom selection, WindowPtr pWindow, CARD32 eventMask) 121{ 122 void *val; 123 int rc; 124 SelectionEventPtr *prev, e; 125 126 rc = XaceHook(XACE_SELECTION_ACCESS, pClient, selection, DixGetAttrAccess); 127 if (rc != Success) 128 return rc; 129 130 for (prev = &selectionEvents; (e = *prev); prev = &e->next) { 131 if (e->selection == selection && 132 e->pClient == pClient && e->pWindow == pWindow) { 133 break; 134 } 135 } 136 if (!eventMask) { 137 if (e) { 138 FreeResource(e->clientResource, 0); 139 } 140 return Success; 141 } 142 if (!e) { 143 e = (SelectionEventPtr) malloc(sizeof(SelectionEventRec)); 144 if (!e) 145 return BadAlloc; 146 147 e->next = 0; 148 e->selection = selection; 149 e->pClient = pClient; 150 e->pWindow = pWindow; 151 e->clientResource = FakeClientID(pClient->index); 152 153 /* 154 * Add a resource hanging from the window to 155 * catch window destroy 156 */ 157 rc = dixLookupResourceByType(&val, pWindow->drawable.id, 158 SelectionWindowType, serverClient, 159 DixGetAttrAccess); 160 if (rc != Success) 161 if (!AddResource(pWindow->drawable.id, SelectionWindowType, 162 (void *) pWindow)) { 163 free(e); 164 return BadAlloc; 165 } 166 167 if (!AddResource(e->clientResource, SelectionClientType, (void *) e)) 168 return BadAlloc; 169 170 *prev = e; 171 if (!CheckSelectionCallback()) { 172 FreeResource(e->clientResource, 0); 173 return BadAlloc; 174 } 175 } 176 e->eventMask = eventMask; 177 return Success; 178} 179 180int 181ProcXFixesSelectSelectionInput(ClientPtr client) 182{ 183 REQUEST(xXFixesSelectSelectionInputReq); 184 WindowPtr pWin; 185 int rc; 186 187 REQUEST_SIZE_MATCH(xXFixesSelectSelectionInputReq); 188 rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); 189 if (rc != Success) 190 return rc; 191 if (stuff->eventMask & ~SelectionAllEvents) { 192 client->errorValue = stuff->eventMask; 193 return BadValue; 194 } 195 return XFixesSelectSelectionInput(client, stuff->selection, 196 pWin, stuff->eventMask); 197} 198 199int 200SProcXFixesSelectSelectionInput(ClientPtr client) 201{ 202 REQUEST(xXFixesSelectSelectionInputReq); 203 204 REQUEST_SIZE_MATCH(xXFixesSelectSelectionInputReq); 205 swaps(&stuff->length); 206 swapl(&stuff->window); 207 swapl(&stuff->selection); 208 swapl(&stuff->eventMask); 209 return (*ProcXFixesVector[stuff->xfixesReqType]) (client); 210} 211 212void 213SXFixesSelectionNotifyEvent(xXFixesSelectionNotifyEvent * from, 214 xXFixesSelectionNotifyEvent * to) 215{ 216 to->type = from->type; 217 cpswaps(from->sequenceNumber, to->sequenceNumber); 218 cpswapl(from->window, to->window); 219 cpswapl(from->owner, to->owner); 220 cpswapl(from->selection, to->selection); 221 cpswapl(from->timestamp, to->timestamp); 222 cpswapl(from->selectionTimestamp, to->selectionTimestamp); 223} 224 225static int 226SelectionFreeClient(void *data, XID id) 227{ 228 SelectionEventPtr old = (SelectionEventPtr) data; 229 SelectionEventPtr *prev, e; 230 231 for (prev = &selectionEvents; (e = *prev); prev = &e->next) { 232 if (e == old) { 233 *prev = e->next; 234 free(e); 235 CheckSelectionCallback(); 236 break; 237 } 238 } 239 return 1; 240} 241 242static int 243SelectionFreeWindow(void *data, XID id) 244{ 245 WindowPtr pWindow = (WindowPtr) data; 246 SelectionEventPtr e, next; 247 248 for (e = selectionEvents; e; e = next) { 249 next = e->next; 250 if (e->pWindow == pWindow) { 251 FreeResource(e->clientResource, 0); 252 } 253 } 254 return 1; 255} 256 257Bool 258XFixesSelectionInit(void) 259{ 260 SelectionClientType = CreateNewResourceType(SelectionFreeClient, 261 "XFixesSelectionClient"); 262 SelectionWindowType = CreateNewResourceType(SelectionFreeWindow, 263 "XFixesSelectionWindow"); 264 return SelectionClientType && SelectionWindowType; 265} 266