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