1432 lines
		
	
	
		
			40 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			1432 lines
		
	
	
		
			40 KiB
		
	
	
	
		
			C
		
	
	
	
 | 
						|
/*
 | 
						|
 * Copyright (c) 1998-2001 by The XFree86 Project, Inc.
 | 
						|
 *
 | 
						|
 * Permission is hereby granted, free of charge, to any person obtaining a
 | 
						|
 * copy of this software and associated documentation files (the "Software"),
 | 
						|
 * to deal in the Software without restriction, including without limitation
 | 
						|
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 | 
						|
 * and/or sell copies of the Software, and to permit persons to whom the
 | 
						|
 * Software is furnished to do so, subject to the following conditions:
 | 
						|
 *
 | 
						|
 * The above copyright notice and this permission notice shall be included in
 | 
						|
 * all copies or substantial portions of the Software.
 | 
						|
 *
 | 
						|
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
						|
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
						|
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 | 
						|
 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
 | 
						|
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 | 
						|
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 | 
						|
 * OTHER DEALINGS IN THE SOFTWARE.
 | 
						|
 *
 | 
						|
 * Except as contained in this notice, the name of the copyright holder(s)
 | 
						|
 * and author(s) shall not be used in advertising or otherwise to promote
 | 
						|
 * the sale, use or other dealings in this Software without prior written
 | 
						|
 * authorization from the copyright holder(s) and author(s).
 | 
						|
 */
 | 
						|
 | 
						|
#ifdef HAVE_XORG_CONFIG_H
 | 
						|
#include <xorg-config.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#include "misc.h"
 | 
						|
#include "xf86.h"
 | 
						|
 | 
						|
#include <X11/X.h>
 | 
						|
#include "scrnintstr.h"
 | 
						|
#include "regionstr.h"
 | 
						|
#include "xf86fbman.h"
 | 
						|
 | 
						|
/*
 | 
						|
#define DEBUG
 | 
						|
*/
 | 
						|
 | 
						|
static DevPrivateKeyRec xf86FBManagerKeyRec;
 | 
						|
static DevPrivateKey xf86FBManagerKey;
 | 
						|
 | 
						|
Bool
 | 
						|
