/* $XConsortium: lbx.h /main/21 1996/11/22 11:02:13 rws $ */
/*
 * Copyright 1992 Network Computing Devices
 * Copyright 1996 X Consortium, Inc.
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of NCD. not be used in advertising or
 * publicity pertaining to distribution of the software without specific,
 * written prior permission.  NCD. makes no representations about the
 * suitability of this software for any purpose.  It is provided "as is"
 * without express or implied warranty.
 *
 * NCD. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL NCD.
 * 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.
 *
 */

#ifndef _LBX_H_
#define _LBX_H_
#include "misc.h"
#include "os.h"
#include "util.h"
#define _XLBX_SERVER_
#include "lbxstr.h"

/* we keep the ifdefs in the code as a guide to what's going on */
/* but we want the proxy to work with all possible servers */
#ifndef BIGREQS
#define BIGREQS
#endif

/* cache stuff */
#define MAX_ATOM_LENGTH 256	/* screw any large ones */
#define MAX_COLORNAME_LENGTH    256	/* screw any large ones */


typedef struct proptagdata {
    Atom        type;
    int         format;
    int         length;		/* in bytes */
    pointer     data;
}           PropertyTagDataRec, *PropertyTagDataPtr;

typedef struct _replystuff *ReplyStuffPtr;

typedef Bool (*ReplyFunc)(
#if NeedNestedPrototypes
    ClientPtr /*client*/,
    ReplyStuffPtr /*nr*/,
    char * /*data*/
#endif
);

typedef struct _replystuff {
    int         sequenceNumber;	/* expected sequence number */
    int         major;		/* major opcode */
    int         minor;		/* minor opcode */
    ReplyFunc	reply_func;	/* function to handle reply */
    union {			/* reply data */
	struct intern_data {
	    int         len;
	    char        str[MAX_ATOM_LENGTH];
	}           xintern;
	struct get_atom {
	    Atom        atom;
	}           xgetatom;
	struct colorname {
	    char        name[MAX_COLORNAME_LENGTH];
	    int         namelen;
	    VisualID    visual;
	}           xlookupcolor;
	struct allocnamedcolor {
	    char        name[MAX_COLORNAME_LENGTH];
	    int         namelen;
	    struct _cmap *pmap;
	}           xallocnamedcolor;
	struct alloccolorcells {
	    struct _cmap *pmap;
	}           xalloccolorcells;
	struct alloccolorplanes {
	    struct _cmap *pmap;
	}           xalloccolorplanes;
	struct grabcmap {
	    struct _cmap *pmap;
	    Bool	alloc_named;
	    CARD16      vred,
	                vgreen,
	                vblue;
	    CARD16      xred,
	                xgreen,
	                xblue;
	}           lbxgrabcmap;
	struct getkeymap {
	    int         count;
	    int         first;
	}           lbxgetkeymap;
	struct getprop {
	    CARD32      offset;
	    CARD32      length;
	}           lbxgetprop;
	struct changeprop {
	    PropertyTagDataRec ptd;
	}           lbxchangeprop;
	struct wingeom {
	    char got_geom_request;
	    char got_geom_reply;
	    CARD8 depth;
	    Window root B32;
	    INT16 x B16, y B16;
	    CARD16 width B16, height B16;
	    CARD16 borderWidth B16;
	}	    lbxWinGeom;
	struct queryextension {
	    char       *name;
	}           lbxqueryextension;
	struct getimage {
#ifdef LBX_STATS
	    Drawable	drawable;
	    INT16	x;
	    INT16	y;
#endif
	    CARD16      width;
	    CARD16      height;
	    CARD8	format;
	}           lbxgetimage;
	pointer     lbxextensiondata;
    }           request_info;
    ReplyStuffPtr next;
}           ReplyStuffRec;

typedef struct _replydata {
    int         dlen;
    xReply      reply;
    pointer     data;
    int         delay_seq_no;	/* what seq i'm waiting for */
    struct _replydata *next;
}           ReplyDataRec, *ReplyDataPtr;


