window.c revision 7e31ba66
1/*
2
3Copyright (c) 2006, Red Hat, Inc.
4
5Permission is hereby granted, free of charge, to any person obtaining a
6copy of this software and associated documentation files (the "Software"),
7to deal in the Software without restriction, including without limitation
8the rights to use, copy, modify, merge, publish, distribute, sublicense,
9and/or sell copies of the Software, and to permit persons to whom the
10Software is furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice (including the next
13paragraph) shall be included in all copies or substantial portions of the
14Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22DEALINGS IN THE SOFTWARE.
23
24Copyright 1987, 1998  The Open Group
25
26Permission to use, copy, modify, distribute, and sell this software and its
27documentation for any purpose is hereby granted without fee, provided that
28the above copyright notice appear in all copies and that both that
29copyright notice and this permission notice appear in supporting
30documentation.
31
32The above copyright notice and this permission notice shall be included
33in all copies or substantial portions of the Software.
34
35THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
36OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
37MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
38IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
39OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
40ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
41OTHER DEALINGS IN THE SOFTWARE.
42
43Except as contained in this notice, the name of The Open Group shall
44not be used in advertising or otherwise to promote the sale, use or
45other dealings in this Software without prior written authorization
46from The Open Group.
47
48Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
49
50			All Rights Reserved
51
52Permission to use, copy, modify, and distribute this software and its
53documentation for any purpose and without fee is hereby granted,
54provided that the above copyright notice appear in all copies and that
55both that copyright notice and this permission notice appear in
56supporting documentation, and that the name of Digital not be
57used in advertising or publicity pertaining to distribution of the
58software without specific, written prior permission.
59
60DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
61ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
62DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
63ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
64WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
65ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
66SOFTWARE.
67
68*/
69
70/* The panoramix components contained the following notice */
71/*****************************************************************
72
73Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.
74
75Permission is hereby granted, free of charge, to any person obtaining a copy
76of this software and associated documentation files (the "Software"), to deal
77in the Software without restriction, including without limitation the rights
78to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
79copies of the Software.
80
81The above copyright notice and this permission notice shall be included in
82all copies or substantial portions of the Software.
83
84THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
85IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
86FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
87DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
88BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
89WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
90IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
91
92Except as contained in this notice, the name of Digital Equipment Corporation
93shall not be used in advertising or otherwise to promote the sale, use or other
94dealings in this Software without prior written authorization from Digital
95Equipment Corporation.
96
97******************************************************************/
98
99#ifdef HAVE_DIX_CONFIG_H
100#include <dix-config.h>
101#endif
102
103#include "misc.h"
104#include "scrnintstr.h"
105#include "os.h"
106#include "regionstr.h"
107#include "validate.h"
108#include "windowstr.h"
109#include "propertyst.h"
110#include "input.h"
111#include "inputstr.h"
112#include "resource.h"
113#include "colormapst.h"
114#include "cursorstr.h"
115#include "dixstruct.h"
116#include "gcstruct.h"
117#include "servermd.h"
118#include "mivalidate.h"
119#ifdef PANORAMIX
120#include "panoramiX.h"
121#include "panoramiXsrv.h"
122#endif
123#include "dixevents.h"
124#include "globals.h"
125#include "mi.h"                 /* miPaintWindow */
126#ifdef COMPOSITE
127#include "compint.h"
128#endif
129#include "selection.h"
130#include "inpututils.h"
131
132#include "privates.h"
133#include "xace.h"
134#include "exevents.h"
135
136#include <X11/Xatom.h>          /* must come after server includes */
137
138/******
139 * Window stuff for server
140 *
141 *    CreateRootWindow, CreateWindow, ChangeWindowAttributes,
142 *    GetWindowAttributes, DeleteWindow, DestroySubWindows,
143 *    HandleSaveSet, ReparentWindow, MapWindow, MapSubWindows,
144 *    UnmapWindow, UnmapSubWindows, ConfigureWindow, CirculateWindow,
145 *    ChangeWindowDeviceCursor
146 ******/
147
148Bool bgNoneRoot = FALSE;
149
150static unsigned char _back_lsb[4] = { 0x88, 0x22, 0x44, 0x11 };
151static unsigned char _back_msb[4] = { 0x11, 0x44, 0x22, 0x88 };
152
153static Bool WindowParentHasDeviceCursor(WindowPtr pWin,
154                                        DeviceIntPtr pDev, CursorPtr pCurs);
155static Bool
156
157WindowSeekDeviceCursor(WindowPtr pWin,
158                       DeviceIntPtr pDev,
159                       DevCursNodePtr * pNode, DevCursNodePtr * pPrev);
160
161int screenIsSaved = SCREEN_SAVER_OFF;
162
163static Bool TileScreenSaver(ScreenPtr pScreen, int kind);
164
165#define INPUTONLY_LEGAL_MASK (CWWinGravity | CWEventMask | \
166			      CWDontPropagate | CWOverrideRedirect | CWCursor )
167
168#define BOXES_OVERLAP(b1, b2) \
169      (!( ((b1)->x2 <= (b2)->x1)  || \
170	( ((b1)->x1 >= (b2)->x2)) || \
171	( ((b1)->y2 <= (b2)->y1)) || \
172	( ((b1)->y1 >= (b2)->y2)) ) )
173
174#define RedirectSend(pWin) \
175    ((pWin->eventMask|wOtherEventMasks(pWin)) & SubstructureRedirectMask)
176
177#define SubSend(pWin) \
178    ((pWin->eventMask|wOtherEventMasks(pWin)) & SubstructureNotifyMask)
179
180#define StrSend(pWin) \
181    ((pWin->eventMask|wOtherEventMasks(pWin)) & StructureNotifyMask)
182
183#define SubStrSend(pWin,pParent) (StrSend(pWin) || SubSend(pParent))
184
185#ifdef COMPOSITE
186static const char *overlay_win_name = "<composite overlay>";
187#endif
188
189static const char *
190get_window_name(WindowPtr pWin)
191{
192#define WINDOW_NAME_BUF_LEN 512
193    PropertyPtr prop;
194    static char buf[WINDOW_NAME_BUF_LEN];
195    int len;
196
197#ifdef COMPOSITE
198    CompScreenPtr comp_screen = GetCompScreen(pWin->drawable.pScreen);
199
200    if (comp_screen && pWin == comp_screen->pOverlayWin)
201        return overlay_win_name;
202#endif
203
204    for (prop = wUserProps(pWin); prop; prop = prop->next) {
205        if (prop->propertyName == XA_WM_NAME && prop->type == XA_STRING &&
206            prop->data) {
207            len = min(prop->size, WINDOW_NAME_BUF_LEN - 1);
208            memcpy(buf, prop->data, len);
209            buf[len] = '\0';
210            return buf;
211        }
212    }
213
214    return NULL;
215#undef WINDOW_NAME_BUF_LEN
216}
217
218static void
219log_window_info(WindowPtr pWin, int depth)
220{
221    int i;
222    const char *win_name, *visibility;
223    BoxPtr rects;
224
225    for (i = 0; i < (depth << 2); i++)
226        ErrorF(" ");
227
228    win_name = get_window_name(pWin);
229    ErrorF("win 0x%.8x (%s), [%d, %d] to [%d, %d]",
230           (unsigned) pWin->drawable.id,
231           win_name ? win_name : "no name",
232           pWin->drawable.x, pWin->drawable.y,
233           pWin->drawable.x + pWin->drawable.width,
234           pWin->drawable.y + pWin->drawable.height);
235
236    if (pWin->overrideRedirect)
237        ErrorF(" (override redirect)");
238#ifdef COMPOSITE
239    if (pWin->redirectDraw)
240        ErrorF(" (%s compositing: pixmap %x)",
241               (pWin->redirectDraw == RedirectDrawAutomatic) ?
242               "automatic" : "manual",
243               (unsigned) pWin->drawable.pScreen->GetWindowPixmap(pWin)->drawable.id);
244#endif
245
246    switch (pWin->visibility) {
247    case VisibilityUnobscured:
248        visibility = "unobscured";
249        break;
250    case VisibilityPartiallyObscured:
251        visibility = "partially obscured";
252        break;
253    case VisibilityFullyObscured:
254        visibility = "fully obscured";
255        break;
256    case VisibilityNotViewable:
257        visibility = "unviewable";
258        break;
259    }
260    ErrorF(", %s", visibility);
261
262    if (RegionNotEmpty(&pWin->clipList)) {
263        ErrorF(", clip list:");
264        rects = RegionRects(&pWin->clipList);
265        for (i = 0; i < RegionNumRects(&pWin->clipList); i++)
266            ErrorF(" [(%d, %d) to (%d, %d)]",
267                   rects[i].x1, rects[i].y1, rects[i].x2, rects[i].y2);
268        ErrorF("; extents [(%d, %d) to (%d, %d)]",
269               pWin->clipList.extents.x1, pWin->clipList.extents.y1,
270               pWin->clipList.extents.x2, pWin->clipList.extents.y2);
271    }
272
273    ErrorF("\n");
274}
275
276static const char*
277grab_grabtype_to_text(GrabPtr pGrab)
278{
279    switch (pGrab->grabtype) {
280        case XI2:
281            return "xi2";
282        case CORE:
283            return "core";
284        default:
285            return "xi1";
286    }
287}
288
289static const char*
290grab_type_to_text(GrabPtr pGrab)
291{
292    switch (pGrab->type) {
293        case ButtonPress:
294            return "ButtonPress";
295        case KeyPress:
296            return "KeyPress";
297        case XI_Enter:
298            return "XI_Enter";
299        case XI_FocusIn:
300            return "XI_FocusIn";
301        default:
302            return "unknown?!";
303    }
304}
305
306static void
307log_grab_info(void *value, XID id, void *cdata)
308{
309    int i, j;
310    GrabPtr pGrab = (GrabPtr)value;
311
312    ErrorF("  grab 0x%lx (%s), type '%s' on window 0x%lx\n",
313           (unsigned long) pGrab->resource,
314           grab_grabtype_to_text(pGrab),
315           grab_type_to_text(pGrab),
316           (unsigned long) pGrab->window->drawable.id);
317    ErrorF("    detail %d (mask %lu), modifiersDetail %d (mask %lu)\n",
318           pGrab->detail.exact,
319           pGrab->detail.pMask ? (unsigned long) *(pGrab->detail.pMask) : 0,
320           pGrab->modifiersDetail.exact,
321           pGrab->modifiersDetail.pMask ?
322           (unsigned long) *(pGrab->modifiersDetail.pMask) :
323           (unsigned long) 0);
324    ErrorF("    device '%s' (%d), modifierDevice '%s' (%d)\n",
325           pGrab->device->name, pGrab->device->id,
326           pGrab->modifierDevice->name, pGrab->modifierDevice->id);
327    if (pGrab->grabtype == CORE) {
328        ErrorF("    core event mask 0x%lx\n",
329               (unsigned long) pGrab->eventMask);
330    }
331    else if (pGrab->grabtype == XI) {
332        ErrorF("    xi1 event mask 0x%lx\n",
333               (unsigned long) pGrab->eventMask);
334    }
335    else if (pGrab->grabtype == XI2) {
336        for (i = 0; i < xi2mask_num_masks(pGrab->xi2mask); i++) {
337            const unsigned char *mask;
338            int print;
339
340            print = 0;
341            for (j = 0; j < XI2MASKSIZE; j++) {
342                mask = xi2mask_get_one_mask(pGrab->xi2mask, i);
343                if (mask[j]) {
344                    print = 1;
345                    break;
346                }
347            }
348            if (!print)
349                continue;
350            ErrorF("      xi2 event mask 0x");
351            for (j = 0; j < xi2mask_mask_size(pGrab->xi2mask); j++)
352                ErrorF("%x ", mask[j]);
353            ErrorF("\n");
354        }
355    }
356    ErrorF("    owner-events %s, kb %d ptr %d, confine 0x%lx, cursor 0x%lx\n",
357           pGrab->ownerEvents ? "true" : "false",
358           pGrab->keyboardMode, pGrab->pointerMode,
359           pGrab->confineTo ? (unsigned long) pGrab->confineTo->drawable.id : 0,
360           pGrab->cursor ? (unsigned long) pGrab->cursor->id : 0);
361}
362
363void
364PrintPassiveGrabs(void)
365{
366    int i;
367    LocalClientCredRec *lcc;
368    pid_t clientpid;
369    const char *cmdname;
370    const char *cmdargs;
371
372    ErrorF("Printing all currently registered grabs\n");
373
374    for (i = 1; i < currentMaxClients; i++) {
375        if (!clients[i] || clients[i]->clientState != ClientStateRunning)
376            continue;
377
378        clientpid = GetClientPid(clients[i]);
379        cmdname = GetClientCmdName(clients[i]);
380        cmdargs = GetClientCmdArgs(clients[i]);
381        if ((clientpid > 0) && (cmdname != NULL)) {
382            ErrorF("  Printing all registered grabs of client pid %ld %s %s\n",
383                   (long) clientpid, cmdname, cmdargs ? cmdargs : "");
384        } else {
385            if (GetLocalClientCreds(clients[i], &lcc) == -1) {
386                ErrorF("  GetLocalClientCreds() failed\n");
387                continue;
388            }
389            ErrorF("  Printing all registered grabs of client pid %ld uid %ld gid %ld\n",
390                   (lcc->fieldsSet & LCC_PID_SET) ? (long) lcc->pid : 0,
391                   (lcc->fieldsSet & LCC_UID_SET) ? (long) lcc->euid : 0,
392                   (lcc->fieldsSet & LCC_GID_SET) ? (long) lcc->egid : 0);
393            FreeLocalClientCreds(lcc);
394        }
395
396        FindClientResourcesByType(clients[i], RT_PASSIVEGRAB, log_grab_info, NULL);
397    }
398    ErrorF("End list of registered passive grabs\n");
399}
400
401void
402PrintWindowTree(void)
403{
404    int scrnum, depth;
405    ScreenPtr pScreen;
406    WindowPtr pWin;
407
408    for (scrnum = 0; scrnum < screenInfo.numScreens; scrnum++) {
409        pScreen = screenInfo.screens[scrnum];
410        ErrorF("[dix] Dumping windows for screen %d (pixmap %x):\n", scrnum,
411               (unsigned) pScreen->GetScreenPixmap(pScreen)->drawable.id);
412        pWin = pScreen->root;
413        depth = 1;
414        while (pWin) {
415            log_window_info(pWin, depth);
416            if (pWin->firstChild) {
417                pWin = pWin->firstChild;
418                depth++;
419                continue;
420            }
421            while (pWin && !pWin->nextSib) {
422                pWin = pWin->parent;
423                depth--;
424            }
425            if (!pWin)
426                break;
427            pWin = pWin->nextSib;
428        }
429    }
430}
431
432int
433TraverseTree(WindowPtr pWin, VisitWindowProcPtr func, void *data)
434{
435    int result;
436    WindowPtr pChild;
437
438    if (!(pChild = pWin))
439        return WT_NOMATCH;
440    while (1) {
441        result = (*func) (pChild, data);
442        if (result == WT_STOPWALKING)
443            return WT_STOPWALKING;
444        if ((result == WT_WALKCHILDREN) && pChild->firstChild) {
445            pChild = pChild->firstChild;
446            continue;
447        }
448        while (!pChild->nextSib && (pChild != pWin))
449            pChild = pChild->parent;
450        if (pChild == pWin)
451            break;
452        pChild = pChild->nextSib;
453    }
454    return WT_NOMATCH;
455}
456
457/*****
458 * WalkTree
459 *   Walk the window tree, for SCREEN, performing FUNC(pWin, data) on
460 *   each window.  If FUNC returns WT_WALKCHILDREN, traverse the children,
461 *   if it returns WT_DONTWALKCHILDREN, don't.  If it returns WT_STOPWALKING,
462 *   exit WalkTree.  Does depth-first traverse.
463 *****/
464
465int
466WalkTree(ScreenPtr pScreen, VisitWindowProcPtr func, void *data)
467{
468    return (TraverseTree(pScreen->root, func, data));
469}
470
471/* hack for forcing backing store on all windows */
472int defaultBackingStore = NotUseful;
473
474/* hack to force no backing store */
475Bool disableBackingStore = FALSE;
476Bool enableBackingStore = FALSE;
477
478static void
479SetWindowToDefaults(WindowPtr pWin)
480{
481    pWin->prevSib = NullWindow;
482    pWin->firstChild = NullWindow;
483    pWin->lastChild = NullWindow;
484
485    pWin->valdata = NULL;
486    pWin->optional = NULL;
487    pWin->cursorIsNone = TRUE;
488
489    pWin->backingStore = NotUseful;
490    pWin->backStorage = 0;
491
492    pWin->mapped = FALSE;       /* off */
493    pWin->realized = FALSE;     /* off */
494    pWin->viewable = FALSE;
495    pWin->visibility = VisibilityNotViewable;
496    pWin->overrideRedirect = FALSE;
497    pWin->saveUnder = FALSE;
498
499    pWin->bitGravity = ForgetGravity;
500    pWin->winGravity = NorthWestGravity;
501
502    pWin->eventMask = 0;
503    pWin->deliverableEvents = 0;
504    pWin->dontPropagate = 0;
505    pWin->forcedBS = FALSE;
506    pWin->redirectDraw = RedirectDrawNone;
507    pWin->forcedBG = FALSE;
508    pWin->unhittable = FALSE;
509
510#ifdef COMPOSITE
511    pWin->damagedDescendants = FALSE;
512#endif
513}
514
515static void
516MakeRootTile(WindowPtr pWin)
517{
518    ScreenPtr pScreen = pWin->drawable.pScreen;
519    GCPtr pGC;
520    unsigned char back[128];
521    int len = BitmapBytePad(sizeof(long));
522    unsigned char *from, *to;
523    int i, j;
524
525    pWin->background.pixmap = (*pScreen->CreatePixmap) (pScreen, 4, 4,
526                                                        pScreen->rootDepth, 0);
527
528    pWin->backgroundState = BackgroundPixmap;
529    pGC = GetScratchGC(pScreen->rootDepth, pScreen);
530    if (!pWin->background.pixmap || !pGC)
531        FatalError("could not create root tile");
532
533    {
534        ChangeGCVal attributes[2];
535
536        attributes[0].val = pScreen->whitePixel;
537        attributes[1].val = pScreen->blackPixel;
538
539        (void) ChangeGC(NullClient, pGC, GCForeground | GCBackground,
540                        attributes);
541    }
542
543    ValidateGC((DrawablePtr) pWin->background.pixmap, pGC);
544
545    from = (screenInfo.bitmapBitOrder == LSBFirst) ? _back_lsb : _back_msb;
546    to = back;
547
548    for (i = 4; i > 0; i--, from++)
549        for (j = len; j > 0; j--)
550            *to++ = *from;
551
552    (*pGC->ops->PutImage) ((DrawablePtr) pWin->background.pixmap, pGC, 1,
553                           0, 0, len, 4, 0, XYBitmap, (char *) back);
554
555    FreeScratchGC(pGC);
556
557}
558
559/*****
560 * CreateRootWindow
561 *    Makes a window at initialization time for specified screen
562 *****/
563
564Bool
565CreateRootWindow(ScreenPtr pScreen)
566{
567    WindowPtr pWin;
568    BoxRec box;
569    PixmapFormatRec *format;
570
571    pWin = dixAllocateScreenObjectWithPrivates(pScreen, WindowRec, PRIVATE_WINDOW);
572    if (!pWin)
573        return FALSE;
574
575    pScreen->screensaver.pWindow = NULL;
576    pScreen->screensaver.wid = FakeClientID(0);
577    pScreen->screensaver.ExternalScreenSaver = NULL;
578    screenIsSaved = SCREEN_SAVER_OFF;
579
580    pScreen->root = pWin;
581
582    pWin->drawable.pScreen = pScreen;
583    pWin->drawable.type = DRAWABLE_WINDOW;
584
585    pWin->drawable.depth = pScreen->rootDepth;
586    for (format = screenInfo.formats;
587         format->depth != pScreen->rootDepth; format++);
588    pWin->drawable.bitsPerPixel = format->bitsPerPixel;
589
590    pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER;
591
592    pWin->parent = NullWindow;
593    SetWindowToDefaults(pWin);
594
595    pWin->optional = malloc(sizeof(WindowOptRec));
596    if (!pWin->optional)
597        return FALSE;
598
599    pWin->optional->dontPropagateMask = 0;
600    pWin->optional->otherEventMasks = 0;
601    pWin->optional->otherClients = NULL;
602    pWin->optional->passiveGrabs = NULL;
603    pWin->optional->userProps = NULL;
604    pWin->optional->backingBitPlanes = ~0L;
605    pWin->optional->backingPixel = 0;
606    pWin->optional->boundingShape = NULL;
607    pWin->optional->clipShape = NULL;
608    pWin->optional->inputShape = NULL;
609    pWin->optional->inputMasks = NULL;
610    pWin->optional->deviceCursors = NULL;
611    pWin->optional->colormap = pScreen->defColormap;
612    pWin->optional->visual = pScreen->rootVisual;
613
614    pWin->nextSib = NullWindow;
615
616    pWin->drawable.id = FakeClientID(0);
617
618    pWin->origin.x = pWin->origin.y = 0;
619    pWin->drawable.height = pScreen->height;
620    pWin->drawable.width = pScreen->width;
621    pWin->drawable.x = pWin->drawable.y = 0;
622
623    box.x1 = 0;
624    box.y1 = 0;
625    box.x2 = pScreen->width;
626    box.y2 = pScreen->height;
627    RegionInit(&pWin->clipList, &box, 1);
628    RegionInit(&pWin->winSize, &box, 1);
629    RegionInit(&pWin->borderSize, &box, 1);
630    RegionInit(&pWin->borderClip, &box, 1);
631
632    pWin->drawable.class = InputOutput;
633    pWin->optional->visual = pScreen->rootVisual;
634
635    pWin->backgroundState = BackgroundPixel;
636    pWin->background.pixel = pScreen->whitePixel;
637
638    pWin->borderIsPixel = TRUE;
639    pWin->border.pixel = pScreen->blackPixel;
640    pWin->borderWidth = 0;
641
642    /*  security creation/labeling check
643     */
644    if (XaceHook(XACE_RESOURCE_ACCESS, serverClient, pWin->drawable.id,
645                 RT_WINDOW, pWin, RT_NONE, NULL, DixCreateAccess))
646        return FALSE;
647
648    if (!AddResource(pWin->drawable.id, RT_WINDOW, (void *) pWin))
649        return FALSE;
650
651    if (disableBackingStore)
652        pScreen->backingStoreSupport = NotUseful;
653    if (enableBackingStore)
654        pScreen->backingStoreSupport = WhenMapped;
655#ifdef COMPOSITE
656    if (noCompositeExtension)
657        pScreen->backingStoreSupport = NotUseful;
658#endif
659
660    pScreen->saveUnderSupport = NotUseful;
661
662    return TRUE;
663}
664
665void
666InitRootWindow(WindowPtr pWin)
667{
668    ScreenPtr pScreen = pWin->drawable.pScreen;
669    int backFlag = CWBorderPixel | CWCursor | CWBackingStore;
670
671    if (!(*pScreen->CreateWindow) (pWin))
672        return;                 /* XXX */
673    (*pScreen->PositionWindow) (pWin, 0, 0);
674
675    pWin->cursorIsNone = FALSE;
676    pWin->optional->cursor = RefCursor(rootCursor);
677
678    if (party_like_its_1989) {
679        MakeRootTile(pWin);
680        backFlag |= CWBackPixmap;
681    }
682    else if (pScreen->canDoBGNoneRoot && bgNoneRoot) {
683        pWin->backgroundState = XaceBackgroundNoneState(pWin);
684        pWin->background.pixel = pScreen->whitePixel;
685        backFlag |= CWBackPixmap;
686    }
687    else {
688        pWin->backgroundState = BackgroundPixel;
689        if (whiteRoot)
690            pWin->background.pixel = pScreen->whitePixel;
691        else
692            pWin->background.pixel = pScreen->blackPixel;
693        backFlag |= CWBackPixel;
694    }
695
696    pWin->backingStore = defaultBackingStore;
697    pWin->forcedBS = (defaultBackingStore != NotUseful);
698    /* We SHOULD check for an error value here XXX */
699    (*pScreen->ChangeWindowAttributes) (pWin, backFlag);
700
701    MapWindow(pWin, serverClient);
702}
703
704/* Set the region to the intersection of the rectangle and the
705 * window's winSize.  The window is typically the parent of the
706 * window from which the region came.
707 */
708
709static void
710ClippedRegionFromBox(WindowPtr pWin, RegionPtr Rgn, int x, int y, int w, int h)
711{
712    BoxRec box = *RegionExtents(&pWin->winSize);
713
714    /* we do these calculations to avoid overflows */
715    if (x > box.x1)
716        box.x1 = x;
717    if (y > box.y1)
718        box.y1 = y;
719    x += w;
720    if (x < box.x2)
721        box.x2 = x;
722    y += h;
723    if (y < box.y2)
724        box.y2 = y;
725    if (box.x1 > box.x2)
726        box.x2 = box.x1;
727    if (box.y1 > box.y2)
728        box.y2 = box.y1;
729    RegionReset(Rgn, &box);
730    RegionIntersect(Rgn, Rgn, &pWin->winSize);
731}
732
733static RealChildHeadProc realChildHeadProc = NULL;
734
735void
736RegisterRealChildHeadProc(RealChildHeadProc proc)
737{
738    realChildHeadProc = proc;
739}
740
741WindowPtr
742RealChildHead(WindowPtr pWin)
743{
744    if (realChildHeadProc) {
745        return realChildHeadProc(pWin);
746    }
747
748    if (!pWin->parent &&
749        (screenIsSaved == SCREEN_SAVER_ON) &&
750        (HasSaverWindow(pWin->drawable.pScreen)))
751        return pWin->firstChild;
752    else
753        return NullWindow;
754}
755
756/*****
757 * CreateWindow
758 *    Makes a window in response to client request
759 *****/
760
761WindowPtr
762CreateWindow(Window wid, WindowPtr pParent, int x, int y, unsigned w,
763             unsigned h, unsigned bw, unsigned class, Mask vmask, XID *vlist,
764             int depth, ClientPtr client, VisualID visual, int *error)
765{
766    WindowPtr pWin;
767    WindowPtr pHead;
768    ScreenPtr pScreen;
769    int idepth, ivisual;
770    Bool fOK;
771    DepthPtr pDepth;
772    PixmapFormatRec *format;
773    WindowOptPtr ancwopt;
774
775    if (class == CopyFromParent)
776        class = pParent->drawable.class;
777
778    if ((class != InputOutput) && (class != InputOnly)) {
779        *error = BadValue;
780        client->errorValue = class;
781        return NullWindow;
782    }
783
784    if ((class != InputOnly) && (pParent->drawable.class == InputOnly)) {
785        *error = BadMatch;
786        return NullWindow;
787    }
788
789    if ((class == InputOnly) && ((bw != 0) || (depth != 0))) {
790        *error = BadMatch;
791        return NullWindow;
792    }
793
794    pScreen = pParent->drawable.pScreen;
795    if ((class == InputOutput) && (depth == 0))
796        depth = pParent->drawable.depth;
797    ancwopt = pParent->optional;
798    if (!ancwopt)
799        ancwopt = FindWindowWithOptional(pParent)->optional;
800    if (visual == CopyFromParent) {
801        visual = ancwopt->visual;
802    }
803
804    /* Find out if the depth and visual are acceptable for this Screen */
805    if ((visual != ancwopt->visual) || (depth != pParent->drawable.depth)) {
806        fOK = FALSE;
807        for (idepth = 0; idepth < pScreen->numDepths; idepth++) {
808            pDepth = (DepthPtr) &pScreen->allowedDepths[idepth];
809            if ((depth == pDepth->depth) || (depth == 0)) {
810                for (ivisual = 0; ivisual < pDepth->numVids; ivisual++) {
811                    if (visual == pDepth->vids[ivisual]) {
812                        fOK = TRUE;
813                        break;
814                    }
815                }
816            }
817        }
818        if (fOK == FALSE) {
819            *error = BadMatch;
820            return NullWindow;
821        }
822    }
823
824    if (((vmask & (CWBorderPixmap | CWBorderPixel)) == 0) &&
825        (class != InputOnly) && (depth != pParent->drawable.depth)) {
826        *error = BadMatch;
827        return NullWindow;
828    }
829
830    if (((vmask & CWColormap) == 0) &&
831        (class != InputOnly) &&
832        ((visual != ancwopt->visual) || (ancwopt->colormap == None))) {
833        *error = BadMatch;
834        return NullWindow;
835    }
836
837    pWin = dixAllocateScreenObjectWithPrivates(pScreen, WindowRec, PRIVATE_WINDOW);
838    if (!pWin) {
839        *error = BadAlloc;
840        return NullWindow;
841    }
842    pWin->drawable = pParent->drawable;
843    pWin->drawable.depth = depth;
844    if (depth == pParent->drawable.depth)
845        pWin->drawable.bitsPerPixel = pParent->drawable.bitsPerPixel;
846    else {
847        for (format = screenInfo.formats; format->depth != depth; format++);
848        pWin->drawable.bitsPerPixel = format->bitsPerPixel;
849    }
850    if (class == InputOnly)
851        pWin->drawable.type = (short) UNDRAWABLE_WINDOW;
852    pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER;
853
854    pWin->drawable.id = wid;
855    pWin->drawable.class = class;
856
857    pWin->parent = pParent;
858    SetWindowToDefaults(pWin);
859
860    if (visual != ancwopt->visual) {
861        if (!MakeWindowOptional(pWin)) {
862            dixFreeObjectWithPrivates(pWin, PRIVATE_WINDOW);
863            *error = BadAlloc;
864            return NullWindow;
865        }
866        pWin->optional->visual = visual;
867        pWin->optional->colormap = None;
868    }
869
870    pWin->borderWidth = bw;
871
872    /*  security creation/labeling check
873     */
874    *error = XaceHook(XACE_RESOURCE_ACCESS, client, wid, RT_WINDOW, pWin,
875                      RT_WINDOW, pWin->parent,
876                      DixCreateAccess | DixSetAttrAccess);
877    if (*error != Success) {
878        dixFreeObjectWithPrivates(pWin, PRIVATE_WINDOW);
879        return NullWindow;
880    }
881
882    pWin->backgroundState = XaceBackgroundNoneState(pWin);
883    pWin->background.pixel = pScreen->whitePixel;
884
885    pWin->borderIsPixel = pParent->borderIsPixel;
886    pWin->border = pParent->border;
887    if (pWin->borderIsPixel == FALSE)
888        pWin->border.pixmap->refcnt++;
889
890    pWin->origin.x = x + (int) bw;
891    pWin->origin.y = y + (int) bw;
892    pWin->drawable.width = w;
893    pWin->drawable.height = h;
894    pWin->drawable.x = pParent->drawable.x + x + (int) bw;
895    pWin->drawable.y = pParent->drawable.y + y + (int) bw;
896
897    /* set up clip list correctly for unobscured WindowPtr */
898    RegionNull(&pWin->clipList);
899    RegionNull(&pWin->borderClip);
900    RegionNull(&pWin->winSize);
901    RegionNull(&pWin->borderSize);
902
903    pHead = RealChildHead(pParent);
904    if (pHead) {
905        pWin->nextSib = pHead->nextSib;
906        if (pHead->nextSib)
907            pHead->nextSib->prevSib = pWin;
908        else
909            pParent->lastChild = pWin;
910        pHead->nextSib = pWin;
911        pWin->prevSib = pHead;
912    }
913    else {
914        pWin->nextSib = pParent->firstChild;
915        if (pParent->firstChild)
916            pParent->firstChild->prevSib = pWin;
917        else
918            pParent->lastChild = pWin;
919        pParent->firstChild = pWin;
920    }
921
922    SetWinSize(pWin);
923    SetBorderSize(pWin);
924
925    /* We SHOULD check for an error value here XXX */
926    if (!(*pScreen->CreateWindow) (pWin)) {
927        *error = BadAlloc;
928        DeleteWindow(pWin, None);
929        return NullWindow;
930    }
931    /* We SHOULD check for an error value here XXX */
932    (*pScreen->PositionWindow) (pWin, pWin->drawable.x, pWin->drawable.y);
933
934    if (!(vmask & CWEventMask))
935        RecalculateDeliverableEvents(pWin);
936
937    if (vmask)
938        *error = ChangeWindowAttributes(pWin, vmask, vlist, wClient(pWin));
939    else
940        *error = Success;
941
942    if (*error != Success) {
943        DeleteWindow(pWin, None);
944        return NullWindow;
945    }
946    if (!(vmask & CWBackingStore) && (defaultBackingStore != NotUseful)) {
947        XID value = defaultBackingStore;
948
949        (void) ChangeWindowAttributes(pWin, CWBackingStore, &value,
950                                      wClient(pWin));
951        pWin->forcedBS = TRUE;
952    }
953
954    if (SubSend(pParent)) {
955        xEvent event = {
956            .u.createNotify.window = wid,
957            .u.createNotify.parent = pParent->drawable.id,
958            .u.createNotify.x = x,
959            .u.createNotify.y = y,
960            .u.createNotify.width = w,
961            .u.createNotify.height = h,
962            .u.createNotify.borderWidth = bw,
963            .u.createNotify.override = pWin->overrideRedirect
964        };
965        event.u.u.type = CreateNotify;
966        DeliverEvents(pParent, &event, 1, NullWindow);
967    }
968    return pWin;
969}
970
971static void
972DisposeWindowOptional(WindowPtr pWin)
973{
974    if (!pWin->optional)
975        return;
976    /*
977     * everything is peachy.  Delete the optional record
978     * and clean up
979     */
980    if (pWin->optional->cursor) {
981        FreeCursor(pWin->optional->cursor, (Cursor) 0);
982        pWin->cursorIsNone = FALSE;
983    }
984    else
985        pWin->cursorIsNone = TRUE;
986
987    if (pWin->optional->deviceCursors) {
988        DevCursorList pList;
989        DevCursorList pPrev;
990
991        pList = pWin->optional->deviceCursors;
992        while (pList) {
993            if (pList->cursor)
994                FreeCursor(pList->cursor, (XID) 0);
995            pPrev = pList;
996            pList = pList->next;
997            free(pPrev);
998        }
999        pWin->optional->deviceCursors = NULL;
1000    }
1001
1002    free(pWin->optional);
1003    pWin->optional = NULL;
1004}
1005
1006static void
1007FreeWindowResources(WindowPtr pWin)
1008{
1009    ScreenPtr pScreen = pWin->drawable.pScreen;
1010
1011    DeleteWindowFromAnySaveSet(pWin);
1012    DeleteWindowFromAnySelections(pWin);
1013    DeleteWindowFromAnyEvents(pWin, TRUE);
1014    RegionUninit(&pWin->clipList);
1015    RegionUninit(&pWin->winSize);
1016    RegionUninit(&pWin->borderClip);
1017    RegionUninit(&pWin->borderSize);
1018    if (wBoundingShape(pWin))
1019        RegionDestroy(wBoundingShape(pWin));
1020    if (wClipShape(pWin))
1021        RegionDestroy(wClipShape(pWin));
1022    if (wInputShape(pWin))
1023        RegionDestroy(wInputShape(pWin));
1024    if (pWin->borderIsPixel == FALSE)
1025        (*pScreen->DestroyPixmap) (pWin->border.pixmap);
1026    if (pWin->backgroundState == BackgroundPixmap)
1027        (*pScreen->DestroyPixmap) (pWin->background.pixmap);
1028
1029    DeleteAllWindowProperties(pWin);
1030    /* We SHOULD check for an error value here XXX */
1031    (*pScreen->DestroyWindow) (pWin);
1032    DisposeWindowOptional(pWin);
1033}
1034
1035static void
1036CrushTree(WindowPtr pWin)
1037{
1038    WindowPtr pChild, pSib, pParent;
1039    UnrealizeWindowProcPtr UnrealizeWindow;
1040
1041    if (!(pChild = pWin->firstChild))
1042        return;
1043    UnrealizeWindow = pWin->drawable.pScreen->UnrealizeWindow;
1044    while (1) {
1045        if (pChild->firstChild) {
1046            pChild = pChild->firstChild;
1047            continue;
1048        }
1049        while (1) {
1050            pParent = pChild->parent;
1051            if (SubStrSend(pChild, pParent)) {
1052                xEvent event = { .u.u.type = DestroyNotify };
1053                event.u.destroyNotify.window = pChild->drawable.id;
1054                DeliverEvents(pChild, &event, 1, NullWindow);
1055            }
1056            FreeResource(pChild->drawable.id, RT_WINDOW);
1057            pSib = pChild->nextSib;
1058            pChild->viewable = FALSE;
1059            if (pChild->realized) {
1060                pChild->realized = FALSE;
1061                (*UnrealizeWindow) (pChild);
1062            }
1063            FreeWindowResources(pChild);
1064            dixFreeObjectWithPrivates(pChild, PRIVATE_WINDOW);
1065            if ((pChild = pSib))
1066                break;
1067            pChild = pParent;
1068            pChild->firstChild = NullWindow;
1069            pChild->lastChild = NullWindow;
1070            if (pChild == pWin)
1071                return;
1072        }
1073    }
1074}
1075
1076/*****
1077 *  DeleteWindow
1078 *	 Deletes child of window then window itself
1079 *	 If wid is None, don't send any events
1080 *****/
1081
1082int
1083DeleteWindow(void *value, XID wid)
1084{
1085    WindowPtr pParent;
1086    WindowPtr pWin = (WindowPtr) value;
1087
1088    UnmapWindow(pWin, FALSE);
1089
1090    CrushTree(pWin);
1091
1092    pParent = pWin->parent;
1093    if (wid && pParent && SubStrSend(pWin, pParent)) {
1094        xEvent event = { .u.u.type = DestroyNotify };
1095        event.u.destroyNotify.window = pWin->drawable.id;
1096        DeliverEvents(pWin, &event, 1, NullWindow);
1097    }
1098
1099    FreeWindowResources(pWin);
1100    if (pParent) {
1101        if (pParent->firstChild == pWin)
1102            pParent->firstChild = pWin->nextSib;
1103        if (pParent->lastChild == pWin)
1104            pParent->lastChild = pWin->prevSib;
1105        if (pWin->nextSib)
1106            pWin->nextSib->prevSib = pWin->prevSib;
1107        if (pWin->prevSib)
1108            pWin->prevSib->nextSib = pWin->nextSib;
1109    }
1110    else
1111        pWin->drawable.pScreen->root = NULL;
1112    dixFreeObjectWithPrivates(pWin, PRIVATE_WINDOW);
1113    return Success;
1114}
1115
1116int
1117DestroySubwindows(WindowPtr pWin, ClientPtr client)
1118{
1119    /* XXX
1120     * The protocol is quite clear that each window should be
1121     * destroyed in turn, however, unmapping all of the first
1122     * eliminates most of the calls to ValidateTree.  So,
1123     * this implementation is incorrect in that all of the
1124     * UnmapNotifies occur before all of the DestroyNotifies.
1125     * If you care, simply delete the call to UnmapSubwindows.
1126     */
1127    UnmapSubwindows(pWin);
1128    while (pWin->lastChild) {
1129        int rc = XaceHook(XACE_RESOURCE_ACCESS, client,
1130                          pWin->lastChild->drawable.id, RT_WINDOW,
1131                          pWin->lastChild, RT_NONE, NULL, DixDestroyAccess);
1132
1133        if (rc != Success)
1134            return rc;
1135        FreeResource(pWin->lastChild->drawable.id, RT_NONE);
1136    }
1137    return Success;
1138}
1139
1140static void
1141SetRootWindowBackground(WindowPtr pWin, ScreenPtr pScreen, Mask *index2)
1142{
1143    /* following the protocol: "Changing the background of a root window to
1144     * None or ParentRelative restores the default background pixmap" */
1145    if (bgNoneRoot) {
1146        pWin->backgroundState = XaceBackgroundNoneState(pWin);
1147        pWin->background.pixel = pScreen->whitePixel;
1148    }
1149    else if (party_like_its_1989)
1150        MakeRootTile(pWin);
1151    else {
1152        pWin->backgroundState = BackgroundPixel;
1153        if (whiteRoot)
1154            pWin->background.pixel = pScreen->whitePixel;
1155        else
1156            pWin->background.pixel = pScreen->blackPixel;
1157        *index2 = CWBackPixel;
1158    }
1159}
1160
1161/*****
1162 *  ChangeWindowAttributes
1163 *
1164 *  The value-mask specifies which attributes are to be changed; the
1165 *  value-list contains one value for each one bit in the mask, from least
1166 *  to most significant bit in the mask.
1167 *****/
1168
1169int
1170ChangeWindowAttributes(WindowPtr pWin, Mask vmask, XID *vlist, ClientPtr client)
1171{
1172    XID *pVlist;
1173    PixmapPtr pPixmap;
1174    Pixmap pixID;
1175    CursorPtr pCursor, pOldCursor;
1176    Cursor cursorID;
1177    WindowPtr pChild;
1178    Colormap cmap;
1179    ColormapPtr pCmap;
1180    xEvent xE;
1181    int error, rc;
1182    ScreenPtr pScreen;
1183    Mask index2, tmask, vmaskCopy = 0;
1184    unsigned int val;
1185    Bool checkOptional = FALSE, borderRelative = FALSE;
1186
1187    if ((pWin->drawable.class == InputOnly) &&
1188        (vmask & (~INPUTONLY_LEGAL_MASK)))
1189        return BadMatch;
1190
1191    error = Success;
1192    pScreen = pWin->drawable.pScreen;
1193    pVlist = vlist;
1194    tmask = vmask;
1195    while (tmask) {
1196        index2 = (Mask) lowbit(tmask);
1197        tmask &= ~index2;
1198        switch (index2) {
1199        case CWBackPixmap:
1200            pixID = (Pixmap) * pVlist;
1201            pVlist++;
1202            if (pWin->backgroundState == ParentRelative)
1203                borderRelative = TRUE;
1204            if (pixID == None) {
1205                if (pWin->backgroundState == BackgroundPixmap)
1206                    (*pScreen->DestroyPixmap) (pWin->background.pixmap);
1207                if (!pWin->parent)
1208                    SetRootWindowBackground(pWin, pScreen, &index2);
1209                else {
1210                    pWin->backgroundState = XaceBackgroundNoneState(pWin);
1211                    pWin->background.pixel = pScreen->whitePixel;
1212                }
1213            }
1214            else if (pixID == ParentRelative) {
1215                if (pWin->parent &&
1216                    pWin->drawable.depth != pWin->parent->drawable.depth) {
1217                    error = BadMatch;
1218                    goto PatchUp;
1219                }
1220                if (pWin->backgroundState == BackgroundPixmap)
1221                    (*pScreen->DestroyPixmap) (pWin->background.pixmap);
1222                if (!pWin->parent)
1223                    SetRootWindowBackground(pWin, pScreen, &index2);
1224                else
1225                    pWin->backgroundState = ParentRelative;
1226                borderRelative = TRUE;
1227                /* Note that the parent's backgroundTile's refcnt is NOT
1228                 * incremented. */
1229            }
1230            else {
1231                rc = dixLookupResourceByType((void **) &pPixmap, pixID,
1232                                             RT_PIXMAP, client, DixReadAccess);
1233                if (rc == Success) {
1234                    if ((pPixmap->drawable.depth != pWin->drawable.depth) ||
1235                        (pPixmap->drawable.pScreen != pScreen)) {
1236                        error = BadMatch;
1237                        goto PatchUp;
1238                    }
1239                    if (pWin->backgroundState == BackgroundPixmap)
1240                        (*pScreen->DestroyPixmap) (pWin->background.pixmap);
1241                    pWin->backgroundState = BackgroundPixmap;
1242                    pWin->background.pixmap = pPixmap;
1243                    pPixmap->refcnt++;
1244                }
1245                else {
1246                    error = rc;
1247                    client->errorValue = pixID;
1248                    goto PatchUp;
1249                }
1250            }
1251            break;
1252        case CWBackPixel:
1253            if (pWin->backgroundState == ParentRelative)
1254                borderRelative = TRUE;
1255            if (pWin->backgroundState == BackgroundPixmap)
1256                (*pScreen->DestroyPixmap) (pWin->background.pixmap);
1257            pWin->backgroundState = BackgroundPixel;
1258            pWin->background.pixel = (CARD32) *pVlist;
1259            /* background pixel overrides background pixmap,
1260               so don't let the ddx layer see both bits */
1261            vmaskCopy &= ~CWBackPixmap;
1262            pVlist++;
1263            break;
1264        case CWBorderPixmap:
1265            pixID = (Pixmap) * pVlist;
1266            pVlist++;
1267            if (pixID == CopyFromParent) {
1268                if (!pWin->parent ||
1269                    (pWin->drawable.depth != pWin->parent->drawable.depth)) {
1270                    error = BadMatch;
1271                    goto PatchUp;
1272                }
1273                if (pWin->parent->borderIsPixel == TRUE) {
1274                    if (pWin->borderIsPixel == FALSE)
1275                        (*pScreen->DestroyPixmap) (pWin->border.pixmap);
1276                    pWin->border = pWin->parent->border;
1277                    pWin->borderIsPixel = TRUE;
1278                    index2 = CWBorderPixel;
1279                    break;
1280                }
1281                else {
1282                    pixID = pWin->parent->border.pixmap->drawable.id;
1283                }
1284            }
1285            rc = dixLookupResourceByType((void **) &pPixmap, pixID, RT_PIXMAP,
1286                                         client, DixReadAccess);
1287            if (rc == Success) {
1288                if ((pPixmap->drawable.depth != pWin->drawable.depth) ||
1289                    (pPixmap->drawable.pScreen != pScreen)) {
1290                    error = BadMatch;
1291                    goto PatchUp;
1292                }
1293                if (pWin->borderIsPixel == FALSE)
1294                    (*pScreen->DestroyPixmap) (pWin->border.pixmap);
1295                pWin->borderIsPixel = FALSE;
1296                pWin->border.pixmap = pPixmap;
1297                pPixmap->refcnt++;
1298            }
1299            else {
1300                error = rc;
1301                client->errorValue = pixID;
1302                goto PatchUp;
1303            }
1304            break;
1305        case CWBorderPixel:
1306            if (pWin->borderIsPixel == FALSE)
1307                (*pScreen->DestroyPixmap) (pWin->border.pixmap);
1308            pWin->borderIsPixel = TRUE;
1309            pWin->border.pixel = (CARD32) *pVlist;
1310            /* border pixel overrides border pixmap,
1311               so don't let the ddx layer see both bits */
1312            vmaskCopy &= ~CWBorderPixmap;
1313            pVlist++;
1314            break;
1315        case CWBitGravity:
1316            val = (CARD8) *pVlist;
1317            pVlist++;
1318            if (val > StaticGravity) {
1319                error = BadValue;
1320                client->errorValue = val;
1321                goto PatchUp;
1322            }
1323            pWin->bitGravity = val;
1324            break;
1325        case CWWinGravity:
1326            val = (CARD8) *pVlist;
1327            pVlist++;
1328            if (val > StaticGravity) {
1329                error = BadValue;
1330                client->errorValue = val;
1331                goto PatchUp;
1332            }
1333            pWin->winGravity = val;
1334            break;
1335        case CWBackingStore:
1336            val = (CARD8) *pVlist;
1337            pVlist++;
1338            if ((val != NotUseful) && (val != WhenMapped) && (val != Always)) {
1339                error = BadValue;
1340                client->errorValue = val;
1341                goto PatchUp;
1342            }
1343            pWin->backingStore = val;
1344            pWin->forcedBS = FALSE;
1345            break;
1346        case CWBackingPlanes:
1347            if (pWin->optional || ((CARD32) *pVlist != (CARD32) ~0L)) {
1348                if (!pWin->optional && !MakeWindowOptional(pWin)) {
1349                    error = BadAlloc;
1350                    goto PatchUp;
1351                }
1352                pWin->optional->backingBitPlanes = (CARD32) *pVlist;
1353                if ((CARD32) *pVlist == (CARD32) ~0L)
1354                    checkOptional = TRUE;
1355            }
1356            pVlist++;
1357            break;
1358        case CWBackingPixel:
1359            if (pWin->optional || (CARD32) *pVlist) {
1360                if (!pWin->optional && !MakeWindowOptional(pWin)) {
1361                    error = BadAlloc;
1362                    goto PatchUp;
1363                }
1364                pWin->optional->backingPixel = (CARD32) *pVlist;
1365                if (!*pVlist)
1366                    checkOptional = TRUE;
1367            }
1368            pVlist++;
1369            break;
1370        case CWSaveUnder:
1371            val = (BOOL) * pVlist;
1372            pVlist++;
1373            if ((val != xTrue) && (val != xFalse)) {
1374                error = BadValue;
1375                client->errorValue = val;
1376                goto PatchUp;
1377            }
1378            pWin->saveUnder = val;
1379            break;
1380        case CWEventMask:
1381            rc = EventSelectForWindow(pWin, client, (Mask) *pVlist);
1382            if (rc) {
1383                error = rc;
1384                goto PatchUp;
1385            }
1386            pVlist++;
1387            break;
1388        case CWDontPropagate:
1389            rc = EventSuppressForWindow(pWin, client, (Mask) *pVlist,
1390                                        &checkOptional);
1391            if (rc) {
1392                error = rc;
1393                goto PatchUp;
1394            }
1395            pVlist++;
1396            break;
1397        case CWOverrideRedirect:
1398            val = (BOOL) * pVlist;
1399            pVlist++;
1400            if ((val != xTrue) && (val != xFalse)) {
1401                error = BadValue;
1402                client->errorValue = val;
1403                goto PatchUp;
1404            }
1405            if (val == xTrue) {
1406                rc = XaceHook(XACE_RESOURCE_ACCESS, client, pWin->drawable.id,
1407                              RT_WINDOW, pWin, RT_NONE, NULL, DixGrabAccess);
1408                if (rc != Success) {
1409                    error = rc;
1410                    client->errorValue = pWin->drawable.id;
1411                    goto PatchUp;
1412                }
1413            }
1414            pWin->overrideRedirect = val;
1415            break;
1416        case CWColormap:
1417            cmap = (Colormap) * pVlist;
1418            pVlist++;
1419            if (cmap == CopyFromParent) {
1420                if (pWin->parent &&
1421                    (!pWin->optional ||
1422                     pWin->optional->visual == wVisual(pWin->parent))) {
1423                    cmap = wColormap(pWin->parent);
1424                }
1425                else
1426                    cmap = None;
1427            }
1428            if (cmap == None) {
1429                error = BadMatch;
1430                goto PatchUp;
1431            }
1432            rc = dixLookupResourceByType((void **) &pCmap, cmap, RT_COLORMAP,
1433                                         client, DixUseAccess);
1434            if (rc != Success) {
1435                error = rc;
1436                client->errorValue = cmap;
1437                goto PatchUp;
1438            }
1439            if (pCmap->pVisual->vid != wVisual(pWin) ||
1440                pCmap->pScreen != pScreen) {
1441                error = BadMatch;
1442                goto PatchUp;
1443            }
1444            if (cmap != wColormap(pWin)) {
1445                if (!pWin->optional) {
1446                    if (!MakeWindowOptional(pWin)) {
1447                        error = BadAlloc;
1448                        goto PatchUp;
1449                    }
1450                }
1451                else if (pWin->parent && cmap == wColormap(pWin->parent))
1452                    checkOptional = TRUE;
1453
1454                /*
1455                 * propagate the original colormap to any children
1456                 * inheriting it
1457                 */
1458
1459                for (pChild = pWin->firstChild; pChild;
1460                     pChild = pChild->nextSib) {
1461                    if (!pChild->optional && !MakeWindowOptional(pChild)) {
1462                        error = BadAlloc;
1463                        goto PatchUp;
1464                    }
1465                }
1466
1467                pWin->optional->colormap = cmap;
1468
1469                /*
1470                 * check on any children now matching the new colormap
1471                 */
1472
1473                for (pChild = pWin->firstChild; pChild;
1474                     pChild = pChild->nextSib) {
1475                    if (pChild->optional->colormap == cmap)
1476                        CheckWindowOptionalNeed(pChild);
1477                }
1478
1479                xE = (xEvent) {
1480                    .u.colormap.window = pWin->drawable.id,
1481                    .u.colormap.colormap = cmap,
1482                    .u.colormap.new = xTrue,
1483                    .u.colormap.state = IsMapInstalled(cmap, pWin)
1484                };
1485                xE.u.u.type = ColormapNotify;
1486                DeliverEvents(pWin, &xE, 1, NullWindow);
1487            }
1488            break;
1489        case CWCursor:
1490            cursorID = (Cursor) * pVlist;
1491            pVlist++;
1492            /*
1493             * install the new
1494             */
1495            if (cursorID == None) {
1496                if (pWin == pWin->drawable.pScreen->root)
1497                    pCursor = rootCursor;
1498                else
1499                    pCursor = (CursorPtr) None;
1500            }
1501            else {
1502                rc = dixLookupResourceByType((void **) &pCursor, cursorID,
1503                                             RT_CURSOR, client, DixUseAccess);
1504                if (rc != Success) {
1505                    error = rc;
1506                    client->errorValue = cursorID;
1507                    goto PatchUp;
1508                }
1509            }
1510
1511            if (pCursor != wCursor(pWin)) {
1512                /*
1513                 * patch up child windows so they don't lose cursors.
1514                 */
1515
1516                for (pChild = pWin->firstChild; pChild;
1517                     pChild = pChild->nextSib) {
1518                    if (!pChild->optional && !pChild->cursorIsNone &&
1519                        !MakeWindowOptional(pChild)) {
1520                        error = BadAlloc;
1521                        goto PatchUp;
1522                    }
1523                }
1524
1525                pOldCursor = 0;
1526                if (pCursor == (CursorPtr) None) {
1527                    pWin->cursorIsNone = TRUE;
1528                    if (pWin->optional) {
1529                        pOldCursor = pWin->optional->cursor;
1530                        pWin->optional->cursor = (CursorPtr) None;
1531                        checkOptional = TRUE;
1532                    }
1533                }
1534                else {
1535                    if (!pWin->optional) {
1536                        if (!MakeWindowOptional(pWin)) {
1537                            error = BadAlloc;
1538                            goto PatchUp;
1539                        }
1540                    }
1541                    else if (pWin->parent && pCursor == wCursor(pWin->parent))
1542                        checkOptional = TRUE;
1543                    pOldCursor = pWin->optional->cursor;
1544                    pWin->optional->cursor = RefCursor(pCursor);
1545                    pWin->cursorIsNone = FALSE;
1546                    /*
1547                     * check on any children now matching the new cursor
1548                     */
1549
1550                    for (pChild = pWin->firstChild; pChild;
1551                         pChild = pChild->nextSib) {
1552                        if (pChild->optional &&
1553                            (pChild->optional->cursor == pCursor))
1554                            CheckWindowOptionalNeed(pChild);
1555                    }
1556                }
1557
1558                CursorVisible = TRUE;
1559
1560                if (pWin->realized)
1561                    WindowHasNewCursor(pWin);
1562
1563                /* Can't free cursor until here - old cursor
1564                 * is needed in WindowHasNewCursor
1565                 */
1566                if (pOldCursor)
1567                    FreeCursor(pOldCursor, (Cursor) 0);
1568            }
1569            break;
1570        default:
1571            error = BadValue;
1572            client->errorValue = vmask;
1573            goto PatchUp;
1574        }
1575        vmaskCopy |= index2;
1576    }
1577 PatchUp:
1578    if (checkOptional)
1579        CheckWindowOptionalNeed(pWin);
1580
1581    /* We SHOULD check for an error value here XXX */
1582    (*pScreen->ChangeWindowAttributes) (pWin, vmaskCopy);
1583
1584    /*
1585       If the border contents have changed, redraw the border.
1586       Note that this has to be done AFTER pScreen->ChangeWindowAttributes
1587       for the tile to be rotated, and the correct function selected.
1588     */
1589    if (((vmaskCopy & (CWBorderPixel | CWBorderPixmap)) || borderRelative)
1590        && pWin->viewable && HasBorder(pWin)) {
1591        RegionRec exposed;
1592
1593        RegionNull(&exposed);
1594        RegionSubtract(&exposed, &pWin->borderClip, &pWin->winSize);
1595        pWin->drawable.pScreen->PaintWindow(pWin, &exposed, PW_BORDER);
1596        RegionUninit(&exposed);
1597    }
1598    return error;
1599}
1600
1601/*****
1602 * GetWindowAttributes
1603 *    Notice that this is different than ChangeWindowAttributes
1604 *****/
1605
1606void
1607GetWindowAttributes(WindowPtr pWin, ClientPtr client,
1608                    xGetWindowAttributesReply * wa)
1609{
1610    wa->type = X_Reply;
1611    wa->bitGravity = pWin->bitGravity;
1612    wa->winGravity = pWin->winGravity;
1613    if (pWin->forcedBS && pWin->backingStore != Always)
1614        wa->backingStore = NotUseful;
1615    else
1616        wa->backingStore = pWin->backingStore;
1617    wa->length = bytes_to_int32(sizeof(xGetWindowAttributesReply) -
1618                                sizeof(xGenericReply));
1619    wa->sequenceNumber = client->sequence;
1620    wa->backingBitPlanes = wBackingBitPlanes(pWin);
1621    wa->backingPixel = wBackingPixel(pWin);
1622    wa->saveUnder = (BOOL) pWin->saveUnder;
1623    wa->override = pWin->overrideRedirect;
1624    if (!pWin->mapped)
1625        wa->mapState = IsUnmapped;
1626    else if (pWin->realized)
1627        wa->mapState = IsViewable;
1628    else
1629        wa->mapState = IsUnviewable;
1630
1631    wa->colormap = wColormap(pWin);
1632    wa->mapInstalled = (wa->colormap == None) ? xFalse
1633        : IsMapInstalled(wa->colormap, pWin);
1634
1635    wa->yourEventMask = EventMaskForClient(pWin, client);
1636    wa->allEventMasks = pWin->eventMask | wOtherEventMasks(pWin);
1637    wa->doNotPropagateMask = wDontPropagateMask(pWin);
1638    wa->class = pWin->drawable.class;
1639    wa->visualID = wVisual(pWin);
1640}
1641
1642WindowPtr
1643MoveWindowInStack(WindowPtr pWin, WindowPtr pNextSib)
1644{
1645    WindowPtr pParent = pWin->parent;
1646    WindowPtr pFirstChange = pWin;      /* highest window where list changes */
1647
1648    if (pWin->nextSib != pNextSib) {
1649        WindowPtr pOldNextSib = pWin->nextSib;
1650
1651        if (!pNextSib) {        /* move to bottom */
1652            if (pParent->firstChild == pWin)
1653                pParent->firstChild = pWin->nextSib;
1654            /* if (pWin->nextSib) *//* is always True: pNextSib == NULL
1655             * and pWin->nextSib != pNextSib
1656             * therefore pWin->nextSib != NULL */
1657            pFirstChange = pWin->nextSib;
1658            pWin->nextSib->prevSib = pWin->prevSib;
1659            if (pWin->prevSib)
1660                pWin->prevSib->nextSib = pWin->nextSib;
1661            pParent->lastChild->nextSib = pWin;
1662            pWin->prevSib = pParent->lastChild;
1663            pWin->nextSib = NullWindow;
1664            pParent->lastChild = pWin;
1665        }
1666        else if (pParent->firstChild == pNextSib) {     /* move to top */
1667            pFirstChange = pWin;
1668            if (pParent->lastChild == pWin)
1669                pParent->lastChild = pWin->prevSib;
1670            if (pWin->nextSib)
1671                pWin->nextSib->prevSib = pWin->prevSib;
1672            if (pWin->prevSib)
1673                pWin->prevSib->nextSib = pWin->nextSib;
1674            pWin->nextSib = pParent->firstChild;
1675            pWin->prevSib = NULL;
1676            pNextSib->prevSib = pWin;
1677            pParent->firstChild = pWin;
1678        }
1679        else {                  /* move in middle of list */
1680
1681            WindowPtr pOldNext = pWin->nextSib;
1682
1683            pFirstChange = NullWindow;
1684            if (pParent->firstChild == pWin)
1685                pFirstChange = pParent->firstChild = pWin->nextSib;
1686            if (pParent->lastChild == pWin) {
1687                pFirstChange = pWin;
1688                pParent->lastChild = pWin->prevSib;
1689            }
1690            if (pWin->nextSib)
1691                pWin->nextSib->prevSib = pWin->prevSib;
1692            if (pWin->prevSib)
1693                pWin->prevSib->nextSib = pWin->nextSib;
1694            pWin->nextSib = pNextSib;
1695            pWin->prevSib = pNextSib->prevSib;
1696            if (pNextSib->prevSib)
1697                pNextSib->prevSib->nextSib = pWin;
1698            pNextSib->prevSib = pWin;
1699            if (!pFirstChange) {        /* do we know it yet? */
1700                pFirstChange = pParent->firstChild;     /* no, search from top */
1701                while ((pFirstChange != pWin) && (pFirstChange != pOldNext))
1702                    pFirstChange = pFirstChange->nextSib;
1703            }
1704        }
1705        if (pWin->drawable.pScreen->RestackWindow)
1706            (*pWin->drawable.pScreen->RestackWindow) (pWin, pOldNextSib);
1707    }
1708
1709#ifdef ROOTLESS
1710    /*
1711     * In rootless mode we can't optimize away window restacks.
1712     * There may be non-X windows around, so even if the window
1713     * is in the correct position from X's point of view,
1714     * the underlying window system may want to reorder it.
1715     */
1716    else if (pWin->drawable.pScreen->RestackWindow)
1717        (*pWin->drawable.pScreen->RestackWindow) (pWin, pWin->nextSib);
1718#endif
1719
1720    return pFirstChange;
1721}
1722
1723void
1724SetWinSize(WindowPtr pWin)
1725{
1726#ifdef COMPOSITE
1727    if (pWin->redirectDraw != RedirectDrawNone) {
1728        BoxRec box;
1729
1730        /*
1731         * Redirected clients get clip list equal to their
1732         * own geometry, not clipped to their parent
1733         */
1734        box.x1 = pWin->drawable.x;
1735        box.y1 = pWin->drawable.y;
1736        box.x2 = pWin->drawable.x + pWin->drawable.width;
1737        box.y2 = pWin->drawable.y + pWin->drawable.height;
1738        RegionReset(&pWin->winSize, &box);
1739    }
1740    else
1741#endif
1742        ClippedRegionFromBox(pWin->parent, &pWin->winSize,
1743                             pWin->drawable.x, pWin->drawable.y,
1744                             (int) pWin->drawable.width,
1745                             (int) pWin->drawable.height);
1746    if (wBoundingShape(pWin) || wClipShape(pWin)) {
1747        RegionTranslate(&pWin->winSize, -pWin->drawable.x, -pWin->drawable.y);
1748        if (wBoundingShape(pWin))
1749            RegionIntersect(&pWin->winSize, &pWin->winSize,
1750                            wBoundingShape(pWin));
1751        if (wClipShape(pWin))
1752            RegionIntersect(&pWin->winSize, &pWin->winSize, wClipShape(pWin));
1753        RegionTranslate(&pWin->winSize, pWin->drawable.x, pWin->drawable.y);
1754    }
1755}
1756
1757void
1758SetBorderSize(WindowPtr pWin)
1759{
1760    int bw;
1761
1762    if (HasBorder(pWin)) {
1763        bw = wBorderWidth(pWin);
1764#ifdef COMPOSITE
1765        if (pWin->redirectDraw != RedirectDrawNone) {
1766            BoxRec box;
1767
1768            /*
1769             * Redirected clients get clip list equal to their
1770             * own geometry, not clipped to their parent
1771             */
1772            box.x1 = pWin->drawable.x - bw;
1773            box.y1 = pWin->drawable.y - bw;
1774            box.x2 = pWin->drawable.x + pWin->drawable.width + bw;
1775            box.y2 = pWin->drawable.y + pWin->drawable.height + bw;
1776            RegionReset(&pWin->borderSize, &box);
1777        }
1778        else
1779#endif
1780            ClippedRegionFromBox(pWin->parent, &pWin->borderSize,
1781                                 pWin->drawable.x - bw, pWin->drawable.y - bw,
1782                                 (int) (pWin->drawable.width + (bw << 1)),
1783                                 (int) (pWin->drawable.height + (bw << 1)));
1784        if (wBoundingShape(pWin)) {
1785            RegionTranslate(&pWin->borderSize, -pWin->drawable.x,
1786                            -pWin->drawable.y);
1787            RegionIntersect(&pWin->borderSize, &pWin->borderSize,
1788                            wBoundingShape(pWin));
1789            RegionTranslate(&pWin->borderSize, pWin->drawable.x,
1790                            pWin->drawable.y);
1791            RegionUnion(&pWin->borderSize, &pWin->borderSize, &pWin->winSize);
1792        }
1793    }
1794    else {
1795        RegionCopy(&pWin->borderSize, &pWin->winSize);
1796    }
1797}
1798
1799/**
1800 *
1801 *  \param x,y          new window position
1802 *  \param oldx,oldy    old window position
1803 *  \param destx,desty  position relative to gravity
1804 */
1805
1806void
1807GravityTranslate(int x, int y, int oldx, int oldy,
1808                 int dw, int dh, unsigned gravity, int *destx, int *desty)
1809{
1810    switch (gravity) {
1811    case NorthGravity:
1812        *destx = x + dw / 2;
1813        *desty = y;
1814        break;
1815    case NorthEastGravity:
1816        *destx = x + dw;
1817        *desty = y;
1818        break;
1819    case WestGravity:
1820        *destx = x;
1821        *desty = y + dh / 2;
1822        break;
1823    case CenterGravity:
1824        *destx = x + dw / 2;
1825        *desty = y + dh / 2;
1826        break;
1827    case EastGravity:
1828        *destx = x + dw;
1829        *desty = y + dh / 2;
1830        break;
1831    case SouthWestGravity:
1832        *destx = x;
1833        *desty = y + dh;
1834        break;
1835    case SouthGravity:
1836        *destx = x + dw / 2;
1837        *desty = y + dh;
1838        break;
1839    case SouthEastGravity:
1840        *destx = x + dw;
1841        *desty = y + dh;
1842        break;
1843    case StaticGravity:
1844        *destx = oldx;
1845        *desty = oldy;
1846        break;
1847    default:
1848        *destx = x;
1849        *desty = y;
1850        break;
1851    }
1852}
1853
1854/* XXX need to retile border on each window with ParentRelative origin */
1855void
1856ResizeChildrenWinSize(WindowPtr pWin, int dx, int dy, int dw, int dh)
1857{
1858    ScreenPtr pScreen;
1859    WindowPtr pSib, pChild;
1860    Bool resized = (dw || dh);
1861
1862    pScreen = pWin->drawable.pScreen;
1863
1864    for (pSib = pWin->firstChild; pSib; pSib = pSib->nextSib) {
1865        if (resized && (pSib->winGravity > NorthWestGravity)) {
1866            int cwsx, cwsy;
1867
1868            cwsx = pSib->origin.x;
1869            cwsy = pSib->origin.y;
1870            GravityTranslate(cwsx, cwsy, cwsx - dx, cwsy - dy, dw, dh,
1871                             pSib->winGravity, &cwsx, &cwsy);
1872            if (cwsx != pSib->origin.x || cwsy != pSib->origin.y) {
1873                xEvent event = {
1874                    .u.gravity.window = pSib->drawable.id,
1875                    .u.gravity.x = cwsx - wBorderWidth(pSib),
1876                    .u.gravity.y = cwsy - wBorderWidth(pSib)
1877                };
1878                event.u.u.type = GravityNotify;
1879                DeliverEvents(pSib, &event, 1, NullWindow);
1880                pSib->origin.x = cwsx;
1881                pSib->origin.y = cwsy;
1882            }
1883        }
1884        pSib->drawable.x = pWin->drawable.x + pSib->origin.x;
1885        pSib->drawable.y = pWin->drawable.y + pSib->origin.y;
1886        SetWinSize(pSib);
1887        SetBorderSize(pSib);
1888        (*pScreen->PositionWindow) (pSib, pSib->drawable.x, pSib->drawable.y);
1889
1890        if ((pChild = pSib->firstChild)) {
1891            while (1) {
1892                pChild->drawable.x = pChild->parent->drawable.x +
1893                    pChild->origin.x;
1894                pChild->drawable.y = pChild->parent->drawable.y +
1895                    pChild->origin.y;
1896                SetWinSize(pChild);
1897                SetBorderSize(pChild);
1898                (*pScreen->PositionWindow) (pChild,
1899                                            pChild->drawable.x,
1900                                            pChild->drawable.y);
1901                if (pChild->firstChild) {
1902                    pChild = pChild->firstChild;
1903                    continue;
1904                }
1905                while (!pChild->nextSib && (pChild != pSib))
1906                    pChild = pChild->parent;
1907                if (pChild == pSib)
1908                    break;
1909                pChild = pChild->nextSib;
1910            }
1911        }
1912    }
1913}
1914
1915#define GET_INT16(m, f) \
1916	if (m & mask) \
1917	  { \
1918	     f = (INT16) *pVlist;\
1919	    pVlist++; \
1920	 }
1921#define GET_CARD16(m, f) \
1922	if (m & mask) \
1923	 { \
1924	    f = (CARD16) *pVlist;\
1925	    pVlist++;\
1926	 }
1927
1928#define GET_CARD8(m, f) \
1929	if (m & mask) \
1930	 { \
1931	    f = (CARD8) *pVlist;\
1932	    pVlist++;\
1933	 }
1934
1935#define ChangeMask ((Mask)(CWX | CWY | CWWidth | CWHeight))
1936
1937/*
1938 * IsSiblingAboveMe
1939 *     returns Above if pSib above pMe in stack or Below otherwise
1940 */
1941
1942static int
1943IsSiblingAboveMe(WindowPtr pMe, WindowPtr pSib)
1944{
1945    WindowPtr pWin;
1946
1947    pWin = pMe->parent->firstChild;
1948    while (pWin) {
1949        if (pWin == pSib)
1950            return Above;
1951        else if (pWin == pMe)
1952            return Below;
1953        pWin = pWin->nextSib;
1954    }
1955    return Below;
1956}
1957
1958static BoxPtr
1959WindowExtents(WindowPtr pWin, BoxPtr pBox)
1960{
1961    pBox->x1 = pWin->drawable.x - wBorderWidth(pWin);
1962    pBox->y1 = pWin->drawable.y - wBorderWidth(pWin);
1963    pBox->x2 = pWin->drawable.x + (int) pWin->drawable.width
1964        + wBorderWidth(pWin);
1965    pBox->y2 = pWin->drawable.y + (int) pWin->drawable.height
1966        + wBorderWidth(pWin);
1967    return pBox;
1968}
1969
1970#define IS_SHAPED(pWin)	(wBoundingShape (pWin) != NULL)
1971
1972static RegionPtr
1973MakeBoundingRegion(WindowPtr pWin, BoxPtr pBox)
1974{
1975    RegionPtr pRgn = RegionCreate(pBox, 1);
1976
1977    if (wBoundingShape(pWin)) {
1978        RegionTranslate(pRgn, -pWin->origin.x, -pWin->origin.y);
1979        RegionIntersect(pRgn, pRgn, wBoundingShape(pWin));
1980        RegionTranslate(pRgn, pWin->origin.x, pWin->origin.y);
1981    }
1982    return pRgn;
1983}
1984
1985static Bool
1986ShapeOverlap(WindowPtr pWin, BoxPtr pWinBox, WindowPtr pSib, BoxPtr pSibBox)
1987{
1988    RegionPtr pWinRgn, pSibRgn;
1989    Bool ret;
1990
1991    if (!IS_SHAPED(pWin) && !IS_SHAPED(pSib))
1992        return TRUE;
1993    pWinRgn = MakeBoundingRegion(pWin, pWinBox);
1994    pSibRgn = MakeBoundingRegion(pSib, pSibBox);
1995    RegionIntersect(pWinRgn, pWinRgn, pSibRgn);
1996    ret = RegionNotEmpty(pWinRgn);
1997    RegionDestroy(pWinRgn);
1998    RegionDestroy(pSibRgn);
1999    return ret;
2000}
2001
2002static Bool
2003AnyWindowOverlapsMe(WindowPtr pWin, WindowPtr pHead, BoxPtr box)
2004{
2005    WindowPtr pSib;
2006    BoxRec sboxrec;
2007    BoxPtr sbox;
2008
2009    for (pSib = pWin->prevSib; pSib != pHead; pSib = pSib->prevSib) {
2010        if (pSib->mapped) {
2011            sbox = WindowExtents(pSib, &sboxrec);
2012            if (BOXES_OVERLAP(sbox, box)
2013                && ShapeOverlap(pWin, box, pSib, sbox))
2014                return TRUE;
2015        }
2016    }
2017    return FALSE;
2018}
2019
2020static Bool
2021IOverlapAnyWindow(WindowPtr pWin, BoxPtr box)
2022{
2023    WindowPtr pSib;
2024    BoxRec sboxrec;
2025    BoxPtr sbox;
2026
2027    for (pSib = pWin->nextSib; pSib; pSib = pSib->nextSib) {
2028        if (pSib->mapped) {
2029            sbox = WindowExtents(pSib, &sboxrec);
2030            if (BOXES_OVERLAP(sbox, box)
2031                && ShapeOverlap(pWin, box, pSib, sbox))
2032                return TRUE;
2033        }
2034    }
2035    return FALSE;
2036}
2037
2038/*
2039 *   WhereDoIGoInTheStack()
2040 *	  Given pWin and pSib and the relationshipe smode, return
2041 *	  the window that pWin should go ABOVE.
2042 *	  If a pSib is specified:
2043 *	      Above:  pWin is placed just above pSib
2044 *	      Below:  pWin is placed just below pSib
2045 *	      TopIf:  if pSib occludes pWin, then pWin is placed
2046 *		      at the top of the stack
2047 *	      BottomIf:	 if pWin occludes pSib, then pWin is
2048 *			 placed at the bottom of the stack
2049 *	      Opposite: if pSib occludes pWin, then pWin is placed at the
2050 *			top of the stack, else if pWin occludes pSib, then
2051 *			pWin is placed at the bottom of the stack
2052 *
2053 *	  If pSib is NULL:
2054 *	      Above:  pWin is placed at the top of the stack
2055 *	      Below:  pWin is placed at the bottom of the stack
2056 *	      TopIf:  if any sibling occludes pWin, then pWin is placed at
2057 *		      the top of the stack
2058 *	      BottomIf: if pWin occludes any sibline, then pWin is placed at
2059 *			the bottom of the stack
2060 *	      Opposite: if any sibling occludes pWin, then pWin is placed at
2061 *			the top of the stack, else if pWin occludes any
2062 *			sibling, then pWin is placed at the bottom of the stack
2063 *
2064 */
2065
2066static WindowPtr
2067WhereDoIGoInTheStack(WindowPtr pWin,
2068                     WindowPtr pSib,
2069                     short x,
2070                     short y, unsigned short w, unsigned short h, int smode)
2071{
2072    BoxRec box;
2073    WindowPtr pHead, pFirst;
2074
2075    if ((pWin == pWin->parent->firstChild) && (pWin == pWin->parent->lastChild))
2076        return NULL;
2077    pHead = RealChildHead(pWin->parent);
2078    pFirst = pHead ? pHead->nextSib : pWin->parent->firstChild;
2079    box.x1 = x;
2080    box.y1 = y;
2081    box.x2 = x + (int) w;
2082    box.y2 = y + (int) h;
2083    switch (smode) {
2084    case Above:
2085        if (pSib)
2086            return pSib;
2087        else if (pWin == pFirst)
2088            return pWin->nextSib;
2089        else
2090            return pFirst;
2091    case Below:
2092        if (pSib)
2093            if (pSib->nextSib != pWin)
2094                return pSib->nextSib;
2095            else
2096                return pWin->nextSib;
2097        else
2098            return NullWindow;
2099    case TopIf:
2100        if ((!pWin->mapped || (pSib && !pSib->mapped)))
2101            return pWin->nextSib;
2102        else if (pSib) {
2103            if ((IsSiblingAboveMe(pWin, pSib) == Above) &&
2104                (RegionContainsRect(&pSib->borderSize, &box) != rgnOUT))
2105                return pFirst;
2106            else
2107                return pWin->nextSib;
2108        }
2109        else if (AnyWindowOverlapsMe(pWin, pHead, &box))
2110            return pFirst;
2111        else
2112            return pWin->nextSib;
2113    case BottomIf:
2114        if ((!pWin->mapped || (pSib && !pSib->mapped)))
2115            return pWin->nextSib;
2116        else if (pSib) {
2117            if ((IsSiblingAboveMe(pWin, pSib) == Below) &&
2118                (RegionContainsRect(&pSib->borderSize, &box) != rgnOUT))
2119                return NullWindow;
2120            else
2121                return pWin->nextSib;
2122        }
2123        else if (IOverlapAnyWindow(pWin, &box))
2124            return NullWindow;
2125        else
2126            return pWin->nextSib;
2127    case Opposite:
2128        if ((!pWin->mapped || (pSib && !pSib->mapped)))
2129            return pWin->nextSib;
2130        else if (pSib) {
2131            if (RegionContainsRect(&pSib->borderSize, &box) != rgnOUT) {
2132                if (IsSiblingAboveMe(pWin, pSib) == Above)
2133                    return pFirst;
2134                else
2135                    return NullWindow;
2136            }
2137            else
2138                return pWin->nextSib;
2139        }
2140        else if (AnyWindowOverlapsMe(pWin, pHead, &box)) {
2141            /* If I'm occluded, I can't possibly be the first child
2142             * if (pWin == pWin->parent->firstChild)
2143             *    return pWin->nextSib;
2144             */
2145            return pFirst;
2146        }
2147        else if (IOverlapAnyWindow(pWin, &box))
2148            return NullWindow;
2149        else
2150            return pWin->nextSib;
2151    default:
2152    {
2153        /* should never happen; make something up. */
2154        return pWin->nextSib;
2155    }
2156    }
2157}
2158
2159static void
2160ReflectStackChange(WindowPtr pWin, WindowPtr pSib, VTKind kind)
2161{
2162/* Note that pSib might be NULL */
2163
2164    Bool WasViewable = (Bool) pWin->viewable;
2165    Bool anyMarked;
2166    WindowPtr pFirstChange;
2167    WindowPtr pLayerWin;
2168    ScreenPtr pScreen = pWin->drawable.pScreen;
2169
2170    /* if this is a root window, can't be restacked */
2171    if (!pWin->parent)
2172        return;
2173
2174    pFirstChange = MoveWindowInStack(pWin, pSib);
2175
2176    if (WasViewable) {
2177        anyMarked = (*pScreen->MarkOverlappedWindows) (pWin, pFirstChange,
2178                                                       &pLayerWin);
2179        if (pLayerWin != pWin)
2180            pFirstChange = pLayerWin;
2181        if (anyMarked) {
2182            (*pScreen->ValidateTree) (pLayerWin->parent, pFirstChange, kind);
2183            (*pScreen->HandleExposures) (pLayerWin->parent);
2184            if (pWin->drawable.pScreen->PostValidateTree)
2185                (*pScreen->PostValidateTree) (pLayerWin->parent, pFirstChange,
2186                                              kind);
2187        }
2188    }
2189    if (pWin->realized)
2190        WindowsRestructured();
2191}
2192
2193/*****
2194 * ConfigureWindow
2195 *****/
2196
2197int
2198ConfigureWindow(WindowPtr pWin, Mask mask, XID *vlist, ClientPtr client)
2199{
2200#define RESTACK_WIN    0
2201#define MOVE_WIN       1
2202#define RESIZE_WIN     2
2203#define REBORDER_WIN   3
2204    WindowPtr pSib = NullWindow;
2205    WindowPtr pParent = pWin->parent;
2206    Window sibwid = 0;
2207    Mask index2, tmask;
2208    XID *pVlist;
2209    short x, y, beforeX, beforeY;
2210    unsigned short w = pWin->drawable.width,
2211        h = pWin->drawable.height, bw = pWin->borderWidth;
2212    int rc, action, smode = Above;
2213
2214    if ((pWin->drawable.class == InputOnly) && (mask & CWBorderWidth))
2215        return BadMatch;
2216
2217    if ((mask & CWSibling) && !(mask & CWStackMode))
2218        return BadMatch;
2219
2220    pVlist = vlist;
2221
2222    if (pParent) {
2223        x = pWin->drawable.x - pParent->drawable.x - (int) bw;
2224        y = pWin->drawable.y - pParent->drawable.y - (int) bw;
2225    }
2226    else {
2227        x = pWin->drawable.x;
2228        y = pWin->drawable.y;
2229    }
2230    beforeX = x;
2231    beforeY = y;
2232    action = RESTACK_WIN;
2233    if ((mask & (CWX | CWY)) && (!(mask & (CWHeight | CWWidth)))) {
2234        GET_INT16(CWX, x);
2235        GET_INT16(CWY, y);
2236        action = MOVE_WIN;
2237    }
2238    /* or should be resized */
2239    else if (mask & (CWX | CWY | CWWidth | CWHeight)) {
2240        GET_INT16(CWX, x);
2241        GET_INT16(CWY, y);
2242        GET_CARD16(CWWidth, w);
2243        GET_CARD16(CWHeight, h);
2244        if (!w || !h) {
2245            client->errorValue = 0;
2246            return BadValue;
2247        }
2248        action = RESIZE_WIN;
2249    }
2250    tmask = mask & ~ChangeMask;
2251    while (tmask) {
2252        index2 = (Mask) lowbit(tmask);
2253        tmask &= ~index2;
2254        switch (index2) {
2255        case CWBorderWidth:
2256            GET_CARD16(CWBorderWidth, bw);
2257            break;
2258        case CWSibling:
2259            sibwid = (Window) *pVlist;
2260            pVlist++;
2261            rc = dixLookupWindow(&pSib, sibwid, client, DixGetAttrAccess);
2262            if (rc != Success) {
2263                client->errorValue = sibwid;
2264                return rc;
2265            }
2266            if (pSib->parent != pParent)
2267                return BadMatch;
2268            if (pSib == pWin)
2269                return BadMatch;
2270            break;
2271        case CWStackMode:
2272            GET_CARD8(CWStackMode, smode);
2273            if ((smode != TopIf) && (smode != BottomIf) &&
2274                (smode != Opposite) && (smode != Above) && (smode != Below)) {
2275                client->errorValue = smode;
2276                return BadValue;
2277            }
2278            break;
2279        default:
2280            client->errorValue = mask;
2281            return BadValue;
2282        }
2283    }
2284    /* root really can't be reconfigured, so just return */
2285    if (!pParent)
2286        return Success;
2287
2288    /* Figure out if the window should be moved.  Doesnt
2289       make the changes to the window if event sent */
2290
2291    if (mask & CWStackMode)
2292        pSib = WhereDoIGoInTheStack(pWin, pSib, pParent->drawable.x + x,
2293                                    pParent->drawable.y + y,
2294                                    w + (bw << 1), h + (bw << 1), smode);
2295    else
2296        pSib = pWin->nextSib;
2297
2298    if ((!pWin->overrideRedirect) && (RedirectSend(pParent))) {
2299        xEvent event = {
2300            .u.configureRequest.window = pWin->drawable.id,
2301            .u.configureRequest.sibling = (mask & CWSibling) ? sibwid : None,
2302            .u.configureRequest.x = x,
2303            .u.configureRequest.y = y,
2304            .u.configureRequest.width = w,
2305            .u.configureRequest.height = h,
2306            .u.configureRequest.borderWidth = bw,
2307            .u.configureRequest.valueMask = mask,
2308            .u.configureRequest.parent = pParent->drawable.id
2309        };
2310        event.u.u.type = ConfigureRequest;
2311        event.u.u.detail = (mask & CWStackMode) ? smode : Above;
2312#ifdef PANORAMIX
2313        if (!noPanoramiXExtension && (!pParent || !pParent->parent)) {
2314            event.u.configureRequest.x += screenInfo.screens[0]->x;
2315            event.u.configureRequest.y += screenInfo.screens[0]->y;
2316        }
2317#endif
2318        if (MaybeDeliverEventsToClient(pParent, &event, 1,
2319                                       SubstructureRedirectMask, client) == 1)
2320            return Success;
2321    }
2322    if (action == RESIZE_WIN) {
2323        Bool size_change = (w != pWin->drawable.width)
2324            || (h != pWin->drawable.height);
2325
2326        if (size_change &&
2327            ((pWin->eventMask | wOtherEventMasks(pWin)) & ResizeRedirectMask)) {
2328            xEvent eventT = {
2329                .u.resizeRequest.window = pWin->drawable.id,
2330                .u.resizeRequest.width = w,
2331                .u.resizeRequest.height = h
2332            };
2333            eventT.u.u.type = ResizeRequest;
2334            if (MaybeDeliverEventsToClient(pWin, &eventT, 1,
2335                                           ResizeRedirectMask, client) == 1) {
2336                /* if event is delivered, leave the actual size alone. */
2337                w = pWin->drawable.width;
2338                h = pWin->drawable.height;
2339                size_change = FALSE;
2340            }
2341        }
2342        if (!size_change) {
2343            if (mask & (CWX | CWY))
2344                action = MOVE_WIN;
2345            else if (mask & (CWStackMode | CWBorderWidth))
2346                action = RESTACK_WIN;
2347            else                /* really nothing to do */
2348                return (Success);
2349        }
2350    }
2351
2352    if (action == RESIZE_WIN)
2353        /* we've already checked whether there's really a size change */
2354        goto ActuallyDoSomething;
2355    if ((mask & CWX) && (x != beforeX))
2356        goto ActuallyDoSomething;
2357    if ((mask & CWY) && (y != beforeY))
2358        goto ActuallyDoSomething;
2359    if ((mask & CWBorderWidth) && (bw != wBorderWidth(pWin)))
2360        goto ActuallyDoSomething;
2361    if (mask & CWStackMode) {
2362#ifndef ROOTLESS
2363        /* See above for why we always reorder in rootless mode. */
2364        if (pWin->nextSib != pSib)
2365#endif
2366            goto ActuallyDoSomething;
2367    }
2368    return Success;
2369
2370 ActuallyDoSomething:
2371    if (pWin->drawable.pScreen->ConfigNotify) {
2372        int ret;
2373
2374        ret =
2375            (*pWin->drawable.pScreen->ConfigNotify) (pWin, x, y, w, h, bw,
2376                                                     pSib);
2377        if (ret) {
2378            client->errorValue = 0;
2379            return ret;
2380        }
2381    }
2382
2383    if (SubStrSend(pWin, pParent)) {
2384        xEvent event = {
2385            .u.configureNotify.window = pWin->drawable.id,
2386            .u.configureNotify.aboveSibling = pSib ? pSib->drawable.id : None,
2387            .u.configureNotify.x = x,
2388            .u.configureNotify.y = y,
2389            .u.configureNotify.width = w,
2390            .u.configureNotify.height = h,
2391            .u.configureNotify.borderWidth = bw,
2392            .u.configureNotify.override = pWin->overrideRedirect
2393        };
2394        event.u.u.type = ConfigureNotify;
2395#ifdef PANORAMIX
2396        if (!noPanoramiXExtension && (!pParent || !pParent->parent)) {
2397            event.u.configureNotify.x += screenInfo.screens[0]->x;
2398            event.u.configureNotify.y += screenInfo.screens[0]->y;
2399        }
2400#endif
2401        DeliverEvents(pWin, &event, 1, NullWindow);
2402    }
2403    if (mask & CWBorderWidth) {
2404        if (action == RESTACK_WIN) {
2405            action = MOVE_WIN;
2406            pWin->borderWidth = bw;
2407        }
2408        else if ((action == MOVE_WIN) &&
2409                 (beforeX + wBorderWidth(pWin) == x + (int) bw) &&
2410                 (beforeY + wBorderWidth(pWin) == y + (int) bw)) {
2411            action = REBORDER_WIN;
2412            (*pWin->drawable.pScreen->ChangeBorderWidth) (pWin, bw);
2413        }
2414        else
2415            pWin->borderWidth = bw;
2416    }
2417    if (action == MOVE_WIN)
2418        (*pWin->drawable.pScreen->MoveWindow) (pWin, x, y, pSib,
2419                                               (mask & CWBorderWidth) ? VTOther
2420                                               : VTMove);
2421    else if (action == RESIZE_WIN)
2422        (*pWin->drawable.pScreen->ResizeWindow) (pWin, x, y, w, h, pSib);
2423    else if (mask & CWStackMode)
2424        ReflectStackChange(pWin, pSib, VTOther);
2425
2426    if (action != RESTACK_WIN)
2427        CheckCursorConfinement(pWin);
2428    return Success;
2429#undef RESTACK_WIN
2430#undef MOVE_WIN
2431#undef RESIZE_WIN
2432#undef REBORDER_WIN
2433}
2434
2435/******
2436 *
2437 * CirculateWindow
2438 *    For RaiseLowest, raises the lowest mapped child (if any) that is
2439 *    obscured by another child to the top of the stack.  For LowerHighest,
2440 *    lowers the highest mapped child (if any) that is obscuring another
2441 *    child to the bottom of the stack.	 Exposure processing is performed
2442 *
2443 ******/
2444
2445int
2446CirculateWindow(WindowPtr pParent, int direction, ClientPtr client)
2447{
2448    WindowPtr pWin, pHead, pFirst;
2449    xEvent event;
2450    BoxRec box;
2451
2452    pHead = RealChildHead(pParent);
2453    pFirst = pHead ? pHead->nextSib : pParent->firstChild;
2454    if (direction == RaiseLowest) {
2455        for (pWin = pParent->lastChild;
2456             (pWin != pHead) &&
2457             !(pWin->mapped &&
2458               AnyWindowOverlapsMe(pWin, pHead, WindowExtents(pWin, &box)));
2459             pWin = pWin->prevSib);
2460        if (pWin == pHead)
2461            return Success;
2462    }
2463    else {
2464        for (pWin = pFirst;
2465             pWin &&
2466             !(pWin->mapped &&
2467               IOverlapAnyWindow(pWin, WindowExtents(pWin, &box)));
2468             pWin = pWin->nextSib);
2469        if (!pWin)
2470            return Success;
2471    }
2472
2473    event = (xEvent) {
2474        .u.circulate.window = pWin->drawable.id,
2475        .u.circulate.parent = pParent->drawable.id,
2476        .u.circulate.event = pParent->drawable.id,
2477        .u.circulate.place = (direction == RaiseLowest) ?
2478                              PlaceOnTop : PlaceOnBottom,
2479    };
2480
2481    if (RedirectSend(pParent)) {
2482        event.u.u.type = CirculateRequest;
2483        if (MaybeDeliverEventsToClient(pParent, &event, 1,
2484                                       SubstructureRedirectMask, client) == 1)
2485            return Success;
2486    }
2487
2488    event.u.u.type = CirculateNotify;
2489    DeliverEvents(pWin, &event, 1, NullWindow);
2490    ReflectStackChange(pWin,
2491                       (direction == RaiseLowest) ? pFirst : NullWindow,
2492                       VTStack);
2493
2494    return Success;
2495}
2496
2497static int
2498CompareWIDs(WindowPtr pWin, void *value)
2499{                               /* must conform to VisitWindowProcPtr */
2500    Window *wid = (Window *) value;
2501
2502    if (pWin->drawable.id == *wid)
2503        return WT_STOPWALKING;
2504    else
2505        return WT_WALKCHILDREN;
2506}
2507
2508/*****
2509 *  ReparentWindow
2510 *****/
2511
2512int
2513ReparentWindow(WindowPtr pWin, WindowPtr pParent,
2514               int x, int y, ClientPtr client)
2515{
2516    WindowPtr pPrev, pPriorParent;
2517    Bool WasMapped = (Bool) (pWin->mapped);
2518    xEvent event;
2519    int bw = wBorderWidth(pWin);
2520    ScreenPtr pScreen;
2521
2522    pScreen = pWin->drawable.pScreen;
2523    if (TraverseTree(pWin, CompareWIDs, (void *) &pParent->drawable.id) ==
2524        WT_STOPWALKING)
2525        return BadMatch;
2526    if (!MakeWindowOptional(pWin))
2527        return BadAlloc;
2528
2529    if (WasMapped)
2530        UnmapWindow(pWin, FALSE);
2531
2532    event = (xEvent) {
2533        .u.reparent.window = pWin->drawable.id,
2534        .u.reparent.parent = pParent->drawable.id,
2535        .u.reparent.x = x,
2536        .u.reparent.y = y,
2537        .u.reparent.override = pWin->overrideRedirect
2538    };
2539    event.u.u.type = ReparentNotify;
2540#ifdef PANORAMIX
2541    if (!noPanoramiXExtension && !pParent->parent) {
2542        event.u.reparent.x += screenInfo.screens[0]->x;
2543        event.u.reparent.y += screenInfo.screens[0]->y;
2544    }
2545#endif
2546    DeliverEvents(pWin, &event, 1, pParent);
2547
2548    /* take out of sibling chain */
2549
2550    pPriorParent = pPrev = pWin->parent;
2551    if (pPrev->firstChild == pWin)
2552        pPrev->firstChild = pWin->nextSib;
2553    if (pPrev->lastChild == pWin)
2554        pPrev->lastChild = pWin->prevSib;
2555
2556    if (pWin->nextSib)
2557        pWin->nextSib->prevSib = pWin->prevSib;
2558    if (pWin->prevSib)
2559        pWin->prevSib->nextSib = pWin->nextSib;
2560
2561    /* insert at begining of pParent */
2562    pWin->parent = pParent;
2563    pPrev = RealChildHead(pParent);
2564    if (pPrev) {
2565        pWin->nextSib = pPrev->nextSib;
2566        if (pPrev->nextSib)
2567            pPrev->nextSib->prevSib = pWin;
2568        else
2569            pParent->lastChild = pWin;
2570        pPrev->nextSib = pWin;
2571        pWin->prevSib = pPrev;
2572    }
2573    else {
2574        pWin->nextSib = pParent->firstChild;
2575        pWin->prevSib = NullWindow;
2576        if (pParent->firstChild)
2577            pParent->firstChild->prevSib = pWin;
2578        else
2579            pParent->lastChild = pWin;
2580        pParent->firstChild = pWin;
2581    }
2582
2583    pWin->origin.x = x + bw;
2584    pWin->origin.y = y + bw;
2585    pWin->drawable.x = x + bw + pParent->drawable.x;
2586    pWin->drawable.y = y + bw + pParent->drawable.y;
2587
2588    /* clip to parent */
2589    SetWinSize(pWin);
2590    SetBorderSize(pWin);
2591
2592    if (pScreen->ReparentWindow)
2593        (*pScreen->ReparentWindow) (pWin, pPriorParent);
2594    (*pScreen->PositionWindow) (pWin, pWin->drawable.x, pWin->drawable.y);
2595    ResizeChildrenWinSize(pWin, 0, 0, 0, 0);
2596
2597    CheckWindowOptionalNeed(pWin);
2598
2599    if (WasMapped)
2600        MapWindow(pWin, client);
2601    RecalculateDeliverableEvents(pWin);
2602    return Success;
2603}
2604
2605static void
2606RealizeTree(WindowPtr pWin)
2607{
2608    WindowPtr pChild;
2609    RealizeWindowProcPtr Realize;
2610
2611    Realize = pWin->drawable.pScreen->RealizeWindow;
2612    pChild = pWin;
2613    while (1) {
2614        if (pChild->mapped) {
2615            pChild->realized = TRUE;
2616            pChild->viewable = (pChild->drawable.class == InputOutput);
2617            (*Realize) (pChild);
2618            if (pChild->firstChild) {
2619                pChild = pChild->firstChild;
2620                continue;
2621            }
2622        }
2623        while (!pChild->nextSib && (pChild != pWin))
2624            pChild = pChild->parent;
2625        if (pChild == pWin)
2626            return;
2627        pChild = pChild->nextSib;
2628    }
2629}
2630
2631static Bool
2632MaybeDeliverMapRequest(WindowPtr pWin, WindowPtr pParent, ClientPtr client)
2633{
2634    xEvent event = {
2635        .u.mapRequest.window = pWin->drawable.id,
2636        .u.mapRequest.parent = pParent->drawable.id
2637    };
2638    event.u.u.type = MapRequest;
2639
2640    return MaybeDeliverEventsToClient(pParent, &event, 1,
2641                                      SubstructureRedirectMask,
2642                                      client) == 1;
2643}
2644
2645static void
2646DeliverMapNotify(WindowPtr pWin)
2647{
2648    xEvent event = {
2649        .u.mapNotify.window = pWin->drawable.id,
2650        .u.mapNotify.override = pWin->overrideRedirect,
2651    };
2652    event.u.u.type = MapNotify;
2653    DeliverEvents(pWin, &event, 1, NullWindow);
2654}
2655
2656/*****
2657 * MapWindow
2658 *    If some other client has selected SubStructureReDirect on the parent
2659 *    and override-redirect is xFalse, then a MapRequest event is generated,
2660 *    but the window remains unmapped.	Otherwise, the window is mapped and a
2661 *    MapNotify event is generated.
2662 *****/
2663
2664int
2665MapWindow(WindowPtr pWin, ClientPtr client)
2666{
2667    ScreenPtr pScreen;
2668
2669    WindowPtr pParent;
2670    WindowPtr pLayerWin;
2671
2672    if (pWin->mapped)
2673        return Success;
2674
2675    /* general check for permission to map window */
2676    if (XaceHook(XACE_RESOURCE_ACCESS, client, pWin->drawable.id, RT_WINDOW,
2677                 pWin, RT_NONE, NULL, DixShowAccess) != Success)
2678        return Success;
2679
2680    pScreen = pWin->drawable.pScreen;
2681    if ((pParent = pWin->parent)) {
2682        Bool anyMarked;
2683
2684        if ((!pWin->overrideRedirect) && (RedirectSend(pParent)))
2685            if (MaybeDeliverMapRequest(pWin, pParent, client))
2686                return Success;
2687
2688        pWin->mapped = TRUE;
2689        if (SubStrSend(pWin, pParent))
2690            DeliverMapNotify(pWin);
2691
2692        if (!pParent->realized)
2693            return Success;
2694        RealizeTree(pWin);
2695        if (pWin->viewable) {
2696            anyMarked = (*pScreen->MarkOverlappedWindows) (pWin, pWin,
2697                                                           &pLayerWin);
2698            if (anyMarked) {
2699                (*pScreen->ValidateTree) (pLayerWin->parent, pLayerWin, VTMap);
2700                (*pScreen->HandleExposures) (pLayerWin->parent);
2701                if (pScreen->PostValidateTree)
2702                    (*pScreen->PostValidateTree) (pLayerWin->parent, pLayerWin,
2703                                                  VTMap);
2704            }
2705        }
2706        WindowsRestructured();
2707    }
2708    else {
2709        RegionRec temp;
2710
2711        pWin->mapped = TRUE;
2712        pWin->realized = TRUE;  /* for roots */
2713        pWin->viewable = pWin->drawable.class == InputOutput;
2714        /* We SHOULD check for an error value here XXX */
2715        (*pScreen->RealizeWindow) (pWin);
2716        if (pScreen->ClipNotify)
2717            (*pScreen->ClipNotify) (pWin, 0, 0);
2718        if (pScreen->PostValidateTree)
2719            (*pScreen->PostValidateTree) (NullWindow, pWin, VTMap);
2720        RegionNull(&temp);
2721        RegionCopy(&temp, &pWin->clipList);
2722        (*pScreen->WindowExposures) (pWin, &temp);
2723        RegionUninit(&temp);
2724    }
2725
2726    return Success;
2727}
2728
2729/*****
2730 * MapSubwindows
2731 *    Performs a MapWindow all unmapped children of the window, in top
2732 *    to bottom stacking order.
2733 *****/
2734
2735void
2736MapSubwindows(WindowPtr pParent, ClientPtr client)
2737{
2738    WindowPtr pWin;
2739    WindowPtr pFirstMapped = NullWindow;
2740    ScreenPtr pScreen;
2741    Mask parentRedirect;
2742    Mask parentNotify;
2743    Bool anyMarked;
2744    WindowPtr pLayerWin;
2745
2746    pScreen = pParent->drawable.pScreen;
2747    parentRedirect = RedirectSend(pParent);
2748    parentNotify = SubSend(pParent);
2749    anyMarked = FALSE;
2750    for (pWin = pParent->firstChild; pWin; pWin = pWin->nextSib) {
2751        if (!pWin->mapped) {
2752            if (parentRedirect && !pWin->overrideRedirect)
2753                if (MaybeDeliverMapRequest(pWin, pParent, client))
2754                    continue;
2755
2756            pWin->mapped = TRUE;
2757            if (parentNotify || StrSend(pWin))
2758                DeliverMapNotify(pWin);
2759
2760            if (!pFirstMapped)
2761                pFirstMapped = pWin;
2762            if (pParent->realized) {
2763                RealizeTree(pWin);
2764                if (pWin->viewable) {
2765                    anyMarked |= (*pScreen->MarkOverlappedWindows) (pWin, pWin,
2766                                                                    NULL);
2767                }
2768            }
2769        }
2770    }
2771
2772    if (pFirstMapped) {
2773        pLayerWin = (*pScreen->GetLayerWindow) (pParent);
2774        if (pLayerWin->parent != pParent) {
2775            anyMarked |= (*pScreen->MarkOverlappedWindows) (pLayerWin,
2776                                                            pLayerWin, NULL);
2777            pFirstMapped = pLayerWin;
2778        }
2779        if (anyMarked) {
2780            (*pScreen->ValidateTree) (pLayerWin->parent, pFirstMapped, VTMap);
2781            (*pScreen->HandleExposures) (pLayerWin->parent);
2782            if (pScreen->PostValidateTree)
2783                (*pScreen->PostValidateTree) (pLayerWin->parent, pFirstMapped,
2784                                              VTMap);
2785        }
2786        WindowsRestructured();
2787    }
2788}
2789
2790static void
2791UnrealizeTree(WindowPtr pWin, Bool fromConfigure)
2792{
2793    WindowPtr pChild;
2794    UnrealizeWindowProcPtr Unrealize;
2795    MarkUnrealizedWindowProcPtr MarkUnrealizedWindow;
2796
2797    Unrealize = pWin->drawable.pScreen->UnrealizeWindow;
2798    MarkUnrealizedWindow = pWin->drawable.pScreen->MarkUnrealizedWindow;
2799    pChild = pWin;
2800    while (1) {
2801        if (pChild->realized) {
2802            pChild->realized = FALSE;
2803            pChild->visibility = VisibilityNotViewable;
2804#ifdef PANORAMIX
2805            if (!noPanoramiXExtension && !pChild->drawable.pScreen->myNum) {
2806                PanoramiXRes *win;
2807                int rc = dixLookupResourceByType((void **) &win,
2808                                                 pChild->drawable.id,
2809                                                 XRT_WINDOW,
2810                                                 serverClient, DixWriteAccess);
2811
2812                if (rc == Success)
2813                    win->u.win.visibility = VisibilityNotViewable;
2814            }
2815#endif
2816            (*Unrealize) (pChild);
2817            DeleteWindowFromAnyEvents(pChild, FALSE);
2818            if (pChild->viewable) {
2819                pChild->viewable = FALSE;
2820                (*MarkUnrealizedWindow) (pChild, pWin, fromConfigure);
2821                pChild->drawable.serialNumber = NEXT_SERIAL_NUMBER;
2822            }
2823            if (pChild->firstChild) {
2824                pChild = pChild->firstChild;
2825                continue;
2826            }
2827        }
2828        while (!pChild->nextSib && (pChild != pWin))
2829            pChild = pChild->parent;
2830        if (pChild == pWin)
2831            return;
2832        pChild = pChild->nextSib;
2833    }
2834}
2835
2836static void
2837DeliverUnmapNotify(WindowPtr pWin, Bool fromConfigure)
2838{
2839    xEvent event = {
2840        .u.unmapNotify.window = pWin->drawable.id,
2841        .u.unmapNotify.fromConfigure = fromConfigure
2842    };
2843    event.u.u.type = UnmapNotify;
2844    DeliverEvents(pWin, &event, 1, NullWindow);
2845}
2846
2847/*****
2848 * UnmapWindow
2849 *    If the window is already unmapped, this request has no effect.
2850 *    Otherwise, the window is unmapped and an UnMapNotify event is
2851 *    generated.  Cannot unmap a root window.
2852 *****/
2853
2854int
2855UnmapWindow(WindowPtr pWin, Bool fromConfigure)
2856{
2857    WindowPtr pParent;
2858    Bool wasRealized = (Bool) pWin->realized;
2859    Bool wasViewable = (Bool) pWin->viewable;
2860    ScreenPtr pScreen = pWin->drawable.pScreen;
2861    WindowPtr pLayerWin = pWin;
2862
2863    if ((!pWin->mapped) || (!(pParent = pWin->parent)))
2864        return Success;
2865    if (SubStrSend(pWin, pParent))
2866        DeliverUnmapNotify(pWin, fromConfigure);
2867    if (wasViewable && !fromConfigure) {
2868        pWin->valdata = UnmapValData;
2869        (*pScreen->MarkOverlappedWindows) (pWin, pWin->nextSib, &pLayerWin);
2870        (*pScreen->MarkWindow) (pLayerWin->parent);
2871    }
2872    pWin->mapped = FALSE;
2873    if (wasRealized)
2874        UnrealizeTree(pWin, fromConfigure);
2875    if (wasViewable) {
2876        if (!fromConfigure) {
2877            (*pScreen->ValidateTree) (pLayerWin->parent, pWin, VTUnmap);
2878            (*pScreen->HandleExposures) (pLayerWin->parent);
2879            if (pScreen->PostValidateTree)
2880                (*pScreen->PostValidateTree) (pLayerWin->parent, pWin, VTUnmap);
2881        }
2882    }
2883    if (wasRealized && !fromConfigure) {
2884        WindowsRestructured();
2885        WindowGone(pWin);
2886    }
2887    return Success;
2888}
2889
2890/*****
2891 * UnmapSubwindows
2892 *    Performs an UnmapWindow request with the specified mode on all mapped
2893 *    children of the window, in bottom to top stacking order.
2894 *****/
2895
2896void
2897UnmapSubwindows(WindowPtr pWin)
2898{
2899    WindowPtr pChild, pHead;
2900    Bool wasRealized = (Bool) pWin->realized;
2901    Bool wasViewable = (Bool) pWin->viewable;
2902    Bool anyMarked = FALSE;
2903    Mask parentNotify;
2904    WindowPtr pLayerWin = NULL;
2905    ScreenPtr pScreen = pWin->drawable.pScreen;
2906
2907    if (!pWin->firstChild)
2908        return;
2909    parentNotify = SubSend(pWin);
2910    pHead = RealChildHead(pWin);
2911
2912    if (wasViewable)
2913        pLayerWin = (*pScreen->GetLayerWindow) (pWin);
2914
2915    for (pChild = pWin->lastChild; pChild != pHead; pChild = pChild->prevSib) {
2916        if (pChild->mapped) {
2917            if (parentNotify || StrSend(pChild))
2918                DeliverUnmapNotify(pChild, xFalse);
2919            if (pChild->viewable) {
2920                pChild->valdata = UnmapValData;
2921                anyMarked = TRUE;
2922            }
2923            pChild->mapped = FALSE;
2924            if (pChild->realized)
2925                UnrealizeTree(pChild, FALSE);
2926        }
2927    }
2928    if (wasViewable) {
2929        if (anyMarked) {
2930            if (pLayerWin->parent == pWin)
2931                (*pScreen->MarkWindow) (pWin);
2932            else {
2933                WindowPtr ptmp;
2934
2935                (*pScreen->MarkOverlappedWindows) (pWin, pLayerWin, NULL);
2936                (*pScreen->MarkWindow) (pLayerWin->parent);
2937
2938                /* Windows between pWin and pLayerWin may not have been marked */
2939                ptmp = pWin;
2940
2941                while (ptmp != pLayerWin->parent) {
2942                    (*pScreen->MarkWindow) (ptmp);
2943                    ptmp = ptmp->parent;
2944                }
2945                pHead = pWin->firstChild;
2946            }
2947            (*pScreen->ValidateTree) (pLayerWin->parent, pHead, VTUnmap);
2948            (*pScreen->HandleExposures) (pLayerWin->parent);
2949            if (pScreen->PostValidateTree)
2950                (*pScreen->PostValidateTree) (pLayerWin->parent, pHead,
2951                                              VTUnmap);
2952        }
2953    }
2954    if (wasRealized) {
2955        WindowsRestructured();
2956        WindowGone(pWin);
2957    }
2958}
2959
2960void
2961HandleSaveSet(ClientPtr client)
2962{
2963    WindowPtr pParent, pWin;
2964    int j;
2965
2966    for (j = 0; j < client->numSaved; j++) {
2967        pWin = SaveSetWindow(client->saveSet[j]);
2968        if (SaveSetToRoot(client->saveSet[j]))
2969            pParent = pWin->drawable.pScreen->root;
2970        else
2971        {
2972            pParent = pWin->parent;
2973            while (pParent && (wClient(pParent) == client))
2974                pParent = pParent->parent;
2975        }
2976        if (pParent) {
2977            if (pParent != pWin->parent) {
2978                /* unmap first so that ReparentWindow doesn't remap */
2979                if (!SaveSetShouldMap(client->saveSet[j]))
2980                    UnmapWindow(pWin, FALSE);
2981                ReparentWindow(pWin, pParent,
2982                               pWin->drawable.x - wBorderWidth(pWin) -
2983                               pParent->drawable.x,
2984                               pWin->drawable.y - wBorderWidth(pWin) -
2985                               pParent->drawable.y, client);
2986                if (!pWin->realized && pWin->mapped)
2987                    pWin->mapped = FALSE;
2988            }
2989            if (SaveSetShouldMap(client->saveSet[j]))
2990                MapWindow(pWin, client);
2991        }
2992    }
2993    free(client->saveSet);
2994    client->numSaved = 0;
2995    client->saveSet = NULL;
2996}
2997
2998/**
2999 *
3000 * \param x,y  in root
3001 */
3002Bool
3003PointInWindowIsVisible(WindowPtr pWin, int x, int y)
3004{
3005    BoxRec box;
3006
3007    if (!pWin->realized)
3008        return FALSE;
3009    if (RegionContainsPoint(&pWin->borderClip, x, y, &box)
3010        && (!wInputShape(pWin) ||
3011            RegionContainsPoint(wInputShape(pWin),
3012                                x - pWin->drawable.x,
3013                                y - pWin->drawable.y, &box)))
3014        return TRUE;
3015    return FALSE;
3016}
3017
3018RegionPtr
3019NotClippedByChildren(WindowPtr pWin)
3020{
3021    RegionPtr pReg = RegionCreate(NullBox, 1);
3022
3023    if (pWin->parent ||
3024        screenIsSaved != SCREEN_SAVER_ON ||
3025        !HasSaverWindow(pWin->drawable.pScreen)) {
3026        RegionIntersect(pReg, &pWin->borderClip, &pWin->winSize);
3027    }
3028    return pReg;
3029}
3030
3031void
3032SendVisibilityNotify(WindowPtr pWin)
3033{
3034    xEvent event;
3035    unsigned int visibility = pWin->visibility;
3036
3037#ifdef PANORAMIX
3038    /* This is not quite correct yet, but it's close */
3039    if (!noPanoramiXExtension) {
3040        PanoramiXRes *win;
3041        WindowPtr pWin2;
3042        int rc, i, Scrnum;
3043
3044        Scrnum = pWin->drawable.pScreen->myNum;
3045
3046        win = PanoramiXFindIDByScrnum(XRT_WINDOW, pWin->drawable.id, Scrnum);
3047
3048        if (!win || (win->u.win.visibility == visibility))
3049            return;
3050
3051        switch (visibility) {
3052        case VisibilityUnobscured:
3053        FOR_NSCREENS(i) {
3054            if (i == Scrnum)
3055                continue;
3056
3057            rc = dixLookupWindow(&pWin2, win->info[i].id, serverClient,
3058                                 DixWriteAccess);
3059
3060            if (rc == Success) {
3061                if (pWin2->visibility == VisibilityPartiallyObscured)
3062                    return;
3063
3064                if (!i)
3065                    pWin = pWin2;
3066            }
3067        }
3068            break;
3069        case VisibilityPartiallyObscured:
3070            if (Scrnum) {
3071                rc = dixLookupWindow(&pWin2, win->info[0].id, serverClient,
3072                                     DixWriteAccess);
3073                if (rc == Success)
3074                    pWin = pWin2;
3075            }
3076            break;
3077        case VisibilityFullyObscured:
3078        FOR_NSCREENS(i) {
3079            if (i == Scrnum)
3080                continue;
3081
3082            rc = dixLookupWindow(&pWin2, win->info[i].id, serverClient,
3083                                 DixWriteAccess);
3084
3085            if (rc == Success) {
3086                if (pWin2->visibility != VisibilityFullyObscured)
3087                    return;
3088
3089                if (!i)
3090                    pWin = pWin2;
3091            }
3092        }
3093            break;
3094        }
3095
3096        win->u.win.visibility = visibility;
3097    }
3098#endif
3099
3100    event = (xEvent) {
3101        .u.visibility.window = pWin->drawable.id,
3102        .u.visibility.state = visibility
3103    };
3104    event.u.u.type = VisibilityNotify;
3105    DeliverEvents(pWin, &event, 1, NullWindow);
3106}
3107
3108#define RANDOM_WIDTH 32
3109int
3110dixSaveScreens(ClientPtr client, int on, int mode)
3111{
3112    int rc, i, what, type;
3113
3114    if (on == SCREEN_SAVER_FORCER) {
3115        if (mode == ScreenSaverReset)
3116            what = SCREEN_SAVER_OFF;
3117        else
3118            what = SCREEN_SAVER_ON;
3119        type = what;
3120    }
3121    else {
3122        what = on;
3123        type = what;
3124        if (what == screenIsSaved)
3125            type = SCREEN_SAVER_CYCLE;
3126    }
3127
3128    for (i = 0; i < screenInfo.numScreens; i++) {
3129        rc = XaceHook(XACE_SCREENSAVER_ACCESS, client, screenInfo.screens[i],
3130                      DixShowAccess | DixHideAccess);
3131        if (rc != Success)
3132            return rc;
3133    }
3134    for (i = 0; i < screenInfo.numScreens; i++) {
3135        ScreenPtr pScreen = screenInfo.screens[i];
3136
3137        if (on == SCREEN_SAVER_FORCER)
3138            (*pScreen->SaveScreen) (pScreen, on);
3139        if (pScreen->screensaver.ExternalScreenSaver) {
3140            if ((*pScreen->screensaver.ExternalScreenSaver)
3141                (pScreen, type, on == SCREEN_SAVER_FORCER))
3142                continue;
3143        }
3144        if (type == screenIsSaved)
3145            continue;
3146        switch (type) {
3147        case SCREEN_SAVER_OFF:
3148            if (pScreen->screensaver.blanked == SCREEN_IS_BLANKED) {
3149                (*pScreen->SaveScreen) (pScreen, what);
3150            }
3151            else if (HasSaverWindow(pScreen)) {
3152                pScreen->screensaver.pWindow = NullWindow;
3153                FreeResource(pScreen->screensaver.wid, RT_NONE);
3154            }
3155            break;
3156        case SCREEN_SAVER_CYCLE:
3157            if (pScreen->screensaver.blanked == SCREEN_IS_TILED) {
3158                WindowPtr pWin = pScreen->screensaver.pWindow;
3159
3160                /* make it look like screen saver is off, so that
3161                 * NotClippedByChildren will compute a clip list
3162                 * for the root window, so PaintWindow works
3163                 */
3164                screenIsSaved = SCREEN_SAVER_OFF;
3165                (*pWin->drawable.pScreen->MoveWindow) (pWin,
3166                                                       (short) (-
3167                                                                (rand() %
3168                                                                 RANDOM_WIDTH)),
3169                                                       (short) (-
3170                                                                (rand() %
3171                                                                 RANDOM_WIDTH)),
3172                                                       pWin->nextSib, VTMove);
3173                screenIsSaved = SCREEN_SAVER_ON;
3174            }
3175            /*
3176             * Call the DDX saver in case it wants to do something
3177             * at cycle time
3178             */
3179            else if (pScreen->screensaver.blanked == SCREEN_IS_BLANKED) {
3180                (*pScreen->SaveScreen) (pScreen, type);
3181            }
3182            break;
3183        case SCREEN_SAVER_ON:
3184            if (ScreenSaverBlanking != DontPreferBlanking) {
3185                if ((*pScreen->SaveScreen) (pScreen, what)) {
3186                    pScreen->screensaver.blanked = SCREEN_IS_BLANKED;
3187                    continue;
3188                }
3189                if ((ScreenSaverAllowExposures != DontAllowExposures) &&
3190                    TileScreenSaver(pScreen, SCREEN_IS_BLACK)) {
3191                    pScreen->screensaver.blanked = SCREEN_IS_BLACK;
3192                    continue;
3193                }
3194            }
3195            if ((ScreenSaverAllowExposures != DontAllowExposures) &&
3196                TileScreenSaver(pScreen, SCREEN_IS_TILED)) {
3197                pScreen->screensaver.blanked = SCREEN_IS_TILED;
3198            }
3199            else
3200                pScreen->screensaver.blanked = SCREEN_ISNT_SAVED;
3201            break;
3202        }
3203    }
3204    screenIsSaved = what;
3205    if (mode == ScreenSaverReset) {
3206        if (on == SCREEN_SAVER_FORCER) {
3207            DeviceIntPtr dev;
3208            UpdateCurrentTimeIf();
3209            nt_list_for_each_entry(dev, inputInfo.devices, next)
3210                NoticeTime(dev, currentTime);
3211        }
3212        SetScreenSaverTimer();
3213    }
3214    return Success;
3215}
3216
3217int
3218SaveScreens(int on, int mode)
3219{
3220    return dixSaveScreens(serverClient, on, mode);
3221}
3222
3223static Bool
3224TileScreenSaver(ScreenPtr pScreen, int kind)
3225{
3226    int j;
3227    int result;
3228    XID attributes[3];
3229    Mask mask;
3230    WindowPtr pWin;
3231    CursorMetricRec cm;
3232    unsigned char *srcbits, *mskbits;
3233    CursorPtr cursor;
3234    XID cursorID = 0;
3235    int attri;
3236
3237    mask = 0;
3238    attri = 0;
3239    switch (kind) {
3240    case SCREEN_IS_TILED:
3241        switch (pScreen->root->backgroundState) {
3242        case BackgroundPixel:
3243            attributes[attri++] = pScreen->root->background.pixel;
3244            mask |= CWBackPixel;
3245            break;
3246        case BackgroundPixmap:
3247            attributes[attri++] = None;
3248            mask |= CWBackPixmap;
3249            break;
3250        default:
3251            break;
3252        }
3253        break;
3254    case SCREEN_IS_BLACK:
3255        attributes[attri++] = pScreen->root->drawable.pScreen->blackPixel;
3256        mask |= CWBackPixel;
3257        break;
3258    }
3259    mask |= CWOverrideRedirect;
3260    attributes[attri++] = xTrue;
3261
3262    /*
3263     * create a blank cursor
3264     */
3265
3266    cm.width = 16;
3267    cm.height = 16;
3268    cm.xhot = 8;
3269    cm.yhot = 8;
3270    srcbits = malloc(BitmapBytePad(32) * 16);
3271    mskbits = malloc(BitmapBytePad(32) * 16);
3272    if (!srcbits || !mskbits) {
3273        free(srcbits);
3274        free(mskbits);
3275        cursor = 0;
3276    }
3277    else {
3278        for (j = 0; j < BitmapBytePad(32) * 16; j++)
3279            srcbits[j] = mskbits[j] = 0x0;
3280        result = AllocARGBCursor(srcbits, mskbits, NULL, &cm, 0, 0, 0, 0, 0, 0,
3281                                 &cursor, serverClient, (XID) 0);
3282        if (cursor) {
3283            cursorID = FakeClientID(0);
3284            if (AddResource(cursorID, RT_CURSOR, (void *) cursor)) {
3285                attributes[attri] = cursorID;
3286                mask |= CWCursor;
3287            }
3288            else
3289                cursor = 0;
3290        }
3291        else {
3292            free(srcbits);
3293            free(mskbits);
3294        }
3295    }
3296
3297    pWin = pScreen->screensaver.pWindow =
3298        CreateWindow(pScreen->screensaver.wid,
3299                     pScreen->root,
3300                     -RANDOM_WIDTH, -RANDOM_WIDTH,
3301                     (unsigned short) pScreen->width + RANDOM_WIDTH,
3302                     (unsigned short) pScreen->height + RANDOM_WIDTH,
3303                     0, InputOutput, mask, attributes, 0, serverClient,
3304                     wVisual(pScreen->root), &result);
3305
3306    if (cursor)
3307        FreeResource(cursorID, RT_NONE);
3308
3309    if (!pWin)
3310        return FALSE;
3311
3312    if (!AddResource(pWin->drawable.id, RT_WINDOW,
3313                     (void *) pScreen->screensaver.pWindow))
3314        return FALSE;
3315
3316    if (mask & CWBackPixmap) {
3317        MakeRootTile(pWin);
3318        (*pWin->drawable.pScreen->ChangeWindowAttributes) (pWin, CWBackPixmap);
3319    }
3320    MapWindow(pWin, serverClient);
3321    return TRUE;
3322}
3323
3324/*
3325 * FindWindowWithOptional
3326 *
3327 * search ancestors of the given window for an entry containing
3328 * a WindowOpt structure.  Assumptions:	 some parent will
3329 * contain the structure.
3330 */
3331
3332WindowPtr
3333FindWindowWithOptional(WindowPtr w)
3334{
3335    do
3336        w = w->parent;
3337    while (!w->optional);
3338    return w;
3339}
3340
3341/*
3342 * CheckWindowOptionalNeed
3343 *
3344 * check each optional entry in the given window to see if
3345 * the value is satisfied by the default rules.	 If so,
3346 * release the optional record
3347 */
3348
3349void
3350CheckWindowOptionalNeed(WindowPtr w)
3351{
3352    WindowOptPtr optional;
3353    WindowOptPtr parentOptional;
3354
3355    if (!w->parent || !w->optional)
3356        return;
3357    optional = w->optional;
3358    if (optional->dontPropagateMask != DontPropagateMasks[w->dontPropagate])
3359        return;
3360    if (optional->otherEventMasks != 0)
3361        return;
3362    if (optional->otherClients != NULL)
3363        return;
3364    if (optional->passiveGrabs != NULL)
3365        return;
3366    if (optional->userProps != NULL)
3367        return;
3368    if (optional->backingBitPlanes != (CARD32)~0L)
3369        return;
3370    if (optional->backingPixel != 0)
3371        return;
3372    if (optional->boundingShape != NULL)
3373        return;
3374    if (optional->clipShape != NULL)
3375        return;
3376    if (optional->inputShape != NULL)
3377        return;
3378    if (optional->inputMasks != NULL)
3379        return;
3380    if (optional->deviceCursors != NULL) {
3381        DevCursNodePtr pNode = optional->deviceCursors;
3382
3383        while (pNode) {
3384            if (pNode->cursor != None)
3385                return;
3386            pNode = pNode->next;
3387        }
3388    }
3389
3390    parentOptional = FindWindowWithOptional(w)->optional;
3391    if (optional->visual != parentOptional->visual)
3392        return;
3393    if (optional->cursor != None &&
3394        (optional->cursor != parentOptional->cursor || w->parent->cursorIsNone))
3395        return;
3396    if (optional->colormap != parentOptional->colormap)
3397        return;
3398    DisposeWindowOptional(w);
3399}
3400
3401/*
3402 * MakeWindowOptional
3403 *
3404 * create an optional record and initialize it with the default
3405 * values.
3406 */
3407
3408Bool
3409MakeWindowOptional(WindowPtr pWin)
3410{
3411    WindowOptPtr optional;
3412    WindowOptPtr parentOptional;
3413
3414    if (pWin->optional)
3415        return TRUE;
3416    optional = malloc(sizeof(WindowOptRec));
3417    if (!optional)
3418        return FALSE;
3419    optional->dontPropagateMask = DontPropagateMasks[pWin->dontPropagate];
3420    optional->otherEventMasks = 0;
3421    optional->otherClients = NULL;
3422    optional->passiveGrabs = NULL;
3423    optional->userProps = NULL;
3424    optional->backingBitPlanes = ~0L;
3425    optional->backingPixel = 0;
3426    optional->boundingShape = NULL;
3427    optional->clipShape = NULL;
3428    optional->inputShape = NULL;
3429    optional->inputMasks = NULL;
3430    optional->deviceCursors = NULL;
3431
3432    parentOptional = FindWindowWithOptional(pWin)->optional;
3433    optional->visual = parentOptional->visual;
3434    if (!pWin->cursorIsNone) {
3435        optional->cursor = RefCursor(parentOptional->cursor);
3436    }
3437    else {
3438        optional->cursor = None;
3439    }
3440    optional->colormap = parentOptional->colormap;
3441    pWin->optional = optional;
3442    return TRUE;
3443}
3444
3445/*
3446 * Changes the cursor struct for the given device and the given window.
3447 * A cursor that does not have a device cursor set will use whatever the
3448 * standard cursor is for the window. If all devices have a cursor set,
3449 * changing the window cursor (e.g. using XDefineCursor()) will not have any
3450 * visible effect. Only when one of the device cursors is set to None again,
3451 * this device's cursor will display the changed standard cursor.
3452 *
3453 * CursorIsNone of the window struct is NOT modified if you set a device
3454 * cursor.
3455 *
3456 * Assumption: If there is a node for a device in the list, the device has a
3457 * cursor. If the cursor is set to None, it is inherited by the parent.
3458 */
3459int
3460ChangeWindowDeviceCursor(WindowPtr pWin, DeviceIntPtr pDev, CursorPtr pCursor)
3461{
3462    DevCursNodePtr pNode, pPrev;
3463    CursorPtr pOldCursor = NULL;
3464    ScreenPtr pScreen;
3465    WindowPtr pChild;
3466
3467    if (!pWin->optional && !MakeWindowOptional(pWin))
3468        return BadAlloc;
3469
3470    /* 1) Check if window has device cursor set
3471     *  Yes: 1.1) swap cursor with given cursor if parent does not have same
3472     *            cursor, free old cursor
3473     *       1.2) free old cursor, use parent cursor
3474     *  No: 1.1) add node to beginning of list.
3475     *      1.2) add cursor to node if parent does not have same cursor
3476     *      1.3) use parent cursor if parent does not have same cursor
3477     *  2) Patch up children if child has a devcursor
3478     *  2.1) if child has cursor None, it inherited from parent, set to old
3479     *  cursor
3480     *  2.2) if child has same cursor as new cursor, remove and set to None
3481     */
3482
3483    pScreen = pWin->drawable.pScreen;
3484
3485    if (WindowSeekDeviceCursor(pWin, pDev, &pNode, &pPrev)) {
3486        /* has device cursor */
3487
3488        if (pNode->cursor == pCursor)
3489            return Success;
3490
3491        pOldCursor = pNode->cursor;
3492
3493        if (!pCursor) {         /* remove from list */
3494            if (pPrev)
3495                pPrev->next = pNode->next;
3496            else
3497                /* first item in list */
3498                pWin->optional->deviceCursors = pNode->next;
3499
3500            free(pNode);
3501            goto out;
3502        }
3503
3504    }
3505    else {
3506        /* no device cursor yet */
3507        DevCursNodePtr pNewNode;
3508
3509        if (!pCursor)
3510            return Success;
3511
3512        pNewNode = malloc(sizeof(DevCursNodeRec));
3513        pNewNode->dev = pDev;
3514        pNewNode->next = pWin->optional->deviceCursors;
3515        pWin->optional->deviceCursors = pNewNode;
3516        pNode = pNewNode;
3517
3518    }
3519
3520    if (pCursor && WindowParentHasDeviceCursor(pWin, pDev, pCursor))
3521        pNode->cursor = None;
3522    else {
3523        pNode->cursor = RefCursor(pCursor);
3524    }
3525
3526    pNode = pPrev = NULL;
3527    /* fix up children */
3528    for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) {
3529        if (WindowSeekDeviceCursor(pChild, pDev, &pNode, &pPrev)) {
3530            if (pNode->cursor == None) {        /* inherited from parent */
3531                pNode->cursor = RefCursor(pOldCursor);
3532            }
3533            else if (pNode->cursor == pCursor) {
3534                pNode->cursor = None;
3535                FreeCursor(pCursor, (Cursor) 0);        /* fix up refcnt */
3536            }
3537        }
3538    }
3539
3540 out:
3541    CursorVisible = TRUE;
3542
3543    if (pWin->realized)
3544        WindowHasNewCursor(pWin);
3545
3546    if (pOldCursor)
3547        FreeCursor(pOldCursor, (Cursor) 0);
3548
3549    /* FIXME: We SHOULD check for an error value here XXX
3550       (comment taken from ChangeWindowAttributes) */
3551    (*pScreen->ChangeWindowAttributes) (pWin, CWCursor);
3552
3553    return Success;
3554}
3555
3556/* Get device cursor for given device or None if none is set */
3557CursorPtr
3558WindowGetDeviceCursor(WindowPtr pWin, DeviceIntPtr pDev)
3559{
3560    DevCursorList pList;
3561
3562    if (!pWin->optional || !pWin->optional->deviceCursors)
3563        return NULL;
3564
3565    pList = pWin->optional->deviceCursors;
3566
3567    while (pList) {
3568        if (pList->dev == pDev) {
3569            if (pList->cursor == None)  /* inherited from parent */
3570                return WindowGetDeviceCursor(pWin->parent, pDev);
3571            else
3572                return pList->cursor;
3573        }
3574        pList = pList->next;
3575    }
3576    return NULL;
3577}
3578
3579/* Searches for a DevCursorNode for the given window and device. If one is
3580 * found, return True and set pNode and pPrev to the node and to the node
3581 * before the node respectively. Otherwise return False.
3582 * If the device is the first in list, pPrev is set to NULL.
3583 */
3584static Bool
3585WindowSeekDeviceCursor(WindowPtr pWin,
3586                       DeviceIntPtr pDev,
3587                       DevCursNodePtr * pNode, DevCursNodePtr * pPrev)
3588{
3589    DevCursorList pList;
3590
3591    if (!pWin->optional)
3592        return FALSE;
3593
3594    pList = pWin->optional->deviceCursors;
3595
3596    if (pList && pList->dev == pDev) {
3597        *pNode = pList;
3598        *pPrev = NULL;
3599        return TRUE;
3600    }
3601
3602    while (pList) {
3603        if (pList->next) {
3604            if (pList->next->dev == pDev) {
3605                *pNode = pList->next;
3606                *pPrev = pList;
3607                return TRUE;
3608            }
3609        }
3610        pList = pList->next;
3611    }
3612    return FALSE;
3613}
3614
3615/* Return True if a parent has the same device cursor set or False if
3616 * otherwise
3617 */
3618static Bool
3619WindowParentHasDeviceCursor(WindowPtr pWin,
3620                            DeviceIntPtr pDev, CursorPtr pCursor)
3621{
3622    WindowPtr pParent;
3623    DevCursNodePtr pParentNode, pParentPrev;
3624
3625    pParent = pWin->parent;
3626    while (pParent) {
3627        if (WindowSeekDeviceCursor(pParent, pDev, &pParentNode, &pParentPrev)) {
3628            /* if there is a node in the list, the win has a dev cursor */
3629            if (!pParentNode->cursor)   /* inherited. */
3630                pParent = pParent->parent;
3631            else if (pParentNode->cursor == pCursor)    /* inherit */
3632                return TRUE;
3633            else                /* different cursor */
3634                return FALSE;
3635        }
3636        else
3637            /* parent does not have a device cursor for our device */
3638            return FALSE;
3639    }
3640    return FALSE;
3641}
3642
3643/*
3644 * SetRootClip --
3645 *	Enable or disable rendering to the screen by
3646 *	setting the root clip list and revalidating
3647 *	all of the windows
3648 */
3649void
3650SetRootClip(ScreenPtr pScreen, int enable)
3651{
3652    WindowPtr pWin = pScreen->root;
3653    WindowPtr pChild;
3654    Bool WasViewable;
3655    Bool anyMarked = FALSE;
3656    WindowPtr pLayerWin;
3657    BoxRec box;
3658    enum RootClipMode mode = enable;
3659
3660    if (!pWin)
3661        return;
3662    WasViewable = (Bool) (pWin->viewable);
3663    if (WasViewable) {
3664        for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) {
3665            (void) (*pScreen->MarkOverlappedWindows) (pChild,
3666                                                      pChild, &pLayerWin);
3667        }
3668        (*pScreen->MarkWindow) (pWin);
3669        anyMarked = TRUE;
3670        if (pWin->valdata) {
3671            if (HasBorder(pWin)) {
3672                RegionPtr borderVisible;
3673
3674                borderVisible = RegionCreate(NullBox, 1);
3675                RegionSubtract(borderVisible,
3676                               &pWin->borderClip, &pWin->winSize);
3677                pWin->valdata->before.borderVisible = borderVisible;
3678            }
3679            pWin->valdata->before.resized = TRUE;
3680        }
3681    }
3682
3683    if (mode != ROOT_CLIP_NONE) {
3684        pWin->drawable.width = pScreen->width;
3685        pWin->drawable.height = pScreen->height;
3686
3687        box.x1 = 0;
3688        box.y1 = 0;
3689        box.x2 = pScreen->width;
3690        box.y2 = pScreen->height;
3691
3692        RegionInit(&pWin->winSize, &box, 1);
3693        RegionInit(&pWin->borderSize, &box, 1);
3694
3695        /*
3696         * Use REGION_BREAK to avoid optimizations in ValidateTree
3697         * that assume the root borderClip can't change well, normally
3698         * it doesn't...)
3699         */
3700        RegionBreak(&pWin->clipList);
3701
3702	/* For INPUT_ONLY, empty the borderClip so no rendering will ever
3703	 * be attempted to the screen pixmap (only redirected windows),
3704	 * but we keep borderSize as full regardless. */
3705        if (WasViewable && mode == ROOT_CLIP_FULL)
3706            RegionReset(&pWin->borderClip, &box);
3707        else
3708            RegionEmpty(&pWin->borderClip);
3709    }
3710    else {
3711        RegionEmpty(&pWin->borderClip);
3712        RegionBreak(&pWin->clipList);
3713    }
3714
3715    ResizeChildrenWinSize(pWin, 0, 0, 0, 0);
3716
3717    if (WasViewable) {
3718        if (pWin->firstChild) {
3719            anyMarked |= (*pScreen->MarkOverlappedWindows) (pWin->firstChild,
3720                                                            pWin->firstChild,
3721                                                            NULL);
3722        }
3723        else {
3724            (*pScreen->MarkWindow) (pWin);
3725            anyMarked = TRUE;
3726        }
3727
3728        if (anyMarked) {
3729            (*pScreen->ValidateTree) (pWin, NullWindow, VTOther);
3730            (*pScreen->HandleExposures) (pWin);
3731            if (pScreen->PostValidateTree)
3732                (*pScreen->PostValidateTree) (pWin, NullWindow, VTOther);
3733        }
3734    }
3735    if (pWin->realized)
3736        WindowsRestructured();
3737    FlushAllOutput();
3738}
3739
3740VisualPtr
3741WindowGetVisual(WindowPtr pWin)
3742{
3743    ScreenPtr pScreen = pWin->drawable.pScreen;
3744    VisualID vid = wVisual(pWin);
3745    int i;
3746
3747    for (i = 0; i < pScreen->numVisuals; i++)
3748        if (pScreen->visuals[i].vid == vid)
3749            return &pScreen->visuals[i];
3750    return 0;
3751}
3752