3661 lines
113 KiB
C
3661 lines
113 KiB
C
/*
|
|
|
|
Copyright (c) 2006, Red Hat, Inc.
|
|
|
|
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, and to permit persons to whom the
|
|
Software is furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice (including the next
|
|
paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
|
|
|
|
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.
|
|
|
|
******************************************************************/
|
|
|
|
#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 "propertyst.h"
|
|
#include "input.h"
|
|
#include "inputstr.h"
|
|
#include "resource.h"
|
|
#include "colormapst.h"
|
|
#include "cursorstr.h"
|
|
#include "dixstruct.h"
|
|
#include "gcstruct.h"
|
|
#include "servermd.h"
|
|
#include "mivalidate.h"
|
|
#ifdef PANORAMIX
|
|
#include "panoramiX.h"
|
|
#include "panoramiXsrv.h"
|
|
#endif
|
|
#include "dixevents.h"
|
|
#include "globals.h"
|
|
#include "mi.h" /* miPaintWindow */
|
|
#ifdef COMPOSITE
|
|
#include "compint.h"
|
|
#endif
|
|
|
|
#include "privates.h"
|
|
#include "xace.h"
|
|
#include "exevents.h"
|
|
|
|
#include <X11/Xatom.h> /* must come after server includes */
|
|
|
|
/******
|
|
* Window stuff for server
|
|
*
|
|
* CreateRootWindow, CreateWindow, ChangeWindowAttributes,
|
|
* GetWindowAttributes, DeleteWindow, DestroySubWindows,
|
|
* HandleSaveSet, ReparentWindow, MapWindow, MapSubWindows,
|
|
* UnmapWindow, UnmapSubWindows, ConfigureWindow, CirculateWindow,
|
|
* ChangeWindowDeviceCursor
|
|
******/
|
|
|
|
Bool bgNoneRoot = FALSE;
|
|
|
|
static unsigned char _back_lsb[4] = { 0x88, 0x22, 0x44, 0x11 };
|
|
static unsigned char _back_msb[4] = { 0x11, 0x44, 0x22, 0x88 };
|
|
|
|
static Bool WindowParentHasDeviceCursor(WindowPtr pWin,
|
|
DeviceIntPtr pDev, CursorPtr pCurs);
|
|
static Bool
|
|
|
|
WindowSeekDeviceCursor(WindowPtr pWin,
|
|
DeviceIntPtr pDev,
|
|
DevCursNodePtr * pNode, DevCursNodePtr * pPrev);
|
|
|
|
int screenIsSaved = SCREEN_SAVER_OFF;
|
|
|
|
static Bool TileScreenSaver(ScreenPtr pScreen, 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))
|
|
|
|
#ifdef COMPOSITE
|
|
static const char *overlay_win_name = "<composite overlay>";
|
|
#endif
|
|
|
|
static const char *
|
|
get_window_name(WindowPtr pWin)
|
|
{
|
|
#define WINDOW_NAME_BUF_LEN 512
|
|
PropertyPtr prop;
|
|
static char buf[WINDOW_NAME_BUF_LEN];
|
|
int len;
|
|
|
|
#ifdef COMPOSITE
|
|
CompScreenPtr comp_screen = GetCompScreen(pWin->drawable.pScreen);
|
|
|
|
if (comp_screen && pWin == comp_screen->pOverlayWin)
|
|
return overlay_win_name;
|
|
#endif
|
|
|
|
for (prop = wUserProps(pWin); prop; prop = prop->next) {
|
|
if (prop->propertyName == XA_WM_NAME && prop->type == XA_STRING &&
|
|
prop->data) {
|
|
len = min(prop->size, WINDOW_NAME_BUF_LEN - 1);
|
|
memcpy(buf, prop->data, len);
|
|
buf[len] = '\0';
|
|
return buf;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
#undef WINDOW_NAME_BUF_LEN
|
|
}
|
|
|
|
static void
|
|
log_window_info(WindowPtr pWin, int depth)
|
|
{
|
|
int i;
|
|
const char *win_name, *visibility;
|
|
BoxPtr rects;
|
|
ScreenPtr pScreen = pWin->drawable.pScreen;
|
|
|
|
for (i = 0; i < (depth << 2); i++)
|
|
ErrorF(" ");
|
|
|
|
win_name = get_window_name(pWin);
|
|
ErrorF("win 0x%.8x (%s), [%d, %d] to [%d, %d]",
|
|
pWin->drawable.id,
|
|
win_name ? win_name : "no name",
|
|
pWin->drawable.x, pWin->drawable.y,
|
|
pWin->drawable.x + pWin->drawable.width,
|
|
pWin->drawable.y + pWin->drawable.height);
|
|
|
|
if (pWin->overrideRedirect)
|
|
ErrorF(" (override redirect)");
|
|
#ifdef COMPOSITE
|
|
if (pWin->redirectDraw)
|
|
ErrorF(" (%s compositing: pixmap %x)",
|
|
(pWin->redirectDraw == RedirectDrawAutomatic) ?
|
|
"automatic" : "manual",
|
|
pScreen->GetWindowPixmap(pWin)->drawable.id);
|
|
#endif
|
|
|
|
switch (pWin->visibility) {
|
|
case VisibilityUnobscured:
|
|
visibility = "unobscured";
|
|
break;
|
|
case VisibilityPartiallyObscured:
|
|
visibility = "partially obscured";
|
|
break;
|
|
case VisibilityFullyObscured:
|
|
visibility = "fully obscured";
|
|
break;
|
|
case VisibilityNotViewable:
|
|
visibility = "unviewable";
|
|
break;
|
|
}
|
|
ErrorF(", %s", visibility);
|
|
|
|
if (REGION_NOTEMPTY(pScreen, &pWin->clipList)) {
|
|
ErrorF(", clip list:");
|
|
rects = REGION_RECTS(&pWin->clipList);
|
|
for (i = 0; i < REGION_NUM_RECTS(&pWin->clipList); i++)
|
|
ErrorF(" [(%d, %d) to (%d, %d)]",
|
|
rects[i].x1, rects[i].y1, rects[i].x2, rects[i].y2);
|
|
ErrorF("; extents [(%d, %d) to (%d, %d)]",
|
|
pWin->clipList.extents.x1, pWin->clipList.extents.y1,
|
|
pWin->clipList.extents.x2, pWin->clipList.extents.y2);
|
|
}
|
|
|
|
ErrorF("\n");
|
|
}
|
|
|
|
void
|
|
PrintWindowTree(void)
|
|
{
|
|
int scrnum, depth;
|
|
ScreenPtr pScreen;
|
|
WindowPtr pWin;
|
|
|
|
for (scrnum = 0; scrnum < screenInfo.numScreens; scrnum++) {
|
|
pScreen = screenInfo.screens[scrnum];
|
|
ErrorF("[dix] Dumping windows for screen %d (pixmap %x):\n", scrnum,
|
|
pScreen->GetScreenPixmap(pScreen)->drawable.id);
|
|
pWin = pScreen->root;
|
|
depth = 1;
|
|
while (pWin) {
|
|
log_window_info(pWin, depth);
|
|
if (pWin->firstChild) {
|
|
pWin = pWin->firstChild;
|
|
depth++;
|
|
continue;
|
|
}
|
|
while (pWin && !pWin->nextSib) {
|
|
pWin = pWin->parent;
|
|
depth--;
|
|
}
|
|
if (!pWin)
|
|
break;
|
|
pWin = pWin->nextSib;
|
|
}
|
|
}
|
|
}
|
|
|
|
int
|
|
TraverseTree(WindowPtr pWin, VisitWindowProcPtr func, pointer data)
|
|
{
|
|
int result;
|
|
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(pScreen->root, 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;
|
|
|
|
static void
|
|
SetWindowToDefaults(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;
|
|
pWin->redirectDraw = RedirectDrawNone;
|
|
pWin->forcedBG = FALSE;
|
|
|
|
#ifdef ROOTLESS
|
|
pWin->rootlessUnhittable = FALSE;
|
|
#endif
|
|
|
|
#ifdef COMPOSITE
|
|
pWin->damagedDescendants = FALSE;
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
MakeRootTile(WindowPtr pWin)
|
|
{
|
|
ScreenPtr pScreen = pWin->drawable.pScreen;
|
|
GCPtr pGC;
|
|
unsigned char back[128];
|
|
int len = BitmapBytePad(sizeof(long));
|
|
unsigned char *from, *to;
|
|
int i, j;
|
|
|
|
pWin->background.pixmap = (*pScreen->CreatePixmap) (pScreen, 4, 4,
|
|
pScreen->rootDepth, 0);
|
|
|
|
pWin->backgroundState = BackgroundPixmap;
|
|
pGC = GetScratchGC(pScreen->rootDepth, pScreen);
|
|
if (!pWin->background.pixmap || !pGC)
|
|
FatalError("could not create root tile");
|
|
|
|
{
|
|
ChangeGCVal attributes[2];
|
|
|
|
attributes[0].val = pScreen->whitePixel;
|
|
attributes[1].val = pScreen->blackPixel;
|
|
|
|
(void) ChangeGC(NullClient, 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;
|
|
|
|
(*pGC->ops->PutImage) ((DrawablePtr) pWin->background.pixmap, pGC, 1,
|
|
0, 0, len, 4, 0, XYBitmap, (char *) back);
|
|
|
|
FreeScratchGC(pGC);
|
|
|
|
}
|
|
|
|
/*****
|
|
* CreateRootWindow
|
|
* Makes a window at initialization time for specified screen
|
|
*****/
|
|
|
|
Bool
|
|
CreateRootWindow(ScreenPtr pScreen)
|
|
{
|
|
WindowPtr pWin;
|
|
BoxRec box;
|
|
PixmapFormatRec *format;
|
|
|
|
pWin = dixAllocateObjectWithPrivates(WindowRec, PRIVATE_WINDOW);
|
|
if (!pWin)
|
|
return FALSE;
|
|
|
|
pScreen->screensaver.pWindow = NULL;
|
|
pScreen->screensaver.wid = FakeClientID(0);
|
|
pScreen->screensaver.ExternalScreenSaver = NULL;
|
|
screenIsSaved = SCREEN_SAVER_OFF;
|
|
|
|
pScreen->root = 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 = malloc(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;
|
|
pWin->optional->boundingShape = NULL;
|
|
pWin->optional->clipShape = NULL;
|
|
pWin->optional->inputShape = NULL;
|
|
pWin->optional->inputMasks = NULL;
|
|
pWin->optional->deviceCursors = NULL;
|
|
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;
|
|
RegionInit(&pWin->clipList, &box, 1);
|
|
RegionInit(&pWin->winSize, &box, 1);
|
|
RegionInit(&pWin->borderSize, &box, 1);
|
|
RegionInit(&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;
|
|
|
|
/* security creation/labeling check
|
|
*/
|
|
if (XaceHook(XACE_RESOURCE_ACCESS, serverClient, pWin->drawable.id,
|
|
RT_WINDOW, pWin, RT_NONE, NULL, DixCreateAccess))
|
|
return FALSE;
|
|
|
|
if (!AddResource(pWin->drawable.id, RT_WINDOW, (pointer) pWin))
|
|
return FALSE;
|
|
|
|
if (disableBackingStore)
|
|
pScreen->backingStoreSupport = NotUseful;
|
|
if (enableBackingStore)
|
|
pScreen->backingStoreSupport = Always;
|
|
|
|
pScreen->saveUnderSupport = NotUseful;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
InitRootWindow(WindowPtr pWin)
|
|
{
|
|
ScreenPtr pScreen = pWin->drawable.pScreen;
|
|
int backFlag = CWBorderPixel | CWCursor | CWBackingStore;
|
|
|
|
if (!(*pScreen->CreateWindow) (pWin))
|
|
return; /* XXX */
|
|
(*pScreen->PositionWindow) (pWin, 0, 0);
|
|
|
|
pWin->cursorIsNone = FALSE;
|
|
pWin->optional->cursor = rootCursor;
|
|
rootCursor->refcnt++;
|
|
|
|
if (party_like_its_1989) {
|
|
MakeRootTile(pWin);
|
|
backFlag |= CWBackPixmap;
|
|
}
|
|
else if (pScreen->canDoBGNoneRoot && bgNoneRoot) {
|
|
pWin->backgroundState = XaceBackgroundNoneState(pWin);
|
|
pWin->background.pixel = pScreen->whitePixel;
|
|
backFlag |= CWBackPixmap;
|
|
}
|
|
else {
|
|
pWin->backgroundState = BackgroundPixel;
|
|
if (whiteRoot)
|
|
pWin->background.pixel = pScreen->whitePixel;
|
|
else
|
|
pWin->background.pixel = pScreen->blackPixel;
|
|
backFlag |= CWBackPixel;
|
|
}
|
|
|
|
pWin->backingStore = defaultBackingStore;
|
|
pWin->forcedBS = (defaultBackingStore != NotUseful);
|
|
/* We SHOULD check for an error value here XXX */
|
|
(*pScreen->ChangeWindowAttributes) (pWin, backFlag);
|
|
|
|
MapWindow(pWin, serverClient);
|
|
}
|
|
|
|
/* 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.
|
|
*/
|
|
|
|
static void
|
|
ClippedRegionFromBox(WindowPtr pWin, RegionPtr Rgn, int x, int y, int w, int h)
|
|
{
|
|
BoxRec box = *RegionExtents(&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;
|
|
RegionReset(Rgn, &box);
|
|
RegionIntersect(Rgn, Rgn, &pWin->winSize);
|
|
}
|
|
|
|
static RealChildHeadProc realChildHeadProc = NULL;
|
|
|
|
void
|
|
RegisterRealChildHeadProc(RealChildHeadProc proc)
|
|
{
|
|
realChildHeadProc = proc;
|
|
}
|
|
|
|
WindowPtr
|
|
RealChildHead(WindowPtr pWin)
|
|
{
|
|
if (realChildHeadProc) {
|
|
return realChildHeadProc(pWin);
|
|
}
|
|
|
|
if (!pWin->parent &&
|
|
(screenIsSaved == SCREEN_SAVER_ON) &&
|
|
(HasSaverWindow(pWin->drawable.pScreen)))
|
|
return pWin->firstChild;
|
|
else
|
|
return NullWindow;
|
|
}
|
|
|
|
/*****
|
|
* CreateWindow
|
|
* Makes a window in response to client request
|
|
*****/
|
|
|
|
WindowPtr
|
|
CreateWindow(Window wid, WindowPtr pParent, int x, int y, unsigned w,
|
|
unsigned h, unsigned bw, unsigned class, Mask vmask, XID *vlist,
|
|
int depth, ClientPtr client, VisualID visual, int *error)
|
|
{
|
|
WindowPtr pWin;
|
|
WindowPtr pHead;
|
|
ScreenPtr pScreen;
|
|
xEvent event;
|
|
int idepth, ivisual;
|
|
Bool fOK;
|
|
DepthPtr pDepth;
|
|
PixmapFormatRec *format;
|
|
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) {
|
|
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 = dixAllocateObjectWithPrivates(WindowRec, PRIVATE_WINDOW);
|
|
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)) {
|
|
dixFreeObjectWithPrivates(pWin, PRIVATE_WINDOW);
|
|
*error = BadAlloc;
|
|
return NullWindow;
|
|
}
|
|
pWin->optional->visual = visual;
|
|
pWin->optional->colormap = None;
|
|
}
|
|
|
|
pWin->borderWidth = bw;
|
|
|
|
/* security creation/labeling check
|
|
*/
|
|
*error = XaceHook(XACE_RESOURCE_ACCESS, client, wid, RT_WINDOW, pWin,
|
|
RT_WINDOW, pWin->parent,
|
|
DixCreateAccess | DixSetAttrAccess);
|
|
if (*error != Success) {
|
|
dixFreeObjectWithPrivates(pWin, PRIVATE_WINDOW);
|
|
return NullWindow;
|
|
}
|
|
|
|
pWin->backgroundState = XaceBackgroundNoneState(pWin);
|
|
pWin->background.pixel = pScreen->whitePixel;
|
|
|
|
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 */
|
|
RegionNull(&pWin->clipList);
|
|
RegionNull(&pWin->borderClip);
|
|
RegionNull(&pWin->winSize);
|
|
RegionNull(&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)) {
|
|
memset(&event, 0, sizeof(xEvent));
|
|
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
|
|
DisposeWindowOptional(WindowPtr pWin)
|
|
{
|
|
if (!pWin->optional)
|
|
return;
|
|
/*
|
|
* everything is peachy. Delete the optional record
|
|
* and clean up
|
|
*/
|
|
if (pWin->optional->cursor) {
|
|
FreeCursor(pWin->optional->cursor, (Cursor) 0);
|
|
pWin->cursorIsNone = FALSE;
|
|
}
|
|
else
|
|
pWin->cursorIsNone = TRUE;
|
|
|
|
if (pWin->optional->deviceCursors) {
|
|
DevCursorList pList;
|
|
DevCursorList pPrev;
|
|
|
|
pList = pWin->optional->deviceCursors;
|
|
while (pList) {
|
|
if (pList->cursor)
|
|
FreeCursor(pList->cursor, (XID) 0);
|
|
pPrev = pList;
|
|
pList = pList->next;
|
|
free(pPrev);
|
|
}
|
|
pWin->optional->deviceCursors = NULL;
|
|
}
|
|
|
|
free(pWin->optional);
|
|
pWin->optional = NULL;
|
|
}
|
|
|
|
static void
|
|
FreeWindowResources(WindowPtr pWin)
|
|
{
|
|
ScreenPtr pScreen = pWin->drawable.pScreen;
|
|
|
|
DeleteWindowFromAnySaveSet(pWin);
|
|
DeleteWindowFromAnySelections(pWin);
|
|
DeleteWindowFromAnyEvents(pWin, TRUE);
|
|
RegionUninit(&pWin->clipList);
|
|
RegionUninit(&pWin->winSize);
|
|
RegionUninit(&pWin->borderClip);
|
|
RegionUninit(&pWin->borderSize);
|
|
if (wBoundingShape(pWin))
|
|
RegionDestroy(wBoundingShape(pWin));
|
|
if (wClipShape(pWin))
|
|
RegionDestroy(wClipShape(pWin));
|
|
if (wInputShape(pWin))
|
|
RegionDestroy(wInputShape(pWin));
|
|
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)
|
|
{
|
|
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)) {
|
|
memset(&event, 0, sizeof(xEvent));
|
|
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;
|
|
pChild->viewable = FALSE;
|
|
if (pChild->realized) {
|
|
pChild->realized = FALSE;
|
|
(*UnrealizeWindow) (pChild);
|
|
}
|
|
FreeWindowResources(pChild);
|
|
dixFreeObjectWithPrivates(pChild, PRIVATE_WINDOW);
|
|
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)
|
|
{
|
|
WindowPtr pParent;
|
|
WindowPtr pWin = (WindowPtr) value;
|
|
xEvent event;
|
|
|
|
UnmapWindow(pWin, FALSE);
|
|
|
|
CrushTree(pWin);
|
|
|
|
pParent = pWin->parent;
|
|
if (wid && pParent && SubStrSend(pWin, pParent)) {
|
|
memset(&event, 0, sizeof(xEvent));
|
|
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;
|
|
}
|
|
else
|
|
pWin->drawable.pScreen->root = NULL;
|
|
dixFreeObjectWithPrivates(pWin, PRIVATE_WINDOW);
|
|
return Success;
|
|
}
|
|
|
|
int
|
|
DestroySubwindows(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) {
|
|
int rc = XaceHook(XACE_RESOURCE_ACCESS, client,
|
|
pWin->lastChild->drawable.id, RT_WINDOW,
|
|
pWin->lastChild, RT_NONE, NULL, DixDestroyAccess);
|
|
|
|
if (rc != Success)
|
|
return rc;
|
|
FreeResource(pWin->lastChild->drawable.id, RT_NONE);
|
|
}
|
|
return Success;
|
|
}
|
|
|
|
static void
|
|
SetRootWindowBackground(WindowPtr pWin, ScreenPtr pScreen, Mask *index2)
|
|
{
|
|
/* following the protocol: "Changing the background of a root window to
|
|
* None or ParentRelative restores the default background pixmap" */
|
|
if (bgNoneRoot) {
|
|
pWin->backgroundState = XaceBackgroundNoneState(pWin);
|
|
pWin->background.pixel = pScreen->whitePixel;
|
|
}
|
|
else if (party_like_its_1989)
|
|
MakeRootTile(pWin);
|
|
else {
|
|
pWin->backgroundState = BackgroundPixel;
|
|
if (whiteRoot)
|
|
pWin->background.pixel = pScreen->whitePixel;
|
|
else
|
|
pWin->background.pixel = pScreen->blackPixel;
|
|
*index2 = CWBackPixel;
|
|
}
|
|
}
|
|
|
|
/*****
|
|
* 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(WindowPtr pWin, Mask vmask, XID *vlist, ClientPtr client)
|
|
{
|
|
XID *pVlist;
|
|
PixmapPtr pPixmap;
|
|
Pixmap pixID;
|
|
CursorPtr pCursor, pOldCursor;
|
|
Cursor cursorID;
|
|
WindowPtr pChild;
|
|
Colormap cmap;
|
|
ColormapPtr pCmap;
|
|
xEvent xE;
|
|
int error, rc;
|
|
ScreenPtr pScreen;
|
|
Mask index2, tmask, vmaskCopy = 0;
|
|
unsigned int val;
|
|
Bool checkOptional = FALSE, borderRelative = FALSE;
|
|
|
|
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) {
|
|
if (pWin->backgroundState == BackgroundPixmap)
|
|
(*pScreen->DestroyPixmap) (pWin->background.pixmap);
|
|
if (!pWin->parent)
|
|
SetRootWindowBackground(pWin, pScreen, &index2);
|
|
else {
|
|
pWin->backgroundState = XaceBackgroundNoneState(pWin);
|
|
pWin->background.pixel = pScreen->whitePixel;
|
|
}
|
|
}
|
|
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)
|
|
SetRootWindowBackground(pWin, pScreen, &index2);
|
|
else
|
|
pWin->backgroundState = ParentRelative;
|
|
borderRelative = TRUE;
|
|
/* Note that the parent's backgroundTile's refcnt is NOT
|
|
* incremented. */
|
|
}
|
|
else {
|
|
rc = dixLookupResourceByType((pointer *) &pPixmap, pixID,
|
|
RT_PIXMAP, client, DixReadAccess);
|
|
if (rc == Success) {
|
|
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 = rc;
|
|
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->parent->borderIsPixel == TRUE) {
|
|
if (pWin->borderIsPixel == FALSE)
|
|
(*pScreen->DestroyPixmap) (pWin->border.pixmap);
|
|
pWin->border = pWin->parent->border;
|
|
pWin->borderIsPixel = TRUE;
|
|
index2 = CWBorderPixel;
|
|
break;
|
|
}
|
|
else {
|
|
pixID = pWin->parent->border.pixmap->drawable.id;
|
|
}
|
|
}
|
|
rc = dixLookupResourceByType((pointer *) &pPixmap, pixID, RT_PIXMAP,
|
|
client, DixReadAccess);
|
|
if (rc == Success) {
|
|
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 = rc;
|
|
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;
|
|
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;
|
|
}
|
|
pWin->saveUnder = val;
|
|
break;
|
|
case CWEventMask:
|
|
rc = EventSelectForWindow(pWin, client, (Mask) *pVlist);
|
|
if (rc) {
|
|
error = rc;
|
|
goto PatchUp;
|
|
}
|
|
pVlist++;
|
|
break;
|
|
case CWDontPropagate:
|
|
rc = EventSuppressForWindow(pWin, client, (Mask) *pVlist,
|
|
&checkOptional);
|
|
if (rc) {
|
|
error = rc;
|
|
goto PatchUp;
|
|
}
|
|
pVlist++;
|
|
break;
|
|
case CWOverrideRedirect:
|
|
val = (BOOL) * pVlist;
|
|
pVlist++;
|
|
if ((val != xTrue) && (val != xFalse)) {
|
|
error = BadValue;
|
|
client->errorValue = val;
|
|
goto PatchUp;
|
|
}
|
|
if (val == xTrue) {
|
|
rc = XaceHook(XACE_RESOURCE_ACCESS, client, pWin->drawable.id,
|
|
RT_WINDOW, pWin, RT_NONE, NULL, DixGrabAccess);
|
|
if (rc != Success) {
|
|
error = rc;
|
|
client->errorValue = pWin->drawable.id;
|
|
goto PatchUp;
|
|
}
|
|
}
|
|
pWin->overrideRedirect = val;
|
|
break;
|
|
case CWColormap:
|
|
cmap = (Colormap) * pVlist;
|
|
pVlist++;
|
|
if (cmap == CopyFromParent) {
|
|
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;
|
|
}
|
|
rc = dixLookupResourceByType((pointer *) &pCmap, cmap, RT_COLORMAP,
|
|
client, DixUseAccess);
|
|
if (rc != Success) {
|
|
error = rc;
|
|
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 == pWin->drawable.pScreen->root)
|
|
pCursor = rootCursor;
|
|
else
|
|
pCursor = (CursorPtr) None;
|
|
}
|
|
else {
|
|
rc = dixLookupResourceByType((pointer *) &pCursor, cursorID,
|
|
RT_CURSOR, client, DixUseAccess);
|
|
if (rc != Success) {
|
|
error = rc;
|
|
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;
|
|
|
|
RegionNull(&exposed);
|
|
RegionSubtract(&exposed, &pWin->borderClip, &pWin->winSize);
|
|
miPaintWindow(pWin, &exposed, PW_BORDER);
|
|
RegionUninit(&exposed);
|
|
}
|
|
return error;
|
|
}
|
|
|
|
/*****
|
|
* GetWindowAttributes
|
|
* Notice that this is different than ChangeWindowAttributes
|
|
*****/
|
|
|
|
void
|
|
GetWindowAttributes(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 = bytes_to_int32(sizeof(xGetWindowAttributesReply) -
|
|
sizeof(xGenericReply));
|
|
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(WindowPtr pWin, WindowPtr pNextSib)
|
|
{
|
|
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;
|
|
}
|
|
|
|
void
|
|
SetWinSize(WindowPtr pWin)
|
|
{
|
|
#ifdef COMPOSITE
|
|
if (pWin->redirectDraw != RedirectDrawNone) {
|
|
BoxRec box;
|
|
|
|
/*
|
|
* Redirected clients get clip list equal to their
|
|
* own geometry, not clipped to their parent
|
|
*/
|
|
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;
|
|
RegionReset(&pWin->winSize, &box);
|
|
}
|
|
else
|
|
#endif
|
|
ClippedRegionFromBox(pWin->parent, &pWin->winSize,
|
|
pWin->drawable.x, pWin->drawable.y,
|
|
(int) pWin->drawable.width,
|
|
(int) pWin->drawable.height);
|
|
if (wBoundingShape(pWin) || wClipShape(pWin)) {
|
|
RegionTranslate(&pWin->winSize, -pWin->drawable.x, -pWin->drawable.y);
|
|
if (wBoundingShape(pWin))
|
|
RegionIntersect(&pWin->winSize, &pWin->winSize,
|
|
wBoundingShape(pWin));
|
|
if (wClipShape(pWin))
|
|
RegionIntersect(&pWin->winSize, &pWin->winSize, wClipShape(pWin));
|
|
RegionTranslate(&pWin->winSize, pWin->drawable.x, pWin->drawable.y);
|
|
}
|
|
}
|
|
|
|
void
|
|
SetBorderSize(WindowPtr pWin)
|
|
{
|
|
int bw;
|
|
|
|
if (HasBorder(pWin)) {
|
|
bw = wBorderWidth(pWin);
|
|
#ifdef COMPOSITE
|
|
if (pWin->redirectDraw != RedirectDrawNone) {
|
|
BoxRec box;
|
|
|
|
/*
|
|
* Redirected clients get clip list equal to their
|
|
* own geometry, not clipped to their parent
|
|
*/
|
|
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;
|
|
RegionReset(&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)));
|
|
if (wBoundingShape(pWin)) {
|
|
RegionTranslate(&pWin->borderSize, -pWin->drawable.x,
|
|
-pWin->drawable.y);
|
|
RegionIntersect(&pWin->borderSize, &pWin->borderSize,
|
|
wBoundingShape(pWin));
|
|
RegionTranslate(&pWin->borderSize, pWin->drawable.x,
|
|
pWin->drawable.y);
|
|
RegionUnion(&pWin->borderSize, &pWin->borderSize, &pWin->winSize);
|
|
}
|
|
}
|
|
else {
|
|
RegionCopy(&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(int x, int y, int oldx, int oldy,
|
|
int dw, int dh, unsigned gravity, int *destx, 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(WindowPtr pWin, int dx, int dy, int dw, int dh)
|
|
{
|
|
ScreenPtr pScreen;
|
|
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);
|
|
(*pScreen->PositionWindow) (pSib, pSib->drawable.x, pSib->drawable.y);
|
|
|
|
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(WindowPtr pMe, WindowPtr pSib)
|
|
{
|
|
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(WindowPtr pWin, 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;
|
|
}
|
|
|
|
#define IS_SHAPED(pWin) (wBoundingShape (pWin) != (RegionPtr) NULL)
|
|
|
|
static RegionPtr
|
|
MakeBoundingRegion(WindowPtr pWin, BoxPtr pBox)
|
|
{
|
|
RegionPtr pRgn = RegionCreate(pBox, 1);
|
|
|
|
if (wBoundingShape(pWin)) {
|
|
RegionTranslate(pRgn, -pWin->origin.x, -pWin->origin.y);
|
|
RegionIntersect(pRgn, pRgn, wBoundingShape(pWin));
|
|
RegionTranslate(pRgn, pWin->origin.x, pWin->origin.y);
|
|
}
|
|
return pRgn;
|
|
}
|
|
|
|
static Bool
|
|
ShapeOverlap(WindowPtr pWin, BoxPtr pWinBox, WindowPtr pSib, BoxPtr pSibBox)
|
|
{
|
|
RegionPtr pWinRgn, pSibRgn;
|
|
Bool ret;
|
|
|
|
if (!IS_SHAPED(pWin) && !IS_SHAPED(pSib))
|
|
return TRUE;
|
|
pWinRgn = MakeBoundingRegion(pWin, pWinBox);
|
|
pSibRgn = MakeBoundingRegion(pSib, pSibBox);
|
|
RegionIntersect(pWinRgn, pWinRgn, pSibRgn);
|
|
ret = RegionNotEmpty(pWinRgn);
|
|
RegionDestroy(pWinRgn);
|
|
RegionDestroy(pSibRgn);
|
|
return ret;
|
|
}
|
|
|
|
static Bool
|
|
AnyWindowOverlapsMe(WindowPtr pWin, WindowPtr pHead, BoxPtr box)
|
|
{
|
|
WindowPtr pSib;
|
|
BoxRec sboxrec;
|
|
BoxPtr sbox;
|
|
|
|
for (pSib = pWin->prevSib; pSib != pHead; pSib = pSib->prevSib) {
|
|
if (pSib->mapped) {
|
|
sbox = WindowExtents(pSib, &sboxrec);
|
|
if (BOXES_OVERLAP(sbox, box)
|
|
&& ShapeOverlap(pWin, box, pSib, sbox)
|
|
)
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static Bool
|
|
IOverlapAnyWindow(WindowPtr pWin, BoxPtr box)
|
|
{
|
|
WindowPtr pSib;
|
|
BoxRec sboxrec;
|
|
BoxPtr sbox;
|
|
|
|
for (pSib = pWin->nextSib; pSib; pSib = pSib->nextSib) {
|
|
if (pSib->mapped) {
|
|
sbox = WindowExtents(pSib, &sboxrec);
|
|
if (BOXES_OVERLAP(sbox, box)
|
|
&& ShapeOverlap(pWin, box, pSib, sbox)
|
|
)
|
|
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(WindowPtr pWin,
|
|
WindowPtr pSib,
|
|
short x,
|
|
short y, unsigned short w, unsigned short h, int smode)
|
|
{
|
|
BoxRec box;
|
|
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;
|
|
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)))
|
|
return pWin->nextSib;
|
|
else if (pSib) {
|
|
if ((IsSiblingAboveMe(pWin, pSib) == Above) &&
|
|
(RegionContainsRect(&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)))
|
|
return pWin->nextSib;
|
|
else if (pSib) {
|
|
if ((IsSiblingAboveMe(pWin, pSib) == Below) &&
|
|
(RegionContainsRect(&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)))
|
|
return pWin->nextSib;
|
|
else if (pSib) {
|
|
if (RegionContainsRect(&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:
|
|
{
|
|
/* should never happen; make something up. */
|
|
return pWin->nextSib;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
ReflectStackChange(WindowPtr pWin, WindowPtr pSib, VTKind kind)
|
|
{
|
|
/* Note that pSib might be NULL */
|
|
|
|
Bool WasViewable = (Bool) pWin->viewable;
|
|
Bool anyMarked;
|
|
WindowPtr pFirstChange;
|
|
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;
|
|
if (anyMarked) {
|
|
(*pScreen->ValidateTree) (pLayerWin->parent, pFirstChange, kind);
|
|
(*pScreen->HandleExposures) (pLayerWin->parent);
|
|
}
|
|
if (anyMarked && pWin->drawable.pScreen->PostValidateTree)
|
|
(*pScreen->PostValidateTree) (pLayerWin->parent, pFirstChange,
|
|
kind);
|
|
}
|
|
if (pWin->realized)
|
|
WindowsRestructured();
|
|
}
|
|
|
|
/*****
|
|
* ConfigureWindow
|
|
*****/
|
|
|
|
int
|
|
ConfigureWindow(WindowPtr pWin, Mask mask, XID *vlist, ClientPtr client)
|
|
{
|
|
#define RESTACK_WIN 0
|
|
#define MOVE_WIN 1
|
|
#define RESIZE_WIN 2
|
|
#define REBORDER_WIN 3
|
|
WindowPtr pSib = NullWindow;
|
|
WindowPtr pParent = pWin->parent;
|
|
Window sibwid = 0;
|
|
Mask index2, tmask;
|
|
XID *pVlist;
|
|
short x, y, beforeX, beforeY;
|
|
unsigned short w = pWin->drawable.width,
|
|
h = pWin->drawable.height, bw = pWin->borderWidth;
|
|
int rc, action, smode = Above;
|
|
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++;
|
|
rc = dixLookupWindow(&pSib, sibwid, client, DixGetAttrAccess);
|
|
if (rc != Success) {
|
|
client->errorValue = sibwid;
|
|
return rc;
|
|
}
|
|
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 */
|
|
|
|
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;
|
|
|
|
if ((!pWin->overrideRedirect) && (RedirectSend(pParent)
|
|
)) {
|
|
memset(&event, 0, sizeof(xEvent));
|
|
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 += screenInfo.screens[0]->x;
|
|
event.u.configureRequest.y += screenInfo.screens[0]->y;
|
|
}
|
|
#endif
|
|
event.u.configureRequest.width = w;
|
|
event.u.configureRequest.height = h;
|
|
event.u.configureRequest.borderWidth = bw;
|
|
event.u.configureRequest.valueMask = mask;
|
|
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;
|
|
|
|
memset(&eventT, 0, sizeof(xEvent));
|
|
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 (pWin->drawable.pScreen->ConfigNotify) {
|
|
int ret;
|
|
|
|
ret =
|
|
(*pWin->drawable.pScreen->ConfigNotify) (pWin, x, y, w, h, bw,
|
|
pSib);
|
|
if (ret) {
|
|
client->errorValue = 0;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
if (SubStrSend(pWin, pParent)) {
|
|
memset(&event, 0, sizeof(xEvent));
|
|
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 += screenInfo.screens[0]->x;
|
|
event.u.configureNotify.y += screenInfo.screens[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);
|
|
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)
|
|
{
|
|
WindowPtr pWin, pHead, pFirst;
|
|
xEvent event;
|
|
BoxRec box;
|
|
|
|
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(WindowPtr pWin, WindowPtr pParent,
|
|
int x, int y, ClientPtr client)
|
|
{
|
|
WindowPtr pPrev, pPriorParent;
|
|
Bool WasMapped = (Bool) (pWin->mapped);
|
|
xEvent event;
|
|
int bw = wBorderWidth(pWin);
|
|
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);
|
|
|
|
memset(&event, 0, sizeof(xEvent));
|
|
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 += screenInfo.screens[0]->x;
|
|
event.u.reparent.y += screenInfo.screens[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 (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)
|
|
{
|
|
WindowPtr pChild;
|
|
RealizeWindowProcPtr Realize;
|
|
|
|
Realize = pWin->drawable.pScreen->RealizeWindow;
|
|
pChild = pWin;
|
|
while (1) {
|
|
if (pChild->mapped) {
|
|
pChild->realized = TRUE;
|
|
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;
|
|
}
|
|
}
|
|
|
|
static WindowPtr windowDisableMapUnmapEvents;
|
|
|
|
void
|
|
DisableMapUnmapEvents(WindowPtr pWin)
|
|
{
|
|
assert(windowDisableMapUnmapEvents == NULL);
|
|
|
|
windowDisableMapUnmapEvents = pWin;
|
|
}
|
|
|
|
void
|
|
EnableMapUnmapEvents(WindowPtr pWin)
|
|
{
|
|
assert(windowDisableMapUnmapEvents != NULL);
|
|
|
|
windowDisableMapUnmapEvents = NULL;
|
|
}
|
|
|
|
static Bool
|
|
MapUnmapEventsEnabled(WindowPtr pWin)
|
|
{
|
|
return pWin != windowDisableMapUnmapEvents;
|
|
}
|
|
|
|
/*****
|
|
* 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(WindowPtr pWin, ClientPtr client)
|
|
{
|
|
ScreenPtr pScreen;
|
|
|
|
WindowPtr pParent;
|
|
WindowPtr pLayerWin;
|
|
|
|
if (pWin->mapped)
|
|
return Success;
|
|
|
|
/* general check for permission to map window */
|
|
if (XaceHook(XACE_RESOURCE_ACCESS, client, pWin->drawable.id, RT_WINDOW,
|
|
pWin, RT_NONE, NULL, DixShowAccess) != Success)
|
|
return Success;
|
|
|
|
pScreen = pWin->drawable.pScreen;
|
|
if ((pParent = pWin->parent)) {
|
|
xEvent event;
|
|
Bool anyMarked;
|
|
|
|
if ((!pWin->overrideRedirect) && (RedirectSend(pParent)
|
|
)) {
|
|
memset(&event, 0, sizeof(xEvent));
|
|
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)
|
|
return Success;
|
|
}
|
|
|
|
pWin->mapped = TRUE;
|
|
if (SubStrSend(pWin, pParent) && MapUnmapEventsEnabled(pWin)) {
|
|
memset(&event, 0, sizeof(xEvent));
|
|
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);
|
|
if (anyMarked) {
|
|
(*pScreen->ValidateTree) (pLayerWin->parent, pLayerWin, VTMap);
|
|
(*pScreen->HandleExposures) (pLayerWin->parent);
|
|
}
|
|
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);
|
|
RegionNull(&temp);
|
|
RegionCopy(&temp, &pWin->clipList);
|
|
(*pScreen->WindowExposures) (pWin, &temp, NullRegion);
|
|
RegionUninit(&temp);
|
|
}
|
|
|
|
return Success;
|
|
}
|
|
|
|
/*****
|
|
* MapSubwindows
|
|
* Performs a MapWindow all unmapped children of the window, in top
|
|
* to bottom stacking order.
|
|
*****/
|
|
|
|
void
|
|
MapSubwindows(WindowPtr pParent, ClientPtr client)
|
|
{
|
|
WindowPtr pWin;
|
|
WindowPtr pFirstMapped = NullWindow;
|
|
ScreenPtr pScreen;
|
|
Mask parentRedirect;
|
|
Mask parentNotify;
|
|
xEvent event;
|
|
Bool anyMarked;
|
|
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) {
|
|
memset(&event, 0, sizeof(xEvent));
|
|
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)) {
|
|
memset(&event, 0, sizeof(xEvent));
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pFirstMapped) {
|
|
pLayerWin = (*pScreen->GetLayerWindow) (pParent);
|
|
if (pLayerWin->parent != pParent) {
|
|
anyMarked |= (*pScreen->MarkOverlappedWindows) (pLayerWin,
|
|
pLayerWin,
|
|
(WindowPtr *) NULL);
|
|
pFirstMapped = pLayerWin;
|
|
}
|
|
if (anyMarked) {
|
|
(*pScreen->ValidateTree) (pLayerWin->parent, pFirstMapped, VTMap);
|
|
(*pScreen->HandleExposures) (pLayerWin->parent);
|
|
}
|
|
if (anyMarked && pScreen->PostValidateTree)
|
|
(*pScreen->PostValidateTree) (pLayerWin->parent, pFirstMapped,
|
|
VTMap);
|
|
WindowsRestructured();
|
|
}
|
|
}
|
|
|
|
static void
|
|
UnrealizeTree(WindowPtr pWin, Bool fromConfigure)
|
|
{
|
|
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;
|
|
int rc = dixLookupResourceByType((pointer *) &win,
|
|
pChild->drawable.id,
|
|
XRT_WINDOW,
|
|
serverClient, DixWriteAccess);
|
|
|
|
if (rc == Success)
|
|
win->u.win.visibility = VisibilityNotViewable;
|
|
}
|
|
#endif
|
|
(*Unrealize) (pChild);
|
|
if (MapUnmapEventsEnabled(pWin))
|
|
DeleteWindowFromAnyEvents(pChild, FALSE);
|
|
if (pChild->viewable) {
|
|
pChild->viewable = FALSE;
|
|
(*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(WindowPtr pWin, Bool fromConfigure)
|
|
{
|
|
WindowPtr pParent;
|
|
xEvent event;
|
|
Bool wasRealized = (Bool) pWin->realized;
|
|
Bool wasViewable = (Bool) pWin->viewable;
|
|
ScreenPtr pScreen = pWin->drawable.pScreen;
|
|
WindowPtr pLayerWin = pWin;
|
|
|
|
if ((!pWin->mapped) || (!(pParent = pWin->parent)))
|
|
return Success;
|
|
if (SubStrSend(pWin, pParent) && MapUnmapEventsEnabled(pWin)) {
|
|
memset(&event, 0, sizeof(xEvent));
|
|
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);
|
|
}
|
|
if (!fromConfigure && pScreen->PostValidateTree)
|
|
(*pScreen->PostValidateTree) (pLayerWin->parent, pWin, VTUnmap);
|
|
}
|
|
if (wasRealized && !fromConfigure) {
|
|
WindowsRestructured();
|
|
WindowGone(pWin);
|
|
}
|
|
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(WindowPtr pWin)
|
|
{
|
|
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) {
|
|
}
|
|
}
|
|
}
|
|
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);
|
|
}
|
|
if (anyMarked && pScreen->PostValidateTree)
|
|
(*pScreen->PostValidateTree) (pLayerWin->parent, pHead, VTUnmap);
|
|
}
|
|
if (wasRealized) {
|
|
WindowsRestructured();
|
|
WindowGone(pWin);
|
|
}
|
|
}
|
|
|
|
void
|
|
HandleSaveSet(ClientPtr client)
|
|
{
|
|
WindowPtr pParent, pWin;
|
|
int j;
|
|
|
|
for (j = 0; j < client->numSaved; j++) {
|
|
pWin = SaveSetWindow(client->saveSet[j]);
|
|
#ifdef XFIXES
|
|
if (SaveSetToRoot(client->saveSet[j]))
|
|
pParent = pWin->drawable.pScreen->root;
|
|
else
|
|
#endif
|
|
{
|
|
pParent = pWin->parent;
|
|
while (pParent && (wClient(pParent) == client))
|
|
pParent = pParent->parent;
|
|
}
|
|
if (pParent) {
|
|
if (pParent != pWin->parent) {
|
|
#ifdef XFIXES
|
|
/* unmap first so that ReparentWindow doesn't remap */
|
|
if (!SaveSetShouldMap(client->saveSet[j]))
|
|
UnmapWindow(pWin, FALSE);
|
|
#endif
|
|
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 (SaveSetShouldMap(client->saveSet[j]))
|
|
#endif
|
|
MapWindow(pWin, client);
|
|
}
|
|
}
|
|
free(client->saveSet);
|
|
client->numSaved = 0;
|
|
client->saveSet = (SaveSetElt *) NULL;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* \param x,y in root
|
|
*/
|
|
Bool
|
|
PointInWindowIsVisible(WindowPtr pWin, int x, int y)
|
|
{
|
|
BoxRec box;
|
|
|
|
if (!pWin->realized)
|
|
return FALSE;
|
|
if (RegionContainsPoint(&pWin->borderClip, x, y, &box)
|
|
&& (!wInputShape(pWin) ||
|
|
RegionContainsPoint(wInputShape(pWin),
|
|
x - pWin->drawable.x,
|
|
y - pWin->drawable.y, &box)))
|
|
return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
RegionPtr
|
|
NotClippedByChildren(WindowPtr pWin)
|
|
{
|
|
RegionPtr pReg = RegionCreate(NullBox, 1);
|
|
|
|
if (pWin->parent ||
|
|
screenIsSaved != SCREEN_SAVER_ON ||
|
|
!HasSaverWindow(pWin->drawable.pScreen)) {
|
|
RegionIntersect(pReg, &pWin->borderClip, &pWin->winSize);
|
|
}
|
|
return pReg;
|
|
}
|
|
|
|
void
|
|
SendVisibilityNotify(WindowPtr pWin)
|
|
{
|
|
xEvent event;
|
|
unsigned int visibility = pWin->visibility;
|
|
|
|
if (!MapUnmapEventsEnabled(pWin))
|
|
return;
|
|
#ifdef PANORAMIX
|
|
/* This is not quite correct yet, but it's close */
|
|
if (!noPanoramiXExtension) {
|
|
PanoramiXRes *win;
|
|
WindowPtr pWin2;
|
|
int rc, 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_NSCREENS(i) {
|
|
if (i == Scrnum)
|
|
continue;
|
|
|
|
rc = dixLookupWindow(&pWin2, win->info[i].id, serverClient,
|
|
DixWriteAccess);
|
|
|
|
if (rc == Success) {
|
|
if (pWin2->visibility == VisibilityPartiallyObscured)
|
|
return;
|
|
|
|
if (!i)
|
|
pWin = pWin2;
|
|
}
|
|
}
|
|
break;
|
|
case VisibilityPartiallyObscured:
|
|
if (Scrnum) {
|
|
rc = dixLookupWindow(&pWin2, win->info[0].id, serverClient,
|
|
DixWriteAccess);
|
|
if (rc == Success)
|
|
pWin = pWin2;
|
|
}
|
|
break;
|
|
case VisibilityFullyObscured:
|
|
FOR_NSCREENS(i) {
|
|
if (i == Scrnum)
|
|
continue;
|
|
|
|
rc = dixLookupWindow(&pWin2, win->info[i].id, serverClient,
|
|
DixWriteAccess);
|
|
|
|
if (rc == Success) {
|
|
if (pWin2->visibility != VisibilityFullyObscured)
|
|
return;
|
|
|
|
if (!i)
|
|
pWin = pWin2;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
win->u.win.visibility = visibility;
|
|
}
|
|
#endif
|
|
|
|
memset(&event, 0, sizeof(xEvent));
|
|
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
|
|
int
|
|
dixSaveScreens(ClientPtr client, int on, int mode)
|
|
{
|
|
int rc, i, what, type;
|
|
|
|
if (on == SCREEN_SAVER_FORCER) {
|
|
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++) {
|
|
rc = XaceHook(XACE_SCREENSAVER_ACCESS, client, screenInfo.screens[i],
|
|
DixShowAccess | DixHideAccess);
|
|
if (rc != Success)
|
|
return rc;
|
|
}
|
|
for (i = 0; i < screenInfo.numScreens; i++) {
|
|
ScreenPtr pScreen = screenInfo.screens[i];
|
|
|
|
if (on == SCREEN_SAVER_FORCER)
|
|
(*pScreen->SaveScreen) (pScreen, on);
|
|
if (pScreen->screensaver.ExternalScreenSaver) {
|
|
if ((*pScreen->screensaver.ExternalScreenSaver)
|
|
(pScreen, type, on == SCREEN_SAVER_FORCER))
|
|
continue;
|
|
}
|
|
if (type == screenIsSaved)
|
|
continue;
|
|
switch (type) {
|
|
case SCREEN_SAVER_OFF:
|
|
if (pScreen->screensaver.blanked == SCREEN_IS_BLANKED) {
|
|
(*pScreen->SaveScreen) (pScreen, what);
|
|
}
|
|
else if (HasSaverWindow(pScreen)) {
|
|
pScreen->screensaver.pWindow = NullWindow;
|
|
FreeResource(pScreen->screensaver.wid, RT_NONE);
|
|
}
|
|
break;
|
|
case SCREEN_SAVER_CYCLE:
|
|
if (pScreen->screensaver.blanked == SCREEN_IS_TILED) {
|
|
WindowPtr pWin = pScreen->screensaver.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;
|
|
(*pWin->drawable.pScreen->MoveWindow) (pWin,
|
|
(short) (-
|
|
(rand() %
|
|
RANDOM_WIDTH)),
|
|
(short) (-
|
|
(rand() %
|
|
RANDOM_WIDTH)),
|
|
pWin->nextSib, VTMove);
|
|
screenIsSaved = SCREEN_SAVER_ON;
|
|
}
|
|
/*
|
|
* Call the DDX saver in case it wants to do something
|
|
* at cycle time
|
|
*/
|
|
else if (pScreen->screensaver.blanked == SCREEN_IS_BLANKED) {
|
|
(*pScreen->SaveScreen) (pScreen, type);
|
|
}
|
|
break;
|
|
case SCREEN_SAVER_ON:
|
|
if (ScreenSaverBlanking != DontPreferBlanking) {
|
|
if ((*pScreen->SaveScreen) (pScreen, what)) {
|
|
pScreen->screensaver.blanked = SCREEN_IS_BLANKED;
|
|
continue;
|
|
}
|
|
if ((ScreenSaverAllowExposures != DontAllowExposures) &&
|
|
TileScreenSaver(pScreen, SCREEN_IS_BLACK)) {
|
|
pScreen->screensaver.blanked = SCREEN_IS_BLACK;
|
|
continue;
|
|
}
|
|
}
|
|
if ((ScreenSaverAllowExposures != DontAllowExposures) &&
|
|
TileScreenSaver(pScreen, SCREEN_IS_TILED)) {
|
|
pScreen->screensaver.blanked = SCREEN_IS_TILED;
|
|
}
|
|
else
|
|
pScreen->screensaver.blanked = SCREEN_ISNT_SAVED;
|
|
break;
|
|
}
|
|
}
|
|
screenIsSaved = what;
|
|
if (mode == ScreenSaverReset) {
|
|
if (on == SCREEN_SAVER_FORCER) {
|
|
UpdateCurrentTimeIf();
|
|
lastDeviceEventTime = currentTime;
|
|
}
|
|
SetScreenSaverTimer();
|
|
}
|
|
return Success;
|
|
}
|
|
|
|
int
|
|
SaveScreens(int on, int mode)
|
|
{
|
|
return dixSaveScreens(serverClient, on, mode);
|
|
}
|
|
|
|
static Bool
|
|
TileScreenSaver(ScreenPtr pScreen, 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 (pScreen->root->backgroundState) {
|
|
case BackgroundPixel:
|
|
attributes[attri++] = pScreen->root->background.pixel;
|
|
mask |= CWBackPixel;
|
|
break;
|
|
case BackgroundPixmap:
|
|
attributes[attri++] = None;
|
|
mask |= CWBackPixmap;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case SCREEN_IS_BLACK:
|
|
attributes[attri++] = pScreen->root->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 = malloc(BitmapBytePad(32) * 16);
|
|
mskbits = malloc(BitmapBytePad(32) * 16);
|
|
if (!srcbits || !mskbits) {
|
|
free(srcbits);
|
|
free(mskbits);
|
|
cursor = 0;
|
|
}
|
|
else {
|
|
for (j = 0; j < BitmapBytePad(32) * 16; j++)
|
|
srcbits[j] = mskbits[j] = 0x0;
|
|
result = AllocARGBCursor(srcbits, mskbits, NULL, &cm, 0, 0, 0, 0, 0, 0,
|
|
&cursor, serverClient, (XID) 0);
|
|
if (cursor) {
|
|
cursorID = FakeClientID(0);
|
|
if (AddResource(cursorID, RT_CURSOR, (pointer) cursor)) {
|
|
attributes[attri] = cursorID;
|
|
mask |= CWCursor;
|
|
}
|
|
else
|
|
cursor = 0;
|
|
}
|
|
else {
|
|
free(srcbits);
|
|
free(mskbits);
|
|
}
|
|
}
|
|
|
|
pWin = pScreen->screensaver.pWindow =
|
|
CreateWindow(pScreen->screensaver.wid,
|
|
pScreen->root,
|
|
-RANDOM_WIDTH, -RANDOM_WIDTH,
|
|
(unsigned short) pScreen->width + RANDOM_WIDTH,
|
|
(unsigned short) pScreen->height + RANDOM_WIDTH,
|
|
0, InputOutput, mask, attributes, 0, serverClient,
|
|
wVisual(pScreen->root), &result);
|
|
|
|
if (cursor)
|
|
FreeResource(cursorID, RT_NONE);
|
|
|
|
if (!pWin)
|
|
return FALSE;
|
|
|
|
if (!AddResource(pWin->drawable.id, RT_WINDOW,
|
|
(pointer) pScreen->screensaver.pWindow))
|
|
return FALSE;
|
|
|
|
if (mask & CWBackPixmap) {
|
|
MakeRootTile(pWin);
|
|
(*pWin->drawable.pScreen->ChangeWindowAttributes) (pWin, CWBackPixmap);
|
|
}
|
|
MapWindow(pWin, serverClient);
|
|
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(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(WindowPtr w)
|
|
{
|
|
WindowOptPtr optional;
|
|
WindowOptPtr parentOptional;
|
|
|
|
if (!w->parent || !w->optional)
|
|
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;
|
|
if (optional->boundingShape != NULL)
|
|
return;
|
|
if (optional->clipShape != NULL)
|
|
return;
|
|
if (optional->inputShape != NULL)
|
|
return;
|
|
if (optional->inputMasks != NULL)
|
|
return;
|
|
if (optional->deviceCursors != NULL) {
|
|
DevCursNodePtr pNode = optional->deviceCursors;
|
|
|
|
while (pNode) {
|
|
if (pNode->cursor != None)
|
|
return;
|
|
pNode = pNode->next;
|
|
}
|
|
}
|
|
|
|
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(WindowPtr pWin)
|
|
{
|
|
WindowOptPtr optional;
|
|
WindowOptPtr parentOptional;
|
|
|
|
if (pWin->optional)
|
|
return TRUE;
|
|
optional = malloc(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;
|
|
optional->boundingShape = NULL;
|
|
optional->clipShape = NULL;
|
|
optional->inputShape = NULL;
|
|
optional->inputMasks = NULL;
|
|
optional->deviceCursors = NULL;
|
|
|
|
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;
|
|
}
|
|
|
|
/*
|
|
* Changes the cursor struct for the given device and the given window.
|
|
* A cursor that does not have a device cursor set will use whatever the
|
|
* standard cursor is for the window. If all devices have a cursor set,
|
|
* changing the window cursor (e.g. using XDefineCursor()) will not have any
|
|
* visible effect. Only when one of the device cursors is set to None again,
|
|
* this device's cursor will display the changed standard cursor.
|
|
*
|
|
* CursorIsNone of the window struct is NOT modified if you set a device
|
|
* cursor.
|
|
*
|
|
* Assumption: If there is a node for a device in the list, the device has a
|
|
* cursor. If the cursor is set to None, it is inherited by the parent.
|
|
*/
|
|
int
|
|
ChangeWindowDeviceCursor(WindowPtr pWin, DeviceIntPtr pDev, CursorPtr pCursor)
|
|
{
|
|
DevCursNodePtr pNode, pPrev;
|
|
CursorPtr pOldCursor = NULL;
|
|
ScreenPtr pScreen;
|
|
WindowPtr pChild;
|
|
|
|
if (!pWin->optional && !MakeWindowOptional(pWin))
|
|
return BadAlloc;
|
|
|
|
/* 1) Check if window has device cursor set
|
|
* Yes: 1.1) swap cursor with given cursor if parent does not have same
|
|
* cursor, free old cursor
|
|
* 1.2) free old cursor, use parent cursor
|
|
* No: 1.1) add node to beginning of list.
|
|
* 1.2) add cursor to node if parent does not have same cursor
|
|
* 1.3) use parent cursor if parent does not have same cursor
|
|
* 2) Patch up children if child has a devcursor
|
|
* 2.1) if child has cursor None, it inherited from parent, set to old
|
|
* cursor
|
|
* 2.2) if child has same cursor as new cursor, remove and set to None
|
|
*/
|
|
|
|
pScreen = pWin->drawable.pScreen;
|
|
|
|
if (WindowSeekDeviceCursor(pWin, pDev, &pNode, &pPrev)) {
|
|
/* has device cursor */
|
|
|
|
if (pNode->cursor == pCursor)
|
|
return Success;
|
|
|
|
pOldCursor = pNode->cursor;
|
|
|
|
if (!pCursor) { /* remove from list */
|
|
if (pPrev)
|
|
pPrev->next = pNode->next;
|
|
else
|
|
/* first item in list */
|
|
pWin->optional->deviceCursors = pNode->next;
|
|
|
|
free(pNode);
|
|
goto out;
|
|
}
|
|
|
|
}
|
|
else {
|
|
/* no device cursor yet */
|
|
DevCursNodePtr pNewNode;
|
|
|
|
if (!pCursor)
|
|
return Success;
|
|
|
|
pNewNode = malloc(sizeof(DevCursNodeRec));
|
|
pNewNode->dev = pDev;
|
|
pNewNode->next = pWin->optional->deviceCursors;
|
|
pWin->optional->deviceCursors = pNewNode;
|
|
pNode = pNewNode;
|
|
|
|
}
|
|
|
|
if (pCursor && WindowParentHasDeviceCursor(pWin, pDev, pCursor))
|
|
pNode->cursor = None;
|
|
else {
|
|
pNode->cursor = pCursor;
|
|
pCursor->refcnt++;
|
|
}
|
|
|
|
pNode = pPrev = NULL;
|
|
/* fix up children */
|
|
for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) {
|
|
if (WindowSeekDeviceCursor(pChild, pDev, &pNode, &pPrev)) {
|
|
if (pNode->cursor == None) { /* inherited from parent */
|
|
pNode->cursor = pOldCursor;
|
|
pOldCursor->refcnt++;
|
|
}
|
|
else if (pNode->cursor == pCursor) {
|
|
pNode->cursor = None;
|
|
FreeCursor(pCursor, (Cursor) 0); /* fix up refcnt */
|
|
}
|
|
}
|
|
}
|
|
|
|
out:
|
|
if (pWin->realized)
|
|
WindowHasNewCursor(pWin);
|
|
|
|
if (pOldCursor)
|
|
FreeCursor(pOldCursor, (Cursor) 0);
|
|
|
|
/* FIXME: We SHOULD check for an error value here XXX
|
|
(comment taken from ChangeWindowAttributes) */
|
|
(*pScreen->ChangeWindowAttributes) (pWin, CWCursor);
|
|
|
|
return Success;
|
|
}
|
|
|
|
/* Get device cursor for given device or None if none is set */
|
|
CursorPtr
|
|
WindowGetDeviceCursor(WindowPtr pWin, DeviceIntPtr pDev)
|
|
{
|
|
DevCursorList pList;
|
|
|
|
if (!pWin->optional || !pWin->optional->deviceCursors)
|
|
return NULL;
|
|
|
|
pList = pWin->optional->deviceCursors;
|
|
|
|
while (pList) {
|
|
if (pList->dev == pDev) {
|
|
if (pList->cursor == None) /* inherited from parent */
|
|
return WindowGetDeviceCursor(pWin->parent, pDev);
|
|
else
|
|
return pList->cursor;
|
|
}
|
|
pList = pList->next;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/* Searches for a DevCursorNode for the given window and device. If one is
|
|
* found, return True and set pNode and pPrev to the node and to the node
|
|
* before the node respectively. Otherwise return False.
|
|
* If the device is the first in list, pPrev is set to NULL.
|
|
*/
|
|
static Bool
|
|
WindowSeekDeviceCursor(WindowPtr pWin,
|
|
DeviceIntPtr pDev,
|
|
DevCursNodePtr * pNode, DevCursNodePtr * pPrev)
|
|
{
|
|
DevCursorList pList;
|
|
|
|
if (!pWin->optional)
|
|
return FALSE;
|
|
|
|
pList = pWin->optional->deviceCursors;
|
|
|
|
if (pList && pList->dev == pDev) {
|
|
*pNode = pList;
|
|
*pPrev = NULL;
|
|
return TRUE;
|
|
}
|
|
|
|
while (pList) {
|
|
if (pList->next) {
|
|
if (pList->next->dev == pDev) {
|
|
*pNode = pList->next;
|
|
*pPrev = pList;
|
|
return TRUE;
|
|
}
|
|
}
|
|
pList = pList->next;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/* Return True if a parent has the same device cursor set or False if
|
|
* otherwise
|
|
*/
|
|
static Bool
|
|
WindowParentHasDeviceCursor(WindowPtr pWin,
|
|
DeviceIntPtr pDev, CursorPtr pCursor)
|
|
{
|
|
WindowPtr pParent;
|
|
DevCursNodePtr pParentNode, pParentPrev;
|
|
|
|
pParent = pWin->parent;
|
|
while (pParent) {
|
|
if (WindowSeekDeviceCursor(pParent, pDev, &pParentNode, &pParentPrev)) {
|
|
/* if there is a node in the list, the win has a dev cursor */
|
|
if (!pParentNode->cursor) /* inherited. */
|
|
pParent = pParent->parent;
|
|
else if (pParentNode->cursor == pCursor) /* inherit */
|
|
return TRUE;
|
|
else /* different cursor */
|
|
return FALSE;
|
|
}
|
|
else
|
|
/* parent does not have a device cursor for our device */
|
|
return FALSE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* SetRootClip --
|
|
* Enable or disable rendering to the screen by
|
|
* setting the root clip list and revalidating
|
|
* all of the windows
|
|
*/
|
|
void
|
|
SetRootClip(ScreenPtr pScreen, Bool enable)
|
|
{
|
|
WindowPtr pWin = pScreen->root;
|
|
WindowPtr pChild;
|
|
Bool WasViewable;
|
|
Bool anyMarked = FALSE;
|
|
WindowPtr pLayerWin;
|
|
BoxRec box;
|
|
|
|
if (!pWin)
|
|
return;
|
|
WasViewable = (Bool) (pWin->viewable);
|
|
if (WasViewable) {
|
|
for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) {
|
|
(void) (*pScreen->MarkOverlappedWindows) (pChild,
|
|
pChild, &pLayerWin);
|
|
}
|
|
(*pScreen->MarkWindow) (pWin);
|
|
anyMarked = TRUE;
|
|
if (pWin->valdata) {
|
|
if (HasBorder(pWin)) {
|
|
RegionPtr borderVisible;
|
|
|
|
borderVisible = RegionCreate(NullBox, 1);
|
|
RegionSubtract(borderVisible,
|
|
&pWin->borderClip, &pWin->winSize);
|
|
pWin->valdata->before.borderVisible = borderVisible;
|
|
}
|
|
pWin->valdata->before.resized = TRUE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Use REGION_BREAK to avoid optimizations in ValidateTree
|
|
* that assume the root borderClip can't change well, normally
|
|
* it doesn't...)
|
|
*/
|
|
if (enable) {
|
|
box.x1 = 0;
|
|
box.y1 = 0;
|
|
box.x2 = pScreen->width;
|
|
box.y2 = pScreen->height;
|
|
RegionInit(&pWin->winSize, &box, 1);
|
|
RegionInit(&pWin->borderSize, &box, 1);
|
|
if (WasViewable)
|
|
RegionReset(&pWin->borderClip, &box);
|
|
pWin->drawable.width = pScreen->width;
|
|
pWin->drawable.height = pScreen->height;
|
|
RegionBreak(&pWin->clipList);
|
|
}
|
|
else {
|
|
RegionEmpty(&pWin->borderClip);
|
|
RegionBreak(&pWin->clipList);
|
|
}
|
|
|
|
ResizeChildrenWinSize(pWin, 0, 0, 0, 0);
|
|
|
|
if (WasViewable) {
|
|
if (pWin->firstChild) {
|
|
anyMarked |= (*pScreen->MarkOverlappedWindows) (pWin->firstChild,
|
|
pWin->firstChild,
|
|
(WindowPtr *) NULL);
|
|
}
|
|
else {
|
|
(*pScreen->MarkWindow) (pWin);
|
|
anyMarked = TRUE;
|
|
}
|
|
|
|
if (anyMarked)
|
|
(*pScreen->ValidateTree) (pWin, NullWindow, VTOther);
|
|
}
|
|
|
|
if (WasViewable) {
|
|
if (anyMarked)
|
|
(*pScreen->HandleExposures) (pWin);
|
|
if (anyMarked && pScreen->PostValidateTree)
|
|
(*pScreen->PostValidateTree) (pWin, NullWindow, VTOther);
|
|
}
|
|
if (pWin->realized)
|
|
WindowsRestructured();
|
|
FlushAllOutput();
|
|
}
|