/************************************************************
Copyright 1989 by The Massachusetts Institute of Technology

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
no- tice appear in all copies and that both that copyright
no- tice and this permission notice appear in supporting
docu- mentation, and that the name of MIT not be used in
advertising or publicity pertaining to distribution of the
software without specific prior written permission.
M.I.T. makes no representation about the suitability of
this software for any purpose. It is provided "as is"
without any express or implied warranty.

MIT DISCLAIMS ALL WARRANTIES WITH REGARD TO  THIS  SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MIT BE  LI-
ABLE  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.

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

/* $XConsortium: shape.c,v 5.11 90/01/23 10:49:17 rws Exp $ */
#define NEED_REPLIES
#define NEED_EVENTS
#include <stdio.h>
#include "X.h"
#include "Xproto.h"
#include "misc.h"
#include "os.h"
#include "windowstr.h"
#include "scrnintstr.h"
#include "pixmapstr.h"
#include "extnsionst.h"
#include "dixstruct.h"
#include "resource.h"
#include "opaque.h"
#define _SHAPE_SERVER_	/* don't want Xlib structures */
#include "shapestr.h"
#include "regionstr.h"
#include "gcstruct.h"
#include "funcs.h"

#ifdef SHAPE

static void ShapeFreeClient(pointer, XID), ShapeFreeEvents(pointer, XID);
static void SendShapeNotify(WindowPtr, int);
static RegionPtr CreateBoundingShape (WindowPtr);
static RegionPtr CreateClipShape (WindowPtr);
static int ProcShapeDispatch (ClientPtr);
static int SProcShapeDispatch (ClientPtr);
static int RegionOperate (ClientPtr, WindowPtr, int, RegionPtr *,
	RegionPtr, int, int, int, RegionPtr (*)(WindowPtr));

static int ProcShapeGetRectangles (ClientPtr);
static int ProcShapeInputSelected (ClientPtr);
static int ProcShapeSelectInput (ClientPtr);
static int ProcShapeQueryExtents (ClientPtr);
static int ProcShapeOffset (ClientPtr);
static int ProcShapeCombine (ClientPtr);
static int ProcShapeMask (ClientPtr);
static int ProcShapeRectangles (ClientPtr);
static int ProcShapeQueryVersion (ClientPtr);

static int SProcShapeGetRectangles (ClientPtr);
static int SProcShapeInputSelected (ClientPtr);
static int SProcShapeSelectInput (ClientPtr);
static int SProcShapeQueryExtents (ClientPtr);
static int SProcShapeOffset (ClientPtr);
static int SProcShapeCombine (ClientPtr);
static int SProcShapeMask (ClientPtr);
static int SProcShapeRectangles (ClientPtr);
static int SProcShapeQueryVersion (ClientPtr);

static void SShapeNotifyEvent(xShapeNotifyEvent *, xShapeNotifyEvent *);

static unsigned char ShapeReqCode = 0;
static int ShapeEventBase = 0;
static RESTYPE ClientType, EventType; /* resource types for event masks */

/*
 * each window has a list of clients requesting
 * ShapeNotify events.  Each client has a resource
 * for each window it selects ShapeNotify input for,
 * this resource is used to delete the ShapeNotifyRec
 * entry from the per-window queue.
 */

typedef struct _ShapeEvent *ShapeEventPtr;

typedef struct _ShapeEvent {
    ShapeEventPtr   next;
    ClientPtr	    client;
    WindowPtr	    window;
    XID		    clientResource;
} ShapeEventRec;

static void  ShapeResetProc(ExtensionEntry *), SShapeNotifyEvent();

/****************
 * ShapeExtensionInit
 *
 * Called from InitExtensions in main() or from QueryExtension() if the
 * extension is dynamically loaded.
 *
 ****************/

void
ShapeExtensionInit()
{
    ExtensionEntry *extEntry;

    ClientType = CreateNewResourceType(ShapeFreeClient);
    EventType = CreateNewResourceType(ShapeFreeEvents);
    if (ClientType && EventType &&
	((extEntry = AddExtension(SHAPENAME, ShapeNumberEvents, 0,
				 ProcShapeDispatch, SProcShapeDispatch,
				 ShapeResetProc, StandardMinorOpcode)) != 0))
    {
	ShapeReqCode = (unsigned char)extEntry->base;
	ShapeEventBase = extEntry->eventBase;
	EventSwapVector[ShapeEventBase] = SShapeNotifyEvent;
    }
}

