xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

xf86fbman.c (40680B)


      1 
      2 /*
      3  * Copyright (c) 1998-2001 by The XFree86 Project, Inc.
      4  *
      5  * Permission is hereby granted, free of charge, to any person obtaining a
      6  * copy of this software and associated documentation files (the "Software"),
      7  * to deal in the Software without restriction, including without limitation
      8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      9  * and/or sell copies of the Software, and to permit persons to whom the
     10  * Software is furnished to do so, subject to the following conditions:
     11  *
     12  * The above copyright notice and this permission notice shall be included in
     13  * all copies or substantial portions of the Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
     19  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     20  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     21  * OTHER DEALINGS IN THE SOFTWARE.
     22  *
     23  * Except as contained in this notice, the name of the copyright holder(s)
     24  * and author(s) shall not be used in advertising or otherwise to promote
     25  * the sale, use or other dealings in this Software without prior written
     26  * authorization from the copyright holder(s) and author(s).
     27  */
     28 
     29 #ifdef HAVE_XORG_CONFIG_H
     30 #include <xorg-config.h>
     31 #endif
     32 
     33 #include "misc.h"
     34 #include "xf86.h"
     35 
     36 #include <X11/X.h>
     37 #include "scrnintstr.h"
     38 #include "regionstr.h"
     39 #include "xf86fbman.h"
     40 
     41 /*
     42 #define DEBUG
     43 */
     44 
     45 static DevPrivateKeyRec xf86FBManagerKeyRec;
     46 static DevPrivateKey xf86FBManagerKey;
     47 
     48 Bool
     49 xf86RegisterOffscreenManager(ScreenPtr pScreen, FBManagerFuncsPtr funcs)
     50 {
     51 
     52     xf86FBManagerKey = &xf86FBManagerKeyRec;
     53 
     54     if (!dixRegisterPrivateKey(&xf86FBManagerKeyRec, PRIVATE_SCREEN, 0))
     55         return FALSE;
     56 
     57     dixSetPrivate(&pScreen->devPrivates, xf86FBManagerKey, funcs);
     58 
     59     return TRUE;
     60 }
     61 
     62 Bool
     63 xf86FBManagerRunning(ScreenPtr pScreen)
     64 {
     65     if (xf86FBManagerKey == NULL)
     66         return FALSE;
     67 
     68     if (!dixLookupPrivate(&pScreen->devPrivates, xf86FBManagerKey))
     69         return FALSE;
     70 
     71     return TRUE;
     72 }
     73 
     74 Bool
     75 xf86RegisterFreeBoxCallback(ScreenPtr pScreen,
     76                             FreeBoxCallbackProcPtr FreeBoxCallback,
     77                             void *devPriv)
     78 {
     79     FBManagerFuncsPtr funcs;
     80 
     81     if (xf86FBManagerKey == NULL)
     82         return FALSE;
     83     if (!(funcs = (FBManagerFuncsPtr) dixLookupPrivate(&pScreen->devPrivates,
     84                                                        xf86FBManagerKey)))
     85         return FALSE;
     86 
     87     return (*funcs->RegisterFreeBoxCallback) (pScreen, FreeBoxCallback,
     88                                               devPriv);
     89 }
     90 
     91 FBAreaPtr
     92 xf86AllocateOffscreenArea(ScreenPtr pScreen,
     93                           int w, int h,
     94                           int gran,
     95                           MoveAreaCallbackProcPtr moveCB,
     96                           RemoveAreaCallbackProcPtr removeCB, void *privData)
     97 {
     98     FBManagerFuncsPtr funcs;
     99 
    100     if (xf86FBManagerKey == NULL)
    101         return NULL;
    102     if (!(funcs = (FBManagerFuncsPtr) dixLookupPrivate(&pScreen->devPrivates,
    103                                                        xf86FBManagerKey)))
    104         return NULL;
    105 
    106     return (*funcs->AllocateOffscreenArea) (pScreen, w, h, gran, moveCB,
    107                                             removeCB, privData);
    108 }
    109 
    110 FBLinearPtr
    111 xf86AllocateOffscreenLinear(ScreenPtr pScreen,
    112                             int length,
    113                             int gran,
    114                             MoveLinearCallbackProcPtr moveCB,
    115                             RemoveLinearCallbackProcPtr removeCB,
    116                             void *privData)
    117 {
    118     FBManagerFuncsPtr funcs;
    119 
    120     if (xf86FBManagerKey == NULL)
    121         return NULL;
    122     if (!(funcs = (FBManagerFuncsPtr) dixLookupPrivate(&pScreen->devPrivates,
    123                                                        xf86FBManagerKey)))
    124         return NULL;
    125 
    126     return (*funcs->AllocateOffscreenLinear) (pScreen, length, gran, moveCB,
    127                                               removeCB, privData);
    128 }
    129 
    130 void
    131 xf86FreeOffscreenArea(FBAreaPtr area)
    132 {
    133     FBManagerFuncsPtr funcs;
    134 
    135     if (!area)
    136         return;
    137 
    138     if (xf86FBManagerKey == NULL)
    139         return;
    140     if (!
    141         (funcs =
    142          (FBManagerFuncsPtr) dixLookupPrivate(&area->pScreen->devPrivates,
    143                                               xf86FBManagerKey)))
    144         return;
    145 
    146     (*funcs->FreeOffscreenArea) (area);
    147 
    148     return;
    149 }
    150 
    151 void
    152 xf86FreeOffscreenLinear(FBLinearPtr linear)
    153 {
    154     FBManagerFuncsPtr funcs;
    155 
    156     if (!linear)
    157         return;
    158 
    159     if (xf86FBManagerKey == NULL)
    160         return;
    161     if (!
    162         (funcs =
    163          (FBManagerFuncsPtr) dixLookupPrivate(&linear->pScreen->devPrivates,
    164                                               xf86FBManagerKey)))
    165         return;
    166 
    167     (*funcs->FreeOffscreenLinear) (linear);
    168 
    169     return;
    170 }
    171 
    172 Bool
    173 xf86ResizeOffscreenArea(FBAreaPtr resize, int w, int h)
    174 {
    175     FBManagerFuncsPtr funcs;
    176 
    177     if (!resize)
    178         return FALSE;
    179 
    180     if (xf86FBManagerKey == NULL)
    181         return FALSE;
    182     if (!
    183         (funcs =
    184          (FBManagerFuncsPtr) dixLookupPrivate(&resize->pScreen->devPrivates,
    185                                               xf86FBManagerKey)))
    186         return FALSE;
    187 
    188     return (*funcs->ResizeOffscreenArea) (resize, w, h);
    189 }
    190 
    191 Bool
    192 xf86ResizeOffscreenLinear(FBLinearPtr resize, int size)
    193 {
    194     FBManagerFuncsPtr funcs;
    195 
    196     if (!resize)
    197         return FALSE;
    198 
    199     if (xf86FBManagerKey == NULL)
    200         return FALSE;
    201     if (!
    202         (funcs =
    203          (FBManagerFuncsPtr) dixLookupPrivate(&resize->pScreen->devPrivates,
    204                                               xf86FBManagerKey)))
    205         return FALSE;
    206 
    207     return (*funcs->ResizeOffscreenLinear) (resize, size);
    208 }
    209 
    210 Bool
    211 xf86QueryLargestOffscreenArea(ScreenPtr pScreen,
    212                               int *w, int *h,
    213                               int gran, int preferences, int severity)
    214 {
    215     FBManagerFuncsPtr funcs;
    216 
    217     *w = 0;
    218     *h = 0;
    219 
    220     if (xf86FBManagerKey == NULL)
    221         return FALSE;
    222     if (!(funcs = (FBManagerFuncsPtr) dixLookupPrivate(&pScreen->devPrivates,
    223                                                        xf86FBManagerKey)))
    224         return FALSE;
    225 
    226     return (*funcs->QueryLargestOffscreenArea) (pScreen, w, h, gran,
    227                                                 preferences, severity);
    228 }
    229 
    230 Bool
    231 xf86QueryLargestOffscreenLinear(ScreenPtr pScreen,
    232                                 int *size, int gran, int severity)
    233 {
    234     FBManagerFuncsPtr funcs;
    235 
    236     *size = 0;
    237 
    238     if (xf86FBManagerKey == NULL)
    239         return FALSE;
    240     if (!(funcs = (FBManagerFuncsPtr) dixLookupPrivate(&pScreen->devPrivates,
    241                                                        xf86FBManagerKey)))
    242         return FALSE;
    243 
    244     return (*funcs->QueryLargestOffscreenLinear) (pScreen, size, gran,
    245                                                   severity);
    246 }
    247 
    248 Bool
    249 xf86PurgeUnlockedOffscreenAreas(ScreenPtr pScreen)
    250 {
    251     FBManagerFuncsPtr funcs;
    252 
    253     if (xf86FBManagerKey == NULL)
    254         return FALSE;
    255     if (!(funcs = (FBManagerFuncsPtr) dixLookupPrivate(&pScreen->devPrivates,
    256                                                        xf86FBManagerKey)))
    257         return FALSE;
    258 
    259     return (*funcs->PurgeOffscreenAreas) (pScreen);
    260 }
    261 
    262 /************************************************************\
    263 
    264    Below is a specific implementation of an offscreen manager.
    265 
    266 \************************************************************/
    267 
    268 static DevPrivateKeyRec xf86FBScreenKeyRec;
    269 
    270 #define xf86FBScreenKey (&xf86FBScreenKeyRec)
    271 
    272 typedef struct _FBLink {
    273     FBArea area;
    274     struct _FBLink *next;
    275 } FBLink, *FBLinkPtr;
    276 
    277 typedef struct _FBLinearLink {
    278     FBLinear linear;
    279     int free;                   /* need to add free here as FBLinear is publicly accessible */
    280     FBAreaPtr area;             /* only used if allocation came from XY area */
    281     struct _FBLinearLink *next;
    282 } FBLinearLink, *FBLinearLinkPtr;
    283 
    284 typedef struct {
    285     ScreenPtr pScreen;
    286     RegionPtr InitialBoxes;
    287     RegionPtr FreeBoxes;
    288     FBLinkPtr UsedAreas;
    289     int NumUsedAreas;
    290     FBLinearLinkPtr LinearAreas;
    291     CloseScreenProcPtr CloseScreen;
    292     int NumCallbacks;
    293     FreeBoxCallbackProcPtr *FreeBoxesUpdateCallback;
    294     DevUnion *devPrivates;
    295 } FBManager, *FBManagerPtr;
    296 
    297 static void
    298 SendCallFreeBoxCallbacks(FBManagerPtr offman)
    299 {
    300     int i = offman->NumCallbacks;
    301 
    302     while (i--) {
    303         (*offman->FreeBoxesUpdateCallback[i]) (offman->pScreen,
    304                                                offman->FreeBoxes,
    305                                                offman->devPrivates[i].ptr);
    306     }
    307 }
    308 
    309 static Bool
    310 localRegisterFreeBoxCallback(ScreenPtr pScreen,
    311                              FreeBoxCallbackProcPtr FreeBoxCallback,
    312                              void *devPriv)
    313 {
    314     FBManagerPtr offman;
    315     FreeBoxCallbackProcPtr *newCallbacks;
    316     DevUnion *newPrivates;
    317 
    318     offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
    319                                              xf86FBScreenKey);
    320     newCallbacks = reallocarray(offman->FreeBoxesUpdateCallback,
    321                                 offman->NumCallbacks + 1,
    322                                 sizeof(FreeBoxCallbackProcPtr));
    323     if (!newCallbacks)
    324         return FALSE;
    325     else
    326         offman->FreeBoxesUpdateCallback = newCallbacks;
    327 
    328     newPrivates = reallocarray(offman->devPrivates,
    329                                offman->NumCallbacks + 1,
    330                                sizeof(DevUnion));
    331     if (!newPrivates)
    332         return FALSE;
    333     else
    334         offman->devPrivates = newPrivates;
    335 
    336     offman->FreeBoxesUpdateCallback[offman->NumCallbacks] = FreeBoxCallback;
    337     offman->devPrivates[offman->NumCallbacks].ptr = devPriv;
    338     offman->NumCallbacks++;
    339 
    340     SendCallFreeBoxCallbacks(offman);
    341 
    342     return TRUE;
    343 }
    344 
    345 static FBAreaPtr
    346 AllocateArea(FBManagerPtr offman,
    347              int w, int h,
    348              int granularity,
    349              MoveAreaCallbackProcPtr moveCB,
    350              RemoveAreaCallbackProcPtr removeCB, void *privData)
    351 {
    352     ScreenPtr pScreen = offman->pScreen;
    353     FBLinkPtr link = NULL;
    354     FBAreaPtr area = NULL;
    355     RegionRec NewReg;
    356     int i, x = 0, num;
    357     BoxPtr boxp;
    358 
    359     if (granularity <= 1)
    360         granularity = 0;
    361 
    362     boxp = RegionRects(offman->FreeBoxes);
    363     num = RegionNumRects(offman->FreeBoxes);
    364 
    365     /* look through the free boxes */
    366     for (i = 0; i < num; i++, boxp++) {
    367         x = boxp->x1;
    368         if (granularity > 1)
    369             x = ((x + granularity - 1) / granularity) * granularity;
    370 
    371         if (((boxp->y2 - boxp->y1) < h) || ((boxp->x2 - x) < w))
    372             continue;
    373 
    374         link = malloc(sizeof(FBLink));
    375         if (!link)
    376             return NULL;
    377 
    378         area = &(link->area);
    379         link->next = offman->UsedAreas;
    380         offman->UsedAreas = link;
    381         offman->NumUsedAreas++;
    382         break;
    383     }
    384 
    385     /* try to boot a removable one out if we are not expendable ourselves */
    386     if (!area && !removeCB) {
    387         link = offman->UsedAreas;
    388 
    389         while (link) {
    390             if (!link->area.RemoveAreaCallback) {
    391                 link = link->next;
    392                 continue;
    393             }
    394 
    395             boxp = &(link->area.box);
    396             x = boxp->x1;
    397             if (granularity > 1)
    398                 x = ((x + granularity - 1) / granularity) * granularity;
    399 
    400             if (((boxp->y2 - boxp->y1) < h) || ((boxp->x2 - x) < w)) {
    401                 link = link->next;
    402                 continue;
    403             }
    404 
    405             /* bye, bye */
    406             (*link->area.RemoveAreaCallback) (&link->area);
    407             RegionInit(&NewReg, &(link->area.box), 1);
    408             RegionUnion(offman->FreeBoxes, offman->FreeBoxes, &NewReg);
    409             RegionUninit(&NewReg);
    410 
    411             area = &(link->area);
    412             break;
    413         }
    414     }
    415 
    416     if (area) {
    417         area->pScreen = pScreen;
    418         area->granularity = granularity;
    419         area->box.x1 = x;
    420         area->box.x2 = x + w;
    421         area->box.y1 = boxp->y1;
    422         area->box.y2 = boxp->y1 + h;
    423         area->MoveAreaCallback = moveCB;
    424         area->RemoveAreaCallback = removeCB;
    425         area->devPrivate.ptr = privData;
    426 
    427         RegionInit(&NewReg, &(area->box), 1);
    428         RegionSubtract(offman->FreeBoxes, offman->FreeBoxes, &NewReg);
    429         RegionUninit(&NewReg);
    430     }
    431 
    432     return area;
    433 }
    434 
    435 static FBAreaPtr
    436 localAllocateOffscreenArea(ScreenPtr pScreen,
    437                            int w, int h,
    438                            int gran,
    439                            MoveAreaCallbackProcPtr moveCB,
    440                            RemoveAreaCallbackProcPtr removeCB, void *privData)
    441 {
    442     FBManagerPtr offman;
    443     FBAreaPtr area = NULL;
    444 
    445     offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
    446                                              xf86FBScreenKey);
    447     if ((area = AllocateArea(offman, w, h, gran, moveCB, removeCB, privData)))
    448         SendCallFreeBoxCallbacks(offman);
    449 
    450     return area;
    451 }
    452 
    453 static void
    454 localFreeOffscreenArea(FBAreaPtr area)
    455 {
    456     FBManagerPtr offman;
    457     FBLinkPtr pLink, pLinkPrev = NULL;
    458     RegionRec FreedRegion;
    459     ScreenPtr pScreen;
    460 
    461     pScreen = area->pScreen;
    462     offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
    463                                              xf86FBScreenKey);
    464     pLink = offman->UsedAreas;
    465     if (!pLink)
    466         return;
    467 
    468     while (&(pLink->area) != area) {
    469         pLinkPrev = pLink;
    470         pLink = pLink->next;
    471         if (!pLink)
    472             return;
    473     }
    474 
    475     /* put the area back into the pool */
    476     RegionInit(&FreedRegion, &(pLink->area.box), 1);
    477     RegionUnion(offman->FreeBoxes, offman->FreeBoxes, &FreedRegion);
    478     RegionUninit(&FreedRegion);
    479 
    480     if (pLinkPrev)
    481         pLinkPrev->next = pLink->next;
    482     else
    483         offman->UsedAreas = pLink->next;
    484 
    485     free(pLink);
    486     offman->NumUsedAreas--;
    487 
    488     SendCallFreeBoxCallbacks(offman);
    489 }
    490 
    491 static Bool
    492 localResizeOffscreenArea(FBAreaPtr resize, int w, int h)
    493 {
    494     FBManagerPtr offman;
    495     ScreenPtr pScreen;
    496     BoxRec OrigArea;
    497     RegionRec FreedReg;
    498     FBAreaPtr area = NULL;
    499     FBLinkPtr pLink, newLink, pLinkPrev = NULL;
    500 
    501     pScreen = resize->pScreen;
    502     offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
    503                                              xf86FBScreenKey);
    504     /* find this link */
    505     if (!(pLink = offman->UsedAreas))
    506         return FALSE;
    507 
    508     while (&(pLink->area) != resize) {
    509         pLinkPrev = pLink;
    510         pLink = pLink->next;
    511         if (!pLink)
    512             return FALSE;
    513     }
    514 
    515     OrigArea.x1 = resize->box.x1;
    516     OrigArea.x2 = resize->box.x2;
    517     OrigArea.y1 = resize->box.y1;
    518     OrigArea.y2 = resize->box.y2;
    519 
    520     /* if it's smaller, this is easy */
    521 
    522     if ((w <= (resize->box.x2 - resize->box.x1)) &&
    523         (h <= (resize->box.y2 - resize->box.y1))) {
    524         RegionRec NewReg;
    525 
    526         resize->box.x2 = resize->box.x1 + w;
    527         resize->box.y2 = resize->box.y1 + h;
    528 
    529         if ((resize->box.y2 == OrigArea.y2) && (resize->box.x2 == OrigArea.x2))
    530             return TRUE;
    531 
    532         RegionInit(&FreedReg, &OrigArea, 1);
    533         RegionInit(&NewReg, &(resize->box), 1);
    534         RegionSubtract(&FreedReg, &FreedReg, &NewReg);
    535         RegionUnion(offman->FreeBoxes, offman->FreeBoxes, &FreedReg);
    536         RegionUninit(&FreedReg);
    537         RegionUninit(&NewReg);
    538 
    539         SendCallFreeBoxCallbacks(offman);
    540 
    541         return TRUE;
    542     }
    543 
    544     /* otherwise we remove the old region */
    545 
    546     RegionInit(&FreedReg, &OrigArea, 1);
    547     RegionUnion(offman->FreeBoxes, offman->FreeBoxes, &FreedReg);
    548 
    549     /* remove the old link */
    550     if (pLinkPrev)
    551         pLinkPrev->next = pLink->next;
    552     else
    553         offman->UsedAreas = pLink->next;
    554 
    555     /* and try to add a new one */
    556 
    557     if ((area = AllocateArea(offman, w, h, resize->granularity,
    558                              resize->MoveAreaCallback,
    559                              resize->RemoveAreaCallback,
    560                              resize->devPrivate.ptr))) {
    561 
    562         /* copy data over to our link and replace the new with old */
    563         memcpy(resize, area, sizeof(FBArea));
    564 
    565         pLinkPrev = NULL;
    566         newLink = offman->UsedAreas;
    567 
    568         while (&(newLink->area) != area) {
    569             pLinkPrev = newLink;
    570             newLink = newLink->next;
    571         }
    572 
    573         if (pLinkPrev)
    574             pLinkPrev->next = newLink->next;
    575         else
    576             offman->UsedAreas = newLink->next;
    577 
    578         pLink->next = offman->UsedAreas;
    579         offman->UsedAreas = pLink;
    580 
    581         free(newLink);
    582 
    583         /* AllocateArea added one but we really only exchanged one */
    584         offman->NumUsedAreas--;
    585     }
    586     else {
    587         /* reinstate the old region */
    588         RegionSubtract(offman->FreeBoxes, offman->FreeBoxes, &FreedReg);
    589         RegionUninit(&FreedReg);
    590 
    591         pLink->next = offman->UsedAreas;
    592         offman->UsedAreas = pLink;
    593         return FALSE;
    594     }
    595 
    596     RegionUninit(&FreedReg);
    597 
    598     SendCallFreeBoxCallbacks(offman);
    599 
    600     return TRUE;
    601 }
    602 
    603 static Bool
    604 localQueryLargestOffscreenArea(ScreenPtr pScreen,
    605                                int *width, int *height,
    606                                int granularity, int preferences, int severity)
    607 {
    608     FBManagerPtr offman;
    609     RegionPtr newRegion = NULL;
    610     BoxPtr pbox;
    611     int nbox;
    612     int x, w, h, area, oldArea;
    613 
    614     *width = *height = oldArea = 0;
    615 
    616     if (granularity <= 1)
    617         granularity = 0;
    618 
    619     if ((preferences < 0) || (preferences > 3))
    620         return FALSE;
    621 
    622     offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
    623                                              xf86FBScreenKey);
    624     if (severity < 0)
    625         severity = 0;
    626     if (severity > 2)
    627         severity = 2;
    628 
    629     switch (severity) {
    630     case 2:
    631         if (offman->NumUsedAreas) {
    632             FBLinkPtr pLink;
    633             RegionRec tmpRegion;
    634 
    635             newRegion = RegionCreate(NULL, 1);
    636             RegionCopy(newRegion, offman->InitialBoxes);
    637             pLink = offman->UsedAreas;
    638 
    639             while (pLink) {
    640                 if (!pLink->area.RemoveAreaCallback) {
    641                     RegionInit(&tmpRegion, &(pLink->area.box), 1);
    642                     RegionSubtract(newRegion, newRegion, &tmpRegion);
    643                     RegionUninit(&tmpRegion);
    644                 }
    645                 pLink = pLink->next;
    646             }
    647 
    648             nbox = RegionNumRects(newRegion);
    649             pbox = RegionRects(newRegion);
    650             break;
    651         }
    652     case 1:
    653         if (offman->NumUsedAreas) {
    654             FBLinkPtr pLink;
    655             RegionRec tmpRegion;
    656 
    657             newRegion = RegionCreate(NULL, 1);
    658             RegionCopy(newRegion, offman->FreeBoxes);
    659             pLink = offman->UsedAreas;
    660 
    661             while (pLink) {
    662                 if (pLink->area.RemoveAreaCallback) {
    663                     RegionInit(&tmpRegion, &(pLink->area.box), 1);
    664                     RegionAppend(newRegion, &tmpRegion);
    665                     RegionUninit(&tmpRegion);
    666                 }
    667                 pLink = pLink->next;
    668             }
    669 
    670             nbox = RegionNumRects(newRegion);
    671             pbox = RegionRects(newRegion);
    672             break;
    673         }
    674     default:
    675         nbox = RegionNumRects(offman->FreeBoxes);
    676         pbox = RegionRects(offman->FreeBoxes);
    677         break;
    678     }
    679 
    680     while (nbox--) {
    681         x = pbox->x1;
    682         if (granularity > 1)
    683             x = ((x + granularity - 1) / granularity) * granularity;
    684 
    685         w = pbox->x2 - x;
    686         h = pbox->y2 - pbox->y1;
    687         area = w * h;
    688 
    689         if (w > 0) {
    690             Bool gotIt = FALSE;
    691 
    692             switch (preferences) {
    693             case FAVOR_AREA_THEN_WIDTH:
    694                 if ((area > oldArea) || ((area == oldArea) && (w > *width)))
    695                     gotIt = TRUE;
    696                 break;
    697             case FAVOR_AREA_THEN_HEIGHT:
    698                 if ((area > oldArea) || ((area == oldArea) && (h > *height)))
    699                     gotIt = TRUE;
    700                 break;
    701             case FAVOR_WIDTH_THEN_AREA:
    702                 if ((w > *width) || ((w == *width) && (area > oldArea)))
    703                     gotIt = TRUE;
    704                 break;
    705             case FAVOR_HEIGHT_THEN_AREA:
    706                 if ((h > *height) || ((h == *height) && (area > oldArea)))
    707                     gotIt = TRUE;
    708                 break;
    709             }
    710             if (gotIt) {
    711                 *width = w;
    712                 *height = h;
    713                 oldArea = area;
    714             }
    715         }
    716         pbox++;
    717     }
    718 
    719     if (newRegion)
    720         RegionDestroy(newRegion);
    721 
    722     return TRUE;
    723 }
    724 
    725 static Bool
    726 localPurgeUnlockedOffscreenAreas(ScreenPtr pScreen)
    727 {
    728     FBManagerPtr offman;
    729     FBLinkPtr pLink, tmp, pPrev = NULL;
    730     RegionRec FreedRegion;
    731     Bool anyUsed = FALSE;
    732 
    733     offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
    734                                              xf86FBScreenKey);
    735     pLink = offman->UsedAreas;
    736     if (!pLink)
    737         return TRUE;
    738 
    739     while (pLink) {
    740         if (pLink->area.RemoveAreaCallback) {
    741             (*pLink->area.RemoveAreaCallback) (&pLink->area);
    742 
    743             RegionInit(&FreedRegion, &(pLink->area.box), 1);
    744             RegionAppend(offman->FreeBoxes, &FreedRegion);
    745             RegionUninit(&FreedRegion);
    746 
    747             if (pPrev)
    748                 pPrev->next = pLink->next;
    749             else
    750                 offman->UsedAreas = pLink->next;
    751 
    752             tmp = pLink;
    753             pLink = pLink->next;
    754             free(tmp);
    755             offman->NumUsedAreas--;
    756             anyUsed = TRUE;
    757         }
    758         else {
    759             pPrev = pLink;
    760             pLink = pLink->next;
    761         }
    762     }
    763 
    764     if (anyUsed) {
    765         RegionValidate(offman->FreeBoxes, &anyUsed);
    766         SendCallFreeBoxCallbacks(offman);
    767     }
    768 
    769     return TRUE;
    770 }
    771 
    772 static void
    773 LinearMoveCBWrapper(FBAreaPtr from, FBAreaPtr to)
    774 {
    775     /* this will never get called */
    776 }
    777 
    778 static void
    779 LinearRemoveCBWrapper(FBAreaPtr area)
    780 {
    781     FBManagerPtr offman;
    782     FBLinearLinkPtr pLink, pLinkPrev = NULL;
    783     ScreenPtr pScreen = area->pScreen;
    784 
    785     offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
    786                                              xf86FBScreenKey);
    787     pLink = offman->LinearAreas;
    788     if (!pLink)
    789         return;
    790 
    791     while (pLink->area != area) {
    792         pLinkPrev = pLink;
    793         pLink = pLink->next;
    794         if (!pLink)
    795             return;
    796     }
    797 
    798     /* give the user the callback it is expecting */
    799     (*pLink->linear.RemoveLinearCallback) (&(pLink->linear));
    800 
    801     if (pLinkPrev)
    802         pLinkPrev->next = pLink->next;
    803     else
    804         offman->LinearAreas = pLink->next;
    805 
    806     free(pLink);
    807 }
    808 
    809 static void
    810 DumpDebug(FBLinearLinkPtr pLink)
    811 {
    812 #ifdef DEBUG
    813     if (!pLink)
    814         ErrorF("MMmm, PLINK IS NULL!\n");
    815 
    816     while (pLink) {
    817         ErrorF("  Offset:%08x, Size:%08x, %s,%s\n",
    818                pLink->linear.offset,
    819                pLink->linear.size,
    820                pLink->free ? "Free" : "Used", pLink->area ? "Area" : "Linear");
    821 
    822         pLink = pLink->next;
    823     }
    824 #endif
    825 }
    826 
    827 static FBLinearPtr
    828 AllocateLinear(FBManagerPtr offman, int size, int granularity, void *privData)
    829 {
    830     ScreenPtr pScreen = offman->pScreen;
    831     FBLinearLinkPtr linear = NULL;
    832     FBLinearLinkPtr newlink = NULL;
    833     int offset, end;
    834 
    835     if (size <= 0)
    836         return NULL;
    837 
    838     if (!offman->LinearAreas)
    839         return NULL;
    840 
    841     linear = offman->LinearAreas;
    842     while (linear) {
    843         /* Make sure we get a free area that's not an XY fallback case */
    844         if (!linear->area && linear->free) {
    845             offset = linear->linear.offset;
    846             if (granularity > 1)
    847                 offset =
    848                     ((offset + granularity - 1) / granularity) * granularity;
    849             end = offset + size;
    850             if (end <= (linear->linear.offset + linear->linear.size))
    851                 break;
    852         }
    853         linear = linear->next;
    854     }
    855     if (!linear)
    856         return NULL;
    857 
    858     /* break left */
    859     if (offset > linear->linear.offset) {
    860         newlink = malloc(sizeof(FBLinearLink));
    861         if (!newlink)
    862             return NULL;
    863         newlink->area = NULL;
    864         newlink->linear.offset = offset;
    865         newlink->linear.size =
    866             linear->linear.size - (offset - linear->linear.offset);
    867         newlink->free = 1;
    868         newlink->next = linear->next;
    869         linear->linear.size -= newlink->linear.size;
    870         linear->next = newlink;
    871         linear = newlink;
    872     }
    873 
    874     /* break right */
    875     if (size < linear->linear.size) {
    876         newlink = malloc(sizeof(FBLinearLink));
    877         if (!newlink)
    878             return NULL;
    879         newlink->area = NULL;
    880         newlink->linear.offset = offset + size;
    881         newlink->linear.size = linear->linear.size - size;
    882         newlink->free = 1;
    883         newlink->next = linear->next;
    884         linear->linear.size = size;
    885         linear->next = newlink;
    886     }
    887 
    888     /* p = middle block */
    889     linear->linear.granularity = granularity;
    890     linear->free = 0;
    891     linear->linear.pScreen = pScreen;
    892     linear->linear.MoveLinearCallback = NULL;
    893     linear->linear.RemoveLinearCallback = NULL;
    894     linear->linear.devPrivate.ptr = NULL;
    895 
    896     DumpDebug(offman->LinearAreas);
    897 
    898     return &(linear->linear);
    899 }
    900 
    901 static FBLinearPtr
    902 localAllocateOffscreenLinear(ScreenPtr pScreen,
    903                              int length,
    904                              int gran,
    905                              MoveLinearCallbackProcPtr moveCB,
    906                              RemoveLinearCallbackProcPtr removeCB,
    907                              void *privData)
    908 {
    909     FBManagerPtr offman;
    910     FBLinearLinkPtr link;
    911     FBAreaPtr area;
    912     FBLinearPtr linear = NULL;
    913     BoxPtr extents;
    914     int w, h, pitch;
    915 
    916     offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
    917                                              xf86FBScreenKey);
    918 
    919     /* Try to allocate from linear memory first...... */
    920     DebugF("ALLOCATING LINEAR\n");
    921     if ((linear = AllocateLinear(offman, length, gran, privData)))
    922         return linear;
    923 
    924     DebugF("NOPE, ALLOCATING AREA\n");
    925 
    926     if (!(link = malloc(sizeof(FBLinearLink))))
    927         return NULL;
    928 
    929     /* No linear available, so try and pinch some from the XY areas */
    930     extents = RegionExtents(offman->InitialBoxes);
    931     pitch = extents->x2 - extents->x1;
    932 
    933     if (gran > 1) {
    934         if (gran > pitch) {
    935             /* we can't match the specified alignment with XY allocations */
    936             free(link);
    937             return NULL;
    938         }
    939 
    940         if (pitch % gran) {
    941             /* pitch and granularity aren't a perfect match, let's allocate
    942              * a bit more so we can align later on
    943              */
    944             length += gran - 1;
    945         }
    946     }
    947 
    948     if (length < pitch) {       /* special case */
    949         w = length;
    950         h = 1;
    951     }
    952     else {
    953         w = pitch;
    954         h = (length + pitch - 1) / pitch;
    955     }
    956 
    957     if ((area = localAllocateOffscreenArea(pScreen, w, h, gran,
    958                                            moveCB ? LinearMoveCBWrapper : NULL,
    959                                            removeCB ? LinearRemoveCBWrapper :
    960                                            NULL, privData))) {
    961         link->area = area;
    962         link->free = 0;
    963         link->next = offman->LinearAreas;
    964         offman->LinearAreas = link;
    965         linear = &(link->linear);
    966         linear->pScreen = pScreen;
    967         linear->size = h * w;
    968         linear->offset = (pitch * area->box.y1) + area->box.x1;
    969         if (gran > 1)
    970             linear->offset = ((linear->offset + gran - 1) / gran) * gran;
    971         linear->granularity = gran;
    972         linear->MoveLinearCallback = moveCB;
    973         linear->RemoveLinearCallback = removeCB;
    974         linear->devPrivate.ptr = privData;
    975     }
    976     else
    977         free(link);
    978 
    979     DumpDebug(offman->LinearAreas);
    980 
    981     return linear;
    982 }
    983 
    984 static void
    985 localFreeOffscreenLinear(FBLinearPtr linear)
    986 {
    987     FBManagerPtr offman;
    988     FBLinearLinkPtr pLink, pLinkPrev = NULL;
    989     ScreenPtr pScreen = linear->pScreen;
    990 
    991     offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
    992                                              xf86FBScreenKey);
    993     pLink = offman->LinearAreas;
    994     if (!pLink)
    995         return;
    996 
    997     while (&(pLink->linear) != linear) {
    998         pLinkPrev = pLink;
    999         pLink = pLink->next;
   1000         if (!pLink)
   1001             return;
   1002     }
   1003 
   1004     if (pLink->area) {          /* really an XY area */
   1005         DebugF("FREEING AREA\n");
   1006         localFreeOffscreenArea(pLink->area);
   1007         if (pLinkPrev)
   1008             pLinkPrev->next = pLink->next;
   1009         else
   1010             offman->LinearAreas = pLink->next;
   1011         free(pLink);
   1012         DumpDebug(offman->LinearAreas);
   1013         return;
   1014     }
   1015 
   1016     pLink->free = 1;
   1017 
   1018     if (pLink->next && pLink->next->free) {
   1019         FBLinearLinkPtr p = pLink->next;
   1020 
   1021         pLink->linear.size += p->linear.size;
   1022         pLink->next = p->next;
   1023         free(p);
   1024     }
   1025 
   1026     if (pLinkPrev) {
   1027         if (pLinkPrev->next && pLinkPrev->next->free && !pLinkPrev->area) {
   1028             FBLinearLinkPtr p = pLinkPrev->next;
   1029 
   1030             pLinkPrev->linear.size += p->linear.size;
   1031             pLinkPrev->next = p->next;
   1032             free(p);
   1033         }
   1034     }
   1035 
   1036     DebugF("FREEING LINEAR\n");
   1037     DumpDebug(offman->LinearAreas);
   1038 }
   1039 
   1040 static Bool
   1041 localResizeOffscreenLinear(FBLinearPtr resize, int length)
   1042 {
   1043     FBManagerPtr offman;
   1044     FBLinearLinkPtr pLink;
   1045     ScreenPtr pScreen = resize->pScreen;
   1046 
   1047     offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
   1048                                              xf86FBScreenKey);
   1049     pLink = offman->LinearAreas;
   1050     if (!pLink)
   1051         return FALSE;
   1052 
   1053     while (&(pLink->linear) != resize) {
   1054         pLink = pLink->next;
   1055         if (!pLink)
   1056             return FALSE;
   1057     }
   1058 
   1059     /* This could actually be a lot smarter and try to move allocations
   1060        from XY to linear when available.  For now if it was XY, we keep
   1061        it XY */
   1062 
   1063     if (pLink->area) {          /* really an XY area */
   1064         BoxPtr extents;
   1065         int pitch, w, h;
   1066 
   1067         extents = RegionExtents(offman->InitialBoxes);
   1068         pitch = extents->x2 - extents->x1;
   1069 
   1070         if (length < pitch) {   /* special case */
   1071             w = length;
   1072             h = 1;
   1073         }
   1074         else {
   1075             w = pitch;
   1076             h = (length + pitch - 1) / pitch;
   1077         }
   1078 
   1079         if (localResizeOffscreenArea(pLink->area, w, h)) {
   1080             resize->size = h * w;
   1081             resize->offset =
   1082                 (pitch * pLink->area->box.y1) + pLink->area->box.x1;
   1083             return TRUE;
   1084         }
   1085     }
   1086     else {
   1087         /* TODO!!!! resize the linear area */
   1088     }
   1089 
   1090     return FALSE;
   1091 }
   1092 
   1093 static Bool
   1094 localQueryLargestOffscreenLinear(ScreenPtr pScreen,
   1095                                  int *size, int gran, int priority)
   1096 {
   1097     FBManagerPtr offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
   1098                                                           xf86FBScreenKey);
   1099     FBLinearLinkPtr pLink;
   1100     FBLinearLinkPtr pLinkRet;
   1101 
   1102     *size = 0;
   1103 
   1104     pLink = offman->LinearAreas;
   1105 
   1106     if (pLink && !pLink->area) {
   1107         pLinkRet = pLink;
   1108         while (pLink) {
   1109             if (pLink->free) {
   1110                 if (pLink->linear.size > pLinkRet->linear.size)
   1111                     pLinkRet = pLink;
   1112             }
   1113             pLink = pLink->next;
   1114         }
   1115 
   1116         if (pLinkRet->free) {
   1117             *size = pLinkRet->linear.size;
   1118             return TRUE;
   1119         }
   1120     }
   1121     else {
   1122         int w, h;
   1123 
   1124         if (localQueryLargestOffscreenArea(pScreen, &w, &h, gran,
   1125                                            FAVOR_WIDTH_THEN_AREA, priority)) {
   1126             BoxPtr extents;
   1127 
   1128             extents = RegionExtents(offman->InitialBoxes);
   1129             if ((extents->x2 - extents->x1) == w)
   1130                 *size = w * h;
   1131             return TRUE;
   1132         }
   1133     }
   1134 
   1135     return FALSE;
   1136 }
   1137 
   1138 static FBManagerFuncs xf86FBManFuncs = {
   1139     localAllocateOffscreenArea,
   1140     localFreeOffscreenArea,
   1141     localResizeOffscreenArea,
   1142     localQueryLargestOffscreenArea,
   1143     localRegisterFreeBoxCallback,
   1144     localAllocateOffscreenLinear,
   1145     localFreeOffscreenLinear,
   1146     localResizeOffscreenLinear,
   1147     localQueryLargestOffscreenLinear,
   1148     localPurgeUnlockedOffscreenAreas
   1149 };
   1150 
   1151 static Bool
   1152 xf86FBCloseScreen(ScreenPtr pScreen)
   1153 {
   1154     FBLinkPtr pLink, tmp;
   1155     FBLinearLinkPtr pLinearLink, tmp2;
   1156     FBManagerPtr offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
   1157                                                           xf86FBScreenKey);
   1158 
   1159     pScreen->CloseScreen = offman->CloseScreen;
   1160 
   1161     pLink = offman->UsedAreas;
   1162     while (pLink) {
   1163         tmp = pLink;
   1164         pLink = pLink->next;
   1165         free(tmp);
   1166     }
   1167 
   1168     pLinearLink = offman->LinearAreas;
   1169     while (pLinearLink) {
   1170         tmp2 = pLinearLink;
   1171         pLinearLink = pLinearLink->next;
   1172         free(tmp2);
   1173     }
   1174 
   1175     RegionDestroy(offman->InitialBoxes);
   1176     RegionDestroy(offman->FreeBoxes);
   1177 
   1178     free(offman->FreeBoxesUpdateCallback);
   1179     free(offman->devPrivates);
   1180     free(offman);
   1181     dixSetPrivate(&pScreen->devPrivates, xf86FBScreenKey, NULL);
   1182 
   1183     return (*pScreen->CloseScreen) (pScreen);
   1184 }
   1185 
   1186 Bool
   1187 xf86InitFBManager(ScreenPtr pScreen, BoxPtr FullBox)
   1188 {
   1189     ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
   1190     RegionRec ScreenRegion;
   1191     RegionRec FullRegion;
   1192     BoxRec ScreenBox;
   1193     Bool ret;
   1194 
   1195     ScreenBox.x1 = 0;
   1196     ScreenBox.y1 = 0;
   1197     ScreenBox.x2 = pScrn->virtualX;
   1198     ScreenBox.y2 = pScrn->virtualY;
   1199 
   1200     if ((FullBox->x1 > ScreenBox.x1) || (FullBox->y1 > ScreenBox.y1) ||
   1201         (FullBox->x2 < ScreenBox.x2) || (FullBox->y2 < ScreenBox.y2)) {
   1202         return FALSE;
   1203     }
   1204 
   1205     if (FullBox->y2 < FullBox->y1)
   1206         return FALSE;
   1207     if (FullBox->x2 < FullBox->x1)
   1208         return FALSE;
   1209 
   1210     RegionInit(&ScreenRegion, &ScreenBox, 1);
   1211     RegionInit(&FullRegion, FullBox, 1);
   1212 
   1213     RegionSubtract(&FullRegion, &FullRegion, &ScreenRegion);
   1214 
   1215     ret = xf86InitFBManagerRegion(pScreen, &FullRegion);
   1216 
   1217     RegionUninit(&ScreenRegion);
   1218     RegionUninit(&FullRegion);
   1219 
   1220     return ret;
   1221 }
   1222 
   1223 Bool
   1224 xf86InitFBManagerArea(ScreenPtr pScreen, int PixelArea, int Verbosity)
   1225 {
   1226     ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
   1227     xRectangle Rect[3];
   1228     RegionPtr pRegion, pScreenRegion;
   1229     int nRect;
   1230     Bool ret = FALSE;
   1231 
   1232     if (PixelArea < (pScrn->displayWidth * pScrn->virtualY))
   1233         return FALSE;
   1234 
   1235     Rect[0].x = Rect[0].y = 0;
   1236     Rect[0].width = pScrn->displayWidth;
   1237     Rect[0].height = PixelArea / pScrn->displayWidth;
   1238     nRect = 1;
   1239 
   1240     /* Add a possible partial scanline */
   1241     if ((Rect[1].height = Rect[1].width = PixelArea % pScrn->displayWidth)) {
   1242         Rect[1].x = 0;
   1243         Rect[1].y = Rect[0].height;
   1244         Rect[1].height = 1;
   1245         nRect++;
   1246     }
   1247 
   1248     /* Factor out virtual resolution */
   1249     pRegion = RegionFromRects(nRect, Rect, 0);
   1250     if (pRegion) {
   1251         if (!RegionNar(pRegion)) {
   1252             Rect[2].x = Rect[2].y = 0;
   1253             Rect[2].width = pScrn->virtualX;
   1254             Rect[2].height = pScrn->virtualY;
   1255 
   1256             pScreenRegion = RegionFromRects(1, &Rect[2], 0);
   1257             if (pScreenRegion) {
   1258                 if (!RegionNar(pScreenRegion)) {
   1259                     RegionSubtract(pRegion, pRegion, pScreenRegion);
   1260 
   1261                     ret = xf86InitFBManagerRegion(pScreen, pRegion);
   1262 
   1263                     if (ret && xf86GetVerbosity() >= Verbosity) {
   1264                         int scrnIndex = pScrn->scrnIndex;
   1265 
   1266                         xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity,
   1267                                        "Largest offscreen areas (with overlaps):\n");
   1268 
   1269                         if (Rect[2].width < Rect[0].width) {
   1270                             xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity,
   1271                                            "\t%d x %d rectangle at %d,0\n",
   1272                                            Rect[0].width - Rect[2].width,
   1273                                            Rect[0].height, Rect[2].width);
   1274                         }
   1275                         if (Rect[2].width < Rect[1].width) {
   1276                             xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity,
   1277                                            "\t%d x %d rectangle at %d,0\n",
   1278                                            Rect[1].width - Rect[2].width,
   1279                                            Rect[0].height + Rect[1].height,
   1280                                            Rect[2].width);
   1281                         }
   1282                         if (Rect[2].height < Rect[0].height) {
   1283                             xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity,
   1284                                            "\t%d x %d rectangle at 0,%d\n",
   1285                                            Rect[0].width,
   1286                                            Rect[0].height - Rect[2].height,
   1287                                            Rect[2].height);
   1288                         }
   1289                         if (Rect[1].height) {
   1290                             xf86DrvMsgVerb(scrnIndex, X_INFO, Verbosity,
   1291                                            "\t%d x %d rectangle at 0,%d\n",
   1292                                            Rect[1].width,
   1293                                            Rect[0].height - Rect[2].height +
   1294                                            Rect[1].height, Rect[2].height);
   1295                         }
   1296                     }
   1297                 }
   1298 
   1299                 RegionDestroy(pScreenRegion);
   1300             }
   1301         }
   1302 
   1303         RegionDestroy(pRegion);
   1304     }
   1305 
   1306     return ret;
   1307 }
   1308 
   1309 Bool
   1310 xf86InitFBManagerRegion(ScreenPtr pScreen, RegionPtr FullRegion)
   1311 {
   1312     FBManagerPtr offman;
   1313 
   1314     if (RegionNil(FullRegion))
   1315         return FALSE;
   1316 
   1317     if (!dixRegisterPrivateKey(&xf86FBScreenKeyRec, PRIVATE_SCREEN, 0))
   1318         return FALSE;
   1319 
   1320     if (!xf86RegisterOffscreenManager(pScreen, &xf86FBManFuncs))
   1321         return FALSE;
   1322 
   1323     offman = malloc(sizeof(FBManager));
   1324     if (!offman)
   1325         return FALSE;
   1326 
   1327     dixSetPrivate(&pScreen->devPrivates, xf86FBScreenKey, offman);
   1328 
   1329     offman->CloseScreen = pScreen->CloseScreen;
   1330     pScreen->CloseScreen = xf86FBCloseScreen;
   1331 
   1332     offman->InitialBoxes = RegionCreate(NULL, 1);
   1333     offman->FreeBoxes = RegionCreate(NULL, 1);
   1334 
   1335     RegionCopy(offman->InitialBoxes, FullRegion);
   1336     RegionCopy(offman->FreeBoxes, FullRegion);
   1337 
   1338     offman->pScreen = pScreen;
   1339     offman->UsedAreas = NULL;
   1340     offman->LinearAreas = NULL;
   1341     offman->NumUsedAreas = 0;
   1342     offman->NumCallbacks = 0;
   1343     offman->FreeBoxesUpdateCallback = NULL;
   1344     offman->devPrivates = NULL;
   1345 
   1346     return TRUE;
   1347 }
   1348 
   1349 Bool
   1350 xf86InitFBManagerLinear(ScreenPtr pScreen, int offset, int size)
   1351 {
   1352     FBManagerPtr offman;
   1353     FBLinearLinkPtr link;
   1354     FBLinearPtr linear;
   1355 
   1356     if (size <= 0)
   1357         return FALSE;
   1358 
   1359     /* we expect people to have called the Area setup first for pixmap cache */
   1360     if (!dixLookupPrivate(&pScreen->devPrivates, xf86FBScreenKey))
   1361         return FALSE;
   1362 
   1363     offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
   1364                                              xf86FBScreenKey);
   1365     offman->LinearAreas = malloc(sizeof(FBLinearLink));
   1366     if (!offman->LinearAreas)
   1367         return FALSE;
   1368 
   1369     link = offman->LinearAreas;
   1370     link->area = NULL;
   1371     link->next = NULL;
   1372     link->free = 1;
   1373     linear = &(link->linear);
   1374     linear->pScreen = pScreen;
   1375     linear->size = size;
   1376     linear->offset = offset;
   1377     linear->granularity = 0;
   1378     linear->MoveLinearCallback = NULL;
   1379     linear->RemoveLinearCallback = NULL;
   1380     linear->devPrivate.ptr = NULL;
   1381 
   1382     return TRUE;
   1383 }
   1384 
   1385 /* This is an implementation specific function and should
   1386    disappear after the next release.  People should use the
   1387    real linear functions instead */
   1388 
   1389 FBAreaPtr
   1390 xf86AllocateLinearOffscreenArea(ScreenPtr pScreen,
   1391                                 int length,
   1392                                 int gran,
   1393                                 MoveAreaCallbackProcPtr moveCB,
   1394                                 RemoveAreaCallbackProcPtr removeCB,
   1395                                 void *privData)
   1396 {
   1397     FBManagerFuncsPtr funcs;
   1398     FBManagerPtr offman;
   1399     BoxPtr extents;
   1400     int w, h;
   1401 
   1402     if (xf86FBManagerKey == NULL)
   1403         return NULL;
   1404     if (!(funcs = (FBManagerFuncsPtr) dixLookupPrivate(&pScreen->devPrivates,
   1405                                                        xf86FBManagerKey)))
   1406         return NULL;
   1407 
   1408     offman = (FBManagerPtr) dixLookupPrivate(&pScreen->devPrivates,
   1409                                              xf86FBScreenKey);
   1410     extents = RegionExtents(offman->InitialBoxes);
   1411     w = extents->x2 - extents->x1;
   1412 
   1413     if (gran > 1) {
   1414         if (gran > w)
   1415             return NULL;
   1416 
   1417         if (w % gran)
   1418             length += gran - 1;
   1419     }
   1420 
   1421     if (length <= w) {          /* special case */
   1422         h = 1;
   1423         w = length;
   1424     }
   1425     else {
   1426         h = (length + w - 1) / w;
   1427     }
   1428 
   1429     return (*funcs->AllocateOffscreenArea) (pScreen, w, h, gran, moveCB,
   1430                                             removeCB, privData);
   1431 }