rootlessCommon.c revision 35c4bbdf
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 42unsigned int rootless_CopyBytes_threshold = 0; 43unsigned int rootless_CopyWindow_threshold = 0; 44int rootlessGlobalOffsetX = 0; 45int rootlessGlobalOffsetY = 0; 46 47RegionRec 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 */ 64WindowPtr 65TopLevelParent(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 */ 84Bool 85IsFramedWindow(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 99Bool 100RootlessResolveColormap(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 */ 143void 144RootlessStartDrawing(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 */ 204static int 205RestorePreDrawingPixmapVisitor(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 235void 236RootlessStopDrawing(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 */ 272void 273RootlessDamageRegion(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 */ 373void 374RootlessDamageBox(WindowPtr pWindow, BoxPtr pBox) 375{ 376 RegionRec region; 377 378 RegionInit(®ion, pBox, 1); 379 380 RootlessDamageRegion(pWindow, ®ion); 381 382 RegionUninit(®ion); /* 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 */ 390void 391RootlessDamageRect(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(®ion, &box, 1); 405 406 RootlessDamageRegion(pWindow, ®ion); 407 408 RegionUninit(®ion); /* no-op */ 409} 410 411/* 412 * RootlessRedisplay 413 * Stop drawing and redisplay the damaged region of a window. 414 */ 415void 416RootlessRedisplay(WindowPtr pWindow) 417{ 418 RootlessStopDrawing(pWindow, TRUE); 419} 420 421/* 422 * RootlessRepositionWindows 423 * Reposition all windows on a screen to their correct positions. 424 */ 425void 426RootlessRepositionWindows(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 */ 445void 446RootlessRedisplayScreen(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} 461