/*ARGSUSED*/
static void
ShapeResetProc (extEntry)
ExtensionEntry	*extEntry;
{
    extEntry = extEntry;
}

static int
RegionOperate (client, pWin, kind, destRgnp, srcRgn, op, xoff, yoff, create)
    ClientPtr	client;
    WindowPtr	pWin;
    int		kind;
    RegionPtr	*destRgnp, srcRgn;
    int		op;
    int		xoff, yoff;
    RegionPtr	(*create)(WindowPtr);	/* creates a reasonable *destRgnp */
{
    ScreenPtr	pScreen = pWin->drawable.pScreen;

    if (srcRgn && (xoff || yoff))
	(*pScreen->TranslateRegion) (srcRgn, xoff, yoff);
    if (!pWin->parent)
    {
	if (srcRgn)
	    (*pScreen->RegionDestroy) (srcRgn);
	return Success;
    }
    switch (op) {
    case ShapeSet:
	if (*destRgnp)
	    (*pScreen->RegionDestroy) (*destRgnp);
	*destRgnp = srcRgn;
	srcRgn = 0;
	break;
    case ShapeUnion:
	if (*destRgnp)
	    (*pScreen->Union) (*destRgnp, *destRgnp, srcRgn);
	break;
    case ShapeIntersect:
	if (*destRgnp)
	    (*pScreen->Intersect) (*destRgnp, *destRgnp, srcRgn);
	else {
	    *destRgnp = srcRgn;
	    srcRgn = 0;
	}
	break;
    case ShapeSubtract:
	if (!*destRgnp)
	    *destRgnp = (*create)(pWin);
	(*pScreen->Subtract) (*destRgnp, *destRgnp, srcRgn);
	break;
    case ShapeInvert:
	if (!*destRgnp)
	    *destRgnp = (*pScreen->RegionCreate) ((BoxPtr) 0, 0);
	else
	    (*pScreen->Subtract) (*destRgnp, srcRgn, *destRgnp);
	break;
    default:
	client->errorValue = op;
	return BadValue;
    }
    if (srcRgn)
	(*pScreen->RegionDestroy) (srcRgn);
    SetShape (pWin);
    SendShapeNotify (pWin, kind);
    return Success;
}

static RegionPtr
CreateBoundingShape (pWin)
    WindowPtr	pWin;
{
    BoxRec	extents;

    extents.x1 = -wBorderWidth (pWin);
    extents.y1 = -wBorderWidth (pWin);
    extents.x2 = pWin->drawable.width + wBorderWidth (pWin);
    extents.y2 = pWin->drawable.height + wBorderWidth (pWin);
    return (*pWin->drawable.pScreen->RegionCreate) (&extents, 1);
}

static RegionPtr
CreateClipShape (pWin)
    WindowPtr	pWin;
{
    BoxRec	extents;

    extents.x1 = 0;
    extents.y1 = 0;
    extents.x2 = pWin->drawable.width;
    extents.y2 = pWin->drawable.height;
    return (*pWin->drawable.pScreen->RegionCreate) (&extents, 1);
}

static int
ProcShapeQueryVersion (client)
    ClientPtr	client;
{
    REQUEST(xShapeQueryVersionReq);
    xShapeQueryVersionReply	rep;

    REQUEST_SIZE_MATCH (xShapeQueryVersionReq);
    rep.type = X_Reply;
    rep.length = 0;
    rep.sequenceNumber = client->sequence;
    rep.majorVersion = SHAPE_MAJOR_VERSION;
    rep.minorVersion = SHAPE_MINOR_VERSION;
    if (client->swapped) {
    	rep.sequenceNumber = lswaps(rep.sequenceNumber);
    	rep.length = lswapl(rep.length);
	rep.majorVersion = lswaps(rep.majorVersion);
	rep.minorVersion = lswaps(rep.minorVersion);
    }
    WriteToClient(client, sizeof (xShapeQueryVersionReply), (char *)&rep);
    return (client->noClientException);
}

/*****************
 * ProcShapeRectangles
 *
 *****************/