xf86RegisterOffscreenManager(ScreenPtr pScreen, FBManagerFuncsPtr funcs)
 | 
						|
{
 | 
						|
 | 
						|
    xf86FBManagerKey = &xf86FBManagerKeyRec;
 | 
						|
 | 
						|
    if (!dixRegisterPrivateKey(&xf86FBManagerKeyRec, PRIVATE_SCREEN, 0))
 | 
						|
        return FALSE;
 | 
						|
 | 
						|
    dixSetPrivate(&pScreen->devPrivates, xf86FBManagerKey, funcs);
 | 
						|
 | 
						|
    return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
Bool
 | 
						|
xf86FBManagerRunning(ScreenPtr pScreen)
 | 
						|
{
 | 
						|
    if (xf86FBManagerKey == NULL)
 | 
						|
        return FALSE;
 | 
						|
 | 
						|
    if (!dixLookupPrivate(&pScreen->devPrivates, xf86FBManagerKey))
 | 
						|
        return FALSE;
 | 
						|
 | 
						|
    return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
Bool
 | 
						|
xf86RegisterFreeBoxCallback(ScreenPtr pScreen,
 | 
						|
                            FreeBoxCallbackProcPtr FreeBoxCallback,
 | 
						|
                            void *devPriv)
 | 
						|
{
 | 
						|
    FBManagerFuncsPtr funcs;
 | 
						|
 | 
						|
    if (xf86FBManagerKey == NULL)
 | 
						|
        return FALSE;
 | 
						|
    if (!(funcs = (FBManagerFuncsPtr) dixLookupPrivate(&pScreen->devPrivates,
 | 
						|
                                                       xf86FBManagerKey)))
 | 
						|
        return FALSE;
 | 
						|
 | 
						|
    return (*funcs->RegisterFreeBoxCallback) (pScreen, FreeBoxCallback,
 | 
						|
                                              devPriv);
 | 
						|
}
 | 
						|
 | 
						|
FBAreaPtr
 | 
						|
xf86AllocateOffscreenArea(ScreenPtr pScreen,
 | 
						|
                          int w, int h,
 | 
						|
                          int gran,
 | 
						|
                          MoveAreaCallbackProcPtr moveCB,
 | 
						|
                          RemoveAreaCallbackProcPtr removeCB, void *privData)
 | 
						|
{
 | 
						|
    FBManagerFuncsPtr funcs;
 | 
						|
 | 
						|
    if (xf86FBManagerKey == NULL)
 | 
						|
        return NULL;
 | 
						|
    if (!(funcs = (FBManagerFuncsPtr) dixLookupPrivate(&pScreen->devPrivates,
 | 
						|
                                                       xf86FBManagerKey)))
 | 
						|
        return NULL;
 | 
						|
 | 
						|
    return (*funcs->AllocateOffscreenArea) (pScreen, w, h, gran, moveCB,
 | 
						|
                                            removeCB, privData);
 | 
						|
}
 | 
						|
 | 
						|
FBLinearPtr
 | 
						|
xf86AllocateOffscreenLinear(ScreenPtr pScreen,
 | 
						|
                            int length,
 | 
						|
                            int gran,
 | 
						|
                            MoveLinearCallbackProcPtr moveCB,
 | 
						|
                            RemoveLinearCallbackProcPtr removeCB,
 | 
						|
                            void *privData)
 | 
						|
{
 | 
						|
    FBManagerFuncsPtr funcs;
 | 
						|
 | 
						|
    if (xf86FBManagerKey == NULL)
 | 
						|
        return NULL;
 | 
						|
    if (!(funcs = (FBManagerFuncsPtr) dixLookupPrivate(&pScreen->devPrivates,
 | 
						|
                                                       xf86FBManagerKey)))
 | 
						|
        return NULL;
 | 
						|
 | 
						|
    return (*funcs->AllocateOffscreenLinear) (pScreen, length, gran, moveCB,
 | 
						|
                                              removeCB, privData);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
xf86FreeOffscreenArea(FBAreaPtr area)
 | 
						|
{
 | 
						|
    FBManagerFuncsPtr funcs;
 | 
						|
 | 
						|
    if (!area)
 | 
						|
        return;
 | 
						|
 | 
						|
    if (xf86FBManagerKey == NULL)
 | 
						|
        return;
 | 
						|
    if (!
 | 
						|
        (funcs =
 | 
						|
         (FBManagerFuncsPtr) dixLookupPrivate(&area->pScreen->devPrivates,
 | 
						|
                                              xf86FBManagerKey)))
 | 
						|
        return;
 | 
						|
 | 
						|
    (*funcs->FreeOffscreenArea) (area);
 | 
						|
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
xf86FreeOffscreenLinear(FBLinearPtr linear)
 | 
						|
{
 | 
						|
    FBManagerFuncsPtr funcs;
 | 
						|
 | 
						|
    if (!linear)
 | 
						|
        return;
 | 
						|
 | 
						|
    if (xf86FBManagerKey == NULL)
 | 
						|
        return;
 | 
						|
    if (!
 | 
						|
        (funcs =
 | 
						|
         (FBManagerFuncsPtr) dixLookupPrivate(&linear->pScreen->devPrivates,
 | 
						|
                                              xf86FBManagerKey)))
 | 
						|
        return;
 | 
						|
 | 
						|
    (*funcs->FreeOffscreenLinear) (linear);
 | 
						|
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
Bool
 | 
						|
xf86ResizeOffscreenArea(FBAreaPtr resize, int w, int h)
 | 
						|
{
 | 
						|
    FBManagerFuncsPtr funcs;
 | 
						|
 | 
						|
    if (!resize)
 | 
						|
        return FALSE;
 | 
						|
 | 
						|
    if (xf86FBManagerKey == NULL)
 | 
						|
        return FALSE;
 | 
						|
    if (!
 | 
						|
        (funcs =
 | 
						|
         (FBManagerFuncsPtr) dixLookupPrivate(&resize->pScreen->devPrivates,
 | 
						|
                                              xf86FBManagerKey)))
 | 
						|
        return FALSE;
 | 
						|
 | 
						|
    return (*funcs->ResizeOffscreenArea) (resize, w, h);
 | 
						|
}
 | 
						|
 | 
						|
Bool
 | 
						|
xf86ResizeOffscreenLinear(FBLinearPtr resize, int size)
 | 
						|
{
 | 
						|
    FBManagerFuncsPtr funcs;
 | 
						|
 | 
						|
    if (!resize)
 | 
						|
        return FALSE;
 | 
						|
 | 
						|
    if (xf86FBManagerKey == NULL)
 | 
						|
        return FALSE;
 | 
						|
    if (!
 | 
						|
        (funcs =
 | 
						|
         (FBManagerFuncsPtr) dixLookupPrivate(&resize->pScreen->devPrivates,
 | 
						|
                                              xf86FBManagerKey)))
 | 
						|
        return FALSE;
 | 
						|
 | 
						|
    return (*funcs->ResizeOffscreenLinear) (resize, size);
 | 
						|
}
 | 
						|
 | 
						|
Bool
 | 
						|
xf86QueryLargestOffscreenArea(ScreenPtr pScreen,
 | 
						|
                              int *w, int *h,
 | 
						|
                              int gran, int preferences, int severity)
 | 
						|
{
 | 
						|
    FBManagerFuncsPtr funcs;
 | 
						|
 | 
						|
    *w = 0;
 | 
						|
    *h = 0;
 | 
						|
 | 
						|
    if (xf86FBManagerKey == NULL)
 | 
						|
        return FALSE;
 | 
						|
    if (!(funcs = (FBManagerFuncsPtr) dixLookupPrivate(&pScreen->devPrivates,
 | 
						|
                                                       xf86FBManagerKey)))
 | 
						|
        return FALSE;
 | 
						|
 | 
						|
    return (*funcs->QueryLargestOffscreenArea) (pScreen, w, h, gran,
 | 
						|
                                                preferences, severity);
 | 
						|
}
 | 
						|
 | 
						|
Bool
 | 
						|
xf86QueryLargestOffscreenLinear(ScreenPtr pScreen,
 | 
						|
                                int *size, int gran, int severity)
 | 
						|
{
 | 
						|
    FBManagerFuncsPtr funcs;
 | 
						|
 | 
						|
    *size = 0;
 | 
						|
 | 
						|
    if (xf86FBManagerKey == NULL)
 | 
						|
        return FALSE;
 | 
						|
    if (!(funcs = (FBManagerFuncsPtr) dixLookupPrivate(&pScreen->devPrivates,
 | 
						|
                                                       xf86FBManagerKey)))
 | 
						|
        return FALSE;
 | 
						|
 | 
						|
    return (*funcs->QueryLargestOffscreenLinear) (pScreen, size, gran,
 | 
						|
                                                  severity);
 | 
						|
}
 | 
						|
 | 
						|
Bool
 | 
						|
xf86PurgeUnlockedOffscreenAreas(ScreenPtr pScreen)
 | 
						|
{
 | 
						|
    FBManagerFuncsPtr funcs;
 | 
						|
 | 
						|
    if (xf86FBManagerKey == NULL)
 | 
						|
        return FALSE;
 | 
						|
    if (!(funcs = (FBManagerFuncsPtr) dixLookupPrivate(&pScreen->devPrivates,
 | 
						|
                                                       xf86FBManagerKey)))
 | 
						|
        return FALSE;
 | 
						|
 | 
						|
    return (*funcs->PurgeOffscreenAreas) (pScreen);
 | 
						|
}
 | 
						|
 | 
						|
/************************************************************\
 | 
						|
 | 
						|
   Below is a specific implementation of an offscreen manager.
 | 
						|
 | 
						|
\************************************************************/
 | 
						|
 | 
						|
static DevPrivateKeyRec xf86FBScreenKeyRec;
 | 
						|
 | 
						|
#define xf86FBScreenKey (&xf86FBScreenKeyRec)
 | 
						|
 | 
						|
typedef struct _FBLink {
 | 
						|
    FBArea area;
 | 
						|
    struct _FBLink *next;
 | 
						|
} FBLink, *FBLinkPtr;
 | 
						|
 | 
						|
typedef struct _FBLinearLink {
 | 
						|
    FBLinear linear;
 | 
						|
    int free;                   /* need to add free here as FBLinear is publicly accessible */
 | 
						|
    FBAreaPtr area;             /* only used if allocation came from XY area */
 | 
						|
    struct _FBLinearLink *next;
 | 
						|
} FBLinearLink, *FBLinearLinkPtr;
 | 
						|
 | 
						|
typedef struct {
 | 
						|
    ScreenPtr pScreen;
 | 
						|
    RegionPtr InitialBoxes;
 | 
						|
    RegionPtr FreeBoxes;
 | 
						|
    FBLinkPtr UsedAreas;
 | 
						|
    int NumUsedAreas;
 | 
						|
    FBLinearLinkPtr LinearAreas;
 | 
						|
    CloseScreenProcPtr CloseScreen;
 | 
						|
    int NumCallbacks;
 | 
						|
    FreeBoxCallbackProcPtr *FreeBoxesUpdateCallback;
 | 
						|
    DevUnion *devPrivates;
 | 
						|
} FBManager, *FBManagerPtr;
 | 
						|
 | 
						|
static void
 | 
						|
SendCallFreeBoxCallbacks(FBManagerPtr offman)
 | 
						|
{
 | 
						|
    int i = offman->NumCallbacks;
 | 
						|
 | 
						|
    while (i--) {
 | 
						|
        (*offman->FreeBoxesUpdateCallback[i]) (offman->pScreen,
 | 
						|
                                               offman->FreeBoxes,
 | 
						|
                                               offman->devPrivates[i].ptr);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static Bool
 | 
						|
localRegisterFreeBoxCallback(ScreenPtr pScreen,
 | 
						|
                             FreeBoxCallbackProcPtr FreeBoxCallback,
 | 
						|
                             void *devPriv)
 | 
						|
{
 | 
						|
    FBManagerPtr offman;
 | 
						|
    FreeBoxCallbackProcPtr *newCallbacks;
 | 
						|
    DevUnion *newPrivates;
 | 
						|
 | 
						|
    offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
 | 
						|
                                             xf86FBScreenKey);
 | 
						|
    newCallbacks = reallocarray(offman->FreeBoxesUpdateCallback,
 | 
						|
                                offman->NumCallbacks + 1,
 | 
						|
                                sizeof(FreeBoxCallbackProcPtr));
 | 
						|
    if (!newCallbacks)
 | 
						|
        return FALSE;
 | 
						|
    else
 | 
						|
        offman->FreeBoxesUpdateCallback = newCallbacks;
 | 
						|
 | 
						|
    newPrivates = reallocarray(offman->devPrivates,
 | 
						|
                               offman->NumCallbacks + 1,
 | 
						|
                               sizeof(DevUnion));
 | 
						|
    if (!newPrivates)
 | 
						|
        return FALSE;
 | 
						|
    else
 | 
						|
        offman->devPrivates = newPrivates;
 | 
						|
 | 
						|
    offman->FreeBoxesUpdateCallback[offman->NumCallbacks] = FreeBoxCallback;
 | 
						|
    offman->devPrivates[offman->NumCallbacks].ptr = devPriv;
 | 
						|
    offman->NumCallbacks++;
 | 
						|
 | 
						|
    SendCallFreeBoxCallbacks(offman);
 | 
						|
 | 
						|
    return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static FBAreaPtr
 | 
						|
AllocateArea(FBManagerPtr offman,
 | 
						|
             int w, int h,
 | 
						|
             int granularity,
 | 
						|
             MoveAreaCallbackProcPtr moveCB,
 | 
						|
             RemoveAreaCallbackProcPtr removeCB, void *privData)
 | 
						|
{
 | 
						|
    ScreenPtr pScreen = offman->pScreen;
 | 
						|
    FBLinkPtr link = NULL;
 | 
						|
    FBAreaPtr area = NULL;
 | 
						|
    RegionRec NewReg;
 | 
						|
    int i, x = 0, num;
 | 
						|
    BoxPtr boxp;
 | 
						|
 | 
						|
    if (granularity <= 1)
 | 
						|
        granularity = 0;
 | 
						|
 | 
						|
    boxp = RegionRects(offman->FreeBoxes);
 | 
						|
    num = RegionNumRects(offman->FreeBoxes);
 | 
						|
 | 
						|
    /* look through the free boxes */
 | 
						|
    for (i = 0; i < num; i++, boxp++) {
 | 
						|
        x = boxp->x1;
 | 
						|
        if (granularity > 1)
 | 
						|
            x = ((x + granularity - 1) / granularity) * granularity;
 | 
						|
 | 
						|
        if (((boxp->y2 - boxp->y1) < h) || ((boxp->x2 - x) < w))
 | 
						|
            continue;
 | 
						|
 | 
						|
        link = malloc(sizeof(FBLink));
 | 
						|
        if (!link)
 | 
						|
            return NULL;
 | 
						|
 | 
						|
        area = &(link->area);
 | 
						|
        link->next = offman->UsedAreas;
 | 
						|
        offman->UsedAreas = link;
 | 
						|
        offman->NumUsedAreas++;
 | 
						|
        break;
 | 
						|
    }
 | 
						|
 | 
						|
    /* try to boot a removable one out if we are not expendable ourselves */
 | 
						|
    if (!area && !removeCB) {
 | 
						|
        link = offman->UsedAreas;
 | 
						|
 | 
						|
        while (link) {
 | 
						|
            if (!link->area.RemoveAreaCallback) {
 | 
						|
                link = link->next;
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
 | 
						|
            boxp = &(link->area.box);
 | 
						|
            x = boxp->x1;
 | 
						|
            if (granularity > 1)
 | 
						|
                x = ((x + granularity - 1) / granularity) * granularity;
 | 
						|
 | 
						|
            if (((boxp->y2 - boxp->y1) < h) || ((boxp->x2 - x) < w)) {
 | 
						|
                link = link->next;
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
 | 
						|
            /* bye, bye */
 | 
						|
            (*link->area.RemoveAreaCallback) (&link->area);
 | 
						|
            RegionInit(&NewReg, &(link->area.box), 1);
 | 
						|
            RegionUnion(offman->FreeBoxes, offman->FreeBoxes, &NewReg);
 | 
						|
            RegionUninit(&NewReg);
 | 
						|
 | 
						|
            area = &(link->area);
 | 
						|
            break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if (area) {
 | 
						|
        area->pScreen = pScreen;
 | 
						|
        area->granularity = granularity;
 | 
						|
        area->box.x1 = x;
 | 
						|
        area->box.x2 = x + w;
 | 
						|
        area->box.y1 = boxp->y1;
 | 
						|
        area->box.y2 = boxp->y1 + h;
 | 
						|
        area->MoveAreaCallback = moveCB;
 | 
						|
        area->RemoveAreaCallback = removeCB;
 | 
						|
        area->devPrivate.ptr = privData;
 | 
						|
 | 
						|
        RegionInit(&NewReg, &(area->box), 1);
 | 
						|
        RegionSubtract(offman->FreeBoxes, offman->FreeBoxes, &NewReg);
 | 
						|
        RegionUninit(&NewReg);
 | 
						|
    }
 | 
						|
 | 
						|
    return area;
 | 
						|
}
 | 
						|
 | 
						|
static FBAreaPtr
 | 
						|
localAllocateOffscreenArea(ScreenPtr pScreen,
 | 
						|
                           int w, int h,
 | 
						|
                           int gran,
 | 
						|
                           MoveAreaCallbackProcPtr moveCB,
 | 
						|
                           RemoveAreaCallbackProcPtr removeCB, void *privData)
 | 
						|
{
 | 
						|
    FBManagerPtr offman;
 | 
						|
    FBAreaPtr area = NULL;
 | 
						|
 | 
						|
    offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
 | 
						|
                                             xf86FBScreenKey);
 | 
						|
    if ((area = AllocateArea(offman, w, h, gran, moveCB, removeCB, privData)))
 | 
						|
        SendCallFreeBoxCallbacks(offman);
 | 
						|
 | 
						|
    return area;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
localFreeOffscreenArea(FBAreaPtr area)
 | 
						|
{
 | 
						|
    FBManagerPtr offman;
 | 
						|
    FBLinkPtr pLink, pLinkPrev = NULL;
 | 
						|
    RegionRec FreedRegion;
 | 
						|
    ScreenPtr pScreen;
 | 
						|
 | 
						|
    pScreen = area->pScreen;
 | 
						|
    offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
 | 
						|
                                             xf86FBScreenKey);
 | 
						|
    pLink = offman->UsedAreas;
 | 
						|
    if (!pLink)
 | 
						|
        return;
 | 
						|
 | 
						|
    while (&(pLink->area) != area) {
 | 
						|
        pLinkPrev = pLink;
 | 
						|
        pLink = pLink->next;
 | 
						|
        if (!pLink)
 | 
						|
            return;
 | 
						|
    }
 | 
						|
 | 
						|
    /* put the area back into the pool */
 | 
						|
    RegionInit(&FreedRegion, &(pLink->area.box), 1);
 | 
						|
    RegionUnion(offman->FreeBoxes, offman->FreeBoxes, &FreedRegion);
 | 
						|
    RegionUninit(&FreedRegion);
 | 
						|
 | 
						|
    if (pLinkPrev)
 | 
						|
        pLinkPrev->next = pLink->next;
 | 
						|
    else
 | 
						|
        offman->UsedAreas = pLink->next;
 | 
						|
 | 
						|
    free(pLink);
 | 
						|
    offman->NumUsedAreas--;
 | 
						|
 | 
						|
    SendCallFreeBoxCallbacks(offman);
 | 
						|
}
 | 
						|
 | 
						|
static Bool
 | 
						|
localResizeOffscreenArea(FBAreaPtr resize, int w, int h)
 | 
						|
{
 | 
						|
    FBManagerPtr offman;
 | 
						|
    ScreenPtr pScreen;
 | 
						|
    BoxRec OrigArea;
 | 
						|
    RegionRec FreedReg;
 | 
						|
    FBAreaPtr area = NULL;
 | 
						|
    FBLinkPtr pLink, newLink, pLinkPrev = NULL;
 | 
						|
 | 
						|
    pScreen = resize->pScreen;
 | 
						|
    offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
 | 
						|
                                             xf86FBScreenKey);
 | 
						|
    /* find this link */
 | 
						|
    if (!(pLink = offman->UsedAreas))
 | 
						|
        return FALSE;
 | 
						|
 | 
						|
    while (&(pLink->area) != resize) {
 | 
						|
        pLinkPrev = pLink;
 | 
						|
        pLink = pLink->next;
 | 
						|
        if (!pLink)
 | 
						|
            return FALSE;
 | 
						|
    }
 | 
						|
 | 
						|
    OrigArea.x1 = resize->box.x1;
 | 
						|
    OrigArea.x2 = resize->box.x2;
 | 
						|
    OrigArea.y1 = resize->box.y1;
 | 
						|
    OrigArea.y2 = resize->box.y2;
 | 
						|
 | 
						|
    /* if it's smaller, this is easy */
 | 
						|
 | 
						|
    if ((w <= (resize->box.x2 - resize->box.x1)) &&
 | 
						|
        (h <= (resize->box.y2 - resize->box.y1))) {
 | 
						|
        RegionRec NewReg;
 | 
						|
 | 
						|
        resize->box.x2 = resize->box.x1 + w;
 | 
						|
        resize->box.y2 = resize->box.y1 + h;
 | 
						|
 | 
						|
        if ((resize->box.y2 == OrigArea.y2) && (resize->box.x2 == OrigArea.x2))
 | 
						|
            return TRUE;
 | 
						|
 | 
						|
        RegionInit(&FreedReg, &OrigArea, 1);
 | 
						|
        RegionInit(&NewReg, &(resize->box), 1);
 | 
						|
        RegionSubtract(&FreedReg, &FreedReg, &NewReg);
 | 
						|
        RegionUnion(offman->FreeBoxes, offman->FreeBoxes, &FreedReg);
 | 
						|
        RegionUninit(&FreedReg);
 | 
						|
        RegionUninit(&NewReg);
 | 
						|
 | 
						|
        SendCallFreeBoxCallbacks(offman);
 | 
						|
 | 
						|
        return TRUE;
 | 
						|
    }
 | 
						|
 | 
						|
    /* otherwise we remove the old region */
 | 
						|
 | 
						|
    RegionInit(&FreedReg, &OrigArea, 1);
 | 
						|
    RegionUnion(offman->FreeBoxes, offman->FreeBoxes, &FreedReg);
 | 
						|
 | 
						|
    /* remove the old link */
 | 
						|
    if (pLinkPrev)
 | 
						|
        pLinkPrev->next = pLink->next;
 | 
						|
    else
 | 
						|
        offman->UsedAreas = pLink->next;
 | 
						|
 | 
						|
    /* and try to add a new one */
 | 
						|
 | 
						|
    if ((area = AllocateArea(offman, w, h, resize->granularity,
 | 
						|
                             resize->MoveAreaCallback,
 | 
						|
                             resize->RemoveAreaCallback,
 | 
						|
                             resize->devPrivate.ptr))) {
 | 
						|
 | 
						|
        /* copy data over to our link and replace the new with old */
 | 
						|
        memcpy(resize, area, sizeof(FBArea));
 | 
						|
 | 
						|
        pLinkPrev = NULL;
 | 
						|
        newLink = offman->UsedAreas;
 | 
						|
 | 
						|
        while (&(newLink->area) != area) {
 | 
						|
            pLinkPrev = newLink;
 | 
						|
            newLink = newLink->next;
 | 
						|
        }
 | 
						|
 | 
						|
        if (pLinkPrev)
 | 
						|
            pLinkPrev->next = newLink->next;
 | 
						|
        else
 | 
						|
            offman->UsedAreas = newLink->next;
 | 
						|
 | 
						|
        pLink->next = offman->UsedAreas;
 | 
						|
        offman->UsedAreas = pLink;
 | 
						|
 | 
						|
        free(newLink);
 | 
						|
 | 
						|
        /* AllocateArea added one but we really only exchanged one */
 | 
						|
        offman->NumUsedAreas--;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        /* reinstate the old region */
 | 
						|
        RegionSubtract(offman->FreeBoxes, offman->FreeBoxes, &FreedReg);
 | 
						|
        RegionUninit(&FreedReg);
 | 
						|
 | 
						|
        pLink->next = offman->UsedAreas;
 | 
						|
        offman->UsedAreas = pLink;
 | 
						|
        return FALSE;
 | 
						|
    }
 | 
						|
 | 
						|
    RegionUninit(&FreedReg);
 | 
						|
 | 
						|
    SendCallFreeBoxCallbacks(offman);
 | 
						|
 | 
						|
    return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static Bool
 | 
						|
localQueryLargestOffscreenArea(ScreenPtr pScreen,
 | 
						|
                               int *width, int *height,
 | 
						|
                               int granularity, int preferences, int severity)
 | 
						|
{
 | 
						|
    FBManagerPtr offman;
 | 
						|
    RegionPtr newRegion = NULL;
 | 
						|
    BoxPtr pbox;
 | 
						|
    int nbox;
 | 
						|
    int x, w, h, area, oldArea;
 | 
						|
 | 
						|
    *width = *height = oldArea = 0;
 | 
						|
 | 
						|
    if (granularity <= 1)
 | 
						|
        granularity = 0;
 | 
						|
 | 
						|
    if ((preferences < 0) || (preferences > 3))
 | 
						|
        return FALSE;
 | 
						|
 | 
						|
    offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
 | 
						|
                                             xf86FBScreenKey);
 | 
						|
    if (severity < 0)
 | 
						|
        severity = 0;
 | 
						|
    if (severity > 2)
 | 
						|
        severity = 2;
 | 
						|
 | 
						|
    switch (severity) {
 | 
						|
    case 2:
 | 
						|
        if (offman->NumUsedAreas) {
 | 
						|
            FBLinkPtr pLink;
 | 
						|
            RegionRec tmpRegion;
 | 
						|
 | 
						|
            newRegion = RegionCreate(NULL, 1);
 | 
						|
            RegionCopy(newRegion, offman->InitialBoxes);
 | 
						|
            pLink = offman->UsedAreas;
 | 
						|
 | 
						|
            while (pLink) {
 | 
						|
                if (!pLink->area.RemoveAreaCallback) {
 | 
						|
                    RegionInit(&tmpRegion, &(pLink->area.box), 1);
 | 
						|
                    RegionSubtract(newRegion, newRegion, &tmpRegion);
 | 
						|
                    RegionUninit(&tmpRegion);
 | 
						|
                }
 | 
						|
                pLink = pLink->next;
 | 
						|
            }
 | 
						|
 | 
						|
            nbox = RegionNumRects(newRegion);
 | 
						|
            pbox = RegionRects(newRegion);
 | 
						|
            break;
 | 
						|
        }
 | 
						|
    case 1:
 | 
						|
        if (offman->NumUsedAreas) {
 | 
						|
            FBLinkPtr pLink;
 | 
						|
            RegionRec tmpRegion;
 | 
						|
 | 
						|
            newRegion = RegionCreate(NULL, 1);
 | 
						|
            RegionCopy(newRegion, offman->FreeBoxes);
 | 
						|
            pLink = offman->UsedAreas;
 | 
						|
 | 
						|
            while (pLink) {
 | 
						|
                if (pLink->area.RemoveAreaCallback) {
 | 
						|
                    RegionInit(&tmpRegion, &(pLink->area.box), 1);
 | 
						|
                    RegionAppend(newRegion, &tmpRegion);
 | 
						|
                    RegionUninit(&tmpRegion);
 | 
						|
                }
 | 
						|
                pLink = pLink->next;
 | 
						|
            }
 | 
						|
 | 
						|
            nbox = RegionNumRects(newRegion);
 | 
						|
            pbox = RegionRects(newRegion);
 | 
						|
            break;
 | 
						|
        }
 | 
						|
    default:
 | 
						|
        nbox = RegionNumRects(offman->FreeBoxes);
 | 
						|
        pbox = RegionRects(offman->FreeBoxes);
 | 
						|
        break;
 | 
						|
    }
 | 
						|
 | 
						|
    while (nbox--) {
 | 
						|
        x = pbox->x1;
 | 
						|
        if (granularity > 1)
 | 
						|
            x = ((x + granularity - 1) / granularity) * granularity;
 | 
						|
 | 
						|
        w = pbox->x2 - x;
 | 
						|
        h = pbox->y2 - pbox->y1;
 | 
						|
        area = w * h;
 | 
						|
 | 
						|
        if (w > 0) {
 | 
						|
            Bool gotIt = FALSE;
 | 
						|
 | 
						|
            switch (preferences) {
 | 
						|
            case FAVOR_AREA_THEN_WIDTH:
 | 
						|
                if ((area > oldArea) || ((area == oldArea) && (w > *width)))
 | 
						|
                    gotIt = TRUE;
 | 
						|
                break;
 | 
						|
            case FAVOR_AREA_THEN_HEIGHT:
 | 
						|
                if ((area > oldArea) || ((area == oldArea) && (h > *height)))
 | 
						|
                    gotIt = TRUE;
 | 
						|
                break;
 | 
						|
            case FAVOR_WIDTH_THEN_AREA:
 | 
						|
                if ((w > *width) || ((w == *width) && (area > oldArea)))
 | 
						|
                    gotIt = TRUE;
 | 
						|
                break;
 | 
						|
            case FAVOR_HEIGHT_THEN_AREA:
 | 
						|
                if ((h > *height) || ((h == *height) && (area > oldArea)))
 | 
						|
                    gotIt = TRUE;
 | 
						|
                break;
 | 
						|
            }
 | 
						|
            if (gotIt) {
 | 
						|
                *width = w;
 | 
						|
                *height = h;
 | 
						|
                oldArea = area;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        pbox++;
 | 
						|
    }
 | 
						|
 | 
						|
    if (newRegion)
 | 
						|
        RegionDestroy(newRegion);
 | 
						|
 | 
						|
    return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static Bool
 | 
						|
localPurgeUnlockedOffscreenAreas(ScreenPtr pScreen)
 | 
						|
{
 | 
						|
    FBManagerPtr offman;
 | 
						|
    FBLinkPtr pLink, tmp, pPrev = NULL;
 | 
						|
    RegionRec FreedRegion;
 | 
						|
    Bool anyUsed = FALSE;
 | 
						|
 | 
						|
    offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
 | 
						|
                                             xf86FBScreenKey);
 | 
						|
    pLink = offman->UsedAreas;
 | 
						|
    if (!pLink)
 | 
						|
        return TRUE;
 | 
						|
 | 
						|
    while (pLink) {
 | 
						|
        if (pLink->area.RemoveAreaCallback) {
 | 
						|
            (*pLink->area.RemoveAreaCallback) (&pLink->area);
 | 
						|
 | 
						|
            RegionInit(&FreedRegion, &(pLink->area.box), 1);
 | 
						|
            RegionAppend(offman->FreeBoxes, &FreedRegion);
 | 
						|
            RegionUninit(&FreedRegion);
 | 
						|
 | 
						|
            if (pPrev)
 | 
						|
                pPrev->next = pLink->next;
 | 
						|
            else
 | 
						|
                offman->UsedAreas = pLink->next;
 | 
						|
 | 
						|
            tmp = pLink;
 | 
						|
            pLink = pLink->next;
 | 
						|
            free(tmp);
 | 
						|
            offman->NumUsedAreas--;
 | 
						|
            anyUsed = TRUE;
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            pPrev = pLink;
 | 
						|
            pLink = pLink->next;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if (anyUsed) {
 | 
						|
        RegionValidate(offman->FreeBoxes, &anyUsed);
 | 
						|
        SendCallFreeBoxCallbacks(offman);
 | 
						|
    }
 | 
						|
 | 
						|
    return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
LinearMoveCBWrapper(FBAreaPtr from, FBAreaPtr to)
 | 
						|
{
 | 
						|
    /* this will never get called */
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
LinearRemoveCBWrapper(FBAreaPtr area)
 | 
						|
{
 | 
						|
    FBManagerPtr offman;
 | 
						|
    FBLinearLinkPtr pLink, pLinkPrev = NULL;
 | 
						|
    ScreenPtr pScreen = area->pScreen;
 | 
						|
 | 
						|
    offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
 | 
						|
                                             xf86FBScreenKey);
 | 
						|
    pLink = offman->LinearAreas;
 | 
						|
    if (!pLink)
 | 
						|
        return;
 | 
						|
 | 
						|
    while (pLink->area != area) {
 | 
						|
        pLinkPrev = pLink;
 | 
						|
        pLink = pLink->next;
 | 
						|
        if (!pLink)
 | 
						|
            return;
 | 
						|
    }
 | 
						|
 | 
						|
    /* give the user the callback it is expecting */
 | 
						|
    (*pLink->linear.RemoveLinearCallback) (&(pLink->linear));
 | 
						|
 | 
						|
    if (pLinkPrev)
 | 
						|
        pLinkPrev->next = pLink->next;
 | 
						|
    else
 | 
						|
        offman->LinearAreas = pLink->next;
 | 
						|
 | 
						|
    free(pLink);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
DumpDebug(FBLinearLinkPtr pLink)
 | 
						|
{
 | 
						|
#ifdef DEBUG
 | 
						|
    if (!pLink)
 | 
						|
        ErrorF("MMmm, PLINK IS NULL!\n");
 | 
						|
 | 
						|
    while (pLink) {
 | 
						|
        ErrorF("  Offset:%08x, Size:%08x, %s,%s\n",
 | 
						|
               pLink->linear.offset,
 | 
						|
               pLink->linear.size,
 | 
						|
               pLink->free ? "Free" : "Used", pLink->area ? "Area" : "Linear");
 | 
						|
 | 
						|
        pLink = pLink->next;
 | 
						|
    }
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
static FBLinearPtr
 | 
						|
AllocateLinear(FBManagerPtr offman, int size, int granularity, void *privData)
 | 
						|
{
 | 
						|
    ScreenPtr pScreen = offman->pScreen;
 | 
						|
    FBLinearLinkPtr linear = NULL;
 | 
						|
    FBLinearLinkPtr newlink = NULL;
 | 
						|
    int offset, end;
 | 
						|
 | 
						|
    if (size <= 0)
 | 
						|
        return NULL;
 | 
						|
 | 
						|
    if (!offman->LinearAreas)
 | 
						|
        return NULL;
 | 
						|
 | 
						|
    linear = offman->LinearAreas;
 | 
						|
    while (linear) {
 | 
						|
        /* Make sure we get a free area that's not an XY fallback case */
 | 
						|
        if (!linear->area && linear->free) {
 | 
						|
            offset = linear->linear.offset;
 | 
						|
            if (granularity > 1)
 | 
						|
                offset =
 | 
						|
                    ((offset + granularity - 1) / granularity) * granularity;
 | 
						|
            end = offset + size;
 | 
						|
            if (end <= (linear->linear.offset + linear->linear.size))
 | 
						|
                break;
 | 
						|
        }
 | 
						|
        linear = linear->next;
 | 
						|
    }
 | 
						|
    if (!linear)
 | 
						|
        return NULL;
 | 
						|
 | 
						|
    /* break left */
 | 
						|
    if (offset > linear->linear.offset) {
 | 
						|
        newlink = malloc(sizeof(FBLinearLink));
 | 
						|
        if (!newlink)
 | 
						|
            return NULL;
 | 
						|
        newlink->area = NULL;
 | 
						|
        newlink->linear.offset = offset;
 | 
						|
        newlink->linear.size =
 | 
						|
            linear->linear.size - (offset - linear->linear.offset);
 | 
						|
        newlink->free = 1;
 | 
						|
        newlink->next = linear->next;
 | 
						|
        linear->linear.size -= newlink->linear.size;
 | 
						|
        linear->next = newlink;
 | 
						|
        linear = newlink;
 | 
						|
    }
 | 
						|
 | 
						|
    /* break right */
 | 
						|
    if (size < linear->linear.size) {
 | 
						|
        newlink = malloc(sizeof(FBLinearLink));
 | 
						|
        if (!newlink)
 | 
						|
            return NULL;
 | 
						|
        newlink->area = NULL;
 | 
						|
        newlink->linear.offset = offset + size;
 | 
						|
        newlink->linear.size = linear->linear.size - size;
 | 
						|
        newlink->free = 1;
 | 
						|
        newlink->next = linear->next;
 | 
						|
        linear->linear.size = size;
 | 
						|
        linear->next = newlink;
 | 
						|
    }
 | 
						|
 | 
						|
    /* p = middle block */
 | 
						|
    linear->linear.granularity = granularity;
 | 
						|
    linear->free = 0;
 | 
						|
    linear->linear.pScreen = pScreen;
 | 
						|
    linear->linear.MoveLinearCallback = NULL;
 | 
						|
    linear->linear.RemoveLinearCallback = NULL;
 | 
						|
    linear->linear.devPrivate.ptr = NULL;
 | 
						|
 | 
						|
    DumpDebug(offman->LinearAreas);
 | 
						|
 | 
						|
    return &(linear->linear);
 | 
						|
}
 | 
						|
 | 
						|
static FBLinearPtr
 | 
						|
localAllocateOffscreenLinear(ScreenPtr pScreen,
 | 
						|
                             int length,
 | 
						|
                             int gran,
 | 
						|
                             MoveLinearCallbackProcPtr moveCB,
 | 
						|
                             RemoveLinearCallbackProcPtr removeCB,
 | 
						|
                             void *privData)
 | 
						|
{
 | 
						|
    FBManagerPtr offman;
 | 
						|
    FBLinearLinkPtr link;
 | 
						|
    FBAreaPtr area;
 | 
						|
    FBLinearPtr linear = NULL;
 | 
						|
    BoxPtr extents;
 | 
						|
    int w, h, pitch;
 | 
						|
 | 
						|
    offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
 | 
						|
                                             xf86FBScreenKey);
 | 
						|
 | 
						|
    /* Try to allocate from linear memory first...... */
 | 
						|
    DebugF("ALLOCATING LINEAR\n");
 | 
						|
    if ((linear = AllocateLinear(offman, length, gran, privData)))
 | 
						|
        return linear;
 | 
						|
 | 
						|
    DebugF("NOPE, ALLOCATING AREA\n");
 | 
						|
 | 
						|
    if (!(link = malloc(sizeof(FBLinearLink))))
 | 
						|
        return NULL;
 | 
						|
 | 
						|
    /* No linear available, so try and pinch some from the XY areas */
 | 
						|
    extents = RegionExtents(offman->InitialBoxes);
 | 
						|
    pitch = extents->x2 - extents->x1;
 | 
						|
 | 
						|
    if (gran > 1) {
 | 
						|
        if (gran > pitch) {
 | 
						|
            /* we can't match the specified alignment with XY allocations */
 | 
						|
            free(link);
 | 
						|
            return NULL;
 | 
						|
        }
 | 
						|
 | 
						|
        if (pitch % gran) {
 | 
						|
            /* pitch and granularity aren't a perfect match, let's allocate
 | 
						|
             * a bit more so we can align later on
 | 
						|
             */
 | 
						|
            length += gran - 1;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if (length < pitch) {       /* special case */
 | 
						|
        w = length;
 | 
						|
        h = 1;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        w = pitch;
 | 
						|
        h = (length + pitch - 1) / pitch;
 | 
						|
    }
 | 
						|
 | 
						|
    if ((area = localAllocateOffscreenArea(pScreen, w, h, gran,
 | 
						|
                                           moveCB ? LinearMoveCBWrapper : NULL,
 | 
						|
                                           removeCB ? LinearRemoveCBWrapper :
 | 
						|
                                           NULL, privData))) {
 | 
						|
        link->area = area;
 | 
						|
        link->free = 0;
 | 
						|
        link->next = offman->LinearAreas;
 | 
						|
        offman->LinearAreas = link;
 | 
						|
        linear = &(link->linear);
 | 
						|
        linear->pScreen = pScreen;
 | 
						|
        linear->size = h * w;
 | 
						|
        linear->offset = (pitch * area->box.y1) + area->box.x1;
 | 
						|
        if (gran > 1)
 | 
						|
            linear->offset = ((linear->offset + gran - 1) / gran) * gran;
 | 
						|
        linear->granularity = gran;
 | 
						|
        linear->MoveLinearCallback = moveCB;
 | 
						|
        linear->RemoveLinearCallback = removeCB;
 | 
						|
        linear->devPrivate.ptr = privData;
 | 
						|
    }
 | 
						|
    else
 | 
						|
        free(link);
 | 
						|
 | 
						|
    DumpDebug(offman->LinearAreas);
 | 
						|
 | 
						|
    return linear;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
localFreeOffscreenLinear(FBLinearPtr linear)
 | 
						|
{
 | 
						|
    FBManagerPtr offman;
 | 
						|
    FBLinearLinkPtr pLink, pLinkPrev = NULL;
 | 
						|
    ScreenPtr pScreen = linear->pScreen;
 | 
						|
 | 
						|
    offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
 | 
						|
                                             xf86FBScreenKey);
 | 
						|
    pLink = offman->LinearAreas;
 | 
						|
    if (!pLink)
 | 
						|
        return;
 | 
						|
 | 
						|
    while (&(pLink->linear) != linear) {
 | 
						|
        pLinkPrev = pLink;
 | 
						|
        pLink = pLink->next;
 | 
						|
        if (!pLink)
 | 
						|
            return;
 | 
						|
    }
 | 
						|
 | 
						|
    if (pLink->area) {          /* really an XY area */
 | 
						|
        DebugF("FREEING AREA\n");
 | 
						|
        localFreeOffscreenArea(pLink->area);
 | 
						|
        if (pLinkPrev)
 | 
						|
            pLinkPrev->next = pLink->next;
 | 
						|
        else
 | 
						|
            offman->LinearAreas = pLink->next;
 | 
						|
        free(pLink);
 | 
						|
        DumpDebug(offman->LinearAreas);
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    pLink->free = 1;
 | 
						|
 | 
						|
    if (pLink->next && pLink->next->free) {
 | 
						|
        FBLinearLinkPtr p = pLink->next;
 | 
						|
 | 
						|
        pLink->linear.size += p->linear.size;
 | 
						|
        pLink->next = p->next;
 | 
						|
        free(p);
 | 
						|
    }
 | 
						|
 | 
						|
    if (pLinkPrev) {
 | 
						|
        if (pLinkPrev->next && pLinkPrev->next->free && !pLinkPrev->area) {
 | 
						|
            FBLinearLinkPtr p = pLinkPrev->next;
 | 
						|
 | 
						|
            pLinkPrev->linear.size += p->linear.size;
 | 
						|
            pLinkPrev->next = p->next;
 | 
						|
            free(p);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    DebugF("FREEING LINEAR\n");
 | 
						|
    DumpDebug(offman->LinearAreas);
 | 
						|
}
 | 
						|
 | 
						|
static Bool
 | 
						|
localResizeOffscreenLinear(FBLinearPtr resize, int length)
 | 
						|
{
 | 
						|
    FBManagerPtr offman;
 | 
						|
    FBLinearLinkPtr pLink;
 | 
						|
    ScreenPtr pScreen = resize->pScreen;
 | 
						|
 | 
						|
    offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
 | 
						|
                                             xf86FBScreenKey);
 | 
						|
    pLink = offman->LinearAreas;
 | 
						|
    if (!pLink)
 | 
						|
        return FALSE;
 | 
						|
 | 
						|
    while (&(pLink->linear) != resize) {
 | 
						|
        pLink = pLink->next;
 | 
						|
        if (!pLink)
 | 
						|
            return FALSE;
 | 
						|
    }
 | 
						|
 | 
						|
    /* This could actually be a lot smarter and try to move allocations
 | 
						|
       from XY to linear when available.  For now if it was XY, we keep
 | 
						|
       it XY */
 | 
						|
 | 
						|
    if (pLink->area) {          /* really an XY area */
 | 
						|
        BoxPtr extents;
 | 
						|
        int pitch, w, h;
 | 
						|
 | 
						|
        extents = RegionExtents(offman->InitialBoxes);
 | 
						|
        pitch = extents->x2 - extents->x1;
 | 
						|
 | 
						|
        if (length < pitch) {   /* special case */
 | 
						|
            w = length;
 | 
						|
            h = 1;
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            w = pitch;
 | 
						|
            h = (length + pitch - 1) / pitch;
 | 
						|
        }
 | 
						|
 | 
						|
        if (localResizeOffscreenArea(pLink->area, w, h)) {
 | 
						|
            resize->size = h * w;
 | 
						|
            resize->offset =
 | 
						|
                (pitch * pLink->area->box.y1) + pLink->area->box.x1;
 | 
						|
            return TRUE;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        /* TODO!!!! resize the linear area */
 | 
						|
    }
 | 
						|
 | 
						|
    return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static Bool
 | 
						|
localQueryLargestOffscreenLinear(ScreenPtr pScreen,
 | 
						|
                                 int *size, int gran, int priority)
 | 
						|
{
 | 
						|
    FBManagerPtr offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
 | 
						|
                                                          xf86FBScreenKey);
 | 
						|
    FBLinearLinkPtr pLink;
 | 
						|
    FBLinearLinkPtr pLinkRet;
 | 
						|
 | 
						|
    *size = 0;
 | 
						|
 | 
						|
    pLink = offman->LinearAreas;
 | 
						|
 | 
						|
    if (pLink && !pLink->area) {
 | 
						|
        pLinkRet = pLink;
 | 
						|
        while (pLink) {
 | 
						|
            if (pLink->free) {
 | 
						|
                if (pLink->linear.size > pLinkRet->linear.size)
 | 
						|
                    pLinkRet = pLink;
 | 
						|
            }
 | 
						|
            pLink = pLink->next;
 | 
						|
        }
 | 
						|
 | 
						|
        if (pLinkRet->free) {
 | 
						|
            *size = pLinkRet->linear.size;
 | 
						|
            return TRUE;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        int w, h;
 | 
						|
 | 
						|
        if (localQueryLargestOffscreenArea(pScreen, &w, &h, gran,
 | 
						|
                                           FAVOR_WIDTH_THEN_AREA, priority)) {
 | 
						|
            BoxPtr extents;
 | 
						|
 | 
						|
            extents = RegionExtents(offman->InitialBoxes);
 | 
						|
            if ((extents->x2 - extents->x1) == w)
 | 
						|
                *size = w * h;
 | 
						|
            return TRUE;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static FBManagerFuncs xf86FBManFuncs = {
 | 
						|
    localAllocateOffscreenArea,
 | 
						|
    localFreeOffscreenArea,
 | 
						|
    localResizeOffscreenArea,
 | 
						|
    localQueryLargestOffscreenArea,
 | 
						|
    localRegisterFreeBoxCallback,
 | 
						|
    localAllocateOffscreenLinear,
 | 
						|
    localFreeOffscreenLinear,
 | 
						|
    localResizeOffscreenLinear,
 | 
						|
    localQueryLargestOffscreenLinear,
 | 
						|
    localPurgeUnlockedOffscreenAreas
 | 
						|
};
 | 
						|
 | 
						|
static Bool
 | 
						|
xf86FBCloseScreen(ScreenPtr pScreen)
 | 
						|
{
 | 
						|
    FBLinkPtr pLink, tmp;
 | 
						|
    FBLinearLinkPtr pLinearLink, tmp2;
 | 
						|
    FBManagerPtr offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
 | 
						|
                                                          xf86FBScreenKey);
 | 
						|
 | 
						|
    pScreen->CloseScreen = offman->CloseScreen;
 | 
						|
 | 
						|
    pLink = offman->UsedAreas;
 | 
						|
    while (pLink) {
 | 
						|
        tmp = pLink;
 | 
						|
        pLink = pLink->next;
 | 
						|
        free(tmp);
 | 
						|
    }
 | 
						|
 | 
						|
    pLinearLink = offman->LinearAreas;
 | 
						|
    while (pLinearLink) {
 | 
						|
        tmp2 = pLinearLink;
 | 
						|
        pLinearLink = pLinearLink->next;
 | 
						|
        free(tmp2);
 | 
						|
    }
 | 
						|
 | 
						|
    RegionDestroy(offman->InitialBoxes);
 | 
						|
    RegionDestroy(offman->FreeBoxes);
 | 
						|
 | 
						|
    free(offman->FreeBoxesUpdateCallback);
 | 
						|
    free(offman->devPrivates);
 | 
						|
    free(offman);
 | 
						|
    dixSetPrivate(&pScreen->devPrivates, xf86FBScreenKey, NULL);
 | 
						|
 | 
						|
    return (*pScreen->CloseScreen) (pScreen);
 | 
						|
}
 | 
						|
 | 
						|
Bool
 | 
						|
xf86InitFBManager(ScreenPtr pScreen, BoxPtr FullBox)
 | 
						|
{
 | 
						|
    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
 | 
						|
    RegionRec ScreenRegion;
 | 
						|
    RegionRec FullRegion;
 | 
						|
    BoxRec ScreenBox;
 | 
						|
    Bool ret;
 | 
						|
 | 
						|
    ScreenBox.x1 = 0;
 | 
						|
    ScreenBox.y1 = 0;
 | 
						|
    ScreenBox.x2 = pScrn->virtualX;
 | 
						|
    ScreenBox.y2 = pScrn->virtualY;
 | 
						|
 | 
						|
    if ((FullBox->x1 > ScreenBox.x1) || (FullBox->y1 > ScreenBox.y1) ||
 | 
						|
        (FullBox->x2 < ScreenBox.x2) || (FullBox->y2 < ScreenBox.y2)) {
 | 
						|
        return FALSE;
 | 
						|
    }
 | 
						|
 | 
						|
    if (FullBox->y2 < FullBox->y1)
 | 
						|
        return FALSE;
 | 
						|
    if (FullBox->x2 < FullBox->x1)
 | 
						|
        return FALSE;
 | 
						|
 | 
						|
    RegionInit(&ScreenRegion, &ScreenBox, 1);
 | 
						|
    RegionInit(&FullRegion, FullBox, 1);
 | 
						|
 | 
						|
    RegionSubtract(&FullRegion, &FullRegion, &ScreenRegion);
 | 
						|
 | 
						|
    ret = xf86InitFBManagerRegion(pScreen, &FullRegion);
 | 
						|
 | 
						|
    RegionUninit(&ScreenRegion);
 | 
						|
    RegionUninit(&FullRegion);
 | 
						|
 | 
						|
    return ret;
 | 
						|
}
 | 
						|
 | 
						|
Bool
 | 
						|
xf86InitFBManagerArea(ScreenPtr pScreen, int PixelArea, int Verbosity)
 | 
						|
{
 | 
						|
    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
 | 
						|
    xRectangle Rect[3];
 | 
						|
    RegionPtr pRegion, pScreenRegion;
 | 
						|
    int nRect;
 | 
						|
    Bool ret = FALSE;
 | 
						|
 | 
						|
    if (PixelArea < (pScrn->displayWidth * pScrn->virtualY))
 | 
						|
        return FALSE;
 | 
						|
 | 
						|
    Rect[0].x = Rect[0].y = 0;
 | 
						|
    Rect[0].width = pScrn->displayWidth;
 | 
						|
    Rect[0].height = PixelArea / pScrn->displayWidth;
 | 
						|
    nRect = 1;
 | 
						|
 | 
						|
    /* Add a possible partial scanline */
 | 
						|
    if ((Rect[1].height = Rect[1].width = PixelArea % pScrn->displayWidth)) {
 | 
						|
        Rect[1].x = 0;
 | 
						|
        Rect[1].y = Rect[0].height;
 | 
						|
        Rect[1].height = 1;
 | 
						|
        nRect++;
 | 
						|
    }
 | 
						|
 | 
						|
    /* Factor out virtual resolution */
 | 
						|
    pRegion = RegionFromRects(nRect, Rect, 0);
 | 
						|
    if (pRegion) {
 | 
						|
        if (!RegionNar(pRegion)) {
 | 
						|
            Rect[2].x = Rect[2].y = 0;
 | 
						|
            Rect[2].width = pScrn->virtualX;
 | 
						|
            Rect[2].height = pScrn->virtualY;
 | 
						|
 | 
						|
            pScreenRegion = RegionFromRects(1, &Rect[2], 0);
 | 
						|
            if (pScreenRegion) {
 | 
						|
                if (!RegionNar(pScreenRegion)) {
 | 
						|
                    RegionSubtract(pRegion, pRegion, pScreenRegion);
 | 
						|
 | 
						|
                    ret = xf86InitFBManagerRegion(pScreen, pRegion);
 | 
						|
 | 
						|
                    if (ret && xf86GetVerbosity() >= Verbosity) {
 | 
						|
                        int scrnIndex = pScrn->scrnIndex;
 | 
						|
 | 
						|
                        xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity,
 | 
						|
                                       "Largest offscreen areas (with overlaps):\n");
 | 
						|
 | 
						|
                        if (Rect[2].width < Rect[0].width) {
 | 
						|
                            xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity,
 | 
						|
                                           "\t%d x %d rectangle at %d,0\n",
 | 
						|
                                           Rect[0].width - Rect[2].width,
 | 
						|
                                           Rect[0].height, Rect[2].width);
 | 
						|
                        }
 | 
						|
                        if (Rect[2].width < Rect[1].width) {
 | 
						|
                            xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity,
 | 
						|
                                           "\t%d x %d rectangle at %d,0\n",
 | 
						|
                                           Rect[1].width - Rect[2].width,
 | 
						|
                                           Rect[0].height + Rect[1].height,
 | 
						|
                                           Rect[2].width);
 | 
						|
                        }
 | 
						|
                        if (Rect[2].height < Rect[0].height) {
 | 
						|
                            xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity,
 | 
						|
                                           "\t%d x %d rectangle at 0,%d\n",
 | 
						|
                                           Rect[0].width,
 | 
						|
                                           Rect[0].height - Rect[2].height,
 | 
						|
                                           Rect[2].height);
 | 
						|
                        }
 | 
						|
                        if (Rect[1].height) {
 | 
						|
                            xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity,
 | 
						|
                                           "\t%d x %d rectangle at 0,%d\n",
 | 
						|
                                           Rect[1].width,
 | 
						|
                                           Rect[0].height - Rect[2].height +
 | 
						|
                                           Rect[1].height, Rect[2].height);
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                }
 | 
						|
 | 
						|
                RegionDestroy(pScreenRegion);
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        RegionDestroy(pRegion);
 | 
						|
    }
 | 
						|
 | 
						|
    return ret;
 | 
						|
}
 | 
						|
 | 
						|
Bool
 | 
						|
xf86InitFBManagerRegion(ScreenPtr pScreen, RegionPtr FullRegion)
 | 
						|
{
 | 
						|
    FBManagerPtr offman;
 | 
						|
 | 
						|
    if (RegionNil(FullRegion))
 | 
						|
        return FALSE;
 | 
						|
 | 
						|
    if (!dixRegisterPrivateKey(&xf86FBScreenKeyRec, PRIVATE_SCREEN, 0))
 | 
						|
        return FALSE;
 | 
						|
 | 
						|
    if (!xf86RegisterOffscreenManager(pScreen, &xf86FBManFuncs))
 | 
						|
        return FALSE;
 | 
						|
 | 
						|
    offman = malloc(sizeof(FBManager));
 | 
						|
    if (!offman)
 | 
						|
        return FALSE;
 | 
						|
 | 
						|
    dixSetPrivate(&pScreen->devPrivates, xf86FBScreenKey, offman);
 | 
						|
 | 
						|
    offman->CloseScreen = pScreen->CloseScreen;
 | 
						|
    pScreen->CloseScreen = xf86FBCloseScreen;
 | 
						|
 | 
						|
    offman->InitialBoxes = RegionCreate(NULL, 1);
 | 
						|
    offman->FreeBoxes = RegionCreate(NULL, 1);
 | 
						|
 | 
						|
    RegionCopy(offman->InitialBoxes, FullRegion);
 | 
						|
    RegionCopy(offman->FreeBoxes, FullRegion);
 | 
						|
 | 
						|
    offman->pScreen = pScreen;
 | 
						|
    offman->UsedAreas = NULL;
 | 
						|
    offman->LinearAreas = NULL;
 | 
						|
    offman->NumUsedAreas = 0;
 | 
						|
    offman->NumCallbacks = 0;
 | 
						|
    offman->FreeBoxesUpdateCallback = NULL;
 | 
						|
    offman->devPrivates = NULL;
 | 
						|
 | 
						|
    return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
Bool
 | 
						|
xf86InitFBManagerLinear(ScreenPtr pScreen, int offset, int size)
 | 
						|
{
 | 
						|
    FBManagerPtr offman;
 | 
						|
    FBLinearLinkPtr link;
 | 
						|
    FBLinearPtr linear;
 | 
						|
 | 
						|
    if (size <= 0)
 | 
						|
        return FALSE;
 | 
						|
 | 
						|
    /* we expect people to have called the Area setup first for pixmap cache */
 | 
						|
    if (!dixLookupPrivate(&pScreen->devPrivates, xf86FBScreenKey))
 | 
						|
        return FALSE;
 | 
						|
 | 
						|
    offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
 | 
						|
                                             xf86FBScreenKey);
 | 
						|
    offman->LinearAreas = malloc(sizeof(FBLinearLink));
 | 
						|
    if (!offman->LinearAreas)
 | 
						|
        return FALSE;
 | 
						|
 | 
						|
    link = offman->LinearAreas;
 | 
						|
    link->area = NULL;
 | 
						|
    link->next = NULL;
 | 
						|
    link->free = 1;
 | 
						|
    linear = &(link->linear);
 | 
						|
    linear->pScreen = pScreen;
 | 
						|
    linear->size = size;
 | 
						|
    linear->offset = offset;
 | 
						|
    linear->granularity = 0;
 | 
						|
    linear->MoveLinearCallback = NULL;
 | 
						|
    linear->RemoveLinearCallback = NULL;
 | 
						|
    linear->devPrivate.ptr = NULL;
 | 
						|
 | 
						|
    return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
/* This is an implementation specific function and should
 | 
						|
   disappear after the next release.  People should use the
 | 
						|
   real linear functions instead */
 | 
						|
 | 
						|
FBAreaPtr
 | 
						|
xf86AllocateLinearOffscreenArea(ScreenPtr pScreen,
 | 
						|
                                int length,
 | 
						|
                                int gran,
 | 
						|
                                MoveAreaCallbackProcPtr moveCB,
 | 
						|
                                RemoveAreaCallbackProcPtr removeCB,
 | 
						|
                                void *privData)
 | 
						|
{
 | 
						|
    FBManagerFuncsPtr funcs;
 | 
						|
    FBManagerPtr offman;
 | 
						|
    BoxPtr extents;
 | 
						|
    int w, h;
 | 
						|
 | 
						|
    if (xf86FBManagerKey == NULL)
 | 
						|
        return NULL;
 | 
						|
    if (!(funcs = (FBManagerFuncsPtr) dixLookupPrivate(&pScreen->devPrivates,
 | 
						|
                                                       xf86FBManagerKey)))
 | 
						|
        return NULL;
 | 
						|
 | 
						|
    offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
 | 
						|
                                             xf86FBScreenKey);
 | 
						|
    extents = RegionExtents(offman->InitialBoxes);
 | 
						|
    w = extents->x2 - extents->x1;
 | 
						|
 | 
						|
    if (gran > 1) {
 | 
						|
        if (gran > w)
 | 
						|
            return NULL;
 | 
						|
 | 
						|
        if (w % gran)
 | 
						|
            length += gran - 1;
 | 
						|
    }
 | 
						|
 | 
						|
    if (length <= w) {          /* special case */
 | 
						|
        h = 1;
 | 
						|
        w = length;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        h = (length + w - 1) / w;
 | 
						|
    }
 | 
						|
 | 
						|
    return (*funcs->AllocateOffscreenArea) (pScreen, w, h, gran, moveCB,
 | 
						|
                                            removeCB, privData);
 | 
						|
}
 |