#define LBX_LARGE_REQUEST_MIN_SIZE	1024
#define LBX_LARGE_REQUEST_CHUNK_SIZE	512

#define LARGE_REQUEST_QUEUE_LEN 16

typedef struct {
    ClientPtr client;
    Bool compressed;
    char *buf;
    unsigned totalBytes;
    unsigned bytesRead;
    unsigned bytesWritten;
} LbxLargeRequestRec;


typedef struct _ClientPublic {
    int             (*writeToClient) ();
    int             (*uncompressedWriteToClient) ();
    unsigned long   (*requestLength) ();
    int             (*readRequest)();
} ClientPublicRec, *ClientPublicPtr;

typedef struct _Client {
    int         index;
    XID         ridBase;
    XID         ridMask;
    pointer     requestBuffer;
    pointer     osPrivate;	/* for OS layer, including scheduler */
    Bool        swapped;
    void        (*pSwapReplyFunc) (
#if NeedNestedPrototypes
		ClientPtr	/* pClient */,
		int		/* size */,
		void *		/* pbuf */
#endif
);
    XID         errorValue;
    int         sequence;
    int         closeDownMode;
    int         clientGone;
    int         noClientException;	/* this client died or needs to be
					 * killed */
    XServerPtr  server;
    Drawable    serverID;
    GContext    lastGCID;
    pointer    *saveSet;
    int         awaitingSetup;
    int         (**requestVector) (
#if NeedNestedPrototypes
		ClientPtr /* pClient */
#endif
);
    CARD32	req_len;		/* length of current request */
    Bool	big_requests;		/* supports large requests */

#ifdef DEBUG
#define MAX_REQUEST_LOG 100
    unsigned char requestLog[MAX_REQUEST_LOG];
    int         requestLogIndex;
#endif

    ClientPublicRec public;
    int         lbxIndex;

    Bool        cache_safe;	/* safe to short circuit request? */
    Bool        can_delay_reply;/* safe to delay short-circuit request? */

    int         sequenceNumber;	/* what we've seen */
    int         sequence_lost;	/* requests short-circuited */
    int         lastForReply;   /* last request with reply known coming */
    int         lastForResponse;/* last request sent with event or reply */
    int         lastResponse;	/* last sequence number seen from server */

    int         yanked;		/* total requests short-circuited */

    KeyCode     minKeyCode,
                maxKeyCode;

    CARD8          imageByteOrder;        /* LSBFirst, MSBFirst */
    CARD8          bitmapBitOrder;        /* LeastSignificant, MostSign...*/
    CARD8          bitmapScanlineUnit,     /* 8, 16, 32 */
                   bitmapScanlinePad;     /* 8, 16, 32 */
    CARD8          ZbitsPerPixel1;	  /* for ZPixmap depth 1 */
    Window	   rootWindow;		  /* root window of screen 0 */

    ReplyStuffPtr replylist;	/* list of pending replies */
    ReplyDataPtr replydata;	/* list of delayed short-circuited replies */
    Drawable	drawableCache[GFX_CACHE_SIZE];
    GContext	gcontextCache[GFX_CACHE_SIZE];

    LbxLargeRequestRec *largeRequest;

}           ClientRec;


#define WriteToClient(client,len,buf)   (((client)->public.writeToClient)(client,len,buf))
#define ReadRequestFromClient(client)   ((client)->public.readRequest(client))
#define RequestLength(r,client,g,p)           (*(client)->public.requestLength) (r,client,g,p)

