/************************************************************
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.

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

#include "X.h"
#define NEED←REPLIES
#define NEED←EVENTS
#include "Xproto.h"
#include "Xprotostr.h"
#include "windowstr.h"
#include "fontstruct.h"
#include "dixfontstr.h"
#include "gcstruct.h"
#include "osstruct.h"
#include "resource.h"
#include "selection.h"
#include "colormapst.h"
#include "dixstruct.h"
#include "extension.h"
#include "input.h"
#include "cursorstr.h"
#include "scrnintstr.h"
#include "opaque.h"

extern void ProcessInputEvents();
extern WindowRec WindowTable[];
extern xConnSetupPrefix connSetupPrefix;
extern char *ConnectionInfo;
extern char *SwappedConnInfo;

extern void ValidateGC();

Selection *CurrentSelections = (Selection *)NULL;
int NumCurrentSelections = 0;

extern long ScreenSaverTime;
extern long ScreenSaverInterval;
extern int  ScreenSaverBlanking;
extern int  ScreenSaverAllowExposures;
ClientPtr onlyClient;
Bool grabbingClient = FALSE;
long *checkForInput[2];

extern Bool clientsDoomed;

extern int (* ProcVector[256]) ();
extern int (* SwappedProcVector[256]) ();
extern void (* EventSwapVector[128]) ();
extern void (* ReplySwapVector[256]) ();

extern void KillAllClients();

/* buffers for clients. legal values below */
int nextFreeClientID=1;	   /* 0 is for the server */

int	nClients = 0;	/* number active clients */

#define SAME←SCREENS(a, b) (\
    (a.pScreen == b.pScreen))

#define VALIDATE(pGC, pDraw, rt) {\
    if (pGC->serialNumber != pDraw->serialNumber)\
    {\
	ValidateGC(pDraw, pGC);\
    } \
}

#define LEGAL←NEW←RESOURCE(id)\
    if ((LookupID(id, RT←ANY, RC←CORE) != 0) || (id & SERVER←BIT) \
	|| (client->clientAsMask != CLIENT←BITS(id)))\
        return(BadIDChoice)


#define LOOKUP←DRAWABLE(did, client)\
    ((client->lastDrawableID == did) ? \
     (DrawablePtr)client->lastDrawable : (DrawablePtr)LookupDrawable(did, client))

#define VERIFY←GC(pGC, rid, client)\
    if (client->lastGCID == rid)\
    {\
        pGC = (GC *) client->lastGC;\
    }\
    else\
    {\
	pGC = (GC *)LookupID(rid, RT←GC, RC←CORE);\
        if (!pGC)\
        {\
	    client->errorValue = rid;\
	    return (BadGC);\
        }\
    }

#define VALIDATE←DRAWABLE←AND←GC(drawID, pDraw, pGC, client)\
    if ((client->lastDrawableID != drawID) || (client->lastGCID != stuff->gc))\
    {\
        if (client->lastDrawableID != drawID)\
	{\
    	    pDraw = (DrawablePtr)LookupID(drawID, RT←DRAWABLE, RC←CORE);\
    	    if (!pDraw)\
	    {\
	        client->errorValue = drawID; \
                return (BadDrawable);\
	    }\
	    if ((pDraw->type == DRAWABLE←WINDOW) || \
		(pDraw->type == DRAWABLE←PIXMAP))\
    	    {\
	        client->lastDrawable = (pointer)pDraw;\
	        client->lastDrawableID = drawID;\
	    }\
            else\
	    {\
	        client->errorValue = drawID;\
                return (BadDrawable);\
	    }\
        }\
        else\
	    pDraw = (DrawablePtr)client->lastDrawable;\
        if (client->lastGCID != stuff->gc)\
	{\
	    pGC = (GC *)LookupID(stuff->gc, RT←GC, RC←CORE);\
            if (!pGC)\
            {\
	        client->errorValue = stuff->gc;\
	        return (BadGC);\
            }\
            client->lastGC = (pointer)pGC;\
            client->lastGCID = stuff->gc;\
        }\
        else\
            pGC = (GC *) client->lastGC;\
        if ((pGC->depth != pDraw->depth) || (pGC->pScreen != pDraw->pScreen))\
	{\
            client->errorValue = stuff->gc;\
	    client->lastGCID = -1;\
	    return (BadMatch);\
         }\
    }\
    else\
    {\
        pGC = (GC *) client->lastGC;\
        pDraw = (DrawablePtr)client->lastDrawable;\
    }\
    if (pGC->serialNumber != pDraw->serialNumber)\
    { \
	ValidateGC(pDraw, pGC);\
    }

void
SetInputCheck(c0, c1)
    long *c0, *c1;
{
    checkForInput[0] = c0;
    checkForInput[1] = c1;
}

void
InitSelections()
{
    int i;

    if (NumCurrentSelections == 0)
    {    
	CurrentSelections = (Selection *)Xalloc(5 * sizeof(Selection));
	NumCurrentSelections = 5;
    }
    for (i = 0; i< NumCurrentSelections; i++)
	CurrentSelections[i].window = None;
}

