484 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			484 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
/*
 | 
						|
 * Common rootless definitions and code
 | 
						|
 */
 | 
						|
/*
 | 
						|
 * Copyright (c) 2001 Greg Parker. All Rights Reserved.
 | 
						|
 * Copyright (c) 2002-2003 Torrey T. Lyons. All Rights Reserved.
 | 
						|
 * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
 | 
						|
 *
 | 
						|
 * 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 ABOVE LISTED COPYRIGHT HOLDER(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(s) of the above copyright
 | 
						|
 * holders shall not be used in advertising or otherwise to promote the sale,
 | 
						|
 * use or other dealings in this Software without prior written authorization.
 | 
						|
 */
 | 
						|
 | 
						|
#ifdef HAVE_DIX_CONFIG_H
 | 
						|
#include <dix-config.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#include <stddef.h> /* For NULL */
 | 
						|
#include <limits.h> /* For CHAR_BIT */
 | 
						|
 | 
						|
#include "rootlessCommon.h"
 | 
						|
#include "colormapst.h"
 | 
						|
 | 
						|
unsigned int rootless_CopyBytes_threshold = 0;
 | 
						|
unsigned int rootless_FillBytes_threshold = 0;
 | 
						|
unsigned int rootless_CompositePixels_threshold = 0;
 | 
						|
unsigned int rootless_CopyWindow_threshold = 0;
 | 
						|
#ifdef ROOTLESS_GLOBAL_COORDS
 | 
						|
int rootlessGlobalOffsetX = 0;
 | 
						|
int rootlessGlobalOffsetY = 0;
 | 
						|
#endif
 | 
						|
 | 
						|
RegionRec rootlessHugeRoot = {{-32767, -32767, 32767, 32767}, NULL};
 | 
						|
 | 
						|
/* Following macro from miregion.c */
 | 
						|
 | 
						|
/*  true iff two Boxes overlap */
 | 
						|
#define EXTENTCHECK(r1,r2) \
 | 
						|
      (!( ((r1)->x2 <= (r2)->x1)  || \
 | 
						|
          ((r1)->x1 >= (r2)->x2)  || \
 | 
						|
          ((r1)->y2 <= (r2)->y1)  || \
 | 
						|
          ((r1)->y1 >= (r2)->y2) ) )
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * TopLevelParent
 | 
						|
 *  Returns the top-level parent of pWindow.
 | 
						|
 *  The root is the top-level parent of itself, even though the root is
 | 
						|
 *  not otherwise considered to be a top-level window.
 | 
						|
 */
 | 
						|
WindowPtr
 | 
						|
