/************************************************************
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 WindowRec WindowTable[];
extern xConnSetupPrefix connSetupPrefix;
extern char *ConnectionInfo;
extern char *SwappedConnInfo;

extern void ValidateGC();

extern Selection *CurrentSelections;
extern int NumCurrentSelections;

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

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

void KillAllClients();

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

extern int	nClients;	/* number active clients */

extern int ProcBadRequest();

#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);\
    }

int
ProcFillPoly(client)
    register ClientPtr client;
{
    int          things;
    register GC *pGC;
    register DrawablePtr pDraw;
    REQUEST(xFillPolyReq);

    REQUEST←AT←LEAST←SIZE(xFillPolyReq);
    if ((stuff->shape != Complex) && (stuff->shape != Nonconvex) &&  
	(stuff->shape != Convex) && (stuff->coordMode != CoordModeOrigin) && 
	(stuff->coordMode != CoordModePrevious))
        return BadValue;

    VALIDATE←DRAWABLE←AND←GC(stuff->drawable, pDraw, pGC, client);
    things = ((stuff->length << 2) - sizeof(xFillPolyReq)) >> 2;
    if (things)
        (*pGC->FillPolygon) (pDraw, pGC, stuff->shape,
			 stuff->coordMode, things,
			 (DDXPointPtr) &stuff[1]);
    return(client->noClientException);
}

int
ProcPolyFillRectangle(client)
    register ClientPtr client;
{
    int             things;
    register GC *pGC;
    register DrawablePtr pDraw;
    REQUEST(xPolyFillRectangleReq);

    REQUEST←AT←LEAST←SIZE(xPolyFillRectangleReq);
    VALIDATE←DRAWABLE←AND←GC(stuff->drawable, pDraw, pGC, client);
    things = ((stuff->length << 2) - 
	      sizeof(xPolyFillRectangleReq)) >> 3;
    if (things)
        (*pGC->PolyFillRect) (pDraw, pGC, things,
		      (xRectangle *) &stuff[1]);
    return (client->noClientException);
}

int
ProcPolyFillArc               (client)
    register ClientPtr client;
{
    int		narcs;
    register GC *pGC;
    register DrawablePtr pDraw;
    REQUEST(xPolyFillArcReq);

    REQUEST←AT←LEAST←SIZE(xPolyFillArcReq);
    VALIDATE←DRAWABLE←AND←GC(stuff->drawable, pDraw, pGC, client);
    narcs = ((stuff->length << 2) - 
	     sizeof(xPolyFillArcReq)) / sizeof(xArc);
    if (narcs)
        (*pGC->PolyFillArc) (pDraw, pGC, narcs, (xArc *) &stuff[1]);
    return (client->noClientException);
}

int
ProcPutImage(client)
    register ClientPtr client;
{
    register GC *pGC;
    register DrawablePtr pDraw;
    REQUEST(xPutImageReq);

    REQUEST←AT←LEAST←SIZE(xPutImageReq);
    VALIDATE←DRAWABLE←AND←GC(stuff->drawable, pDraw, pGC, client);
    if (stuff->format == XYBitmap)
    {
        if ((stuff->depth != 1) || (stuff->leftPad > screenInfo.bitmapScanlineUnit))
            return BadMatch;
    }
    else if (stuff->format == XYPixmap)
    {
        if ((pDraw->depth != stuff->depth) || 
	    (stuff->leftPad > screenInfo.bitmapScanlineUnit))
            return BadMatch;
    }
    else if (stuff->format == ZPixmap)
    {
        if ((pDraw->depth != stuff->depth) || (stuff->leftPad != 0))
            return BadMatch;
    }
    else
        return BadValue;
    (*pGC->PutImage) (pDraw, pGC, stuff->depth, stuff->dstX, stuff->dstY,
		  stuff->width, stuff->height, 
		  stuff->leftPad, stuff->format, 
		  (int *) &stuff[1]);
     return (client->noClientException);
}

