Commit | Line | Data |
---|---|---|
a09e091a JB |
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 | ||
42 | unsigned int rootless_CopyBytes_threshold = 0; | |
43 | unsigned int rootless_CopyWindow_threshold = 0; | |
44 | int rootlessGlobalOffsetX = 0; | |
45 | int rootlessGlobalOffsetY = 0; | |
46 | ||
47 | RegionRec 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 | */ | |
64 | WindowPtr | |
65 | TopLevelParent(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 | */ | |
84 | Bool | |
85 | IsFramedWindow(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 | ||
99 | Bool | |
100 | RootlessResolveColormap(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 | */ | |
143 | void | |
144 | RootlessStartDrawing(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 | */ | |
204 | static int | |
205 | RestorePreDrawingPixmapVisitor(WindowPtr pWindow, pointer 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 | ||
235 | void | |
236 | RootlessStopDrawing(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, (pointer) 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 | */ | |
272 | void | |
273 | RootlessDamageRegion(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 | */ | |
373 | void | |
374 | RootlessDamageBox(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 | */ | |
390 | void | |
391 | RootlessDamageRect(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 | */ | |
415 | void | |
416 | RootlessRedisplay(WindowPtr pWindow) | |
417 | { | |
418 | RootlessStopDrawing(pWindow, TRUE); | |
419 | } | |
420 | ||
421 | /* | |
422 | * RootlessRepositionWindows | |
423 | * Reposition all windows on a screen to their correct positions. | |
424 | */ | |
425 | void | |
426 | RootlessRepositionWindows(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 | */ | |
445 | void | |
446 | RootlessRedisplayScreen(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 | } |