123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 |
- /*
- * Copyright © 2002 Keith Packard
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of Keith Packard not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. Keith Packard makes no
- * representations about the suitability of this software for any purpose. It
- * is provided "as is" without express or implied warranty.
- *
- * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
- * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
- #ifdef HAVE_DIX_CONFIG_H
- #include <dix-config.h>
- #endif
- #include "xfixesint.h"
- static RESTYPE SelectionClientType, SelectionWindowType;
- static Bool SelectionCallbackRegistered = FALSE;
- /*
- * There is a global list of windows selecting for selection events
- * on every selection. This should be plenty efficient for the
- * expected usage, if it does become a problem, it should be easily
- * replaced with a hash table of some kind keyed off the selection atom
- */
- typedef struct _SelectionEvent *SelectionEventPtr;
- typedef struct _SelectionEvent {
- SelectionEventPtr next;
- Atom selection;
- CARD32 eventMask;
- ClientPtr pClient;
- WindowPtr pWindow;
- XID clientResource;
- } SelectionEventRec;
- static SelectionEventPtr selectionEvents;
- static void
- XFixesSelectionCallback(CallbackListPtr *callbacks, pointer data, pointer args)
- {
- SelectionEventPtr e;
- SelectionInfoRec *info = (SelectionInfoRec *) args;
- Selection *selection = info->selection;
- int subtype;
- CARD32 eventMask;
- switch (info->kind) {
- case SelectionSetOwner:
- subtype = XFixesSetSelectionOwnerNotify;
- eventMask = XFixesSetSelectionOwnerNotifyMask;
- break;
- case SelectionWindowDestroy:
- subtype = XFixesSelectionWindowDestroyNotify;
- eventMask = XFixesSelectionWindowDestroyNotifyMask;
- break;
- case SelectionClientClose:
- subtype = XFixesSelectionClientCloseNotify;
- eventMask = XFixesSelectionClientCloseNotifyMask;
- break;
- default:
- return;
- }
- for (e = selectionEvents; e; e = e->next) {
- if (e->selection == selection->selection && (e->eventMask & eventMask)) {
- xXFixesSelectionNotifyEvent ev;
- ev.type = XFixesEventBase + XFixesSelectionNotify;
- ev.subtype = subtype;
- ev.window = e->pWindow->drawable.id;
- if (subtype == XFixesSetSelectionOwnerNotify)
- ev.owner = selection->window;
- else
- ev.owner = 0;
- ev.selection = e->selection;
- ev.timestamp = currentTime.milliseconds;
- ev.selectionTimestamp = selection->lastTimeChanged.milliseconds;
- WriteEventsToClient(e->pClient, 1, (xEvent *) &ev);
- }
- }
- }
- static Bool
- CheckSelectionCallback(void)
- {
- if (selectionEvents) {
- if (!SelectionCallbackRegistered) {
- if (!AddCallback(&SelectionCallback, XFixesSelectionCallback, NULL))
- return FALSE;
- SelectionCallbackRegistered = TRUE;
- }
- }
- else {
- if (SelectionCallbackRegistered) {
- DeleteCallback(&SelectionCallback, XFixesSelectionCallback, NULL);
- SelectionCallbackRegistered = FALSE;
- }
- }
- return TRUE;
- }
- #define SelectionAllEvents (XFixesSetSelectionOwnerNotifyMask |\
- XFixesSelectionWindowDestroyNotifyMask |\
- XFixesSelectionClientCloseNotifyMask)
- static int
- XFixesSelectSelectionInput(ClientPtr pClient,
- Atom selection, WindowPtr pWindow, CARD32 eventMask)
- {
- SelectionEventPtr *prev, e;
- for (prev = &selectionEvents; (e = *prev); prev = &e->next) {
- if (e->selection == selection &&
- e->pClient == pClient && e->pWindow == pWindow) {
- break;
- }
- }
- if (!eventMask) {
- if (e) {
- FreeResource(e->clientResource, 0);
- }
- return Success;
- }
- if (!e) {
- e = malloc(sizeof(SelectionEventRec));
- if (!e)
- return BadAlloc;
- e->next = 0;
- e->selection = selection;
- e->pClient = pClient;
- e->pWindow = pWindow;
- e->clientResource = FakeClientID(pClient->index);
- /*
- * Add a resource hanging from the window to
- * catch window destroy
- */
- if (!LookupIDByType(pWindow->drawable.id, SelectionWindowType))
- if (!AddResource(pWindow->drawable.id, SelectionWindowType,
- (pointer) pWindow)) {
- free(e);
- return BadAlloc;
- }
- if (!AddResource(e->clientResource, SelectionClientType, (pointer) e))
- return BadAlloc;
- *prev = e;
- if (!CheckSelectionCallback()) {
- FreeResource(e->clientResource, 0);
- return BadAlloc;
- }
- }
- e->eventMask = eventMask;
- return Success;
- }
- int
- ProcXFixesSelectSelectionInput(ClientPtr client)
- {
- REQUEST(xXFixesSelectSelectionInputReq);
- WindowPtr pWin;
- REQUEST_SIZE_MATCH(xXFixesSelectSelectionInputReq);
- pWin = (WindowPtr) SecurityLookupWindow(stuff->window, client,
- SecurityReadAccess);
- if (!pWin)
- return (BadWindow);
- if (stuff->eventMask & ~SelectionAllEvents) {
- client->errorValue = stuff->eventMask;
- return (BadValue);
- }
- return XFixesSelectSelectionInput(client, stuff->selection,
- pWin, stuff->eventMask);
- }
- int
- SProcXFixesSelectSelectionInput(ClientPtr client)
- {
- REQUEST(xXFixesSelectSelectionInputReq);
- swaps(&stuff->length);
- swapl(&stuff->window);
- swapl(&stuff->selection);
- swapl(&stuff->eventMask);
- return ProcXFixesSelectSelectionInput(client);
- }
- void
- SXFixesSelectionNotifyEvent(xXFixesSelectionNotifyEvent * from,
- xXFixesSelectionNotifyEvent * to)
- {
- to->type = from->type;
- cpswaps(from->sequenceNumber, to->sequenceNumber);
- cpswapl(from->window, to->window);
- cpswapl(from->owner, to->owner);
- cpswapl(from->selection, to->selection);
- cpswapl(from->timestamp, to->timestamp);
- cpswapl(from->selectionTimestamp, to->selectionTimestamp);
- }
- static int
- SelectionFreeClient(pointer data, XID id)
- {
- SelectionEventPtr old = (SelectionEventPtr) data;
- SelectionEventPtr *prev, e;
- for (prev = &selectionEvents; (e = *prev); prev = &e->next) {
- if (e == old) {
- *prev = e->next;
- free(e);
- CheckSelectionCallback();
- break;
- }
- }
- return 1;
- }
- static int
- SelectionFreeWindow(pointer data, XID id)
- {
- WindowPtr pWindow = (WindowPtr) data;
- SelectionEventPtr e, next;
- for (e = selectionEvents; e; e = next) {
- next = e->next;
- if (e->pWindow == pWindow) {
- FreeResource(e->clientResource, 0);
- }
- }
- return 1;
- }
- Bool
- XFixesSelectionInit(void)
- {
- SelectionClientType = CreateNewResourceType(SelectionFreeClient);
- SelectionWindowType = CreateNewResourceType(SelectionFreeWindow);
- return SelectionClientType && SelectionWindowType;
- }
|