static int
ProcShapeRectangles (client)
    ClientPtr client;
{
    WindowPtr		pWin;
    ScreenPtr		pScreen;
    REQUEST(xShapeRectanglesReq);
    xRectangle		*prects;
    int		        nrects, ctype;
    RegionPtr		srcRgn;
    RegionPtr		*destRgn;
    RegionPtr		(*createDefault)(WindowPtr);
    int			destBounding;

    REQUEST_AT_LEAST_SIZE (xShapeRectanglesReq);
    UpdateCurrentTime();
    pWin = LookupWindow (stuff->dest, client);
    if (!pWin)
	return BadWindow;
    switch (stuff->destKind) {
    case ShapeBounding:
	destBounding = 1;
	createDefault = CreateBoundingShape;
	break;
    case ShapeClip:
	destBounding = 0;
	createDefault = CreateClipShape;
	break;
    default:
	client->errorValue = stuff->destKind;
	return BadValue;
    }
    if ((stuff->ordering != Unsorted) && (stuff->ordering != YSorted) &&
	(stuff->ordering != YXSorted) && (stuff->ordering != YXBanded))
    {
	client->errorValue = stuff->ordering;
        return BadValue;
    }
    pScreen = pWin->drawable.pScreen;
    nrects = ((stuff->length  << 2) - sizeof(xShapeRectanglesReq));
    if (nrects & 4)
	return BadLength;
    nrects >>= 3;
    prects = (xRectangle *) &stuff[1];
    ctype = VerifyRectOrder(nrects, prects, (int)stuff->ordering);
    if (ctype < 0)
	return BadMatch;
    srcRgn = (*pScreen->RectsToRegion)(nrects, prects, ctype);

    if (!pWin->optional)
	MakeWindowOptional (pWin);
    if (destBounding)
	destRgn = &pWin->optional->boundingShape;
    else
	destRgn = &pWin->optional->clipShape;

    return RegionOperate (client, pWin, (int)stuff->destKind,
			  destRgn, srcRgn, (int)stuff->op,
			  stuff->xOff, stuff->yOff, createDefault);
}

/**************
 * ProcShapeMask
 **************/

static int
ProcShapeMask (client)
    ClientPtr client;
{
    WindowPtr		pWin;
    ScreenPtr		pScreen;
    REQUEST(xShapeMaskReq);
    RegionPtr		srcRgn;
    RegionPtr		*destRgn;
    PixmapPtr		pPixmap;
    RegionPtr		(*createDefault)(WindowPtr);
    int			destBounding;

    REQUEST_SIZE_MATCH (xShapeMaskReq);
    UpdateCurrentTime();
    pWin = LookupWindow (stuff->dest, client);
    if (!pWin)
	return BadWindow;
    switch (stuff->destKind) {
    case ShapeBounding:
	destBounding = 1;
	createDefault = CreateBoundingShape;
	break;
    case ShapeClip:
	destBounding = 0;
	createDefault = CreateClipShape;
	break;
    default:
	client->errorValue = stuff->destKind;
	return BadValue;
    }
    pScreen = pWin->drawable.pScreen;
    if (stuff->src == None)
	srcRgn = 0;
    else {
        pPixmap = (PixmapPtr) LookupIDByType(stuff->src, RT_PIXMAP);
        if (!pPixmap)
	    return BadPixmap;
	if (pPixmap->drawable.pScreen != pScreen)
	    return BadMatch;
	srcRgn = (*pScreen->BitmapToRegion)(pPixmap);
	if (!srcRgn)
	    return BadAlloc;
    }

    if (!pWin->optional)
	MakeWindowOptional (pWin);
    if (destBounding)
	destRgn = &pWin->optional->boundingShape;
    else
	destRgn = &pWin->optional->clipShape;

    return RegionOperate (client, pWin, (int)stuff->destKind,
			  destRgn, srcRgn, (int)stuff->op,
			  stuff->xOff, stuff->yOff, createDefault);
}

/************
 * ProcShapeCombine
 ************/