void 
FlushClientCaches(id)
    long id;
{
    int i;
    register ClientPtr client;

    for (i=0; i<currentMaxClients; i++)
    {
        if (client == clients[i])
	{
            if (client->lastDrawableID == id)
                client->lastDrawableID = -1;
            else if (client->lastGCID == id)
                client->lastGCID = -1;
	}
    }
}

Dispatch()
{
    ClientPtr	        *clientReady;     /* mask of request ready clients */
    ClientPtr	        *newClients;      /* mask of new clients */ 
    int			result;
    int			i;
    xReq		*request = 0;
    int			ErrorStatus;
    ClientPtr		client;
    int			nready, nnew;

    currentMaxClients = 10;
    clients = (ClientPtr *)Xalloc(currentMaxClients * sizeof(ClientPtr));
    for (i=1; i<currentMaxClients; i++) 
        clients[i] = NullClient;
    clients[0] = serverClient;
    nextFreeClientID = 1;
    InitSelections();
    nClients = 0;
    clientsDoomed = FALSE;

    clientReady = (ClientPtr *) ALLOCATE←LOCAL((int)(sizeof(ClientPtr) * MaxClients));
    newClients = (ClientPtr *)ALLOCATE←LOCAL((int)(sizeof(ClientPtr) * MaxClients));

    while (1) 
    {
StartOver:
        if (*checkForInput[0] != *checkForInput[1])
	    ProcessInputEvents();

	WaitForSomething(clientReady, &nready, newClients, &nnew);

	/*****************
	 *  Establish any new connections
	 *****************/

	while (nnew--)
        {
	    client = newClients[nnew];
	    InitClientResources(client);
	    SendConnectionSetupInfo(client);
	    nClients++;
	}

       /***************** 
	*  Handle events in round robin fashion, doing input between 
	*  each round 
	*****************/

	while ((nready--) > 0)
	{
	    client = clientReady[nready];
	    if (! client)
	    {
		ErrorF( "HORRIBLE ERROR, unused client %d\n", nready);
		continue;
	    }
	    isItTimeToYield = FALSE;
 
            requestingClient = client;
	    while (! isItTimeToYield)
	    {
	        if (*checkForInput[0] != *checkForInput[1])
		    ProcessInputEvents();
	   
		/* now, finally, deal with client requests */

	        request = (xReq *)ReadRequestFromClient(
				      client, &result, (pointer)request);
	        if (result < 0) 
	        {
		    CloseDownClient(client);
		    isItTimeToYield = TRUE;
		    continue;
	        }
	        else if (result == 0)
	        {
		    ErrorF(  "Blocked read in dispatcher\n");
		    ErrorF(  "reqType %d %d\n", 
			     (request ? request->reqType : -1),
			       nready);
		    if (nready > 0)
			continue;
		    else
		        goto StartOver;
		}

		client->sequence++;
		client->requestBuffer = (pointer)request;

		ErrorStatus = (* (client->swapped ?
		    SwappedProcVector : ProcVector)[request->reqType])(client);
	    
		if (ErrorStatus != Success) 
		{
		    if (client->noClientException != Success)
                        CloseDownClient(client);
                    else
		        Oops(client, (char)request->reqType, 0, ErrorStatus);
		    isItTimeToYield = TRUE;
		    continue;
	        }
	    }
	}
	/* Not an error, we just need to know to restart */
	if((nClients == -1) || clientsDoomed)
	    break;         /* so that DEALLOCATE←LOCALs happen */
    }
    if (clientsDoomed)
        KillAllClients();
    DEALLOCATE←LOCAL(newClients);
    DEALLOCATE←LOCAL(clientReady);
    Xfree(clients);
}

int
ProcBadRequest(client)
    ClientPtr client;
{
    return (BadRequest);
}

extern int Ones();

int
ProcCreateWindow(client)
    register ClientPtr client;
{
    register WindowPtr pParent, pWin;
    REQUEST(xCreateWindowReq);
    int result;
    int len;

    REQUEST←AT←LEAST←SIZE(xCreateWindowReq);
    
    LEGAL←NEW←RESOURCE(stuff->wid); 
    if (!(pParent = (WindowPtr)LookupWindow(stuff->parent, client)))
        return BadWindow;
    len = stuff->length -  (sizeof(xCreateWindowReq) >> 2);
    if (Ones(stuff->mask) != len)
        return BadLength;
    if (!stuff->width || !stuff->height)
        return BadValue;
    pWin = CreateWindow(stuff->wid, pParent, stuff->x,
			      stuff->y, stuff->width, stuff->height, 
			      stuff->borderWidth, stuff->class,
			      stuff->mask, (long *) &stuff[1], 
			      stuff->depth, 
			      client, stuff->visual, &result);
    if (pWin)
        AddResource(stuff->wid, RT←WINDOW, (pointer)pWin, DeleteWindow, RC←CORE);
    if (client->noClientException != Success)
        return(client->noClientException);
    else
        return(result);
}

