/***********************************************************
Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
and the Massachusetts Institute of Technology, Cambridge, 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 names of Digital or MIT 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.

******************************************************************/

/* $Header: window.c,v 1.144 87/06/16 15:27:22 toddb Exp $ */

#include "X.h"
#define NEED←REPLIES
#define NEED←EVENTS
#include "Xproto.h"
#include "misc.h"
#include "scrnintstr.h"
#include "os.h"
#include "regionstr.h"
#include "windowstr.h"
#include "input.h"
#include "resource.h"
#include "colormapst.h"
#include "cursorstr.h"
#include "dixstruct.h"
#include "gcstruct.h"
#include "opaque.h"

/******
 * Window stuff for server 
 *
 *    CreateRootWindow, CreateWindow, ChangeWindowAttributes,
 *    GetWindowAttributes, DeleteWindow, DestroySubWindows,
 *    HandleSaveSet, ReparentWindow, MapWindow, MapSubWindows,
 *    UnmapWindow, UnmapSubWindows, ConfigureWindow, CirculateWindow,
 *
 ******/

int ←back[16] = {0x8888, 0x2222, 0x4444, 0x1111,
			 0x8888, 0x2222, 0x4444, 0x1111,
			 0x8888, 0x2222, 0x4444, 0x1111,
			 0x8888, 0x2222, 0x4444, 0x1111};

typedef struct ←ScreenSaverStuff {
    WindowPtr pWindow;
    XID       wid;
    XID       cid;
    BYTE      blanked;
} ScreenSaverStuffRec;

#define SCREEN←IS←BLANKED   0
#define SCREEN←IS←TILED     1
#define SCREEN←ISNT←SAVED   2

extern int ScreenSaverBlanking, ScreenSaverAllowExposures;
int screenIsSaved = FALSE;

ScreenSaverStuffRec savedScreenInfo[MAXSCREENS];

extern WindowRec WindowTable[];
extern void (* ReplySwapVector[256]) ();


#define INPUTONLY←LEGAL←MASK (CWWinGravity | CWEventMask | \
			      CWDontPropagate | CWCursor )

/******
 * PrintWindowTree
 *    For debugging only
 ******/

int
PrintChildren(p1, indent)
    WindowPtr p1;
    int indent;
{
    WindowPtr p2;
    int i;
 
    while (p1) 
    {
        p2 = p1->firstChild;
        for (i=0; i<indent; i++) ErrorF( " ");
	ErrorF( "%x\n", p1->wid);
        miprintRects(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];
        miprintRects(pWin->clipList); 
	p1 = pWin->firstChild;
	PrintChildren(p1, 4);
    }
}


/*****
 * 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
TraverseTree(pWin, func, data)
    WindowPtr pWin;
    int (*func)();
    pointer data;
{
    int result;
    WindowPtr pChild;

    if (!pWin) 
       return(WT←NOMATCH);
    result = (* func)(pWin, data);

    if (result == WT←STOPWALKING) 
        return(WT←STOPWALKING);

    if (result == WT←WALKCHILDREN) 
        for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib)
            if (TraverseTree(pChild, func,data) ==  WT←STOPWALKING) 
                return(WT←STOPWALKING);

    return(WT←NOMATCH);
}

int
WalkTree(pScreen, func, data)
    ScreenPtr pScreen;
    int (* func)();
    char *data;
{
    WindowPtr pWin;
    
    pWin = &WindowTable[pScreen->myNum];
    return(TraverseTree(pWin, func, (pointer)data));
}

/*****
 *  DoObscures(pWin)
 *    
 *****/

void
DoObscures(pWin)
    WindowPtr pWin;
{
    WindowPtr pSib;

    if (!pWin->backStorage || (pWin->backingStore == NotUseful))
        return ;
    if ((* pWin->drawable.pScreen->RegionNotEmpty)(pWin->backStorage->obscured))
    {
        (*pWin->backStorage->SaveDoomedAreas)( pWin );
        (* pWin->drawable.pScreen->RegionEmpty)(pWin->backStorage->obscured);
    }
    pSib = pWin->firstChild;
    while (pSib)
    {
        DoObscures(pSib);
	pSib = pSib->nextSib;
    }
}

/*****
 *  HandleExposures(pWin)
 *    starting at pWin, draw background in any windows that have exposure
 *    regions, translate the regions, restore any backing store,
 *    and then send any regions stille xposed to the client
 *****/

/* NOTE
   the order of painting and restoration needs to be different,
to avoid an extra repaint of the background. --rgd
*/

void
HandleExposures(pWin)
    WindowPtr pWin;
{
    WindowPtr pSib;

    if ((* pWin->drawable.pScreen->RegionNotEmpty)(pWin->borderExposed))
    {
	(*pWin->PaintWindowBorder)(pWin, pWin->borderExposed, PW←BORDER);
	(* pWin->drawable.pScreen->RegionEmpty)(pWin->borderExposed);
    }
    (* pWin->drawable.pScreen->WindowExposures)(pWin);
    pSib = pWin->firstChild;
    while (pSib)
    {
        HandleExposures(pSib);
	pSib = pSib->nextSib;
    }
}


static void
InitProcedures(pWin)
    WindowPtr pWin;
{
#ifdef DEBUG
    void (**j) ();
    for (j = &pWin->PaintWindowBackground;
         j < &pWin->ClearToBackground; j++ )
        *j = (void (*) ())NotImplemented;
#endif /* DEBUG */

}

