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/* 60 * TopLevelParent 61 * Returns the top-level parent of pWindow. 62 * The root is the top-level parent of itself, even though the root is 63 * not otherwise considered to be a top-level window. 64 */ 65WindowPtr 66TopLevelParent(WindowPtr pWindow) 67{ 68 WindowPtr top; 69 70 if (IsRoot(pWindow)) 71 return pWindow; 72 73 top = pWindow; 74 while (top && ! IsTopLevel(top)) 75 top = top->parent; 76 77 return top; 78} 79 80 81/* 82 * IsFramedWindow 83 * Returns TRUE if this window is visible inside a frame 84 * (e.g. it is visible and has a top-level or root parent) 85 */ 86Bool 87IsFramedWindow(WindowPtr pWin) 88{ 89 WindowPtr top; 90 91 if (!dixPrivateKeyRegistered(&rootlessWindowPrivateKeyRec)) 92 return FALSE; 93 94 if (!pWin->realized) 95 return FALSE; 96 top = TopLevelParent(pWin); 97 98 return (top && WINREC(top)); 99} 100 101Bool 102RootlessResolveColormap (ScreenPtr pScreen, int first_color, 103 int n_colors, uint32_t *colors) 104{ 105 int last, i; 106 ColormapPtr map; 107 108 map = RootlessGetColormap (pScreen); 109 if (map == NULL || map->class != PseudoColor) return FALSE; 110 111 last = min (map->pVisual->ColormapEntries, first_color + n_colors); 112 for (i = max (0, first_color); i < last; i++) { 113 Entry *ent = map->red + i; 114 uint16_t red, green, blue; 115 116 if (!ent->refcnt) 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 } else { 122 red = ent->co.local.red; 123 green = ent->co.local.green; 124 blue = ent->co.local.blue; 125 } 126 127 colors[i - first_color] = (0xFF000000UL 128 | ((uint32_t) red & 0xff00) << 8 129 | (green & 0xff00) 130 | (blue >> 8)); 131 } 132 133 return TRUE; 134} 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 RootlessStartDrawing(WindowPtr pWindow) 144{ 145 ScreenPtr pScreen = pWindow->drawable.pScreen; 146 WindowPtr top = TopLevelParent(pWindow); 147 RootlessWindowRec *winRec; 148 PixmapPtr curPixmap; 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 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 RootlessWindowRec *winRec; 265 RegionRec clipped; 266 WindowPtr pTop; 267 BoxPtr b1, b2; 268 269 RL_DEBUG_MSG("Damaged win 0x%x ", pWindow); 270 271 pTop = TopLevelParent(pWindow); 272 if (pTop == NULL) 273 return; 274 275 winRec = WINREC(pTop); 276 if (winRec == NULL) 277 return; 278 279 /* We need to intersect the drawn region with the clip of the window 280 to avoid marking places we didn't actually draw (which can cause 281 problems when the window has an extra client-side backing store) 282 283 But this is a costly operation and since we'll normally just be 284 drawing inside the clip, go to some lengths to avoid the general 285 case intersection. */ 286 287 b1 = RegionExtents(&pWindow->borderClip); 288 b2 = RegionExtents(pRegion); 289 290 if (EXTENTCHECK(b1, b2)) { 291 /* Regions may overlap. */ 292 293 if (RegionNumRects(pRegion) == 1) { 294 int in; 295 296 /* Damaged region only has a single rect, so we can 297 just compare that against the region */ 298 299 in = RegionContainsRect(&pWindow->borderClip, 300 RegionRects (pRegion)); 301 if (in == rgnIN) { 302 /* clip totally contains pRegion */ 303 304 SCREENREC(pWindow->drawable.pScreen)->imp-> 305 DamageRects(winRec->wid, 306 RegionNumRects(pRegion), 307 RegionRects(pRegion), 308 -winRec->x, -winRec->y); 309 310 RootlessQueueRedisplay(pTop->drawable.pScreen); 311 goto out; 312 } 313 else if (in == rgnOUT) { 314 /* clip doesn't contain pRegion */ 315 316 goto out; 317 } 318 } 319 320 /* clip overlaps pRegion, need to intersect */ 321 322 RegionNull(&clipped); 323 RegionIntersect(&clipped, &pWindow->borderClip, pRegion); 324 325 SCREENREC(pWindow->drawable.pScreen)->imp-> 326 DamageRects(winRec->wid, 327 RegionNumRects(&clipped), 328 RegionRects(&clipped), 329 -winRec->x, -winRec->y); 330 331 RegionUninit(&clipped); 332 333 RootlessQueueRedisplay(pTop->drawable.pScreen); 334 } 335 336out: 337#ifdef ROOTLESSDEBUG 338 { 339 BoxRec *box = RegionRects(pRegion), *end; 340 int numBox = RegionNumRects(pRegion); 341 342 for (end = box+numBox; box < end; box++) { 343 RL_DEBUG_MSG("Damage rect: %i, %i, %i, %i\n", 344 box->x1, box->x2, box->y1, box->y2); 345 } 346 } 347#endif 348 return; 349} 350 351 352/* 353 * RootlessDamageBox 354 * Mark a damaged box as requiring redisplay to screen. 355 * pRegion is in GLOBAL coordinates. 356 */ 357void 358RootlessDamageBox(WindowPtr pWindow, BoxPtr pBox) 359{ 360 RegionRec region; 361 362 RegionInit(®ion, pBox, 1); 363 364 RootlessDamageRegion(pWindow, ®ion); 365 366 RegionUninit(®ion); /* no-op */ 367} 368 369 370/* 371 * RootlessDamageRect 372 * Mark a damaged rectangle as requiring redisplay to screen. 373 * (x, y, w, h) is in window-local coordinates. 374 */ 375void 376RootlessDamageRect(WindowPtr pWindow, int x, int y, int w, int h) 377{ 378 BoxRec box; 379 RegionRec region; 380 381 x += pWindow->drawable.x; 382 y += pWindow->drawable.y; 383 384 box.x1 = x; 385 box.x2 = x + w; 386 box.y1 = y; 387 box.y2 = y + h; 388 389 RegionInit(®ion, &box, 1); 390 391 RootlessDamageRegion(pWindow, ®ion); 392 393 RegionUninit(®ion); /* no-op */ 394} 395 396 397/* 398 * RootlessRedisplay 399 * Stop drawing and redisplay the damaged region of a window. 400 */ 401void 402RootlessRedisplay(WindowPtr pWindow) 403{ 404 RootlessStopDrawing(pWindow, TRUE); 405} 406 407 408/* 409 * RootlessRepositionWindows 410 * Reposition all windows on a screen to their correct positions. 411 */ 412void 413RootlessRepositionWindows(ScreenPtr pScreen) 414{ 415 WindowPtr root = pScreen->root; 416 WindowPtr win; 417 418 if (root != NULL) { 419 RootlessRepositionWindow(root); 420 421 for (win = root->firstChild; win; win = win->nextSib) { 422 if (WINREC(win) != NULL) 423 RootlessRepositionWindow(win); 424 } 425 } 426} 427 428 429/* 430 * RootlessRedisplayScreen 431 * Walk every window on a screen and redisplay the damaged regions. 432 */ 433void 434RootlessRedisplayScreen(ScreenPtr pScreen) 435{ 436 WindowPtr root = pScreen->root; 437 438 if (root != NULL) { 439 WindowPtr win; 440 441 RootlessRedisplay(root); 442 for (win = root->firstChild; win; win = win->nextSib) { 443 if (WINREC(win) != NULL) { 444 RootlessRedisplay(win); 445 } 446 } 447 } 448} 449