int
ProcChangeWindowAttributes(client)
    register ClientPtr client;
{
    register WindowPtr pWin;
    REQUEST(xChangeWindowAttributesReq);
    register int result;
    int len;

    REQUEST←AT←LEAST←SIZE(xChangeWindowAttributesReq);
    pWin = (WindowPtr)LookupWindow(stuff->window, client);
    if (!pWin)
        return(BadWindow);
    len = stuff->length - (sizeof(xChangeWindowAttributesReq) >> 2);
    if (len != Ones(stuff->valueMask))
        return BadLength;
    client->lastDrawableID = -1;   
    result =  ChangeWindowAttributes(pWin, 
				  (unsigned long)stuff->valueMask, 
				  (long *) &stuff[1], 
				  client);
    if (client->noClientException != Success)
        return(client->noClientException);
    else
        return(result);
}

int
ProcGetWindowAttributes(client)
    register ClientPtr client;
{
    register WindowPtr pWin;
    REQUEST(xResourceReq);

    REQUEST←SIZE←MATCH(xResourceReq);
    pWin = (WindowPtr)LookupWindow(stuff->id, client);
    if (!pWin)
        return(BadWindow);
    GetWindowAttributes(pWin, client);
    return(client->noClientException);
}

int
ProcDestroyWindow(client)
    register ClientPtr client;
{
    register WindowPtr pWin;
    REQUEST(xResourceReq);

    REQUEST←SIZE←MATCH(xResourceReq);
    pWin = (WindowPtr)LookupWindow(stuff->id, client);
    if (!pWin)
        return(BadWindow);
    FreeResource(stuff->id, RC←NONE);
    return(client->noClientException);
}

int
ProcDestroySubwindows(client)
    register ClientPtr client;
{
    register WindowPtr pWin;
    REQUEST(xResourceReq);

    REQUEST←SIZE←MATCH(xResourceReq);
    pWin = (WindowPtr)LookupWindow(stuff->id, client);
    if (!pWin)
        return(BadWindow);
    DestroySubwindows(pWin, client);
    return(client->noClientException);
}

int
ProcChangeSaveSet(client)
    register ClientPtr client;
{
    register WindowPtr pWin;
    REQUEST(xChangeSaveSetReq);
    register result;
		  
    REQUEST←SIZE←MATCH(xChangeSaveSetReq);
    pWin = (WindowPtr)LookupWindow(stuff->window, client);
    if (!pWin)
        return(BadWindow);
    if (client->clientAsMask == (CLIENT←ID(pWin->wid)))
        return BadMatch;
    if ((stuff->mode == SetModeInsert) || (stuff->mode == SetModeDelete))
    {
        result = AlterSaveSetForClient(client, (pointer)pWin, (char)stuff->mode);
	if (client->noClientException != Success)
	    return(client->noClientException);
	else
            return(result);
    }
    else
	return( BadValue );
}

int
ProcReparentWindow(client)
    register ClientPtr client;
{
    register WindowPtr pWin, pParent;
    REQUEST(xReparentWindowReq);
    register int result;

    REQUEST←SIZE←MATCH(xReparentWindowReq);
    pWin = (WindowPtr)LookupWindow(stuff->window, client);
    if (!pWin)
        return(BadWindow);
    pParent = (WindowPtr)LookupWindow(stuff->parent, client);
    if (!pParent)
        return(BadWindow);
    if (SAME←SCREENS(pWin->drawable, pParent->drawable))
    {
        if ((pWin->backgroundTile == (PixmapPtr)ParentRelative) &&
            (pParent->drawable.depth != pWin->drawable.depth))
            return BadMatch;
        result =  ReparentWindow(pWin, pParent, 
			 (short)stuff->x, (short)stuff->y, client);
	if (client->noClientException != Success)
            return(client->noClientException);
	else
            return(result);
    }
    else 
        return (BadMatch);
}

int
ProcMapWindow(client)
    register ClientPtr client;
{
    register WindowPtr pWin;
    REQUEST(xResourceReq);

    REQUEST←SIZE←MATCH(xResourceReq);
    pWin = (WindowPtr)LookupWindow(stuff->id, client);
    if (!pWin)
        return(BadWindow);
    MapWindow(pWin, HANDLE←EXPOSURES, BITS←DISCARDED,
		  SEND←NOTIFICATION, client);
           /* update cache to say it is mapped */
    return(client->noClientException);
}

int
ProcMapSubwindows(client)
    register ClientPtr client;
{
    register WindowPtr pWin;
    REQUEST(xResourceReq);

    REQUEST←SIZE←MATCH(xResourceReq);
    pWin = (WindowPtr)LookupWindow( stuff->id, client);
    if (!pWin)
        return(BadWindow);
    MapSubwindows(pWin, HANDLE←EXPOSURES, client);
           /* update cache to say it is mapped */
    return(client->noClientException);
}