static void
SetWindowToDefaults(pWin, pScreen)
    WindowPtr pWin;
    ScreenPtr pScreen;
{
    pWin->prevSib = NullWindow;
    pWin->firstChild = NullWindow;
    pWin->lastChild = NullWindow;

/*    pWin->drawable.lastGC = (pointer)NULL; */
    pWin->userProps = (PropertyPtr)NULL;

    pWin->backingStore = NotUseful;
    pWin->backStorage = (BackingStorePtr) NULL;

    pWin->mapped = 0;           /* off */
    pWin->realized = 0;         /* off */
    pWin->viewable = 0;
    pWin->overrideRedirect = FALSE;
    pWin->saveUnder = FALSE;

    pWin->bitGravity = ForgetGravity; 
    pWin->winGravity = NorthWestGravity;
    pWin->backingBitPlanes = -1;
    pWin->backingPixel = 0;

    pWin->eventMask = 0;
    pWin->dontPropagateMask = 0;
    pWin->allEventMasks = 0;
    pWin->deliverableEvents = 0;

    pWin->otherClients = (pointer)NULL;
    pWin->passiveGrabs = (pointer)NULL;
    pWin->colormap = (Colormap)None;            /* None */

    pWin->exposed = (* pScreen->RegionCreate)((BoxPtr)NULL, 1);
    pWin->borderExposed = (* pScreen->RegionCreate)((BoxPtr)NULL, 1);

}

static void
MakeRootCursor(pWin)
    WindowPtr pWin;
{
    unsigned char *srcbits, *mskbits;
    int i;
    if (rootCursor)
    {
	pWin->cursor = rootCursor;
	rootCursor->refcnt++;
    }
    else
    {
	CursorMetricRec cm;
	cm.width=32;
	cm.height=16;
	cm.xhot=8;
	cm.yhot=8;

        srcbits = (unsigned char *)Xalloc( PixmapBytePad(32, 1)*16); 
        mskbits = (unsigned char *)Xalloc( PixmapBytePad(32, 1)*16); 
        for (i=0; i<PixmapBytePad(32, 1)*16; i++)
	{
	    srcbits[i] = mskbits[i] = 0xff;
	}
	pWin->cursor = AllocCursor( srcbits, mskbits,	&cm,
		    ~0, ~0, ~0, 0, 0, 0);
    }
}

static void
MakeRootTile(pWin)
    WindowPtr pWin;
{
    ScreenPtr pScreen = pWin->drawable.pScreen;
    GCPtr pGC;

    pWin->backgroundTile = (*pScreen->CreatePixmap)(pScreen, 16, 16, 
			        pScreen->rootDepth);

    pGC = GetScratchGC(pScreen->rootDepth, pScreen);

    {
	CARD32 attributes[3];

	attributes[0] = pScreen->whitePixel;
	attributes[1] = pScreen->blackPixel;
	attributes[2] = FALSE;

	ChangeGC(pGC, GCForeground | GCBackground | GCGraphicsExposures,
	     attributes);
   }

   ValidateGC((DrawablePtr)pWin->backgroundTile, pGC);

   (*pGC->PutImage)(pWin->backgroundTile, pGC, pScreen->rootDepth,
	            0, 0, 16, 16, 0, XYBitmap, ←back);

    pWin->backgroundTile->refcnt++;
    FreeScratchGC(pGC);

}

/*****
 * CreateRootWindow
 *    Makes a window at initialization time for specified screen
 *****/

void
CreateRootWindow(screen)
    int		screen;
{
    WindowPtr	pWin;
    BoxRec	box;
    ScreenPtr	pScreen;
    int		i;

    savedScreenInfo[screen].pWindow = NULL;
    savedScreenInfo[screen].wid = FakeClientID(0);
    savedScreenInfo[screen].cid = FakeClientID(0);
    screenIsSaved = SCREEN←SAVER←OFF;
    
    pWin = &WindowTable[screen];
    pScreen = &screenInfo.screen[screen];
    InitProcedures(pWin);

    pWin->drawable.pScreen = pScreen;
    pWin->drawable.type = DRAWABLE←WINDOW;

    pWin->drawable.depth = pScreen->rootDepth;

    pWin->parent = NullWindow;
    SetWindowToDefaults(pWin, pScreen);
    pWin->nextSib = NullWindow;

    MakeRootCursor(pWin);

    pWin->client = serverClient;        /* since belongs to server */
    pWin->wid = FakeClientID(0);

    pWin->clientWinSize.x = pWin->clientWinSize.y = 0;
    pWin->clientWinSize.height = screenInfo.screen[screen].height;
    pWin->clientWinSize.width = screenInfo.screen[screen].width;
    pWin->absCorner.x = pWin->absCorner.y = 0;
    pWin->oldAbsCorner.x = pWin->oldAbsCorner.y = 0;

    box.x1 = 0;
    box.y1 = 0;
    box.x2 = screenInfo.screen[screen].width ;
    box.y2 = screenInfo.screen[screen].height;
    pWin->clipList = (* pScreen->RegionCreate)(&box, 1); 
    pWin->winSize = (* pScreen->RegionCreate)(&box, 1);
    pWin->borderSize = (* pScreen->RegionCreate)(&box, 1);
    pWin->borderClip = (* pScreen->RegionCreate)(&box, 1); 

    pWin->class = InputOutput;
    pWin->visual = pScreen->rootVisual;

    pWin->backgroundPixel = pScreen->whitePixel;

    pWin->borderPixel = pScreen->blackPixel;
    pWin->borderWidth = 0;

    AddResource(pWin->wid, RT←WINDOW, (pointer)pWin, DeleteWindow, RC←CORE);

    MakeRootTile(pWin);
    pWin->borderTile = (PixmapPtr)USE←BORDER←PIXEL;

    /* re-validate GC for use with root Window */

    (*pScreen->CreateWindow)(pWin);
    MapWindow(pWin, DONT←HANDLE←EXPOSURES, BITS←DISCARDED, 
	      DONT←SEND←NOTIFICATION, serverClient);

    (*pScreen->ChangeWindowAttributes)(pWin, (long)CWBackPixmap | CWBorderPixel);

    (*pWin->PaintWindowBackground)(pWin, pWin->clipList, PW←BACKGROUND);
    EventSelectForWindow(pWin, serverClient, (Mask) 0);
}

