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
TopLevelParent(WindowPtr pWindow)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
IsFramedWindow(WindowPtr pWin)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
RootlessResolveColormap(ScreenPtr pScreen,int first_color,int n_colors,uint32_t * colors)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
RootlessStartDrawing(WindowPtr pWindow)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
RestorePreDrawingPixmapVisitor(WindowPtr pWindow,void * data)205 RestorePreDrawingPixmapVisitor(WindowPtr pWindow, void *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
RootlessStopDrawing(WindowPtr pWindow,Bool flush)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, (void *) 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
RootlessDamageRegion(WindowPtr pWindow,RegionPtr pRegion)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
RootlessDamageBox(WindowPtr pWindow,BoxPtr pBox)374 RootlessDamageBox(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  */
390 void
RootlessDamageRect(WindowPtr pWindow,int x,int y,int w,int h)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(&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  */
415 void
RootlessRedisplay(WindowPtr pWindow)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
RootlessRepositionWindows(ScreenPtr pScreen)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
RootlessRedisplayScreen(ScreenPtr pScreen)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 }
461