#define	LBXSequenceNumber(client)	(client->sequenceNumber)
#define	LBXCacheSafe(client)	(client->cache_safe)
#define	LBXCanDelayReply(client) (client->can_delay_reply)
#define	LBXSequenceLost(client)	(client->sequence_lost)
#define	LBXYanked(client)	(client->yanked)
#define	LBXLastForReply(client)	(client->lastForReply)
#define	LBXLastForResponse(client)	(client->lastForResponse)
#define	LBXLastResponse(client)	(client->lastResponse)
#define	LBXReplyList(client)	(client->replylist)
#define	LBXReplyData(client)	(client->replydata)
#define	LBXMinKeyCode(client)	(client->minKeyCode)
#define	LBXMaxKeyCode(client)	(client->maxKeyCode)
#define	LBXImageByteOrder(client) (client->imageByteOrder)
#define	LBXBitmapBitOrder(client) (client->bitmapBitOrder)
#define	LBXBitmapScanlineUnit(client) (client->bitmapScanlineUnit)
#define	LBXBitmapScanlinePad(client) (client->bitmapScanlinePad)
#define	LBXZBitsPerPixel1(client) (client->ZbitsPerPixel1)
#define LBXRootWindow(client) (client->rootWindow)
#define	LBXDrawableCache(client)(client->drawableCache)
#define	LBXGContextCache(client)(client->gcontextCache)

extern ClientPtr *clients;
#define MAXCLIENTS       128
#define NullClient ((ClientPtr) 0)
extern ClientPtr serverClient;
extern int currentMaxClients;

extern LbxLargeRequestRec *largeRequestQueue[];
extern int numLargeRequestsInQueue;

/*
 * Notes on request short-circuiting
 *
 * X guarentees that any replies, events or errors generated by a
 * previous request will be sent before those of a later request.
 * this means that any requests that can be handled by the proxy
 * must have their reply sent after any previous events or errors.
 *
 * there are 3 possible stages implemented here:
 *
 * - fully correct protocol, where nothing can be out of order
 * - mostly correct protocol, where only errors can be out of order
 * - poor protocol, where events & errors can be out of order
 *
 * for most applications, poor is 'good enough', because they don't
 * depend on events coming in order, and instead let Xlib do
 * the work.
 *
 * depending on the type of protocol being used, the cache_safe
 * flag in the ClientRec will be set appropriately, and if TRUE,
 * the proxy is cleared to short-circuit a request.
 *
 * for full correct protocol, the flag is set if the previous request
 * was a round trip and the reply has come back.
 *
 * for a mostly correct protocol, the flag is set for the above
 * case, and for requests that can generate only errors (mostly
 * graphics)
 *
 * for a 'good enough' protocol, the flag is always on, and we let
 * the client sort things out.
 *
 * (note than in no case do we allow replies to come out of order.)
 *
 *
 * Note on Xlib's handling of sequences:
 *
 * Xlib usually waits for the reply to sync request before
 * issuing another -- its archetecture depends on it.  However,
 * this is not required.  Xlib itself misses this in at least one
 * case (XGetWindowAttributes, which uses both the GetWindowAttributes
 * and GetGeometry requests).
 *
 * The upshot is that the proxy has to be able to handle seeing
 * another request before it receives an expected reply.
 *
 * this means we can't assume a single pending reply, but many.
 * currently these get tacked onto a list.
 *
 *
 * Notes on how the proxy attempts to solve all of this:
 *
 * There are 4 request that it will attempt to short-circuit:
 * InternAtom, GetAtomName, LookupColor, AllocColor, and AllocNamedColor.
 * All the code to do this is in lbxfuncs.c, and all of it works in
 * essentially the same way -- whenever possible, it will try to respond 
 * to the client without sending the request all the way to the X server.
 * The goal is to remove a roudn-trip entirely -- even though not a lot of data
 * is involved, remving the roundtrip can make this useful.

 * Unfortunately, figuring out *when* its safe is very nasty.  First
 * there are all the possibile stages outlined above.  If the proxy
 * isn't waiting, thinking there might be pending data, it can always
 * short-circuit the request.  However, this is the rare case.  When
 * the proxy can't immediately respond, it attempts to short-circuit anyways,
 * delaying the reply until whatever it was waiting on arrives.  Often
 * it can't -- if the most paranoid type of checking is turned on, it'll
 * never work.  The complex part occurs with loose checking.  If it knows
 * a reply is coming back, it can delay the short-circuit until it gets
 * the reply.  This works fine for the core protocol, but breaks down 
 * again for extensions -- to be safe, any unknown extensions are assumed
 * to have replies -- but since they may never arrive, the delayed
 * short-circuit can never be flushed.  To avoid this, whether a reply
 * has been guessed at is tracked, and this info is used to decide
 * whether a short-circuit can be delayed -- if not, it always needs
 * to do the full round-trip.
 *
 * The complexity really makes me wonder if this stuff is worth the effort...
 */