/*****
 * DestroyRootWindow
 *    Cleans up the root window at re-initialization time.
 *****/

void
DestroyRootWindow(screen)
    int	screen;
{
    WindowPtr pWin;

    pWin = &WindowTable[screen];
    bzero((char *)pWin, sizeof (WindowRec));
}

/*****
 * CreateWindow
 *    Makes a window in response to client request 
 *    XXX  What about depth of inputonly windows -- should be 0
 *****/

WindowPtr
CreateWindow(wid, pParent, x, y, w, h, bw, class, vmask, vlist, 
	     depth, client, visual, error)
    Window wid;
    WindowPtr pParent;    /* already looked up in table to do error checking*/
    short x,y;
    unsigned short w, h, bw;
    int class;
    long vmask;
    long *vlist;
    int depth;
    ClientPtr client;
    VisualID visual;
    int *error;
{
    WindowPtr pWin;
    ScreenPtr pScreen;
    BoxRec box;
    xEvent event;
    int idepth, ivisual;
    Bool fOK;
    DepthPtr pDepth;

    if ((class != InputOnly) && (pParent->class == InputOnly))
    {
        *error = BadMatch;
	return (WindowPtr)NULL;
    }

    if ((class == InputOnly) && ((bw != 0) || (depth != 0)))
    {
        *error = BadMatch;
	return (WindowPtr)NULL;
    }

    pScreen = pParent->drawable.pScreen;
    /* Find out if the depth and visual are acceptable for this Screen */
    fOK = FALSE;
    if ((class == InputOutput && depth == 0) || 
	(class == InputOnly) || (class == CopyFromParent))
        depth = pParent->drawable.depth;

    if (visual == CopyFromParent)
        visual = pParent->visual;
    else
    {
        for(idepth = 0; idepth < pScreen->numDepths; idepth++)
        {
	    pDepth = (DepthPtr) &pScreen->allowedDepths[idepth];
	    if (depth == pDepth->depth)
    	    {
		for (ivisual = 0; ivisual < pDepth->numVids; ivisual++)
	        {
		    if (visual == pDepth->vids[ivisual])
		        fOK = TRUE;
	        }
	    }
        }
        if (!fOK)
        {
            *error = BadMatch;
	    return (WindowPtr)NULL;
        }
    }

    pWin = (WindowPtr ) Xalloc( sizeof(WindowRec) );
    if (!pWin) 
    {
	*error = BadAlloc;
	return (WindowPtr)NULL;
    }
    InitProcedures(pWin);
    pWin->drawable = pParent->drawable;
    if (class == InputOutput)
	pWin->drawable.depth = depth;
    else if (class == InputOnly)
        pWin->drawable.type = UNDRAWABLE←WINDOW;

    pWin->wid = wid;
    pWin->client = client;
    pWin->visual = visual;

    SetWindowToDefaults(pWin, pScreen);

    pWin->cursor = (CursorPtr)None;

    if (class == CopyFromParent)
	pWin->class = pParent->class;
    else
	pWin->class = class;

    pWin->borderWidth = bw;
    pWin->backgroundTile = (PixmapPtr)None;
    pWin->backgroundPixel = pScreen->whitePixel;

    if ((pWin->drawable.depth != pParent->drawable.depth) &&
	(! (vmask & (CWBorderPixmap | CWBorderPixel))))
    {
        Xfree(pWin);
        *error = BadMatch;
        return (WindowPtr)NULL;
    }
    if (vmask & (CWBorderPixmap | CWBorderPixel))
		/* it will just get fixed in ChangeWindowAttributes */
        pWin->borderTile = (PixmapPtr)NULL;
    else
    {                              /* this is WRONG!!         XXX */
	                           /* should be actually copied */
        pWin->borderTile = pParent->borderTile;   
        if (IS←VALID←PIXMAP(pParent->borderTile))
            pParent->borderTile->refcnt++;
    }
    pWin->borderPixel = pParent->borderPixel;
    pWin->visibility = VisibilityFullyObscured;
		
    pWin->clientWinSize.x = x + bw;
    pWin->clientWinSize.y = y + bw;
    pWin->clientWinSize.height = h;
    pWin->clientWinSize.width = w;
    pWin->absCorner.x = pWin->oldAbsCorner.x = pParent->absCorner.x + x + bw;
    pWin->absCorner.y = pWin->oldAbsCorner.y = pParent->absCorner.y + y + bw;

        /* set up clip list correctly for unobscured WindowPtr */
    pWin->clipList = (* pScreen->RegionCreate)((BoxPtr)NULL, 1);
    pWin->borderClip = (* pScreen->RegionCreate)((BoxPtr)NULL, 1);
    box.x1 = pWin->absCorner.x;
    box.y1 = pWin->absCorner.y;
    box.x2 = box.x1 + w;
    box.y2 = box.y1 + h;
    pWin->winSize = (* pScreen->RegionCreate)(&box, 1);
    (* pScreen->Intersect)(pWin->winSize, pWin->winSize,  pParent->winSize);
    if (bw)
    {
	box.x1 -= bw;
	box.y1 -= bw;
	box.x2 += bw;
	box.y2 += bw;
        pWin->borderSize = (* pScreen->RegionCreate)(&box, 1);
        (* pScreen->Intersect)(pWin->borderSize, pWin->borderSize, 
			       pParent->winSize);
    }
    else
    {
        pWin->borderSize = (* pScreen->RegionCreate)((BoxPtr)NULL, 1);
	(* pScreen->RegionCopy)(pWin->borderSize, pWin->winSize);
    }	

    pWin->parent = pParent;    
    if ((screenIsSaved == SCREEN←SAVER←ON)
	&& (pParent == &WindowTable[pScreen->myNum])
	&& (pParent->firstChild)
	&& (savedScreenInfo[pScreen->myNum].blanked == SCREEN←IS←TILED))
    {
	WindowPtr pFirst = pParent->firstChild;
	pWin->nextSib = pFirst->nextSib;
        if (pFirst->nextSib)
    	    pFirst->nextSib->prevSib = pWin;
	else
	    pParent->lastChild = pWin;
        pFirst->nextSib = pWin;
	pWin->prevSib = pFirst;
    }
    else
    {
        pWin->nextSib = pParent->firstChild;
        if (pParent->firstChild) 
	    pParent->firstChild->prevSib = pWin;
        else
            pParent->lastChild = pWin;
	pParent->firstChild = pWin;
    }

    (*pScreen->CreateWindow)(pWin);
    (*pScreen->PositionWindow)(pWin, pWin->absCorner.x, pWin->absCorner.y);
    if (! (vmask & CWEventMask))
        EventSelectForWindow(pWin, client, (Mask) 0);

    if (vmask)
        *error = ChangeWindowAttributes(pWin, (unsigned long)vmask, vlist, pWin->client);
    else
        *error = Success;

    WindowHasNewCursor( pWin);

    event.u.u.type = CreateNotify;
    event.u.createNotify.window = wid;
    event.u.createNotify.parent = pParent->wid;
    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(pWin->parent, &event, 1, NullWindow);		

    return pWin;
}

