291 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			291 lines
		
	
	
		
			7.5 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 "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;
 | 
						|
    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) &&
 | 
						|
	    !e->pClient->clientGone)
 | 
						|
	{
 | 
						|
	    xXFixesSelectionNotifyEvent	ev;
 | 
						|
 | 
						|
	    memset(&ev, 0, sizeof(xXFixesSelectionNotifyEvent));
 | 
						|
	    ev.type = XFixesEventBase + XFixesSelectionNotify;
 | 
						|
	    ev.subtype = subtype;
 | 
						|
	    ev.sequenceNumber = e->pClient->sequence;
 | 
						|
	    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)
 | 
						|
{
 | 
						|
    pointer val;
 | 
						|
    int rc;
 | 
						|
    SelectionEventPtr	*prev, e;
 | 
						|
 | 
						|
    rc = XaceHook(XACE_SELECTION_ACCESS, pClient, selection, 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) xalloc (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,
 | 
						|
			      (pointer) pWindow))
 | 
						|
	    {
 | 
						|
		xfree (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;
 | 
						|
    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
 | 
						|
SProcXFixesSelectSelectionInput (ClientPtr client)
 | 
						|
{
 | 
						|
    register int n;
 | 
						|
    REQUEST(xXFixesSelectSelectionInputReq);
 | 
						|
 | 
						|
    swaps(&stuff->length, n);
 | 
						|
    swapl(&stuff->window, n);
 | 
						|
    swapl(&stuff->selection, n);
 | 
						|
    swapl(&stuff->eventMask, n);
 | 
						|
    return (*ProcXFixesVector[stuff->xfixesReqType])(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;
 | 
						|
	    xfree (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;
 | 
						|
}
 |