int
ProcGetImage(client)
    register ClientPtr	client;
{
    register DrawablePtr pDraw;
    int			nlines, linesDone, widthLine, linesPerBuf,
                         widthBytesLine, height;
    char		*pBuf;
    xGetImageReply	xgi;

    REQUEST(xGetImageReq);

    height = stuff->height;
    REQUEST←SIZE←MATCH(xGetImageReq);
    if ((stuff->format != XYPixmap) && (stuff->format != ZPixmap))
        return(BadValue);
    if(!(pDraw = LOOKUP←DRAWABLE(stuff->drawable, client) ))
	return (BadDrawable);
    if(pDraw->type == DRAWABLE←WINDOW)
    {
	if(((WindowPtr) pDraw)->absCorner.x + stuff->x < 0 ||
	   ((WindowPtr) pDraw)->absCorner.x + stuff->x + stuff->width >
	       pDraw->pScreen->width ||
	   ((WindowPtr) pDraw)->absCorner.y + stuff->y < 0 ||
	   ((WindowPtr) pDraw)->absCorner.y + stuff->y + height >
	       pDraw->pScreen->height)
	    return(BadMatch);
	xgi.visual = ((WindowPtr) pDraw)->visual;
    }
    else
    {
	xgi.visual = None;
    }
    xgi.type = X←Reply;
    xgi.depth = pDraw->depth;
    if(stuff->format == ZPixmap)
    {
	widthLine = stuff->width;
	widthBytesLine = widthLine << 2;
    }
    else 
    {
	widthLine = PixmapWidthInPadUnits(stuff->width, pDraw->depth);
	widthBytesLine = PixmapBytePad(stuff->width, pDraw->depth);
    }
    xgi.length = widthLine * height;
    linesPerBuf = IMAGE←BUFSIZE / widthBytesLine;
    if(!(pBuf = (char *) ALLOCATE←LOCAL(IMAGE←BUFSIZE)))
        return (client->noClientException = BadAlloc);

    WriteReplyToClient(client, sizeof (xGetImageReply), &xgi);

    linesDone = 0;
    while (height - linesDone > 0)
    {
	nlines = min(linesPerBuf, height - linesDone);
	(*pDraw->pScreen->GetImage) (pDraw,
	                             stuff->x,
				     stuff->y + linesDone,
				     stuff->width, 
				     nlines,
				     stuff->format,
				     stuff->planeMask,
				     (int *)pBuf);
	/* Note that this is NOT a call to WriteReplyToClient, as we do NOT
	 * byte swap */
	WriteToClient(client, nlines * widthBytesLine, pBuf);
	linesDone += nlines;

    }
    
    DEALLOCATE←LOCAL(pBuf);
    return (client->noClientException);
}