/* short-circuiting protocol */

#define	PROTOCOL_FULL	0		/* DEFAULT - best w/ accuracy */
#define	PROTOCOL_MOST	1		/* cheat on errors */
#define	PROTOCOL_POOR	2		/* cheat on errors & events */

#undef	DEBUG

#undef	TRACE

/* possible states of request handlers.  some requests are short-circuited
 * (yanked), some are replaced with LBX requests, and some are let through
 * unchanged
 *
 * any replaced request expecting a reply needs to be sure the sequence
 * number isn't lagging before its sends its data
 */
#define	REQ_PASSTHROUGH	0	/* pass through */
#define	REQ_YANK	1	/* completely remove, reply sent */
#define REQ_YANKLATE	2	/* completely remove, reply not sent yet */
#define	REQ_REPLACE	3	/* replaced with 1way, reply sent */
#define	REQ_REPLACELATE	4	/* replaced with 1way, reply not sent yet */

/*
 * size of motion event queue
 *
 * this specifies the maximum number of motion events that the server
 * can spew out at once.  the proxy will send it NUM_MOTION_EVENTS
 * AllowMotion requests at startup, and then send a new one each time it
 * processes a Motion event.  this will prevent the wire from being
 * swamped by MotionNotify.
 */

/* XXX this should be a calculation based on the wire latency */

#define	NUM_MOTION_EVENTS	8


#ifdef LBX_STATS
extern int  intern_good,
            intern_miss;
extern int  getatom_good,
            getatom_miss;
extern int  luc_good,
            luc_miss;
extern int  ac_good,
            ac_miss;
extern int  anc_good,
            anc_miss;

extern int  getmodmap_tag,	/* tag only */
            getmodmap_full;
extern int  getkeymap_tag,	/* tag only */
            getkeymap_full;
extern int  queryfont_tag,	/* tag only */
            queryfont_full;
extern int  getsetup_tag,	/* tag only */
            getsetup_full;

extern int  getprop_tag,
            getprop_full;

extern int  tag_bytes_unsent;	/* approx data kept off wire by tags */


extern void DumpOtherStats();
extern void ZeroOtherStats();

#endif /* LBX_STATS */

extern void DumpCompressionStats();
extern void ZeroCompressionStats();

/* tables.c */
extern int ProcLBXInternAtom(
#if NeedFunctionPrototypes
    ClientPtr /*client*/
#endif
);

extern int ProcLBXGetAtomName(
#if NeedFunctionPrototypes
    ClientPtr /*client*/
#endif
);

extern int ProcLBXCreateColormap(
#if NeedFunctionPrototypes
    ClientPtr /*client*/
#endif
);

extern int ProcLBXAllocColor(
#if NeedFunctionPrototypes
    ClientPtr /*client*/
#endif
);

extern int ProcLBXAllocNamedColor(
#if NeedFunctionPrototypes
    ClientPtr /*client*/
#endif
);

extern int ProcLBXFreeColormap(
#if NeedFunctionPrototypes
    ClientPtr /*client*/
#endif
);

extern int ProcLBXCopyColormapAndFree(
#if NeedFunctionPrototypes
    ClientPtr /*client*/
#endif
);

extern int ProcLBXFreeColors(
#if NeedFunctionPrototypes
    ClientPtr /*client*/
#endif
);

extern int ProcLBXLookupColor(
#if NeedFunctionPrototypes
    ClientPtr /*client*/
#endif
);

extern int ProcLBXGetModifierMapping(
#if NeedFunctionPrototypes
    ClientPtr /*client*/
#endif
);

extern int ProcLBXGetKeyboardMapping(
#if NeedFunctionPrototypes
    ClientPtr /*client*/
#endif
);

extern int ProcLBXQueryFont(
#if NeedFunctionPrototypes
    ClientPtr /*client*/
#endif
);