static int
ProcShapeCombine (client)
    ClientPtr client;
{
    WindowPtr		pSrcWin, pDestWin;
    ScreenPtr		pScreen;
    REQUEST(xShapeCombineReq);
    RegionPtr		srcRgn;
    RegionPtr		*destRgn;
    RegionPtr		(*createDefault)(WindowPtr);
    RegionPtr		(*createSrc)(WindowPtr);
    RegionPtr		tmp;
    int			destBounding;

    REQUEST_SIZE_MATCH (xShapeCombineReq);
    UpdateCurrentTime();
    pDestWin = LookupWindow (stuff->dest, client);
    if (!pDestWin)
	return BadWindow;
    if (!pDestWin->optional)
	MakeWindowOptional (pDestWin);
    switch (stuff->destKind) {
    case ShapeBounding:
	destBounding = 1;
	createDefault = CreateBoundingShape;
	break;
    case ShapeClip:
	destBounding = 0;
	createDefault = CreateClipShape;
	break;
    default:
	client->errorValue = stuff->destKind;
	return BadValue;
    }
    pScreen = pDestWin->drawable.pScreen;

    pSrcWin = LookupWindow (stuff->src, client);
    if (!pSrcWin)
	return BadWindow;
    switch (stuff->srcKind) {
    case ShapeBounding:
	srcRgn = wBoundingShape (pSrcWin);
	createSrc = CreateBoundingShape;
	break;
    case ShapeClip:
	srcRgn = wClipShape (pSrcWin);
	createSrc = CreateClipShape;
	break;
    default:
	client->errorValue = stuff->srcKind;
	return BadValue;
    }
    if (pSrcWin->drawable.pScreen != pScreen)
    {
	return BadMatch;
    }

    if (srcRgn) {
        tmp = (*pScreen->RegionCreate) ((BoxPtr) 0, 0);
        (*pScreen->RegionCopy) (tmp, srcRgn);
        srcRgn = tmp;
    } else
	srcRgn = (*createSrc) (pSrcWin);

    if (!pDestWin->optional)
	MakeWindowOptional (pDestWin);
    if (destBounding)
	destRgn = &pDestWin->optional->boundingShape;
    else
	destRgn = &pDestWin->optional->clipShape;

    return RegionOperate (client, pDestWin, (int)stuff->destKind,
			  destRgn, srcRgn, (int)stuff->op,
			  stuff->xOff, stuff->yOff, createDefault);
}

/*************
 * ProcShapeOffset
 *************/

static int
ProcShapeOffset (client)
    ClientPtr client;
{
    WindowPtr		pWin;
    ScreenPtr		pScreen;
    REQUEST(xShapeOffsetReq);
    RegionPtr		srcRgn;

    REQUEST_SIZE_MATCH (xShapeOffsetReq);
    UpdateCurrentTime();
    pWin = LookupWindow (stuff->dest, client);
    if (!pWin)
	return BadWindow;
    switch (stuff->destKind) {
    case ShapeBounding:
	srcRgn = wBoundingShape (pWin);
	break;
    case ShapeClip:
	srcRgn = wClipShape(pWin);
	break;
    default:
	client->errorValue = stuff->destKind;
	return BadValue;
    }
    pScreen = pWin->drawable.pScreen;
    if (srcRgn)
    {
        (*pScreen->TranslateRegion) (srcRgn, stuff->xOff, stuff->yOff);
        SetShape (pWin);
    }
    SendShapeNotify (pWin, (int)stuff->destKind);
    return Success;
}

