1706f2543Smrg/* 2706f2543Smrg * Copyright © 2002 Keith Packard 3706f2543Smrg * 4706f2543Smrg * Permission to use, copy, modify, distribute, and sell this software and its 5706f2543Smrg * documentation for any purpose is hereby granted without fee, provided that 6706f2543Smrg * the above copyright notice appear in all copies and that both that 7706f2543Smrg * copyright notice and this permission notice appear in supporting 8706f2543Smrg * documentation, and that the name of Keith Packard not be used in 9706f2543Smrg * advertising or publicity pertaining to distribution of the software without 10706f2543Smrg * specific, written prior permission. Keith Packard makes no 11706f2543Smrg * representations about the suitability of this software for any purpose. It 12706f2543Smrg * is provided "as is" without express or implied warranty. 13706f2543Smrg * 14706f2543Smrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15706f2543Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16706f2543Smrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17706f2543Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18706f2543Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19706f2543Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 20706f2543Smrg * PERFORMANCE OF THIS SOFTWARE. 21706f2543Smrg */ 22706f2543Smrg 23706f2543Smrg#ifdef HAVE_DIX_CONFIG_H 24706f2543Smrg#include <dix-config.h> 25706f2543Smrg#endif 26706f2543Smrg 27706f2543Smrg#include "xfixesint.h" 28706f2543Smrg#include "xace.h" 29706f2543Smrg 30706f2543Smrgstatic RESTYPE SelectionClientType, SelectionWindowType; 31706f2543Smrgstatic Bool SelectionCallbackRegistered = FALSE; 32706f2543Smrg 33706f2543Smrg/* 34706f2543Smrg * There is a global list of windows selecting for selection events 35706f2543Smrg * on every selection. This should be plenty efficient for the 36706f2543Smrg * expected usage, if it does become a problem, it should be easily 37706f2543Smrg * replaced with a hash table of some kind keyed off the selection atom 38706f2543Smrg */ 39706f2543Smrg 40706f2543Smrgtypedef struct _SelectionEvent *SelectionEventPtr; 41706f2543Smrg 42706f2543Smrgtypedef struct _SelectionEvent { 43706f2543Smrg SelectionEventPtr next; 44706f2543Smrg Atom selection; 45706f2543Smrg CARD32 eventMask; 46706f2543Smrg ClientPtr pClient; 47706f2543Smrg WindowPtr pWindow; 48706f2543Smrg XID clientResource; 49706f2543Smrg} SelectionEventRec; 50706f2543Smrg 51706f2543Smrgstatic SelectionEventPtr selectionEvents; 52706f2543Smrg 53706f2543Smrgstatic void 54706f2543SmrgXFixesSelectionCallback (CallbackListPtr *callbacks, pointer data, pointer args) 55706f2543Smrg{ 56706f2543Smrg SelectionEventPtr e; 57706f2543Smrg SelectionInfoRec *info = (SelectionInfoRec *) args; 58706f2543Smrg Selection *selection = info->selection; 59706f2543Smrg int subtype; 60706f2543Smrg CARD32 eventMask; 61706f2543Smrg 62706f2543Smrg switch (info->kind) { 63706f2543Smrg case SelectionSetOwner: 64706f2543Smrg subtype = XFixesSetSelectionOwnerNotify; 65706f2543Smrg eventMask = XFixesSetSelectionOwnerNotifyMask; 66706f2543Smrg break; 67706f2543Smrg case SelectionWindowDestroy: 68706f2543Smrg subtype = XFixesSelectionWindowDestroyNotify; 69706f2543Smrg eventMask = XFixesSelectionWindowDestroyNotifyMask; 70706f2543Smrg break; 71706f2543Smrg case SelectionClientClose: 72706f2543Smrg subtype = XFixesSelectionClientCloseNotify; 73706f2543Smrg eventMask = XFixesSelectionClientCloseNotifyMask; 74706f2543Smrg break; 75706f2543Smrg default: 76706f2543Smrg return; 77706f2543Smrg } 78706f2543Smrg for (e = selectionEvents; e; e = e->next) 79706f2543Smrg { 80706f2543Smrg if (e->selection == selection->selection && 81706f2543Smrg (e->eventMask & eventMask)) 82706f2543Smrg { 83706f2543Smrg xXFixesSelectionNotifyEvent ev; 84706f2543Smrg 85706f2543Smrg memset(&ev, 0, sizeof(xXFixesSelectionNotifyEvent)); 86706f2543Smrg ev.type = XFixesEventBase + XFixesSelectionNotify; 87706f2543Smrg ev.subtype = subtype; 88706f2543Smrg ev.window = e->pWindow->drawable.id; 89706f2543Smrg if (subtype == XFixesSetSelectionOwnerNotify) 90706f2543Smrg ev.owner = selection->window; 91706f2543Smrg else 92706f2543Smrg ev.owner = 0; 93706f2543Smrg ev.selection = e->selection; 94706f2543Smrg ev.timestamp = currentTime.milliseconds; 95706f2543Smrg ev.selectionTimestamp = selection->lastTimeChanged.milliseconds; 96706f2543Smrg WriteEventsToClient (e->pClient, 1, (xEvent *) &ev); 97706f2543Smrg } 98706f2543Smrg } 99706f2543Smrg} 100706f2543Smrg 101706f2543Smrgstatic Bool 102706f2543SmrgCheckSelectionCallback (void) 103706f2543Smrg{ 104706f2543Smrg if (selectionEvents) 105706f2543Smrg { 106706f2543Smrg if (!SelectionCallbackRegistered) 107706f2543Smrg { 108706f2543Smrg if (!AddCallback (&SelectionCallback, XFixesSelectionCallback, NULL)) 109706f2543Smrg return FALSE; 110706f2543Smrg SelectionCallbackRegistered = TRUE; 111706f2543Smrg } 112706f2543Smrg } 113706f2543Smrg else 114706f2543Smrg { 115706f2543Smrg if (SelectionCallbackRegistered) 116706f2543Smrg { 117706f2543Smrg DeleteCallback (&SelectionCallback, XFixesSelectionCallback, NULL); 118706f2543Smrg SelectionCallbackRegistered = FALSE; 119706f2543Smrg } 120706f2543Smrg } 121706f2543Smrg return TRUE; 122706f2543Smrg} 123706f2543Smrg 124706f2543Smrg#define SelectionAllEvents (XFixesSetSelectionOwnerNotifyMask |\ 125706f2543Smrg XFixesSelectionWindowDestroyNotifyMask |\ 126706f2543Smrg XFixesSelectionClientCloseNotifyMask) 127706f2543Smrg 128706f2543Smrgstatic int 129706f2543SmrgXFixesSelectSelectionInput (ClientPtr pClient, 130706f2543Smrg Atom selection, 131706f2543Smrg WindowPtr pWindow, 132706f2543Smrg CARD32 eventMask) 133706f2543Smrg{ 134706f2543Smrg pointer val; 135706f2543Smrg int rc; 136706f2543Smrg SelectionEventPtr *prev, e; 137706f2543Smrg 138706f2543Smrg rc = XaceHook(XACE_SELECTION_ACCESS, pClient, selection, DixGetAttrAccess); 139706f2543Smrg if (rc != Success) 140706f2543Smrg return rc; 141706f2543Smrg 142706f2543Smrg for (prev = &selectionEvents; (e = *prev); prev = &e->next) 143706f2543Smrg { 144706f2543Smrg if (e->selection == selection && 145706f2543Smrg e->pClient == pClient && 146706f2543Smrg e->pWindow == pWindow) 147706f2543Smrg { 148706f2543Smrg break; 149706f2543Smrg } 150706f2543Smrg } 151706f2543Smrg if (!eventMask) 152706f2543Smrg { 153706f2543Smrg if (e) 154706f2543Smrg { 155706f2543Smrg FreeResource (e->clientResource, 0); 156706f2543Smrg } 157706f2543Smrg return Success; 158706f2543Smrg } 159706f2543Smrg if (!e) 160706f2543Smrg { 161706f2543Smrg e = (SelectionEventPtr) malloc(sizeof (SelectionEventRec)); 162706f2543Smrg if (!e) 163706f2543Smrg return BadAlloc; 164706f2543Smrg 165706f2543Smrg e->next = 0; 166706f2543Smrg e->selection = selection; 167706f2543Smrg e->pClient = pClient; 168706f2543Smrg e->pWindow = pWindow; 169706f2543Smrg e->clientResource = FakeClientID(pClient->index); 170706f2543Smrg 171706f2543Smrg /* 172706f2543Smrg * Add a resource hanging from the window to 173706f2543Smrg * catch window destroy 174706f2543Smrg */ 175706f2543Smrg rc = dixLookupResourceByType (&val, pWindow->drawable.id, 176706f2543Smrg SelectionWindowType, serverClient, 177706f2543Smrg DixGetAttrAccess); 178706f2543Smrg if (rc != Success) 179706f2543Smrg if (!AddResource (pWindow->drawable.id, SelectionWindowType, 180706f2543Smrg (pointer) pWindow)) 181706f2543Smrg { 182706f2543Smrg free(e); 183706f2543Smrg return BadAlloc; 184706f2543Smrg } 185706f2543Smrg 186706f2543Smrg if (!AddResource (e->clientResource, SelectionClientType, (pointer) e)) 187706f2543Smrg return BadAlloc; 188706f2543Smrg 189706f2543Smrg *prev = e; 190706f2543Smrg if (!CheckSelectionCallback ()) 191706f2543Smrg { 192706f2543Smrg FreeResource (e->clientResource, 0); 193706f2543Smrg return BadAlloc; 194706f2543Smrg } 195706f2543Smrg } 196706f2543Smrg e->eventMask = eventMask; 197706f2543Smrg return Success; 198706f2543Smrg} 199706f2543Smrg 200706f2543Smrgint 201706f2543SmrgProcXFixesSelectSelectionInput (ClientPtr client) 202706f2543Smrg{ 203706f2543Smrg REQUEST (xXFixesSelectSelectionInputReq); 204706f2543Smrg WindowPtr pWin; 205706f2543Smrg int rc; 206706f2543Smrg 207706f2543Smrg REQUEST_SIZE_MATCH (xXFixesSelectSelectionInputReq); 208706f2543Smrg rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); 209706f2543Smrg if (rc != Success) 210706f2543Smrg return rc; 211706f2543Smrg if (stuff->eventMask & ~SelectionAllEvents) 212706f2543Smrg { 213706f2543Smrg client->errorValue = stuff->eventMask; 214706f2543Smrg return BadValue; 215706f2543Smrg } 216706f2543Smrg return XFixesSelectSelectionInput (client, stuff->selection, 217706f2543Smrg pWin, stuff->eventMask); 218706f2543Smrg} 219706f2543Smrg 220706f2543Smrgint 221706f2543SmrgSProcXFixesSelectSelectionInput (ClientPtr client) 222706f2543Smrg{ 223706f2543Smrg register int n; 224706f2543Smrg REQUEST(xXFixesSelectSelectionInputReq); 225706f2543Smrg 226706f2543Smrg REQUEST_SIZE_MATCH(xXFixesSelectSelectionInputReq); 227706f2543Smrg swaps(&stuff->length, n); 228706f2543Smrg swapl(&stuff->window, n); 229706f2543Smrg swapl(&stuff->selection, n); 230706f2543Smrg swapl(&stuff->eventMask, n); 231706f2543Smrg return (*ProcXFixesVector[stuff->xfixesReqType])(client); 232706f2543Smrg} 233706f2543Smrg 234706f2543Smrgvoid 235706f2543SmrgSXFixesSelectionNotifyEvent (xXFixesSelectionNotifyEvent *from, 236706f2543Smrg xXFixesSelectionNotifyEvent *to) 237706f2543Smrg{ 238706f2543Smrg to->type = from->type; 239706f2543Smrg cpswaps (from->sequenceNumber, to->sequenceNumber); 240706f2543Smrg cpswapl (from->window, to->window); 241706f2543Smrg cpswapl (from->owner, to->owner); 242706f2543Smrg cpswapl (from->selection, to->selection); 243706f2543Smrg cpswapl (from->timestamp, to->timestamp); 244706f2543Smrg cpswapl (from->selectionTimestamp, to->selectionTimestamp); 245706f2543Smrg} 246706f2543Smrg 247706f2543Smrgstatic int 248706f2543SmrgSelectionFreeClient (pointer data, XID id) 249706f2543Smrg{ 250706f2543Smrg SelectionEventPtr old = (SelectionEventPtr) data; 251706f2543Smrg SelectionEventPtr *prev, e; 252706f2543Smrg 253706f2543Smrg for (prev = &selectionEvents; (e = *prev); prev = &e->next) 254706f2543Smrg { 255706f2543Smrg if (e == old) 256706f2543Smrg { 257706f2543Smrg *prev = e->next; 258706f2543Smrg free(e); 259706f2543Smrg CheckSelectionCallback (); 260706f2543Smrg break; 261706f2543Smrg } 262706f2543Smrg } 263706f2543Smrg return 1; 264706f2543Smrg} 265706f2543Smrg 266706f2543Smrgstatic int 267706f2543SmrgSelectionFreeWindow (pointer data, XID id) 268706f2543Smrg{ 269706f2543Smrg WindowPtr pWindow = (WindowPtr) data; 270706f2543Smrg SelectionEventPtr e, next; 271706f2543Smrg 272706f2543Smrg for (e = selectionEvents; e; e = next) 273706f2543Smrg { 274706f2543Smrg next = e->next; 275706f2543Smrg if (e->pWindow == pWindow) 276706f2543Smrg { 277706f2543Smrg FreeResource (e->clientResource, 0); 278706f2543Smrg } 279706f2543Smrg } 280706f2543Smrg return 1; 281706f2543Smrg} 282706f2543Smrg 283706f2543SmrgBool 284706f2543SmrgXFixesSelectionInit (void) 285706f2543Smrg{ 286706f2543Smrg SelectionClientType = CreateNewResourceType(SelectionFreeClient, 287706f2543Smrg "XFixesSelectionClient"); 288706f2543Smrg SelectionWindowType = CreateNewResourceType(SelectionFreeWindow, 289706f2543Smrg "XFixesSelectionWindow"); 290706f2543Smrg return SelectionClientType && SelectionWindowType; 291706f2543Smrg} 292