extern void FinishLBXRequest(
#if NeedFunctionPrototypes
    ClientPtr /*client*/,
    int /*yank*/
#endif
);

extern void DoLBXReply(
#if NeedFunctionPrototypes
    ClientPtr /*client*/,
    char * /*data*/,
    int /*len*/
#endif
);

extern void SendLbxSync(
#if NeedFunctionPrototypes
    ClientPtr /*client*/
#endif
);

/* dispatch.c */

extern int Dispatch(
#if NeedFunctionPrototypes
    void
#endif
);

extern void SendErrorToClient(
#if NeedFunctionPrototypes
    ClientPtr /*client*/,
    unsigned int /*majorCode*/,
    unsigned int /*minorCode*/,
    XID /*resId*/,
    int /*errorCode*/
#endif
);

extern ClientPtr NextAvailableClient(
#if NeedFunctionPrototypes
    pointer /*ospriv*/
#endif
);

extern int ProcInitialConnection(
#if NeedFunctionPrototypes
    ClientPtr /*client*/
#endif
);

extern int ProcEstablishConnection(
#if NeedFunctionPrototypes
    ClientPtr /*client*/
#endif
);

extern void CloseDownClient(
#if NeedFunctionPrototypes
    ClientPtr /*client*/
#endif
);

extern int ProcStandardRequest(
#if NeedFunctionPrototypes
    ClientPtr /*client*/
#endif
);

extern int ProcBadRequest(
#if NeedFunctionPrototypes
    ClientPtr /*client*/
#endif
);

extern void AdjustProcVector(
#if NeedFunctionPrototypes
    void
#endif
);

/* lbxutil.c */

extern ReplyStuffPtr NewReply(
#if NeedFunctionPrototypes
    ClientPtr /*client*/,
    int /*major*/,
    int /*minor*/,
    ReplyFunc /*reply_func*/
#endif
);

extern void RemoveReply(
#if NeedFunctionPrototypes
    ClientPtr /*client*/,
    ReplyStuffPtr /*rp*/
#endif
);

extern ReplyStuffPtr GetMatchingReply(
#if NeedFunctionPrototypes
    ClientPtr /*client*/,
    int /*seqno*/,
    Bool /*flush_older*/
#endif
);

extern Bool AnyReplies(
#if NeedFunctionPrototypes
    ClientPtr /*client*/
#endif
);

extern Bool SaveReplyData(
#if NeedFunctionPrototypes
    ClientPtr /*client*/,
    xReply * /*rep*/,
    int /*len*/,
    pointer /*data*/
#endif
);

extern Bool FlushDelayedReplies(
#if NeedFunctionPrototypes
    ClientPtr /*client*/
#endif
);

extern void BumpSequence(
#if NeedFunctionPrototypes
    ClientPtr /*client*/
#endif
);

extern void ForceSequenceUpdate(
#if NeedFunctionPrototypes
    ClientPtr /*client*/
#endif
);

extern void LbxFreeTag(
#if NeedFunctionPrototypes
    XID /*tag*/,
    int /*tagtype*/
#endif
);

extern void LbxSendTagData(
#if NeedFunctionPrototypes
    XID /*tag*/,
    int /*tagtype*/
#endif
);

extern void SendInitLBXPackets(
#if NeedFunctionPrototypes
    void
#endif
);

extern void LbxCleanupSession(
#if NeedFunctionPrototypes
    void
#endif
);

/* unsquish.c */

extern int EventLength(
#if NeedFunctionPrototypes
    xEvent * /*ev*/
#endif
);

extern Bool UnsquishEvent(
#if NeedFunctionPrototypes
    xReply * /*rep*/,
    xEvent * /*ev*/,
    int * /*lenp*/
#endif
);

/* props.c */

extern int ProcLBXChangeProperty(
#if NeedFunctionPrototypes
    ClientPtr /*client*/
#endif
);

extern int ProcLBXGetProperty(
#if NeedFunctionPrototypes
    ClientPtr /*client*/
#endif
);

#endif