static int
ProcShapeQueryExtents (client)
    ClientPtr	client;
{
    REQUEST(xShapeQueryExtentsReq);
    WindowPtr		pWin;
    xShapeQueryExtentsReply	rep;
    BoxRec		extents;

    REQUEST_SIZE_MATCH (xShapeQueryExtentsReq);
    pWin = LookupWindow (stuff->window, client);
    if (!pWin)
	return BadWindow;
    rep.type = X_Reply;
    rep.length = 0;
    rep.sequenceNumber = client->sequence;
    rep.boundingShaped = (wBoundingShape(pWin) != 0);
    rep.clipShaped = (wClipShape(pWin) != 0);
    if (wBoundingShape(pWin)) {
	extents = *(pWin->drawable.pScreen->RegionExtents) (wBoundingShape(pWin));
    } else {
	extents.x1 = -wBorderWidth (pWin);
	extents.y1 = -wBorderWidth (pWin);
	extents.x2 = pWin->drawable.width + wBorderWidth (pWin);
	extents.y2 = pWin->drawable.height + wBorderWidth (pWin);
    }
    rep.xBoundingShape = extents.x1;
    rep.yBoundingShape = extents.y1;
    rep.widthBoundingShape = extents.x2 - extents.x1;
    rep.heightBoundingShape = extents.y2 - extents.y1;
    if (wClipShape(pWin)) {
	extents = *(pWin->drawable.pScreen->RegionExtents) (wClipShape(pWin));
    } else {
	extents.x1 = 0;
	extents.y1 = 0;
	extents.x2 = pWin->drawable.width;
	extents.y2 = pWin->drawable.height;
    }
    rep.xClipShape = extents.x1;
    rep.yClipShape = extents.y1;
    rep.widthClipShape = extents.x2 - extents.x1;
    rep.heightClipShape = extents.y2 - extents.y1;
    if (client->swapped) {
    	rep.sequenceNumber = lswaps(rep.sequenceNumber);
    	rep.length = lswapl(rep.length);
	rep.xBoundingShape = lswaps(rep.xBoundingShape);
	rep.yBoundingShape = lswaps(rep.yBoundingShape);
	rep.widthBoundingShape = lswaps(rep.widthBoundingShape);
	rep.heightBoundingShape = lswaps(rep.heightBoundingShape);
	rep.xClipShape = lswaps(rep.xClipShape);
	rep.yClipShape = lswaps(rep.yClipShape);
	rep.widthClipShape = lswaps(rep.widthClipShape);
	rep.heightClipShape = lswaps(rep.heightClipShape);
    }
    WriteToClient(client, sizeof (xShapeQueryExtentsReply), (char *)&rep);
    return (client->noClientException);
}

/*ARGSUSED*/
static void
ShapeFreeClient (data, id)
    pointer	    data;
    XID		    id;
{
    ShapeEventPtr   pShapeEvent;
    WindowPtr	    pWin;
    ShapeEventPtr   *pHead, pCur, pPrev;

    id = id;
    pShapeEvent = (ShapeEventPtr) data;
    pWin = pShapeEvent->window;
    pHead = (ShapeEventPtr *) LookupIDByType(pWin->drawable.id, EventType);
    if (pHead) {
	pPrev = 0;
	for (pCur = *pHead; pCur && pCur != pShapeEvent; pCur=pCur->next)
	    pPrev = pCur;
	if (pPrev)
	    pPrev->next = pShapeEvent->next;
	else
	    *pHead = pShapeEvent->next;
    }
    xfree ((pointer) pShapeEvent);
}

/*ARGSUSED*/
static void
ShapeFreeEvents (data, id)
    pointer	    data;
    XID		    id;
{
    ShapeEventPtr   *pHead, pCur, pNext;

    id = id;
    pHead = (ShapeEventPtr *) data;
    for (pCur = *pHead; pCur; pCur = pNext) {
	pNext = pCur->next;
	FreeResource (pCur->clientResource, ClientType);
	xfree ((pointer) pCur);
    }
    xfree ((pointer) pHead);
}

static int
ProcShapeSelectInput (client)
    ClientPtr	client;
{
    REQUEST(xShapeSelectInputReq);
    WindowPtr		pWin;
    ShapeEventPtr	pShapeEvent, pNewShapeEvent, *pHead;
    XID			clientResource;

    REQUEST_SIZE_MATCH (xShapeSelectInputReq);
    pWin = LookupWindow (stuff->window, client);
    if (!pWin)
	return BadWindow;
    pHead = (ShapeEventPtr *) LookupIDByType(pWin->drawable.id, EventType);
    switch (stuff->enable) {
    case xTrue:
	if (pHead) {

	    /* check for existing entry. */
	    for (pShapeEvent = *pHead;
		 pShapeEvent;
 		 pShapeEvent = pShapeEvent->next)
	    {
		if (pShapeEvent->client == client)
		    return Success;
	    }
	}

	/* build the entry */
    	pNewShapeEvent = (ShapeEventPtr)
			    xalloc (sizeof (ShapeEventRec));
    	if (!pNewShapeEvent)
	    return BadAlloc;
    	pNewShapeEvent->next = 0;
    	pNewShapeEvent->client = client;
    	pNewShapeEvent->window = pWin;
    	/*
 	 * add a resource that will be deleted when
     	 * the client goes away
     	 */
   	clientResource = FakeClientID (client->index);
    	pNewShapeEvent->clientResource = clientResource;
    	if (!AddResource (clientResource, ClientType, (pointer)pNewShapeEvent))
    	{
	    xfree (pNewShapeEvent);
	    return BadAlloc;
    	}
    	/*
     	 * create a resource to contain a pointer to the list
     	 * of clients selecting input.  This must be indirect as
     	 * the list may be arbitrarily rearranged which cannot be
     	 * done through the resource database.
     	 */
    	if (!pHead)
    	{
	    pHead = (ShapeEventPtr *) xalloc (sizeof (ShapeEventPtr));
	    if (!pHead ||
	    	!AddResource (pWin->drawable.id, EventType, (pointer)pHead))
	    {
	    	FreeResource (clientResource, ClientType);
	    	xfree (pHead);
	    	xfree (pNewShapeEvent);
	    	return BadAlloc;
	    }
	    *pHead = 0;
    	}
    	pNewShapeEvent->next = *pHead;
    	*pHead = pNewShapeEvent;
	break;
    case xFalse:
	/* delete the interest */
	if (pHead) {
	    pNewShapeEvent = 0;
	    for (pShapeEvent = *pHead; pShapeEvent; pShapeEvent = pShapeEvent->next) {
		if (pShapeEvent->client == client)
		    break;
		pNewShapeEvent = 0;
	    }
	    if (pShapeEvent) {
		FreeResource (pShapeEvent->clientResource, ClientType);
		if (pNewShapeEvent)
		    pNewShapeEvent->next = pShapeEvent->next;
		else
		    *pHead = pShapeEvent->next;
		xfree (pShapeEvent);
	    }
	}
	break;
    default:
	client->errorValue = stuff->enable;
	return BadValue;
    }
    return Success;
}