int
ProcPolyText(client)
    register ClientPtr client;
{
    int		xorg;
    REQUEST(xPolyTextReq);
    register DrawablePtr pDraw;
    register GC *pGC;
    register FontPtr pFont;

    int (* polyText)();
    register unsigned char *pElt;
    unsigned char *pNextElt;
    unsigned char *endReq;
    int		itemSize;
    Bool	swapped16;	/* True iff we are handling swapped Text16 */
    
#define TextEltHeader 2
#define FontShiftSize 5

    REQUEST←AT←LEAST←SIZE(xPolyTextReq);
    VALIDATE←DRAWABLE←AND←GC(stuff->drawable, pDraw, pGC, client);

    pElt = (unsigned char *)&stuff[1];
    endReq = ((unsigned char *) stuff) + (stuff->length <<2);
    xorg = stuff->x;
    if (stuff->reqType == X←PolyText8)
    {
	polyText = pGC->PolyText8;
	itemSize = 1;
	swapped16 = FALSE;
    }
    else
    {
	polyText =  pGC->PolyText16;
	itemSize = 2;
	swapped16 = client->swapped;
    }

    while (endReq - pElt > TextEltHeader)
    {
	if (*pElt == FontChange)
        {
	    Font	fid;

	    if (endReq - pElt < FontShiftSize)
		 return (BadLength);
	    fid =  *(pElt+4)		/* big-endian */
		 | *(pElt+3) << 8
		 | *(pElt+2) << 16
		 | *(pElt+1) << 24;
	    pFont = (FontPtr)LookupID(fid, RT←FONT, RC←CORE);
	    if (!pFont)
	    {
		client->errorValue = fid;
		return (BadFont);
	    }
	    if (pFont != pGC->font)
	    {
		ChangeGC( pGC, GCFont, &fid);
		ValidateGC(pDraw, pGC);
	    }
	    pElt += FontShiftSize;
	}
	else	/* print a string */
	{
	    pNextElt = pElt + TextEltHeader + (*pElt)*itemSize;
	    if ( pNextElt > endReq)
		return( BadLength);
	    xorg += *((char *)(pElt + 1));	/* must be signed */
	    if(swapped16)
		SwapShorts((short *)(*pElt + TextEltHeader), (int)*pElt);
	    xorg = (* polyText)(pDraw, pGC, xorg, stuff->y, *pElt,
		pElt + TextEltHeader);
	    pElt = pNextElt;
	}
    }
    return (client->noClientException);
#undef TextEltHeader
#undef FontShiftSize
}
int
ProcCreateGC(client)
    register ClientPtr client;
{
    int error;
    GC *pGC;
    register DrawablePtr pDraw;
    int len;
    REQUEST(xCreateGCReq);

    REQUEST←AT←LEAST←SIZE(xCreateGCReq);
    client->errorValue = stuff->gc;
    LEGAL←NEW←RESOURCE(stuff->gc);
    if (!(pDraw = LOOKUP←DRAWABLE( stuff->drawable, client) ))
        return (BadDrawable);
    len = stuff->length -  (sizeof(xCreateGCReq) >> 2);
    if (len != Ones(stuff->mask))
        return BadLength;
    pGC = (GC *)CreateGC(pDraw, stuff->mask, 
			 (long *) &stuff[1], (long *)&error);
    if (error != Success)
        return error;
    if (pGC)
    {
	AddResource(stuff->gc, RT←GC, (pointer)pGC, FreeGC, RC←CORE);
	return(client->noClientException);
    }
    else 
	return (BadAlloc);
}

int
ProcChangeGC(client)
    register ClientPtr client;
{
    GC *pGC;
    REQUEST(xChangeGCReq);
    int result, len;
		
    REQUEST←AT←LEAST←SIZE(xChangeGCReq);
    VERIFY←GC(pGC, stuff->gc, client);
    len = stuff->length -  (sizeof(xChangeGCReq) >> 2);
    if (len != Ones(stuff->mask))
        return BadLength;
    result = ChangeGC(pGC, stuff->mask, (long *) &stuff[1]);
    if (client->noClientException != Success)
        return(client->noClientException);
    else
        return(result);
}

int
ProcCopyGC(client)
    register ClientPtr client;
{
    register GC *dstGC;
    register GC *pGC;
    REQUEST(xCopyGCReq);

    REQUEST←SIZE←MATCH(xCopyGCReq);
    VERIFY←GC( pGC, stuff->srcGC, client);
    VERIFY←GC( dstGC, stuff->dstGC, client);
    if (dstGC->pScreen != pGC->pScreen)
        return (BadMatch);    
    CopyGC(pGC, dstGC, stuff->mask);
    return (client->noClientException);
}

int
ProcSetDashes(client)
    register ClientPtr client;
{
    register GC *pGC;
    int result;
    REQUEST(xSetDashesReq);

    REQUEST←AT←LEAST←SIZE(xSetDashesReq);
    if ((sizeof(xSetDashesReq) >> 2) == stuff->length)
         return BadValue;

    VERIFY←GC(pGC,stuff->gc, client);

    result = SetDashes(pGC, (int)stuff->dashOffset, (int)stuff->nDashes, (unsigned char *)&stuff[1]);
    if (client->noClientException != Success)
        return(client->noClientException);
    else
        return(result);
}

