1706f2543Smrg/*
2706f2543Smrg * Common rootless definitions and code
3706f2543Smrg */
4706f2543Smrg/*
5706f2543Smrg * Copyright (c) 2001 Greg Parker. All Rights Reserved.
6706f2543Smrg * Copyright (c) 2002-2003 Torrey T. Lyons. All Rights Reserved.
7706f2543Smrg * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
8706f2543Smrg *
9706f2543Smrg * Permission is hereby granted, free of charge, to any person obtaining a
10706f2543Smrg * copy of this software and associated documentation files (the "Software"),
11706f2543Smrg * to deal in the Software without restriction, including without limitation
12706f2543Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13706f2543Smrg * and/or sell copies of the Software, and to permit persons to whom the
14706f2543Smrg * Software is furnished to do so, subject to the following conditions:
15706f2543Smrg *
16706f2543Smrg * The above copyright notice and this permission notice shall be included in
17706f2543Smrg * all copies or substantial portions of the Software.
18706f2543Smrg *
19706f2543Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20706f2543Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21706f2543Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22706f2543Smrg * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
23706f2543Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24706f2543Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25706f2543Smrg * DEALINGS IN THE SOFTWARE.
26706f2543Smrg *
27706f2543Smrg * Except as contained in this notice, the name(s) of the above copyright
28706f2543Smrg * holders shall not be used in advertising or otherwise to promote the sale,
29706f2543Smrg * use or other dealings in this Software without prior written authorization.
30706f2543Smrg */
31706f2543Smrg
32706f2543Smrg#ifdef HAVE_DIX_CONFIG_H
33706f2543Smrg#include <dix-config.h>
34706f2543Smrg#endif
35706f2543Smrg
36706f2543Smrg#include <stddef.h> /* For NULL */
37706f2543Smrg#include <limits.h> /* For CHAR_BIT */
38706f2543Smrg
39706f2543Smrg#include "rootlessCommon.h"
40706f2543Smrg#include "colormapst.h"
41706f2543Smrg
42706f2543Smrgunsigned int rootless_CopyBytes_threshold = 0;
43706f2543Smrgunsigned int rootless_CopyWindow_threshold = 0;
44706f2543Smrgint rootlessGlobalOffsetX = 0;
45706f2543Smrgint rootlessGlobalOffsetY = 0;
46706f2543Smrg
47706f2543SmrgRegionRec rootlessHugeRoot = {{-32767, -32767, 32767, 32767}, NULL};
48706f2543Smrg
49706f2543Smrg/* Following macro from miregion.c */
50706f2543Smrg
51706f2543Smrg/*  true iff two Boxes overlap */
52706f2543Smrg#define EXTENTCHECK(r1,r2) \
53706f2543Smrg      (!( ((r1)->x2 <= (r2)->x1)  || \
54706f2543Smrg          ((r1)->x1 >= (r2)->x2)  || \
55706f2543Smrg          ((r1)->y2 <= (r2)->y1)  || \
56706f2543Smrg          ((r1)->y1 >= (r2)->y2) ) )
57706f2543Smrg
58706f2543Smrg
59706f2543Smrg/*
60706f2543Smrg * TopLevelParent
61706f2543Smrg *  Returns the top-level parent of pWindow.
62706f2543Smrg *  The root is the top-level parent of itself, even though the root is
63706f2543Smrg *  not otherwise considered to be a top-level window.
64706f2543Smrg */
65706f2543SmrgWindowPtr
66706f2543SmrgTopLevelParent(WindowPtr pWindow)
67706f2543Smrg{
68706f2543Smrg    WindowPtr top;
69706f2543Smrg
70706f2543Smrg    if (IsRoot(pWindow))
71706f2543Smrg        return pWindow;
72706f2543Smrg
73706f2543Smrg    top = pWindow;
74706f2543Smrg    while (top && ! IsTopLevel(top))
75706f2543Smrg        top = top->parent;
76706f2543Smrg
77706f2543Smrg    return top;
78706f2543Smrg}
79706f2543Smrg
80706f2543Smrg
81706f2543Smrg/*
82706f2543Smrg * IsFramedWindow
83706f2543Smrg *  Returns TRUE if this window is visible inside a frame
84706f2543Smrg *  (e.g. it is visible and has a top-level or root parent)
85706f2543Smrg */
86706f2543SmrgBool
87706f2543SmrgIsFramedWindow(WindowPtr pWin)
88706f2543Smrg{
89706f2543Smrg    WindowPtr top;
90706f2543Smrg
91706f2543Smrg    if (!dixPrivateKeyRegistered(&rootlessWindowPrivateKeyRec))
92706f2543Smrg        return FALSE;
93706f2543Smrg
94706f2543Smrg    if (!pWin->realized)
95706f2543Smrg        return FALSE;
96706f2543Smrg    top = TopLevelParent(pWin);
97706f2543Smrg
98706f2543Smrg    return (top && WINREC(top));
99706f2543Smrg}
100706f2543Smrg
101706f2543SmrgBool
102706f2543SmrgRootlessResolveColormap (ScreenPtr pScreen, int first_color,
103706f2543Smrg                         int n_colors, uint32_t *colors)
104706f2543Smrg{
105706f2543Smrg  int last, i;
106706f2543Smrg  ColormapPtr map;
107706f2543Smrg
108706f2543Smrg  map = RootlessGetColormap (pScreen);
109706f2543Smrg  if (map == NULL || map->class != PseudoColor) return FALSE;
110706f2543Smrg
111706f2543Smrg  last = min (map->pVisual->ColormapEntries, first_color + n_colors);
112706f2543Smrg  for (i = max (0, first_color); i < last; i++) {
113706f2543Smrg    Entry *ent = map->red + i;
114706f2543Smrg    uint16_t red, green, blue;
115706f2543Smrg
116706f2543Smrg      if (!ent->refcnt)	continue;
117706f2543Smrg      if (ent->fShared) {
118706f2543Smrg	red = ent->co.shco.red->color;
119706f2543Smrg	green = ent->co.shco.green->color;
120706f2543Smrg	blue = ent->co.shco.blue->color;
121706f2543Smrg      } else {
122706f2543Smrg	red = ent->co.local.red;
123706f2543Smrg	green = ent->co.local.green;
124706f2543Smrg	blue = ent->co.local.blue;
125706f2543Smrg      }
126706f2543Smrg
127706f2543Smrg      colors[i - first_color] = (0xFF000000UL
128706f2543Smrg				 | ((uint32_t) red & 0xff00) << 8
129706f2543Smrg				 | (green & 0xff00)
130706f2543Smrg				 | (blue >> 8));
131706f2543Smrg    }
132706f2543Smrg
133706f2543Smrg  return TRUE;
134706f2543Smrg}
135706f2543Smrg
136706f2543Smrg
137706f2543Smrg/*
138706f2543Smrg * RootlessStartDrawing
139706f2543Smrg *  Prepare a window for direct access to its backing buffer.
140706f2543Smrg *  Each top-level parent has a Pixmap representing its backing buffer,
141706f2543Smrg *  which all of its children inherit.
142706f2543Smrg */
143706f2543Smrgvoid RootlessStartDrawing(WindowPtr pWindow)
144706f2543Smrg{
145706f2543Smrg    ScreenPtr pScreen = pWindow->drawable.pScreen;
146706f2543Smrg    WindowPtr top = TopLevelParent(pWindow);
147706f2543Smrg    RootlessWindowRec *winRec;
148706f2543Smrg    PixmapPtr curPixmap;
149706f2543Smrg
150706f2543Smrg    if (top == NULL)
151706f2543Smrg        return;
152706f2543Smrg    winRec = WINREC(top);
153706f2543Smrg    if (winRec == NULL)
154706f2543Smrg        return;
155706f2543Smrg
156706f2543Smrg    // Make sure the window's top-level parent is prepared for drawing.
157706f2543Smrg    if (!winRec->is_drawing) {
158706f2543Smrg        int bw = wBorderWidth(top);
159706f2543Smrg
160706f2543Smrg        SCREENREC(pScreen)->imp->StartDrawing(winRec->wid, &winRec->pixelData,
161706f2543Smrg                                              &winRec->bytesPerRow);
162706f2543Smrg
163706f2543Smrg        winRec->pixmap =
164706f2543Smrg            GetScratchPixmapHeader(pScreen, winRec->width, winRec->height,
165706f2543Smrg                                   top->drawable.depth,
166706f2543Smrg                                   top->drawable.bitsPerPixel,
167706f2543Smrg                                   winRec->bytesPerRow,
168706f2543Smrg                                   winRec->pixelData);
169706f2543Smrg        SetPixmapBaseToScreen(winRec->pixmap,
170706f2543Smrg                              top->drawable.x - bw, top->drawable.y - bw);
171706f2543Smrg
172706f2543Smrg        winRec->is_drawing = TRUE;
173706f2543Smrg    }
174706f2543Smrg
175706f2543Smrg    curPixmap = pScreen->GetWindowPixmap(pWindow);
176706f2543Smrg    if (curPixmap == winRec->pixmap)
177706f2543Smrg    {
178706f2543Smrg        RL_DEBUG_MSG("Window %p already has winRec->pixmap %p; not pushing\n", pWindow, winRec->pixmap);
179706f2543Smrg    }
180706f2543Smrg    else
181706f2543Smrg    {
182706f2543Smrg        PixmapPtr oldPixmap = dixLookupPrivate(&pWindow->devPrivates, rootlessWindowOldPixmapPrivateKey);
183706f2543Smrg        if (oldPixmap != NULL)
184706f2543Smrg        {
185706f2543Smrg            if (oldPixmap == curPixmap)
186706f2543Smrg                RL_DEBUG_MSG("Window %p's curPixmap %p is the same as its oldPixmap; strange\n", pWindow, curPixmap);
187706f2543Smrg            else
188706f2543Smrg                RL_DEBUG_MSG("Window %p's existing oldPixmap %p being lost!\n", pWindow, oldPixmap);
189706f2543Smrg        }
190706f2543Smrg	dixSetPrivate(&pWindow->devPrivates, rootlessWindowOldPixmapPrivateKey, curPixmap);
191706f2543Smrg        pScreen->SetWindowPixmap(pWindow, winRec->pixmap);
192706f2543Smrg    }
193706f2543Smrg}
194706f2543Smrg
195706f2543Smrg
196706f2543Smrg/*
197706f2543Smrg * RootlessStopDrawing
198706f2543Smrg *  Stop drawing to a window's backing buffer. If flush is true,
199706f2543Smrg *  damaged regions are flushed to the screen.
200706f2543Smrg */
201706f2543Smrgstatic int RestorePreDrawingPixmapVisitor(WindowPtr pWindow, pointer data)
202706f2543Smrg{
203706f2543Smrg    RootlessWindowRec *winRec = (RootlessWindowRec*)data;
204706f2543Smrg    ScreenPtr pScreen = pWindow->drawable.pScreen;
205706f2543Smrg    PixmapPtr exPixmap = pScreen->GetWindowPixmap(pWindow);
206706f2543Smrg    PixmapPtr oldPixmap = dixLookupPrivate(&pWindow->devPrivates, rootlessWindowOldPixmapPrivateKey);
207706f2543Smrg    if (oldPixmap == NULL)
208706f2543Smrg    {
209706f2543Smrg        if (exPixmap == winRec->pixmap)
210706f2543Smrg            RL_DEBUG_MSG("Window %p appears to be in drawing mode (ex-pixmap %p equals winRec->pixmap, which is being freed) but has no oldPixmap!\n", pWindow, exPixmap);
211706f2543Smrg    }
212706f2543Smrg    else
213706f2543Smrg    {
214706f2543Smrg        if (exPixmap != winRec->pixmap)
215706f2543Smrg            RL_DEBUG_MSG("Window %p appears to be in drawing mode (oldPixmap %p) but ex-pixmap %p not winRec->pixmap %p!\n", pWindow, oldPixmap, exPixmap, winRec->pixmap);
216706f2543Smrg        if (oldPixmap == winRec->pixmap)
217706f2543Smrg            RL_DEBUG_MSG("Window %p's oldPixmap %p is winRec->pixmap, which has just been freed!\n", pWindow, oldPixmap);
218706f2543Smrg        pScreen->SetWindowPixmap(pWindow, oldPixmap);
219706f2543Smrg        dixSetPrivate(&pWindow->devPrivates, rootlessWindowOldPixmapPrivateKey, NULL);
220706f2543Smrg    }
221706f2543Smrg    return WT_WALKCHILDREN;
222706f2543Smrg}
223706f2543Smrg
224706f2543Smrgvoid RootlessStopDrawing(WindowPtr pWindow, Bool flush)
225706f2543Smrg{
226706f2543Smrg    ScreenPtr pScreen = pWindow->drawable.pScreen;
227706f2543Smrg    WindowPtr top = TopLevelParent(pWindow);
228706f2543Smrg    RootlessWindowRec *winRec;
229706f2543Smrg
230706f2543Smrg    if (top == NULL)
231706f2543Smrg        return;
232706f2543Smrg    winRec = WINREC(top);
233706f2543Smrg    if (winRec == NULL)
234706f2543Smrg        return;
235706f2543Smrg
236706f2543Smrg    if (winRec->is_drawing) {
237706f2543Smrg        SCREENREC(pScreen)->imp->StopDrawing(winRec->wid, flush);
238706f2543Smrg
239706f2543Smrg        FreeScratchPixmapHeader(winRec->pixmap);
240706f2543Smrg        TraverseTree(top, RestorePreDrawingPixmapVisitor, (pointer)winRec);
241706f2543Smrg        winRec->pixmap = NULL;
242706f2543Smrg
243706f2543Smrg        winRec->is_drawing = FALSE;
244706f2543Smrg    }
245706f2543Smrg    else if (flush) {
246706f2543Smrg        SCREENREC(pScreen)->imp->UpdateRegion(winRec->wid, NULL);
247706f2543Smrg    }
248706f2543Smrg
249706f2543Smrg    if (flush && winRec->is_reorder_pending) {
250706f2543Smrg        winRec->is_reorder_pending = FALSE;
251706f2543Smrg        RootlessReorderWindow(pWindow);
252706f2543Smrg    }
253706f2543Smrg}
254706f2543Smrg
255706f2543Smrg
256706f2543Smrg/*
257706f2543Smrg * RootlessDamageRegion
258706f2543Smrg *  Mark a damaged region as requiring redisplay to screen.
259706f2543Smrg *  pRegion is in GLOBAL coordinates.
260706f2543Smrg */
261706f2543Smrgvoid
262706f2543SmrgRootlessDamageRegion(WindowPtr pWindow, RegionPtr pRegion)
263706f2543Smrg{
264706f2543Smrg    RootlessWindowRec *winRec;
265706f2543Smrg    RegionRec clipped;
266706f2543Smrg    WindowPtr pTop;
267706f2543Smrg    BoxPtr b1, b2;
268706f2543Smrg
269706f2543Smrg    RL_DEBUG_MSG("Damaged win 0x%x ", pWindow);
270706f2543Smrg
271706f2543Smrg    pTop = TopLevelParent(pWindow);
272706f2543Smrg    if (pTop == NULL)
273706f2543Smrg        return;
274706f2543Smrg
275706f2543Smrg    winRec = WINREC(pTop);
276706f2543Smrg    if (winRec == NULL)
277706f2543Smrg        return;
278706f2543Smrg
279706f2543Smrg    /* We need to intersect the drawn region with the clip of the window
280706f2543Smrg       to avoid marking places we didn't actually draw (which can cause
281706f2543Smrg       problems when the window has an extra client-side backing store)
282706f2543Smrg
283706f2543Smrg       But this is a costly operation and since we'll normally just be
284706f2543Smrg       drawing inside the clip, go to some lengths to avoid the general
285706f2543Smrg       case intersection. */
286706f2543Smrg
287706f2543Smrg    b1 = RegionExtents(&pWindow->borderClip);
288706f2543Smrg    b2 = RegionExtents(pRegion);
289706f2543Smrg
290706f2543Smrg    if (EXTENTCHECK(b1, b2)) {
291706f2543Smrg        /* Regions may overlap. */
292706f2543Smrg
293706f2543Smrg        if (RegionNumRects(pRegion) == 1) {
294706f2543Smrg            int in;
295706f2543Smrg
296706f2543Smrg            /* Damaged region only has a single rect, so we can
297706f2543Smrg               just compare that against the region */
298706f2543Smrg
299706f2543Smrg            in = RegionContainsRect(&pWindow->borderClip,
300706f2543Smrg                                RegionRects (pRegion));
301706f2543Smrg            if (in == rgnIN) {
302706f2543Smrg            /* clip totally contains pRegion */
303706f2543Smrg
304706f2543Smrg                SCREENREC(pWindow->drawable.pScreen)->imp->
305706f2543Smrg                    DamageRects(winRec->wid,
306706f2543Smrg                                RegionNumRects(pRegion),
307706f2543Smrg                                RegionRects(pRegion),
308706f2543Smrg                                -winRec->x, -winRec->y);
309706f2543Smrg
310706f2543Smrg                RootlessQueueRedisplay(pTop->drawable.pScreen);
311706f2543Smrg                goto out;
312706f2543Smrg            }
313706f2543Smrg            else if (in == rgnOUT) {
314706f2543Smrg                /* clip doesn't contain pRegion */
315706f2543Smrg
316706f2543Smrg                goto out;
317706f2543Smrg            }
318706f2543Smrg        }
319706f2543Smrg
320706f2543Smrg        /* clip overlaps pRegion, need to intersect */
321706f2543Smrg
322706f2543Smrg        RegionNull(&clipped);
323706f2543Smrg        RegionIntersect(&clipped, &pWindow->borderClip, pRegion);
324706f2543Smrg
325706f2543Smrg        SCREENREC(pWindow->drawable.pScreen)->imp->
326706f2543Smrg            DamageRects(winRec->wid,
327706f2543Smrg                        RegionNumRects(&clipped),
328706f2543Smrg                        RegionRects(&clipped),
329706f2543Smrg                        -winRec->x, -winRec->y);
330706f2543Smrg
331706f2543Smrg        RegionUninit(&clipped);
332706f2543Smrg
333706f2543Smrg        RootlessQueueRedisplay(pTop->drawable.pScreen);
334706f2543Smrg    }
335706f2543Smrg
336706f2543Smrgout:
337706f2543Smrg#ifdef ROOTLESSDEBUG
338706f2543Smrg    {
339706f2543Smrg        BoxRec *box = RegionRects(pRegion), *end;
340706f2543Smrg        int numBox = RegionNumRects(pRegion);
341706f2543Smrg
342706f2543Smrg        for (end = box+numBox; box < end; box++) {
343706f2543Smrg            RL_DEBUG_MSG("Damage rect: %i, %i, %i, %i\n",
344706f2543Smrg                         box->x1, box->x2, box->y1, box->y2);
345706f2543Smrg        }
346706f2543Smrg    }
347706f2543Smrg#endif
348706f2543Smrg    return;
349706f2543Smrg}
350706f2543Smrg
351706f2543Smrg
352706f2543Smrg/*
353706f2543Smrg * RootlessDamageBox
354706f2543Smrg *  Mark a damaged box as requiring redisplay to screen.
355706f2543Smrg *  pRegion is in GLOBAL coordinates.
356706f2543Smrg */
357706f2543Smrgvoid
358706f2543SmrgRootlessDamageBox(WindowPtr pWindow, BoxPtr pBox)
359706f2543Smrg{
360706f2543Smrg    RegionRec region;
361706f2543Smrg
362706f2543Smrg    RegionInit(&region, pBox, 1);
363706f2543Smrg
364706f2543Smrg    RootlessDamageRegion(pWindow, &region);
365706f2543Smrg
366706f2543Smrg    RegionUninit(&region);  /* no-op */
367706f2543Smrg}
368706f2543Smrg
369706f2543Smrg
370706f2543Smrg/*
371706f2543Smrg * RootlessDamageRect
372706f2543Smrg *  Mark a damaged rectangle as requiring redisplay to screen.
373706f2543Smrg *  (x, y, w, h) is in window-local coordinates.
374706f2543Smrg */
375706f2543Smrgvoid
376706f2543SmrgRootlessDamageRect(WindowPtr pWindow, int x, int y, int w, int h)
377706f2543Smrg{
378706f2543Smrg    BoxRec box;
379706f2543Smrg    RegionRec region;
380706f2543Smrg
381706f2543Smrg    x += pWindow->drawable.x;
382706f2543Smrg    y += pWindow->drawable.y;
383706f2543Smrg
384706f2543Smrg    box.x1 = x;
385706f2543Smrg    box.x2 = x + w;
386706f2543Smrg    box.y1 = y;
387706f2543Smrg    box.y2 = y + h;
388706f2543Smrg
389706f2543Smrg    RegionInit(&region, &box, 1);
390706f2543Smrg
391706f2543Smrg    RootlessDamageRegion(pWindow, &region);
392706f2543Smrg
393706f2543Smrg    RegionUninit(&region);  /* no-op */
394706f2543Smrg}
395706f2543Smrg
396706f2543Smrg
397706f2543Smrg/*
398706f2543Smrg * RootlessRedisplay
399706f2543Smrg *  Stop drawing and redisplay the damaged region of a window.
400706f2543Smrg */
401706f2543Smrgvoid
402706f2543SmrgRootlessRedisplay(WindowPtr pWindow)
403706f2543Smrg{
404706f2543Smrg    RootlessStopDrawing(pWindow, TRUE);
405706f2543Smrg}
406706f2543Smrg
407706f2543Smrg
408706f2543Smrg/*
409706f2543Smrg * RootlessRepositionWindows
410706f2543Smrg *  Reposition all windows on a screen to their correct positions.
411706f2543Smrg */
412706f2543Smrgvoid
413706f2543SmrgRootlessRepositionWindows(ScreenPtr pScreen)
414706f2543Smrg{
415706f2543Smrg    WindowPtr root = pScreen->root;
416706f2543Smrg    WindowPtr win;
417706f2543Smrg
418706f2543Smrg    if (root != NULL) {
419706f2543Smrg        RootlessRepositionWindow(root);
420706f2543Smrg
421706f2543Smrg        for (win = root->firstChild; win; win = win->nextSib) {
422706f2543Smrg            if (WINREC(win) != NULL)
423706f2543Smrg                RootlessRepositionWindow(win);
424706f2543Smrg        }
425706f2543Smrg    }
426706f2543Smrg}
427706f2543Smrg
428706f2543Smrg
429706f2543Smrg/*
430706f2543Smrg * RootlessRedisplayScreen
431706f2543Smrg *  Walk every window on a screen and redisplay the damaged regions.
432706f2543Smrg */
433706f2543Smrgvoid
434706f2543SmrgRootlessRedisplayScreen(ScreenPtr pScreen)
435706f2543Smrg{
436706f2543Smrg    WindowPtr root = pScreen->root;
437706f2543Smrg
438706f2543Smrg    if (root != NULL) {
439706f2543Smrg        WindowPtr win;
440706f2543Smrg
441706f2543Smrg        RootlessRedisplay(root);
442706f2543Smrg        for (win = root->firstChild; win; win = win->nextSib) {
443706f2543Smrg            if (WINREC(win) != NULL) {
444706f2543Smrg                RootlessRedisplay(win);
445706f2543Smrg            }
446706f2543Smrg        }
447706f2543Smrg    }
448706f2543Smrg}
449