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