int
ProcSetClipRectangles(client)
    register ClientPtr client;
{
    int	nr;
    register GC *pGC;
    REQUEST(xSetClipRectanglesReq);

    REQUEST←AT←LEAST←SIZE(xSetClipRectanglesReq);
    if ((stuff->ordering != Unsorted) && (stuff->ordering != YSorted) &&
	(stuff->ordering != YXSorted) && (stuff->ordering != YXBanded))
        return BadValue;
    VERIFY←GC(pGC,stuff->gc, client);
    pGC->clipOrg.x = stuff->xOrigin;
    pGC->stateChanges |= GCClipXOrigin;
		 
    pGC->clipOrg.y = stuff->yOrigin;
    pGC->stateChanges |= GCClipYOrigin;
		 
    nr = ((stuff->length  << 2) - sizeof(xSetClipRectanglesReq)) >> 3;
    SetClipRects(pGC, (int)nr, (xRectangle *)&stuff[1], (int)stuff->ordering);
    pGC->stateChanges |= GCClipMask;
    pGC->serialNumber = 0;
    return(client->noClientException);
}

int
ProcFreeGC(client)
    register ClientPtr client;
{
    register GC *pGC;
    REQUEST(xResourceReq);

    REQUEST←SIZE←MATCH(xResourceReq);
    VERIFY←GC(pGC,stuff->id,client);
    FreeResource(stuff->id, RC←NONE);
    return(client->noClientException);
}

int
ProcClearToBackground(client)
    register ClientPtr client;
{
    REQUEST(xClearAreaReq);
    register WindowPtr pWin;

    REQUEST←SIZE←MATCH(xClearAreaReq);
    pWin = (WindowPtr)LookupWindow( stuff->window, client);
    if (!pWin)
        return(BadWindow);
    if (pWin->class == InputOnly)
    {
	client->errorValue = stuff->window;
	return (BadWindow);
    }		    
    if ((stuff->exposures != xTrue) && (stuff->exposures != xFalse))
        return(BadValue);
    (*pWin->ClearToBackground)(pWin, stuff->x, stuff->y,
			       stuff->width, stuff->height,
			       (Bool)stuff->exposures);
    return(client->noClientException);
}

int
ProcCopyArea(client)
    register ClientPtr client;
{
    register DrawablePtr pDst;
    register DrawablePtr pSrc;
    register GC *pGC;
    REQUEST(xCopyAreaReq);

    REQUEST←SIZE←MATCH(xCopyAreaReq);

    VALIDATE←DRAWABLE←AND←GC(stuff->dstDrawable, pDst, pGC, client); 
    if (stuff->dstDrawable != stuff->srcDrawable)
    {
        if (!(pSrc = LOOKUP←DRAWABLE(stuff->srcDrawable, client)))
            return(BadDrawable);
	if ((pDst->pScreen != pSrc->pScreen) || (pDst->depth != pSrc->depth))
	{
	    client->errorValue = stuff->dstDrawable;
	    return (BadMatch);
	}
    }
    else
        pSrc = pDst;
    (*pGC->CopyArea)(pSrc, pDst, pGC, stuff->srcX, stuff->srcY,
				 stuff->width, stuff->height, 
				 stuff->dstX, stuff->dstY);
				 
    return(client->noClientException);
}

int
ProcCopyPlane(client)
    register ClientPtr client;
{
    register DrawablePtr psrcDraw, pdstDraw;
    register GC *pGC;
    REQUEST(xCopyPlaneReq);

    REQUEST←SIZE←MATCH(xCopyPlaneReq);

   /* Check to see if stff->plane  only has ONE bit set     XXX */

    VALIDATE←DRAWABLE←AND←GC(stuff->dstDrawable, pdstDraw, pGC, client);
    if (stuff->dstDrawable != stuff->srcDrawable)
    {
        if (!(psrcDraw = LOOKUP←DRAWABLE(stuff->srcDrawable, client)))
            return(BadDrawable);
	if ((pdstDraw->pScreen != psrcDraw->pScreen) || 
	    (pdstDraw->depth != psrcDraw->depth))
	{
	    client->errorValue = stuff->dstDrawable;
	    return (BadMatch);
	}
    }
    else
        psrcDraw = pdstDraw;
    (*pGC->CopyPlane)(psrcDraw, pdstDraw, pGC, stuff->srcX, stuff->srcY,
				 stuff->width, stuff->height, 
				 stuff->dstX, stuff->dstY, stuff->bitPlane);
    return(client->noClientException);
}