int
ProcUnmapWindow(client)
    register ClientPtr client;
{
    register WindowPtr pWin;
    REQUEST(xResourceReq);

    REQUEST←SIZE←MATCH(xResourceReq);
    pWin = (WindowPtr)LookupWindow( stuff->id, client);
    if (!pWin)
        return(BadWindow);
    UnmapWindow(pWin, HANDLE←EXPOSURES, SEND←NOTIFICATION, FALSE);
           /* update cache to say it is mapped */
    return(client->noClientException);
}

int
ProcUnmapSubwindows(client)
    register ClientPtr client;
{
    register WindowPtr pWin;
    REQUEST(xResourceReq);

    REQUEST←SIZE←MATCH(xResourceReq);
    pWin = (WindowPtr)LookupWindow( stuff->id, client);
    if (!pWin)
        return(BadWindow);
    UnmapSubwindows(pWin, HANDLE←EXPOSURES);
    return(client->noClientException);
}

int
ProcConfigureWindow(client)
    register ClientPtr client;
{
    register WindowPtr pWin;
    REQUEST(xConfigureWindowReq);
    register int result;
    int len;

    REQUEST←AT←LEAST←SIZE(xConfigureWindowReq);
    pWin = (WindowPtr)LookupWindow( stuff->window, client);
    if (!pWin)
        return(BadWindow);
    len = stuff->length - (sizeof(xConfigureWindowReq) >> 2);
    if (Ones((long)stuff->mask) != len)
        return BadLength;
    result =  ConfigureWindow(pWin, (unsigned long)stuff->mask, (long *) &stuff[1], 
			      client);
    if (client->noClientException != Success)
        return(client->noClientException);
    else
        return(result);
}

int
ProcCirculateWindow(client)
    register ClientPtr client;
{
    register WindowPtr pWin;
    REQUEST(xCirculateWindowReq);

    REQUEST←SIZE←MATCH(xCirculateWindowReq);
    if ((stuff->direction != RaiseLowest) &&
	(stuff->direction != LowerHighest))
        return BadValue;
    pWin = (WindowPtr)LookupWindow(stuff->window, client);
    if (!pWin)
        return(BadWindow);
    CirculateWindow(pWin, (int)stuff->direction, client);
    return(client->noClientException);
}

int
ProcGetGeometry(client)
    register ClientPtr client;
{
    xGetGeometryReply rep;
    register DrawablePtr pDraw;
    REQUEST(xResourceReq);

    REQUEST←SIZE←MATCH(xResourceReq);
    if (!(pDraw = LOOKUP←DRAWABLE(stuff->id, client)))
        return (BadDrawable);

    rep.type = X←Reply;
    rep.length = 0;
    rep.sequenceNumber = client->sequence;
    rep.root = WindowTable[pDraw->pScreen->myNum].wid;
    rep.depth = pDraw->depth;

    if (pDraw->type == DRAWABLE←PIXMAP)
    {
	PixmapPtr pPixmap = (PixmapPtr)pDraw;

	rep.x = rep.y = rep.borderWidth = 0;
	rep.width = pPixmap->width;
	rep.height = pPixmap->height;
    }
    else
    {
        register WindowPtr pWin = (WindowPtr)pDraw;
	rep.x = pWin->clientWinSize.x - pWin->borderWidth;
	rep.y = pWin->clientWinSize.y - pWin->borderWidth;
	rep.borderWidth = pWin->borderWidth;
	rep.width = pWin->clientWinSize.width;
	rep.height = pWin->clientWinSize.height;
    }
    WriteReplyToClient(client, sizeof(xGetGeometryReply), &rep);
    return(client->noClientException);
}

int
ProcQueryTree(client)
    register ClientPtr client;
{

    xQueryTreeReply reply;
    int numChildren = 0;
    register WindowPtr pChild, pWin;
    Window  *childIDs = (Window *)NULL;
    REQUEST(xResourceReq);

    REQUEST←SIZE←MATCH(xResourceReq);
    pWin = (WindowPtr)LookupWindow(stuff->id, client);
    if (!pWin)
        return(BadWindow);
    reply.type = X←Reply;
    reply.root = WindowTable[pWin->drawable.pScreen->myNum].wid;
    reply.sequenceNumber = client->sequence;
    if (pWin->parent)
	reply.parent = pWin->parent->wid;
    else
        reply.parent = (Window)None;
    if (pChild = pWin->lastChild)
    {
	int csize = 10;

	childIDs = (Window *) Xalloc(csize * sizeof(Window));
	while (pChild) 
        {
	    *childIDs = pChild->wid;
	    childIDs++;
	    numChildren++;
	    if (numChildren > csize)
	    {
		csize *= 2;
		childIDs = (Window *) Xrealloc(childIDs, 
				sizeof(Window) * csize);
		childIDs += numChildren;
	    }
	    pChild = pChild->prevSib;
	}
	reply.nChildren = numChildren;
	reply.length = (numChildren * sizeof(Window)) >> 2;
	WriteReplyToClient(client, sizeof(xQueryTreeReply), &reply);
	if (numChildren)
	{
	    childIDs -= numChildren;
	    WriteReplyToClient(client, numChildren * sizeof(Window), childIDs);
	    Xfree(childIDs);
	}
    }
    else
    {        
	reply.nChildren = 0;
	reply.length = 0;
	WriteReplyToClient(client, sizeof(xQueryTreeReply), &reply);
    }        
    return(client->noClientException);
}

