diff options
Diffstat (limited to 'nx-X11/programs/Xserver/hw/nxagent/X/NXwindow.c')
-rw-r--r-- | nx-X11/programs/Xserver/hw/nxagent/X/NXwindow.c | 4174 |
1 files changed, 4174 insertions, 0 deletions
diff --git a/nx-X11/programs/Xserver/hw/nxagent/X/NXwindow.c b/nx-X11/programs/Xserver/hw/nxagent/X/NXwindow.c new file mode 100644 index 000000000..7ba468ac0 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/X/NXwindow.c @@ -0,0 +1,4174 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2007 NoMachine, http://www.nomachine.com/. */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of NoMachine. Redistribution and use of the present */ +/* software is allowed according to terms specified in the file LICENSE */ +/* which comes in the source distribution. */ +/* */ +/* Check http://www.nomachine.com/licensing.html for applicability. */ +/* */ +/* NX and NoMachine are trademarks of NoMachine S.r.l. */ +/* */ +/* All rights reserved. */ +/* */ +/**************************************************************************/ + +/* $XdotOrg: xc/programs/Xserver/dix/window.c,v 1.12 2005/07/03 08:53:38 daniels Exp $ */ +/* $Xorg: window.c,v 1.4 2001/02/09 02:04:41 xorgcvs Exp $ */ +/* + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts, + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +*/ + +/* The panoramix components contained the following notice */ +/***************************************************************** + +Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, +BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Digital Equipment Corporation +shall not be used in advertising or otherwise to promote the sale, use or other +dealings in this Software without prior written authorization from Digital +Equipment Corporation. + +******************************************************************/ + +/* $XFree86: xc/programs/Xserver/dix/window.c,v 3.36 2003/11/14 23:52:50 torrey Exp $ */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include "misc.h" +#include "scrnintstr.h" +#include "os.h" +#include "regionstr.h" +#include "validate.h" +#include "windowstr.h" +#include "input.h" +#include "resource.h" +#include "colormapst.h" +#include "cursorstr.h" +#include "dixstruct.h" +#include "gcstruct.h" +#include "servermd.h" +#include "selection.h" +#ifdef PANORAMIX +#include "../../Xext/panoramiX.h" +#include "../../Xext/panoramiXsrv.h" +#endif +#include "dixevents.h" +#include "globals.h" + +#ifdef XAPPGROUP +#include <X11/extensions/Xagsrv.h> +#endif +#ifdef XCSECURITY +#define _SECURITY_SERVER +#include <X11/extensions/security.h> +#endif + +#include "Screen.h" +#include "Options.h" +#include "Atoms.h" +#include "Clipboard.h" +#include "Splash.h" +#include "Rootless.h" +#include "Composite.h" +#include "Drawable.h" +#include "Colormap.h" + +extern Bool nxagentWMIsRunning; +extern Bool nxagentScreenTrap; + +/****** + * Window stuff for server + * + * CreateRootWindow, CreateWindow, ChangeWindowAttributes, + * GetWindowAttributes, DeleteWindow, DestroySubWindows, + * HandleSaveSet, ReparentWindow, MapWindow, MapSubWindows, + * UnmapWindow, UnmapSubWindows, ConfigureWindow, CirculateWindow, + * + ******/ + +int screenIsSaved = SCREEN_SAVER_OFF; + +ScreenSaverStuffRec savedScreenInfo[MAXSCREENS]; + +#if 0 +extern void DeleteWindowFromAnyEvents(); +extern Mask EventMaskForClient(); +extern void WindowHasNewCursor(); +extern void RecalculateDeliverableEvents(); +#endif + +static Bool TileScreenSaver(int i, int kind); + + +#define INPUTONLY_LEGAL_MASK (CWWinGravity | CWEventMask | \ + CWDontPropagate | CWOverrideRedirect | CWCursor ) + +#define BOXES_OVERLAP(b1, b2) \ + (!( ((b1)->x2 <= (b2)->x1) || \ + ( ((b1)->x1 >= (b2)->x2)) || \ + ( ((b1)->y2 <= (b2)->y1)) || \ + ( ((b1)->y1 >= (b2)->y2)) ) ) + +#define RedirectSend(pWin) \ + ((pWin->eventMask|wOtherEventMasks(pWin)) & SubstructureRedirectMask) + +#define SubSend(pWin) \ + ((pWin->eventMask|wOtherEventMasks(pWin)) & SubstructureNotifyMask) + +#define StrSend(pWin) \ + ((pWin->eventMask|wOtherEventMasks(pWin)) & StructureNotifyMask) + +#define SubStrSend(pWin,pParent) (StrSend(pWin) || SubSend(pParent)) + + +/* + * Set here the required log level. + */ + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +int numSaveUndersViewable = 0; +int deltaSaveUndersViewable = 0; + +WindowPtr nxagentRootTileWindow; + +/* + * This block used the DEBUG symbol. + */ + +#ifdef WINDOW_TREE_DEBUG +/****** + * PrintWindowTree + * For debugging only + ******/ + +int +PrintChildren(WindowPtr p1, int indent) +{ + WindowPtr p2; + int i; + + while (p1) + { + p2 = p1->firstChild; + for (i=0; i<indent; i++) ErrorF( " "); + ErrorF( "%x\n", p1->drawable.id); + miPrintRegion(&p1->clipList); + PrintChildren(p2, indent+4); + p1 = p1->nextSib; + } +} + +PrintWindowTree() +{ + int i; + WindowPtr pWin, p1; + + for (i=0; i<screenInfo.numScreens; i++) + { + ErrorF( "WINDOW %d\n", i); + pWin = WindowTable[i]; + miPrintRegion(&pWin->clipList); + p1 = pWin->firstChild; + PrintChildren(p1, 4); + } +} +#endif + +int +TraverseTree(register WindowPtr pWin, VisitWindowProcPtr func, pointer data) +{ + register int result; + register WindowPtr pChild; + + if (!(pChild = pWin)) + return(WT_NOMATCH); + while (1) + { + result = (* func)(pChild, data); + if (result == WT_STOPWALKING) + return(WT_STOPWALKING); + if ((result == WT_WALKCHILDREN) && pChild->firstChild) + { + pChild = pChild->firstChild; + continue; + } + while (!pChild->nextSib && (pChild != pWin)) + pChild = pChild->parent; + if (pChild == pWin) + break; + pChild = pChild->nextSib; + } + return(WT_NOMATCH); +} + +/***** + * WalkTree + * Walk the window tree, for SCREEN, preforming FUNC(pWin, data) on + * each window. If FUNC returns WT_WALKCHILDREN, traverse the children, + * if it returns WT_DONTWALKCHILDREN, dont. If it returns WT_STOPWALKING + * exit WalkTree. Does depth-first traverse. + *****/ + +int +WalkTree(ScreenPtr pScreen, VisitWindowProcPtr func, pointer data) +{ + return(TraverseTree(WindowTable[pScreen->myNum], func, data)); +} + +/* hack for forcing backing store on all windows */ +int defaultBackingStore = NotUseful; +/* hack to force no backing store */ +Bool disableBackingStore = FALSE; +Bool enableBackingStore = FALSE; +/* hack to force no save unders */ +Bool disableSaveUnders = FALSE; + +static void +SetWindowToDefaults(register WindowPtr pWin) +{ + pWin->prevSib = NullWindow; + pWin->firstChild = NullWindow; + pWin->lastChild = NullWindow; + + pWin->valdata = (ValidatePtr)NULL; + pWin->optional = (WindowOptPtr)NULL; + pWin->cursorIsNone = TRUE; + + pWin->backingStore = NotUseful; + pWin->DIXsaveUnder = FALSE; + pWin->backStorage = (pointer) NULL; + + pWin->mapped = FALSE; /* off */ + pWin->realized = FALSE; /* off */ + pWin->viewable = FALSE; + pWin->visibility = VisibilityNotViewable; + pWin->overrideRedirect = FALSE; + pWin->saveUnder = FALSE; + + pWin->bitGravity = ForgetGravity; + pWin->winGravity = NorthWestGravity; + + pWin->eventMask = 0; + pWin->deliverableEvents = 0; + pWin->dontPropagate = 0; + pWin->forcedBS = FALSE; +#ifdef NEED_DBE_BUF_BITS + pWin->srcBuffer = DBE_FRONT_BUFFER; + pWin->dstBuffer = DBE_FRONT_BUFFER; +#endif +#ifdef COMPOSITE + pWin->redirectDraw = 0; +#endif +} + +#ifdef NXAGENT_SERVER + +void nxagentClearSplash(WindowPtr pW) +{ + int w, h; + ScreenPtr pScreen; + + w = pW->drawable.width; + h = pW->drawable.height; + + pScreen = pW->drawable.pScreen; + + if (pW->backgroundState == BackgroundPixmap) + { + (*pScreen->DestroyPixmap)(pW->background.pixmap); + } + + pW->backgroundState = BackgroundPixel; + pW->background.pixel = nxagentLogoBlack; + + (*pScreen->ChangeWindowAttributes)(pW, CWBackPixmap|CWBackPixel); +} + +static void +#if NeedFunctionPrototypes +MakeRootTile(WindowPtr pWin) +#else +MakeRootTile(pWin) + WindowPtr pWin; +#endif +{ + nxagentRootTileWindow = pWin; +} + +#else /* NXAGENT_SERVER */ + +static void +MakeRootTile(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + GCPtr pGC; + unsigned char back[128]; + int len = BitmapBytePad(sizeof(long)); + register unsigned char *from, *to; + register int i, j; + + pWin->background.pixmap = (*pScreen->CreatePixmap)(pScreen, 4, 4, + pScreen->rootDepth); + + pWin->backgroundState = BackgroundPixmap; + pGC = GetScratchGC(pScreen->rootDepth, pScreen); + if (!pWin->background.pixmap || !pGC) + FatalError("could not create root tile"); + + { + CARD32 attributes[2]; + + attributes[0] = pScreen->whitePixel; + attributes[1] = pScreen->blackPixel; + + (void)ChangeGC(pGC, GCForeground | GCBackground, attributes); + } + + ValidateGC((DrawablePtr)pWin->background.pixmap, pGC); + + from = (screenInfo.bitmapBitOrder == LSBFirst) ? _back_lsb : _back_msb; + to = back; + + for (i = 4; i > 0; i--, from++) + for (j = len; j > 0; j--) + *to++ = *from; + + if (blackRoot) + bzero(back, sizeof(back)); + + (*pGC->ops->PutImage)((DrawablePtr)pWin->background.pixmap, pGC, 1, + 0, 0, len, 4, 0, XYBitmap, (char *)back); + + FreeScratchGC(pGC); + +} + +#endif /* NXAGENT_SERVER */ + +WindowPtr +AllocateWindow(ScreenPtr pScreen) +{ + WindowPtr pWin; + register char *ptr; + register DevUnion *ppriv; + register unsigned *sizes; + register unsigned size; + register int i; + + pWin = (WindowPtr)xalloc(pScreen->totalWindowSize); + if (pWin) + { + ppriv = (DevUnion *)(pWin + 1); + pWin->devPrivates = ppriv; + sizes = pScreen->WindowPrivateSizes; + ptr = (char *)(ppriv + pScreen->WindowPrivateLen); + for (i = pScreen->WindowPrivateLen; --i >= 0; ppriv++, sizes++) + { + if ( (size = *sizes) ) + { + ppriv->ptr = (pointer)ptr; + ptr += size; + } + else + ppriv->ptr = (pointer)NULL; + } + } + return pWin; +} + +/***** + * CreateRootWindow + * Makes a window at initialization time for specified screen + *****/ + +Bool +CreateRootWindow(ScreenPtr pScreen) +{ + WindowPtr pWin; + BoxRec box; + PixmapFormatRec *format; + + pWin = AllocateWindow(pScreen); + if (!pWin) + return FALSE; + + savedScreenInfo[pScreen->myNum].pWindow = NULL; + savedScreenInfo[pScreen->myNum].wid = FakeClientID(0); + savedScreenInfo[pScreen->myNum].ExternalScreenSaver = NULL; + screenIsSaved = SCREEN_SAVER_OFF; + + WindowTable[pScreen->myNum] = pWin; + + pWin->drawable.pScreen = pScreen; + pWin->drawable.type = DRAWABLE_WINDOW; + + pWin->drawable.depth = pScreen->rootDepth; + for (format = screenInfo.formats; + format->depth != pScreen->rootDepth; + format++) + ; + pWin->drawable.bitsPerPixel = format->bitsPerPixel; + + pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER; + + pWin->parent = NullWindow; + SetWindowToDefaults(pWin); + + pWin->optional = (WindowOptRec *) xalloc (sizeof (WindowOptRec)); + if (!pWin->optional) + return FALSE; + + pWin->optional->dontPropagateMask = 0; + pWin->optional->otherEventMasks = 0; + pWin->optional->otherClients = NULL; + pWin->optional->passiveGrabs = NULL; + pWin->optional->userProps = NULL; + pWin->optional->backingBitPlanes = ~0L; + pWin->optional->backingPixel = 0; +#ifdef SHAPE + pWin->optional->boundingShape = NULL; + pWin->optional->clipShape = NULL; + pWin->optional->inputShape = NULL; +#endif +#ifdef XINPUT + pWin->optional->inputMasks = NULL; +#endif + pWin->optional->colormap = pScreen->defColormap; + pWin->optional->visual = pScreen->rootVisual; + + pWin->nextSib = NullWindow; + + pWin->drawable.id = FakeClientID(0); + + pWin->origin.x = pWin->origin.y = 0; + pWin->drawable.height = pScreen->height; + pWin->drawable.width = pScreen->width; + pWin->drawable.x = pWin->drawable.y = 0; + + box.x1 = 0; + box.y1 = 0; + box.x2 = pScreen->width; + box.y2 = pScreen->height; + REGION_INIT(pScreen, &pWin->clipList, &box, 1); + REGION_INIT(pScreen, &pWin->winSize, &box, 1); + REGION_INIT(pScreen, &pWin->borderSize, &box, 1); + REGION_INIT(pScreen, &pWin->borderClip, &box, 1); + + pWin->drawable.class = InputOutput; + pWin->optional->visual = pScreen->rootVisual; + + pWin->backgroundState = BackgroundPixel; + pWin->background.pixel = pScreen->whitePixel; + + pWin->borderIsPixel = TRUE; + pWin->border.pixel = pScreen->blackPixel; + pWin->borderWidth = 0; + + if (!AddResource(pWin->drawable.id, RT_WINDOW, (pointer)pWin)) + return FALSE; + + if (disableBackingStore) + { + pScreen -> backingStoreSupport = NotUseful; + } + + if (enableBackingStore) + { + pScreen -> backingStoreSupport = Always; + } + + pScreen->saveUnderSupport = False; + +#ifdef DO_SAVE_UNDERS + if ((pScreen->backingStoreSupport != NotUseful) && + (pScreen->saveUnderSupport == NotUseful)) + { + /* + * If the screen has backing-store but no save-unders, let the + * clients know we can support save-unders using backing-store. + */ + pScreen->saveUnderSupport = USE_DIX_SAVE_UNDERS; + } +#endif /* DO_SAVE_UNDERS */ + + if (disableSaveUnders) + pScreen->saveUnderSupport = NotUseful; + + return TRUE; +} + +#ifdef NXAGENT_SERVER + +void +InitRootWindow(WindowPtr pWin) +{ + ScreenPtr pScreen; + + #ifdef TEST + fprintf(stderr, "InitRootWindow: Called for window at [%p][%ld] with parent [%p].\n", + (void *) pWin, nxagentWindowPriv(pWin)->window, (void *) pWin -> parent); + #endif + + if (nxagentOption(Rootless)) + { + #ifdef TEST + fprintf(stderr, "InitRootWindow: Assigned agent root to window at [%p][%ld] with parent [%p].\n", + (void *) pWin, nxagentWindowPriv(pWin)->window, (void *) pWin -> parent); + #endif + + nxagentRootlessWindow = pWin; + } + + pScreen = pWin->drawable.pScreen; + + /* + * A root window is created for each screen by main + * and the pointer is saved in WindowTable as in the + * following snippet: + * + * for (i = 0; i < screenInfo.numScreens; i++) + * InitRootWindow(WindowTable[i]); + * + * Our root window on the real display was already + * created at the time the screen was opened, so it + * is unclear how this window (or the other window, + * if you prefer) fits in the big picture. + */ + + #ifdef TEST + fprintf(stderr, "InitRootWindow: Going to create window as root at [%p][%ld] with parent [%p].\n", + (void *) pWin, nxagentWindowPriv(pWin)->window, (void *) pWin -> parent); + #endif + + if (!(*pScreen->CreateWindow)(pWin)) + return; /* XXX */ + + #ifdef TEST + fprintf(stderr, "InitRootWindow: Created window as root at [%p][%ld] with parent [%p].\n", + (void *) pWin, nxagentWindowPriv(pWin)->window, (void *) pWin -> parent); + #endif + + (*pScreen->PositionWindow)(pWin, 0, 0); + + pWin->cursorIsNone = FALSE; + pWin->optional->cursor = rootCursor; + rootCursor->refcnt++; + pWin->backingStore = defaultBackingStore; + pWin->forcedBS = (defaultBackingStore != NotUseful); + + #ifdef NXAGENT_SPLASH + /* We SHOULD check for an error value here XXX */ + pWin -> background.pixel = pScreen -> blackPixel; + (*pScreen->ChangeWindowAttributes)(pWin, + CWBackPixel|CWBorderPixel|CWCursor|CWBackingStore); + #else + (*pScreen->ChangeWindowAttributes)(pWin, + CWBackPixmap|CWBorderPixel|CWCursor|CWBackingStore); + #endif + + MakeRootTile(pWin); + + /* + * Map both the root and the default agent window. + */ + + #ifdef TEST + fprintf(stderr, "InitRootWindow: Mapping default windows.\n"); + #endif + + nxagentInitAtoms(pWin); + + nxagentInitClipboard(pWin); + + nxagentMapDefaultWindows(); + + nxagentRedirectDefaultWindows(); + + #ifdef NXAGENT_ARTSD + { + char artsd_port[10]; + int nPort; + extern void nxagentPropagateArtsdProperties(ScreenPtr pScreen, char *port); + nPort = atoi(display) + 7000; + sprintf(artsd_port,"%d", nPort); + nxagentPropagateArtsdProperties(pScreen, artsd_port); + } + #endif +} + +#else /* NXAGENT_SERVER */ + +void +InitRootWindow(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + + if (!(*pScreen->CreateWindow)(pWin)) + return; /* XXX */ + (*pScreen->PositionWindow)(pWin, 0, 0); + + pWin->cursorIsNone = FALSE; + pWin->optional->cursor = rootCursor; + rootCursor->refcnt++; + MakeRootTile(pWin); + pWin->backingStore = defaultBackingStore; + pWin->forcedBS = (defaultBackingStore != NotUseful); + /* We SHOULD check for an error value here XXX */ + (*pScreen->ChangeWindowAttributes)(pWin, + CWBackPixmap|CWBorderPixel|CWCursor|CWBackingStore); + + MapWindow(pWin, serverClient); +} + +#endif /* NXAGENT_SERVER */ + +/* Set the region to the intersection of the rectangle and the + * window's winSize. The window is typically the parent of the + * window from which the region came. + */ + +void +ClippedRegionFromBox(register WindowPtr pWin, RegionPtr Rgn, + register int x, register int y, + register int w, register int h) +{ +#ifndef NXAGENT_SERVER + ScreenPtr pScreen = pWin->drawable.pScreen; +#endif /* NXAGENT_SERVER */ + BoxRec box; + + box = *(REGION_EXTENTS(pScreen, &pWin->winSize)); + /* we do these calculations to avoid overflows */ + if (x > box.x1) + box.x1 = x; + if (y > box.y1) + box.y1 = y; + x += w; + if (x < box.x2) + box.x2 = x; + y += h; + if (y < box.y2) + box.y2 = y; + if (box.x1 > box.x2) + box.x2 = box.x1; + if (box.y1 > box.y2) + box.y2 = box.y1; + REGION_RESET(pScreen, Rgn, &box); + REGION_INTERSECT(pScreen, Rgn, Rgn, &pWin->winSize); +} + +WindowPtr +RealChildHead(register WindowPtr pWin) +{ + if (!pWin->parent && + (screenIsSaved == SCREEN_SAVER_ON) && + (HasSaverWindow (pWin->drawable.pScreen->myNum))) + return (pWin->firstChild); + else + return (NullWindow); +} + +/***** + * CreateWindow + * Makes a window in response to client request + *****/ + +WindowPtr +CreateWindow(Window wid, register WindowPtr pParent, int x, int y, unsigned w, + unsigned h, unsigned bw, unsigned class, register Mask vmask, XID *vlist, + int depth, ClientPtr client, VisualID visual, int *error) +{ + register WindowPtr pWin; + WindowPtr pHead; + register ScreenPtr pScreen; + xEvent event; + int idepth, ivisual; + Bool fOK; + DepthPtr pDepth; + PixmapFormatRec *format; + register WindowOptPtr ancwopt; + + if (class == CopyFromParent) + class = pParent->drawable.class; + + if ((class != InputOutput) && (class != InputOnly)) + { + *error = BadValue; + client->errorValue = class; + return NullWindow; + } + + if ((class != InputOnly) && (pParent->drawable.class == InputOnly)) + { + *error = BadMatch; + return NullWindow; + } + + if ((class == InputOnly) && ((bw != 0) || (depth != 0))) + { + *error = BadMatch; + return NullWindow; + } + + pScreen = pParent->drawable.pScreen; + if ((class == InputOutput) && (depth == 0)) + depth = pParent->drawable.depth; + ancwopt = pParent->optional; + if (!ancwopt) + ancwopt = FindWindowWithOptional(pParent)->optional; + if (visual == CopyFromParent) { +#ifdef XAPPGROUP + VisualID ag_visual; + + if (client->appgroup && !pParent->parent && + (ag_visual = XagRootVisual (client))) + visual = ag_visual; + else +#endif + visual = ancwopt->visual; + } + + /* Find out if the depth and visual are acceptable for this Screen */ + if ((visual != ancwopt->visual) || (depth != pParent->drawable.depth)) + { + fOK = FALSE; + for(idepth = 0; idepth < pScreen->numDepths; idepth++) + { + pDepth = (DepthPtr) &pScreen->allowedDepths[idepth]; + if ((depth == pDepth->depth) || (depth == 0)) + { + for (ivisual = 0; ivisual < pDepth->numVids; ivisual++) + { + if (visual == pDepth->vids[ivisual]) + { + fOK = TRUE; + break; + } + } + } + } + if (fOK == FALSE) + { + *error = BadMatch; + return NullWindow; + } + } + + if (((vmask & (CWBorderPixmap | CWBorderPixel)) == 0) && + (class != InputOnly) && + (depth != pParent->drawable.depth)) + { + *error = BadMatch; + return NullWindow; + } + + if (((vmask & CWColormap) == 0) && + (class != InputOnly) && + ((visual != ancwopt->visual) || (ancwopt->colormap == None))) + { + *error = BadMatch; + return NullWindow; + } + + pWin = AllocateWindow(pScreen); + if (!pWin) + { + *error = BadAlloc; + return NullWindow; + } + pWin->drawable = pParent->drawable; + pWin->drawable.depth = depth; + if (depth == pParent->drawable.depth) + pWin->drawable.bitsPerPixel = pParent->drawable.bitsPerPixel; + else + { + for (format = screenInfo.formats; format->depth != depth; format++) + ; + pWin->drawable.bitsPerPixel = format->bitsPerPixel; + } + if (class == InputOnly) + pWin->drawable.type = (short) UNDRAWABLE_WINDOW; + pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER; + + pWin->drawable.id = wid; + pWin->drawable.class = class; + + pWin->parent = pParent; + SetWindowToDefaults(pWin); + + if (visual != ancwopt->visual) + { + if (!MakeWindowOptional (pWin)) + { + xfree (pWin); + *error = BadAlloc; + return NullWindow; + } + pWin->optional->visual = visual; + pWin->optional->colormap = None; + } + + pWin->borderWidth = bw; +#ifdef XCSECURITY + /* can't let untrusted clients have background None windows; + * they make it too easy to steal window contents + */ + if (client->trustLevel != XSecurityClientTrusted) + { + pWin->backgroundState = BackgroundPixel; + pWin->background.pixel = 0; + } + else +#endif + pWin->backgroundState = None; + + pWin->borderIsPixel = pParent->borderIsPixel; + pWin->border = pParent->border; + if (pWin->borderIsPixel == FALSE) + pWin->border.pixmap->refcnt++; + + pWin->origin.x = x + (int)bw; + pWin->origin.y = y + (int)bw; + pWin->drawable.width = w; + pWin->drawable.height = h; + pWin->drawable.x = pParent->drawable.x + x + (int)bw; + pWin->drawable.y = pParent->drawable.y + y + (int)bw; + + /* set up clip list correctly for unobscured WindowPtr */ + REGION_NULL(pScreen, &pWin->clipList); + REGION_NULL(pScreen, &pWin->borderClip); + REGION_NULL(pScreen, &pWin->winSize); + REGION_NULL(pScreen, &pWin->borderSize); + + pHead = RealChildHead(pParent); + if (pHead) + { + pWin->nextSib = pHead->nextSib; + if (pHead->nextSib) + pHead->nextSib->prevSib = pWin; + else + pParent->lastChild = pWin; + pHead->nextSib = pWin; + pWin->prevSib = pHead; + } + else + { + pWin->nextSib = pParent->firstChild; + if (pParent->firstChild) + pParent->firstChild->prevSib = pWin; + else + pParent->lastChild = pWin; + pParent->firstChild = pWin; + } + + SetWinSize (pWin); + SetBorderSize (pWin); + + /* We SHOULD check for an error value here XXX */ + if (!(*pScreen->CreateWindow)(pWin)) + { + *error = BadAlloc; + DeleteWindow(pWin, None); + return NullWindow; + } + /* We SHOULD check for an error value here XXX */ + (*pScreen->PositionWindow)(pWin, pWin->drawable.x, pWin->drawable.y); + + if (!(vmask & CWEventMask)) + RecalculateDeliverableEvents(pWin); + + if (vmask) + *error = ChangeWindowAttributes(pWin, vmask, vlist, wClient (pWin)); + else + *error = Success; + + if (*error != Success) + { + DeleteWindow(pWin, None); + return NullWindow; + } + if (!(vmask & CWBackingStore) && (defaultBackingStore != NotUseful)) + { + XID value = defaultBackingStore; + (void)ChangeWindowAttributes(pWin, CWBackingStore, &value, wClient (pWin)); + pWin->forcedBS = TRUE; + } + + if (SubSend(pParent)) + { + event.u.u.type = CreateNotify; + event.u.createNotify.window = wid; + event.u.createNotify.parent = pParent->drawable.id; + event.u.createNotify.x = x; + event.u.createNotify.y = y; + event.u.createNotify.width = w; + event.u.createNotify.height = h; + event.u.createNotify.borderWidth = bw; + event.u.createNotify.override = pWin->overrideRedirect; + DeliverEvents(pParent, &event, 1, NullWindow); + } + return pWin; +} + +static void +FreeWindowResources(register WindowPtr pWin) +{ + register ScreenPtr pScreen = pWin->drawable.pScreen; + + DeleteWindowFromAnySaveSet(pWin); + DeleteWindowFromAnySelections(pWin); + DeleteWindowFromAnyEvents(pWin, TRUE); + REGION_UNINIT(pScreen, &pWin->clipList); + REGION_UNINIT(pScreen, &pWin->winSize); + REGION_UNINIT(pScreen, &pWin->borderClip); + REGION_UNINIT(pScreen, &pWin->borderSize); +#ifdef SHAPE + if (wBoundingShape (pWin)) + REGION_DESTROY(pScreen, wBoundingShape (pWin)); + if (wClipShape (pWin)) + REGION_DESTROY(pScreen, wClipShape (pWin)); + if (wInputShape (pWin)) + REGION_DESTROY(pScreen, wInputShape (pWin)); +#endif + if (pWin->borderIsPixel == FALSE) + (*pScreen->DestroyPixmap)(pWin->border.pixmap); + if (pWin->backgroundState == BackgroundPixmap) + (*pScreen->DestroyPixmap)(pWin->background.pixmap); + + DeleteAllWindowProperties(pWin); + /* We SHOULD check for an error value here XXX */ + (*pScreen->DestroyWindow)(pWin); + DisposeWindowOptional (pWin); +} + +static void +CrushTree(WindowPtr pWin) +{ + register WindowPtr pChild, pSib, pParent; + UnrealizeWindowProcPtr UnrealizeWindow; + xEvent event; + + if (!(pChild = pWin->firstChild)) + return; + UnrealizeWindow = pWin->drawable.pScreen->UnrealizeWindow; + while (1) + { + if (pChild->firstChild) + { + pChild = pChild->firstChild; + continue; + } + while (1) + { + pParent = pChild->parent; + if (SubStrSend(pChild, pParent)) + { + event.u.u.type = DestroyNotify; + event.u.destroyNotify.window = pChild->drawable.id; + DeliverEvents(pChild, &event, 1, NullWindow); + } + FreeResource(pChild->drawable.id, RT_WINDOW); + pSib = pChild->nextSib; +#ifdef DO_SAVE_UNDERS + if (pChild->saveUnder && pChild->viewable) + deltaSaveUndersViewable--; +#endif + pChild->viewable = FALSE; + if (pChild->realized) + { + pChild->realized = FALSE; + (*UnrealizeWindow)(pChild); + } + FreeWindowResources(pChild); + xfree(pChild); + if ( (pChild = pSib) ) + break; + pChild = pParent; + pChild->firstChild = NullWindow; + pChild->lastChild = NullWindow; + if (pChild == pWin) + return; + } + } +} + +/***** + * DeleteWindow + * Deletes child of window then window itself + * If wid is None, don't send any events + *****/ + +int +DeleteWindow(pointer value, XID wid) + { + register WindowPtr pParent; + register WindowPtr pWin = (WindowPtr)value; + xEvent event; + + UnmapWindow(pWin, FALSE); + + CrushTree(pWin); + + pParent = pWin->parent; + if (wid && pParent && SubStrSend(pWin, pParent)) + { + event.u.u.type = DestroyNotify; + event.u.destroyNotify.window = pWin->drawable.id; + DeliverEvents(pWin, &event, 1, NullWindow); + } + + FreeWindowResources(pWin); + if (pParent) + { + if (pParent->firstChild == pWin) + pParent->firstChild = pWin->nextSib; + if (pParent->lastChild == pWin) + pParent->lastChild = pWin->prevSib; + if (pWin->nextSib) + pWin->nextSib->prevSib = pWin->prevSib; + if (pWin->prevSib) + pWin->prevSib->nextSib = pWin->nextSib; + } + + if (pWin -> optional && + pWin -> optional -> colormap && + pWin -> parent) + { + nxagentSetInstalledColormapWindows(pWin -> drawable.pScreen); + } + + xfree(pWin); + return Success; +} + +void +DestroySubwindows(register WindowPtr pWin, ClientPtr client) +{ + /* XXX + * The protocol is quite clear that each window should be + * destroyed in turn, however, unmapping all of the first + * eliminates most of the calls to ValidateTree. So, + * this implementation is incorrect in that all of the + * UnmapNotifies occur before all of the DestroyNotifies. + * If you care, simply delete the call to UnmapSubwindows. + */ + UnmapSubwindows(pWin); + while (pWin->lastChild) + FreeResource(pWin->lastChild->drawable.id, RT_NONE); +} + +#define DeviceEventMasks (KeyPressMask | KeyReleaseMask | ButtonPressMask | \ + ButtonReleaseMask | PointerMotionMask) + +/***** + * ChangeWindowAttributes + * + * The value-mask specifies which attributes are to be changed; the + * value-list contains one value for each one bit in the mask, from least + * to most significant bit in the mask. + *****/ + +int +ChangeWindowAttributes(register WindowPtr pWin, Mask vmask, XID *vlist, ClientPtr client) +{ + register Mask index2; + register XID *pVlist; + PixmapPtr pPixmap; + Pixmap pixID; + CursorPtr pCursor, pOldCursor; + Cursor cursorID; + WindowPtr pChild; + Colormap cmap; + ColormapPtr pCmap; + xEvent xE; + int result; + register ScreenPtr pScreen; + Mask vmaskCopy = 0; + register Mask tmask; + unsigned int val; + int error; + Bool checkOptional = FALSE; + Bool borderRelative = FALSE; + WindowPtr pLayerWin; + + if ((pWin->drawable.class == InputOnly) && (vmask & (~INPUTONLY_LEGAL_MASK))) + return BadMatch; + + error = Success; + pScreen = pWin->drawable.pScreen; + pVlist = vlist; + tmask = vmask; + while (tmask) + { + index2 = (Mask) lowbit (tmask); + tmask &= ~index2; + switch (index2) + { + case CWBackPixmap: + pixID = (Pixmap )*pVlist; + pVlist++; + if (pWin->backgroundState == ParentRelative) + borderRelative = TRUE; + if (pixID == None) + { +#ifdef XCSECURITY + /* can't let untrusted clients have background None windows */ + if (client->trustLevel == XSecurityClientTrusted) + { +#endif + if (pWin->backgroundState == BackgroundPixmap) + (*pScreen->DestroyPixmap)(pWin->background.pixmap); + if (!pWin->parent) + MakeRootTile(pWin); + else + pWin->backgroundState = None; +#ifdef XCSECURITY + } + else + { /* didn't change the background to None, so don't tell ddx */ + index2 = 0; + } +#endif + } + else if (pixID == ParentRelative) + { + if (pWin->parent && + pWin->drawable.depth != pWin->parent->drawable.depth) + { + error = BadMatch; + goto PatchUp; + } + if (pWin->backgroundState == BackgroundPixmap) + (*pScreen->DestroyPixmap)(pWin->background.pixmap); + if (!pWin->parent) + MakeRootTile(pWin); + else + pWin->backgroundState = ParentRelative; + borderRelative = TRUE; + /* Note that the parent's backgroundTile's refcnt is NOT + * incremented. */ + } + else + { + pPixmap = (PixmapPtr)SecurityLookupIDByType(client, pixID, + RT_PIXMAP, SecurityReadAccess); + if (pPixmap != (PixmapPtr) NULL) + { + if ((pPixmap->drawable.depth != pWin->drawable.depth) || + (pPixmap->drawable.pScreen != pScreen)) + { + error = BadMatch; + goto PatchUp; + } + if (pWin->backgroundState == BackgroundPixmap) + (*pScreen->DestroyPixmap)(pWin->background.pixmap); + pWin->backgroundState = BackgroundPixmap; + pWin->background.pixmap = pPixmap; + pPixmap->refcnt++; + } + else + { + error = BadPixmap; + client->errorValue = pixID; + goto PatchUp; + } + } + break; + case CWBackPixel: + if (pWin->backgroundState == ParentRelative) + borderRelative = TRUE; + if (pWin->backgroundState == BackgroundPixmap) + (*pScreen->DestroyPixmap)(pWin->background.pixmap); + pWin->backgroundState = BackgroundPixel; + pWin->background.pixel = (CARD32 ) *pVlist; + /* background pixel overrides background pixmap, + so don't let the ddx layer see both bits */ + vmaskCopy &= ~CWBackPixmap; + pVlist++; + break; + case CWBorderPixmap: + pixID = (Pixmap ) *pVlist; + pVlist++; + if (pixID == CopyFromParent) + { + if (!pWin->parent || + (pWin->drawable.depth != pWin->parent->drawable.depth)) + { + error = BadMatch; + goto PatchUp; + } + if (pWin->borderIsPixel == FALSE) + (*pScreen->DestroyPixmap)(pWin->border.pixmap); + pWin->border = pWin->parent->border; + if ((pWin->borderIsPixel = pWin->parent->borderIsPixel) == TRUE) + { + index2 = CWBorderPixel; + } + else + { + pWin->parent->border.pixmap->refcnt++; + } + } + else + { + pPixmap = (PixmapPtr)SecurityLookupIDByType(client, pixID, + RT_PIXMAP, SecurityReadAccess); + if (pPixmap) + { + if ((pPixmap->drawable.depth != pWin->drawable.depth) || + (pPixmap->drawable.pScreen != pScreen)) + { + error = BadMatch; + goto PatchUp; + } + if (pWin->borderIsPixel == FALSE) + (*pScreen->DestroyPixmap)(pWin->border.pixmap); + pWin->borderIsPixel = FALSE; + pWin->border.pixmap = pPixmap; + pPixmap->refcnt++; + } + else + { + error = BadPixmap; + client->errorValue = pixID; + goto PatchUp; + } + } + break; + case CWBorderPixel: + if (pWin->borderIsPixel == FALSE) + (*pScreen->DestroyPixmap)(pWin->border.pixmap); + pWin->borderIsPixel = TRUE; + pWin->border.pixel = (CARD32) *pVlist; + /* border pixel overrides border pixmap, + so don't let the ddx layer see both bits */ + vmaskCopy &= ~CWBorderPixmap; + pVlist++; + break; + case CWBitGravity: + val = (CARD8 )*pVlist; + pVlist++; + if (val > StaticGravity) + { + error = BadValue; + client->errorValue = val; + goto PatchUp; + } + pWin->bitGravity = val; + break; + case CWWinGravity: + val = (CARD8 )*pVlist; + pVlist++; + if (val > StaticGravity) + { + error = BadValue; + client->errorValue = val; + goto PatchUp; + } + pWin->winGravity = val; + break; + case CWBackingStore: + val = (CARD8 )*pVlist; + pVlist++; + if ((val != NotUseful) && (val != WhenMapped) && (val != Always)) + { + error = BadValue; + client->errorValue = val; + goto PatchUp; + } + pWin->backingStore = val; + + #ifdef TEST + fprintf(stderr, "ChangeWindowAttributes: Changed backing store value to %d for window at %p.\n", + val, (void*)pWin); + #endif + + pWin->forcedBS = FALSE; + break; + case CWBackingPlanes: + if (pWin->optional || ((CARD32)*pVlist != (CARD32)~0L)) { + if (!pWin->optional && !MakeWindowOptional (pWin)) + { + error = BadAlloc; + goto PatchUp; + } + pWin->optional->backingBitPlanes = (CARD32) *pVlist; + if ((CARD32)*pVlist == (CARD32)~0L) + checkOptional = TRUE; + } + pVlist++; + break; + case CWBackingPixel: + if (pWin->optional || (CARD32) *pVlist) { + if (!pWin->optional && !MakeWindowOptional (pWin)) + { + error = BadAlloc; + goto PatchUp; + } + pWin->optional->backingPixel = (CARD32) *pVlist; + if (!*pVlist) + checkOptional = TRUE; + } + pVlist++; + break; + case CWSaveUnder: + val = (BOOL) *pVlist; + pVlist++; + if ((val != xTrue) && (val != xFalse)) + { + error = BadValue; + client->errorValue = val; + goto PatchUp; + } +#ifdef DO_SAVE_UNDERS + if (pWin->parent && (pWin->saveUnder != val) && (pWin->viewable) && + DO_SAVE_UNDERS(pWin)) + { + /* + * Re-check all siblings and inferiors for obscurity or + * exposition (hee hee). + */ + if (pWin->saveUnder) + deltaSaveUndersViewable--; + else + deltaSaveUndersViewable++; + pWin->saveUnder = val; + + if (pWin->firstChild) + { + pLayerWin = (*pScreen->GetLayerWindow)(pWin); + if ((*pScreen->ChangeSaveUnder)(pLayerWin->parent, pWin->nextSib)) + (*pScreen->PostChangeSaveUnder)(pLayerWin->parent, + pWin->nextSib); + } + else + { + if ((*pScreen->ChangeSaveUnder)(pWin, pWin->nextSib)) + (*pScreen->PostChangeSaveUnder)(pWin, + pWin->nextSib); + } + } + else + { + /* If we're changing the saveUnder attribute of the root + * window, all we do is set pWin->saveUnder so that + * GetWindowAttributes returns the right value. We don't + * do the "normal" save-under processing (as above). + * Hope that doesn't cause any problems. + */ + pWin->saveUnder = val; + } +#else + pWin->saveUnder = val; +#endif /* DO_SAVE_UNDERS */ + break; + case CWEventMask: + /* + * TODO: Some applications like java bean shell + * don' t work if they cannot monitor the root + * window for Structure Redirect events. However + * this doesn't seem to be the best solution, since + * also an X server with a window manager running, + * doesn't allow to monitor for those events, but + * the java bean shell works flawlessy on this + * server. + * + * if (nxagentCheckIllegalRootMonitoring(pWin, (Mask)*pVlist)) + * { + * return BadAccess; + * } + */ + + result = EventSelectForWindow(pWin, client, (Mask )*pVlist); + if (result) + { + error = result; + goto PatchUp; + } + pVlist++; + break; + case CWDontPropagate: + result = EventSuppressForWindow(pWin, client, (Mask )*pVlist, + &checkOptional); + if (result) + { + error = result; + goto PatchUp; + } + pVlist++; + break; + case CWOverrideRedirect: + val = (BOOL ) *pVlist; + pVlist++; + if ((val != xTrue) && (val != xFalse)) + { + error = BadValue; + client->errorValue = val; + goto PatchUp; + } + pWin->overrideRedirect = val; + break; + case CWColormap: + cmap = (Colormap) *pVlist; + pVlist++; + if (cmap == CopyFromParent) + { +#ifdef XAPPGROUP + Colormap ag_colormap; + ClientPtr win_owner; + + /* + * win_owner == client for CreateWindow, other clients + * can ChangeWindowAttributes + */ + win_owner = clients[CLIENT_ID(pWin->drawable.id)]; + + if ( win_owner && win_owner->appgroup && + !pWin->parent->parent && + (ag_colormap = XagDefaultColormap (win_owner))) + cmap = ag_colormap; + else +#endif + if (pWin->parent && + (!pWin->optional || + pWin->optional->visual == wVisual (pWin->parent))) + { + cmap = wColormap (pWin->parent); + } + else + cmap = None; + } + if (cmap == None) + { + error = BadMatch; + goto PatchUp; + } + pCmap = (ColormapPtr)SecurityLookupIDByType(client, cmap, + RT_COLORMAP, SecurityReadAccess); + if (!pCmap) + { + error = BadColor; + client->errorValue = cmap; + goto PatchUp; + } + if (pCmap->pVisual->vid != wVisual (pWin) || + pCmap->pScreen != pScreen) + { + error = BadMatch; + goto PatchUp; + } + if (cmap != wColormap (pWin)) + { + if (!pWin->optional) + { + if (!MakeWindowOptional (pWin)) + { + error = BadAlloc; + goto PatchUp; + } + } + else if (pWin->parent && cmap == wColormap (pWin->parent)) + checkOptional = TRUE; + + /* + * propagate the original colormap to any children + * inheriting it + */ + + for (pChild = pWin->firstChild; pChild; pChild=pChild->nextSib) + { + if (!pChild->optional && !MakeWindowOptional (pChild)) + { + error = BadAlloc; + goto PatchUp; + } + } + + pWin->optional->colormap = cmap; + + /* + * check on any children now matching the new colormap + */ + + for (pChild = pWin->firstChild; pChild; pChild=pChild->nextSib) + { + if (pChild->optional->colormap == cmap) + CheckWindowOptionalNeed (pChild); + } + + xE.u.u.type = ColormapNotify; + xE.u.colormap.window = pWin->drawable.id; + xE.u.colormap.colormap = cmap; + xE.u.colormap.new = xTrue; + xE.u.colormap.state = IsMapInstalled(cmap, pWin); + DeliverEvents(pWin, &xE, 1, NullWindow); + } + break; + case CWCursor: + cursorID = (Cursor ) *pVlist; + pVlist++; + /* + * install the new + */ + if ( cursorID == None) + { + if (pWin == WindowTable[pWin->drawable.pScreen->myNum]) + pCursor = rootCursor; + else + pCursor = (CursorPtr) None; + } + else + { + pCursor = (CursorPtr)SecurityLookupIDByType(client, cursorID, + RT_CURSOR, SecurityReadAccess); + if (!pCursor) + { + error = BadCursor; + client->errorValue = cursorID; + goto PatchUp; + } + } + + if (pCursor != wCursor (pWin)) + { + /* + * patch up child windows so they don't lose cursors. + */ + + for (pChild = pWin->firstChild; pChild; pChild=pChild->nextSib) + { + if (!pChild->optional && !pChild->cursorIsNone && + !MakeWindowOptional (pChild)) + { + error = BadAlloc; + goto PatchUp; + } + } + + pOldCursor = 0; + if (pCursor == (CursorPtr) None) + { + pWin->cursorIsNone = TRUE; + if (pWin->optional) + { + pOldCursor = pWin->optional->cursor; + pWin->optional->cursor = (CursorPtr) None; + checkOptional = TRUE; + } + } else { + if (!pWin->optional) + { + if (!MakeWindowOptional (pWin)) + { + error = BadAlloc; + goto PatchUp; + } + } + else if (pWin->parent && pCursor == wCursor (pWin->parent)) + checkOptional = TRUE; + pOldCursor = pWin->optional->cursor; + pWin->optional->cursor = pCursor; + pCursor->refcnt++; + pWin->cursorIsNone = FALSE; + /* + * check on any children now matching the new cursor + */ + + for (pChild=pWin->firstChild; pChild; pChild=pChild->nextSib) + { + if (pChild->optional && + (pChild->optional->cursor == pCursor)) + CheckWindowOptionalNeed (pChild); + } + } + + if (pWin->realized) + WindowHasNewCursor( pWin); + + /* Can't free cursor until here - old cursor + * is needed in WindowHasNewCursor + */ + if (pOldCursor) + FreeCursor (pOldCursor, (Cursor)0); + } + break; + default: + error = BadValue; + client->errorValue = vmask; + goto PatchUp; + } + vmaskCopy |= index2; + } +PatchUp: + if (checkOptional) + CheckWindowOptionalNeed (pWin); + + /* We SHOULD check for an error value here XXX */ + (*pScreen->ChangeWindowAttributes)(pWin, vmaskCopy); + + /* + If the border contents have changed, redraw the border. + Note that this has to be done AFTER pScreen->ChangeWindowAttributes + for the tile to be rotated, and the correct function selected. + */ + if (((vmaskCopy & (CWBorderPixel | CWBorderPixmap)) || borderRelative) + && pWin->viewable && HasBorder (pWin)) + { + RegionRec exposed; + + REGION_NULL(pScreen, &exposed); + REGION_SUBTRACT(pScreen, &exposed, &pWin->borderClip, &pWin->winSize); + (*pWin->drawable.pScreen->PaintWindowBorder)(pWin, &exposed, PW_BORDER); + REGION_UNINIT(pScreen, &exposed); + } + return error; +} + + +/***** + * GetWindowAttributes + * Notice that this is different than ChangeWindowAttributes + *****/ + +void +GetWindowAttributes(register WindowPtr pWin, ClientPtr client, xGetWindowAttributesReply *wa) +{ + wa->type = X_Reply; + wa->bitGravity = pWin->bitGravity; + wa->winGravity = pWin->winGravity; + if (pWin->forcedBS && pWin->backingStore != Always) + wa->backingStore = NotUseful; + else + wa->backingStore = pWin->backingStore; + wa->length = (sizeof(xGetWindowAttributesReply) - + sizeof(xGenericReply)) >> 2; + wa->sequenceNumber = client->sequence; + wa->backingBitPlanes = wBackingBitPlanes (pWin); + wa->backingPixel = wBackingPixel (pWin); + wa->saveUnder = (BOOL)pWin->saveUnder; + wa->override = pWin->overrideRedirect; + if (!pWin->mapped) + wa->mapState = IsUnmapped; + else if (pWin->realized) + wa->mapState = IsViewable; + else + wa->mapState = IsUnviewable; + + wa->colormap = wColormap (pWin); + wa->mapInstalled = (wa->colormap == None) ? xFalse + : IsMapInstalled(wa->colormap, pWin); + + wa->yourEventMask = EventMaskForClient(pWin, client); + wa->allEventMasks = pWin->eventMask | wOtherEventMasks (pWin); + wa->doNotPropagateMask = wDontPropagateMask (pWin); + wa->class = pWin->drawable.class; + wa->visualID = wVisual (pWin); +} + + +WindowPtr +MoveWindowInStack(register WindowPtr pWin, register WindowPtr pNextSib) +{ + register WindowPtr pParent = pWin->parent; + WindowPtr pFirstChange = pWin; /* highest window where list changes */ + + if (pWin->nextSib != pNextSib) + { + WindowPtr pOldNextSib = pWin->nextSib; + + if (!pNextSib) /* move to bottom */ + { + if (pParent->firstChild == pWin) + pParent->firstChild = pWin->nextSib; + /* if (pWin->nextSib) */ /* is always True: pNextSib == NULL + * and pWin->nextSib != pNextSib + * therefore pWin->nextSib != NULL */ + pFirstChange = pWin->nextSib; + pWin->nextSib->prevSib = pWin->prevSib; + if (pWin->prevSib) + pWin->prevSib->nextSib = pWin->nextSib; + pParent->lastChild->nextSib = pWin; + pWin->prevSib = pParent->lastChild; + pWin->nextSib = NullWindow; + pParent->lastChild = pWin; + } + else if (pParent->firstChild == pNextSib) /* move to top */ + { + pFirstChange = pWin; + if (pParent->lastChild == pWin) + pParent->lastChild = pWin->prevSib; + if (pWin->nextSib) + pWin->nextSib->prevSib = pWin->prevSib; + if (pWin->prevSib) + pWin->prevSib->nextSib = pWin->nextSib; + pWin->nextSib = pParent->firstChild; + pWin->prevSib = (WindowPtr ) NULL; + pNextSib->prevSib = pWin; + pParent->firstChild = pWin; + } + else /* move in middle of list */ + { + WindowPtr pOldNext = pWin->nextSib; + + pFirstChange = NullWindow; + if (pParent->firstChild == pWin) + pFirstChange = pParent->firstChild = pWin->nextSib; + if (pParent->lastChild == pWin) { + pFirstChange = pWin; + pParent->lastChild = pWin->prevSib; + } + if (pWin->nextSib) + pWin->nextSib->prevSib = pWin->prevSib; + if (pWin->prevSib) + pWin->prevSib->nextSib = pWin->nextSib; + pWin->nextSib = pNextSib; + pWin->prevSib = pNextSib->prevSib; + if (pNextSib->prevSib) + pNextSib->prevSib->nextSib = pWin; + pNextSib->prevSib = pWin; + if (!pFirstChange) { /* do we know it yet? */ + pFirstChange = pParent->firstChild; /* no, search from top */ + while ((pFirstChange != pWin) && (pFirstChange != pOldNext)) + pFirstChange = pFirstChange->nextSib; + } + } + if(pWin->drawable.pScreen->RestackWindow) + (*pWin->drawable.pScreen->RestackWindow)(pWin, pOldNextSib); + } + +#ifdef ROOTLESS + /* + * In rootless mode we can't optimize away window restacks. + * There may be non-X windows around, so even if the window + * is in the correct position from X's point of view, + * the underlying window system may want to reorder it. + */ + else if (pWin->drawable.pScreen->RestackWindow) + (*pWin->drawable.pScreen->RestackWindow)(pWin, pWin->nextSib); +#endif + + return( pFirstChange ); +} + +RegionPtr +CreateUnclippedWinSize (register WindowPtr pWin) +{ + RegionPtr pRgn; + BoxRec box; + + box.x1 = pWin->drawable.x; + box.y1 = pWin->drawable.y; + box.x2 = pWin->drawable.x + (int) pWin->drawable.width; + box.y2 = pWin->drawable.y + (int) pWin->drawable.height; + pRgn = REGION_CREATE(pWin->drawable.pScreen, &box, 1); +#ifdef SHAPE + if (wBoundingShape (pWin) || wClipShape (pWin)) { +#ifndef NXAGENT_SERVER + ScreenPtr pScreen = pWin->drawable.pScreen; +#endif /* NXAGENT_SERVER */ + REGION_TRANSLATE(pScreen, pRgn, - pWin->drawable.x, + - pWin->drawable.y); + if (wBoundingShape (pWin)) + REGION_INTERSECT(pScreen, pRgn, pRgn, wBoundingShape (pWin)); + if (wClipShape (pWin)) + REGION_INTERSECT(pScreen, pRgn, pRgn, wClipShape (pWin)); + REGION_TRANSLATE(pScreen, pRgn, pWin->drawable.x, pWin->drawable.y); + } +#endif + return pRgn; +} + +void +SetWinSize (register WindowPtr pWin) +{ +#ifdef COMPOSITE + if (pWin->redirectDraw) + { + BoxRec box; + + box.x1 = pWin->drawable.x; + box.y1 = pWin->drawable.y; + box.x2 = pWin->drawable.x + pWin->drawable.width; + box.y2 = pWin->drawable.y + pWin->drawable.height; + REGION_RESET (pScreen, &pWin->winSize, &box); + } + else +#endif + ClippedRegionFromBox(pWin->parent, &pWin->winSize, + pWin->drawable.x, pWin->drawable.y, + (int)pWin->drawable.width, + (int)pWin->drawable.height); +#ifdef SHAPE + if (wBoundingShape (pWin) || wClipShape (pWin)) { +#ifndef NXAGENT_SERVER + ScreenPtr pScreen = pWin->drawable.pScreen; +#endif /* NXAGENT_SERVER */ + REGION_TRANSLATE(pScreen, &pWin->winSize, - pWin->drawable.x, + - pWin->drawable.y); + if (wBoundingShape (pWin)) + REGION_INTERSECT(pScreen, &pWin->winSize, &pWin->winSize, + wBoundingShape (pWin)); + if (wClipShape (pWin)) + REGION_INTERSECT(pScreen, &pWin->winSize, &pWin->winSize, + wClipShape (pWin)); + REGION_TRANSLATE(pScreen, &pWin->winSize, pWin->drawable.x, + pWin->drawable.y); + } +#endif +} + +void +SetBorderSize (register WindowPtr pWin) +{ + int bw; + + if (HasBorder (pWin)) { + bw = wBorderWidth (pWin); +#ifdef COMPOSITE + if (pWin->redirectDraw) + { + BoxRec box; + + box.x1 = pWin->drawable.x - bw; + box.y1 = pWin->drawable.y - bw; + box.x2 = pWin->drawable.x + pWin->drawable.width + bw; + box.y2 = pWin->drawable.y + pWin->drawable.height + bw; + REGION_RESET (pScreen, &pWin->borderSize, &box); + } + else +#endif + ClippedRegionFromBox(pWin->parent, &pWin->borderSize, + pWin->drawable.x - bw, pWin->drawable.y - bw, + (int)(pWin->drawable.width + (bw<<1)), + (int)(pWin->drawable.height + (bw<<1))); +#ifdef SHAPE + if (wBoundingShape (pWin)) { +#ifndef NXAGENT_SERVER + ScreenPtr pScreen = pWin->drawable.pScreen; +#endif /* NXAGENT_SERVER */ + REGION_TRANSLATE(pScreen, &pWin->borderSize, - pWin->drawable.x, + - pWin->drawable.y); + REGION_INTERSECT(pScreen, &pWin->borderSize, &pWin->borderSize, + wBoundingShape (pWin)); + REGION_TRANSLATE(pScreen, &pWin->borderSize, pWin->drawable.x, + pWin->drawable.y); + REGION_UNION(pScreen, &pWin->borderSize, &pWin->borderSize, + &pWin->winSize); + } +#endif + } else { + REGION_COPY(pWin->drawable.pScreen, &pWin->borderSize, + &pWin->winSize); + } +} + +/** + * + * \param x,y new window position + * \param oldx,oldy old window position + * \param destx,desty position relative to gravity + */ + +void +GravityTranslate (register int x, register int y, int oldx, int oldy, + int dw, int dh, unsigned gravity, + register int *destx, register int *desty) +{ + switch (gravity) { + case NorthGravity: + *destx = x + dw / 2; + *desty = y; + break; + case NorthEastGravity: + *destx = x + dw; + *desty = y; + break; + case WestGravity: + *destx = x; + *desty = y + dh / 2; + break; + case CenterGravity: + *destx = x + dw / 2; + *desty = y + dh / 2; + break; + case EastGravity: + *destx = x + dw; + *desty = y + dh / 2; + break; + case SouthWestGravity: + *destx = x; + *desty = y + dh; + break; + case SouthGravity: + *destx = x + dw / 2; + *desty = y + dh; + break; + case SouthEastGravity: + *destx = x + dw; + *desty = y + dh; + break; + case StaticGravity: + *destx = oldx; + *desty = oldy; + break; + default: + *destx = x; + *desty = y; + break; + } +} + +/* XXX need to retile border on each window with ParentRelative origin */ +void +ResizeChildrenWinSize(register WindowPtr pWin, int dx, int dy, int dw, int dh) +{ + register ScreenPtr pScreen; + register WindowPtr pSib, pChild; + Bool resized = (dw || dh); + + pScreen = pWin->drawable.pScreen; + + for (pSib = pWin->firstChild; pSib; pSib = pSib->nextSib) + { + if (resized && (pSib->winGravity > NorthWestGravity)) + { + int cwsx, cwsy; + + cwsx = pSib->origin.x; + cwsy = pSib->origin.y; + GravityTranslate (cwsx, cwsy, cwsx - dx, cwsy - dy, dw, dh, + pSib->winGravity, &cwsx, &cwsy); + if (cwsx != pSib->origin.x || cwsy != pSib->origin.y) + { + xEvent event; + + event.u.u.type = GravityNotify; + event.u.gravity.window = pSib->drawable.id; + event.u.gravity.x = cwsx - wBorderWidth (pSib); + event.u.gravity.y = cwsy - wBorderWidth (pSib); + DeliverEvents (pSib, &event, 1, NullWindow); + pSib->origin.x = cwsx; + pSib->origin.y = cwsy; + } + } + pSib->drawable.x = pWin->drawable.x + pSib->origin.x; + pSib->drawable.y = pWin->drawable.y + pSib->origin.y; + SetWinSize (pSib); + SetBorderSize (pSib); + + /* + * Don't force X to move children. It will position them + * according with gravity. + * + * (*pScreen->PositionWindow)(pSib, pSib->drawable.x, pSib->drawable.y); + */ + + /* + * Update pSib privates, as this window is moved by X. + */ + + nxagentAddConfiguredWindow(pSib, CW_Update); + + if ( (pChild = pSib->firstChild) ) + { + while (1) + { + pChild->drawable.x = pChild->parent->drawable.x + + pChild->origin.x; + pChild->drawable.y = pChild->parent->drawable.y + + pChild->origin.y; + SetWinSize (pChild); + SetBorderSize (pChild); + + (*pScreen->PositionWindow)(pChild, pChild->drawable.x, + pChild->drawable.y); + + if (pChild->firstChild) + { + pChild = pChild->firstChild; + continue; + } + while (!pChild->nextSib && (pChild != pSib)) + pChild = pChild->parent; + if (pChild == pSib) + break; + pChild = pChild->nextSib; + } + } + } +} + +#define GET_INT16(m, f) \ + if (m & mask) \ + { \ + f = (INT16) *pVlist;\ + pVlist++; \ + } +#define GET_CARD16(m, f) \ + if (m & mask) \ + { \ + f = (CARD16) *pVlist;\ + pVlist++;\ + } + +#define GET_CARD8(m, f) \ + if (m & mask) \ + { \ + f = (CARD8) *pVlist;\ + pVlist++;\ + } + +#define ChangeMask ((Mask)(CWX | CWY | CWWidth | CWHeight)) + +#define IllegalInputOnlyConfigureMask (CWBorderWidth) + +/* + * IsSiblingAboveMe + * returns Above if pSib above pMe in stack or Below otherwise + */ + +static int +IsSiblingAboveMe( + register WindowPtr pMe, + register WindowPtr pSib) +{ + register WindowPtr pWin; + + pWin = pMe->parent->firstChild; + while (pWin) + { + if (pWin == pSib) + return(Above); + else if (pWin == pMe) + return(Below); + pWin = pWin->nextSib; + } + return(Below); +} + +static BoxPtr +WindowExtents( + register WindowPtr pWin, + register BoxPtr pBox) +{ + pBox->x1 = pWin->drawable.x - wBorderWidth (pWin); + pBox->y1 = pWin->drawable.y - wBorderWidth (pWin); + pBox->x2 = pWin->drawable.x + (int)pWin->drawable.width + + wBorderWidth (pWin); + pBox->y2 = pWin->drawable.y + (int)pWin->drawable.height + + wBorderWidth (pWin); + return(pBox); +} + +#ifdef SHAPE +#define IS_SHAPED(pWin) (wBoundingShape (pWin) != (RegionPtr) NULL) + +static RegionPtr +MakeBoundingRegion ( + register WindowPtr pWin, + BoxPtr pBox) +{ + RegionPtr pRgn; +#ifndef NXAGENT_SERVER + ScreenPtr pScreen = pWin->drawable.pScreen; +#endif /* NXAGENT_SERVER */ + pRgn = REGION_CREATE(pScreen, pBox, 1); + if (wBoundingShape (pWin)) { + REGION_TRANSLATE(pScreen, pRgn, -pWin->origin.x, + -pWin->origin.y); + REGION_INTERSECT(pScreen, pRgn, pRgn, wBoundingShape (pWin)); + REGION_TRANSLATE(pScreen, pRgn, pWin->origin.x, + pWin->origin.y); + } + return pRgn; +} + +static Bool +ShapeOverlap ( + WindowPtr pWin, + BoxPtr pWinBox, + WindowPtr pSib, + BoxPtr pSibBox) +{ + RegionPtr pWinRgn, pSibRgn; + register ScreenPtr pScreen; + Bool ret; + + if (!IS_SHAPED(pWin) && !IS_SHAPED(pSib)) + return TRUE; + pScreen = pWin->drawable.pScreen; + pWinRgn = MakeBoundingRegion (pWin, pWinBox); + pSibRgn = MakeBoundingRegion (pSib, pSibBox); + REGION_INTERSECT(pScreen, pWinRgn, pWinRgn, pSibRgn); + ret = REGION_NOTEMPTY(pScreen, pWinRgn); + REGION_DESTROY(pScreen, pWinRgn); + REGION_DESTROY(pScreen, pSibRgn); + return ret; +} +#endif + +static Bool +AnyWindowOverlapsMe( + WindowPtr pWin, + WindowPtr pHead, + register BoxPtr box) +{ + register WindowPtr pSib; + BoxRec sboxrec; + register BoxPtr sbox; + + for (pSib = pWin->prevSib; pSib != pHead; pSib = pSib->prevSib) + { + if (pSib->mapped) + { + sbox = WindowExtents(pSib, &sboxrec); + if (BOXES_OVERLAP(sbox, box) +#ifdef SHAPE + && ShapeOverlap (pWin, box, pSib, sbox) +#endif + ) + return(TRUE); + } + } + return(FALSE); +} + +static Bool +IOverlapAnyWindow( + WindowPtr pWin, + register BoxPtr box) +{ + register WindowPtr pSib; + BoxRec sboxrec; + register BoxPtr sbox; + + for (pSib = pWin->nextSib; pSib; pSib = pSib->nextSib) + { + if (pSib->mapped) + { + sbox = WindowExtents(pSib, &sboxrec); + if (BOXES_OVERLAP(sbox, box) +#ifdef SHAPE + && ShapeOverlap (pWin, box, pSib, sbox) +#endif + ) + return(TRUE); + } + } + return(FALSE); +} + +/* + * WhereDoIGoInTheStack() + * Given pWin and pSib and the relationshipe smode, return + * the window that pWin should go ABOVE. + * If a pSib is specified: + * Above: pWin is placed just above pSib + * Below: pWin is placed just below pSib + * TopIf: if pSib occludes pWin, then pWin is placed + * at the top of the stack + * BottomIf: if pWin occludes pSib, then pWin is + * placed at the bottom of the stack + * Opposite: if pSib occludes pWin, then pWin is placed at the + * top of the stack, else if pWin occludes pSib, then + * pWin is placed at the bottom of the stack + * + * If pSib is NULL: + * Above: pWin is placed at the top of the stack + * Below: pWin is placed at the bottom of the stack + * TopIf: if any sibling occludes pWin, then pWin is placed at + * the top of the stack + * BottomIf: if pWin occludes any sibline, then pWin is placed at + * the bottom of the stack + * Opposite: if any sibling occludes pWin, then pWin is placed at + * the top of the stack, else if pWin occludes any + * sibling, then pWin is placed at the bottom of the stack + * + */ + +static WindowPtr +WhereDoIGoInTheStack( + register WindowPtr pWin, + register WindowPtr pSib, + short x, + short y, + unsigned short w, + unsigned short h, + int smode) +{ + BoxRec box; + register ScreenPtr pScreen; + WindowPtr pHead, pFirst; + + if ((pWin == pWin->parent->firstChild) && + (pWin == pWin->parent->lastChild)) + return((WindowPtr ) NULL); + pHead = RealChildHead(pWin->parent); + pFirst = pHead ? pHead->nextSib : pWin->parent->firstChild; + pScreen = pWin->drawable.pScreen; + box.x1 = x; + box.y1 = y; + box.x2 = x + (int)w; + box.y2 = y + (int)h; + switch (smode) + { + case Above: + if (pSib) + return(pSib); + else if (pWin == pFirst) + return(pWin->nextSib); + else + return(pFirst); + case Below: + if (pSib) + if (pSib->nextSib != pWin) + return(pSib->nextSib); + else + return(pWin->nextSib); + else + return NullWindow; + case TopIf: + if ((!pWin->mapped || (pSib && !pSib->mapped)) && !permitOldBugs) + return(pWin->nextSib); + else if (pSib) + { + if ((IsSiblingAboveMe(pWin, pSib) == Above) && + (RECT_IN_REGION(pScreen, &pSib->borderSize, &box) != rgnOUT)) + return(pFirst); + else + return(pWin->nextSib); + } + else if (AnyWindowOverlapsMe(pWin, pHead, &box)) + return(pFirst); + else + return(pWin->nextSib); + case BottomIf: + if ((!pWin->mapped || (pSib && !pSib->mapped)) && !permitOldBugs) + return(pWin->nextSib); + else if (pSib) + { + if ((IsSiblingAboveMe(pWin, pSib) == Below) && + (RECT_IN_REGION(pScreen, &pSib->borderSize, &box) != rgnOUT)) + return NullWindow; + else + return(pWin->nextSib); + } + else if (IOverlapAnyWindow(pWin, &box)) + return NullWindow; + else + return(pWin->nextSib); + case Opposite: + if ((!pWin->mapped || (pSib && !pSib->mapped)) && !permitOldBugs) + return(pWin->nextSib); + else if (pSib) + { + if (RECT_IN_REGION(pScreen, &pSib->borderSize, &box) != rgnOUT) + { + if (IsSiblingAboveMe(pWin, pSib) == Above) + return(pFirst); + else + return NullWindow; + } + else + return(pWin->nextSib); + } + else if (AnyWindowOverlapsMe(pWin, pHead, &box)) + { + /* If I'm occluded, I can't possibly be the first child + * if (pWin == pWin->parent->firstChild) + * return pWin->nextSib; + */ + return(pFirst); + } + else if (IOverlapAnyWindow(pWin, &box)) + return NullWindow; + else + return pWin->nextSib; + default: + { + ErrorF("Internal error in ConfigureWindow, smode == %d\n",smode ); + return pWin->nextSib; + } + } +} + +static void +ReflectStackChange( + register WindowPtr pWin, + register WindowPtr pSib, + VTKind kind) +{ +/* Note that pSib might be NULL */ + + Bool WasViewable = (Bool)pWin->viewable; + Bool anyMarked; + WindowPtr pFirstChange; +#ifdef DO_SAVE_UNDERS + Bool dosave = FALSE; +#endif + WindowPtr pLayerWin; + ScreenPtr pScreen = pWin->drawable.pScreen; + + /* if this is a root window, can't be restacked */ + if (!pWin->parent) + return; + + pFirstChange = MoveWindowInStack(pWin, pSib); + + if (WasViewable) + { + anyMarked = (*pScreen->MarkOverlappedWindows)(pWin, pFirstChange, + &pLayerWin); + if (pLayerWin != pWin) pFirstChange = pLayerWin; +#ifdef DO_SAVE_UNDERS + if (DO_SAVE_UNDERS(pWin)) + { + dosave = (*pScreen->ChangeSaveUnder)(pLayerWin, pFirstChange); + } +#endif /* DO_SAVE_UNDERS */ + if (anyMarked) + { + (*pScreen->ValidateTree)(pLayerWin->parent, pFirstChange, kind); + (*pScreen->HandleExposures)(pLayerWin->parent); + } +#ifdef DO_SAVE_UNDERS + if (dosave) + (*pScreen->PostChangeSaveUnder)(pLayerWin, pFirstChange); +#endif /* DO_SAVE_UNDERS */ + if (anyMarked && pWin->drawable.pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pLayerWin->parent, pFirstChange, kind); + } + if (pWin->realized) + WindowsRestructured (); +} + +/***** + * ConfigureWindow + *****/ + +int +ConfigureWindow(register WindowPtr pWin, register Mask mask, XID *vlist, ClientPtr client) +{ +#define RESTACK_WIN 0 +#define MOVE_WIN 1 +#define RESIZE_WIN 2 +#define REBORDER_WIN 3 + register WindowPtr pSib = NullWindow; + register WindowPtr pParent = pWin->parent; + Window sibwid = 0; + Mask index2, tmask; + register XID *pVlist; + short x, y, beforeX, beforeY; + unsigned short w = pWin->drawable.width, + h = pWin->drawable.height, + bw = pWin->borderWidth; + int action, smode = Above; +#ifdef XAPPGROUP + ClientPtr win_owner; + ClientPtr ag_leader = NULL; +#endif + xEvent event; + + if ((pWin->drawable.class == InputOnly) && (mask & IllegalInputOnlyConfigureMask)) + return(BadMatch); + + if ((mask & CWSibling) && !(mask & CWStackMode)) + return(BadMatch); + + pVlist = vlist; + + if (pParent) + { + x = pWin->drawable.x - pParent->drawable.x - (int)bw; + y = pWin->drawable.y - pParent->drawable.y - (int)bw; + } + else + { + x = pWin->drawable.x; + y = pWin->drawable.y; + } + beforeX = x; + beforeY = y; + action = RESTACK_WIN; + if ((mask & (CWX | CWY)) && (!(mask & (CWHeight | CWWidth)))) + { + GET_INT16(CWX, x); + GET_INT16(CWY, y); + action = MOVE_WIN; + } + /* or should be resized */ + else if (mask & (CWX | CWY | CWWidth | CWHeight)) + { + GET_INT16(CWX, x); + GET_INT16(CWY, y); + GET_CARD16(CWWidth, w); + GET_CARD16 (CWHeight, h); + if (!w || !h) + { + client->errorValue = 0; + return BadValue; + } + action = RESIZE_WIN; + } + tmask = mask & ~ChangeMask; + while (tmask) + { + index2 = (Mask)lowbit (tmask); + tmask &= ~index2; + switch (index2) + { + case CWBorderWidth: + GET_CARD16(CWBorderWidth, bw); + break; + case CWSibling: + sibwid = (Window ) *pVlist; + pVlist++; + pSib = (WindowPtr )SecurityLookupIDByType(client, sibwid, + RT_WINDOW, SecurityReadAccess); + if (!pSib) + { + client->errorValue = sibwid; + return(BadWindow); + } + if (pSib->parent != pParent) + return(BadMatch); + if (pSib == pWin) + return(BadMatch); + break; + case CWStackMode: + GET_CARD8(CWStackMode, smode); + if ((smode != TopIf) && (smode != BottomIf) && + (smode != Opposite) && (smode != Above) && (smode != Below)) + { + client->errorValue = smode; + return(BadValue); + } + break; + default: + client->errorValue = mask; + return(BadValue); + } + } + /* root really can't be reconfigured, so just return */ + if (!pParent) + return Success; + + /* Figure out if the window should be moved. Doesnt + make the changes to the window if event sent */ + + #ifdef TEST + if (nxagentWindowTopLevel(pWin)) + { + + fprintf(stderr, "ConfigureWindow: pWin [%p] mask [%lu] client [%p]\n", + pWin, mask, client); + + fprintf(stderr, "ConfigureWindow: x [%d] y [%d] w [%d] h [%d] CWStackMode [%d] " + "smode [%d] pSib [%p]\n", + x, y, w, h, (mask & CWStackMode) ? 1 : 0, smode, pSib); + } + #endif + + if (nxagentOption(Rootless) && nxagentWindowTopLevel(pWin) && + pWin -> overrideRedirect == 0 && + nxagentScreenTrap == 0) + { + nxagentConfigureRootlessWindow(pWin, x, y, w, h, bw, pSib, smode, mask); + + return Success; + } + + if (mask & CWStackMode) + pSib = WhereDoIGoInTheStack(pWin, pSib, pParent->drawable.x + x, + pParent->drawable.y + y, + w + (bw << 1), h + (bw << 1), smode); + else + pSib = pWin->nextSib; + +#ifdef XAPPGROUP + win_owner = clients[CLIENT_ID(pWin->drawable.id)]; + ag_leader = XagLeader (win_owner); +#endif + + if ((!pWin->overrideRedirect) && + (RedirectSend(pParent) +#ifdef XAPPGROUP + || (win_owner->appgroup && ag_leader && + XagIsControlledRoot (client, pParent)) +#endif + )) + { + event.u.u.type = ConfigureRequest; + event.u.configureRequest.window = pWin->drawable.id; + if (mask & CWSibling) + event.u.configureRequest.sibling = sibwid; + else + event.u.configureRequest.sibling = None; + if (mask & CWStackMode) + event.u.u.detail = smode; + else + event.u.u.detail = Above; + event.u.configureRequest.x = x; + event.u.configureRequest.y = y; +#ifdef PANORAMIX + if(!noPanoramiXExtension && (!pParent || !pParent->parent)) { + event.u.configureRequest.x += panoramiXdataPtr[0].x; + event.u.configureRequest.y += panoramiXdataPtr[0].y; + } +#endif + event.u.configureRequest.width = w; + event.u.configureRequest.height = h; + event.u.configureRequest.borderWidth = bw; + event.u.configureRequest.valueMask = mask; +#ifdef XAPPGROUP + /* make sure if the ag_leader maps the window it goes to the wm */ + if (ag_leader && ag_leader != client && + XagIsControlledRoot (client, pParent)) { + event.u.configureRequest.parent = XagId (win_owner); + (void) TryClientEvents (ag_leader, &event, 1, + NoEventMask, NoEventMask, NullGrab); + return Success; + } +#endif + event.u.configureRequest.parent = pParent->drawable.id; + if (MaybeDeliverEventsToClient(pParent, &event, 1, + SubstructureRedirectMask, client) == 1) + return(Success); + } + if (action == RESIZE_WIN) + { + Bool size_change = (w != pWin->drawable.width) + || (h != pWin->drawable.height); + if (size_change && ((pWin->eventMask|wOtherEventMasks(pWin)) & ResizeRedirectMask)) + { + xEvent eventT; + eventT.u.u.type = ResizeRequest; + eventT.u.resizeRequest.window = pWin->drawable.id; + eventT.u.resizeRequest.width = w; + eventT.u.resizeRequest.height = h; + if (MaybeDeliverEventsToClient(pWin, &eventT, 1, + ResizeRedirectMask, client) == 1) + { + /* if event is delivered, leave the actual size alone. */ + w = pWin->drawable.width; + h = pWin->drawable.height; + size_change = FALSE; + } + } + if (!size_change) + { + if (mask & (CWX | CWY)) + action = MOVE_WIN; + else if (mask & (CWStackMode | CWBorderWidth)) + action = RESTACK_WIN; + else /* really nothing to do */ + return(Success) ; + } + } + + if (action == RESIZE_WIN) + /* we've already checked whether there's really a size change */ + goto ActuallyDoSomething; + if ((mask & CWX) && (x != beforeX)) + goto ActuallyDoSomething; + if ((mask & CWY) && (y != beforeY)) + goto ActuallyDoSomething; + if ((mask & CWBorderWidth) && (bw != wBorderWidth (pWin))) + goto ActuallyDoSomething; + if (mask & CWStackMode) + { +#ifndef ROOTLESS + /* See above for why we always reorder in rootless mode. */ + if (pWin->nextSib != pSib) +#endif + goto ActuallyDoSomething; + } + return(Success); + +ActuallyDoSomething: + if (SubStrSend(pWin, pParent)) + { + event.u.u.type = ConfigureNotify; + event.u.configureNotify.window = pWin->drawable.id; + if (pSib) + event.u.configureNotify.aboveSibling = pSib->drawable.id; + else + event.u.configureNotify.aboveSibling = None; + event.u.configureNotify.x = x; + event.u.configureNotify.y = y; +#ifdef PANORAMIX + if(!noPanoramiXExtension && (!pParent || !pParent->parent)) { + event.u.configureNotify.x += panoramiXdataPtr[0].x; + event.u.configureNotify.y += panoramiXdataPtr[0].y; + } +#endif + event.u.configureNotify.width = w; + event.u.configureNotify.height = h; + event.u.configureNotify.borderWidth = bw; + event.u.configureNotify.override = pWin->overrideRedirect; + DeliverEvents(pWin, &event, 1, NullWindow); + } + if (mask & CWBorderWidth) + { + if (action == RESTACK_WIN) + { + action = MOVE_WIN; + pWin->borderWidth = bw; + } + else if ((action == MOVE_WIN) && + (beforeX + wBorderWidth (pWin) == x + (int)bw) && + (beforeY + wBorderWidth (pWin) == y + (int)bw)) + { + action = REBORDER_WIN; + (*pWin->drawable.pScreen->ChangeBorderWidth)(pWin, bw); + } + else + pWin->borderWidth = bw; + } + if (action == MOVE_WIN) + (*pWin->drawable.pScreen->MoveWindow)(pWin, x, y, pSib, + (mask & CWBorderWidth) ? VTOther : VTMove); + else if (action == RESIZE_WIN) + (*pWin->drawable.pScreen->ResizeWindow)(pWin, x, y, w, h, pSib); + else if (mask & CWStackMode) + ReflectStackChange(pWin, pSib, VTOther); + + if (action != RESTACK_WIN) + CheckCursorConfinement(pWin); + + nxagentFlushConfigureWindow(); + + return(Success); +#undef RESTACK_WIN +#undef MOVE_WIN +#undef RESIZE_WIN +#undef REBORDER_WIN +} + + +/****** + * + * CirculateWindow + * For RaiseLowest, raises the lowest mapped child (if any) that is + * obscured by another child to the top of the stack. For LowerHighest, + * lowers the highest mapped child (if any) that is obscuring another + * child to the bottom of the stack. Exposure processing is performed + * + ******/ + +int +CirculateWindow(WindowPtr pParent, int direction, ClientPtr client) +{ + register WindowPtr pWin, pHead, pFirst; + xEvent event; + BoxRec box; + + #ifdef TEST + fprintf(stderr, "CirculateWindow: pParent [%p] direction [%d] client [%p]\n", + pParent, direction, client); + #endif + + /* + * if (nxagentOption(Rootless) && nxagentWMIsRunning && + * nxagentWindowTopLevel(pWin) && pWin -> overrideRedirect == 0) + * { + * nxagentCirculateRootlessWindows(direction); + * return Success; + * } + */ + + pHead = RealChildHead(pParent); + pFirst = pHead ? pHead->nextSib : pParent->firstChild; + if (direction == RaiseLowest) + { + for (pWin = pParent->lastChild; + (pWin != pHead) && + !(pWin->mapped && + AnyWindowOverlapsMe(pWin, pHead, WindowExtents(pWin, &box))); + pWin = pWin->prevSib) ; + if (pWin == pHead) + return Success; + } + else + { + for (pWin = pFirst; + pWin && + !(pWin->mapped && + IOverlapAnyWindow(pWin, WindowExtents(pWin, &box))); + pWin = pWin->nextSib) ; + if (!pWin) + return Success; + } + + event.u.circulate.window = pWin->drawable.id; + event.u.circulate.parent = pParent->drawable.id; + event.u.circulate.event = pParent->drawable.id; + if (direction == RaiseLowest) + event.u.circulate.place = PlaceOnTop; + else + event.u.circulate.place = PlaceOnBottom; + + if (RedirectSend(pParent)) + { + event.u.u.type = CirculateRequest; + if (MaybeDeliverEventsToClient(pParent, &event, 1, + SubstructureRedirectMask, client) == 1) + return(Success); + } + + event.u.u.type = CirculateNotify; + DeliverEvents(pWin, &event, 1, NullWindow); + ReflectStackChange(pWin, + (direction == RaiseLowest) ? pFirst : NullWindow, + VTStack); + + return(Success); +} + +static int +CompareWIDs( + WindowPtr pWin, + pointer value) /* must conform to VisitWindowProcPtr */ +{ + Window *wid = (Window *)value; + + if (pWin->drawable.id == *wid) + return(WT_STOPWALKING); + else + return(WT_WALKCHILDREN); +} + +/***** + * ReparentWindow + *****/ + +int +ReparentWindow(register WindowPtr pWin, register WindowPtr pParent, + int x, int y, ClientPtr client) +{ + WindowPtr pPrev, pPriorParent; + Bool WasMapped = (Bool)(pWin->mapped); + xEvent event; + int bw = wBorderWidth (pWin); + register ScreenPtr pScreen; + + pScreen = pWin->drawable.pScreen; + if (TraverseTree(pWin, CompareWIDs, (pointer)&pParent->drawable.id) == WT_STOPWALKING) + return(BadMatch); + if (!MakeWindowOptional(pWin)) + return(BadAlloc); + + if (WasMapped) + UnmapWindow(pWin, FALSE); + + event.u.u.type = ReparentNotify; + event.u.reparent.window = pWin->drawable.id; + event.u.reparent.parent = pParent->drawable.id; + event.u.reparent.x = x; + event.u.reparent.y = y; +#ifdef PANORAMIX + if(!noPanoramiXExtension && !pParent->parent) { + event.u.reparent.x += panoramiXdataPtr[0].x; + event.u.reparent.y += panoramiXdataPtr[0].y; + } +#endif + event.u.reparent.override = pWin->overrideRedirect; + DeliverEvents(pWin, &event, 1, pParent); + + /* take out of sibling chain */ + + pPriorParent = pPrev = pWin->parent; + if (pPrev->firstChild == pWin) + pPrev->firstChild = pWin->nextSib; + if (pPrev->lastChild == pWin) + pPrev->lastChild = pWin->prevSib; + + if (pWin->nextSib) + pWin->nextSib->prevSib = pWin->prevSib; + if (pWin->prevSib) + pWin->prevSib->nextSib = pWin->nextSib; + + /* insert at begining of pParent */ + pWin->parent = pParent; + pPrev = RealChildHead(pParent); + + if (pWin->parent == WindowTable[0]) + { + nxagentSetTopLevelEventMask(pWin); + } + + if (pPrev) + { + pWin->nextSib = pPrev->nextSib; + if (pPrev->nextSib) + pPrev->nextSib->prevSib = pWin; + else + pParent->lastChild = pWin; + pPrev->nextSib = pWin; + pWin->prevSib = pPrev; + } + else + { + pWin->nextSib = pParent->firstChild; + pWin->prevSib = NullWindow; + if (pParent->firstChild) + pParent->firstChild->prevSib = pWin; + else + pParent->lastChild = pWin; + pParent->firstChild = pWin; + } + + pWin->origin.x = x + bw; + pWin->origin.y = y + bw; + pWin->drawable.x = x + bw + pParent->drawable.x; + pWin->drawable.y = y + bw + pParent->drawable.y; + + /* clip to parent */ + SetWinSize (pWin); + SetBorderSize (pWin); + + if (pScreen->ReparentWindow) + (*pScreen->ReparentWindow)(pWin, pPriorParent); + + (*pScreen->PositionWindow)(pWin, pWin->drawable.x, pWin->drawable.y); + + ResizeChildrenWinSize(pWin, 0, 0, 0, 0); + + CheckWindowOptionalNeed(pWin); + + if (WasMapped) + MapWindow(pWin, client); + RecalculateDeliverableEvents(pWin); + return(Success); +} + +static void +RealizeTree(WindowPtr pWin) +{ + register WindowPtr pChild; + RealizeWindowProcPtr Realize; + + Realize = pWin->drawable.pScreen->RealizeWindow; + pChild = pWin; + while (1) + { + if (pChild->mapped) + { + pChild->realized = TRUE; +#ifdef DO_SAVE_UNDERS + if (pChild->saveUnder) + deltaSaveUndersViewable++; +#endif + pChild->viewable = (pChild->drawable.class == InputOutput); + (* Realize)(pChild); + if (pChild->firstChild) + { + pChild = pChild->firstChild; + continue; + } + } + while (!pChild->nextSib && (pChild != pWin)) + pChild = pChild->parent; + if (pChild == pWin) + return; + pChild = pChild->nextSib; + } +} + +/***** + * MapWindow + * If some other client has selected SubStructureReDirect on the parent + * and override-redirect is xFalse, then a MapRequest event is generated, + * but the window remains unmapped. Otherwise, the window is mapped and a + * MapNotify event is generated. + *****/ + +int +MapWindow(register WindowPtr pWin, ClientPtr client) +{ + register ScreenPtr pScreen; + + register WindowPtr pParent; +#ifdef DO_SAVE_UNDERS + Bool dosave = FALSE; +#endif + WindowPtr pLayerWin; + + #ifdef TEST + if (nxagentWindowTopLevel(pWin)) + { + fprintf(stderr, "MapWindow: pWin [%p] client [%p]\n", pWin, client); + } + #endif + + if (pWin->mapped) + return(Success); + +#ifdef XCSECURITY + /* don't let an untrusted client map a child-of-trusted-window, InputOnly + * window; too easy to steal device input + */ + if ( (client->trustLevel != XSecurityClientTrusted) && + (pWin->drawable.class == InputOnly) && + (wClient(pWin->parent)->trustLevel == XSecurityClientTrusted) ) + return Success; +#endif + + pScreen = pWin->drawable.pScreen; + if ( (pParent = pWin->parent) ) + { + xEvent event; + Bool anyMarked; +#ifdef XAPPGROUP + ClientPtr win_owner = clients[CLIENT_ID(pWin->drawable.id)]; + ClientPtr ag_leader = XagLeader (win_owner); +#endif + + if ((!pWin->overrideRedirect) && + (RedirectSend(pParent) +#ifdef XAPPGROUP + || (win_owner->appgroup && ag_leader && + XagIsControlledRoot (client, pParent)) +#endif + )) + { + event.u.u.type = MapRequest; + event.u.mapRequest.window = pWin->drawable.id; +#ifdef XAPPGROUP + /* make sure if the ag_leader maps the window it goes to the wm */ + if (ag_leader && ag_leader != client && + XagIsControlledRoot (client, pParent)) { + event.u.mapRequest.parent = XagId (win_owner); + (void) TryClientEvents (ag_leader, &event, 1, + NoEventMask, NoEventMask, NullGrab); + return Success; + } +#endif + event.u.mapRequest.parent = pParent->drawable.id; + + if (MaybeDeliverEventsToClient(pParent, &event, 1, + SubstructureRedirectMask, client) == 1) + return(Success); + } + + pWin->mapped = TRUE; + if (SubStrSend(pWin, pParent)) + { + event.u.u.type = MapNotify; + event.u.mapNotify.window = pWin->drawable.id; + event.u.mapNotify.override = pWin->overrideRedirect; + DeliverEvents(pWin, &event, 1, NullWindow); + } + + if (!pParent->realized) + return(Success); + RealizeTree(pWin); + if (pWin->viewable) + { + anyMarked = (*pScreen->MarkOverlappedWindows)(pWin, pWin, + &pLayerWin); +#ifdef DO_SAVE_UNDERS + if (DO_SAVE_UNDERS(pWin)) + { + dosave = (*pScreen->ChangeSaveUnder)(pLayerWin, pWin->nextSib); + } +#endif /* DO_SAVE_UNDERS */ + if (anyMarked) + { + (*pScreen->ValidateTree)(pLayerWin->parent, pLayerWin, VTMap); + (*pScreen->HandleExposures)(pLayerWin->parent); + } +#ifdef DO_SAVE_UNDERS + if (dosave) + (*pScreen->PostChangeSaveUnder)(pLayerWin, pWin->nextSib); +#endif /* DO_SAVE_UNDERS */ + if (anyMarked && pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pLayerWin->parent, pLayerWin, VTMap); + } + WindowsRestructured (); + } + else + { + RegionRec temp; + + pWin->mapped = TRUE; + pWin->realized = TRUE; /* for roots */ + pWin->viewable = pWin->drawable.class == InputOutput; + /* We SHOULD check for an error value here XXX */ + (*pScreen->RealizeWindow)(pWin); + if (pScreen->ClipNotify) + (*pScreen->ClipNotify) (pWin, 0, 0); + if (pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(NullWindow, pWin, VTMap); + REGION_NULL(pScreen, &temp); + REGION_COPY(pScreen, &temp, &pWin->clipList); + (*pScreen->WindowExposures) (pWin, &temp, NullRegion); + REGION_UNINIT(pScreen, &temp); + } + + nxagentFlushConfigureWindow(); + + return(Success); +} + + +/***** + * MapSubwindows + * Performs a MapWindow all unmapped children of the window, in top + * to bottom stacking order. + *****/ + +void +MapSubwindows(register WindowPtr pParent, ClientPtr client) +{ + register WindowPtr pWin; + WindowPtr pFirstMapped = NullWindow; +#ifdef DO_SAVE_UNDERS + WindowPtr pFirstSaveUndered = NullWindow; +#endif + register ScreenPtr pScreen; + register Mask parentRedirect; + register Mask parentNotify; + xEvent event; + Bool anyMarked; +#ifdef DO_SAVE_UNDERS + Bool dosave = FALSE; +#endif + WindowPtr pLayerWin; + + pScreen = pParent->drawable.pScreen; + parentRedirect = RedirectSend(pParent); + parentNotify = SubSend(pParent); + anyMarked = FALSE; + for (pWin = pParent->firstChild; pWin; pWin = pWin->nextSib) + { + if (!pWin->mapped) + { + if (parentRedirect && !pWin->overrideRedirect) + { + event.u.u.type = MapRequest; + event.u.mapRequest.window = pWin->drawable.id; + event.u.mapRequest.parent = pParent->drawable.id; + + if (MaybeDeliverEventsToClient(pParent, &event, 1, + SubstructureRedirectMask, client) == 1) + continue; + } + + pWin->mapped = TRUE; + if (parentNotify || StrSend(pWin)) + { + event.u.u.type = MapNotify; + event.u.mapNotify.window = pWin->drawable.id; + event.u.mapNotify.override = pWin->overrideRedirect; + DeliverEvents(pWin, &event, 1, NullWindow); + } + + if (!pFirstMapped) + pFirstMapped = pWin; + if (pParent->realized) + { + RealizeTree(pWin); + if (pWin->viewable) + { + anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin, pWin, + (WindowPtr *)NULL); +#ifdef DO_SAVE_UNDERS + if (DO_SAVE_UNDERS(pWin)) + { + dosave = TRUE; + } +#endif /* DO_SAVE_UNDERS */ + } + } + } + } + + if (pFirstMapped) + { + pLayerWin = (*pScreen->GetLayerWindow)(pParent); + if (pLayerWin->parent != pParent) { + anyMarked |= (*pScreen->MarkOverlappedWindows)(pLayerWin, + pLayerWin, + (WindowPtr *)NULL); + pFirstMapped = pLayerWin; + } + if (anyMarked) + { +#ifdef DO_SAVE_UNDERS + if (pLayerWin->parent != pParent) + { + if (dosave || (DO_SAVE_UNDERS(pLayerWin))) + { + dosave = (*pScreen->ChangeSaveUnder)(pLayerWin, + pLayerWin); + } + } + else if (dosave) + { + dosave = FALSE; + for (pWin = pParent->firstChild; pWin; pWin = pWin->nextSib) + { + if (DO_SAVE_UNDERS(pWin)) + { + dosave |= (*pScreen->ChangeSaveUnder)(pWin, + pWin->nextSib); + if (dosave && !pFirstSaveUndered) + pFirstSaveUndered = pWin; + } + } + } +#endif /* DO_SAVE_UNDERS */ + (*pScreen->ValidateTree)(pLayerWin->parent, pFirstMapped, VTMap); + (*pScreen->HandleExposures)(pLayerWin->parent); + } +#ifdef DO_SAVE_UNDERS + if (dosave) + (*pScreen->PostChangeSaveUnder)(pLayerWin, + pFirstSaveUndered->nextSib); +#endif /* DO_SAVE_UNDERS */ + if (anyMarked && pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pLayerWin->parent, pFirstMapped, + VTMap); + WindowsRestructured (); + } +} + +static void +UnrealizeTree( + WindowPtr pWin, + Bool fromConfigure) +{ + register WindowPtr pChild; + UnrealizeWindowProcPtr Unrealize; + MarkUnrealizedWindowProcPtr MarkUnrealizedWindow; + + Unrealize = pWin->drawable.pScreen->UnrealizeWindow; + MarkUnrealizedWindow = pWin->drawable.pScreen->MarkUnrealizedWindow; + pChild = pWin; + while (1) + { + if (pChild->realized) + { + pChild->realized = FALSE; + pChild->visibility = VisibilityNotViewable; +#ifdef PANORAMIX + if(!noPanoramiXExtension && !pChild->drawable.pScreen->myNum) { + PanoramiXRes *win; + win = (PanoramiXRes*)LookupIDByType(pChild->drawable.id, + XRT_WINDOW); + if(win) + win->u.win.visibility = VisibilityNotViewable; + } +#endif + (* Unrealize)(pChild); + DeleteWindowFromAnyEvents(pChild, FALSE); + if (pChild->viewable) + { +#ifdef DO_SAVE_UNDERS + if (pChild->saveUnder) + deltaSaveUndersViewable--; +#endif + pChild->viewable = FALSE; + if (pChild->backStorage) + (*pChild->drawable.pScreen->SaveDoomedAreas)( + pChild, &pChild->clipList, 0, 0); + (* MarkUnrealizedWindow)(pChild, pWin, fromConfigure); + pChild->drawable.serialNumber = NEXT_SERIAL_NUMBER; + } + if (pChild->firstChild) + { + pChild = pChild->firstChild; + continue; + } + } + while (!pChild->nextSib && (pChild != pWin)) + pChild = pChild->parent; + if (pChild == pWin) + return; + pChild = pChild->nextSib; + } +} + +/***** + * UnmapWindow + * If the window is already unmapped, this request has no effect. + * Otherwise, the window is unmapped and an UnMapNotify event is + * generated. Cannot unmap a root window. + *****/ + +int +UnmapWindow(register WindowPtr pWin, Bool fromConfigure) +{ + register WindowPtr pParent; + xEvent event; + Bool wasRealized = (Bool)pWin->realized; + Bool wasViewable = (Bool)pWin->viewable; + ScreenPtr pScreen = pWin->drawable.pScreen; + WindowPtr pLayerWin = pWin; + + #ifdef TEST + if (nxagentWindowTopLevel(pWin)) + { + fprintf(stderr, "UnmapWindow: pWin [%p] fromConfigure [%d]\n", pWin, + fromConfigure); + } + #endif + + if ((!pWin->mapped) || (!(pParent = pWin->parent))) + return(Success); + if (SubStrSend(pWin, pParent)) + { + event.u.u.type = UnmapNotify; + event.u.unmapNotify.window = pWin->drawable.id; + event.u.unmapNotify.fromConfigure = fromConfigure; + DeliverEvents(pWin, &event, 1, NullWindow); + } + if (wasViewable && !fromConfigure) + { + pWin->valdata = UnmapValData; + (*pScreen->MarkOverlappedWindows)(pWin, pWin->nextSib, &pLayerWin); + (*pScreen->MarkWindow)(pLayerWin->parent); + } + pWin->mapped = FALSE; + if (wasRealized) + UnrealizeTree(pWin, fromConfigure); + if (wasViewable) + { + if (!fromConfigure) + { + (*pScreen->ValidateTree)(pLayerWin->parent, pWin, VTUnmap); + (*pScreen->HandleExposures)(pLayerWin->parent); + } +#ifdef DO_SAVE_UNDERS + if (DO_SAVE_UNDERS(pWin)) + { + if ( (*pScreen->ChangeSaveUnder)(pLayerWin, pWin->nextSib) ) + { + (*pScreen->PostChangeSaveUnder)(pLayerWin, pWin->nextSib); + } + } + pWin->DIXsaveUnder = FALSE; +#endif /* DO_SAVE_UNDERS */ + if (!fromConfigure && pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pLayerWin->parent, pWin, VTUnmap); + } + if (wasRealized && !fromConfigure) + WindowsRestructured (); + return(Success); +} + +/***** + * UnmapSubwindows + * Performs an UnmapWindow request with the specified mode on all mapped + * children of the window, in bottom to top stacking order. + *****/ + +void +UnmapSubwindows(register WindowPtr pWin) +{ + register WindowPtr pChild, pHead; + xEvent event; + Bool wasRealized = (Bool)pWin->realized; + Bool wasViewable = (Bool)pWin->viewable; + Bool anyMarked = FALSE; + Mask parentNotify; + WindowPtr pLayerWin = NULL; + ScreenPtr pScreen = pWin->drawable.pScreen; + + if (!pWin->firstChild) + return; + parentNotify = SubSend(pWin); + pHead = RealChildHead(pWin); + + if (wasViewable) + pLayerWin = (*pScreen->GetLayerWindow)(pWin); + + for (pChild = pWin->lastChild; pChild != pHead; pChild = pChild->prevSib) + { + if (pChild->mapped) + { + if (parentNotify || StrSend(pChild)) + { + event.u.u.type = UnmapNotify; + event.u.unmapNotify.window = pChild->drawable.id; + event.u.unmapNotify.fromConfigure = xFalse; + DeliverEvents(pChild, &event, 1, NullWindow); + } + if (pChild->viewable) + { + pChild->valdata = UnmapValData; + anyMarked = TRUE; + } + pChild->mapped = FALSE; + if (pChild->realized) + UnrealizeTree(pChild, FALSE); + if (wasViewable) + { +#ifdef DO_SAVE_UNDERS + pChild->DIXsaveUnder = FALSE; +#endif /* DO_SAVE_UNDERS */ + if (pChild->backStorage) + (*pScreen->SaveDoomedAreas)( + pChild, &pChild->clipList, 0, 0); + } + } + } + if (wasViewable) + { + if (anyMarked) + { + if (pLayerWin->parent == pWin) + (*pScreen->MarkWindow)(pWin); + else + { + WindowPtr ptmp; + (*pScreen->MarkOverlappedWindows)(pWin, pLayerWin, + (WindowPtr *)NULL); + (*pScreen->MarkWindow)(pLayerWin->parent); + + /* Windows between pWin and pLayerWin may not have been marked */ + ptmp = pWin; + + while (ptmp != pLayerWin->parent) + { + (*pScreen->MarkWindow)(ptmp); + ptmp = ptmp->parent; + } + pHead = pWin->firstChild; + } + (*pScreen->ValidateTree)(pLayerWin->parent, pHead, VTUnmap); + (*pScreen->HandleExposures)(pLayerWin->parent); + } +#ifdef DO_SAVE_UNDERS + if (DO_SAVE_UNDERS(pWin)) + { + if ( (*pScreen->ChangeSaveUnder)(pLayerWin, pLayerWin)) + (*pScreen->PostChangeSaveUnder)(pLayerWin, pLayerWin); + } +#endif /* DO_SAVE_UNDERS */ + if (anyMarked && pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pLayerWin->parent, pHead, VTUnmap); + } + if (wasRealized) + WindowsRestructured (); +} + + +void +HandleSaveSet(register ClientPtr client) +{ + register WindowPtr pParent, pWin; + register int j; + + for (j=0; j<client->numSaved; j++) + { + pWin = SaveSetWindow(client->saveSet[j]); +#ifdef XFIXES + if (SaveSetToRoot(client->saveSet[j])) + pParent = WindowTable[pWin->drawable.pScreen->myNum]; + else +#endif + { + pParent = pWin->parent; + while (pParent && (wClient (pParent) == client)) + pParent = pParent->parent; + } + if (pParent) + { + if (pParent != pWin->parent) + { + ReparentWindow(pWin, pParent, + pWin->drawable.x - wBorderWidth (pWin) - pParent->drawable.x, + pWin->drawable.y - wBorderWidth (pWin) - pParent->drawable.y, + client); + if(!pWin->realized && pWin->mapped) + pWin->mapped = FALSE; + } +#ifdef XFIXES + if (SaveSetRemap (client->saveSet[j])) +#endif + MapWindow(pWin, client); + } + } + xfree(client->saveSet); + client->numSaved = 0; + client->saveSet = (SaveSetElt *)NULL; +} + +/** + * + * \param x,y in root + * \param box "return" value + */ +Bool +VisibleBoundingBoxFromPoint(register WindowPtr pWin, int x, int y, BoxPtr box) +{ + if (!pWin->realized) + return (FALSE); + if (POINT_IN_REGION(pWin->drawable.pScreen, &pWin->clipList, x, y, box)) + return(TRUE); + return(FALSE); +} + +/** + * + * \param x,y in root + */ +Bool +PointInWindowIsVisible(register WindowPtr pWin, int x, int y) +{ + BoxRec box; + + if (!pWin->realized) + return (FALSE); + if (POINT_IN_REGION(pWin->drawable.pScreen, &pWin->borderClip, + x, y, &box) + && (!wInputShape(pWin) || + POINT_IN_REGION(pWin->drawable.pScreen, + wInputShape(pWin), + x - pWin->drawable.x, + y - pWin->drawable.y, &box))) + return(TRUE); + return(FALSE); +} + + +RegionPtr +NotClippedByChildren(register WindowPtr pWin) +{ + register ScreenPtr pScreen; + RegionPtr pReg; + + pScreen = pWin->drawable.pScreen; + pReg = REGION_CREATE(pScreen, NullBox, 1); + if (pWin->parent || + screenIsSaved != SCREEN_SAVER_ON || + !HasSaverWindow (pWin->drawable.pScreen->myNum)) + { + REGION_INTERSECT(pScreen, pReg, &pWin->borderClip, &pWin->winSize); + } + return(pReg); +} + +void +SendVisibilityNotify(WindowPtr pWin) +{ + xEvent event; +#ifndef NO_XINERAMA_PORT + unsigned int visibility = pWin->visibility; +#endif +#ifdef PANORAMIX + /* This is not quite correct yet, but it's close */ + if(!noPanoramiXExtension) { + PanoramiXRes *win; + WindowPtr pWin2; + int i, Scrnum; + + Scrnum = pWin->drawable.pScreen->myNum; + + win = PanoramiXFindIDByScrnum(XRT_WINDOW, pWin->drawable.id, Scrnum); + + if(!win || (win->u.win.visibility == visibility)) + return; + + switch(visibility) { + case VisibilityUnobscured: + for(i = 0; i < PanoramiXNumScreens; i++) { + if(i == Scrnum) continue; + + pWin2 = (WindowPtr)LookupIDByType(win->info[i].id, RT_WINDOW); + + if (pWin2) { + if(pWin2->visibility == VisibilityPartiallyObscured) + return; + + if(!i) pWin = pWin2; + } + } + break; + case VisibilityPartiallyObscured: + if(Scrnum) { + pWin2 = (WindowPtr)LookupIDByType(win->info[0].id, RT_WINDOW); + if (pWin2) pWin = pWin2; + } + break; + case VisibilityFullyObscured: + for(i = 0; i < PanoramiXNumScreens; i++) { + if(i == Scrnum) continue; + + pWin2 = (WindowPtr)LookupIDByType(win->info[i].id, RT_WINDOW); + + if (pWin2) { + if(pWin2->visibility != VisibilityFullyObscured) + return; + + if(!i) pWin = pWin2; + } + } + break; + } + + win->u.win.visibility = visibility; + } +#endif + + event.u.u.type = VisibilityNotify; + event.u.visibility.window = pWin->drawable.id; + event.u.visibility.state = visibility; + DeliverEvents(pWin, &event, 1, NullWindow); +} + + +#define RANDOM_WIDTH 32 + +#ifndef NOLOGOHACK +static void DrawLogo( + WindowPtr pWin +); +#endif + +void +SaveScreens(int on, int mode) +{ + int i; + int what; + int type; + + if (on == SCREEN_SAVER_FORCER) + { + UpdateCurrentTimeIf(); + lastDeviceEventTime = currentTime; + if (mode == ScreenSaverReset) + what = SCREEN_SAVER_OFF; + else + what = SCREEN_SAVER_ON; + type = what; + } + else + { + what = on; + type = what; + if (what == screenIsSaved) + type = SCREEN_SAVER_CYCLE; + } + for (i = 0; i < screenInfo.numScreens; i++) + { + if (on == SCREEN_SAVER_FORCER) + (* screenInfo.screens[i]->SaveScreen) (screenInfo.screens[i], on); + if (savedScreenInfo[i].ExternalScreenSaver) + { + if (nxagentOption(Timeout) != 0) + { + #ifdef TEST + fprintf(stderr, "SaveScreens: An external screen-saver handler is installed. " + "Ignoring it to let the auto-disconnect feature work.\n"); + #endif + } + else + { + if ((*savedScreenInfo[i].ExternalScreenSaver) + (screenInfo.screens[i], type, on == SCREEN_SAVER_FORCER)) + continue; + } + } + if (type == screenIsSaved) + continue; + switch (type) { + case SCREEN_SAVER_OFF: + if (savedScreenInfo[i].blanked == SCREEN_IS_BLANKED) + { + (* screenInfo.screens[i]->SaveScreen) (screenInfo.screens[i], + what); + } + else if (HasSaverWindow (i)) + { + savedScreenInfo[i].pWindow = NullWindow; + FreeResource(savedScreenInfo[i].wid, RT_NONE); + } + break; + case SCREEN_SAVER_CYCLE: + if (savedScreenInfo[i].blanked == SCREEN_IS_TILED) + { + WindowPtr pWin = savedScreenInfo[i].pWindow; + /* make it look like screen saver is off, so that + * NotClippedByChildren will compute a clip list + * for the root window, so miPaintWindow works + */ + screenIsSaved = SCREEN_SAVER_OFF; +#ifndef NOLOGOHACK + if (logoScreenSaver) + (*pWin->drawable.pScreen->ClearToBackground)(pWin, 0, 0, 0, 0, FALSE); +#endif + (*pWin->drawable.pScreen->MoveWindow)(pWin, + (short)(-(rand() % RANDOM_WIDTH)), + (short)(-(rand() % RANDOM_WIDTH)), + pWin->nextSib, VTMove); +#ifndef NOLOGOHACK + if (logoScreenSaver) + DrawLogo(pWin); +#endif + screenIsSaved = SCREEN_SAVER_ON; + } + /* + * Call the DDX saver in case it wants to do something + * at cycle time + */ + else if (savedScreenInfo[i].blanked == SCREEN_IS_BLANKED) + { + (* screenInfo.screens[i]->SaveScreen) (screenInfo.screens[i], + type); + } + break; + case SCREEN_SAVER_ON: + if (ScreenSaverBlanking != DontPreferBlanking) + { + if ((* screenInfo.screens[i]->SaveScreen) + (screenInfo.screens[i], what)) + { + savedScreenInfo[i].blanked = SCREEN_IS_BLANKED; + continue; + } + if ((ScreenSaverAllowExposures != DontAllowExposures) && + TileScreenSaver(i, SCREEN_IS_BLACK)) + { + savedScreenInfo[i].blanked = SCREEN_IS_BLACK; + continue; + } + } + if ((ScreenSaverAllowExposures != DontAllowExposures) && + TileScreenSaver(i, SCREEN_IS_TILED)) + { + savedScreenInfo[i].blanked = SCREEN_IS_TILED; + } + else + savedScreenInfo[i].blanked = SCREEN_ISNT_SAVED; + break; + } + } + screenIsSaved = what; + if (mode == ScreenSaverReset) + SetScreenSaverTimer(); +} + +static Bool +TileScreenSaver(int i, int kind) +{ + int j; + int result; + XID attributes[3]; + Mask mask; + WindowPtr pWin; + CursorMetricRec cm; + unsigned char *srcbits, *mskbits; + CursorPtr cursor; + XID cursorID = 0; + int attri; + + mask = 0; + attri = 0; + switch (kind) { + case SCREEN_IS_TILED: + switch (WindowTable[i]->backgroundState) { + case BackgroundPixel: + attributes[attri++] = WindowTable[i]->background.pixel; + mask |= CWBackPixel; + break; + case BackgroundPixmap: + attributes[attri++] = None; + mask |= CWBackPixmap; + break; + default: + break; + } + break; + case SCREEN_IS_BLACK: + attributes[attri++] = WindowTable[i]->drawable.pScreen->blackPixel; + mask |= CWBackPixel; + break; + } + mask |= CWOverrideRedirect; + attributes[attri++] = xTrue; + + /* + * create a blank cursor + */ + + cm.width=16; + cm.height=16; + cm.xhot=8; + cm.yhot=8; + srcbits = (unsigned char *)xalloc( BitmapBytePad(32)*16); + mskbits = (unsigned char *)xalloc( BitmapBytePad(32)*16); + if (!srcbits || !mskbits) + { + xfree(srcbits); + xfree(mskbits); + cursor = 0; + } + else + { + for (j=0; j<BitmapBytePad(32)*16; j++) + srcbits[j] = mskbits[j] = 0x0; + cursor = AllocCursor(srcbits, mskbits, &cm, 0, 0, 0, 0, 0, 0); + if (cursor) + { + cursorID = FakeClientID(0); + if (AddResource (cursorID, RT_CURSOR, (pointer) cursor)) + { + attributes[attri] = cursorID; + mask |= CWCursor; + } + else + cursor = 0; + } + else + { + xfree (srcbits); + xfree (mskbits); + } + } + + pWin = savedScreenInfo[i].pWindow = + CreateWindow(savedScreenInfo[i].wid, + WindowTable[i], + -RANDOM_WIDTH, -RANDOM_WIDTH, + (unsigned short)screenInfo.screens[i]->width + RANDOM_WIDTH, + (unsigned short)screenInfo.screens[i]->height + RANDOM_WIDTH, + 0, InputOutput, mask, attributes, 0, serverClient, + wVisual (WindowTable[i]), &result); + + if (cursor) + FreeResource (cursorID, RT_NONE); + + if (!pWin) + return FALSE; + + if (!AddResource(pWin->drawable.id, RT_WINDOW, + (pointer)savedScreenInfo[i].pWindow)) + return FALSE; + + if (mask & CWBackPixmap) + { + MakeRootTile (pWin); + (*pWin->drawable.pScreen->ChangeWindowAttributes)(pWin, CWBackPixmap); + } + MapWindow(pWin, serverClient); +#ifndef NOLOGOHACK + if (kind == SCREEN_IS_TILED && logoScreenSaver) + DrawLogo(pWin); +#endif + return TRUE; +} + +/* + * FindWindowWithOptional + * + * search ancestors of the given window for an entry containing + * a WindowOpt structure. Assumptions: some parent will + * contain the structure. + */ + +WindowPtr +FindWindowWithOptional (register WindowPtr w) +{ + do + w = w->parent; + while (!w->optional); + return w; +} + +/* + * CheckWindowOptionalNeed + * + * check each optional entry in the given window to see if + * the value is satisfied by the default rules. If so, + * release the optional record + */ + +void +CheckWindowOptionalNeed (register WindowPtr w) +{ + register WindowOptPtr optional; + register WindowOptPtr parentOptional; + + if (!w->parent) + return; + optional = w->optional; + if (optional->dontPropagateMask != DontPropagateMasks[w->dontPropagate]) + return; + if (optional->otherEventMasks != 0) + return; + if (optional->otherClients != NULL) + return; + if (optional->passiveGrabs != NULL) + return; + if (optional->userProps != NULL) + return; + if (optional->backingBitPlanes != ~0L) + return; + if (optional->backingPixel != 0) + return; +#ifdef SHAPE + if (optional->boundingShape != NULL) + return; + if (optional->clipShape != NULL) + return; + if (optional->inputShape != NULL) + return; +#endif +#ifdef XINPUT + if (optional->inputMasks != NULL) + return; +#endif + parentOptional = FindWindowWithOptional(w)->optional; + if (optional->visual != parentOptional->visual) + return; + if (optional->cursor != None && + (optional->cursor != parentOptional->cursor || + w->parent->cursorIsNone)) + return; + if (optional->colormap != parentOptional->colormap) + return; + DisposeWindowOptional (w); +} + +/* + * MakeWindowOptional + * + * create an optional record and initialize it with the default + * values. + */ + +Bool +MakeWindowOptional (register WindowPtr pWin) +{ + register WindowOptPtr optional; + register WindowOptPtr parentOptional; + + if (pWin->optional) + return TRUE; + optional = (WindowOptPtr) xalloc (sizeof (WindowOptRec)); + if (!optional) + return FALSE; + optional->dontPropagateMask = DontPropagateMasks[pWin->dontPropagate]; + optional->otherEventMasks = 0; + optional->otherClients = NULL; + optional->passiveGrabs = NULL; + optional->userProps = NULL; + optional->backingBitPlanes = ~0L; + optional->backingPixel = 0; +#ifdef SHAPE + optional->boundingShape = NULL; + optional->clipShape = NULL; + optional->inputShape = NULL; +#endif +#ifdef XINPUT + optional->inputMasks = NULL; +#endif + parentOptional = FindWindowWithOptional(pWin)->optional; + optional->visual = parentOptional->visual; + if (!pWin->cursorIsNone) + { + optional->cursor = parentOptional->cursor; + optional->cursor->refcnt++; + } + else + { + optional->cursor = None; + } + optional->colormap = parentOptional->colormap; + pWin->optional = optional; + return TRUE; +} + +void +DisposeWindowOptional (register WindowPtr pWin) +{ + if (!pWin->optional) + return; + /* + * everything is peachy. Delete the optional record + * and clean up + */ + /* + * TOG changed this code to: + * + * if (pWin->cursorIsNone == FALSE) + * FreeCursor (pWin->optional->cursor, (Cursor)0); + * pWin->cursorIsNone = TRUE; + * + * This is blatently wrong; windows without optionals can have + * two different cursor values, either None or sharing their + * parents cursor. This difference is controlled by the + * cursorIsNone value; when TRUE, the window has no cursor, + * when false, it shares its cursor with its parent; TOG + * made it impossible for a window to have a cursor without + * an optional record. + */ + if (pWin->optional->cursor) + { + FreeCursor (pWin->optional->cursor, (Cursor)0); + pWin->cursorIsNone = FALSE; + } + else + pWin->cursorIsNone = TRUE; +/* FIXME + There is an error when disposing ClientResources on Agent exit + this xfree is not valid in some window at exit +*/ + + xfree (pWin->optional); + pWin->optional = NULL; +} + +#ifndef NOLOGOHACK +static void +DrawLogo(WindowPtr pWin) +{ + DrawablePtr pDraw; + ScreenPtr pScreen; + int x, y; + unsigned int width, height, size; + GC *pGC; + int thin, gap, d31; + DDXPointRec poly[4]; + ChangeGCVal fore[2], back[2]; + xrgb rgb[2]; + BITS32 fmask, bmask; + ColormapPtr cmap; + + pDraw = (DrawablePtr)pWin; + pScreen = pDraw->pScreen; + x = -pWin->origin.x; + y = -pWin->origin.y; + width = pScreen->width; + height = pScreen->height; + pGC = GetScratchGC(pScreen->rootDepth, pScreen); + if (!pGC) + return; + + if ((rand() % 100) <= 17) /* make the probability for white fairly low */ + fore[0].val = pScreen->whitePixel; + else + fore[0].val = pScreen->blackPixel; + if ((pWin->backgroundState == BackgroundPixel) && + (cmap = (ColormapPtr)LookupIDByType(wColormap (pWin), RT_COLORMAP))) { + Pixel querypixels[2]; + + querypixels[0] = fore[0].val; + querypixels[1] = pWin->background.pixel; + QueryColors(cmap, 2, querypixels, rgb); + if ((rgb[0].red == rgb[1].red) && + (rgb[0].green == rgb[1].green) && + (rgb[0].blue == rgb[1].blue)) { + if (fore[0].val == pScreen->blackPixel) + fore[0].val = pScreen->whitePixel; + else + fore[0].val = pScreen->blackPixel; + } + } + fore[1].val = FillSolid; + fmask = GCForeground|GCFillStyle; + if (pWin->backgroundState == BackgroundPixel) { + back[0].val = pWin->background.pixel; + back[1].val = FillSolid; + bmask = GCForeground|GCFillStyle; + } else { + back[0].val = 0; + back[1].val = 0; + dixChangeGC(NullClient, pGC, GCTileStipXOrigin|GCTileStipYOrigin, + NULL, back); + back[0].val = FillTiled; + back[1].ptr = pWin->background.pixmap; + bmask = GCFillStyle|GCTile; + } + + /* should be the same as the reference function XmuDrawLogo() */ + + size = width; + if (height < width) + size = height; + size = RANDOM_WIDTH + rand() % (size - RANDOM_WIDTH); + size &= ~1; + x += rand() % (width - size); + y += rand() % (height - size); + +/* + * Draw what will be the thin strokes. + * + * ----- + * / / + * / / + * / / + * / / + * /____/ + * d + * + * Point d is 9/44 (~1/5) of the way across. + */ + + thin = (size / 11); + if (thin < 1) thin = 1; + gap = (thin+3) / 4; + d31 = thin + thin + gap; + poly[0].x = x + size; poly[0].y = y; + poly[1].x = x + size-d31; poly[1].y = y; + poly[2].x = x + 0; poly[2].y = y + size; + poly[3].x = x + d31; poly[3].y = y + size; + dixChangeGC(NullClient, pGC, fmask, NULL, fore); + ValidateGC(pDraw, pGC); + (*pGC->ops->FillPolygon)(pDraw, pGC, Convex, CoordModeOrigin, 4, poly); + +/* + * Erase area not needed for lower thin stroke. + * + * ------ + * / / + * / __ / + * / / / + * / / / + * /__/__/ + */ + + poly[0].x = x + d31/2; poly[0].y = y + size; + poly[1].x = x + size / 2; poly[1].y = y + size/2; + poly[2].x = x + (size/2)+(d31-(d31/2)); poly[2].y = y + size/2; + poly[3].x = x + d31; poly[3].y = y + size; + dixChangeGC(NullClient, pGC, bmask, NULL, back); + ValidateGC(pDraw, pGC); + (*pGC->ops->FillPolygon)(pDraw, pGC, Convex, CoordModeOrigin, 4, poly); + +/* + * Erase area not needed for upper thin stroke. + * + * ------ + * / / / + * /--/ / + * / / + * / / + * /_____/ + */ + + poly[0].x = x + size - d31/2; poly[0].y = y; + poly[1].x = x + size / 2; poly[1].y = y + size/2; + poly[2].x = x + (size/2)-(d31-(d31/2)); poly[2].y = y + size/2; + poly[3].x = x + size - d31; poly[3].y = y; + ValidateGC(pDraw, pGC); + (*pGC->ops->FillPolygon)(pDraw, pGC, Convex, CoordModeOrigin, 4, poly); + +/* + * Draw thick stroke. + * Point b is 1/4 of the way across. + * + * b + * ----- + * \ \ + * \ \ + * \ \ + * \ \ + * \____\ + */ + + poly[0].x = x; poly[0].y = y; + poly[1].x = x + size/4; poly[1].y = y; + poly[2].x = x + size; poly[2].y = y + size; + poly[3].x = x + size - size/4; poly[3].y = y + size; + dixChangeGC(NullClient, pGC, fmask, NULL, fore); + ValidateGC(pDraw, pGC); + (*pGC->ops->FillPolygon)(pDraw, pGC, Convex, CoordModeOrigin, 4, poly); + +/* + * Erase to create gap. + * + * / + * / + * / + * / + * / + */ + + poly[0].x = x + size- thin; poly[0].y = y; + poly[1].x = x + size-( thin+gap); poly[1].y = y; + poly[2].x = x + thin; poly[2].y = y + size; + poly[3].x = x + thin + gap; poly[3].y = y + size; + dixChangeGC(NullClient, pGC, bmask, NULL, back); + ValidateGC(pDraw, pGC); + (*pGC->ops->FillPolygon)(pDraw, pGC, Convex, CoordModeOrigin, 4, poly); + + FreeScratchGC(pGC); +} + +#endif + |