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, &region, pBox, 1);
297
298    RootlessDamageRegion(pWindow, &region);
299
300    REGION_UNINIT(pWindow->drawable.pScreen, &region);  /* 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, &region, &box, 1);
324
325    RootlessDamageRegion(pWindow, &region);
326
327    REGION_UNINIT(pWindow->drawable.pScreen, &region);  /* 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