Imported Upstream version 1.15.1
[deb_xorg-server.git] / miext / rootless / rootlessCommon.c
CommitLineData
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
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, 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
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, (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 */
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(&region, pBox, 1);
379
380 RootlessDamageRegion(pWindow, &region);
381
382 RegionUninit(&region); /* 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(&region, &box, 1);
405
406 RootlessDamageRegion(pWindow, &region);
407
408 RegionUninit(&region); /* 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}