int
ProcInternAtom(client)
    register ClientPtr client;
{
    Atom atom;
    char *tchar;
    REQUEST(xInternAtomReq);

    REQUEST←AT←LEAST←SIZE(xInternAtomReq);
    tchar = (char *) &stuff[1];
    atom = MakeAtom(tchar, (int)stuff->nbytes, !stuff->onlyIfExists);
    if (atom || stuff->onlyIfExists)
    {
	xInternAtomReply reply;
	reply.type = X←Reply;
	reply.length = 0;
	reply.sequenceNumber = client->sequence;
	reply.atom = (atom ? atom : None);
	WriteReplyToClient(client, sizeof(xInternAtomReply), &reply);
	return(client->noClientException);
    }
    else
	return (BadAlloc);
}

int
ProcGetAtomName(client)
    register ClientPtr client;
{
    char *str;
    xGetAtomNameReply reply;
    int len;
    REQUEST(xResourceReq);

    REQUEST←SIZE←MATCH(xResourceReq);
    if (str = (char *)NameForAtom(stuff->id)) 
    {
	len = strlen(str);
	reply.type = X←Reply;
	reply.length = (len + 3) >> 2;
	reply.sequenceNumber = client->sequence;
	reply.nameLength = len;
	WriteReplyToClient(client, sizeof(xGetAtomNameReply), &reply);
	WriteReplyToClient(client, len, str);
	return(client->noClientException);
    }
    else 
    { 
	client->errorValue = stuff->id;
	return (BadAtom);
    }
}

int 
ProcDeleteProperty(client)
    register ClientPtr client;
{
    WindowPtr pWin;
    REQUEST(xDeletePropertyReq);
    int result;
              
    REQUEST←SIZE←MATCH(xDeletePropertyReq);
    pWin = (WindowPtr)LookupWindow(stuff->window, client);
    if (!pWin)
        return(BadWindow);
    if (ValidAtom(stuff->property))
    {
	result = DeleteProperty(pWin, (ATOM) stuff->property);
        if (client->noClientException != Success)
            return(client->noClientException);
	else
	    return(result);
    }
    else 
	return (BadAtom);
}


int
ProcSetSelectionOwner(client)
    register ClientPtr client;
{
    WindowPtr pWin;
    REQUEST(xSetSelectionOwnerReq);

    REQUEST←SIZE←MATCH(xSetSelectionOwnerReq);
    if (stuff->window != None)
    {
        pWin = (WindowPtr)LookupWindow(stuff->window, client);
        if (!pWin)
            return(BadWindow);
    }
    else
        pWin = (WindowPtr)None;
    if (ValidAtom(stuff->selection))
    {
	int i = 0;

	/*
	 * First, see if the selection is already set... 
	 */
	while ((i < NumCurrentSelections) && 
	       CurrentSelections[i].selection != stuff->selection) 
            i++;
        if (i < NumCurrentSelections)
        {        
	    xEvent event;

            if (CurrentSelections[i].pWin != (WindowPtr)None)
	    {
		event.u.u.type = SelectionClear;
		event.u.selectionClear.time = 0;
		event.u.selectionClear.window = CurrentSelections[i].window;
		event.u.selectionClear.atom = CurrentSelections[i].selection;
		DeliverEvents(CurrentSelections[i].pWin, &event, 1, (long)0);
	    }
	    CurrentSelections[i].selection = stuff->selection;
	    CurrentSelections[i].window = stuff->window;
	    CurrentSelections[i].pWin = pWin;
	    return (client->noClientException);
	}
	/*
	 * It doesn't exist, so add it...
	 */
	i = 0;
	while ((i < NumCurrentSelections) && 
	       CurrentSelections[i].window != 0) 
            i++;
	if (i == NumCurrentSelections)   /* there's no room, grow array */
	{
	    NumCurrentSelections += 5;
	    CurrentSelections = 
			(Selection *)Xrealloc(CurrentSelections, 
			NumCurrentSelections * sizeof(Selection));
	}
	CurrentSelections[i].selection = stuff->selection;
	CurrentSelections[i].window = stuff->window;
	CurrentSelections[i].pWin = pWin;
	return (client->noClientException);
    }
    else 
        return (BadAtom);
}

int
ProcGetSelectionOwner(client)
    register ClientPtr client;
{
    REQUEST(xResourceReq);

    REQUEST←SIZE←MATCH(xResourceReq);
    if (ValidAtom(stuff->id))
    {
	int i;
        xGetSelectionOwnerReply reply;

	i = 0;
        while ((i < NumCurrentSelections) && 
	       CurrentSelections[i].selection != stuff->id) i++;
        reply.type = X←Reply;
	reply.length = 0;
	reply.sequenceNumber = client->sequence;
        if (i < NumCurrentSelections)
            reply.owner = CurrentSelections[i].window;
        else
            reply.owner = None;
        WriteReplyToClient(client, sizeof(xGetSelectionOwnerReply), &reply);
        return(client->noClientException);
    }
    else            
        return (BadAtom); 
}