/*****
 *  DeleteWindow
 *       Deletes child of window then window itself
 *****/

static void
FreeWindowResources(pWin)
    WindowPtr pWin;
{
    ScreenPtr pScreen;
    void (* proc)();

    pScreen = pWin->drawable.pScreen;

    DeleteWindowFromAnySaveSet((pointer)pWin);
    DeleteWindowFromAnySelections(pWin);
    DeleteWindowFromAnyEvents(pWin, TRUE);
    proc = pScreen->RegionDestroy;
    (* proc)(pWin->clipList);
    (* proc)(pWin->winSize);
    (* proc)(pWin->borderClip);
    (* proc)(pWin->borderSize);
    (* proc)(pWin->exposed);
    (* proc)(pWin->borderExposed);
    if (pWin->backStorage)
    {
        (* proc)(pWin->backStorage->obscured);
	Xfree(pWin->backStorage);
    }
    (* pScreen->DestroyPixmap)(pWin->borderTile);
    (* pScreen->DestroyPixmap)(pWin->backgroundTile);

    if (pWin->cursor != (CursorPtr)None)
        FreeCursor( pWin->cursor, 0);

    DeleteAllWindowProperties(pWin);
    (* pScreen->DestroyWindow)(pWin);
}

static void
CrushTree(pWin)
    WindowPtr pWin;
{
    WindowPtr pSib;
    xEvent event;

    if (!pWin) 
        return ;
    while (pWin) 
    {
	FreeResource(pWin->wid, RC←CORE);
	pSib = pWin->nextSib;
        pWin->realized = FALSE;
        pWin->viewable = FALSE;
        (* pWin->drawable.pScreen->UnrealizeWindow)(pWin);
	FreeWindowResources(pWin);

	CrushTree(pWin->firstChild);

	event.u.u.type = DestroyNotify;
       	event.u.destroyNotify.window = pWin->wid;
	DeliverEvents(pWin, &event, 1, NullWindow);		

	Xfree(pWin);
	pWin = pSib;
    }
}
	
DeleteWindow(pWin, wid)
    WindowPtr pWin;
    int wid;
{
    WindowPtr pParent;
    xEvent event;

    UnmapWindow(pWin, HANDLE←EXPOSURES, SEND←NOTIFICATION, FALSE);

    event.u.u.type = DestroyNotify;
    event.u.destroyNotify.window = pWin->wid;
    DeliverEvents(pWin, &event, 1, NullWindow);		

    CrushTree(pWin->firstChild);
    pParent = pWin->parent;
    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;
	Xfree(pWin);
    }
}

DestroySubwindows(pWin, client)
    WindowPtr pWin;
    ClientPtr client;
{
    WindowPtr pChild, pSib;
    xEvent event;

    if (!(pChild = pWin->lastChild))
        return;
    while (pChild) 
    {
	event.u.u.type = DestroyNotify;
	event.u.destroyNotify.window = pChild->wid;
	DeliverEvents(pChild, &event, 1, NullWindow);		
    
	pSib = pChild->prevSib;
	/* a little lazy evaluation, don't send exposes until all deleted */
	if (pSib != (WindowPtr )NULL)
	{
	    event.u.u.type = UnmapNotify;
	    event.u.unmapNotify.window = pWin->wid;
	    event.u.unmapNotify.fromConfigure = xFalse;
	    DeliverEvents(pWin, &event, 1, NullWindow);
	}
        else
        {
	    pChild->nextSib = (WindowPtr)NULL;
    	    UnmapWindow(pChild, HANDLE←EXPOSURES, SEND←NOTIFICATION, FALSE);
	}
	FreeResource(pChild->wid, RC←CORE);
	CrushTree(pChild->firstChild);
	FreeWindowResources(pChild);
	Xfree(pChild);
	pChild = pSib;
    }
    pWin->firstChild = (WindowPtr )NULL;
}


