TinyX/dix/window.c

3363 lines
99 KiB
C
Raw Permalink Normal View History

2013-11-30 13:51:10 +00:00
/*
Copyright (c) 2006, Red Hat, Inc.
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
RED HAT 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 Red Hat shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Red Hat.
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.
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include "misc.h"
#include "scrnintstr.h"
#include "os.h"
#include "regionstr.h"
#include "validate.h"
#include "windowstr.h"
#include "input.h"
#include "resource.h"
#include "colormapst.h"
#include "cursorstr.h"
#include "dixstruct.h"
#include "gcstruct.h"
#include "servermd.h"
#include "dixevents.h"
#include "globals.h"
/******
* Window stuff for server
*
* CreateRootWindow, CreateWindow, ChangeWindowAttributes,
* GetWindowAttributes, DeleteWindow, DestroySubWindows,
* HandleSaveSet, ReparentWindow, MapWindow, MapSubWindows,
* UnmapWindow, UnmapSubWindows, ConfigureWindow, CirculateWindow,
*
******/
static const unsigned char _back_lsb[4] = { 0x88, 0x22, 0x44, 0x11 };
static const unsigned char _back_msb[4] = { 0x11, 0x44, 0x22, 0x88 };
_X_EXPORT int screenIsSaved = SCREEN_SAVER_OFF;
_X_EXPORT ScreenSaverStuffRec savedScreenInfo[MAXSCREENS];
static Bool TileScreenSaver(int i, int kind);
#define INPUTONLY_LEGAL_MASK (CWWinGravity | CWEventMask | \
CWDontPropagate | CWOverrideRedirect | CWCursor )
#define BOXES_OVERLAP(b1, b2) \
(!( ((b1)->x2 <= (b2)->x1) || \
( ((b1)->x1 >= (b2)->x2)) || \
( ((b1)->y2 <= (b2)->y1)) || \
( ((b1)->y1 >= (b2)->y2)) ) )
#define RedirectSend(pWin) \
((pWin->eventMask|wOtherEventMasks(pWin)) & SubstructureRedirectMask)
#define SubSend(pWin) \
((pWin->eventMask|wOtherEventMasks(pWin)) & SubstructureNotifyMask)
#define StrSend(pWin) \
((pWin->eventMask|wOtherEventMasks(pWin)) & StructureNotifyMask)
#define SubStrSend(pWin,pParent) (StrSend(pWin) || SubSend(pParent))
#ifdef DEBUG
/******
* PrintWindowTree
* For debugging only
******/
int
PrintChildren(WindowPtr p1, int indent)
{
WindowPtr p2;
int i;
while (p1) {
p2 = p1->firstChild;
for (i = 0; i < indent; i++)
ErrorF(" ");
ErrorF("%x\n", p1->drawable.id);
miPrintRegion(&p1->clipList);
PrintChildren(p2, indent + 4);
p1 = p1->nextSib;
}
}
PrintWindowTree()
{
int i;
WindowPtr pWin, p1;
for (i = 0; i < screenInfo.numScreens; i++) {
ErrorF("WINDOW %d\n", i);
pWin = WindowTable[i];
miPrintRegion(&pWin->clipList);
p1 = pWin->firstChild;
PrintChildren(p1, 4);
}
}
#endif
_X_EXPORT int
TraverseTree(register 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.
*****/
_X_EXPORT int
WalkTree(ScreenPtr pScreen, VisitWindowProcPtr func, pointer data)
{
return (TraverseTree(WindowTable[pScreen->myNum], func, data));
}
/* hack for forcing backing store on all windows */
static const int defaultBackingStore = NotUseful;
static void
SetWindowToDefaults(register WindowPtr pWin)
{
pWin->prevSib = NullWindow;
pWin->firstChild = NullWindow;
pWin->lastChild = NullWindow;
pWin->valdata = (ValidatePtr) NULL;
pWin->optional = (WindowOptPtr) NULL;
pWin->cursorIsNone = TRUE;
pWin->backingStore = NotUseful;
pWin->DIXsaveUnder = FALSE;
pWin->backStorage = (pointer) NULL;
pWin->mapped = FALSE; /* off */
pWin->realized = FALSE; /* off */
pWin->viewable = FALSE;
pWin->visibility = VisibilityNotViewable;
pWin->overrideRedirect = FALSE;
pWin->saveUnder = FALSE;
pWin->bitGravity = ForgetGravity;
pWin->winGravity = NorthWestGravity;
pWin->eventMask = 0;
pWin->deliverableEvents = 0;
pWin->dontPropagate = 0;
pWin->forcedBS = FALSE;
#ifdef NEED_DBE_BUF_BITS
pWin->srcBuffer = DBE_FRONT_BUFFER;
pWin->dstBuffer = DBE_FRONT_BUFFER;
#endif
}
static void
MakeRootTile(WindowPtr pWin)
{
ScreenPtr pScreen = pWin->drawable.pScreen;
GCPtr pGC;
unsigned char back[128];
int len = BitmapBytePad(sizeof(long));
const unsigned char *from;
unsigned char *to;
int i, j;
pWin->background.pixmap = (*pScreen->CreatePixmap) (pScreen, 4, 4,
pScreen->rootDepth);
pWin->backgroundState = BackgroundPixmap;
pGC = GetScratchGC(pScreen->rootDepth, pScreen);
if (!pWin->background.pixmap || !pGC)
FatalError("could not create root tile");
{
CARD32 attributes[2];
attributes[0] = pScreen->whitePixel;
attributes[1] = pScreen->blackPixel;
(void) ChangeGC(pGC, GCForeground | GCBackground, attributes);
}
ValidateGC((DrawablePtr) pWin->background.pixmap, pGC);
from = (screenInfo.bitmapBitOrder == LSBFirst) ? _back_lsb : _back_msb;
to = back;
for (i = 4; i > 0; i--, from++)
for (j = len; j > 0; j--)
*to++ = *from;
(*pGC->ops->PutImage) ((DrawablePtr) pWin->background.pixmap, pGC, 1,
0, 0, len, 4, 0, XYBitmap, (char *) back);
FreeScratchGC(pGC);
}
WindowPtr
AllocateWindow(ScreenPtr pScreen)
{
WindowPtr pWin;
char *ptr;
DevUnion *ppriv;
unsigned *sizes;
unsigned size;
int i;
pWin = malloc(pScreen->totalWindowSize);
if (pWin) {
ppriv = (DevUnion *) (pWin + 1);
pWin->devPrivates = ppriv;
sizes = pScreen->WindowPrivateSizes;
ptr = (char *) (ppriv + pScreen->WindowPrivateLen);
for (i = pScreen->WindowPrivateLen; --i >= 0; ppriv++, sizes++) {
if ((size = *sizes)) {
ppriv->ptr = (pointer) ptr;
ptr += size;
}
else
ppriv->ptr = (pointer) NULL;
}
#if _XSERVER64
pWin->drawable.pad0 = 0;
pWin->drawable.pad1 = 0;
#endif
}
return pWin;
}
/*****
* CreateRootWindow
* Makes a window at initialization time for specified screen
*****/
Bool
CreateRootWindow(ScreenPtr pScreen)
{
WindowPtr pWin;
BoxRec box;
PixmapFormatRec *format;
pWin = AllocateWindow(pScreen);
if (!pWin)
return FALSE;
savedScreenInfo[pScreen->myNum].pWindow = NULL;
savedScreenInfo[pScreen->myNum].wid = FakeClientID(0);
savedScreenInfo[pScreen->myNum].ExternalScreenSaver = NULL;
screenIsSaved = SCREEN_SAVER_OFF;
WindowTable[pScreen->myNum] = pWin;
pWin->drawable.pScreen = pScreen;
pWin->drawable.type = DRAWABLE_WINDOW;
pWin->drawable.depth = pScreen->rootDepth;
for (format = screenInfo.formats;
format->depth != pScreen->rootDepth; format++);
pWin->drawable.bitsPerPixel = format->bitsPerPixel;
pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER;
pWin->parent = NullWindow;
SetWindowToDefaults(pWin);
pWin->optional = 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->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;
BoxRec *boxptr = &box;
REGION_INIT(&pWin->clipList, boxptr, 1);
REGION_INIT(&pWin->winSize, boxptr, 1);
REGION_INIT(&pWin->borderSize, boxptr, 1);
REGION_INIT(&pWin->borderClip, boxptr, 1);
pWin->drawable.class = InputOutput;
pWin->optional->visual = pScreen->rootVisual;
pWin->backgroundState = BackgroundPixel;
pWin->background.pixel = pScreen->whitePixel;
pWin->borderIsPixel = TRUE;
pWin->border.pixel = pScreen->blackPixel;
pWin->borderWidth = 0;
if (!AddResource(pWin->drawable.id, RT_WINDOW, (pointer) pWin))
return FALSE;
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 (!blackRoot && !whiteRoot) {
MakeRootTile(pWin);
backFlag |= CWBackPixmap;
}
else {
if (blackRoot)
pWin->background.pixel = pScreen->blackPixel;
else
pWin->background.pixel = pScreen->whitePixel;
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.
*/
void
ClippedRegionFromBox(register WindowPtr pWin, RegionPtr Rgn,
register int x, register int y,
register int w, register int h)
{
BoxRec box;
box = *(REGION_EXTENTS(&pWin->winSize));
/* we do these calculations to avoid overflows */
if (x > box.x1)
box.x1 = x;
if (y > box.y1)
box.y1 = y;
x += w;
if (x < box.x2)
box.x2 = x;
y += h;
if (y < box.y2)
box.y2 = y;
if (box.x1 > box.x2)
box.x2 = box.x1;
if (box.y1 > box.y2)
box.y2 = box.y1;
REGION_RESET(Rgn, &box);
REGION_INTERSECT(Rgn, Rgn, &pWin->winSize);
}
static RealChildHeadProc realChildHeadProc = NULL;
void
RegisterRealChildHeadProc(RealChildHeadProc proc)
{
realChildHeadProc = proc;
}
WindowPtr
RealChildHead(register WindowPtr pWin)
{
if (realChildHeadProc) {
return realChildHeadProc(pWin);
}
if (!pWin->parent &&
(screenIsSaved == SCREEN_SAVER_ON) &&
(HasSaverWindow(pWin->drawable.pScreen->myNum)))
return (pWin->firstChild);
else
return (NullWindow);
}
/*****
* CreateWindow
* Makes a window in response to client request
*****/
_X_EXPORT WindowPtr
CreateWindow(Window wid, register WindowPtr pParent, int x, int y, unsigned w,
unsigned h, unsigned bw, unsigned class, register Mask vmask,
XID *vlist, int depth, ClientPtr client, VisualID visual,
int *error)
{
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 = AllocateWindow(pScreen);
if (!pWin) {
*error = BadAlloc;
return NullWindow;
}
pWin->drawable = pParent->drawable;
pWin->drawable.depth = depth;
if (depth == pParent->drawable.depth)
pWin->drawable.bitsPerPixel = pParent->drawable.bitsPerPixel;
else {
for (format = screenInfo.formats; format->depth != depth; format++);
pWin->drawable.bitsPerPixel = format->bitsPerPixel;
}
if (class == InputOnly)
pWin->drawable.type = (short) UNDRAWABLE_WINDOW;
pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER;
pWin->drawable.id = wid;
pWin->drawable.class = class;
pWin->parent = pParent;
SetWindowToDefaults(pWin);
if (visual != ancwopt->visual) {
if (!MakeWindowOptional(pWin)) {
free(pWin);
*error = BadAlloc;
return NullWindow;
}
pWin->optional->visual = visual;
pWin->optional->colormap = None;
}
pWin->borderWidth = bw;
pWin->backgroundState = None;
pWin->borderIsPixel = pParent->borderIsPixel;
pWin->border = pParent->border;
if (pWin->borderIsPixel == FALSE)
pWin->border.pixmap->refcnt++;
pWin->origin.x = x + (int) bw;
pWin->origin.y = y + (int) bw;
pWin->drawable.width = w;
pWin->drawable.height = h;
pWin->drawable.x = pParent->drawable.x + x + (int) bw;
pWin->drawable.y = pParent->drawable.y + y + (int) bw;
/* set up clip list correctly for unobscured WindowPtr */
REGION_NULL(&pWin->clipList);
REGION_NULL(&pWin->borderClip);
REGION_NULL(&pWin->winSize);
REGION_NULL(&pWin->borderSize);
pHead = RealChildHead(pParent);
if (pHead) {
pWin->nextSib = pHead->nextSib;
if (pHead->nextSib)
pHead->nextSib->prevSib = pWin;
else
pParent->lastChild = pWin;
pHead->nextSib = pWin;
pWin->prevSib = pHead;
}
else {
pWin->nextSib = pParent->firstChild;
if (pParent->firstChild)
pParent->firstChild->prevSib = pWin;
else
pParent->lastChild = pWin;
pParent->firstChild = pWin;
}
SetWinSize(pWin);
SetBorderSize(pWin);
/* We SHOULD check for an error value here XXX */
if (!(*pScreen->CreateWindow) (pWin)) {
*error = BadAlloc;
DeleteWindow(pWin, None);
return NullWindow;
}
/* We SHOULD check for an error value here XXX */
(*pScreen->PositionWindow) (pWin, pWin->drawable.x, pWin->drawable.y);
if (!(vmask & CWEventMask))
RecalculateDeliverableEvents(pWin);
if (vmask)
*error = ChangeWindowAttributes(pWin, vmask, vlist, wClient(pWin));
else
*error = Success;
if (*error != Success) {
DeleteWindow(pWin, None);
return NullWindow;
}
if (!(vmask & CWBackingStore) && (defaultBackingStore != NotUseful)) {
XID value = defaultBackingStore;
(void) ChangeWindowAttributes(pWin, CWBackingStore, &value,
wClient(pWin));
pWin->forcedBS = TRUE;
}
if (SubSend(pParent)) {
event.u.u.type = CreateNotify;
event.u.createNotify.window = wid;
event.u.createNotify.parent = pParent->drawable.id;
event.u.createNotify.x = x;
event.u.createNotify.y = y;
event.u.createNotify.width = w;
event.u.createNotify.height = h;
event.u.createNotify.borderWidth = bw;
event.u.createNotify.override = pWin->overrideRedirect;
DeliverEvents(pParent, &event, 1, NullWindow);
}
return pWin;
}
static void
FreeWindowResources(register WindowPtr pWin)
{
ScreenPtr pScreen = pWin->drawable.pScreen;
DeleteWindowFromAnySaveSet(pWin);
DeleteWindowFromAnySelections(pWin);
DeleteWindowFromAnyEvents(pWin, TRUE);
REGION_UNINIT(&pWin->clipList);
REGION_UNINIT(&pWin->winSize);
REGION_UNINIT(&pWin->borderClip);
REGION_UNINIT(&pWin->borderSize);
if (wBoundingShape(pWin))
REGION_DESTROY(wBoundingShape(pWin));
if (wClipShape(pWin))
REGION_DESTROY(wClipShape(pWin));
if (wInputShape(pWin))
REGION_DESTROY(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)) {
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);
free(pChild);
if ((pChild = pSib))
break;
pChild = pParent;
pChild->firstChild = NullWindow;
pChild->lastChild = NullWindow;
if (pChild == pWin)
return;
}
}
}
/*****
* DeleteWindow
* Deletes child of window then window itself
* If wid is None, don't send any events
*****/
int
DeleteWindow(pointer value, XID wid)
{
WindowPtr pParent;
WindowPtr pWin = (WindowPtr) value;
xEvent event;
UnmapWindow(pWin, FALSE);
CrushTree(pWin);
pParent = pWin->parent;
if (wid && pParent && SubStrSend(pWin, pParent)) {
event.u.u.type = DestroyNotify;
event.u.destroyNotify.window = pWin->drawable.id;
DeliverEvents(pWin, &event, 1, NullWindow);
}
FreeWindowResources(pWin);
if (pParent) {
if (pParent->firstChild == pWin)
pParent->firstChild = pWin->nextSib;
if (pParent->lastChild == pWin)
pParent->lastChild = pWin->prevSib;
if (pWin->nextSib)
pWin->nextSib->prevSib = pWin->prevSib;
if (pWin->prevSib)
pWin->prevSib->nextSib = pWin->nextSib;
}
free(pWin);
return Success;
}
void
DestroySubwindows(register WindowPtr pWin, ClientPtr client)
{
/* XXX
* The protocol is quite clear that each window should be
* destroyed in turn, however, unmapping all of the first
* eliminates most of the calls to ValidateTree. So,
* this implementation is incorrect in that all of the
* UnmapNotifies occur before all of the DestroyNotifies.
* If you care, simply delete the call to UnmapSubwindows.
*/
UnmapSubwindows(pWin);
while (pWin->lastChild)
FreeResource(pWin->lastChild->drawable.id, RT_NONE);
}
#define DeviceEventMasks (KeyPressMask | KeyReleaseMask | ButtonPressMask | \
ButtonReleaseMask | PointerMotionMask)
/*****
* ChangeWindowAttributes
*
* The value-mask specifies which attributes are to be changed; the
* value-list contains one value for each one bit in the mask, from least
* to most significant bit in the mask.
*****/
_X_EXPORT int
ChangeWindowAttributes(register WindowPtr pWin, Mask vmask, XID *vlist,
ClientPtr client)
{
Mask index2;
XID *pVlist;
PixmapPtr pPixmap;
Pixmap pixID;
CursorPtr pCursor, pOldCursor;
Cursor cursorID;
WindowPtr pChild;
Colormap cmap;
ColormapPtr pCmap;
xEvent xE;
int result;
ScreenPtr pScreen;
Mask vmaskCopy = 0;
Mask tmask;
unsigned int val;
int error;
Bool checkOptional = FALSE;
Bool 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)
MakeRootTile(pWin);
else
pWin->backgroundState = None;
}
else if (pixID == ParentRelative) {
if (pWin->parent &&
pWin->drawable.depth != pWin->parent->drawable.depth) {
error = BadMatch;
goto PatchUp;
}
if (pWin->backgroundState == BackgroundPixmap)
(*pScreen->DestroyPixmap) (pWin->background.pixmap);
if (!pWin->parent)
MakeRootTile(pWin);
else
pWin->backgroundState = ParentRelative;
borderRelative = TRUE;
/* Note that the parent's backgroundTile's refcnt is NOT
* incremented. */
}
else {
pPixmap = (PixmapPtr) SecurityLookupIDByType(client, pixID,
RT_PIXMAP,
SecurityReadAccess);
if (pPixmap != (PixmapPtr) NULL) {
if ((pPixmap->drawable.depth != pWin->drawable.depth) ||
(pPixmap->drawable.pScreen != pScreen)) {
error = BadMatch;
goto PatchUp;
}
if (pWin->backgroundState == BackgroundPixmap)
(*pScreen->DestroyPixmap) (pWin->background.pixmap);
pWin->backgroundState = BackgroundPixmap;
pWin->background.pixmap = pPixmap;
pPixmap->refcnt++;
}
else {
error = BadPixmap;
client->errorValue = pixID;
goto PatchUp;
}
}
break;
case CWBackPixel:
if (pWin->backgroundState == ParentRelative)
borderRelative = TRUE;
if (pWin->backgroundState == BackgroundPixmap)
(*pScreen->DestroyPixmap) (pWin->background.pixmap);
pWin->backgroundState = BackgroundPixel;
pWin->background.pixel = (CARD32) *pVlist;
/* background pixel overrides background pixmap,
so don't let the ddx layer see both bits */
vmaskCopy &= ~CWBackPixmap;
pVlist++;
break;
case CWBorderPixmap:
pixID = (Pixmap) * pVlist;
pVlist++;
if (pixID == CopyFromParent) {
if (!pWin->parent ||
(pWin->drawable.depth != pWin->parent->drawable.depth)) {
error = BadMatch;
goto PatchUp;
}
if (pWin->borderIsPixel == FALSE)
(*pScreen->DestroyPixmap) (pWin->border.pixmap);
pWin->border = pWin->parent->border;
if ((pWin->borderIsPixel = pWin->parent->borderIsPixel) == TRUE) {
index2 = CWBorderPixel;
}
else {
pWin->parent->border.pixmap->refcnt++;
}
}
else {
pPixmap = (PixmapPtr) SecurityLookupIDByType(client, pixID,
RT_PIXMAP,
SecurityReadAccess);
if (pPixmap) {
if ((pPixmap->drawable.depth != pWin->drawable.depth) ||
(pPixmap->drawable.pScreen != pScreen)) {
error = BadMatch;
goto PatchUp;
}
if (pWin->borderIsPixel == FALSE)
(*pScreen->DestroyPixmap) (pWin->border.pixmap);
pWin->borderIsPixel = FALSE;
pWin->border.pixmap = pPixmap;
pPixmap->refcnt++;
}
else {
error = BadPixmap;
client->errorValue = pixID;
goto PatchUp;
}
}
break;
case CWBorderPixel:
if (pWin->borderIsPixel == FALSE)
(*pScreen->DestroyPixmap) (pWin->border.pixmap);
pWin->borderIsPixel = TRUE;
pWin->border.pixel = (CARD32) *pVlist;
/* border pixel overrides border pixmap,
so don't let the ddx layer see both bits */
vmaskCopy &= ~CWBorderPixmap;
pVlist++;
break;
case CWBitGravity:
val = (CARD8) *pVlist;
pVlist++;
if (val > StaticGravity) {
error = BadValue;
client->errorValue = val;
goto PatchUp;
}
pWin->bitGravity = val;
break;
case CWWinGravity:
val = (CARD8) *pVlist;
pVlist++;
if (val > StaticGravity) {
error = BadValue;
client->errorValue = val;
goto PatchUp;
}
pWin->winGravity = val;
break;
case CWBackingStore:
val = (CARD8) *pVlist;
pVlist++;
if ((val != NotUseful) && (val != WhenMapped) && (val != Always)) {
error = BadValue;
client->errorValue = val;
goto PatchUp;
}
pWin->backingStore = val;
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:
result = EventSelectForWindow(pWin, client, (Mask) *pVlist);
if (result) {
error = result;
goto PatchUp;
}
pVlist++;
break;
case CWDontPropagate:
result = EventSuppressForWindow(pWin, client, (Mask) *pVlist,
&checkOptional);
if (result) {
error = result;
goto PatchUp;
}
pVlist++;
break;
case CWOverrideRedirect:
val = (BOOL) * pVlist;
pVlist++;
if ((val != xTrue) && (val != xFalse)) {
error = BadValue;
client->errorValue = val;
goto PatchUp;
}
pWin->overrideRedirect = val;
break;
case CWColormap:
cmap = (Colormap) * pVlist;
pVlist++;
if (cmap == CopyFromParent) {
if (pWin->parent &&
(!pWin->optional ||
pWin->optional->visual == wVisual(pWin->parent))) {
cmap = wColormap(pWin->parent);
}
else
cmap = None;
}
if (cmap == None) {
error = BadMatch;
goto PatchUp;
}
pCmap = (ColormapPtr) SecurityLookupIDByType(client, cmap,
RT_COLORMAP,
SecurityReadAccess);
if (!pCmap) {
error = BadColor;
client->errorVa