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