/*
 * deliver the event
 */

static void
SendShapeNotify (pWin, which)
    WindowPtr	pWin;
    int		which;
{
    ShapeEventPtr	*pHead, pShapeEvent;
    ClientPtr		client;
    xShapeNotifyEvent	se;
    BoxRec		extents;
    RegionPtr		region;
    BYTE		shaped;

    pHead = (ShapeEventPtr *) LookupIDByType(pWin->drawable.id, EventType);
    if (!pHead)
	return;
    if (which == ShapeBounding) {
	region = wBoundingShape(pWin);
	if (region) {
	    extents = *(pWin->drawable.pScreen->RegionExtents) (region);
	    shaped = xTrue;
	} else {
	    extents.x1 = -wBorderWidth (pWin);
	    extents.y1 = -wBorderWidth (pWin);
	    extents.x2 = pWin->drawable.width + wBorderWidth (pWin);
	    extents.y2 = pWin->drawable.height + wBorderWidth (pWin);
	    shaped = xFalse;
	}
    } else {
	region = wClipShape(pWin);
	if (region) {
	    extents = *(pWin->drawable.pScreen->RegionExtents) (region);
	    shaped = xTrue;
	} else {
	    extents.x1 = 0;
	    extents.y1 = 0;
	    extents.x2 = pWin->drawable.width;
	    extents.y2 = pWin->drawable.height;
	    shaped = xFalse;
	}
    }
    for (pShapeEvent = *pHead; pShapeEvent; pShapeEvent = pShapeEvent->next) {
	client = pShapeEvent->client;
	if (client == serverClient || client->clientGone)
	    continue;
	se.type = ShapeNotify + ShapeEventBase;
	se.kind = which;
	se.window = pWin->drawable.id;
	se.sequenceNumber = client->sequence;
	se.x = extents.x1;
	se.y = extents.y1;
	se.width = extents.x2 - extents.x1;
	se.height = extents.y2 - extents.y1;
	se.time = currentTime.milliseconds;
	se.shaped = shaped;
	WriteEventsToClient (client, 1, (xEvent *) &se);
    }
}

static int
ProcShapeInputSelected (client)
    ClientPtr	client;
{
    REQUEST(xShapeInputSelectedReq);
    WindowPtr		pWin;
    ShapeEventPtr	pShapeEvent, *pHead;
    CARD8		enabled;
    xShapeInputSelectedReply	rep;

    REQUEST_SIZE_MATCH (xShapeSelectInputReq);
    pWin = LookupWindow (stuff->window, client);
    if (!pWin)
	return BadWindow;
    pHead = (ShapeEventPtr *) LookupIDByType(pWin->drawable.id, EventType);
    enabled = xFalse;
    if (pHead) {
    	for (pShapeEvent = *pHead;
	     pShapeEvent;
	     pShapeEvent = pShapeEvent->next)
    	{
	    if (pShapeEvent->client == client) {
	    	enabled = xTrue;
		break;
	    }
    	}
    }
    rep.type = X_Reply;
    rep.length = 0;
    rep.sequenceNumber = client->sequence;
    rep.enabled = enabled;
    if (client->swapped) {
	rep.sequenceNumber = lswaps(rep.sequenceNumber);
	rep.length = lswapl(rep.length);
    }
    WriteToClient (client, sizeof (xShapeInputSelectedReply), (char *) &rep);
    return (client->noClientException);
}

