408 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			408 lines
		
	
	
		
			11 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"
 | |
| 
 | |
| 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));
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * 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;
 | |
| 
 | |
|     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;
 | |
|     }
 | |
| 
 | |
|     winRec->oldPixmap = pScreen->GetWindowPixmap(pWindow);
 | |
|     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.
 | |
|  */
 | |
| 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);
 | |
|         pScreen->SetWindowPixmap(pWindow, winRec->oldPixmap);
 | |
|         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);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 |