int
ProcPolyPoint(client)
    register ClientPtr client;
{
    int npoint;
    register GC *pGC;
    register DrawablePtr pDraw;
    REQUEST(xPolyPointReq);

    REQUEST←AT←LEAST←SIZE(xPolyPointReq);
    if ((stuff->coordMode != CoordModeOrigin) && 
	(stuff->coordMode != CoordModePrevious))
        return BadValue;
    VALIDATE←DRAWABLE←AND←GC(stuff->drawable, pDraw, pGC, client); 
    npoint = ((stuff->length << 2) - sizeof(xPolyPointReq)) >> 2;
    if (npoint)
        (*pGC->PolyPoint)(pDraw, pGC, stuff->coordMode, npoint,
			  (xPoint *) &stuff[1]);
    return (client->noClientException);
}

int
ProcPolyLine(client)
    register ClientPtr client;
{
    int npoint;
    register GC *pGC;
    register DrawablePtr pDraw;
    REQUEST(xPolyLineReq);

    REQUEST←AT←LEAST←SIZE(xPolyLineReq);
    if ((stuff->coordMode != CoordModeOrigin) && 
	(stuff->coordMode != CoordModePrevious))
        return BadValue;
    VALIDATE←DRAWABLE←AND←GC(stuff->drawable, pDraw, pGC, client);
    npoint = ((stuff->length << 2) - sizeof(xPolyLineReq));
    if(npoint % sizeof(xPoint) != 0)
	return(BadLength);
    npoint >>= 2;
    if (npoint < 1)
	return(BadLength);

    (*pGC->Polylines)(pDraw, pGC, stuff->coordMode, npoint, 
			  (xPoint *) &stuff[1]);
    return(client->noClientException);
}

int
ProcPolySegment(client)
    register ClientPtr client;
{
    int nsegs;
    register GC *pGC;
    register DrawablePtr pDraw;
    REQUEST(xPolySegmentReq);

    REQUEST←AT←LEAST←SIZE(xPolySegmentReq);
    VALIDATE←DRAWABLE←AND←GC(stuff->drawable, pDraw, pGC, client);
    nsegs = (stuff->length << 2) - sizeof(xPolySegmentReq);
    if(nsegs % sizeof(xSegment) != 0)
	return(BadLength);
    nsegs >>= 3;
    if (nsegs)
        (*pGC->PolySegment)(pDraw, pGC, nsegs, (xSegment *) &stuff[1]);
    return (client->noClientException);
}

int
ProcPolyRectangle (client)
    register ClientPtr client;
{
    int nrects;
    register GC *pGC;
    register DrawablePtr pDraw;
    REQUEST(xPolyRectangleReq);

    REQUEST←AT←LEAST←SIZE(xPolyRectangleReq);
    VALIDATE←DRAWABLE←AND←GC(stuff->drawable, pDraw, pGC, client);
    nrects = ((stuff->length << 2) - sizeof(xPolyRectangleReq)) >> 3;
    if (nrects)
        (*pGC->PolyRectangle)(pDraw, pGC, 
		    nrects, (xRectangle *) &stuff[1]);
    return(client->noClientException);
}

int
ProcPolyArc(client)
    register ClientPtr client;
{
    int		narcs;
    register GC *pGC;
    register DrawablePtr pDraw;
    REQUEST(xPolyArcReq);

    REQUEST←AT←LEAST←SIZE(xPolyArcReq);
    VALIDATE←DRAWABLE←AND←GC(stuff->drawable, pDraw, pGC, client);
    narcs = ((stuff->length << 2) - sizeof(xPolyArcReq)) / 
	    sizeof(xArc);
    if (narcs)
        (*pGC->PolyArc)(pDraw, pGC, narcs, (xArc *) &stuff[1]);
    return (client->noClientException);
}