diff options
Diffstat (limited to 'miext/rootless/rootlessCommon.c')
-rw-r--r-- | miext/rootless/rootlessCommon.c | 380 |
1 files changed, 380 insertions, 0 deletions
diff --git a/miext/rootless/rootlessCommon.c b/miext/rootless/rootlessCommon.c new file mode 100644 index 000000000..bc6259ea6 --- /dev/null +++ b/miext/rootless/rootlessCommon.c @@ -0,0 +1,380 @@ +/* + * 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. + */ +/* $XFree86: xc/programs/Xserver/miext/rootless/rootlessCommon.c,v 1.5 2003/11/10 18:22:50 tsi Exp $ */ + +#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 +} + + +/* + * 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); + } + } + } +} |