/*****
 *  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(pWin, vmask, vlist, client)
    WindowPtr pWin;
    unsigned long vmask;
    long *vlist;
    ClientPtr client;
{
    long index;
    long *pVlist;
    PixmapPtr pPixmap;
    Pixmap pixID;
    CursorPtr pCursor;
    Cursor cursorID;
    int result;
    ScreenPtr pScreen;
    unsigned long vmaskCopy = 0;
    int error;

    if ((pWin->class == InputOnly) && (vmask & (~INPUTONLY←LEGAL←MASK)))
        return BadMatch;

    error = Success;
    pScreen = pWin->drawable.pScreen;
    pVlist = vlist;
    while (vmask) 
    {
	index = ffs((long)vmask) - 1;
	vmask &= ~(index = (1 << index));
	switch (index) 
        {
	  case CWBackPixmap: 
	    pixID = (Pixmap )*pVlist;
	    pVlist++;
	    if (pixID == None)
	    {
		(* pScreen->DestroyPixmap)(pWin->backgroundTile);
		if (!pWin->parent)
                    MakeRootTile(pWin);
                else
                    pWin->backgroundTile = (PixmapPtr)NULL;
	    }
	    else if (pixID == ParentRelative)
	    {
		(* pScreen->DestroyPixmap)(pWin->backgroundTile);
		if (!pWin->parent)
		    MakeRootTile(pWin);
		else
	            pWin->backgroundTile = (PixmapPtr)ParentRelative;
		/* Note that the parent's backgroundTile's refcnt is NOT
		 * incremented. */
	    }
            else
	    {	
                pPixmap = (PixmapPtr)LookupID((long)pixID, RT←PIXMAP, RC←CORE);
                if (pPixmap)
		{
                    if  ((pPixmap->drawable.depth != pWin->drawable.depth) ||
			 (pPixmap->drawable.pScreen != pScreen))
		    {
                        error = BadMatch;
			goto PatchUp;
		    }
		    (* pScreen->DestroyPixmap)(pWin->backgroundTile); 
		    pWin->backgroundTile = pPixmap;
		    pPixmap->refcnt++;
		}
	        else 
		{
		    error = BadPixmap;
		    goto PatchUp;
		}
	    }
	    break;
	  case CWBackPixel: 
	    pWin->backgroundPixel = (CARD32 ) *pVlist;
	    (* pScreen->DestroyPixmap)(pWin->backgroundTile);
	    pWin->backgroundTile = (PixmapPtr)USE←BACKGROUND←PIXEL;
	    pVlist++;
	    break;
	  case CWBorderPixmap:
	    pixID = (Pixmap ) *pVlist;
	    pVlist++;
	    if (pixID == CopyFromParent)
	    {
		GCPtr pGC;
		PixmapPtr parentPixmap;
		if ((!pWin->parent) || (pWin->parent && 
		        	       (pWin->drawable.depth != 
					pWin->parent->drawable.depth)))
		{
		    error = BadMatch;
		    goto PatchUp;
		}
		(* pScreen->DestroyPixmap)(pWin->borderTile);
		parentPixmap = pWin->parent->borderTile;
		if (parentPixmap == (PixmapPtr)USE←BORDER←PIXEL)
		{
		    pWin->borderTile = (PixmapPtr)USE←BORDER←PIXEL;
		    pWin->borderPixel = pWin->parent->borderPixel;
		}
                else
		{
		    CARD32 attribute;

		    pPixmap = (* pWin->drawable.pScreen->CreatePixmap)
				(pWin->drawable.pScreen, parentPixmap->width,
				 parentPixmap->height, pWin->drawable.depth);
		    pGC = GetScratchGC(pWin->drawable.depth, 
				   pWin->drawable.pScreen);
			
		    attribute = GXcopy;
		    ChangeGC(pGC, GCFunction, &attribute);
		    ValidateGC((DrawablePtr)pPixmap, pGC);

		    (* pGC->CopyArea)(parentPixmap, pPixmap, pGC, 0, 0,
				       parentPixmap->width,
				       parentPixmap->height, 
				       pWin->drawable.depth,
				       0, 0);
		    pWin->borderTile = pPixmap;
		    FreeScratchGC(pGC);
		}
	    }
	    else
	    {	
		pPixmap = (PixmapPtr)LookupID((long)pixID, RT←PIXMAP, RC←CORE);
		if (pPixmap) 
		{
                    if  ((pPixmap->drawable.depth != pWin->drawable.depth) ||
			 (pPixmap->drawable.pScreen != pScreen))
		    {
			error = BadMatch;
			goto PatchUp;
		    }
		    (* pScreen->DestroyPixmap)(pWin->borderTile);
		    pWin->borderTile = pPixmap;
		    pPixmap->refcnt++;
		}
    	        else
		{
		    error = BadPixmap;
		    goto PatchUp;
		}
	    }
	    break;
	  case CWBorderPixel: 
            pWin->borderPixel = (CARD32) *pVlist;
	    (* pScreen->DestroyPixmap)(pWin->borderTile);	    
	    pWin->borderTile = (PixmapPtr)USE←BORDER←PIXEL;
	    pVlist++;
            break;
	  case CWBitGravity: 
            pWin->bitGravity = (CARD8 )*pVlist;
	    pVlist++;
	    break;
	  case CWWinGravity: 
            pWin->winGravity = (CARD8 )*pVlist;
	    pVlist++;
	    break;
	  case CWBackingStore: 
            pWin->backingStore = (CARD8 )*pVlist;
	    pVlist++;
	    break;
	  case CWBackingPlanes: 
	    pWin->backingBitPlanes = (CARD32) *pVlist;
	    pVlist++;
	    break;
	  case CWBackingPixel: 
            pWin->backingPixel = (CARD32)*pVlist;
	    pVlist++;
	    break;
	  case CWSaveUnder:
            pWin->saveUnder = (Bool) *pVlist;
	    pVlist++;
	    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);
	    if (result)
	    {
		error = result;
		goto PatchUp;
	    }
	    pVlist++;
	    break;
	  case CWOverrideRedirect:
            pWin->overrideRedirect = (Bool ) *pVlist;
	    pVlist++;
	    break;
	  case CWColormap:
	    {
            Colormap	cmap;
	    ColormapPtr	pCmap;
	    xEvent	xE;
	    WindowPtr	pWinT;

	    cmap = (Colormap ) *pVlist;
	    pWinT = pWin;
	    while(cmap == CopyFromParent || cmap == CopyFromParent)
	    {
		if(pWinT->parent)
		{
		    if((pWinT->parent->colormap != CopyFromParent) &&
		      (pWinT->parent->colormap != CopyFromParent))
		    {
			cmap = pWinT->parent->colormap;
			if(((Colormap ) *pVlist) == CopyFromParent)
			    *( Colormap*)pVlist = cmap;
		    }
		    else
			pWinT = pWinT->parent;
		}
		else
		{
		    error = BadMatch;
		    goto PatchUp;
		}
	    }
	    pCmap = (ColormapPtr)LookupID(cmap, RT←COLORMAP, RC←CORE);
	    if (pCmap)
	    {
	        if (pCmap->pVisual->vid == pWin->visual)
	        { 
		    pWin->colormap = (Colormap ) *pVlist;
		    xE.u.u.type = ColormapNotify;
	            xE.u.colormap.new = TRUE;
	            xE.u.colormap.state = IsMapInstalled(cmap, pWin);
	            TraverseTree(pWin, TellNewMap, (pointer)&xE);
		}
                else
		{
		    error = BadMatch;
		    goto PatchUp;
		}
	    }
            else
	    {
		error = BadColor;
		goto PatchUp;
	    }
	    pVlist++;
	    break;
	    }
	  case CWCursor:
	    cursorID = (Cursor ) *pVlist;
	    pVlist++;
	    /*
	     * install the new
	     */
	    if ( cursorID == None)
	    {
	        if ( pWin->cursor != None)
		    FreeCursor( pWin->cursor, 0);
                if (pWin == &WindowTable[pWin->drawable.pScreen->myNum])
		   MakeRootCursor( pWin);
                else            
                    pWin->cursor = (CursorPtr)None;
	    }
            else
	    {
	        pCursor = (CursorPtr)LookupID(cursorID, RT←CURSOR, RC←CORE);
                if (pCursor) 
		{
    	            if ( pWin->cursor != None)
			FreeCursor( pWin->cursor, 0);
                    pWin->cursor = pCursor;
                    pWin->cursor->refcnt++;
		}
	        else
		{
		    error = BadCursor;
		    goto PatchUp;
		}
	    }
	    WindowHasNewCursor( pWin);
	    break;
	 default: break;
      }
      vmaskCopy |= index;
    }