int
ProcConvertSelection(client)
    register ClientPtr client;
{
    Bool paramsOkay = TRUE;
    xEvent event;
    WindowPtr pWin;
    REQUEST(xConvertSelectionReq);

    REQUEST←SIZE←MATCH(xConvertSelectionReq);
    pWin = (WindowPtr)LookupWindow(stuff->requestor, client);
    if (!pWin)
        return(BadWindow);

    paramsOkay = (ValidAtom(stuff->selection) && ValidAtom(stuff->target));
    if (stuff->property != None)
	paramsOkay &= ValidAtom(stuff->property);
    if (paramsOkay)
    {
	int i;

	i = 0;
	while ((i < NumCurrentSelections) && 
	       CurrentSelections[i].selection != stuff->selection) i++;
	if ((i < NumCurrentSelections) && 
	    (CurrentSelections[i].window != None))
	{        
	    event.u.u.type = SelectionRequest;
	    event.u.selectionRequest.time = 0;
	    event.u.selectionRequest.owner = 
			CurrentSelections[i].window;
	    event.u.selectionRequest.requestor = stuff->requestor;
	    event.u.selectionRequest.selection = stuff->selection;
	    event.u.selectionRequest.target = stuff->target;
	    event.u.selectionRequest.property = stuff->property;
	    DeliverEvents(CurrentSelections[i].pWin, &event, 1, (long)0);
	}
	else    /* didn't find so send SelectionNotify */
	{
	    event.u.u.type = SelectionNotify;
	    event.u.selectionNotify.time = 0;
	    event.u.selectionNotify.requestor = stuff->requestor;
	    event.u.selectionNotify.selection = stuff->selection;
	    event.u.selectionNotify.target = stuff->target;
	    event.u.selectionNotify.property = None;
	    DeliverEvents(pWin, &event, 1, (long)0);
	}
	return (client->noClientException);
    }
    else 
        return (BadAtom);
}

int
ProcGrabServer(client)
    register ClientPtr client;
{
    OnlyListenToOneClient(client);
    grabbingClient = TRUE;
    onlyClient = client;
    return(client->noClientException);
}

int
ProcUngrabServer(client)
    register ClientPtr client;
{
    REQUEST(xReq);
    REQUEST←SIZE←MATCH(xReq);
    grabbingClient = FALSE;
    ListenToAllClients();
    return(client->noClientException);
}

int
ProcTranslateCoords(client)
    register ClientPtr client;
{
    REQUEST(xTranslateCoordsReq);

    register WindowPtr pWin, pDst;
    xTranslateCoordsReply rep;

    REQUEST←SIZE←MATCH(xTranslateCoordsReq);
    pWin = (WindowPtr)LookupWindow(stuff->srcWid, client);
    if (!pWin)
        return(BadWindow);
    pDst = (WindowPtr)LookupWindow(stuff->dstWid, client);
    if (!pDst)
        return(BadWindow);
    rep.type = X←Reply;
    rep.length = 0;
    rep.sequenceNumber = client->sequence;
    if (!SAME←SCREENS(pWin->drawable, pDst->drawable))
    {
	rep.sameScreen = xFalse;
        rep.child = None;
	rep.dstX = rep.dstY = 0;
    }
    else
    {
	INT16 x, y;
	rep.sameScreen = xTrue;
	rep.child = None;
	x = pWin->absCorner.x + stuff->srcX - pDst->absCorner.x;
	y = pWin->absCorner.y + stuff->srcY - pDst->absCorner.y;
	pWin = pDst->firstChild;
	while (pWin)
	{
	    if ((pWin->mapped) &&
		(x >= pWin->absCorner.x - pWin->borderWidth) &&
		(x < pWin->absCorner.x + pWin->clientWinSize.width +
		 pWin->borderWidth) &&
		(y >= pWin->absCorner.y - pWin->borderWidth) &&
		(y < pWin->absCorner.y + pWin->clientWinSize.height
		 + pWin->borderWidth))
            {
		rep.child = pWin->wid;
		pWin = (WindowPtr) NULL;
	    }
	    else
		pWin = pWin->nextSib;
	}
	rep.dstX = x;
	rep.dstY = y;
    }
    WriteReplyToClient(client, sizeof(xTranslateCoordsReply), &rep);
    return(client->noClientException);
}

int
ProcOpenFont(client)
    register ClientPtr client;
{
    FontPtr pFont;
    REQUEST(xOpenFontReq);

    REQUEST←AT←LEAST←SIZE(xOpenFontReq);
    client->errorValue = stuff->fid;
    LEGAL←NEW←RESOURCE(stuff->fid);
    if ( pFont = OpenFont( (int)stuff->nbytes, (char *)&stuff[1]))
    {
	AddResource( stuff->fid, RT←FONT, (pointer)pFont, CloseFont,RC←CORE);
	return(client->noClientException);
    }
    else
	return (BadName);
}