static int
ProcShapeGetRectangles (client)
    ClientPtr	client;
{
    REQUEST(xShapeGetRectanglesReq);
    WindowPtr			pWin;
    xShapeGetRectanglesReply	rep;
    xRectangle			*rects;
    int				nrects, i;
    RegionPtr			region;

    REQUEST_SIZE_MATCH(xShapeGetRectanglesReq);
    pWin = LookupWindow (stuff->window, client);
    if (!pWin)
	return BadWindow;
    switch (stuff->kind) {
    case ShapeBounding:
	region = wBoundingShape(pWin);
	break;
    case ShapeClip:
	region = wClipShape(pWin);
	break;
    default:
	client->errorValue = stuff->kind;
	return BadValue;
    }
    if (!region) {
	nrects = 1;
	rects = (xRectangle *) ALLOCATE_LOCAL (sizeof (xRectangle));
	if (!rects)
	    return BadAlloc;
	switch (stuff->kind) {
	case ShapeBounding:
	    rects->x = - (int) wBorderWidth (pWin);
	    rects->y = - (int) wBorderWidth (pWin);
	    rects->width = pWin->drawable.width + wBorderWidth (pWin);
	    rects->height = pWin->drawable.height + wBorderWidth (pWin);
	    break;
	case ShapeClip:
	    rects->x = 0;
	    rects->y = 0;
	    rects->width = pWin->drawable.width;
	    rects->height = pWin->drawable.height;
	    break;
	}
    } else {
	BoxPtr box;
	nrects = REGION_NUM_RECTS(region);
	box = REGION_RECTS(region);
	if (nrects) {
	    if (nrects * sizeof (xRectangle) > 2048)
		return BadAlloc;
	    rects = (xRectangle *) ALLOCATE_LOCAL (nrects * sizeof (xRectangle));
	    if (!rects && nrects)
		return BadAlloc;
	}
	for (i = 0; i < nrects; i++, box++) {
	    rects[i].x = box->x1;
	    rects[i].y = box->y1;
	    rects[i].width = box->x2 - box->x1;
	    rects[i].height = box->y2 - box->y1;
	}
    }
    rep.type = X_Reply;
    rep.sequenceNumber = client->sequence;
    rep.length = (nrects * sizeof (xRectangle)) >> 2;
    rep.ordering = YXBanded;
    rep.nrects = nrects;
    if (client->swapped) {
	rep.sequenceNumber = lswaps(rep.sequenceNumber);
	rep.length = lswapl(rep.length);
	rep.nrects = lswapl(rep.nrects);
	SwapShorts ((short *)rects, (unsigned long)nrects * 4);
    }
    WriteToClient (client, sizeof (rep), (char *) &rep);
    WriteToClient (client, nrects * sizeof (xRectangle), (char *) rects);
    DEALLOCATE_LOCAL (rects);
    return client->noClientException;
}

static int
ProcShapeDispatch (client)
    ClientPtr	client;
{
    REQUEST(xReq);
    switch (stuff->data) {
    case X_ShapeQueryVersion:
	return ProcShapeQueryVersion (client);
    case X_ShapeRectangles:
	return ProcShapeRectangles (client);
    case X_ShapeMask:
	return ProcShapeMask (client);
    case X_ShapeCombine:
	return ProcShapeCombine (client);
    case X_ShapeOffset:
	return ProcShapeOffset (client);
    case X_ShapeQueryExtents:
	return ProcShapeQueryExtents (client);
    case X_ShapeSelectInput:
	return ProcShapeSelectInput (client);
    case X_ShapeInputSelected:
	return ProcShapeInputSelected (client);
    case X_ShapeGetRectangles:
	return ProcShapeGetRectangles (client);
    default:
	return BadRequest;
    }
}

