270 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			270 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  * 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 "dix/dix_priv.h"
 | |
| 
 | |
| #include "xfixesint.h"
 | |
| #include "xace.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;
 | |
|     Selection *selection;
 | |
|     CARD32 eventMask;
 | |
|     ClientPtr pClient;
 | |
|     WindowPtr pWindow;
 | |
|     XID clientResource;
 | |
| } SelectionEventRec;
 | |
| 
 | |
| static SelectionEventPtr selectionEvents;
 | |
| 
 | |
| static void
 | |
| XFixesSelectionCallback(CallbackListPtr *callbacks, void *data, void *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;
 | |
|     }
 | |
|     UpdateCurrentTimeIf();
 | |
|     for (e = selectionEvents; e; e = e->next) {
 | |
|         if (e->selection == selection && (e->eventMask & eventMask)) {
 | |
|             xXFixesSelectionNotifyEvent ev = {
 | |
|                 .type = XFixesEventBase + XFixesSelectionNotify,
 | |
|                 .subtype = subtype,
 | |
|                 .window = e->pWindow->drawable.id,
 | |
|                 .owner = (subtype == XFixesSetSelectionOwnerNotify) ?
 | |
|                             selection->window : 0,
 | |
|                 .selection = e->selection->selection,
 | |
|                 .timestamp = currentTime.milliseconds,
 | |
|                 .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_name, WindowPtr pWindow, CARD32 eventMask)
 | |
| {
 | |
|     void *val;
 | |
|     int rc;
 | |
|     SelectionEventPtr *prev, e;
 | |
|     Selection *selection;
 | |
| 
 | |
|     rc = dixLookupSelection(&selection, selection_name, pClient, DixGetAttrAccess);
 | |
|     if (rc != Success)
 | |
|         return rc;
 | |
| 
 | |
|     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 = (SelectionEventPtr) 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
 | |
|          */
 | |
|         rc = dixLookupResourceByType(&val, pWindow->drawable.id,
 | |
|                                      SelectionWindowType, serverClient,
 | |
|                                      DixGetAttrAccess);
 | |
|         if (rc != Success)
 | |
|             if (!AddResource(pWindow->drawable.id, SelectionWindowType,
 | |
|                              (void *) pWindow)) {
 | |
|                 free(e);
 | |
|                 return BadAlloc;
 | |
|             }
 | |
| 
 | |
|         if (!AddResource(e->clientResource, SelectionClientType, (void *) 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;
 | |
|     int rc;
 | |
| 
 | |
|     REQUEST_SIZE_MATCH(xXFixesSelectSelectionInputReq);
 | |
|     rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
 | |
|     if (rc != Success)
 | |
|         return rc;
 | |
|     if (stuff->eventMask & ~SelectionAllEvents) {
 | |
|         client->errorValue = stuff->eventMask;
 | |
|         return BadValue;
 | |
|     }
 | |
|     return XFixesSelectSelectionInput(client, stuff->selection,
 | |
|                                       pWin, stuff->eventMask);
 | |
| }
 | |
| 
 | |
| int _X_COLD
 | |
| SProcXFixesSelectSelectionInput(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xXFixesSelectSelectionInputReq);
 | |
| 
 | |
|     REQUEST_SIZE_MATCH(xXFixesSelectSelectionInputReq);
 | |
|     swaps(&stuff->length);
 | |
|     swapl(&stuff->window);
 | |
|     swapl(&stuff->selection);
 | |
|     swapl(&stuff->eventMask);
 | |
|     return ProcXFixesSelectSelectionInput(client);
 | |
| }
 | |
| 
 | |
| void _X_COLD
 | |
| 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(void *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(void *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,
 | |
|                                                 "XFixesSelectionClient");
 | |
|     SelectionWindowType = CreateNewResourceType(SelectionFreeWindow,
 | |
|                                                 "XFixesSelectionWindow");
 | |
|     return SelectionClientType && SelectionWindowType;
 | |
| }
 |