PatchUp:
    (*pScreen->ChangeWindowAttributes)(pWin, vmaskCopy);

    /* 
        If the border pixel 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)) 
	&& pWin->viewable && pWin->borderWidth)
    {
        (* pScreen->Subtract)(pWin->borderExposed, pWin->borderClip, 
			      pWin->winSize);
	(*pWin->PaintWindowBorder)(pWin, pWin->borderExposed, PW←BORDER);
        (* pScreen->RegionEmpty)(pWin->borderExposed);
    }
    return error;
}


/*****
 * GetWindowAttributes
 *    Notice that this is different than ChangeWindowAttributes
 *****/

GetWindowAttributes(pWin, client)
    WindowPtr pWin;
    ClientPtr client;
{
    xGetWindowAttributesReply wa;

    wa.type = X←Reply;
    wa.bitGravity = pWin->bitGravity;
    wa.winGravity = pWin->winGravity;
    wa.backingStore  = pWin->backingStore;
    wa.length = (sizeof(xGetWindowAttributesReply) - 
		 sizeof(xGenericReply)) >> 2;
    wa.sequenceNumber = client->sequence;
    wa.backingBitPlanes =  pWin->backingBitPlanes;
    wa.backingPixel =  pWin->backingPixel;
    wa.saveUnder = (BOOL)pWin->saveUnder;
    wa.mapInstalled = IsMapInstalled(pWin->colormap, pWin);
    wa.override = pWin->overrideRedirect;
    wa.mapState = pWin->mapped;
    wa.colormap =  pWin->colormap;
    wa.yourEventMask = EventMaskForClient(pWin, client, &wa.allEventMasks);
    wa.doNotPropagateMask = pWin->dontPropagateMask ;
    wa.class = pWin->class;
    wa.visualID = pWin->visual;

    WriteReplyToClient(client, sizeof(xGetWindowAttributesReply), &wa);
}

