Edit

IABSD.fr/xenocara/xserver/xfixes/select.c

Branch :

  • Show log

    Commit

  • Author : matthieu
    Date : 2006-11-26 18:13:41
    Hash : 889b8606
    Message : Importing xserver from X.Org 7.2RC2

  • xserver/xfixes/select.c
  • /*
     * $Id: select.c,v 1.1.1.1 2006/11/26 18:15:08 matthieu Exp $
     *
     * 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.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)
    {
        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 = (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
    	 */
    	if (!LookupIDByType(pWindow->drawable.id, SelectionWindowType))
    	    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;
    
        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)
    {
        register int n;
        REQUEST(xXFixesSelectSelectionInputReq);
    
        swaps(&stuff->length, n);
        swapl(&stuff->window, n);
        swapl(&stuff->selection, n);
        swapl(&stuff->eventMask, n);
        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;
    	    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;
    }