1
2#ifdef HAVE_DIX_CONFIG_H
3#include <dix-config.h>
4#endif
5
6#include <X11/X.h>
7#include "scrnintstr.h"
8#include <X11/extensions/shapeproto.h>
9#include "validate.h"
10#include "windowstr.h"
11#include "mi.h"
12#include "gcstruct.h"
13#include "regionstr.h"
14#include "privates.h"
15#include "mivalidate.h"
16#include "mioverlay.h"
17#include "migc.h"
18
19#include "globals.h"
20
21typedef struct {
22    RegionRec exposed;
23    RegionRec borderExposed;
24    RegionPtr borderVisible;
25    DDXPointRec oldAbsCorner;
26} miOverlayValDataRec, *miOverlayValDataPtr;
27
28typedef struct _TreeRec {
29    WindowPtr pWin;
30    struct _TreeRec *parent;
31    struct _TreeRec *firstChild;
32    struct _TreeRec *lastChild;
33    struct _TreeRec *prevSib;
34    struct _TreeRec *nextSib;
35    RegionRec borderClip;
36    RegionRec clipList;
37    unsigned visibility;
38    miOverlayValDataPtr valdata;
39} miOverlayTreeRec, *miOverlayTreePtr;
40
41typedef struct {
42    miOverlayTreePtr tree;
43} miOverlayWindowRec, *miOverlayWindowPtr;
44
45typedef struct {
46    CloseScreenProcPtr CloseScreen;
47    CreateWindowProcPtr CreateWindow;
48    DestroyWindowProcPtr DestroyWindow;
49    UnrealizeWindowProcPtr UnrealizeWindow;
50    RealizeWindowProcPtr RealizeWindow;
51    miOverlayTransFunc MakeTransparent;
52    miOverlayInOverlayFunc InOverlay;
53    Bool underlayMarked;
54    Bool copyUnderlay;
55} miOverlayScreenRec, *miOverlayScreenPtr;
56
57static DevPrivateKeyRec miOverlayWindowKeyRec;
58
59#define miOverlayWindowKey (&miOverlayWindowKeyRec)
60static DevPrivateKeyRec miOverlayScreenKeyRec;
61
62#define miOverlayScreenKey (&miOverlayScreenKeyRec)
63
64static void RebuildTree(WindowPtr);
65static Bool HasUnderlayChildren(WindowPtr);
66static void MarkUnderlayWindow(WindowPtr);
67static Bool CollectUnderlayChildrenRegions(WindowPtr, RegionPtr);
68
69static Bool miOverlayCloseScreen(ScreenPtr);
70static Bool miOverlayCreateWindow(WindowPtr);
71static Bool miOverlayDestroyWindow(WindowPtr);
72static Bool miOverlayUnrealizeWindow(WindowPtr);
73static Bool miOverlayRealizeWindow(WindowPtr);
74static void miOverlayMarkWindow(WindowPtr);
75static void miOverlayReparentWindow(WindowPtr, WindowPtr);
76static void miOverlayRestackWindow(WindowPtr, WindowPtr);
77static Bool miOverlayMarkOverlappedWindows(WindowPtr, WindowPtr, WindowPtr *);
78static void miOverlayMarkUnrealizedWindow(WindowPtr, WindowPtr, Bool);
79static int miOverlayValidateTree(WindowPtr, WindowPtr, VTKind);
80static void miOverlayHandleExposures(WindowPtr);
81static void miOverlayMoveWindow(WindowPtr, int, int, WindowPtr, VTKind);
82static void miOverlayWindowExposures(WindowPtr, RegionPtr);
83static void miOverlayResizeWindow(WindowPtr, int, int, unsigned int,
84                                  unsigned int, WindowPtr);
85static void miOverlayClearToBackground(WindowPtr, int, int, int, int, Bool);
86
87static void miOverlaySetShape(WindowPtr, int);
88static void miOverlayChangeBorderWidth(WindowPtr, unsigned int);
89
90#define MIOVERLAY_GET_SCREEN_PRIVATE(pScreen) ((miOverlayScreenPtr) \
91	dixLookupPrivate(&(pScreen)->devPrivates, miOverlayScreenKey))
92#define MIOVERLAY_GET_WINDOW_PRIVATE(pWin) ((miOverlayWindowPtr) \
93	dixLookupPrivate(&(pWin)->devPrivates, miOverlayWindowKey))
94#define MIOVERLAY_GET_WINDOW_TREE(pWin) \
95	(MIOVERLAY_GET_WINDOW_PRIVATE(pWin)->tree)
96
97#define IN_UNDERLAY(w) MIOVERLAY_GET_WINDOW_TREE(w)
98#define IN_OVERLAY(w) !MIOVERLAY_GET_WINDOW_TREE(w)
99
100#define MARK_OVERLAY(w) miMarkWindow(w)
101#define MARK_UNDERLAY(w) MarkUnderlayWindow(w)
102
103#define HasParentRelativeBorder(w) (!(w)->borderIsPixel && \
104                                    HasBorder(w) && \
105                                    (w)->backgroundState == ParentRelative)
106
107Bool
108miInitOverlay(ScreenPtr pScreen,
109              miOverlayInOverlayFunc inOverlayFunc,
110              miOverlayTransFunc transFunc)
111{
112    miOverlayScreenPtr pScreenPriv;
113
114    if (!inOverlayFunc || !transFunc)
115        return FALSE;
116
117    if (!dixRegisterPrivateKey
118        (&miOverlayWindowKeyRec, PRIVATE_WINDOW, sizeof(miOverlayWindowRec)))
119        return FALSE;
120
121    if (!dixRegisterPrivateKey(&miOverlayScreenKeyRec, PRIVATE_SCREEN, 0))
122        return FALSE;
123
124    if (!(pScreenPriv = malloc(sizeof(miOverlayScreenRec))))
125        return FALSE;
126
127    dixSetPrivate(&pScreen->devPrivates, miOverlayScreenKey, pScreenPriv);
128
129    pScreenPriv->InOverlay = inOverlayFunc;
130    pScreenPriv->MakeTransparent = transFunc;
131    pScreenPriv->underlayMarked = FALSE;
132
133    pScreenPriv->CloseScreen = pScreen->CloseScreen;
134    pScreenPriv->CreateWindow = pScreen->CreateWindow;
135    pScreenPriv->DestroyWindow = pScreen->DestroyWindow;
136    pScreenPriv->UnrealizeWindow = pScreen->UnrealizeWindow;
137    pScreenPriv->RealizeWindow = pScreen->RealizeWindow;
138
139    pScreen->CloseScreen = miOverlayCloseScreen;
140    pScreen->CreateWindow = miOverlayCreateWindow;
141    pScreen->DestroyWindow = miOverlayDestroyWindow;
142    pScreen->UnrealizeWindow = miOverlayUnrealizeWindow;
143    pScreen->RealizeWindow = miOverlayRealizeWindow;
144
145    pScreen->ReparentWindow = miOverlayReparentWindow;
146    pScreen->RestackWindow = miOverlayRestackWindow;
147    pScreen->MarkOverlappedWindows = miOverlayMarkOverlappedWindows;
148    pScreen->MarkUnrealizedWindow = miOverlayMarkUnrealizedWindow;
149    pScreen->ValidateTree = miOverlayValidateTree;
150    pScreen->HandleExposures = miOverlayHandleExposures;
151    pScreen->MoveWindow = miOverlayMoveWindow;
152    pScreen->WindowExposures = miOverlayWindowExposures;
153    pScreen->ResizeWindow = miOverlayResizeWindow;
154    pScreen->MarkWindow = miOverlayMarkWindow;
155    pScreen->ClearToBackground = miOverlayClearToBackground;
156    pScreen->SetShape = miOverlaySetShape;
157    pScreen->ChangeBorderWidth = miOverlayChangeBorderWidth;
158
159    return TRUE;
160}
161
162static Bool
163miOverlayCloseScreen(ScreenPtr pScreen)
164{
165    miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
166
167    pScreen->CloseScreen = pScreenPriv->CloseScreen;
168    pScreen->CreateWindow = pScreenPriv->CreateWindow;
169    pScreen->DestroyWindow = pScreenPriv->DestroyWindow;
170    pScreen->UnrealizeWindow = pScreenPriv->UnrealizeWindow;
171    pScreen->RealizeWindow = pScreenPriv->RealizeWindow;
172
173    free(pScreenPriv);
174
175    return (*pScreen->CloseScreen) (pScreen);
176}
177
178static Bool
179miOverlayCreateWindow(WindowPtr pWin)
180{
181    ScreenPtr pScreen = pWin->drawable.pScreen;
182    miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
183    miOverlayWindowPtr pWinPriv = MIOVERLAY_GET_WINDOW_PRIVATE(pWin);
184    miOverlayTreePtr pTree = NULL;
185    Bool result = TRUE;
186
187    pWinPriv->tree = NULL;
188
189    if (!pWin->parent || !((*pScreenPriv->InOverlay) (pWin))) {
190        if (!(pTree = (miOverlayTreePtr) calloc(1, sizeof(miOverlayTreeRec))))
191            return FALSE;
192    }
193
194    if (pScreenPriv->CreateWindow) {
195        pScreen->CreateWindow = pScreenPriv->CreateWindow;
196        result = (*pScreen->CreateWindow) (pWin);
197        pScreen->CreateWindow = miOverlayCreateWindow;
198    }
199
200    if (pTree) {
201        if (result) {
202            pTree->pWin = pWin;
203            pTree->visibility = VisibilityNotViewable;
204            pWinPriv->tree = pTree;
205            if (pWin->parent) {
206                RegionNull(&(pTree->borderClip));
207                RegionNull(&(pTree->clipList));
208                RebuildTree(pWin);
209            }
210            else {
211                BoxRec fullBox;
212
213                fullBox.x1 = 0;
214                fullBox.y1 = 0;
215                fullBox.x2 = pScreen->width;
216                fullBox.y2 = pScreen->height;
217                RegionInit(&(pTree->borderClip), &fullBox, 1);
218                RegionInit(&(pTree->clipList), &fullBox, 1);
219            }
220        }
221        else
222            free(pTree);
223    }
224
225    return TRUE;
226}
227
228static Bool
229miOverlayDestroyWindow(WindowPtr pWin)
230{
231    ScreenPtr pScreen = pWin->drawable.pScreen;
232    miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
233    miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
234    Bool result = TRUE;
235
236    if (pTree) {
237        if (pTree->prevSib)
238            pTree->prevSib->nextSib = pTree->nextSib;
239        else if (pTree->parent)
240            pTree->parent->firstChild = pTree->nextSib;
241
242        if (pTree->nextSib)
243            pTree->nextSib->prevSib = pTree->prevSib;
244        else if (pTree->parent)
245            pTree->parent->lastChild = pTree->prevSib;
246
247        RegionUninit(&(pTree->borderClip));
248        RegionUninit(&(pTree->clipList));
249        free(pTree);
250    }
251
252    if (pScreenPriv->DestroyWindow) {
253        pScreen->DestroyWindow = pScreenPriv->DestroyWindow;
254        result = (*pScreen->DestroyWindow) (pWin);
255        pScreen->DestroyWindow = miOverlayDestroyWindow;
256    }
257
258    return result;
259}
260
261static Bool
262miOverlayUnrealizeWindow(WindowPtr pWin)
263{
264    ScreenPtr pScreen = pWin->drawable.pScreen;
265    miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
266    miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
267    Bool result = TRUE;
268
269    if (pTree)
270        pTree->visibility = VisibilityNotViewable;
271
272    if (pScreenPriv->UnrealizeWindow) {
273        pScreen->UnrealizeWindow = pScreenPriv->UnrealizeWindow;
274        result = (*pScreen->UnrealizeWindow) (pWin);
275        pScreen->UnrealizeWindow = miOverlayUnrealizeWindow;
276    }
277
278    return result;
279}
280
281static Bool
282miOverlayRealizeWindow(WindowPtr pWin)
283{
284    ScreenPtr pScreen = pWin->drawable.pScreen;
285    miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
286    Bool result = TRUE;
287
288    if (pScreenPriv->RealizeWindow) {
289        pScreen->RealizeWindow = pScreenPriv->RealizeWindow;
290        result = (*pScreen->RealizeWindow) (pWin);
291        pScreen->RealizeWindow = miOverlayRealizeWindow;
292    }
293
294    /* we only need to catch the root window realization */
295
296    if (result && !pWin->parent && !((*pScreenPriv->InOverlay) (pWin))) {
297        BoxRec box;
298
299        box.x1 = box.y1 = 0;
300        box.x2 = pWin->drawable.width;
301        box.y2 = pWin->drawable.height;
302        (*pScreenPriv->MakeTransparent) (pScreen, 1, &box);
303    }
304
305    return result;
306}
307
308static void
309miOverlayReparentWindow(WindowPtr pWin, WindowPtr pPriorParent)
310{
311    if (IN_UNDERLAY(pWin) || HasUnderlayChildren(pWin)) {
312        /* This could probably be more optimal */
313        RebuildTree(pWin->drawable.pScreen->root->firstChild);
314    }
315}
316
317static void
318miOverlayRestackWindow(WindowPtr pWin, WindowPtr oldNextSib)
319{
320    if (IN_UNDERLAY(pWin) || HasUnderlayChildren(pWin)) {
321        /* This could probably be more optimal */
322        RebuildTree(pWin);
323    }
324}
325
326static Bool
327miOverlayMarkOverlappedWindows(WindowPtr pWin,
328                               WindowPtr pFirst, WindowPtr *pLayerWin)
329{
330    WindowPtr pChild, pLast;
331    Bool overMarked, underMarked, doUnderlay, markAll;
332    miOverlayTreePtr pTree = NULL, tLast, tChild;
333    BoxPtr box;
334
335    overMarked = underMarked = markAll = FALSE;
336
337    if (pLayerWin)
338        *pLayerWin = pWin;      /* hah! */
339
340    doUnderlay = (IN_UNDERLAY(pWin) || HasUnderlayChildren(pWin));
341
342    box = RegionExtents(&pWin->borderSize);
343
344    if ((pChild = pFirst)) {
345        pLast = pChild->parent->lastChild;
346        while (1) {
347            if (pChild == pWin)
348                markAll = TRUE;
349
350            if (doUnderlay && IN_UNDERLAY(pChild))
351                pTree = MIOVERLAY_GET_WINDOW_TREE(pChild);
352
353            if (pChild->viewable) {
354                if (RegionBroken(&pChild->winSize))
355                    SetWinSize(pChild);
356                if (RegionBroken(&pChild->borderSize))
357                    SetBorderSize(pChild);
358
359                if (markAll || RegionContainsRect(&pChild->borderSize, box)) {
360                    MARK_OVERLAY(pChild);
361                    overMarked = TRUE;
362                    if (doUnderlay && IN_UNDERLAY(pChild)) {
363                        MARK_UNDERLAY(pChild);
364                        underMarked = TRUE;
365                    }
366                    if (pChild->firstChild) {
367                        pChild = pChild->firstChild;
368                        continue;
369                    }
370                }
371            }
372            while (!pChild->nextSib && (pChild != pLast)) {
373                pChild = pChild->parent;
374                if (doUnderlay && IN_UNDERLAY(pChild))
375                    pTree = MIOVERLAY_GET_WINDOW_TREE(pChild);
376            }
377
378            if (pChild == pWin)
379                markAll = FALSE;
380
381            if (pChild == pLast)
382                break;
383
384            pChild = pChild->nextSib;
385        }
386        if (overMarked)
387            MARK_OVERLAY(pWin->parent);
388    }
389
390    if (doUnderlay && !pTree) {
391        if (!(pTree = MIOVERLAY_GET_WINDOW_TREE(pWin))) {
392            pChild = pWin->lastChild;
393            while (1) {
394                if ((pTree = MIOVERLAY_GET_WINDOW_TREE(pChild)))
395                    break;
396
397                if (pChild->lastChild) {
398                    pChild = pChild->lastChild;
399                    continue;
400                }
401
402                while (!pChild->prevSib)
403                    pChild = pChild->parent;
404
405                pChild = pChild->prevSib;
406            }
407        }
408    }
409
410    if (pTree && pTree->nextSib) {
411        tChild = pTree->parent->lastChild;
412        tLast = pTree->nextSib;
413
414        while (1) {
415            if (tChild->pWin->viewable) {
416                if (RegionBroken(&tChild->pWin->winSize))
417                    SetWinSize(tChild->pWin);
418                if (RegionBroken(&tChild->pWin->borderSize))
419                    SetBorderSize(tChild->pWin);
420
421                if (RegionContainsRect(&(tChild->pWin->borderSize), box)) {
422                    MARK_UNDERLAY(tChild->pWin);
423                    underMarked = TRUE;
424                }
425            }
426
427            if (tChild->lastChild) {
428                tChild = tChild->lastChild;
429                continue;
430            }
431
432            while (!tChild->prevSib && (tChild != tLast))
433                tChild = tChild->parent;
434
435            if (tChild == tLast)
436                break;
437
438            tChild = tChild->prevSib;
439        }
440    }
441
442    if (underMarked) {
443        ScreenPtr pScreen = pWin->drawable.pScreen;
444
445        MARK_UNDERLAY(pTree->parent->pWin);
446        MIOVERLAY_GET_SCREEN_PRIVATE(pScreen)->underlayMarked = TRUE;
447    }
448
449    return underMarked || overMarked;
450}
451
452static void
453miOverlayComputeClips(WindowPtr pParent,
454                      RegionPtr universe, VTKind kind, RegionPtr exposed)
455{
456    ScreenPtr pScreen = pParent->drawable.pScreen;
457    int oldVis, newVis, dx, dy;
458    BoxRec borderSize;
459    RegionPtr borderVisible;
460    RegionRec childUniverse, childUnion;
461    miOverlayTreePtr tParent = MIOVERLAY_GET_WINDOW_TREE(pParent);
462    miOverlayTreePtr tChild;
463    Bool overlap;
464
465    borderSize.x1 = pParent->drawable.x - wBorderWidth(pParent);
466    borderSize.y1 = pParent->drawable.y - wBorderWidth(pParent);
467    dx = (int) pParent->drawable.x + (int) pParent->drawable.width +
468        wBorderWidth(pParent);
469    if (dx > 32767)
470        dx = 32767;
471    borderSize.x2 = dx;
472    dy = (int) pParent->drawable.y + (int) pParent->drawable.height +
473        wBorderWidth(pParent);
474    if (dy > 32767)
475        dy = 32767;
476    borderSize.y2 = dy;
477
478    oldVis = tParent->visibility;
479    switch (RegionContainsRect(universe, &borderSize)) {
480    case rgnIN:
481        newVis = VisibilityUnobscured;
482        break;
483    case rgnPART:
484        newVis = VisibilityPartiallyObscured;
485        {
486            RegionPtr pBounding;
487
488            if ((pBounding = wBoundingShape(pParent))) {
489                switch (miShapedWindowIn(universe, pBounding,
490                                         &borderSize,
491                                         pParent->drawable.x,
492                                         pParent->drawable.y)) {
493                case rgnIN:
494                    newVis = VisibilityUnobscured;
495                    break;
496                case rgnOUT:
497                    newVis = VisibilityFullyObscured;
498                    break;
499                }
500            }
501        }
502        break;
503    default:
504        newVis = VisibilityFullyObscured;
505        break;
506    }
507    tParent->visibility = newVis;
508
509    dx = pParent->drawable.x - tParent->valdata->oldAbsCorner.x;
510    dy = pParent->drawable.y - tParent->valdata->oldAbsCorner.y;
511
512    switch (kind) {
513    case VTMap:
514    case VTStack:
515    case VTUnmap:
516        break;
517    case VTMove:
518        if ((oldVis == newVis) &&
519            ((oldVis == VisibilityFullyObscured) ||
520             (oldVis == VisibilityUnobscured))) {
521            tChild = tParent;
522            while (1) {
523                if (tChild->pWin->viewable) {
524                    if (tChild->visibility != VisibilityFullyObscured) {
525                        RegionTranslate(&tChild->borderClip, dx, dy);
526                        RegionTranslate(&tChild->clipList, dx, dy);
527
528                        tChild->pWin->drawable.serialNumber =
529                            NEXT_SERIAL_NUMBER;
530                        if (pScreen->ClipNotify)
531                            (*pScreen->ClipNotify) (tChild->pWin, dx, dy);
532                    }
533                    if (tChild->valdata) {
534                        RegionNull(&tChild->valdata->borderExposed);
535                        if (HasParentRelativeBorder(tChild->pWin)) {
536                            RegionSubtract(&tChild->valdata->borderExposed,
537                                           &tChild->borderClip,
538                                           &tChild->pWin->winSize);
539                        }
540                        RegionNull(&tChild->valdata->exposed);
541                    }
542                    if (tChild->firstChild) {
543                        tChild = tChild->firstChild;
544                        continue;
545                    }
546                }
547                while (!tChild->nextSib && (tChild != tParent))
548                    tChild = tChild->parent;
549                if (tChild == tParent)
550                    break;
551                tChild = tChild->nextSib;
552            }
553            return;
554        }
555        /* fall through */
556    default:
557        if (dx || dy) {
558            RegionTranslate(&tParent->borderClip, dx, dy);
559            RegionTranslate(&tParent->clipList, dx, dy);
560        }
561        break;
562    case VTBroken:
563        RegionEmpty(&tParent->borderClip);
564        RegionEmpty(&tParent->clipList);
565        break;
566    }
567
568    borderVisible = tParent->valdata->borderVisible;
569    RegionNull(&tParent->valdata->borderExposed);
570    RegionNull(&tParent->valdata->exposed);
571
572    if (HasBorder(pParent)) {
573        if (borderVisible) {
574            RegionSubtract(exposed, universe, borderVisible);
575            RegionDestroy(borderVisible);
576        }
577        else
578            RegionSubtract(exposed, universe, &tParent->borderClip);
579
580        if (HasParentRelativeBorder(pParent) && (dx || dy))
581            RegionSubtract(&tParent->valdata->borderExposed,
582                           universe, &pParent->winSize);
583        else
584            RegionSubtract(&tParent->valdata->borderExposed,
585                           exposed, &pParent->winSize);
586
587        RegionCopy(&tParent->borderClip, universe);
588        RegionIntersect(universe, universe, &pParent->winSize);
589    }
590    else
591        RegionCopy(&tParent->borderClip, universe);
592
593    if ((tChild = tParent->firstChild) && pParent->mapped) {
594        RegionNull(&childUniverse);
595        RegionNull(&childUnion);
596
597        for (; tChild; tChild = tChild->nextSib) {
598            if (tChild->pWin->viewable)
599                RegionAppend(&childUnion, &tChild->pWin->borderSize);
600        }
601
602        RegionValidate(&childUnion, &overlap);
603
604        for (tChild = tParent->firstChild; tChild; tChild = tChild->nextSib) {
605            if (tChild->pWin->viewable) {
606                if (tChild->valdata) {
607                    RegionIntersect(&childUniverse, universe,
608                                    &tChild->pWin->borderSize);
609                    miOverlayComputeClips(tChild->pWin, &childUniverse,
610                                          kind, exposed);
611                }
612                if (overlap)
613                    RegionSubtract(universe, universe,
614                                   &tChild->pWin->borderSize);
615            }
616        }
617        if (!overlap)
618            RegionSubtract(universe, universe, &childUnion);
619        RegionUninit(&childUnion);
620        RegionUninit(&childUniverse);
621    }
622
623    if (oldVis == VisibilityFullyObscured || oldVis == VisibilityNotViewable) {
624        RegionCopy(&tParent->valdata->exposed, universe);
625    }
626    else if (newVis != VisibilityFullyObscured &&
627             newVis != VisibilityNotViewable) {
628        RegionSubtract(&tParent->valdata->exposed,
629                       universe, &tParent->clipList);
630    }
631
632    /* HACK ALERT - copying contents of regions, instead of regions */
633    {
634        RegionRec tmp;
635
636        tmp = tParent->clipList;
637        tParent->clipList = *universe;
638        *universe = tmp;
639    }
640
641    pParent->drawable.serialNumber = NEXT_SERIAL_NUMBER;
642
643    if (pScreen->ClipNotify)
644        (*pScreen->ClipNotify) (pParent, dx, dy);
645}
646
647static void
648miOverlayMarkWindow(WindowPtr pWin)
649{
650    miOverlayTreePtr pTree = NULL;
651    WindowPtr pChild, pGrandChild;
652
653    miMarkWindow(pWin);
654
655    /* look for UnmapValdata among immediate children */
656
657    if (!(pChild = pWin->firstChild))
658        return;
659
660    for (; pChild; pChild = pChild->nextSib) {
661        if (pChild->valdata == UnmapValData) {
662            if (IN_UNDERLAY(pChild)) {
663                pTree = MIOVERLAY_GET_WINDOW_TREE(pChild);
664                pTree->valdata = (miOverlayValDataPtr) UnmapValData;
665                continue;
666            }
667            else {
668                if (!(pGrandChild = pChild->firstChild))
669                    continue;
670
671                while (1) {
672                    if (IN_UNDERLAY(pGrandChild)) {
673                        pTree = MIOVERLAY_GET_WINDOW_TREE(pGrandChild);
674                        pTree->valdata = (miOverlayValDataPtr) UnmapValData;
675                    }
676                    else if (pGrandChild->firstChild) {
677                        pGrandChild = pGrandChild->firstChild;
678                        continue;
679                    }
680
681                    while (!pGrandChild->nextSib && (pGrandChild != pChild))
682                        pGrandChild = pGrandChild->parent;
683
684                    if (pChild == pGrandChild)
685                        break;
686
687                    pGrandChild = pGrandChild->nextSib;
688                }
689            }
690        }
691    }
692
693    if (pTree) {
694        MARK_UNDERLAY(pTree->parent->pWin);
695        MIOVERLAY_GET_SCREEN_PRIVATE(pWin->drawable.pScreen)->underlayMarked =
696            TRUE;
697    }
698}
699
700static void
701miOverlayMarkUnrealizedWindow(WindowPtr pChild,
702                              WindowPtr pWin, Bool fromConfigure)
703{
704    if ((pChild != pWin) || fromConfigure) {
705        miOverlayTreePtr pTree;
706
707        RegionEmpty(&pChild->clipList);
708        if (pChild->drawable.pScreen->ClipNotify)
709            (*pChild->drawable.pScreen->ClipNotify) (pChild, 0, 0);
710        RegionEmpty(&pChild->borderClip);
711        if ((pTree = MIOVERLAY_GET_WINDOW_TREE(pChild))) {
712            if (pTree->valdata != (miOverlayValDataPtr) UnmapValData) {
713                RegionEmpty(&pTree->clipList);
714                RegionEmpty(&pTree->borderClip);
715            }
716        }
717    }
718}
719
720static int
721miOverlayValidateTree(WindowPtr pParent, WindowPtr pChild,      /* first child effected */
722                      VTKind kind)
723{
724    ScreenPtr pScreen = pParent->drawable.pScreen;
725    miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
726    RegionRec totalClip, childClip, exposed;
727    miOverlayTreePtr tParent, tChild, tWin;
728    Bool overlap;
729    WindowPtr newParent;
730
731    if (!pPriv->underlayMarked)
732        goto SKIP_UNDERLAY;
733
734    if (!pChild)
735        pChild = pParent->firstChild;
736
737    RegionNull(&totalClip);
738    RegionNull(&childClip);
739    RegionNull(&exposed);
740
741    newParent = pParent;
742
743    while (IN_OVERLAY(newParent))
744        newParent = newParent->parent;
745
746    tParent = MIOVERLAY_GET_WINDOW_TREE(newParent);
747
748    if (IN_UNDERLAY(pChild))
749        tChild = MIOVERLAY_GET_WINDOW_TREE(pChild);
750    else
751        tChild = tParent->firstChild;
752
753    if (RegionBroken(&tParent->clipList) && !RegionBroken(&tParent->borderClip)) {
754        kind = VTBroken;
755        RegionCopy(&totalClip, &tParent->borderClip);
756        RegionIntersect(&totalClip, &totalClip, &tParent->pWin->winSize);
757
758        for (tWin = tParent->firstChild; tWin != tChild; tWin = tWin->nextSib) {
759            if (tWin->pWin->viewable)
760                RegionSubtract(&totalClip, &totalClip, &tWin->pWin->borderSize);
761        }
762        RegionEmpty(&tParent->clipList);
763    }
764    else {
765        for (tWin = tChild; tWin; tWin = tWin->nextSib) {
766            if (tWin->valdata)
767                RegionAppend(&totalClip, &tWin->borderClip);
768        }
769        RegionValidate(&totalClip, &overlap);
770    }
771
772    if (kind != VTStack)
773        RegionUnion(&totalClip, &totalClip, &tParent->clipList);
774
775    for (tWin = tChild; tWin; tWin = tWin->nextSib) {
776        if (tWin->valdata) {
777            if (tWin->pWin->viewable) {
778                RegionIntersect(&childClip, &totalClip,
779                                &tWin->pWin->borderSize);
780                miOverlayComputeClips(tWin->pWin, &childClip, kind, &exposed);
781                RegionSubtract(&totalClip, &totalClip, &tWin->pWin->borderSize);
782            }
783            else {              /* Means we are unmapping */
784                RegionEmpty(&tWin->clipList);
785                RegionEmpty(&tWin->borderClip);
786                tWin->valdata = NULL;
787            }
788        }
789    }
790
791    RegionUninit(&childClip);
792
793    if (!((*pPriv->InOverlay) (newParent))) {
794        RegionNull(&tParent->valdata->exposed);
795        RegionNull(&tParent->valdata->borderExposed);
796    }
797
798    switch (kind) {
799    case VTStack:
800        break;
801    default:
802        if (!((*pPriv->InOverlay) (newParent)))
803            RegionSubtract(&tParent->valdata->exposed, &totalClip,
804                           &tParent->clipList);
805        /* fall through */
806    case VTMap:
807        RegionCopy(&tParent->clipList, &totalClip);
808        if (!((*pPriv->InOverlay) (newParent)))
809            newParent->drawable.serialNumber = NEXT_SERIAL_NUMBER;
810        break;
811    }
812
813    RegionUninit(&totalClip);
814    RegionUninit(&exposed);
815
816 SKIP_UNDERLAY:
817
818    miValidateTree(pParent, pChild, kind);
819
820    return 1;
821}
822
823static void
824miOverlayHandleExposures(WindowPtr pWin)
825{
826    ScreenPtr pScreen = pWin->drawable.pScreen;
827    miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
828    WindowPtr pChild;
829    ValidatePtr val;
830    WindowExposuresProcPtr WindowExposures;
831
832    WindowExposures = pWin->drawable.pScreen->WindowExposures;
833    if (pPriv->underlayMarked) {
834        miOverlayTreePtr pTree;
835        miOverlayValDataPtr mival;
836
837        pChild = pWin;
838        while (IN_OVERLAY(pChild))
839            pChild = pChild->parent;
840
841        pTree = MIOVERLAY_GET_WINDOW_TREE(pChild);
842
843        while (1) {
844            if ((mival = pTree->valdata)) {
845                if (!((*pPriv->InOverlay) (pTree->pWin))) {
846                    if (RegionNotEmpty(&mival->borderExposed)) {
847                        pScreen->PaintWindow(pTree->pWin, &mival->borderExposed,
848                                             PW_BORDER);
849                    }
850                    RegionUninit(&mival->borderExposed);
851
852                    (*WindowExposures) (pTree->pWin, &mival->exposed);
853                    RegionUninit(&mival->exposed);
854                }
855                free(mival);
856                pTree->valdata = NULL;
857                if (pTree->firstChild) {
858                    pTree = pTree->firstChild;
859                    continue;
860                }
861            }
862            while (!pTree->nextSib && (pTree->pWin != pChild))
863                pTree = pTree->parent;
864            if (pTree->pWin == pChild)
865                break;
866            pTree = pTree->nextSib;
867        }
868        pPriv->underlayMarked = FALSE;
869    }
870
871    pChild = pWin;
872    while (1) {
873        if ((val = pChild->valdata)) {
874            if (!((*pPriv->InOverlay) (pChild))) {
875                RegionUnion(&val->after.exposed, &val->after.exposed,
876                            &val->after.borderExposed);
877
878                if (RegionNotEmpty(&val->after.exposed)) {
879                    (*(MIOVERLAY_GET_SCREEN_PRIVATE(pScreen)->MakeTransparent))
880                        (pScreen, RegionNumRects(&val->after.exposed),
881                         RegionRects(&val->after.exposed));
882                }
883            }
884            else {
885                if (RegionNotEmpty(&val->after.borderExposed)) {
886                    pScreen->PaintWindow(pChild, &val->after.borderExposed,
887                                         PW_BORDER);
888                }
889                (*WindowExposures) (pChild, &val->after.exposed);
890            }
891            RegionUninit(&val->after.borderExposed);
892            RegionUninit(&val->after.exposed);
893            free(val);
894            pChild->valdata = NULL;
895            if (pChild->firstChild) {
896                pChild = pChild->firstChild;
897                continue;
898            }
899        }
900        while (!pChild->nextSib && (pChild != pWin))
901            pChild = pChild->parent;
902        if (pChild == pWin)
903            break;
904        pChild = pChild->nextSib;
905    }
906}
907
908static void
909miOverlayMoveWindow(WindowPtr pWin,
910                    int x, int y, WindowPtr pNextSib, VTKind kind)
911{
912    ScreenPtr pScreen = pWin->drawable.pScreen;
913    miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
914    WindowPtr pParent, windowToValidate;
915    Bool WasViewable = (Bool) (pWin->viewable);
916    short bw;
917    RegionRec overReg, underReg;
918    DDXPointRec oldpt;
919
920    if (!(pParent = pWin->parent))
921        return;
922    bw = wBorderWidth(pWin);
923
924    oldpt.x = pWin->drawable.x;
925    oldpt.y = pWin->drawable.y;
926    if (WasViewable) {
927        RegionNull(&overReg);
928        RegionNull(&underReg);
929        if (pTree) {
930            RegionCopy(&overReg, &pWin->borderClip);
931            RegionCopy(&underReg, &pTree->borderClip);
932        }
933        else {
934            RegionCopy(&overReg, &pWin->borderClip);
935            CollectUnderlayChildrenRegions(pWin, &underReg);
936        }
937        (*pScreen->MarkOverlappedWindows) (pWin, pWin, NULL);
938    }
939    pWin->origin.x = x + (int) bw;
940    pWin->origin.y = y + (int) bw;
941    x = pWin->drawable.x = pParent->drawable.x + x + (int) bw;
942    y = pWin->drawable.y = pParent->drawable.y + y + (int) bw;
943
944    SetWinSize(pWin);
945    SetBorderSize(pWin);
946
947    (*pScreen->PositionWindow) (pWin, x, y);
948
949    windowToValidate = MoveWindowInStack(pWin, pNextSib);
950
951    ResizeChildrenWinSize(pWin, x - oldpt.x, y - oldpt.y, 0, 0);
952
953    if (WasViewable) {
954        miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
955
956        (*pScreen->MarkOverlappedWindows) (pWin, windowToValidate, NULL);
957
958        (*pScreen->ValidateTree) (pWin->parent, NullWindow, kind);
959        if (RegionNotEmpty(&underReg)) {
960            pPriv->copyUnderlay = TRUE;
961            (*pWin->drawable.pScreen->CopyWindow) (pWin, oldpt, &underReg);
962        }
963        RegionUninit(&underReg);
964        if (RegionNotEmpty(&overReg)) {
965            pPriv->copyUnderlay = FALSE;
966            (*pWin->drawable.pScreen->CopyWindow) (pWin, oldpt, &overReg);
967        }
968        RegionUninit(&overReg);
969        (*pScreen->HandleExposures) (pWin->parent);
970
971        if (pScreen->PostValidateTree)
972            (*pScreen->PostValidateTree) (pWin->parent, NullWindow, kind);
973    }
974    if (pWin->realized)
975        WindowsRestructured();
976}
977
978#ifndef RECTLIMIT
979#define RECTLIMIT 25
980#endif
981
982static void
983miOverlayWindowExposures(WindowPtr pWin, RegionPtr prgn)
984{
985    RegionPtr exposures = prgn;
986    ScreenPtr pScreen = pWin->drawable.pScreen;
987
988    if (prgn && !RegionNil(prgn)) {
989        RegionRec expRec;
990        int clientInterested =
991            (pWin->eventMask | wOtherEventMasks(pWin)) & ExposureMask;
992        if (clientInterested && (RegionNumRects(prgn) > RECTLIMIT)) {
993            miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
994            BoxRec box;
995
996            box = *RegionExtents(prgn);
997            exposures = &expRec;
998            RegionInit(exposures, &box, 1);
999            RegionReset(prgn, &box);
1000            /* This is the only reason why we are replacing mi's version
1001               of this file */
1002
1003            if (!((*pPriv->InOverlay) (pWin))) {
1004                miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
1005
1006                RegionIntersect(prgn, prgn, &pTree->clipList);
1007            }
1008            else
1009                RegionIntersect(prgn, prgn, &pWin->clipList);
1010        }
1011        pScreen->PaintWindow(pWin, prgn, PW_BACKGROUND);
1012        if (clientInterested)
1013            miSendExposures(pWin, exposures,
1014                            pWin->drawable.x, pWin->drawable.y);
1015        if (exposures == &expRec)
1016            RegionUninit(exposures);
1017        RegionEmpty(prgn);
1018    }
1019}
1020
1021typedef struct {
1022    RegionPtr over;
1023    RegionPtr under;
1024} miOverlayTwoRegions;
1025
1026static int
1027miOverlayRecomputeExposures(WindowPtr pWin, void *value)
1028{
1029    miOverlayTwoRegions *pValid = (miOverlayTwoRegions *) value;
1030    miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
1031
1032    if (pWin->valdata) {
1033        /*
1034         * compute exposed regions of this window
1035         */
1036        RegionSubtract(&pWin->valdata->after.exposed,
1037                       &pWin->clipList, pValid->over);
1038        /*
1039         * compute exposed regions of the border
1040         */
1041        RegionSubtract(&pWin->valdata->after.borderExposed,
1042                       &pWin->borderClip, &pWin->winSize);
1043        RegionSubtract(&pWin->valdata->after.borderExposed,
1044                       &pWin->valdata->after.borderExposed, pValid->over);
1045    }
1046
1047    if (pTree && pTree->valdata) {
1048        RegionSubtract(&pTree->valdata->exposed,
1049                       &pTree->clipList, pValid->under);
1050        RegionSubtract(&pTree->valdata->borderExposed,
1051                       &pTree->borderClip, &pWin->winSize);
1052        RegionSubtract(&pTree->valdata->borderExposed,
1053                       &pTree->valdata->borderExposed, pValid->under);
1054    }
1055    else if (!pWin->valdata)
1056        return WT_NOMATCH;
1057
1058    return WT_WALKCHILDREN;
1059}
1060
1061static void
1062miOverlayResizeWindow(WindowPtr pWin,
1063                      int x, int y,
1064                      unsigned int w, unsigned int h, WindowPtr pSib)
1065{
1066    ScreenPtr pScreen = pWin->drawable.pScreen;
1067    WindowPtr pParent;
1068    miOverlayTreePtr tChild, pTree;
1069    Bool WasViewable = (Bool) (pWin->viewable);
1070    unsigned short width = pWin->drawable.width;
1071    unsigned short height = pWin->drawable.height;
1072    short oldx = pWin->drawable.x;
1073    short oldy = pWin->drawable.y;
1074    int bw = wBorderWidth(pWin);
1075    short dw, dh;
1076    DDXPointRec oldpt;
1077    RegionPtr oldRegion = NULL, oldRegion2 = NULL;
1078    WindowPtr pFirstChange;
1079    WindowPtr pChild;
1080    RegionPtr gravitate[StaticGravity + 1];
1081    RegionPtr gravitate2[StaticGravity + 1];
1082    unsigned g;
1083    int nx, ny;                 /* destination x,y */
1084    int newx, newy;             /* new inner window position */
1085    RegionPtr pRegion = NULL;
1086    RegionPtr destClip, destClip2;
1087    RegionPtr oldWinClip = NULL, oldWinClip2 = NULL;
1088    RegionPtr borderVisible = NullRegion;
1089    RegionPtr borderVisible2 = NullRegion;
1090    Bool shrunk = FALSE;        /* shrunk in an inner dimension */
1091    Bool moved = FALSE;         /* window position changed */
1092    Bool doUnderlay;
1093
1094    /* if this is a root window, can't be resized */
1095    if (!(pParent = pWin->parent))
1096        return;
1097
1098    pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
1099    doUnderlay = ((pTree) || HasUnderlayChildren(pWin));
1100    newx = pParent->drawable.x + x + bw;
1101    newy = pParent->drawable.y + y + bw;
1102    if (WasViewable) {
1103        /*
1104         * save the visible region of the window
1105         */
1106        oldRegion = RegionCreate(NullBox, 1);
1107        RegionCopy(oldRegion, &pWin->winSize);
1108        if (doUnderlay) {
1109            oldRegion2 = RegionCreate(NullBox, 1);
1110            RegionCopy(oldRegion2, &pWin->winSize);
1111        }
1112
1113        /*
1114         * categorize child windows into regions to be moved
1115         */
1116        for (g = 0; g <= StaticGravity; g++)
1117            gravitate[g] = gravitate2[g] = NULL;
1118        for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) {
1119            g = pChild->winGravity;
1120            if (g != UnmapGravity) {
1121                if (!gravitate[g])
1122                    gravitate[g] = RegionCreate(NullBox, 1);
1123                RegionUnion(gravitate[g], gravitate[g], &pChild->borderClip);
1124
1125                if (doUnderlay) {
1126                    if (!gravitate2[g])
1127                        gravitate2[g] = RegionCreate(NullBox, 0);
1128
1129                    if ((tChild = MIOVERLAY_GET_WINDOW_TREE(pChild))) {
1130                        RegionUnion(gravitate2[g],
1131                                    gravitate2[g], &tChild->borderClip);
1132                    }
1133                    else
1134                        CollectUnderlayChildrenRegions(pChild, gravitate2[g]);
1135                }
1136            }
1137            else {
1138                UnmapWindow(pChild, TRUE);
1139            }
1140        }
1141        (*pScreen->MarkOverlappedWindows) (pWin, pWin, NULL);
1142
1143        oldWinClip = oldWinClip2 = NULL;
1144        if (pWin->bitGravity != ForgetGravity) {
1145            oldWinClip = RegionCreate(NullBox, 1);
1146            RegionCopy(oldWinClip, &pWin->clipList);
1147            if (pTree) {
1148                oldWinClip2 = RegionCreate(NullBox, 1);
1149                RegionCopy(oldWinClip2, &pTree->clipList);
1150            }
1151        }
1152        /*
1153         * if the window is changing size, borderExposed
1154         * can't be computed correctly without some help.
1155         */
1156        if (pWin->drawable.height > h || pWin->drawable.width > w)
1157            shrunk = TRUE;
1158
1159        if (newx != oldx || newy != oldy)
1160            moved = TRUE;
1161
1162        if ((pWin->drawable.height != h || pWin->drawable.width != w) &&
1163            HasBorder(pWin)) {
1164            borderVisible = RegionCreate(NullBox, 1);
1165            if (pTree)
1166                borderVisible2 = RegionCreate(NullBox, 1);
1167            /* for tiled borders, we punt and draw the whole thing */
1168            if (pWin->borderIsPixel || !moved) {
1169                if (shrunk || moved)
1170                    RegionSubtract(borderVisible,
1171                                   &pWin->borderClip, &pWin->winSize);
1172                else
1173                    RegionCopy(borderVisible, &pWin->borderClip);
1174                if (pTree) {
1175                    if (shrunk || moved)
1176                        RegionSubtract(borderVisible,
1177                                       &pTree->borderClip, &pWin->winSize);
1178                    else
1179                        RegionCopy(borderVisible, &pTree->borderClip);
1180                }
1181            }
1182        }
1183    }
1184    pWin->origin.x = x + bw;
1185    pWin->origin.y = y + bw;
1186    pWin->drawable.height = h;
1187    pWin->drawable.width = w;
1188
1189    x = pWin->drawable.x = newx;
1190    y = pWin->drawable.y = newy;
1191
1192    SetWinSize(pWin);
1193    SetBorderSize(pWin);
1194
1195    dw = (int) w - (int) width;
1196    dh = (int) h - (int) height;
1197    ResizeChildrenWinSize(pWin, x - oldx, y - oldy, dw, dh);
1198
1199    /* let the hardware adjust background and border pixmaps, if any */
1200    (*pScreen->PositionWindow) (pWin, x, y);
1201
1202    pFirstChange = MoveWindowInStack(pWin, pSib);
1203
1204    if (WasViewable) {
1205        pRegion = RegionCreate(NullBox, 1);
1206
1207        (*pScreen->MarkOverlappedWindows) (pWin, pFirstChange, NULL);
1208
1209        pWin->valdata->before.resized = TRUE;
1210        pWin->valdata->before.borderVisible = borderVisible;
1211        if (pTree)
1212            pTree->valdata->borderVisible = borderVisible2;
1213
1214        (*pScreen->ValidateTree) (pWin->parent, pFirstChange, VTOther);
1215        /*
1216         * the entire window is trashed unless bitGravity
1217         * recovers portions of it
1218         */
1219        RegionCopy(&pWin->valdata->after.exposed, &pWin->clipList);
1220        if (pTree)
1221            RegionCopy(&pTree->valdata->exposed, &pTree->clipList);
1222    }
1223
1224    GravityTranslate(x, y, oldx, oldy, dw, dh, pWin->bitGravity, &nx, &ny);
1225
1226    if (WasViewable) {
1227        miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
1228        miOverlayTwoRegions TwoRegions;
1229
1230        /* avoid the border */
1231        if (HasBorder(pWin)) {
1232            int offx, offy, dx, dy;
1233
1234            /* kruft to avoid double translates for each gravity */
1235            offx = 0;
1236            offy = 0;
1237            for (g = 0; g <= StaticGravity; g++) {
1238                if (!gravitate[g] && !gravitate2[g])
1239                    continue;
1240
1241                /* align winSize to gravitate[g].
1242                 * winSize is in new coordinates,
1243                 * gravitate[g] is still in old coordinates */
1244                GravityTranslate(x, y, oldx, oldy, dw, dh, g, &nx, &ny);
1245
1246                dx = (oldx - nx) - offx;
1247                dy = (oldy - ny) - offy;
1248                if (dx || dy) {
1249                    RegionTranslate(&pWin->winSize, dx, dy);
1250                    offx += dx;
1251                    offy += dy;
1252                }
1253                if (gravitate[g])
1254                    RegionIntersect(gravitate[g], gravitate[g], &pWin->winSize);
1255                if (gravitate2[g])
1256                    RegionIntersect(gravitate2[g], gravitate2[g],
1257                                    &pWin->winSize);
1258            }
1259            /* get winSize back where it belongs */
1260            if (offx || offy)
1261                RegionTranslate(&pWin->winSize, -offx, -offy);
1262        }
1263        /*
1264         * add screen bits to the appropriate bucket
1265         */
1266
1267        if (oldWinClip2) {
1268            RegionCopy(pRegion, oldWinClip2);
1269            RegionTranslate(pRegion, nx - oldx, ny - oldy);
1270            RegionIntersect(oldWinClip2, pRegion, &pTree->clipList);
1271
1272            for (g = pWin->bitGravity + 1; g <= StaticGravity; g++) {
1273                if (gravitate2[g])
1274                    RegionSubtract(oldWinClip2, oldWinClip2, gravitate2[g]);
1275            }
1276            RegionTranslate(oldWinClip2, oldx - nx, oldy - ny);
1277            g = pWin->bitGravity;
1278            if (!gravitate2[g])
1279                gravitate2[g] = oldWinClip2;
1280            else {
1281                RegionUnion(gravitate2[g], gravitate2[g], oldWinClip2);
1282                RegionDestroy(oldWinClip2);
1283            }
1284        }
1285
1286        if (oldWinClip) {
1287            /*
1288             * clip to new clipList
1289             */
1290            RegionCopy(pRegion, oldWinClip);
1291            RegionTranslate(pRegion, nx - oldx, ny - oldy);
1292            RegionIntersect(oldWinClip, pRegion, &pWin->clipList);
1293            /*
1294             * don't step on any gravity bits which will be copied after this
1295             * region.  Note -- this assumes that the regions will be copied
1296             * in gravity order.
1297             */
1298            for (g = pWin->bitGravity + 1; g <= StaticGravity; g++) {
1299                if (gravitate[g])
1300                    RegionSubtract(oldWinClip, oldWinClip, gravitate[g]);
1301            }
1302            RegionTranslate(oldWinClip, oldx - nx, oldy - ny);
1303            g = pWin->bitGravity;
1304            if (!gravitate[g])
1305                gravitate[g] = oldWinClip;
1306            else {
1307                RegionUnion(gravitate[g], gravitate[g], oldWinClip);
1308                RegionDestroy(oldWinClip);
1309            }
1310        }
1311
1312        /*
1313         * move the bits on the screen
1314         */
1315
1316        destClip = destClip2 = NULL;
1317
1318        for (g = 0; g <= StaticGravity; g++) {
1319            if (!gravitate[g] && !gravitate2[g])
1320                continue;
1321
1322            GravityTranslate(x, y, oldx, oldy, dw, dh, g, &nx, &ny);
1323
1324            oldpt.x = oldx + (x - nx);
1325            oldpt.y = oldy + (y - ny);
1326
1327            /* Note that gravitate[g] is *translated* by CopyWindow */
1328
1329            /* only copy the remaining useful bits */
1330
1331            if (gravitate[g])
1332                RegionIntersect(gravitate[g], gravitate[g], oldRegion);
1333            if (gravitate2[g])
1334                RegionIntersect(gravitate2[g], gravitate2[g], oldRegion2);
1335
1336            /* clip to not overwrite already copied areas */
1337
1338            if (destClip && gravitate[g]) {
1339                RegionTranslate(destClip, oldpt.x - x, oldpt.y - y);
1340                RegionSubtract(gravitate[g], gravitate[g], destClip);
1341                RegionTranslate(destClip, x - oldpt.x, y - oldpt.y);
1342            }
1343            if (destClip2 && gravitate2[g]) {
1344                RegionTranslate(destClip2, oldpt.x - x, oldpt.y - y);
1345                RegionSubtract(gravitate2[g], gravitate2[g], destClip2);
1346                RegionTranslate(destClip2, x - oldpt.x, y - oldpt.y);
1347            }
1348
1349            /* and move those bits */
1350
1351            if (oldpt.x != x || oldpt.y != y) {
1352                if (gravitate2[g]) {
1353                    pPriv->copyUnderlay = TRUE;
1354                    (*pScreen->CopyWindow) (pWin, oldpt, gravitate2[g]);
1355                }
1356                if (gravitate[g]) {
1357                    pPriv->copyUnderlay = FALSE;
1358                    (*pScreen->CopyWindow) (pWin, oldpt, gravitate[g]);
1359                }
1360            }
1361
1362            /* remove any overwritten bits from the remaining useful bits */
1363
1364            if (gravitate[g])
1365                RegionSubtract(oldRegion, oldRegion, gravitate[g]);
1366            if (gravitate2[g])
1367                RegionSubtract(oldRegion2, oldRegion2, gravitate2[g]);
1368
1369            /*
1370             * recompute exposed regions of child windows
1371             */
1372
1373            for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) {
1374                if (pChild->winGravity != g)
1375                    continue;
1376
1377                TwoRegions.over = gravitate[g];
1378                TwoRegions.under = gravitate2[g];
1379
1380                TraverseTree(pChild, miOverlayRecomputeExposures,
1381                             (void *) (&TwoRegions));
1382            }
1383
1384            /*
1385             * remove the successfully copied regions of the
1386             * window from its exposed region
1387             */
1388
1389            if (g == pWin->bitGravity) {
1390                if (gravitate[g])
1391                    RegionSubtract(&pWin->valdata->after.exposed,
1392                                   &pWin->valdata->after.exposed, gravitate[g]);
1393                if (gravitate2[g] && pTree)
1394                    RegionSubtract(&pTree->valdata->exposed,
1395                                   &pTree->valdata->exposed, gravitate2[g]);
1396            }
1397            if (gravitate[g]) {
1398                if (!destClip)
1399                    destClip = gravitate[g];
1400                else {
1401                    RegionUnion(destClip, destClip, gravitate[g]);
1402                    RegionDestroy(gravitate[g]);
1403                }
1404            }
1405            if (gravitate2[g]) {
1406                if (!destClip2)
1407                    destClip2 = gravitate2[g];
1408                else {
1409                    RegionUnion(destClip2, destClip2, gravitate2[g]);
1410                    RegionDestroy(gravitate2[g]);
1411                }
1412            }
1413        }
1414
1415        RegionDestroy(pRegion);
1416        RegionDestroy(oldRegion);
1417        if (doUnderlay)
1418            RegionDestroy(oldRegion2);
1419        if (destClip)
1420            RegionDestroy(destClip);
1421        if (destClip2)
1422            RegionDestroy(destClip2);
1423        (*pScreen->HandleExposures) (pWin->parent);
1424        if (pScreen->PostValidateTree)
1425            (*pScreen->PostValidateTree) (pWin->parent, pFirstChange, VTOther);
1426    }
1427    if (pWin->realized)
1428        WindowsRestructured();
1429}
1430
1431static void
1432miOverlaySetShape(WindowPtr pWin, int kind)
1433{
1434    Bool WasViewable = (Bool) (pWin->viewable);
1435    ScreenPtr pScreen = pWin->drawable.pScreen;
1436
1437    if (kind != ShapeInput) {
1438        if (WasViewable) {
1439            (*pScreen->MarkOverlappedWindows) (pWin, pWin, NULL);
1440
1441            if (HasBorder(pWin)) {
1442                RegionPtr borderVisible;
1443
1444                borderVisible = RegionCreate(NullBox, 1);
1445                RegionSubtract(borderVisible,
1446                               &pWin->borderClip, &pWin->winSize);
1447                pWin->valdata->before.borderVisible = borderVisible;
1448                pWin->valdata->before.resized = TRUE;
1449                if (IN_UNDERLAY(pWin)) {
1450                    miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
1451                    RegionPtr borderVisible2;
1452
1453                    borderVisible2 = RegionCreate(NULL, 1);
1454                    RegionSubtract(borderVisible2,
1455                                   &pTree->borderClip, &pWin->winSize);
1456                    pTree->valdata->borderVisible = borderVisible2;
1457                }
1458            }
1459        }
1460
1461        SetWinSize(pWin);
1462        SetBorderSize(pWin);
1463
1464        ResizeChildrenWinSize(pWin, 0, 0, 0, 0);
1465
1466        if (WasViewable) {
1467            (*pScreen->MarkOverlappedWindows) (pWin, pWin, NULL);
1468            (*pScreen->ValidateTree) (pWin->parent, NullWindow, VTOther);
1469            (*pScreen->HandleExposures) (pWin->parent);
1470            if (pScreen->PostValidateTree)
1471                (*pScreen->PostValidateTree) (pWin->parent, NullWindow,
1472                                              VTOther);
1473        }
1474    }
1475    if (pWin->realized)
1476        WindowsRestructured();
1477    CheckCursorConfinement(pWin);
1478}
1479
1480static void
1481miOverlayChangeBorderWidth(WindowPtr pWin, unsigned int width)
1482{
1483    int oldwidth;
1484    ScreenPtr pScreen;
1485    Bool WasViewable = (Bool) (pWin->viewable);
1486    Bool HadBorder;
1487
1488    oldwidth = wBorderWidth(pWin);
1489    if (oldwidth == width)
1490        return;
1491    HadBorder = HasBorder(pWin);
1492    pScreen = pWin->drawable.pScreen;
1493    if (WasViewable && (width < oldwidth))
1494        (*pScreen->MarkOverlappedWindows) (pWin, pWin, NULL);
1495
1496    pWin->borderWidth = width;
1497    SetBorderSize(pWin);
1498
1499    if (WasViewable) {
1500        if (width > oldwidth) {
1501            (*pScreen->MarkOverlappedWindows) (pWin, pWin, NULL);
1502
1503            if (HadBorder) {
1504                RegionPtr borderVisible;
1505
1506                borderVisible = RegionCreate(NULL, 1);
1507                RegionSubtract(borderVisible,
1508                               &pWin->borderClip, &pWin->winSize);
1509                pWin->valdata->before.borderVisible = borderVisible;
1510                if (IN_UNDERLAY(pWin)) {
1511                    miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
1512                    RegionPtr borderVisible2;
1513
1514                    borderVisible2 = RegionCreate(NULL, 1);
1515                    RegionSubtract(borderVisible2,
1516                                   &pTree->borderClip, &pWin->winSize);
1517                    pTree->valdata->borderVisible = borderVisible2;
1518                }
1519            }
1520        }
1521        (*pScreen->ValidateTree) (pWin->parent, pWin, VTOther);
1522        (*pScreen->HandleExposures) (pWin->parent);
1523
1524        if (pScreen->PostValidateTree)
1525            (*pScreen->PostValidateTree) (pWin->parent, pWin, VTOther);
1526    }
1527    if (pWin->realized)
1528        WindowsRestructured();
1529}
1530
1531/*  We need this as an addition since the xf86 common code doesn't
1532    know about the second tree which is static to this file.  */
1533
1534void
1535miOverlaySetRootClip(ScreenPtr pScreen, Bool enable)
1536{
1537    WindowPtr pRoot = pScreen->root;
1538    miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pRoot);
1539
1540    MARK_UNDERLAY(pRoot);
1541
1542    if (enable) {
1543        BoxRec box;
1544
1545        box.x1 = 0;
1546        box.y1 = 0;
1547        box.x2 = pScreen->width;
1548        box.y2 = pScreen->height;
1549
1550        RegionReset(&pTree->borderClip, &box);
1551    }
1552    else
1553        RegionEmpty(&pTree->borderClip);
1554
1555    RegionBreak(&pTree->clipList);
1556}
1557
1558static void
1559miOverlayClearToBackground(WindowPtr pWin,
1560                           int x, int y, int w, int h, Bool generateExposures)
1561{
1562    miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
1563    BoxRec box;
1564    RegionRec reg;
1565    ScreenPtr pScreen = pWin->drawable.pScreen;
1566    miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
1567    RegionPtr clipList;
1568    BoxPtr extents;
1569    int x1, y1, x2, y2;
1570
1571    x1 = pWin->drawable.x + x;
1572    y1 = pWin->drawable.y + y;
1573    if (w)
1574        x2 = x1 + (int) w;
1575    else
1576        x2 = x1 + (int) pWin->drawable.width - (int) x;
1577    if (h)
1578        y2 = y1 + h;
1579    else
1580        y2 = y1 + (int) pWin->drawable.height - (int) y;
1581
1582    clipList = ((*pScreenPriv->InOverlay) (pWin)) ? &pWin->clipList :
1583        &pTree->clipList;
1584
1585    extents = RegionExtents(clipList);
1586
1587    if (x1 < extents->x1)
1588        x1 = extents->x1;
1589    if (x2 > extents->x2)
1590        x2 = extents->x2;
1591    if (y1 < extents->y1)
1592        y1 = extents->y1;
1593    if (y2 > extents->y2)
1594        y2 = extents->y2;
1595
1596    if (x2 <= x1 || y2 <= y1)
1597        x2 = x1 = y2 = y1 = 0;
1598
1599    box.x1 = x1;
1600    box.x2 = x2;
1601    box.y1 = y1;
1602    box.y2 = y2;
1603
1604    RegionInit(&reg, &box, 1);
1605
1606    RegionIntersect(&reg, &reg, clipList);
1607    if (generateExposures)
1608        (*pScreen->WindowExposures) (pWin, &reg);
1609    else if (pWin->backgroundState != None)
1610        pScreen->PaintWindow(pWin, &reg, PW_BACKGROUND);
1611    RegionUninit(&reg);
1612}
1613
1614/****************************************************************/
1615
1616/* not used */
1617Bool
1618miOverlayGetPrivateClips(WindowPtr pWin,
1619                         RegionPtr *borderClip, RegionPtr *clipList)
1620{
1621    miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
1622
1623    if (pTree) {
1624        *borderClip = &(pTree->borderClip);
1625        *clipList = &(pTree->clipList);
1626        return TRUE;
1627    }
1628
1629    *borderClip = *clipList = NULL;
1630
1631    return FALSE;
1632}
1633
1634void
1635miOverlaySetTransFunction(ScreenPtr pScreen, miOverlayTransFunc transFunc)
1636{
1637    MIOVERLAY_GET_SCREEN_PRIVATE(pScreen)->MakeTransparent = transFunc;
1638}
1639
1640Bool
1641miOverlayCopyUnderlay(ScreenPtr pScreen)
1642{
1643    return MIOVERLAY_GET_SCREEN_PRIVATE(pScreen)->copyUnderlay;
1644}
1645
1646void
1647miOverlayComputeCompositeClip(GCPtr pGC, WindowPtr pWin)
1648{
1649    miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
1650    RegionPtr pregWin;
1651    Bool freeTmpClip, freeCompClip;
1652
1653    if (!pTree) {
1654        miComputeCompositeClip(pGC, &pWin->drawable);
1655        return;
1656    }
1657
1658    if (pGC->subWindowMode == IncludeInferiors) {
1659        pregWin = RegionCreate(NullBox, 1);
1660        freeTmpClip = TRUE;
1661        if (pWin->parent || (screenIsSaved != SCREEN_SAVER_ON) ||
1662            !HasSaverWindow(pGC->pScreen)) {
1663            RegionIntersect(pregWin, &pTree->borderClip, &pWin->winSize);
1664        }
1665    }
1666    else {
1667        pregWin = &pTree->clipList;
1668        freeTmpClip = FALSE;
1669    }
1670    freeCompClip = pGC->freeCompClip;
1671    if (!pGC->clientClip) {
1672        if (freeCompClip)
1673            RegionDestroy(pGC->pCompositeClip);
1674        pGC->pCompositeClip = pregWin;
1675        pGC->freeCompClip = freeTmpClip;
1676    }
1677    else {
1678        RegionTranslate(pGC->clientClip,
1679                        pWin->drawable.x + pGC->clipOrg.x,
1680                        pWin->drawable.y + pGC->clipOrg.y);
1681
1682        if (freeCompClip) {
1683            RegionIntersect(pGC->pCompositeClip, pregWin, pGC->clientClip);
1684            if (freeTmpClip)
1685                RegionDestroy(pregWin);
1686        }
1687        else if (freeTmpClip) {
1688            RegionIntersect(pregWin, pregWin, pGC->clientClip);
1689            pGC->pCompositeClip = pregWin;
1690        }
1691        else {
1692            pGC->pCompositeClip = RegionCreate(NullBox, 0);
1693            RegionIntersect(pGC->pCompositeClip, pregWin, pGC->clientClip);
1694        }
1695        pGC->freeCompClip = TRUE;
1696        RegionTranslate(pGC->clientClip,
1697                        -(pWin->drawable.x + pGC->clipOrg.x),
1698                        -(pWin->drawable.y + pGC->clipOrg.y));
1699    }
1700}
1701
1702Bool
1703miOverlayCollectUnderlayRegions(WindowPtr pWin, RegionPtr *region)
1704{
1705    miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
1706
1707    if (pTree) {
1708        *region = &pTree->borderClip;
1709        return FALSE;
1710    }
1711
1712    *region = RegionCreate(NullBox, 0);
1713
1714    CollectUnderlayChildrenRegions(pWin, *region);
1715
1716    return TRUE;
1717}
1718
1719static miOverlayTreePtr
1720DoLeaf(WindowPtr pWin, miOverlayTreePtr parent, miOverlayTreePtr prevSib)
1721{
1722    miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
1723
1724    pTree->parent = parent;
1725    pTree->firstChild = NULL;
1726    pTree->lastChild = NULL;
1727    pTree->prevSib = prevSib;
1728    pTree->nextSib = NULL;
1729
1730    if (prevSib)
1731        prevSib->nextSib = pTree;
1732
1733    if (!parent->firstChild)
1734        parent->firstChild = parent->lastChild = pTree;
1735    else if (parent->lastChild == prevSib)
1736        parent->lastChild = pTree;
1737
1738    return pTree;
1739}
1740
1741static void
1742RebuildTree(WindowPtr pWin)
1743{
1744    miOverlayTreePtr parent, prevSib, tChild;
1745    WindowPtr pChild;
1746
1747    prevSib = tChild = NULL;
1748
1749    pWin = pWin->parent;
1750
1751    while (IN_OVERLAY(pWin))
1752        pWin = pWin->parent;
1753
1754    parent = MIOVERLAY_GET_WINDOW_TREE(pWin);
1755
1756    pChild = pWin->firstChild;
1757    parent->firstChild = parent->lastChild = NULL;
1758
1759    while (1) {
1760        if (IN_UNDERLAY(pChild))
1761            prevSib = tChild = DoLeaf(pChild, parent, prevSib);
1762
1763        if (pChild->firstChild) {
1764            if (IN_UNDERLAY(pChild)) {
1765                parent = tChild;
1766                prevSib = NULL;
1767            }
1768            pChild = pChild->firstChild;
1769            continue;
1770        }
1771
1772        while (!pChild->nextSib) {
1773            pChild = pChild->parent;
1774            if (pChild == pWin)
1775                return;
1776            if (IN_UNDERLAY(pChild)) {
1777                prevSib = tChild = MIOVERLAY_GET_WINDOW_TREE(pChild);
1778                parent = tChild->parent;
1779            }
1780        }
1781
1782        pChild = pChild->nextSib;
1783    }
1784}
1785
1786static Bool
1787HasUnderlayChildren(WindowPtr pWin)
1788{
1789    WindowPtr pChild;
1790
1791    if (!(pChild = pWin->firstChild))
1792        return FALSE;
1793
1794    while (1) {
1795        if (IN_UNDERLAY(pChild))
1796            return TRUE;
1797
1798        if (pChild->firstChild) {
1799            pChild = pChild->firstChild;
1800            continue;
1801        }
1802
1803        while (!pChild->nextSib && (pWin != pChild))
1804            pChild = pChild->parent;
1805
1806        if (pChild == pWin)
1807            break;
1808
1809        pChild = pChild->nextSib;
1810    }
1811
1812    return FALSE;
1813}
1814
1815static Bool
1816CollectUnderlayChildrenRegions(WindowPtr pWin, RegionPtr pReg)
1817{
1818    WindowPtr pChild;
1819    miOverlayTreePtr pTree;
1820    Bool hasUnderlay;
1821
1822    if (!(pChild = pWin->firstChild))
1823        return FALSE;
1824
1825    hasUnderlay = FALSE;
1826
1827    while (1) {
1828        if ((pTree = MIOVERLAY_GET_WINDOW_TREE(pChild))) {
1829            RegionAppend(pReg, &pTree->borderClip);
1830            hasUnderlay = TRUE;
1831        }
1832        else if (pChild->firstChild) {
1833            pChild = pChild->firstChild;
1834            continue;
1835        }
1836
1837        while (!pChild->nextSib && (pWin != pChild))
1838            pChild = pChild->parent;
1839
1840        if (pChild == pWin)
1841            break;
1842
1843        pChild = pChild->nextSib;
1844    }
1845
1846    if (hasUnderlay) {
1847        Bool overlap;
1848
1849        RegionValidate(pReg, &overlap);
1850    }
1851
1852    return hasUnderlay;
1853}
1854
1855static void
1856MarkUnderlayWindow(WindowPtr pWin)
1857{
1858    miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
1859
1860    if (pTree->valdata)
1861        return;
1862    pTree->valdata =
1863        (miOverlayValDataPtr) xnfalloc(sizeof(miOverlayValDataRec));
1864    pTree->valdata->oldAbsCorner.x = pWin->drawable.x;
1865    pTree->valdata->oldAbsCorner.y = pWin->drawable.y;
1866    pTree->valdata->borderVisible = NullRegion;
1867}
1868