1706f2543Smrg/* 2706f2543Smrg * Common rootless definitions and code 3706f2543Smrg */ 4706f2543Smrg/* 5706f2543Smrg * Copyright (c) 2001 Greg Parker. All Rights Reserved. 6706f2543Smrg * Copyright (c) 2002-2003 Torrey T. Lyons. All Rights Reserved. 7706f2543Smrg * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. 8706f2543Smrg * 9706f2543Smrg * Permission is hereby granted, free of charge, to any person obtaining a 10706f2543Smrg * copy of this software and associated documentation files (the "Software"), 11706f2543Smrg * to deal in the Software without restriction, including without limitation 12706f2543Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 13706f2543Smrg * and/or sell copies of the Software, and to permit persons to whom the 14706f2543Smrg * Software is furnished to do so, subject to the following conditions: 15706f2543Smrg * 16706f2543Smrg * The above copyright notice and this permission notice shall be included in 17706f2543Smrg * all copies or substantial portions of the Software. 18706f2543Smrg * 19706f2543Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20706f2543Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21706f2543Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22706f2543Smrg * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 23706f2543Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 24706f2543Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25706f2543Smrg * DEALINGS IN THE SOFTWARE. 26706f2543Smrg * 27706f2543Smrg * Except as contained in this notice, the name(s) of the above copyright 28706f2543Smrg * holders shall not be used in advertising or otherwise to promote the sale, 29706f2543Smrg * use or other dealings in this Software without prior written authorization. 30706f2543Smrg */ 31706f2543Smrg 32706f2543Smrg#ifdef HAVE_DIX_CONFIG_H 33706f2543Smrg#include <dix-config.h> 34706f2543Smrg#endif 35706f2543Smrg 36706f2543Smrg#include <stddef.h> /* For NULL */ 37706f2543Smrg#include <limits.h> /* For CHAR_BIT */ 38706f2543Smrg 39706f2543Smrg#include "rootlessCommon.h" 40706f2543Smrg#include "colormapst.h" 41706f2543Smrg 42706f2543Smrgunsigned int rootless_CopyBytes_threshold = 0; 43706f2543Smrgunsigned int rootless_CopyWindow_threshold = 0; 44706f2543Smrgint rootlessGlobalOffsetX = 0; 45706f2543Smrgint rootlessGlobalOffsetY = 0; 46706f2543Smrg 47706f2543SmrgRegionRec rootlessHugeRoot = {{-32767, -32767, 32767, 32767}, NULL}; 48706f2543Smrg 49706f2543Smrg/* Following macro from miregion.c */ 50706f2543Smrg 51706f2543Smrg/* true iff two Boxes overlap */ 52706f2543Smrg#define EXTENTCHECK(r1,r2) \ 53706f2543Smrg (!( ((r1)->x2 <= (r2)->x1) || \ 54706f2543Smrg ((r1)->x1 >= (r2)->x2) || \ 55706f2543Smrg ((r1)->y2 <= (r2)->y1) || \ 56706f2543Smrg ((r1)->y1 >= (r2)->y2) ) ) 57706f2543Smrg 58706f2543Smrg 59706f2543Smrg/* 60706f2543Smrg * TopLevelParent 61706f2543Smrg * Returns the top-level parent of pWindow. 62706f2543Smrg * The root is the top-level parent of itself, even though the root is 63706f2543Smrg * not otherwise considered to be a top-level window. 64706f2543Smrg */ 65706f2543SmrgWindowPtr 66706f2543SmrgTopLevelParent(WindowPtr pWindow) 67706f2543Smrg{ 68706f2543Smrg WindowPtr top; 69706f2543Smrg 70706f2543Smrg if (IsRoot(pWindow)) 71706f2543Smrg return pWindow; 72706f2543Smrg 73706f2543Smrg top = pWindow; 74706f2543Smrg while (top && ! IsTopLevel(top)) 75706f2543Smrg top = top->parent; 76706f2543Smrg 77706f2543Smrg return top; 78706f2543Smrg} 79706f2543Smrg 80706f2543Smrg 81706f2543Smrg/* 82706f2543Smrg * IsFramedWindow 83706f2543Smrg * Returns TRUE if this window is visible inside a frame 84706f2543Smrg * (e.g. it is visible and has a top-level or root parent) 85706f2543Smrg */ 86706f2543SmrgBool 87706f2543SmrgIsFramedWindow(WindowPtr pWin) 88706f2543Smrg{ 89706f2543Smrg WindowPtr top; 90706f2543Smrg 91706f2543Smrg if (!dixPrivateKeyRegistered(&rootlessWindowPrivateKeyRec)) 92706f2543Smrg return FALSE; 93706f2543Smrg 94706f2543Smrg if (!pWin->realized) 95706f2543Smrg return FALSE; 96706f2543Smrg top = TopLevelParent(pWin); 97706f2543Smrg 98706f2543Smrg return (top && WINREC(top)); 99706f2543Smrg} 100706f2543Smrg 101706f2543SmrgBool 102706f2543SmrgRootlessResolveColormap (ScreenPtr pScreen, int first_color, 103706f2543Smrg int n_colors, uint32_t *colors) 104706f2543Smrg{ 105706f2543Smrg int last, i; 106706f2543Smrg ColormapPtr map; 107706f2543Smrg 108706f2543Smrg map = RootlessGetColormap (pScreen); 109706f2543Smrg if (map == NULL || map->class != PseudoColor) return FALSE; 110706f2543Smrg 111706f2543Smrg last = min (map->pVisual->ColormapEntries, first_color + n_colors); 112706f2543Smrg for (i = max (0, first_color); i < last; i++) { 113706f2543Smrg Entry *ent = map->red + i; 114706f2543Smrg uint16_t red, green, blue; 115706f2543Smrg 116706f2543Smrg if (!ent->refcnt) continue; 117706f2543Smrg if (ent->fShared) { 118706f2543Smrg red = ent->co.shco.red->color; 119706f2543Smrg green = ent->co.shco.green->color; 120706f2543Smrg blue = ent->co.shco.blue->color; 121706f2543Smrg } else { 122706f2543Smrg red = ent->co.local.red; 123706f2543Smrg green = ent->co.local.green; 124706f2543Smrg blue = ent->co.local.blue; 125706f2543Smrg } 126706f2543Smrg 127706f2543Smrg colors[i - first_color] = (0xFF000000UL 128706f2543Smrg | ((uint32_t) red & 0xff00) << 8 129706f2543Smrg | (green & 0xff00) 130706f2543Smrg | (blue >> 8)); 131706f2543Smrg } 132706f2543Smrg 133706f2543Smrg return TRUE; 134706f2543Smrg} 135706f2543Smrg 136706f2543Smrg 137706f2543Smrg/* 138706f2543Smrg * RootlessStartDrawing 139706f2543Smrg * Prepare a window for direct access to its backing buffer. 140706f2543Smrg * Each top-level parent has a Pixmap representing its backing buffer, 141706f2543Smrg * which all of its children inherit. 142706f2543Smrg */ 143706f2543Smrgvoid RootlessStartDrawing(WindowPtr pWindow) 144706f2543Smrg{ 145706f2543Smrg ScreenPtr pScreen = pWindow->drawable.pScreen; 146706f2543Smrg WindowPtr top = TopLevelParent(pWindow); 147706f2543Smrg RootlessWindowRec *winRec; 148706f2543Smrg PixmapPtr curPixmap; 149706f2543Smrg 150706f2543Smrg if (top == NULL) 151706f2543Smrg return; 152706f2543Smrg winRec = WINREC(top); 153706f2543Smrg if (winRec == NULL) 154706f2543Smrg return; 155706f2543Smrg 156706f2543Smrg // Make sure the window's top-level parent is prepared for drawing. 157706f2543Smrg if (!winRec->is_drawing) { 158706f2543Smrg int bw = wBorderWidth(top); 159706f2543Smrg 160706f2543Smrg SCREENREC(pScreen)->imp->StartDrawing(winRec->wid, &winRec->pixelData, 161706f2543Smrg &winRec->bytesPerRow); 162706f2543Smrg 163706f2543Smrg winRec->pixmap = 164706f2543Smrg GetScratchPixmapHeader(pScreen, winRec->width, winRec->height, 165706f2543Smrg top->drawable.depth, 166706f2543Smrg top->drawable.bitsPerPixel, 167706f2543Smrg winRec->bytesPerRow, 168706f2543Smrg winRec->pixelData); 169706f2543Smrg SetPixmapBaseToScreen(winRec->pixmap, 170706f2543Smrg top->drawable.x - bw, top->drawable.y - bw); 171706f2543Smrg 172706f2543Smrg winRec->is_drawing = TRUE; 173706f2543Smrg } 174706f2543Smrg 175706f2543Smrg curPixmap = pScreen->GetWindowPixmap(pWindow); 176706f2543Smrg if (curPixmap == winRec->pixmap) 177706f2543Smrg { 178706f2543Smrg RL_DEBUG_MSG("Window %p already has winRec->pixmap %p; not pushing\n", pWindow, winRec->pixmap); 179706f2543Smrg } 180706f2543Smrg else 181706f2543Smrg { 182706f2543Smrg PixmapPtr oldPixmap = dixLookupPrivate(&pWindow->devPrivates, rootlessWindowOldPixmapPrivateKey); 183706f2543Smrg if (oldPixmap != NULL) 184706f2543Smrg { 185706f2543Smrg if (oldPixmap == curPixmap) 186706f2543Smrg RL_DEBUG_MSG("Window %p's curPixmap %p is the same as its oldPixmap; strange\n", pWindow, curPixmap); 187706f2543Smrg else 188706f2543Smrg RL_DEBUG_MSG("Window %p's existing oldPixmap %p being lost!\n", pWindow, oldPixmap); 189706f2543Smrg } 190706f2543Smrg dixSetPrivate(&pWindow->devPrivates, rootlessWindowOldPixmapPrivateKey, curPixmap); 191706f2543Smrg pScreen->SetWindowPixmap(pWindow, winRec->pixmap); 192706f2543Smrg } 193706f2543Smrg} 194706f2543Smrg 195706f2543Smrg 196706f2543Smrg/* 197706f2543Smrg * RootlessStopDrawing 198706f2543Smrg * Stop drawing to a window's backing buffer. If flush is true, 199706f2543Smrg * damaged regions are flushed to the screen. 200706f2543Smrg */ 201706f2543Smrgstatic int RestorePreDrawingPixmapVisitor(WindowPtr pWindow, pointer data) 202706f2543Smrg{ 203706f2543Smrg RootlessWindowRec *winRec = (RootlessWindowRec*)data; 204706f2543Smrg ScreenPtr pScreen = pWindow->drawable.pScreen; 205706f2543Smrg PixmapPtr exPixmap = pScreen->GetWindowPixmap(pWindow); 206706f2543Smrg PixmapPtr oldPixmap = dixLookupPrivate(&pWindow->devPrivates, rootlessWindowOldPixmapPrivateKey); 207706f2543Smrg if (oldPixmap == NULL) 208706f2543Smrg { 209706f2543Smrg if (exPixmap == winRec->pixmap) 210706f2543Smrg 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); 211706f2543Smrg } 212706f2543Smrg else 213706f2543Smrg { 214706f2543Smrg if (exPixmap != winRec->pixmap) 215706f2543Smrg 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); 216706f2543Smrg if (oldPixmap == winRec->pixmap) 217706f2543Smrg RL_DEBUG_MSG("Window %p's oldPixmap %p is winRec->pixmap, which has just been freed!\n", pWindow, oldPixmap); 218706f2543Smrg pScreen->SetWindowPixmap(pWindow, oldPixmap); 219706f2543Smrg dixSetPrivate(&pWindow->devPrivates, rootlessWindowOldPixmapPrivateKey, NULL); 220706f2543Smrg } 221706f2543Smrg return WT_WALKCHILDREN; 222706f2543Smrg} 223706f2543Smrg 224706f2543Smrgvoid RootlessStopDrawing(WindowPtr pWindow, Bool flush) 225706f2543Smrg{ 226706f2543Smrg ScreenPtr pScreen = pWindow->drawable.pScreen; 227706f2543Smrg WindowPtr top = TopLevelParent(pWindow); 228706f2543Smrg RootlessWindowRec *winRec; 229706f2543Smrg 230706f2543Smrg if (top == NULL) 231706f2543Smrg return; 232706f2543Smrg winRec = WINREC(top); 233706f2543Smrg if (winRec == NULL) 234706f2543Smrg return; 235706f2543Smrg 236706f2543Smrg if (winRec->is_drawing) { 237706f2543Smrg SCREENREC(pScreen)->imp->StopDrawing(winRec->wid, flush); 238706f2543Smrg 239706f2543Smrg FreeScratchPixmapHeader(winRec->pixmap); 240706f2543Smrg TraverseTree(top, RestorePreDrawingPixmapVisitor, (pointer)winRec); 241706f2543Smrg winRec->pixmap = NULL; 242706f2543Smrg 243706f2543Smrg winRec->is_drawing = FALSE; 244706f2543Smrg } 245706f2543Smrg else if (flush) { 246706f2543Smrg SCREENREC(pScreen)->imp->UpdateRegion(winRec->wid, NULL); 247706f2543Smrg } 248706f2543Smrg 249706f2543Smrg if (flush && winRec->is_reorder_pending) { 250706f2543Smrg winRec->is_reorder_pending = FALSE; 251706f2543Smrg RootlessReorderWindow(pWindow); 252706f2543Smrg } 253706f2543Smrg} 254706f2543Smrg 255706f2543Smrg 256706f2543Smrg/* 257706f2543Smrg * RootlessDamageRegion 258706f2543Smrg * Mark a damaged region as requiring redisplay to screen. 259706f2543Smrg * pRegion is in GLOBAL coordinates. 260706f2543Smrg */ 261706f2543Smrgvoid 262706f2543SmrgRootlessDamageRegion(WindowPtr pWindow, RegionPtr pRegion) 263706f2543Smrg{ 264706f2543Smrg RootlessWindowRec *winRec; 265706f2543Smrg RegionRec clipped; 266706f2543Smrg WindowPtr pTop; 267706f2543Smrg BoxPtr b1, b2; 268706f2543Smrg 269706f2543Smrg RL_DEBUG_MSG("Damaged win 0x%x ", pWindow); 270706f2543Smrg 271706f2543Smrg pTop = TopLevelParent(pWindow); 272706f2543Smrg if (pTop == NULL) 273706f2543Smrg return; 274706f2543Smrg 275706f2543Smrg winRec = WINREC(pTop); 276706f2543Smrg if (winRec == NULL) 277706f2543Smrg return; 278706f2543Smrg 279706f2543Smrg /* We need to intersect the drawn region with the clip of the window 280706f2543Smrg to avoid marking places we didn't actually draw (which can cause 281706f2543Smrg problems when the window has an extra client-side backing store) 282706f2543Smrg 283706f2543Smrg But this is a costly operation and since we'll normally just be 284706f2543Smrg drawing inside the clip, go to some lengths to avoid the general 285706f2543Smrg case intersection. */ 286706f2543Smrg 287706f2543Smrg b1 = RegionExtents(&pWindow->borderClip); 288706f2543Smrg b2 = RegionExtents(pRegion); 289706f2543Smrg 290706f2543Smrg if (EXTENTCHECK(b1, b2)) { 291706f2543Smrg /* Regions may overlap. */ 292706f2543Smrg 293706f2543Smrg if (RegionNumRects(pRegion) == 1) { 294706f2543Smrg int in; 295706f2543Smrg 296706f2543Smrg /* Damaged region only has a single rect, so we can 297706f2543Smrg just compare that against the region */ 298706f2543Smrg 299706f2543Smrg in = RegionContainsRect(&pWindow->borderClip, 300706f2543Smrg RegionRects (pRegion)); 301706f2543Smrg if (in == rgnIN) { 302706f2543Smrg /* clip totally contains pRegion */ 303706f2543Smrg 304706f2543Smrg SCREENREC(pWindow->drawable.pScreen)->imp-> 305706f2543Smrg DamageRects(winRec->wid, 306706f2543Smrg RegionNumRects(pRegion), 307706f2543Smrg RegionRects(pRegion), 308706f2543Smrg -winRec->x, -winRec->y); 309706f2543Smrg 310706f2543Smrg RootlessQueueRedisplay(pTop->drawable.pScreen); 311706f2543Smrg goto out; 312706f2543Smrg } 313706f2543Smrg else if (in == rgnOUT) { 314706f2543Smrg /* clip doesn't contain pRegion */ 315706f2543Smrg 316706f2543Smrg goto out; 317706f2543Smrg } 318706f2543Smrg } 319706f2543Smrg 320706f2543Smrg /* clip overlaps pRegion, need to intersect */ 321706f2543Smrg 322706f2543Smrg RegionNull(&clipped); 323706f2543Smrg RegionIntersect(&clipped, &pWindow->borderClip, pRegion); 324706f2543Smrg 325706f2543Smrg SCREENREC(pWindow->drawable.pScreen)->imp-> 326706f2543Smrg DamageRects(winRec->wid, 327706f2543Smrg RegionNumRects(&clipped), 328706f2543Smrg RegionRects(&clipped), 329706f2543Smrg -winRec->x, -winRec->y); 330706f2543Smrg 331706f2543Smrg RegionUninit(&clipped); 332706f2543Smrg 333706f2543Smrg RootlessQueueRedisplay(pTop->drawable.pScreen); 334706f2543Smrg } 335706f2543Smrg 336706f2543Smrgout: 337706f2543Smrg#ifdef ROOTLESSDEBUG 338706f2543Smrg { 339706f2543Smrg BoxRec *box = RegionRects(pRegion), *end; 340706f2543Smrg int numBox = RegionNumRects(pRegion); 341706f2543Smrg 342706f2543Smrg for (end = box+numBox; box < end; box++) { 343706f2543Smrg RL_DEBUG_MSG("Damage rect: %i, %i, %i, %i\n", 344706f2543Smrg box->x1, box->x2, box->y1, box->y2); 345706f2543Smrg } 346706f2543Smrg } 347706f2543Smrg#endif 348706f2543Smrg return; 349706f2543Smrg} 350706f2543Smrg 351706f2543Smrg 352706f2543Smrg/* 353706f2543Smrg * RootlessDamageBox 354706f2543Smrg * Mark a damaged box as requiring redisplay to screen. 355706f2543Smrg * pRegion is in GLOBAL coordinates. 356706f2543Smrg */ 357706f2543Smrgvoid 358706f2543SmrgRootlessDamageBox(WindowPtr pWindow, BoxPtr pBox) 359706f2543Smrg{ 360706f2543Smrg RegionRec region; 361706f2543Smrg 362706f2543Smrg RegionInit(®ion, pBox, 1); 363706f2543Smrg 364706f2543Smrg RootlessDamageRegion(pWindow, ®ion); 365706f2543Smrg 366706f2543Smrg RegionUninit(®ion); /* no-op */ 367706f2543Smrg} 368706f2543Smrg 369706f2543Smrg 370706f2543Smrg/* 371706f2543Smrg * RootlessDamageRect 372706f2543Smrg * Mark a damaged rectangle as requiring redisplay to screen. 373706f2543Smrg * (x, y, w, h) is in window-local coordinates. 374706f2543Smrg */ 375706f2543Smrgvoid 376706f2543SmrgRootlessDamageRect(WindowPtr pWindow, int x, int y, int w, int h) 377706f2543Smrg{ 378706f2543Smrg BoxRec box; 379706f2543Smrg RegionRec region; 380706f2543Smrg 381706f2543Smrg x += pWindow->drawable.x; 382706f2543Smrg y += pWindow->drawable.y; 383706f2543Smrg 384706f2543Smrg box.x1 = x; 385706f2543Smrg box.x2 = x + w; 386706f2543Smrg box.y1 = y; 387706f2543Smrg box.y2 = y + h; 388706f2543Smrg 389706f2543Smrg RegionInit(®ion, &box, 1); 390706f2543Smrg 391706f2543Smrg RootlessDamageRegion(pWindow, ®ion); 392706f2543Smrg 393706f2543Smrg RegionUninit(®ion); /* no-op */ 394706f2543Smrg} 395706f2543Smrg 396706f2543Smrg 397706f2543Smrg/* 398706f2543Smrg * RootlessRedisplay 399706f2543Smrg * Stop drawing and redisplay the damaged region of a window. 400706f2543Smrg */ 401706f2543Smrgvoid 402706f2543SmrgRootlessRedisplay(WindowPtr pWindow) 403706f2543Smrg{ 404706f2543Smrg RootlessStopDrawing(pWindow, TRUE); 405706f2543Smrg} 406706f2543Smrg 407706f2543Smrg 408706f2543Smrg/* 409706f2543Smrg * RootlessRepositionWindows 410706f2543Smrg * Reposition all windows on a screen to their correct positions. 411706f2543Smrg */ 412706f2543Smrgvoid 413706f2543SmrgRootlessRepositionWindows(ScreenPtr pScreen) 414706f2543Smrg{ 415706f2543Smrg WindowPtr root = pScreen->root; 416706f2543Smrg WindowPtr win; 417706f2543Smrg 418706f2543Smrg if (root != NULL) { 419706f2543Smrg RootlessRepositionWindow(root); 420706f2543Smrg 421706f2543Smrg for (win = root->firstChild; win; win = win->nextSib) { 422706f2543Smrg if (WINREC(win) != NULL) 423706f2543Smrg RootlessRepositionWindow(win); 424706f2543Smrg } 425706f2543Smrg } 426706f2543Smrg} 427706f2543Smrg 428706f2543Smrg 429706f2543Smrg/* 430706f2543Smrg * RootlessRedisplayScreen 431706f2543Smrg * Walk every window on a screen and redisplay the damaged regions. 432706f2543Smrg */ 433706f2543Smrgvoid 434706f2543SmrgRootlessRedisplayScreen(ScreenPtr pScreen) 435706f2543Smrg{ 436706f2543Smrg WindowPtr root = pScreen->root; 437706f2543Smrg 438706f2543Smrg if (root != NULL) { 439706f2543Smrg WindowPtr win; 440706f2543Smrg 441706f2543Smrg RootlessRedisplay(root); 442706f2543Smrg for (win = root->firstChild; win; win = win->nextSib) { 443706f2543Smrg if (WINREC(win) != NULL) { 444706f2543Smrg RootlessRedisplay(win); 445706f2543Smrg } 446706f2543Smrg } 447706f2543Smrg } 448706f2543Smrg} 449