int
ProcCloseFont(client)
    register ClientPtr client;
{
    FontPtr pFont;
    REQUEST(xResourceReq);

    REQUEST←SIZE←MATCH(xResourceReq);
    pFont = (FontPtr)LookupID(stuff->id, RT←FONT, RC←CORE);
    if ( pFont != (FontPtr)NULL)	/* id was valid */
    {
        FreeResource( stuff->id, RC←NONE);
	return(client->noClientException);
    }
    else
        return (BadFont);
}

int
ProcQueryFont(client)
    register ClientPtr client;
{
    xQueryFontReply	*reply;
    FontPtr pFont;
    register GC *pGC;
    REQUEST(xResourceReq);

    REQUEST←SIZE←MATCH(xResourceReq);
    client->errorValue = stuff->id;		/* EITHER font or gc */
    pFont = (FontPtr)LookupID(stuff->id, RT←FONT, RC←CORE);
    if (!pFont)
    {
	VERIFY←GC(pGC, stuff->id, client);
        if (!pGC)
            return(BadGC);
	pFont = pGC->font;
    }

    {
	CharInfoPtr	pmax = &pFont->pFI->maxbounds;
	CharInfoPtr	pmin = &pFont->pFI->minbounds;
	int		nprotoxcistructs;
	int		rlength;

	nprotoxcistructs = (
	   pmax->metrics.rightSideBearing == pmin->metrics.rightSideBearing &&
	   pmax->metrics.leftSideBearing == pmin->metrics.leftSideBearing &&
	   pmax->metrics.descent == pmin->metrics.descent &&
	   pmax->metrics.ascent == pmin->metrics.ascent &&
	   pmax->metrics.characterWidth == pmin->metrics.characterWidth) ?
		0 : n2dChars(pFont->pFI);

	rlength = sizeof(xQueryFontReply) +
	             pFont->pFI->nProps * sizeof(xFontProp)  +
		     nprotoxcistructs * sizeof(xCharInfo);
	reply = (xQueryFontReply *)ALLOCATE←LOCAL(rlength);
	if(!reply)
	{
	    return(client->noClientException = BadAlloc);
	}

	reply->type = X←Reply;
	reply->length = (rlength - sizeof(xGenericReply)) >> 2;
	reply->sequenceNumber = client->sequence;
	QueryFont( pFont, reply, nprotoxcistructs);

        WriteReplyToClient(client, rlength, reply);
	DEALLOCATE←LOCAL(reply);
	return(client->noClientException);
    }
}

int
ProcQueryTextExtents(client)
    register ClientPtr client;
{
    REQUEST(xQueryTextExtentsReq);
    xQueryTextExtentsReply reply;
    FontPtr pFont;
    GC *pGC;
    ExtentInfoRec info;
    short length;

    REQUEST←AT←LEAST←SIZE(xQueryTextExtentsReq);
        
    pFont = (FontPtr)LookupID( stuff->fid, RT←FONT, RC←CORE);
    if (!pFont)
    {
        pGC = (GC *)LookupID( stuff->fid, RT←GC, RC←CORE);
        if (!pGC)
            return(BadFont);
	pFont = pGC->font;
    }
    length = stuff->length - (sizeof(xQueryTextExtentsReq) >> 2);
    length = length << 1;
    if (stuff->oddLength)
        length--;
    QueryTextExtents(pFont, (unsigned int)length, (unsigned short *)&stuff[1], &info);   
    reply.type = X←Reply;
    reply.length = 0;
    reply.sequenceNumber = client->sequence;
    reply.drawDirection = info.drawDirection;
    reply.fontAscent = info.fontAscent;
    reply.fontDescent = info.fontDescent;
    reply.overallAscent = info.overallAscent;
    reply.overallDescent = info.overallDescent;
    reply.overallWidth = info.overallWidth;
    reply.overallLeft = info.overallLeft;
    reply.overallRight = info.overallRight;
    WriteReplyToClient(client, sizeof(xQueryTextExtentsReply), &reply);
    return(client->noClientException);
}

int
ProcListFonts(client)
    register ClientPtr client;
{
    xListFontsReply reply; 
    FontPathPtr fpr;
    int stringLens, i;
    char *bufptr, *bufferStart;
    REQUEST(xListFontsReq);

    REQUEST←AT←LEAST←SIZE(xListFontsReq);

    fpr = ExpandFontNamePattern( (int)stuff->nbytes, 
				 (char *) &stuff[1], (int)stuff->maxNames);
    stringLens = 0;
    for (i=0; i<fpr->npaths; i++)
        stringLens += fpr->length[i];

    reply.type = X←Reply;
    reply.length = (stringLens + fpr->npaths + 3) >> 2;
    reply.nFonts = fpr->npaths;
    reply.sequenceNumber = client->sequence;

    bufptr = bufferStart = (char *)ALLOCATE←LOCAL((int)reply.length << 2);
    if(!bufptr)
        return(client->noClientException = BadAlloc);

            /* since WriteToClient long word aligns things, 
	       copy to temp buffer and write all at once */
    for (i=0; i<fpr->npaths; i++)
    {
        *bufptr++ = fpr->length[i];
        bcopy(fpr->paths[i], bufptr,  fpr->length[i]);
        bufptr += fpr->length[i];
    }
    WriteReplyToClient(client, sizeof(xListFontsReply), &reply);
    WriteReplyToClient(client, reply.length << 2, bufferStart);
    FreeFontRecord(fpr);
    DEALLOCATE←LOCAL(bufferStart);
    
    return(client->noClientException);
}

