xserver

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

rootlessCommon.c (14081B)


      1 /*
      2  * Common rootless definitions and code
      3  */
      4 /*
      5  * Copyright (c) 2001 Greg Parker. All Rights Reserved.
      6  * Copyright (c) 2002-2003 Torrey T. Lyons. All Rights Reserved.
      7  * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
      8  *
      9  * Permission is hereby granted, free of charge, to any person obtaining a
     10  * copy of this software and associated documentation files (the "Software"),
     11  * to deal in the Software without restriction, including without limitation
     12  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     13  * and/or sell copies of the Software, and to permit persons to whom the
     14  * Software is furnished to do so, subject to the following conditions:
     15  *
     16  * The above copyright notice and this permission notice shall be included in
     17  * all copies or substantial portions of the Software.
     18  *
     19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     20  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     22  * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
     23  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     24  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     25  * DEALINGS IN THE SOFTWARE.
     26  *
     27  * Except as contained in this notice, the name(s) of the above copyright
     28  * holders shall not be used in advertising or otherwise to promote the sale,
     29  * use or other dealings in this Software without prior written authorization.
     30  */
     31 
     32 #ifdef HAVE_DIX_CONFIG_H
     33 #include <dix-config.h>
     34 #endif
     35 
     36 #include <stddef.h>             /* For NULL */
     37 #include <limits.h>             /* For CHAR_BIT */
     38 
     39 #include "rootlessCommon.h"
     40 #include "colormapst.h"
     41 
     42 unsigned int rootless_CopyBytes_threshold = 0;
     43 unsigned int rootless_CopyWindow_threshold = 0;
     44 int rootlessGlobalOffsetX = 0;
     45 int rootlessGlobalOffsetY = 0;
     46 
     47 RegionRec rootlessHugeRoot = { {-32767, -32767, 32767, 32767}, NULL };
     48 
     49 /* Following macro from miregion.c */
     50 
     51 /*  true iff two Boxes overlap */
     52 #define EXTENTCHECK(r1,r2) \
     53       (!( ((r1)->x2 <= (r2)->x1)  || \
     54           ((r1)->x1 >= (r2)->x2)  || \
     55           ((r1)->y2 <= (r2)->y1)  || \
     56           ((r1)->y1 >= (r2)->y2) ) )
     57 
     58 /*
     59  * TopLevelParent
     60  *  Returns the top-level parent of pWindow.
     61  *  The root is the top-level parent of itself, even though the root is
     62  *  not otherwise considered to be a top-level window.
     63  */
     64 WindowPtr
     65 TopLevelParent(WindowPtr pWindow)
     66 {
     67     WindowPtr top;
     68 
     69     if (IsRoot(pWindow))
     70         return pWindow;
     71 
     72     top = pWindow;
     73     while (top && !IsTopLevel(top))
     74         top = top->parent;
     75 
     76     return top;
     77 }
     78 
     79 /*
     80  * IsFramedWindow
     81  *  Returns TRUE if this window is visible inside a frame
     82  *  (e.g. it is visible and has a top-level or root parent)
     83  */
     84 Bool
     85 IsFramedWindow(WindowPtr pWin)
     86 {
     87     WindowPtr top;
     88 
     89     if (!dixPrivateKeyRegistered(&rootlessWindowPrivateKeyRec))
     90         return FALSE;
     91 
     92     if (!pWin->realized)
     93         return FALSE;
     94     top = TopLevelParent(pWin);
     95 
     96     return (top && WINREC(top));
     97 }
     98 
     99 Bool
    100 RootlessResolveColormap(ScreenPtr pScreen, int first_color,
    101                         int n_colors, uint32_t * colors)
    102 {
    103     int last, i;
    104     ColormapPtr map;
    105 
    106     map = RootlessGetColormap(pScreen);
    107     if (map == NULL || map->class != PseudoColor)
    108         return FALSE;
    109 
    110     last = min(map->pVisual->ColormapEntries, first_color + n_colors);
    111     for (i = max(0, first_color); i < last; i++) {
    112         Entry *ent = map->red + i;
    113         uint16_t red, green, blue;
    114 
    115         if (!ent->refcnt)
    116             continue;
    117         if (ent->fShared) {
    118             red = ent->co.shco.red->color;
    119             green = ent->co.shco.green->color;
    120             blue = ent->co.shco.blue->color;
    121         }
    122         else {
    123             red = ent->co.local.red;
    124             green = ent->co.local.green;
    125             blue = ent->co.local.blue;
    126         }
    127 
    128         colors[i - first_color] = (0xFF000000UL
    129                                    | ((uint32_t) red & 0xff00) << 8
    130                                    | (green & 0xff00)
    131                                    | (blue >> 8));
    132     }
    133 
    134     return TRUE;
    135 }
    136 
    137 /*
    138  * RootlessStartDrawing
    139  *  Prepare a window for direct access to its backing buffer.
    140  *  Each top-level parent has a Pixmap representing its backing buffer,
    141  *  which all of its children inherit.
    142  */
    143 void
    144 RootlessStartDrawing(WindowPtr pWindow)
    145 {
    146     ScreenPtr pScreen = pWindow->drawable.pScreen;
    147     WindowPtr top = TopLevelParent(pWindow);
    148     RootlessWindowRec *winRec;
    149     PixmapPtr curPixmap;
    150 
    151     if (top == NULL)
    152         return;
    153     winRec = WINREC(top);
    154     if (winRec == NULL)
    155         return;
    156 
    157     // Make sure the window's top-level parent is prepared for drawing.
    158     if (!winRec->is_drawing) {
    159         int bw = wBorderWidth(top);
    160 
    161         SCREENREC(pScreen)->imp->StartDrawing(winRec->wid, &winRec->pixelData,
    162                                               &winRec->bytesPerRow);
    163 
    164         winRec->pixmap =
    165             GetScratchPixmapHeader(pScreen, winRec->width, winRec->height,
    166                                    top->drawable.depth,
    167                                    top->drawable.bitsPerPixel,
    168                                    winRec->bytesPerRow, winRec->pixelData);
    169         SetPixmapBaseToScreen(winRec->pixmap,
    170                               top->drawable.x - bw, top->drawable.y - bw);
    171 
    172         winRec->is_drawing = TRUE;
    173     }
    174 
    175     curPixmap = pScreen->GetWindowPixmap(pWindow);
    176     if (curPixmap == winRec->pixmap) {
    177         RL_DEBUG_MSG("Window %p already has winRec->pixmap %p; not pushing\n",
    178                      pWindow, winRec->pixmap);
    179     }
    180     else {
    181         PixmapPtr oldPixmap =
    182             dixLookupPrivate(&pWindow->devPrivates,
    183                              rootlessWindowOldPixmapPrivateKey);
    184         if (oldPixmap != NULL) {
    185             if (oldPixmap == curPixmap)
    186                 RL_DEBUG_MSG
    187                     ("Window %p's curPixmap %p is the same as its oldPixmap; strange\n",
    188                      pWindow, curPixmap);
    189             else
    190                 RL_DEBUG_MSG("Window %p's existing oldPixmap %p being lost!\n",
    191                              pWindow, oldPixmap);
    192         }
    193         dixSetPrivate(&pWindow->devPrivates, rootlessWindowOldPixmapPrivateKey,
    194                       curPixmap);
    195         pScreen->SetWindowPixmap(pWindow, winRec->pixmap);
    196     }
    197 }
    198 
    199 /*
    200  * RootlessStopDrawing
    201  *  Stop drawing to a window's backing buffer. If flush is true,
    202  *  damaged regions are flushed to the screen.
    203  */
    204 static int
    205 RestorePreDrawingPixmapVisitor(WindowPtr pWindow, void *data)
    206 {
    207     RootlessWindowRec *winRec = (RootlessWindowRec *) data;
    208     ScreenPtr pScreen = pWindow->drawable.pScreen;
    209     PixmapPtr exPixmap = pScreen->GetWindowPixmap(pWindow);
    210     PixmapPtr oldPixmap =
    211         dixLookupPrivate(&pWindow->devPrivates,
    212                          rootlessWindowOldPixmapPrivateKey);
    213     if (oldPixmap == NULL) {
    214         if (exPixmap == winRec->pixmap)
    215             RL_DEBUG_MSG
    216                 ("Window %p appears to be in drawing mode (ex-pixmap %p equals winRec->pixmap, which is being freed) but has no oldPixmap!\n",
    217                  pWindow, exPixmap);
    218     }
    219     else {
    220         if (exPixmap != winRec->pixmap)
    221             RL_DEBUG_MSG
    222                 ("Window %p appears to be in drawing mode (oldPixmap %p) but ex-pixmap %p not winRec->pixmap %p!\n",
    223                  pWindow, oldPixmap, exPixmap, winRec->pixmap);
    224         if (oldPixmap == winRec->pixmap)
    225             RL_DEBUG_MSG
    226                 ("Window %p's oldPixmap %p is winRec->pixmap, which has just been freed!\n",
    227                  pWindow, oldPixmap);
    228         pScreen->SetWindowPixmap(pWindow, oldPixmap);
    229         dixSetPrivate(&pWindow->devPrivates, rootlessWindowOldPixmapPrivateKey,
    230                       NULL);
    231     }
    232     return WT_WALKCHILDREN;
    233 }
    234 
    235 void
    236 RootlessStopDrawing(WindowPtr pWindow, Bool flush)
    237 {
    238     ScreenPtr pScreen = pWindow->drawable.pScreen;
    239     WindowPtr top = TopLevelParent(pWindow);
    240     RootlessWindowRec *winRec;
    241 
    242     if (top == NULL)
    243         return;
    244     winRec = WINREC(top);
    245     if (winRec == NULL)
    246         return;
    247 
    248     if (winRec->is_drawing) {
    249         SCREENREC(pScreen)->imp->StopDrawing(winRec->wid, flush);
    250 
    251         FreeScratchPixmapHeader(winRec->pixmap);
    252         TraverseTree(top, RestorePreDrawingPixmapVisitor, (void *) winRec);
    253         winRec->pixmap = NULL;
    254 
    255         winRec->is_drawing = FALSE;
    256     }
    257     else if (flush) {
    258         SCREENREC(pScreen)->imp->UpdateRegion(winRec->wid, NULL);
    259     }
    260 
    261     if (flush && winRec->is_reorder_pending) {
    262         winRec->is_reorder_pending = FALSE;
    263         RootlessReorderWindow(pWindow);
    264     }
    265 }
    266 
    267 /*
    268  * RootlessDamageRegion
    269  *  Mark a damaged region as requiring redisplay to screen.
    270  *  pRegion is in GLOBAL coordinates.
    271  */
    272 void
    273 RootlessDamageRegion(WindowPtr pWindow, RegionPtr pRegion)
    274 {
    275     RootlessWindowRec *winRec;
    276     RegionRec clipped;
    277     WindowPtr pTop;
    278     BoxPtr b1, b2;
    279 
    280     RL_DEBUG_MSG("Damaged win 0x%x ", pWindow);
    281 
    282     pTop = TopLevelParent(pWindow);
    283     if (pTop == NULL)
    284         return;
    285 
    286     winRec = WINREC(pTop);
    287     if (winRec == NULL)
    288         return;
    289 
    290     /* We need to intersect the drawn region with the clip of the window
    291        to avoid marking places we didn't actually draw (which can cause
    292        problems when the window has an extra client-side backing store)
    293 
    294        But this is a costly operation and since we'll normally just be
    295        drawing inside the clip, go to some lengths to avoid the general
    296        case intersection. */
    297 
    298     b1 = RegionExtents(&pWindow->borderClip);
    299     b2 = RegionExtents(pRegion);
    300 
    301     if (EXTENTCHECK(b1, b2)) {
    302         /* Regions may overlap. */
    303 
    304         if (RegionNumRects(pRegion) == 1) {
    305             int in;
    306 
    307             /* Damaged region only has a single rect, so we can
    308                just compare that against the region */
    309 
    310             in = RegionContainsRect(&pWindow->borderClip, RegionRects(pRegion));
    311             if (in == rgnIN) {
    312                 /* clip totally contains pRegion */
    313 
    314                 SCREENREC(pWindow->drawable.pScreen)->imp->DamageRects(winRec->
    315                                                                        wid,
    316                                                                        RegionNumRects
    317                                                                        (pRegion),
    318                                                                        RegionRects
    319                                                                        (pRegion),
    320                                                                        -winRec->
    321                                                                        x,
    322                                                                        -winRec->
    323                                                                        y);
    324 
    325                 RootlessQueueRedisplay(pTop->drawable.pScreen);
    326                 goto out;
    327             }
    328             else if (in == rgnOUT) {
    329                 /* clip doesn't contain pRegion */
    330 
    331                 goto out;
    332             }
    333         }
    334 
    335         /* clip overlaps pRegion, need to intersect */
    336 
    337         RegionNull(&clipped);
    338         RegionIntersect(&clipped, &pWindow->borderClip, pRegion);
    339 
    340         SCREENREC(pWindow->drawable.pScreen)->imp->DamageRects(winRec->wid,
    341                                                                RegionNumRects
    342                                                                (&clipped),
    343                                                                RegionRects
    344                                                                (&clipped),
    345                                                                -winRec->x,
    346                                                                -winRec->y);
    347 
    348         RegionUninit(&clipped);
    349 
    350         RootlessQueueRedisplay(pTop->drawable.pScreen);
    351     }
    352 
    353  out:
    354 #ifdef ROOTLESSDEBUG
    355     {
    356         BoxRec *box = RegionRects(pRegion), *end;
    357         int numBox = RegionNumRects(pRegion);
    358 
    359         for (end = box + numBox; box < end; box++) {
    360             RL_DEBUG_MSG("Damage rect: %i, %i, %i, %i\n",
    361                          box->x1, box->x2, box->y1, box->y2);
    362         }
    363     }
    364 #endif
    365     return;
    366 }
    367 
    368 /*
    369  * RootlessDamageBox
    370  *  Mark a damaged box as requiring redisplay to screen.
    371  *  pRegion is in GLOBAL coordinates.
    372  */
    373 void
    374 RootlessDamageBox(WindowPtr pWindow, BoxPtr pBox)
    375 {
    376     RegionRec region;
    377 
    378     RegionInit(&region, pBox, 1);
    379 
    380     RootlessDamageRegion(pWindow, &region);
    381 
    382     RegionUninit(&region);      /* no-op */
    383 }
    384 
    385 /*
    386  * RootlessDamageRect
    387  *  Mark a damaged rectangle as requiring redisplay to screen.
    388  *  (x, y, w, h) is in window-local coordinates.
    389  */
    390 void
    391 RootlessDamageRect(WindowPtr pWindow, int x, int y, int w, int h)
    392 {
    393     BoxRec box;
    394     RegionRec region;
    395 
    396     x += pWindow->drawable.x;
    397     y += pWindow->drawable.y;
    398 
    399     box.x1 = x;
    400     box.x2 = x + w;
    401     box.y1 = y;
    402     box.y2 = y + h;
    403 
    404     RegionInit(&region, &box, 1);
    405 
    406     RootlessDamageRegion(pWindow, &region);
    407 
    408     RegionUninit(&region);      /* no-op */
    409 }
    410 
    411 /*
    412  * RootlessRedisplay
    413  *  Stop drawing and redisplay the damaged region of a window.
    414  */
    415 void
    416 RootlessRedisplay(WindowPtr pWindow)
    417 {
    418     RootlessStopDrawing(pWindow, TRUE);
    419 }
    420 
    421 /*
    422  * RootlessRepositionWindows
    423  *  Reposition all windows on a screen to their correct positions.
    424  */
    425 void
    426 RootlessRepositionWindows(ScreenPtr pScreen)
    427 {
    428     WindowPtr root = pScreen->root;
    429     WindowPtr win;
    430 
    431     if (root != NULL) {
    432         RootlessRepositionWindow(root);
    433 
    434         for (win = root->firstChild; win; win = win->nextSib) {
    435             if (WINREC(win) != NULL)
    436                 RootlessRepositionWindow(win);
    437         }
    438     }
    439 }
    440 
    441 /*
    442  * RootlessRedisplayScreen
    443  *  Walk every window on a screen and redisplay the damaged regions.
    444  */
    445 void
    446 RootlessRedisplayScreen(ScreenPtr pScreen)
    447 {
    448     WindowPtr root = pScreen->root;
    449 
    450     if (root != NULL) {
    451         WindowPtr win;
    452 
    453         RootlessRedisplay(root);
    454         for (win = root->firstChild; win; win = win->nextSib) {
    455             if (WINREC(win) != NULL) {
    456                 RootlessRedisplay(win);
    457             }
    458         }
    459     }
    460 }