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