static void
SShapeNotifyEvent(from, to)
    xShapeNotifyEvent *from, *to;
{
    to->type = from->type;
    to->kind = from->kind;
    to->window = lswapl(from->window);
    to->sequenceNumber = lswaps(from->sequenceNumber);
    to->x = lswaps(from->x);
    to->y = lswaps(from->y);
    to->width = lswaps(from->width);
    to->height = lswaps(from->height);
    to->time = lswapl(from->time);
    to->shaped = from->shaped;
}

static int
SProcShapeQueryVersion (client)
    ClientPtr	client;
{
    REQUEST (xShapeQueryVersionReq);

    stuff->length = lswaps(stuff->length);
    return ProcShapeQueryVersion (client);
}

static int
SProcShapeRectangles (client)
    ClientPtr	client;
{
    REQUEST (xShapeRectanglesReq);

    stuff->length = lswaps(stuff->length);
    stuff->dest = lswapl(stuff->dest);
    stuff->xOff = lswaps(stuff->xOff);
    stuff->yOff = lswaps(stuff->yOff);
    SwapRestS(stuff);
    return ProcShapeRectangles (client);
}

static int
SProcShapeMask (client)
    ClientPtr	client;
{
    REQUEST (xShapeMaskReq);

    stuff->length = lswaps(stuff->length);
    stuff->dest = lswapl(stuff->dest);
    stuff->xOff = lswaps(stuff->xOff);
    stuff->yOff = lswaps(stuff->yOff);
    stuff->src = lswapl(stuff->src);
    return ProcShapeMask (client);
}

static int
SProcShapeCombine (client)
    ClientPtr	client;
{
    REQUEST (xShapeCombineReq);

    stuff->length = lswaps(stuff->length);
    stuff->dest = lswapl(stuff->dest);
    stuff->xOff = lswaps(stuff->xOff);
    stuff->yOff = lswaps(stuff->yOff);
    stuff->src = lswapl(stuff->src);
    return ProcShapeCombine (client);
}

static int
SProcShapeOffset (client)
    ClientPtr	client;
{
    REQUEST (xShapeOffsetReq);

    stuff->length = lswaps(stuff->length);
    stuff->dest = lswapl(stuff->dest);
    stuff->xOff = lswaps(stuff->xOff);
    stuff->yOff = lswaps(stuff->yOff);
    return ProcShapeOffset (client);
}

static int
SProcShapeQueryExtents (client)
    ClientPtr	client;
{
    REQUEST (xShapeQueryExtentsReq);

    stuff->length = lswaps(stuff->length);
    stuff->window = lswapl(stuff->window);
    return ProcShapeQueryExtents (client);
}

static int
SProcShapeSelectInput (client)
    ClientPtr	client;
{
    REQUEST (xShapeSelectInputReq);

    stuff->length = lswaps(stuff->length);
    stuff->window = lswapl(stuff->window);
    return ProcShapeSelectInput (client);
}

static int
SProcShapeInputSelected (client)
    ClientPtr	client;
{
    REQUEST (xShapeInputSelectedReq);

    stuff->length = lswaps(stuff->length);
    stuff->window = lswapl(stuff->window);
    return ProcShapeInputSelected (client);
}

static int
SProcShapeGetRectangles (client)
    ClientPtr	client;
{
    REQUEST(xShapeGetRectanglesReq);

    stuff->length = lswaps(stuff->length);
    stuff->window = lswapl(stuff->window);
    return ProcShapeGetRectangles (client);
}

static int
SProcShapeDispatch (client)
    ClientPtr	client;
{
    REQUEST(xReq);
    switch (stuff->data) {
    case X_ShapeQueryVersion:
	return SProcShapeQueryVersion (client);
    case X_ShapeRectangles:
	return SProcShapeRectangles (client);
    case X_ShapeMask:
	return SProcShapeMask (client);
    case X_ShapeCombine:
	return SProcShapeCombine (client);
    case X_ShapeOffset:
	return SProcShapeOffset (client);
    case X_ShapeQueryExtents:
	return SProcShapeQueryExtents (client);
    case X_ShapeSelectInput:
	return SProcShapeSelectInput (client);
    case X_ShapeInputSelected:
	return SProcShapeInputSelected (client);
    case X_ShapeGetRectangles:
	return SProcShapeGetRectangles (client);
    default:
	return BadRequest;
    }
}
#endif