int
ProcListFontsWithInfo(client)
    register ClientPtr client;
{
    xListFontsWithInfoReply reply; 
    FontDataRec fdr;
    FontPathPtr fpr;
    int stringLens, i;
    char *bufptr, *bufferStart;
    REQUEST(xListFontsWithInfoReq);

    REQUEST←AT←LEAST←SIZE(xListFontsWithInfoReq);

    fpr = ExpandFontNamePattern( (int)stuff->nbytes, (char *)&stuff[1], (int)stuff->maxNames);
    fdr.nfonts = fpr->npaths;
    fdr.pFI = (FontInfoPtr)ALLOCATE←LOCAL(sizeof(FontInfoRec) * fdr.nfonts);
    fdr.pFP = (DIXFontProp **)ALLOCATE←LOCAL(sizeof(DIXFontProp) * fdr.nfonts);
    if(!fdr.pFI || !fdr.pFP)
    {
	DEALLOCATE←LOCAL(fdr.pFP);
	DEALLOCATE←LOCAL(fdr.pFI);
        return(client->noClientException = BadAlloc);
    }

    DescribeFontList(fpr, &fdr);
    stringLens = 0;
    for (i=0; i<fpr->npaths; i++)
        stringLens += fpr->length[i];

    reply.type = X←Reply;
    reply.length = (stringLens + fpr->npaths + 3) >> 2;
    reply.nFonts = fpr->npaths;
    reply.sequenceNumber = client->sequence;

    if(!(bufptr = bufferStart = (char *)ALLOCATE←LOCAL((int)reply.length << 2)))
        return(client->noClientException = BadAlloc);
	
            /* since WriteToClient long word aligns things, 
	       copy to temp buffer and write all at once */
    for (i=0; i<fpr->npaths; i++)
    {
        *bufptr++ = fpr->length[i];
        bcopy(fpr->paths[i], bufptr,  fpr->length[i]);
        bufptr += fpr->length[i];
    }
    WriteReplyToClient(client, sizeof(xListFontsWithInfoReply), &reply);
    WriteReplyToClient(client, reply.length << 2, bufferStart);
    FreeFontRecord(fpr);
    DEALLOCATE←LOCAL(bufferStart);
    DEALLOCATE←LOCAL(fdr.pFP);
    DEALLOCATE←LOCAL(fdr.pFI);
    return(client->noClientException);
}

int
ProcCreatePixmap(client)
    register ClientPtr client;
{
    PixmapPtr pMap;
    register DrawablePtr pDraw;
    REQUEST(xCreatePixmapReq);
    DepthPtr pDepth;
    register int i;

    REQUEST←AT←LEAST←SIZE(xCreatePixmapReq);
    client->errorValue = stuff->pid;
    LEGAL←NEW←RESOURCE(stuff->pid);
    if (!(pDraw = LOOKUP←DRAWABLE(stuff->drawable, client)))
        return (BadDrawable);

    if (!stuff->width || !stuff->height)
        return BadValue;
    if (stuff->depth != 1)
    {
        pDepth = pDraw->pScreen->allowedDepths;
        for (i=0; i<pDraw->pScreen->numDepths; i++, pDepth++)
	   if (pDepth->depth == stuff->depth)
               goto CreatePmap;
        return BadValue;
    }
CreatePmap:
    pMap = (PixmapPtr)(*pDraw->pScreen->CreatePixmap)
		(pDraw->pScreen, stuff->width,
		 stuff->height, stuff->depth);
    if (pMap)
    {
	pMap->drawable.serialNumber = NEXT←SERIAL←NUMBER;
	AddResource(
	    stuff->pid, RT←PIXMAP, (pointer)pMap, pDraw->pScreen->DestroyPixmap,
	    RC←CORE);
	return(client->noClientException);
    }
    else
	return (BadAlloc);
}

int
ProcFreePixmap(client)
    register ClientPtr client;
{
    PixmapPtr pMap;

    REQUEST(xResourceReq);

    REQUEST←SIZE←MATCH(xResourceReq);
    pMap = (PixmapPtr)LookupID(stuff->id, RT←PIXMAP, RC←CORE);
    if (pMap) 
    {
	FreeResource(stuff->id, RC←NONE);
	return(client->noClientException);
    }
    else 
    {
	client->errorValue = stuff->id;
	return (BadPixmap);
    }
}