void
fixChildrenWinSize(pWin)
    WindowPtr pWin;
{
    WindowPtr pSib;
    RegionPtr parentReg;
    BoxRec box;
    register short x, y, cwsx, cwsy;
    ScreenPtr pScreen;

    parentReg = pWin->winSize;
    pSib = pWin->firstChild;
    x = pWin->absCorner.x;
    y = pWin->absCorner.y;

    pScreen = pWin->drawable.pScreen;
    while (pSib) 
    {
	cwsx = pSib->clientWinSize.x;
	cwsy = pSib->clientWinSize.y;
	box.x1 = x + cwsx;
	box.y1 = y + cwsy;
	box.x2 = box.x1 + pSib->clientWinSize.width;
	box.y2 = box.y1 + pSib->clientWinSize.height;

        pSib->oldAbsCorner.x = pSib->absCorner.x;
        pSib->oldAbsCorner.y = pSib->absCorner.y;
        pSib->absCorner.x = x + cwsx;
        pSib->absCorner.y = y + cwsy;

	(* pScreen->RegionReset)(pSib->winSize, &box);
	(* pScreen->Intersect)(pSib->winSize, pSib->winSize, parentReg);

        if (pSib->borderWidth)
	{
	    box.x1 -= pSib->borderWidth;
	    box.y1 -= pSib->borderWidth;
	    box.x2 += pSib->borderWidth;
	    box.y2 += pSib->borderWidth;
	    (* pScreen->RegionReset)(pSib->borderSize, &box);
	    (* pScreen->Intersect)(pSib->borderSize, pSib->borderSize, parentReg);
	}
	else
        {
	    (* pScreen->RegionCopy)(pSib->borderSize, pSib->winSize);
	}

        (*pSib->drawable.pScreen->PositionWindow)(pSib,
					      pSib->absCorner.x,
					      pSib->absCorner.y);
        pSib->marked = 1;

	if (pSib->firstChild) 
            fixChildrenWinSize(pSib);
        pSib = pSib->nextSib;
    }
}

