Edit

IABSD.fr/xenocara/xserver/randr/randr.c

Branch :

  • Show log

    Commit

  • Author : matthieu
    Date : 2010-12-05 15:36:02
    Hash : 42826119
    Message : Upgrade to xorg-server 1.9.2. Tested by ajacoutot@, krw@, shadchin@ and jasper@ on various configurations including multihead with both zaphod and xrandr.

  • xserver/randr/randr.c
  • /*
     * Copyright © 2000 Compaq Computer Corporation
     * Copyright © 2002 Hewlett-Packard Company
     * Copyright © 2006 Intel Corporation
     *
     * 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 the copyright holders not be used in advertising or
     * publicity pertaining to distribution of the software without specific,
     * written prior permission.  The copyright holders make no representations
     * about the suitability of this software for any purpose.  It is provided "as
     * is" without express or implied warranty.
     *
     * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
     * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
     * EVENT SHALL THE COPYRIGHT HOLDERS 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.
     *
     * Author:  Jim Gettys, Hewlett-Packard Company, Inc.
     *	    Keith Packard, Intel Corporation
     */
    
    #ifdef HAVE_DIX_CONFIG_H
    #include <dix-config.h>
    #endif
    
    #include "randrstr.h"
    
    /* From render.h */
    #ifndef SubPixelUnknown
    #define SubPixelUnknown 0
    #endif
    
    #define RR_VALIDATE
    static int	RRNScreens;
    
    #define wrap(priv,real,mem,func) {\
        priv->mem = real->mem; \
        real->mem = func; \
    }
    
    #define unwrap(priv,real,mem) {\
        real->mem = priv->mem; \
    }
    
    static int ProcRRDispatch (ClientPtr pClient);
    static int SProcRRDispatch (ClientPtr pClient);
    
    int	RREventBase;
    int	RRErrorBase;
    RESTYPE RRClientType, RREventType; /* resource types for event masks */
    DevPrivateKeyRec RRClientPrivateKeyRec;
    
    DevPrivateKeyRec rrPrivKeyRec;
    
    static void
    RRClientCallback (CallbackListPtr	*list,
    		  pointer		closure,
    		  pointer		data)
    {
        NewClientInfoRec	*clientinfo = (NewClientInfoRec *) data;
        ClientPtr		pClient = clientinfo->client;
        rrClientPriv(pClient);
        RRTimesPtr		pTimes = (RRTimesPtr) (pRRClient + 1);
        int			i;
    
        pRRClient->major_version = 0;
        pRRClient->minor_version = 0;
        for (i = 0; i < screenInfo.numScreens; i++)
        {
    	ScreenPtr   pScreen = screenInfo.screens[i];
    	rrScrPriv(pScreen);
    
    	if (pScrPriv)
    	{
    	    pTimes[i].setTime = pScrPriv->lastSetTime;
    	    pTimes[i].configTime = pScrPriv->lastConfigTime;
    	}
        }
    }
    
    static Bool
    RRCloseScreen (int i, ScreenPtr pScreen)
    {
        rrScrPriv(pScreen);
        int		    j;
    
        unwrap (pScrPriv, pScreen, CloseScreen);
        for (j = pScrPriv->numCrtcs - 1; j >= 0; j--)
    	RRCrtcDestroy (pScrPriv->crtcs[j]);
        for (j = pScrPriv->numOutputs - 1; j >= 0; j--)
    	RROutputDestroy (pScrPriv->outputs[j]);
        
        free(pScrPriv->crtcs);
        free(pScrPriv->outputs);
        free(pScrPriv);
        RRNScreens -= 1;	/* ok, one fewer screen with RandR running */
        return (*pScreen->CloseScreen) (i, pScreen);    
    }
    
    static void
    SRRScreenChangeNotifyEvent(xRRScreenChangeNotifyEvent *from,
    			   xRRScreenChangeNotifyEvent *to)
    {
        to->type = from->type;
        to->rotation = from->rotation;
        cpswaps(from->sequenceNumber, to->sequenceNumber);
        cpswapl(from->timestamp, to->timestamp);
        cpswapl(from->configTimestamp, to->configTimestamp);
        cpswapl(from->root, to->root);
        cpswapl(from->window, to->window);
        cpswaps(from->sizeID, to->sizeID);
        cpswaps(from->subpixelOrder, to->subpixelOrder);
        cpswaps(from->widthInPixels, to->widthInPixels);
        cpswaps(from->heightInPixels, to->heightInPixels);
        cpswaps(from->widthInMillimeters, to->widthInMillimeters);
        cpswaps(from->heightInMillimeters, to->heightInMillimeters);
    }
    
    static void
    SRRCrtcChangeNotifyEvent(xRRCrtcChangeNotifyEvent *from,
    			 xRRCrtcChangeNotifyEvent *to)
    {
        to->type = from->type;
        to->subCode = from->subCode;
        cpswaps(from->sequenceNumber, to->sequenceNumber);
        cpswapl(from->timestamp, to->timestamp);
        cpswapl(from->window, to->window);
        cpswapl(from->crtc, to->crtc);
        cpswapl(from->mode, to->mode);
        cpswaps(from->rotation, to->rotation);
        /* pad1 */
        cpswaps(from->x, to->x);
        cpswaps(from->y, to->y);
        cpswaps(from->width, to->width);
        cpswaps(from->height, to->height);
    }
    
    static void
    SRROutputChangeNotifyEvent(xRROutputChangeNotifyEvent *from,
    			   xRROutputChangeNotifyEvent *to)
    {
        to->type = from->type;
        to->subCode = from->subCode;
        cpswaps(from->sequenceNumber, to->sequenceNumber);
        cpswapl(from->timestamp, to->timestamp);
        cpswapl(from->configTimestamp, to->configTimestamp);
        cpswapl(from->window, to->window);
        cpswapl(from->output, to->output);
        cpswapl(from->crtc, to->crtc);
        cpswapl(from->mode, to->mode);
        cpswaps(from->rotation, to->rotation);
        to->connection = from->connection;
        to->subpixelOrder = from->subpixelOrder;
    }
    
    static void
    SRROutputPropertyNotifyEvent(xRROutputPropertyNotifyEvent *from,
    			     xRROutputPropertyNotifyEvent *to)
    {
        to->type = from->type;
        to->subCode = from->subCode;
        cpswaps(from->sequenceNumber, to->sequenceNumber);
        cpswapl(from->window, to->window);
        cpswapl(from->output, to->output);
        cpswapl(from->atom, to->atom);
        cpswapl(from->timestamp, to->timestamp);
        to->state = from->state;
        /* pad1 */
        /* pad2 */
        /* pad3 */
        /* pad4 */
    }
    
    static void
    SRRNotifyEvent (xEvent *from,
    		xEvent *to)
    {
        switch (from->u.u.detail) {
        case RRNotify_CrtcChange:
    	SRRCrtcChangeNotifyEvent ((xRRCrtcChangeNotifyEvent *) from,
    				  (xRRCrtcChangeNotifyEvent *) to);
    	break;
        case RRNotify_OutputChange:
    	SRROutputChangeNotifyEvent ((xRROutputChangeNotifyEvent *) from,
    				    (xRROutputChangeNotifyEvent *) to);
    	break;
        case RRNotify_OutputProperty:
    	SRROutputPropertyNotifyEvent ((xRROutputPropertyNotifyEvent *) from,
    				      (xRROutputPropertyNotifyEvent *) to);
    	break;
        default:
    	break;
        }
    }
    
    static int RRGeneration;
    
    Bool RRInit (void)
    {
        if (RRGeneration != serverGeneration)
        {
    	if (!RRModeInit ())
    	    return FALSE;
    	if (!RRCrtcInit ())
    	    return FALSE;
    	if (!RROutputInit ())
    	    return FALSE;
    	RRGeneration = serverGeneration;
        }
        if (!dixRegisterPrivateKey(&rrPrivKeyRec, PRIVATE_SCREEN, 0))
    	return FALSE;
    
        return TRUE;
    }
    
    Bool RRScreenInit(ScreenPtr pScreen)
    {
        rrScrPrivPtr   pScrPriv;
    
        if (!RRInit ())
    	return FALSE;
    
        pScrPriv = (rrScrPrivPtr) calloc(1, sizeof (rrScrPrivRec));
        if (!pScrPriv)
    	return FALSE;
    
        SetRRScreen(pScreen, pScrPriv);
    
        /*
         * Calling function best set these function vectors
         */
        pScrPriv->rrGetInfo = 0;
        pScrPriv->maxWidth = pScrPriv->minWidth = pScreen->width;
        pScrPriv->maxHeight = pScrPriv->minHeight = pScreen->height;
        
        pScrPriv->width = pScreen->width;
        pScrPriv->height = pScreen->height;
        pScrPriv->mmWidth = pScreen->mmWidth;
        pScrPriv->mmHeight = pScreen->mmHeight;
    #if RANDR_12_INTERFACE
        pScrPriv->rrScreenSetSize = NULL;
        pScrPriv->rrCrtcSet = NULL;
        pScrPriv->rrCrtcSetGamma = NULL;
    #endif
    #if RANDR_10_INTERFACE    
        pScrPriv->rrSetConfig = 0;
        pScrPriv->rotations = RR_Rotate_0;
        pScrPriv->reqWidth = pScreen->width;
        pScrPriv->reqHeight = pScreen->height;
        pScrPriv->nSizes = 0;
        pScrPriv->pSizes = NULL;
        pScrPriv->rotation = RR_Rotate_0;
        pScrPriv->rate = 0;
        pScrPriv->size = 0;
    #endif
        
        /*
         * This value doesn't really matter -- any client must call
         * GetScreenInfo before reading it which will automatically update
         * the time
         */
        pScrPriv->lastSetTime = currentTime;
        pScrPriv->lastConfigTime = currentTime;
        
        wrap (pScrPriv, pScreen, CloseScreen, RRCloseScreen);
    
        pScrPriv->numOutputs = 0;
        pScrPriv->outputs = NULL;
        pScrPriv->numCrtcs = 0;
        pScrPriv->crtcs = NULL;
        
        RRNScreens += 1;	/* keep count of screens that implement randr */
        return TRUE;
    }
    
    /*ARGSUSED*/
    static int
    RRFreeClient (pointer data, XID id)
    {
        RREventPtr   pRREvent;
        WindowPtr	    pWin;
        RREventPtr   *pHead, pCur, pPrev;
    
        pRREvent = (RREventPtr) data;
        pWin = pRREvent->window;
        dixLookupResourceByType((pointer *)&pHead, pWin->drawable.id,
    			    RREventType, serverClient, DixDestroyAccess);
        if (pHead) {
    	pPrev = 0;
    	for (pCur = *pHead; pCur && pCur != pRREvent; pCur=pCur->next)
    	    pPrev = pCur;
    	if (pCur)
    	{
    	    if (pPrev)
    	    	pPrev->next = pRREvent->next;
    	    else
    	    	*pHead = pRREvent->next;
    	}
        }
        free((pointer) pRREvent);
        return 1;
    }
    
    /*ARGSUSED*/
    static int
    RRFreeEvents (pointer data, XID id)
    {
        RREventPtr   *pHead, pCur, pNext;
    
        pHead = (RREventPtr *) data;
        for (pCur = *pHead; pCur; pCur = pNext) {
    	pNext = pCur->next;
    	FreeResource (pCur->clientResource, RRClientType);
    	free((pointer) pCur);
        }
        free((pointer) pHead);
        return 1;
    }
    
    void
    RRExtensionInit (void)
    {
        ExtensionEntry *extEntry;
    
        if (RRNScreens == 0) return;
    
        if (!dixRegisterPrivateKey(&RRClientPrivateKeyRec, PRIVATE_CLIENT,
    			       sizeof (RRClientRec) +
    			       screenInfo.numScreens * sizeof (RRTimesRec)))
    	return;
        if (!AddCallback (&ClientStateCallback, RRClientCallback, 0))
    	return;
    
        RRClientType = CreateNewResourceType(RRFreeClient, "RandRClient");
        if (!RRClientType)
    	return;
        RREventType = CreateNewResourceType(RRFreeEvents, "RandREvent");
        if (!RREventType)
    	return;
        extEntry = AddExtension (RANDR_NAME, RRNumberEvents, RRNumberErrors,
    			     ProcRRDispatch, SProcRRDispatch,
    			     NULL, StandardMinorOpcode);
        if (!extEntry)
    	return;
        RRErrorBase = extEntry->errorBase;
        RREventBase = extEntry->eventBase;
        EventSwapVector[RREventBase + RRScreenChangeNotify] = (EventSwapPtr) 
    	SRRScreenChangeNotifyEvent;
        EventSwapVector[RREventBase + RRNotify] = (EventSwapPtr)
    	SRRNotifyEvent;
    
        RRModeInitErrorValue();
        RRCrtcInitErrorValue();
        RROutputInitErrorValue();
    
    #ifdef PANORAMIX
        RRXineramaExtensionInit();
    #endif
    }
    
    static int
    TellChanged (WindowPtr pWin, pointer value)
    {
        RREventPtr			*pHead, pRREvent;
        ClientPtr			client;
        ScreenPtr			pScreen = pWin->drawable.pScreen;
        rrScrPriv(pScreen);
        int				i;
    
        dixLookupResourceByType((pointer *)&pHead, pWin->drawable.id,
    			    RREventType, serverClient, DixReadAccess);
        if (!pHead)
    	return WT_WALKCHILDREN;
    
        for (pRREvent = *pHead; pRREvent; pRREvent = pRREvent->next) 
        {
    	client = pRREvent->client;
    	if (client == serverClient || client->clientGone)
    	    continue;
    
    	if (pRREvent->mask & RRScreenChangeNotifyMask)
    	    RRDeliverScreenEvent (client, pWin, pScreen);
    	
    	if (pRREvent->mask & RRCrtcChangeNotifyMask)
    	{
    	    for (i = 0; i < pScrPriv->numCrtcs; i++)
    	    {
    		RRCrtcPtr   crtc = pScrPriv->crtcs[i];
    		if (crtc->changed)
    		    RRDeliverCrtcEvent (client, pWin, crtc);
    	    }
    	}
    	
    	if (pRREvent->mask & RROutputChangeNotifyMask)
    	{
    	    for (i = 0; i < pScrPriv->numOutputs; i++)
    	    {
    		RROutputPtr   output = pScrPriv->outputs[i];
    		if (output->changed)
    		    RRDeliverOutputEvent (client, pWin, output);
    	    }
    	}
        }
        return WT_WALKCHILDREN;
    }
    
    /*
     * Something changed; send events and adjust pointer position
     */
    void
    RRTellChanged (ScreenPtr pScreen)
    {
        rrScrPriv (pScreen);
        int i;
        
        if (pScrPriv->changed)
        {
    	UpdateCurrentTime ();
    	if (pScrPriv->configChanged)
    	{
    	    pScrPriv->lastConfigTime = currentTime;
    	    pScrPriv->configChanged = FALSE;
    	}
    	pScrPriv->changed = FALSE;
    	WalkTree (pScreen, TellChanged, (pointer) pScreen);
    	for (i = 0; i < pScrPriv->numOutputs; i++)
    	    pScrPriv->outputs[i]->changed = FALSE;
    	for (i = 0; i < pScrPriv->numCrtcs; i++)
    	    pScrPriv->crtcs[i]->changed = FALSE;
    	if (pScrPriv->layoutChanged)
    	{
    	    pScrPriv->layoutChanged = FALSE;
    	    RRPointerScreenConfigured (pScreen);
    	    RRSendConfigNotify (pScreen);
    	}
        }
    }
    
    /*
     * Return the first output which is connected to an active CRTC
     * Used in emulating 1.0 behaviour
     */
    RROutputPtr
    RRFirstOutput (ScreenPtr pScreen)
    {
        rrScrPriv(pScreen);
        RROutputPtr		    output;
        int	i, j;
        
        if (pScrPriv->primaryOutput && pScrPriv->primaryOutput->crtc)
    	return pScrPriv->primaryOutput;
    
        for (i = 0; i < pScrPriv->numCrtcs; i++)
        {
    	RRCrtcPtr   crtc = pScrPriv->crtcs[i];
    	for (j = 0; j < pScrPriv->numOutputs; j++)
    	{
    	    output = pScrPriv->outputs[j];
    	    if (output->crtc == crtc)
    		return output;
    	}
        }
        return NULL;
    }
    
    CARD16
    RRVerticalRefresh (xRRModeInfo *mode)
    {
        CARD32  refresh;
        CARD32  dots = mode->hTotal * mode->vTotal;
        if (!dots)
    	return 0;
        refresh = (mode->dotClock + dots/2) / dots;
        if (refresh > 0xffff)
    	refresh = 0xffff;
        return (CARD16) refresh;
    }
    
    static int
    ProcRRDispatch (ClientPtr client)
    {
        REQUEST(xReq);
        if (stuff->data >= RRNumberRequests || !ProcRandrVector[stuff->data])
    	return BadRequest;
        return (*ProcRandrVector[stuff->data]) (client);
    }
    
    static int
    SProcRRDispatch (ClientPtr client)
    {
        REQUEST(xReq);
        if (stuff->data >= RRNumberRequests || !ProcRandrVector[stuff->data])
    	return BadRequest;
        return (*SProcRandrVector[stuff->data]) (client);
    }