rootlessCommon.c revision 4642e01f
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_FillBytes_threshold = 0; 44unsigned int rootless_CompositePixels_threshold = 0; 45unsigned int rootless_CopyWindow_threshold = 0; 46#ifdef ROOTLESS_GLOBAL_COORDS 47int rootlessGlobalOffsetX = 0; 48int rootlessGlobalOffsetY = 0; 49#endif 50 51RegionRec rootlessHugeRoot = {{-32767, -32767, 32767, 32767}, NULL}; 52 53/* Following macro from miregion.c */ 54 55/* true iff two Boxes overlap */ 56#define EXTENTCHECK(r1,r2) \ 57 (!( ((r1)->x2 <= (r2)->x1) || \ 58 ((r1)->x1 >= (r2)->x2) || \ 59 ((r1)->y2 <= (r2)->y1) || \ 60 ((r1)->y1 >= (r2)->y2) ) ) 61 62 63/* 64 * TopLevelParent 65 * Returns the top-level parent of pWindow. 66 * The root is the top-level parent of itself, even though the root is 67 * not otherwise considered to be a top-level window. 68 */ 69WindowPtr 70TopLevelParent(WindowPtr pWindow) 71{ 72 WindowPtr top; 73 74 if (IsRoot(pWindow)) 75 return pWindow; 76 77 top = pWindow; 78 while (top && ! IsTopLevel(top)) 79 top = top->parent; 80 81 return top; 82} 83 84 85/* 86 * IsFramedWindow 87 * Returns TRUE if this window is visible inside a frame 88 * (e.g. it is visible and has a top-level or root parent) 89 */ 90Bool 91IsFramedWindow(WindowPtr pWin) 92{ 93 WindowPtr top; 94 95 if (!pWin->realized) 96 return FALSE; 97 top = TopLevelParent(pWin); 98 99 return (top && WINREC(top)); 100} 101 102Bool 103RootlessResolveColormap (ScreenPtr pScreen, int first_color, 104 int n_colors, uint32_t *colors) 105{ 106 int last, i; 107 ColormapPtr map; 108 109 map = RootlessGetColormap (pScreen); 110 if (map == NULL || map->class != PseudoColor) return FALSE; 111 112 last = MIN (map->pVisual->ColormapEntries, first_color + n_colors); 113 for (i = MAX (0, first_color); i < last; i++) { 114 Entry *ent = map->red + i; 115 uint16_t red, green, blue; 116 117 if (!ent->refcnt) continue; 118 if (ent->fShared) { 119 red = ent->co.shco.red->color; 120 green = ent->co.shco.green->color; 121 blue = ent->co.shco.blue->color; 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/* 139 * RootlessStartDrawing 140 * Prepare a window for direct access to its backing buffer. 141 * Each top-level parent has a Pixmap representing its backing buffer, 142 * which all of its children inherit. 143 */ 144void RootlessStartDrawing(WindowPtr pWindow) 145{ 146 ScreenPtr pScreen = pWindow->drawable.pScreen; 147 WindowPtr top = TopLevelParent(pWindow); 148 RootlessWindowRec *winRec; 149 150 if (top == NULL) 151 return; 152 winRec = WINREC(top); 153 if (winRec == NULL) 154 return; 155 156 // Make sure the window's top-level parent is prepared for drawing. 157 if (!winRec->is_drawing) { 158 int bw = wBorderWidth(top); 159 160 SCREENREC(pScreen)->imp->StartDrawing(winRec->wid, &winRec->pixelData, 161 &winRec->bytesPerRow); 162 163 winRec->pixmap = 164 GetScratchPixmapHeader(pScreen, winRec->width, winRec->height, 165 top->drawable.depth, 166 top->drawable.bitsPerPixel, 167 winRec->bytesPerRow, 168 winRec->pixelData); 169 SetPixmapBaseToScreen(winRec->pixmap, 170 top->drawable.x - bw, top->drawable.y - bw); 171 172 winRec->is_drawing = TRUE; 173 } 174 175 PixmapPtr curPixmap = pScreen->GetWindowPixmap(pWindow); 176 if (curPixmap == winRec->pixmap) 177 { 178 RL_DEBUG_MSG("Window %p already has winRec->pixmap %p; not pushing\n", pWindow, winRec->pixmap); 179 } 180 else 181 { 182 PixmapPtr oldPixmap = dixLookupPrivate(&pWindow->devPrivates, rootlessWindowOldPixmapPrivateKey); 183 if (oldPixmap != NULL) 184 { 185 if (oldPixmap == curPixmap) 186 RL_DEBUG_MSG("Window %p's curPixmap %p is the same as its oldPixmap; strange\n", pWindow, curPixmap); 187 else 188 RL_DEBUG_MSG("Window %p's existing oldPixmap %p being lost!\n", pWindow, oldPixmap); 189 } 190 dixSetPrivate(&pWindow->devPrivates, rootlessWindowOldPixmapPrivateKey, curPixmap); 191 pScreen->SetWindowPixmap(pWindow, winRec->pixmap); 192 } 193} 194 195 196/* 197 * RootlessStopDrawing 198 * Stop drawing to a window's backing buffer. If flush is true, 199 * damaged regions are flushed to the screen. 200 */ 201static int RestorePreDrawingPixmapVisitor(WindowPtr pWindow, pointer data) 202{ 203 RootlessWindowRec *winRec = (RootlessWindowRec*)data; 204 ScreenPtr pScreen = pWindow->drawable.pScreen; 205 PixmapPtr exPixmap = pScreen->GetWindowPixmap(pWindow); 206 PixmapPtr oldPixmap = dixLookupPrivate(&pWindow->devPrivates, rootlessWindowOldPixmapPrivateKey); 207 if (oldPixmap == NULL) 208 { 209 if (exPixmap == winRec->pixmap) 210 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); 211 } 212 else 213 { 214 if (exPixmap != winRec->pixmap) 215 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); 216 if (oldPixmap == winRec->pixmap) 217 RL_DEBUG_MSG("Window %p's oldPixmap %p is winRec->pixmap, which has just been freed!\n", pWindow, oldPixmap); 218 pScreen->SetWindowPixmap(pWindow, oldPixmap); 219 dixSetPrivate(&pWindow->devPrivates, rootlessWindowOldPixmapPrivateKey, NULL); 220 } 221 return WT_WALKCHILDREN; 222} 223 224void RootlessStopDrawing(WindowPtr pWindow, Bool flush) 225{ 226 ScreenPtr pScreen = pWindow->drawable.pScreen; 227 WindowPtr top = TopLevelParent(pWindow); 228 RootlessWindowRec *winRec; 229 230 if (top == NULL) 231 return; 232 winRec = WINREC(top); 233 if (winRec == NULL) 234 return; 235 236 if (winRec->is_drawing) { 237 SCREENREC(pScreen)->imp->StopDrawing(winRec->wid, flush); 238 239 FreeScratchPixmapHeader(winRec->pixmap); 240 TraverseTree(top, RestorePreDrawingPixmapVisitor, (pointer)winRec); 241 winRec->pixmap = NULL; 242 243 winRec->is_drawing = FALSE; 244 } 245 else if (flush) { 246 SCREENREC(pScreen)->imp->UpdateRegion(winRec->wid, NULL); 247 } 248 249 if (flush && winRec->is_reorder_pending) { 250 winRec->is_reorder_pending = FALSE; 251 RootlessReorderWindow(pWindow); 252 } 253} 254 255 256/* 257 * RootlessDamageRegion 258 * Mark a damaged region as requiring redisplay to screen. 259 * pRegion is in GLOBAL coordinates. 260 */ 261void 262RootlessDamageRegion(WindowPtr pWindow, RegionPtr pRegion) 263{ 264 ScreenPtr pScreen = pWindow->drawable.pScreen; 265 RootlessWindowRec *winRec; 266 RegionRec clipped; 267 WindowPtr pTop; 268 BoxPtr b1, b2; 269 270 RL_DEBUG_MSG("Damaged win 0x%x ", pWindow); 271 272 pTop = TopLevelParent(pWindow); 273 if (pTop == NULL) 274 return; 275 276 winRec = WINREC(pTop); 277 if (winRec == NULL) 278 return; 279 280 /* We need to intersect the drawn region with the clip of the window 281 to avoid marking places we didn't actually draw (which can cause 282 problems when the window has an extra client-side backing store) 283 284 But this is a costly operation and since we'll normally just be 285 drawing inside the clip, go to some lengths to avoid the general 286 case intersection. */ 287 288 b1 = REGION_EXTENTS(pScreen, &pWindow->borderClip); 289 b2 = REGION_EXTENTS(pScreen, pRegion); 290 291 if (EXTENTCHECK(b1, b2)) { 292 /* Regions may overlap. */ 293 294 if (REGION_NUM_RECTS(pRegion) == 1) { 295 int in; 296 297 /* Damaged region only has a single rect, so we can 298 just compare that against the region */ 299 300 in = RECT_IN_REGION(pScreen, &pWindow->borderClip, 301 REGION_RECTS (pRegion)); 302 if (in == rgnIN) { 303 /* clip totally contains pRegion */ 304 305#ifdef ROOTLESS_TRACK_DAMAGE 306 REGION_UNION(pScreen, &winRec->damage, 307 &winRec->damage, (pRegion)); 308#else 309 SCREENREC(pScreen)->imp->DamageRects(winRec->wid, 310 REGION_NUM_RECTS(pRegion), 311 REGION_RECTS(pRegion), 312 -winRec->x, -winRec->y); 313#endif 314 315 RootlessQueueRedisplay(pTop->drawable.pScreen); 316 goto out; 317 } 318 else if (in == rgnOUT) { 319 /* clip doesn't contain pRegion */ 320 321 goto out; 322 } 323 } 324 325 /* clip overlaps pRegion, need to intersect */ 326 327 REGION_NULL(pScreen, &clipped); 328 REGION_INTERSECT(pScreen, &clipped, &pWindow->borderClip, pRegion); 329 330#ifdef ROOTLESS_TRACK_DAMAGE 331 REGION_UNION(pScreen, &winRec->damage, 332 &winRec->damage, (pRegion)); 333#else 334 SCREENREC(pScreen)->imp->DamageRects(winRec->wid, 335 REGION_NUM_RECTS(&clipped), 336 REGION_RECTS(&clipped), 337 -winRec->x, -winRec->y); 338#endif 339 340 REGION_UNINIT(pScreen, &clipped); 341 342 RootlessQueueRedisplay(pTop->drawable.pScreen); 343 } 344 345out: 346#ifdef ROOTLESSDEBUG 347 { 348 BoxRec *box = REGION_RECTS(pRegion), *end; 349 int numBox = REGION_NUM_RECTS(pRegion); 350 351 for (end = box+numBox; box < end; box++) { 352 RL_DEBUG_MSG("Damage rect: %i, %i, %i, %i\n", 353 box->x1, box->x2, box->y1, box->y2); 354 } 355 } 356#endif 357 return; 358} 359 360 361/* 362 * RootlessDamageBox 363 * Mark a damaged box as requiring redisplay to screen. 364 * pRegion is in GLOBAL coordinates. 365 */ 366void 367RootlessDamageBox(WindowPtr pWindow, BoxPtr pBox) 368{ 369 RegionRec region; 370 371 REGION_INIT(pWindow->drawable.pScreen, ®ion, pBox, 1); 372 373 RootlessDamageRegion(pWindow, ®ion); 374 375 REGION_UNINIT(pWindow->drawable.pScreen, ®ion); /* no-op */ 376} 377 378 379/* 380 * RootlessDamageRect 381 * Mark a damaged rectangle as requiring redisplay to screen. 382 * (x, y, w, h) is in window-local coordinates. 383 */ 384void 385RootlessDamageRect(WindowPtr pWindow, int x, int y, int w, int h) 386{ 387 BoxRec box; 388 RegionRec region; 389 390 x += pWindow->drawable.x; 391 y += pWindow->drawable.y; 392 393 box.x1 = x; 394 box.x2 = x + w; 395 box.y1 = y; 396 box.y2 = y + h; 397 398 REGION_INIT(pWindow->drawable.pScreen, ®ion, &box, 1); 399 400 RootlessDamageRegion(pWindow, ®ion); 401 402 REGION_UNINIT(pWindow->drawable.pScreen, ®ion); /* no-op */ 403} 404 405 406/* 407 * RootlessRedisplay 408 * Stop drawing and redisplay the damaged region of a window. 409 */ 410void 411RootlessRedisplay(WindowPtr pWindow) 412{ 413#ifdef ROOTLESS_TRACK_DAMAGE 414 415 RootlessWindowRec *winRec = WINREC(pWindow); 416 ScreenPtr pScreen = pWindow->drawable.pScreen; 417 418 RootlessStopDrawing(pWindow, FALSE); 419 420 if (REGION_NOTEMPTY(pScreen, &winRec->damage)) { 421 RL_DEBUG_MSG("Redisplay Win 0x%x, %i x %i @ (%i, %i)\n", 422 pWindow, winRec->width, winRec->height, 423 winRec->x, winRec->y); 424 425 // move region to window local coords 426 REGION_TRANSLATE(pScreen, &winRec->damage, 427 -winRec->x, -winRec->y); 428 429 SCREENREC(pScreen)->imp->UpdateRegion(winRec->wid, &winRec->damage); 430 431 REGION_EMPTY(pScreen, &winRec->damage); 432 } 433 434#else /* !ROOTLESS_TRACK_DAMAGE */ 435 436 RootlessStopDrawing(pWindow, TRUE); 437 438#endif 439} 440 441 442/* 443 * RootlessRepositionWindows 444 * Reposition all windows on a screen to their correct positions. 445 */ 446void 447RootlessRepositionWindows(ScreenPtr pScreen) 448{ 449 WindowPtr root = WindowTable[pScreen->myNum]; 450 WindowPtr win; 451 452 if (root != NULL) { 453 RootlessRepositionWindow(root); 454 455 for (win = root->firstChild; win; win = win->nextSib) { 456 if (WINREC(win) != NULL) 457 RootlessRepositionWindow(win); 458 } 459 } 460} 461 462 463/* 464 * RootlessRedisplayScreen 465 * Walk every window on a screen and redisplay the damaged regions. 466 */ 467void 468RootlessRedisplayScreen(ScreenPtr pScreen) 469{ 470 WindowPtr root = WindowTable[pScreen->myNum]; 471 472 if (root != NULL) { 473 WindowPtr win; 474 475 RootlessRedisplay(root); 476 for (win = root->firstChild; win; win = win->nextSib) { 477 if (WINREC(win) != NULL) { 478 RootlessRedisplay(win); 479 } 480 } 481 } 482} 483