void
MoveWindowInStack(pWin, pNextSib)
    WindowPtr pWin, pNextSib;
{
    WindowPtr pParent = pWin->parent;

    if (pWin->nextSib != pNextSib)
    {
        if (!pNextSib)        /* move to bottom */
	{
            if (pParent->firstChild == pWin)
                pParent->firstChild = pWin->nextSib;
	    if (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 = (WindowPtr )NULL;
            pParent->lastChild = pWin;
	}
        else if (pParent->firstChild == pNextSib)
        {        
	    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 
        {
            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;
            pWin->nextSib = pNextSib;
            pWin->prevSib = pNextSib->prevSib;
	    if (pNextSib->prevSib)
                pNextSib->prevSib->nextSib = pWin;
            pNextSib->prevSib = pWin;
	}
    }
}

void
MoveWindow(pWin, x, y, pNextSib, above)
   /* for first pass, puts window on top of stack first */
    WindowPtr pWin;
    short x,y;
    WindowPtr pNextSib;
    int above;
{
    WindowPtr pParent;
    Bool WasMapped = (Bool)(pWin->realized);
    BoxRec box;
    short oldx, oldy, bw;
    RegionPtr oldRegion;
    DDXPointRec oldpt;
    Bool anyMarked;
    register ScreenPtr pScreen;
    BoxPtr pBox;
    WindowPtr windowToValidate = pWin;

    /* if this is a root window, can't be moved */
    if (!(pParent = pWin->parent)) 
       return ;
    pScreen = pWin->drawable.pScreen;
    bw = pWin->borderWidth;

    oldx = pWin->absCorner.x;
    oldy = pWin->absCorner.y;
    oldpt.x = oldx;
    oldpt.y = oldy;
    if (WasMapped) 
    {
        oldRegion = (* pScreen->RegionCreate)((BoxPtr)NULL, 1);
        (* pScreen->RegionCopy)(oldRegion, pWin->borderClip);
        pBox = (* pScreen->RegionExtents)(pWin->borderSize);
	anyMarked = MarkSiblingsBelowMe(pWin, pBox, TRUE);
    }
    pWin->clientWinSize.x = x + bw;
    pWin->clientWinSize.y = y + bw;
    pWin->oldAbsCorner.x = oldx;
    pWin->oldAbsCorner.y = oldy;
    pWin->absCorner.x = pParent->absCorner.x + x +bw;
    pWin->absCorner.y = pParent->absCorner.y + y + bw;

    box.x1 = pWin->absCorner.x;
    box.y1 = pWin->absCorner.y;
    box.x2 = box.x1 + pWin->clientWinSize.width;
    box.y2 = box.y1+ pWin->clientWinSize.height;
    (* pScreen->RegionReset)(pWin->winSize, &box);
    (* pScreen->Intersect)(pWin->winSize, pWin->winSize, pParent->winSize); 

    if (bw)
    {
	box.x1 -= bw;
	box.y1 -= bw;
	box.x2 += bw;
	box.y2 += bw;
	(* pScreen->RegionReset)(pWin->borderSize, &box);
        (* pScreen->Intersect)(pWin->borderSize, pWin->borderSize, 
			       pParent->winSize);
    }
    else
        (* pScreen->RegionCopy)(pWin->borderSize, pWin->winSize);

    (* pScreen->PositionWindow)(pWin,pWin->absCorner.x, pWin->absCorner.y);
    if (!pNextSib || (above == Above))
        MoveWindowInStack(pWin, pNextSib);
    else
    {
        MoveWindowInStack(pNextSib, pWin);
        windowToValidate = pNextSib;
    }

    fixChildrenWinSize(pWin);
    if (WasMapped) 
    {
	short wid, hgt;
	Bool addborder = TRUE;
        BoxPtr parentBox;

        parentBox = (* pScreen->RegionExtents)(pParent->winSize);
	x = pWin->absCorner.x;
	y = pWin->absCorner.y;
        wid = pWin->clientWinSize.width;
	hgt = pWin->clientWinSize.height;
	if (oldx - bw < 0)
	    addborder = FALSE;
	else if (oldy - bw < 0)
	    addborder = FALSE;
        else if (oldx + wid + bw > parentBox->x2)
	    addborder = FALSE;
        else if (oldy + hgt + bw > parentBox->y2)
	    addborder = FALSE;
        if (!addborder)
            (* pScreen->RegionEmpty)(pWin->borderClip); /* force redraw of border */

        anyMarked = MarkSiblingsBelowMe(windowToValidate, pBox, 
					TRUE) || anyMarked;
            
        (* pScreen->ValidateTree)(pParent, (WindowPtr)NULL, TRUE, anyMarked);
/*
		       (anyMarked ? windowToValidate : (WindowPtr )NULL), 
						 TRUE, anyMarked);
*/
	
	DoObscures(pParent); 
        if (pWin->backgroundTile == (PixmapPtr)ParentRelative)
            (* pScreen->RegionCopy)(pWin->exposed, pWin->clipList);
        else
        {
       	    (* pWin->CopyWindow)(pWin, oldpt, oldRegion);
    	    (* pScreen->Subtract)(pParent->exposed, pParent->exposed, 
				  pWin->borderSize); 
	}
	(* pScreen->RegionDestroy)(oldRegion);
	HandleExposures(pParent); 
    }    
}

void
ResizeChildrenWinSize(pWin, XYSame, dw, dh)
    WindowPtr pWin;
    Bool XYSame;
    int dw, dh;
{
    WindowPtr pSib;
    RegionPtr parentReg;
    BoxRec box;
    register short x, y, cwsx, cwsy;
    Bool unmap = FALSE;
    register ScreenPtr pScreen;

    pScreen = pWin->drawable.pScreen;
    parentReg = pWin->winSize;
    pSib = pWin->firstChild;
    x = pWin->absCorner.x;
    y = pWin->absCorner.y;

    while (pSib) 
    {
	cwsx = pSib->clientWinSize.x;
	cwsy = pSib->clientWinSize.y;
	switch (pSib->winGravity)
	{
	  case UnmapGravity: 
                    unmap = TRUE;
	  case NorthWestGravity: 
		    break;
          case NorthGravity:  
                   cwsx += dw/2;
		   break;
          case NorthEastGravity:    
		   cwsx += dw;	     
		   break;
          case WestGravity:         
                   cwsy += dh/2;
                   break;
          case CenterGravity:    
                   cwsx += dw/2;
		   cwsy += dh/2;
                   break;
          case EastGravity:         
                   cwsx += dw;
		   cwsy += dh/2;
                   break;
          case SouthWestGravity:    
		   cwsy += dh;
                   break;
          case SouthGravity:        
                   cwsx += dw/2;
		   cwsy += dh;
                   break;
          case SouthEastGravity:    
                   cwsx += dw;
		   cwsy += dh;
		   break;
          case StaticGravity:           /* XXX */
		   break;
	  default:
                   break;
	}
	box.x1 = x + cwsx;
	box.y1 = y + cwsy;
	box.x2 = box.x1 + pSib->clientWinSize.width;
	box.y2 = box.y1 + pSib->clientWinSize.height;

	pSib->oldAbsCorner.x = pSib->absCorner.x;
	pSib->oldAbsCorner.y = pSib->absCorner.y;
	pSib->absCorner.x = x + cwsx;
	pSib->absCorner.y = y + cwsy;

	(* pScreen->RegionReset)(pSib->winSize, &box);
	(* pScreen->Intersect)(pSib->winSize, pSib->winSize, 
					      parentReg);

	if (pSib->borderWidth)
	{
	    box.x1 -= pSib->borderWidth;
	    box.y1 -= pSib->borderWidth;
	    box.x2 += pSib->borderWidth;
	    box.y2 += pSib->borderWidth;
	    (* pScreen->RegionReset)(pSib->borderSize, &box);
	    (* pScreen->Intersect)(pSib->borderSize, 
					 pSib->borderSize, parentReg);
	}
	else
	    (* pScreen->RegionCopy)(pSib->borderSize, pSib->winSize);
	(* pScreen->PositionWindow)(pSib, pSib->absCorner.x, pSib->absCorner.y);
	pSib->marked = 1;
	if (pSib->firstChild) 
            ResizeChildrenWinSize(pSib, XYSame, dw, dh);
        if (unmap)
	{
            UnmapWindow(pSib, DONT←HANDLE←EXPOSURES, SEND←NOTIFICATION,	TRUE);
	    unmap = FALSE;
	}
        pSib = pSib->nextSib;
    }
}

int
ExposeAll(pWin, pScreen)
    WindowPtr pWin;
    ScreenPtr pScreen;
{
    if (!pWin)
        return(WT←NOMATCH);
    if (pWin->mapped)
    {
        (* pScreen->RegionCopy)(pWin->exposed, pWin->clipList);
        return (WT←WALKCHILDREN);
    }
    else
        return(WT←NOMATCH);
}