TopLevelParent(WindowPtr pWindow)
 | 
						|
{
 | 
						|
    WindowPtr top;
 | 
						|
 | 
						|
    if (IsRoot(pWindow))
 | 
						|
        return pWindow;
 | 
						|
 | 
						|
    top = pWindow;
 | 
						|
    while (top && ! IsTopLevel(top))
 | 
						|
        top = top->parent;
 | 
						|
 | 
						|
    return top;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * IsFramedWindow
 | 
						|
 *  Returns TRUE if this window is visible inside a frame
 | 
						|
 *  (e.g. it is visible and has a top-level or root parent)
 | 
						|
 */
 | 
						|
Bool
 | 
						|
IsFramedWindow(WindowPtr pWin)
 | 
						|
{
 | 
						|
    WindowPtr top;
 | 
						|
 | 
						|
    if (!pWin->realized)
 | 
						|
        return FALSE;
 | 
						|
    top = TopLevelParent(pWin);
 | 
						|
 | 
						|
    return (top && WINREC(top));
 | 
						|
}
 | 
						|
 | 
						|
Bool
 | 
						|
RootlessResolveColormap (ScreenPtr pScreen, int first_color,
 | 
						|
                         int n_colors, uint32_t *colors)
 | 
						|
{
 | 
						|
  int last, i;
 | 
						|
  ColormapPtr map;
 | 
						|
 | 
						|
  map = RootlessGetColormap (pScreen);
 | 
						|
  if (map == NULL || map->class != PseudoColor) return FALSE;
 | 
						|
 | 
						|
  last = min (map->pVisual->ColormapEntries, first_color + n_colors);
 | 
						|
  for (i = max (0, first_color); i < last; i++) {
 | 
						|
    Entry *ent = map->red + i;
 | 
						|
    uint16_t red, green, blue;
 | 
						|
 | 
						|
      if (!ent->refcnt)	continue;
 | 
						|
      if (ent->fShared) {
 | 
						|
	red = ent->co.shco.red->color;
 | 
						|
	green = ent->co.shco.green->color;
 | 
						|
	blue = ent->co.shco.blue->color;
 | 
						|
      } else {
 | 
						|
	red = ent->co.local.red;
 | 
						|
	green = ent->co.local.green;
 | 
						|
	blue = ent->co.local.blue;
 | 
						|
      }
 | 
						|
 | 
						|
      colors[i - first_color] = (0xFF000000UL
 | 
						|
				 | ((uint32_t) red & 0xff00) << 8
 | 
						|
				 | (green & 0xff00)
 | 
						|
				 | (blue >> 8));
 | 
						|
    }
 | 
						|
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * RootlessStartDrawing
 | 
						|
 *  Prepare a window for direct access to its backing buffer.
 | 
						|
 *  Each top-level parent has a Pixmap representing its backing buffer,
 | 
						|
 *  which all of its children inherit.
 | 
						|
 */
 | 
						|
void RootlessStartDrawing(WindowPtr pWindow)
 | 
						|
{
 | 
						|
    ScreenPtr pScreen = pWindow->drawable.pScreen;
 | 
						|
    WindowPtr top = TopLevelParent(pWindow);
 | 
						|
    RootlessWindowRec *winRec;
 | 
						|
    PixmapPtr curPixmap;
 | 
						|
 | 
						|
    if (top == NULL)
 | 
						|
        return;
 | 
						|
    winRec = WINREC(top);
 | 
						|
    if (winRec == NULL)
 | 
						|
        return;
 | 
						|
 | 
						|
    // Make sure the window's top-level parent is prepared for drawing.
 | 
						|
    if (!winRec->is_drawing) {
 | 
						|
        int bw = wBorderWidth(top);
 | 
						|
 | 
						|
        SCREENREC(pScreen)->imp->StartDrawing(winRec->wid, &winRec->pixelData,
 | 
						|
                                              &winRec->bytesPerRow);
 | 
						|
 | 
						|
        winRec->pixmap =
 | 
						|
            GetScratchPixmapHeader(pScreen, winRec->width, winRec->height,
 | 
						|
                                   top->drawable.depth,
 | 
						|
                                   top->drawable.bitsPerPixel,
 | 
						|
                                   winRec->bytesPerRow,
 | 
						|
                                   winRec->pixelData);
 | 
						|
        SetPixmapBaseToScreen(winRec->pixmap,
 | 
						|
                              top->drawable.x - bw, top->drawable.y - bw);
 | 
						|
 | 
						|
        winRec->is_drawing = TRUE;
 | 
						|
    }
 | 
						|
 | 
						|
    curPixmap = pScreen->GetWindowPixmap(pWindow);
 | 
						|
    if (curPixmap == winRec->pixmap)
 | 
						|
    {
 | 
						|
        RL_DEBUG_MSG("Window %p already has winRec->pixmap %p; not pushing\n", pWindow, winRec->pixmap);
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        PixmapPtr oldPixmap = dixLookupPrivate(&pWindow->devPrivates, rootlessWindowOldPixmapPrivateKey);
 | 
						|
        if (oldPixmap != NULL)
 | 
						|
        {
 | 
						|
            if (oldPixmap == curPixmap)
 | 
						|
                RL_DEBUG_MSG("Window %p's curPixmap %p is the same as its oldPixmap; strange\n", pWindow, curPixmap);
 | 
						|
            else
 | 
						|
                RL_DEBUG_MSG("Window %p's existing oldPixmap %p being lost!\n", pWindow, oldPixmap);
 | 
						|
        }
 | 
						|
	dixSetPrivate(&pWindow->devPrivates, rootlessWindowOldPixmapPrivateKey, curPixmap);
 | 
						|
        pScreen->SetWindowPixmap(pWindow, winRec->pixmap);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * RootlessStopDrawing
 | 
						|
 *  Stop drawing to a window's backing buffer. If flush is true,
 | 
						|
 *  damaged regions are flushed to the screen.
 | 
						|
 */
 | 
						|
static int RestorePreDrawingPixmapVisitor(WindowPtr pWindow, pointer data)
 | 
						|
{
 | 
						|
    RootlessWindowRec *winRec = (RootlessWindowRec*)data;
 | 
						|
    ScreenPtr pScreen = pWindow->drawable.pScreen;
 | 
						|
    PixmapPtr exPixmap = pScreen->GetWindowPixmap(pWindow);
 | 
						|
    PixmapPtr oldPixmap = dixLookupPrivate(&pWindow->devPrivates, rootlessWindowOldPixmapPrivateKey);
 | 
						|
    if (oldPixmap == NULL)
 | 
						|
    {
 | 
						|
        if (exPixmap == winRec->pixmap)
 | 
						|
            RL_DEBUG_MSG("Window %p appears to be in drawing mode (ex-pixmap %p equals winRec->pixmap, which is being freed) but has no oldPixmap!\n", pWindow, exPixmap);
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        if (exPixmap != winRec->pixmap)
 | 
						|
            RL_DEBUG_MSG("Window %p appears to be in drawing mode (oldPixmap %p) but ex-pixmap %p not winRec->pixmap %p!\n", pWindow, oldPixmap, exPixmap, winRec->pixmap);
 | 
						|
        if (oldPixmap == winRec->pixmap)
 | 
						|
            RL_DEBUG_MSG("Window %p's oldPixmap %p is winRec->pixmap, which has just been freed!\n", pWindow, oldPixmap);
 | 
						|
        pScreen->SetWindowPixmap(pWindow, oldPixmap);
 | 
						|
        dixSetPrivate(&pWindow->devPrivates, rootlessWindowOldPixmapPrivateKey, NULL);
 | 
						|
    }
 | 
						|
    return WT_WALKCHILDREN;
 | 
						|
}
 | 
						|
 | 
						|
void RootlessStopDrawing(WindowPtr pWindow, Bool flush)
 | 
						|
{
 | 
						|
    ScreenPtr pScreen = pWindow->drawable.pScreen;
 | 
						|
    WindowPtr top = TopLevelParent(pWindow);
 | 
						|
    RootlessWindowRec *winRec;
 | 
						|
 | 
						|
    if (top == NULL)
 | 
						|
        return;
 | 
						|
    winRec = WINREC(top);
 | 
						|
    if (winRec == NULL)
 | 
						|
        return;
 | 
						|
 | 
						|
    if (winRec->is_drawing) {
 | 
						|
        SCREENREC(pScreen)->imp->StopDrawing(winRec->wid, flush);
 | 
						|
 | 
						|
        FreeScratchPixmapHeader(winRec->pixmap);
 | 
						|
        TraverseTree(top, RestorePreDrawingPixmapVisitor, (pointer)winRec);
 | 
						|
        winRec->pixmap = NULL;
 | 
						|
 | 
						|
        winRec->is_drawing = FALSE;
 | 
						|
    }
 | 
						|
    else if (flush) {
 | 
						|
        SCREENREC(pScreen)->imp->UpdateRegion(winRec->wid, NULL);
 | 
						|
    }
 | 
						|
 | 
						|
    if (flush && winRec->is_reorder_pending) {
 | 
						|
        winRec->is_reorder_pending = FALSE;
 | 
						|
        RootlessReorderWindow(pWindow);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * RootlessDamageRegion
 | 
						|
 *  Mark a damaged region as requiring redisplay to screen.
 | 
						|
 *  pRegion is in GLOBAL coordinates.
 | 
						|
 */
 | 
						|
void
 | 
						|
RootlessDamageRegion(WindowPtr pWindow, RegionPtr pRegion)
 | 
						|
{
 | 
						|
    ScreenPtr pScreen = pWindow->drawable.pScreen;
 | 
						|
    RootlessWindowRec *winRec;
 | 
						|
    RegionRec clipped;
 | 
						|
    WindowPtr pTop;
 | 
						|
    BoxPtr b1, b2;
 | 
						|
 | 
						|
    RL_DEBUG_MSG("Damaged win 0x%x ", pWindow);
 | 
						|
 | 
						|
    pTop = TopLevelParent(pWindow);
 | 
						|
    if (pTop == NULL)
 | 
						|
        return;
 | 
						|
 | 
						|
    winRec = WINREC(pTop);
 | 
						|
    if (winRec == NULL)
 | 
						|
        return;
 | 
						|
 | 
						|
    /* We need to intersect the drawn region with the clip of the window
 | 
						|
       to avoid marking places we didn't actually draw (which can cause
 | 
						|
       problems when the window has an extra client-side backing store)
 | 
						|
 | 
						|
       But this is a costly operation and since we'll normally just be
 | 
						|
       drawing inside the clip, go to some lengths to avoid the general
 | 
						|
       case intersection. */
 | 
						|
 | 
						|
    b1 = REGION_EXTENTS(pScreen, &pWindow->borderClip);
 | 
						|
    b2 = REGION_EXTENTS(pScreen, pRegion);
 | 
						|
 | 
						|
    if (EXTENTCHECK(b1, b2)) {
 | 
						|
        /* Regions may overlap. */
 | 
						|
 | 
						|
        if (REGION_NUM_RECTS(pRegion) == 1) {
 | 
						|
            int in;
 | 
						|
 | 
						|
            /* Damaged region only has a single rect, so we can
 | 
						|
               just compare that against the region */
 | 
						|
 | 
						|
            in = RECT_IN_REGION(pScreen, &pWindow->borderClip,
 | 
						|
                                REGION_RECTS (pRegion));
 | 
						|
            if (in == rgnIN) {
 | 
						|
            /* clip totally contains pRegion */
 | 
						|
 | 
						|
#ifdef ROOTLESS_TRACK_DAMAGE
 | 
						|
                REGION_UNION(pScreen, &winRec->damage,
 | 
						|
                                 &winRec->damage, (pRegion));
 | 
						|
#else
 | 
						|
                SCREENREC(pScreen)->imp->DamageRects(winRec->wid,
 | 
						|
                                REGION_NUM_RECTS(pRegion),
 | 
						|
                                REGION_RECTS(pRegion),
 | 
						|
                                -winRec->x, -winRec->y);
 | 
						|
#endif
 | 
						|
 | 
						|
                RootlessQueueRedisplay(pTop->drawable.pScreen);
 | 
						|
                goto out;
 | 
						|
            }
 | 
						|
            else if (in == rgnOUT) {
 | 
						|
                /* clip doesn't contain pRegion */
 | 
						|
 | 
						|
                goto out;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        /* clip overlaps pRegion, need to intersect */
 | 
						|
 | 
						|
        REGION_NULL(pScreen, &clipped);
 | 
						|
        REGION_INTERSECT(pScreen, &clipped, &pWindow->borderClip, pRegion);
 | 
						|
 | 
						|
#ifdef ROOTLESS_TRACK_DAMAGE
 | 
						|
        REGION_UNION(pScreen, &winRec->damage,
 | 
						|
                     &winRec->damage, (pRegion));
 | 
						|
#else
 | 
						|
        SCREENREC(pScreen)->imp->DamageRects(winRec->wid,
 | 
						|
                        REGION_NUM_RECTS(&clipped),
 | 
						|
                        REGION_RECTS(&clipped),
 | 
						|
                        -winRec->x, -winRec->y);
 | 
						|
#endif
 | 
						|
 | 
						|
        REGION_UNINIT(pScreen, &clipped);
 | 
						|
 | 
						|
        RootlessQueueRedisplay(pTop->drawable.pScreen);
 | 
						|
    }
 | 
						|
 | 
						|
out:
 | 
						|
#ifdef ROOTLESSDEBUG
 | 
						|
    {
 | 
						|
        BoxRec *box = REGION_RECTS(pRegion), *end;
 | 
						|
        int numBox = REGION_NUM_RECTS(pRegion);
 | 
						|
 | 
						|
        for (end = box+numBox; box < end; box++) {
 | 
						|
            RL_DEBUG_MSG("Damage rect: %i, %i, %i, %i\n",
 | 
						|
                         box->x1, box->x2, box->y1, box->y2);
 | 
						|
        }
 | 
						|
    }
 | 
						|
#endif
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * RootlessDamageBox
 | 
						|
 *  Mark a damaged box as requiring redisplay to screen.
 | 
						|
 *  pRegion is in GLOBAL coordinates.
 | 
						|
 */
 | 
						|
void
 | 
						|
RootlessDamageBox(WindowPtr pWindow, BoxPtr pBox)
 | 
						|
{
 | 
						|
    RegionRec region;
 | 
						|
 | 
						|
    REGION_INIT(pWindow->drawable.pScreen, ®ion, pBox, 1);
 | 
						|
 | 
						|
    RootlessDamageRegion(pWindow, ®ion);
 | 
						|
 | 
						|
    REGION_UNINIT(pWindow->drawable.pScreen, ®ion);  /* no-op */
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * RootlessDamageRect
 | 
						|
 *  Mark a damaged rectangle as requiring redisplay to screen.
 | 
						|
 *  (x, y, w, h) is in window-local coordinates.
 | 
						|
 */
 | 
						|
void
 | 
						|
RootlessDamageRect(WindowPtr pWindow, int x, int y, int w, int h)
 | 
						|
{
 | 
						|
    BoxRec box;
 | 
						|
    RegionRec region;
 | 
						|
 | 
						|
    x += pWindow->drawable.x;
 | 
						|
    y += pWindow->drawable.y;
 | 
						|
 | 
						|
    box.x1 = x;
 | 
						|
    box.x2 = x + w;
 | 
						|
    box.y1 = y;
 | 
						|
    box.y2 = y + h;
 | 
						|
 | 
						|
    REGION_INIT(pWindow->drawable.pScreen, ®ion, &box, 1);
 | 
						|
 | 
						|
    RootlessDamageRegion(pWindow, ®ion);
 | 
						|
 | 
						|
    REGION_UNINIT(pWindow->drawable.pScreen, ®ion);  /* no-op */
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * RootlessRedisplay
 | 
						|
 *  Stop drawing and redisplay the damaged region of a window.
 | 
						|
 */
 | 
						|
void
 | 
						|
RootlessRedisplay(WindowPtr pWindow)
 | 
						|
{
 | 
						|
#ifdef ROOTLESS_TRACK_DAMAGE
 | 
						|
 | 
						|
    RootlessWindowRec *winRec = WINREC(pWindow);
 | 
						|
    ScreenPtr pScreen = pWindow->drawable.pScreen;
 | 
						|
 | 
						|
    RootlessStopDrawing(pWindow, FALSE);
 | 
						|
 | 
						|
    if (REGION_NOTEMPTY(pScreen, &winRec->damage)) {
 | 
						|
        RL_DEBUG_MSG("Redisplay Win 0x%x, %i x %i @ (%i, %i)\n",
 | 
						|
                     pWindow, winRec->width, winRec->height,
 | 
						|
                     winRec->x, winRec->y);
 | 
						|
 | 
						|
        // move region to window local coords
 | 
						|
        REGION_TRANSLATE(pScreen, &winRec->damage,
 | 
						|
                         -winRec->x, -winRec->y);
 | 
						|
 | 
						|
        SCREENREC(pScreen)->imp->UpdateRegion(winRec->wid, &winRec->damage);
 | 
						|
 | 
						|
        REGION_EMPTY(pScreen, &winRec->damage);
 | 
						|
    }
 | 
						|
 | 
						|
#else   /* !ROOTLESS_TRACK_DAMAGE */
 | 
						|
 | 
						|
    RootlessStopDrawing(pWindow, TRUE);
 | 
						|
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * RootlessRepositionWindows
 | 
						|
 *  Reposition all windows on a screen to their correct positions.
 | 
						|
 */
 | 
						|
void
 | 
						|
RootlessRepositionWindows(ScreenPtr pScreen)
 | 
						|
{
 | 
						|
    WindowPtr root = WindowTable[pScreen->myNum];
 | 
						|
    WindowPtr win;
 | 
						|
 | 
						|
    if (root != NULL) {
 | 
						|
        RootlessRepositionWindow(root);
 | 
						|
 | 
						|
        for (win = root->firstChild; win; win = win->nextSib) {
 | 
						|
            if (WINREC(win) != NULL)
 | 
						|
                RootlessRepositionWindow(win);
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * RootlessRedisplayScreen
 | 
						|
 *  Walk every window on a screen and redisplay the damaged regions.
 | 
						|
 */
 | 
						|
void
 | 
						|
RootlessRedisplayScreen(ScreenPtr pScreen)
 | 
						|
{
 | 
						|
    WindowPtr root = WindowTable[pScreen->myNum];
 | 
						|
 | 
						|
    if (root != NULL) {
 | 
						|
        WindowPtr win;
 | 
						|
 | 
						|
        RootlessRedisplay(root);
 | 
						|
        for (win = root->firstChild; win; win = win->nextSib) {
 | 
						|
            if (WINREC(win) != NULL) {
 | 
						|
                RootlessRedisplay(win);
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 |