diff options
Diffstat (limited to 'xc/lib/dps/XDPS.c')
-rw-r--r-- | xc/lib/dps/XDPS.c | 2330 |
1 files changed, 2330 insertions, 0 deletions
diff --git a/xc/lib/dps/XDPS.c b/xc/lib/dps/XDPS.c new file mode 100644 index 000000000..b945a4c8c --- /dev/null +++ b/xc/lib/dps/XDPS.c @@ -0,0 +1,2330 @@ +/* + * XDPS.c -- implementation of low-level Xlib routines for XDPS extension + * + * (c) Copyright 1989-1994 Adobe Systems Incorporated. + * All rights reserved. + * + * Permission to use, copy, modify, distribute, and sublicense this software + * and its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notices appear in all copies and that + * both those copyright notices and this permission notice appear in + * supporting documentation and that the name of Adobe Systems Incorporated + * not be used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. No trademark license + * to use the Adobe trademarks is hereby granted. If the Adobe trademark + * "Display PostScript"(tm) is used to describe this software, its + * functionality or for any other purpose, such use shall be limited to a + * statement that this software works in conjunction with the Display + * PostScript system. Proper trademark attribution to reflect Adobe's + * ownership of the trademark shall be given whenever any such reference to + * the Display PostScript system is made. + * + * ADOBE MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THE SOFTWARE FOR + * ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. + * ADOBE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON- INFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL ADOBE BE LIABLE + * TO YOU OR ANY OTHER PARTY FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE, STRICT LIABILITY OR ANY OTHER ACTION ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ADOBE WILL NOT + * PROVIDE ANY TRAINING OR OTHER SUPPORT FOR THE SOFTWARE. + * + * Adobe, PostScript, and Display PostScript are trademarks of Adobe Systems + * Incorporated which may be registered in certain jurisdictions + * + * Author: Adobe Systems Incorporated + */ + +#define NEED_EVENTS +#define NEED_REPLIES + +#include <stdio.h> +/* Include this first so that Xasync.h, included from Xlibint.h, can find + the definition of NOFILE */ +#include <sys/param.h> +#include <X11/Xlibint.h> +#include "cslibint.h" +#include "DPS/XDPS.h" +#include "DPS/XDPSproto.h" +#include "DPS/XDPSlib.h" +#include "DPS/dpsNXargs.h" +#include <X11/Xatom.h> +#include <X11/Xutil.h> +#include "dpsassert.h" +#include "DPSCAPClient.h" + +/* === DEFINITIONS === */ + +#ifndef _NFILE +#define DPSMAXDISPLAYS 128 +#else +#define DPSMAXDISPLAYS _NFILE +#endif /* _NFILE */ + +#define MajorOpCode(dpy) (Codes[DPY_NUMBER(dpy)] ? \ + Codes[DPY_NUMBER(dpy)]->major_opcode : \ + Punt()) + +#define DPSCAP_INITCTXTS 4 /* per display */ + +/* === TYPES === */ + +typedef Status (*PSCMProc)(); + +typedef struct { + char passEvents; + char wrapWaiting; + char syncMask; /* CSDPS only */ + char debugMask; /* CSDPS only */ +} DPSDisplayFlags; + +/* For now DPSDisplayFlags is no larger than a pointer. Revisit this if the + structure grows. */ + +typedef int (*GenericProcPtrReturnsInt)(); + +typedef struct _t_DPSCAPPausedContextData { + struct _t_DPSCAPPausedContextData *next; + Bool paused; + ContextXID cxid; + unsigned int seqnum; +} DPSCAPPausedContextData; + +typedef struct { + char showSmallSizes; + char pixMem; +} DPSCAPAgentArgs; + +typedef struct { + int (*Flush)(); + int (*Read)(); + int (*ReadPad)(); + Status (*Reply)(); + int (*Send)(); +} XDPSLIOProcs; + +/* === GLOBALS === */ + +/* For debugging, allows client to force the library to use an agent */ +int gForceCSDPS = 0; + +/* Force all DPS NX protocol requests to flush if CSDPS */ +int gAutoFlush = 1; + +/* Force all NX XDPSLGiveInputs to flush independent of gAutoFlush */ +int gForceFlush = 1; + +/* Quick check for any paused contexts */ +int gTotalPaused = 0; + +/* === LOCALS === */ + +/* Common stuff */ +static XExtCodes *Codes[DPSMAXDISPLAYS]; +static int version[DPSMAXDISPLAYS]; +static XDPSLEventHandler StatusProc[DPSMAXDISPLAYS]; +static DPSDisplayFlags displayFlags[DPSMAXDISPLAYS]; +static XDPSLEventHandler TextProc = NULL; +static XDPSLEventHandler ReadyProc[DPSMAXDISPLAYS]; /* L2-DPS/PROTO 9 */ +static int NumberType[DPSMAXDISPLAYS]; /* Garbage okay after dpy closed */ +static char *FloatingName[DPSMAXDISPLAYS]; /* Garbage okay after dpy closed */ + +/* CSDPS stuff */ +static Display *ShuntMap[DPSMAXDISPLAYS]; +static PSCMProc ClientMsgProc[DPSMAXDISPLAYS]; +static GenericProcPtrReturnsInt AfterProcs[DPSMAXDISPLAYS]; +static DPSCAPPausedContextData *PausedPerDisplay[DPSMAXDISPLAYS]; +static DPSCAPAgentArgs AgentArgs[DPSMAXDISPLAYS]; +static unsigned int LastXRequest[DPSMAXDISPLAYS]; +static int GCFlushMode[DPSMAXDISPLAYS]; + +#ifdef VMS +static Display *dpys[DPSMAXDISPLAYS]; +static nextDpy = 0; +#endif /* VMS */ + +static void DPSCAPInitGC(); +static Bool DPSCAPResumeWithIX(); +static Status DPSCAPClientMessageProc(); +static int DPSCAPAfterProc(); +static unsigned int DPSCAPSetPause(); +static Bool DPSCAPResumeContext(); +static Bool WaitForSyncProc(); + +static XDPSLIOProcs xlProcs = { /* Use these for DPS/X extension */ + _XFlush, + _XRead, + _XReadPad, + _XReply, + _XSend + }; + +static XDPSLIOProcs nxlProcs = { /* Use these for NX */ + N_XFlush, + N_XRead, + N_XReadPad, + N_XReply, + N_XSend + }; + +/* === MACROS === */ + +#define IFNXSETCALL(a, x) call = ((a) != (x)) ? &nxlProcs : &xlProcs + +/* === PRIVATE PROCS === */ + +static int Punt() +{ + DPSFatalProc(NULL, "Extension has not been initialized"); + exit(1); +} + +#ifdef VMS +/* This is a terribly inefficient way to find a per-display index, but we + need it till we get dpy->fd fixed in VMS%%%%%*/ +static int FindDpyNum(dpy) +{ +int i; +for (i=0; dpys[i] != dpy ; i++) + { + if (i == nextDpy) + { + dpys[nextDpy++]=dpy; + break; + } + } +return i; +} +#define DPY_NUMBER(dpy) FindDpyNum(dpy) +#else /* VMS */ +#define DPY_NUMBER(dpy) ((dpy)->fd) +#endif /* VMS */ + +/* === PROCEDURES === */ + +/* ARGSUSED */ +void +XDPSLSetTextEventHandler(dpy, proc) + Display *dpy; + XDPSLEventHandler proc; +{ + TextProc = proc; +} + +/* ARGSUSED */ +void +XDPSLCallOutputEventHandler(dpy, event) + Display *dpy; + XEvent *event; +{ + (*TextProc)(event); +} + +void +XDPSLSetStatusEventHandler(dpy, proc) + Display *dpy; + XDPSLEventHandler proc; +{ + StatusProc[DPY_NUMBER(dpy)] = proc; +} + +void +XDPSLCallStatusEventHandler(dpy, event) + Display *dpy; + XEvent *event; +{ + (*(StatusProc[DPY_NUMBER(dpy)]))(event); +} + +/* Added for L2-DPS/PROTO 9 */ +void +XDPSLSetReadyEventHandler(dpy, proc) + Display *dpy; + XDPSLEventHandler proc; +{ + ReadyProc[DPY_NUMBER(dpy)] = proc; +} + +/* Added for L2-DPS/PROTO 9 */ +void +XDPSLCallReadyEventHandler(dpy, event) + Display *dpy; + XEvent *event; +{ + (*(ReadyProc[DPY_NUMBER(dpy)]))(event); +} + +/* Added for L2-DPS/PROTO 9 */ +int +XDPSLGetVersion(dpy) + Display *dpy; +{ + return(version[DPY_NUMBER(dpy)]); +} +/* See CSDPS additions for XDPSLSetVersion */ + +void +XDPSLInitDisplayFlags(dpy) + Display *dpy; +{ + int d = DPY_NUMBER(dpy); + displayFlags[d].wrapWaiting = False; + + /* Instead of explicitly setting the pass-event flag, rely upon the fact + that it gets initialized to 0 by the compiler. This means that you + can set the event delivery mode on a display before creating any + contexts, which is a Good Thing */ +} + +XExtCodes *XDPSLGetCodes(dpy) + Display *dpy; +{ + return Codes[DPY_NUMBER(dpy)]; +} + +/* ARGSUSED */ +static int +CloseDisplayProc(dpy, codes) +Display *dpy; +XExtCodes *codes; +{ + extern void XDPSPrivZapDpy(); + + /* This proc is for native DPS/X only, not CSDPS */ + Codes[DPY_NUMBER(dpy)] = NULL; + /* Clear list */ + XDPSPrivZapDpy(dpy); +#ifdef VMS + dpys[DPY_NUMBER(dpy)] = NULL; + /*%%%%Temp till we fix dpy->fd*/ +#endif /* VMS */ +} + +Bool +XDPSLGetPassEventsFlag(dpy) + Display *dpy; +{ + return displayFlags[DPY_NUMBER(dpy)].passEvents; +} + +void +XDPSLSetPassEventsFlag(dpy, flag) + Display *dpy; + Bool flag; +{ + displayFlags[DPY_NUMBER(dpy)].passEvents = flag; +} + +Bool +XDPSLGetWrapWaitingFlag(dpy) + Display *dpy; +{ + return displayFlags[DPY_NUMBER(dpy)].wrapWaiting; +} + +void +XDPSLSetWrapWaitingFlag(dpy, flag) + Display *dpy; + Bool flag; +{ + displayFlags[DPY_NUMBER(dpy)].wrapWaiting = flag; +} + +static Status +ConvertOutputEvent(dpy, ce, we) + Display *dpy; + XEvent *ce; + xEvent *we; +{ + register PSOutputEvent *wireevent = (PSOutputEvent *) we; + register XDPSLOutputEvent *clientevent = (XDPSLOutputEvent *) ce; + + clientevent->type = wireevent->type & 0x7f; + clientevent->serial = _XSetLastRequestRead(dpy, + (xGenericReply *)wireevent); + clientevent->send_event = (wireevent->type & 0x80) != 0; + clientevent->display = dpy; + clientevent->cxid = wireevent->cxid; + clientevent->length = wireevent->length; + bcopy((char *) wireevent->data, clientevent->data, wireevent->length); + if (TextProc && !XDPSLGetPassEventsFlag(dpy)) { + (*TextProc)((XEvent *) clientevent); + return False; + } + return True; +} + +static Status +ConvertStatusEvent(dpy, ce, we) + Display *dpy; + XEvent *ce; + xEvent *we; +{ + register PSStatusEvent *wireevent = (PSStatusEvent *) we; + register XDPSLStatusEvent *clientevent = (XDPSLStatusEvent *) ce; + + clientevent->type = wireevent->type & 0x7f; + clientevent->serial = _XSetLastRequestRead(dpy, + (xGenericReply *)wireevent); + clientevent->send_event = (wireevent->type & 0x80) != 0; + clientevent->display = dpy; + clientevent->cxid = wireevent->cxid; + clientevent->status = wireevent->status; + if (StatusProc[DPY_NUMBER(dpy)] && !XDPSLGetPassEventsFlag(dpy)) { + (*(StatusProc[DPY_NUMBER(dpy)]))((XEvent *) clientevent); + return False; + } + return True; +} + +/* Added for L2-DPS/PROTO 9 */ +static Status +ConvertReadyEvent(dpy, ce, we) + Display *dpy; + XEvent *ce; + xEvent *we; +{ + register PSReadyEvent *wireevent = (PSReadyEvent *) we; + register XDPSLReadyEvent *clientevent = (XDPSLReadyEvent *) ce; + + clientevent->type = wireevent->type & 0x7f; + clientevent->serial = _XSetLastRequestRead(dpy, + (xGenericReply *)wireevent); + clientevent->send_event = (wireevent->type & 0x80) != 0; + clientevent->display = dpy; + clientevent->cxid = wireevent->cxid; + clientevent->val[0] = wireevent->val1; + clientevent->val[1] = wireevent->val2; + clientevent->val[2] = wireevent->val3; + clientevent->val[3] = wireevent->val4; + if (ReadyProc[DPY_NUMBER(dpy)] && !XDPSLGetPassEventsFlag(dpy)) { + (*(ReadyProc[DPY_NUMBER(dpy)]))((XEvent *) clientevent); + return False; + } + return True; +} + +/* Added for L2-DPS/PROTO 9 */ +/* ARGSUSED */ + +static int +CatchBadMatch(dpy, err, codes, ret_code) + Display *dpy; + xError *err; + XExtCodes *codes; + int *ret_code; +{ + if (err->errorCode == BadMatch) + { + *ret_code = 0; + return 1; /* suppress error */ + } + else + { + *ret_code = 1; + return 0; /* pass error along */ + } +} + + +int +XDPSLInit(dpy, numberType, floatingName) + Display *dpy; + int *numberType; /* RETURN */ + char **floatingName; /* RETURN: CALLER MUST NOT MODIFY OR FREE! */ +{ + XExtCodes *codes = (XExtCodes *)NULL; + register xPSInitReq *req; + xPSInitReply rep; + char *ptr; + int first_event; + + { + char *ddt; + extern char *getenv(); + + if ((ddt = getenv("DPSNXOVER")) != NULL) { + gForceCSDPS = (*ddt == 't' || *ddt == 'T'); + if (gForceCSDPS) + DPSWarnProc(NULL, "*** USING DPS NX ***"); + } + } + + if ((codes = Codes[DPY_NUMBER(dpy)]) != NULL) { + if (numberType) + *numberType = NumberType[DPY_NUMBER(dpy)]; + if (floatingName) + *floatingName = FloatingName[DPY_NUMBER(dpy)]; + return codes->first_event; + } else { + if (gForceCSDPS) + goto try_dps_nx; + codes = XInitExtension(dpy, DPSNAME); + if (codes == NULL) { + /* try DEC UWS 2.2 server */ + codes = XInitExtension(dpy, DECDPSNAME); +try_dps_nx: + if (codes == NULL) { + int myNumberType; + char *myFloatingName; + + first_event = CSDPSInit(dpy, &myNumberType, &myFloatingName); + NumberType[DPY_NUMBER(dpy)] = myNumberType; + FloatingName[DPY_NUMBER(dpy)] = myFloatingName; + if (numberType) + *numberType = myNumberType; + if (floatingName) + *floatingName = myFloatingName; + return first_event; + } + } + Codes[DPY_NUMBER(dpy)] = codes; + ShuntMap[DPY_NUMBER(dpy)] = dpy; + /* set procs for native DPS/X */ + XESetCloseDisplay(dpy, codes->extension, CloseDisplayProc); + XESetWireToEvent(dpy, codes->first_event + PSEVENTOUTPUT, + ConvertOutputEvent); + XESetWireToEvent(dpy, codes->first_event + PSEVENTSTATUS, + ConvertStatusEvent); + XESetWireToEvent(dpy, codes->first_event + PSEVENTREADY, + ConvertReadyEvent); + first_event = codes->first_event; + } + + /* We have to handle a BadMatch error, in the case where + the client has a later (higher) version of + the protocol than the server */ + { + int (*oldErrorProc)(); + int libVersion; + Bool doneIt; + + XSync(dpy, False); + LockDisplay(dpy); + oldErrorProc = XESetError(dpy, codes->extension, CatchBadMatch); + libVersion = DPSPROTOCOLVERSION; + doneIt = False; + while (libVersion >= DPSPROTO_OLDEST) + { + GetReq(PSInit, req); + req->reqType = MajorOpCode(dpy); + req->dpsReqType = X_PSInit; + req->libraryversion = libVersion; + if (_XReply(dpy, (xReply *) &rep, 0, xFalse)) + { + doneIt = True; + break; + } + /* otherwise, try previous version */ + --libVersion; + } + oldErrorProc = XESetError(dpy, codes->extension, oldErrorProc); + if (!doneIt) + { + DPSFatalProc(NULL, "Incompatible protocol versions"); + exit(1); + } + + /* NOTE ************************************************* + We made a boo-boo in the 1007.2 and earlier versions of + our X server glue code. Instead of sending a + BadMatch error if the client's version is newer (higher) + than the server's, it just replies with success. We + could test for that situation here by looking at + rep.serverversion, but it turns out that we don't need + to do anything special. Since rep.serverversion gets + assigned to our version[] array, it is as if we handled + the BadMatch correctly. Just for safety's sake, we'll + do some bulletproofing here instead. + Fixes 2ps_xdps BUG #6 */ + + else if (rep.serverversion < DPSPROTO_OLDEST + || rep.serverversion > DPSPROTOCOLVERSION) + { + DPSFatalProc(NULL, "Server replied with bogus version"); + exit(1); + } + } + + version[DPY_NUMBER(dpy)] = rep.serverversion; + NumberType[DPY_NUMBER(dpy)] = rep.preferredNumberFormat; + if (numberType) + *numberType = rep.preferredNumberFormat; + + ptr = (char *) Xmalloc(rep.floatingNameLength + 1); + _XReadPad(dpy, ptr, rep.floatingNameLength); + ptr[rep.floatingNameLength] = 0; + FloatingName[DPY_NUMBER(dpy)] = ptr; + if (floatingName) + *floatingName = ptr; + + UnlockDisplay(dpy); + SyncHandle(); + return first_event; +} + + + + +static void CopyColorMapsIntoCreateContextReq(req, colorcube, grayramp) + xPSCreateContextReq *req; + XStandardColormap *colorcube, *grayramp; +{ + req->cmap = 0; + if (colorcube != NULL) { + req->cmap = colorcube->colormap; + req->redmax = colorcube->red_max; + req->redmult = colorcube->red_mult; + req->greenmax = colorcube->green_max; + req->greenmult = colorcube->green_mult; + req->bluemax = colorcube->blue_max; + req->bluemult = colorcube->blue_mult; + req->colorbase = colorcube->base_pixel; + } + else { + req->redmult = 0; + /* The rest of this shouldn't be necessary, but there are some + servers out there that erroneously check the other fields + even when redmult is 0 */ + req->redmax = 0; + req->greenmult = 0; + req->greenmax = 0; + req->bluemult = 0; + req->bluemax = 0; + req->colorbase = 0; + } + + if (grayramp != NULL) { + req->cmap = grayramp->colormap; + req->graymax = grayramp->red_max; + req->graymult = grayramp->red_mult; + req->graybase = grayramp->base_pixel; + } + else req->graymult = 0; +} + + + + + + +/* ARGSUSED */ +ContextXID +XDPSLCreateContextAndSpace(xdpy, draw, gc, x, y, eventMask, grayRamp, + colorCube, actual, cpsid, sxid, + secure) + register Display *xdpy; + Drawable draw; + GC gc; + int x, y; + unsigned int eventMask; + XStandardColormap *grayRamp,*colorCube; + unsigned int actual; + ContextPSID *cpsid; /* RETURN */ + SpaceXID *sxid; /* RETURN */ + Bool secure; /* Added for L2-DPS/PROTO 9 */ +{ + int dpyix; + register Display *dpy = ShuntMap[dpyix = DPY_NUMBER(xdpy)]; + ContextXID cxid; + register xPSCreateContextReq *req; /* Same struct for CreateSecureContext */ + xPSCreateContextReply rep; + XStandardColormap defColorcube, defGrayramp; + XStandardColormap *requestCube, *requestRamp; + int index; + XDPSLIOProcs *call; + + if (grayRamp == NULL && colorCube == NULL) return(None); + + if (secure && version[dpyix] < DPSPROTO_V09) + return(None); /* No secure contexts before PROTO 9 */ + + /* Index gets encoded as follows: + * + * 0 grayRamp = Default, colorCube = Default + * 1 grayRamp = non-Default, colorcube = Default + * 2 grayRamp = Default, colorcube = non-Default + * 3 grayRamp = non-Default, colorcube = non-Default + * + */ + index = ((grayRamp == DefaultStdCMap || grayRamp == NULL) ? 0 : 1) + + (colorCube == DefaultStdCMap ? 0 : 2); + + switch (index) + { + case 0: /* Both are default */ + XDPSGetDefaultColorMaps(xdpy, (Screen *) NULL, draw, + &defColorcube, &defGrayramp); + requestCube = &defColorcube; + requestRamp = &defGrayramp; + break; + + case 1: /* gray specified, Color default */ + XDPSGetDefaultColorMaps(xdpy, (Screen *) NULL, draw, + &defColorcube, (XStandardColormap *) NULL); + requestCube = &defColorcube; + requestRamp = grayRamp; + break; + + case 2: /* gray default, Color specified */ + XDPSGetDefaultColorMaps(xdpy, (Screen *) NULL, draw, + (XStandardColormap *) NULL, &defGrayramp); + requestCube = colorCube; + requestRamp = &defGrayramp; + break; + + case 3: /* Both specified */ + requestCube = colorCube; + requestRamp = grayRamp; + break; + } + + if (gc != NULL) + XDPSLFlushGC(xdpy, gc); + if (dpy != xdpy) + { + int syncMask = displayFlags[dpyix].syncMask; + + /* Don't worry about pauses here, since we are just + now creating the context! */ + if (syncMask & (DPSCAP_SYNCMASK_SYNC|DPSCAP_SYNCMASK_RECONCILE)) + XSync(xdpy, False); + } + LockDisplay(dpy); + + NXMacroGetReq(PSCreateContext, req); + CopyColorMapsIntoCreateContextReq(req, requestCube, requestRamp); + + req->reqType = MajorOpCode(xdpy); + req->dpsReqType = (secure) ? X_PSCreateSecureContext : X_PSCreateContext; + req->x = x; + req->y = y; + req->drawable = draw; + req->gc = (gc != NULL) ? XGContextFromGC(gc) : None; + cxid = req->cxid = XAllocID(xdpy); + req->sxid = XAllocID(xdpy); + if (sxid) + *sxid = req->sxid; + req->eventmask = 0; /* %%% */ + req->actual = actual; + IFNXSETCALL(dpy, xdpy); + (void) (*call->Reply) (dpy, (xReply *)&rep, 0, xTrue); + + if (cpsid) + *cpsid = (int)rep.cpsid; + + UnlockDisplay(dpy); + /* If the context creation succeeded and we are CSDPS, send GC values */ + if (rep.cpsid && xdpy != dpy && gc != NULL) + { + DPSCAPInitGC(xdpy, dpy, gc); + } + SyncHandle(); + + if (dpy != xdpy) + LastXRequest[dpyix] = XNextRequest(xdpy)-1; + return (cxid); +} + + +/* ARGSUSED */ +ContextXID +XDPSLCreateContext(xdpy, sxid, draw, gc, x, y, eventMask, grayRamp, + colorCube, actual, cpsid, + secure) + register Display *xdpy; + SpaceXID sxid; + Drawable draw; + GC gc; + int x, y; + unsigned int eventMask; + XStandardColormap *grayRamp,*colorCube; + unsigned int actual; + ContextPSID *cpsid; /* RETURN */ + Bool secure; /* L2-DPS/PROTO 9 addition */ +{ + int dpyix; + register Display *dpy = ShuntMap[dpyix = DPY_NUMBER(xdpy)]; + register xPSCreateContextReq *req; + xPSCreateContextReply rep; + ContextXID cxid; /* RETURN */ + XStandardColormap defColorcube, defGrayramp; + XStandardColormap *requestCube, *requestRamp; + int index; + XDPSLIOProcs *call; + + if (secure && version[dpyix] < DPSPROTO_V09) + return(None); /* No secure contexts before PROTO 9 */ + + /* Index gets encoded as follows: + * + * 0 grayRamp = Default, colorCube = Default + * 1 grayRamp = non-Default, colorcube = Default + * 2 grayRamp = Default, colorcube = non-Default + * 3 grayRamp = non-Default, colorcube = non-Default + * + * Note that only the first or last case should ever happen. + */ + index = ((grayRamp == DefaultStdCMap) ? 0 : 1) + + ((colorCube == DefaultStdCMap) ? 0 : 2); + + switch (index) + { + case 0: /* Both are default */ + XDPSGetDefaultColorMaps(xdpy, (Screen *) NULL, draw, + &defColorcube, &defGrayramp); + requestCube = &defColorcube; + requestRamp = &defGrayramp; + break; + + case 1: /* gray specified, Color default */ + XDPSGetDefaultColorMaps(xdpy, (Screen *) NULL, draw, + &defColorcube, (XStandardColormap *) NULL); + requestCube = &defColorcube; + requestRamp = grayRamp; + break; + + case 2: /* gray default, Color specified */ + XDPSGetDefaultColorMaps(xdpy, (Screen *) NULL, draw, + (XStandardColormap *) NULL, &defGrayramp); + requestCube = colorCube; + requestRamp = &defGrayramp; + break; + + case 3: /* Both specified */ + requestCube = colorCube; + requestRamp = grayRamp; + break; + } + + + if (gc != NULL) + XDPSLFlushGC(xdpy, gc); + if (dpy != xdpy) + { + int syncMask = displayFlags[dpyix].syncMask; + + /* Don't worry about pauses here, since we are + just now creating this context! */ + if (syncMask & (DPSCAP_SYNCMASK_SYNC|DPSCAP_SYNCMASK_RECONCILE)) + XSync(xdpy, False); + } + LockDisplay(dpy); + + NXMacroGetReq(PSCreateContext, req); + CopyColorMapsIntoCreateContextReq(req, requestCube, requestRamp); + + req->reqType = MajorOpCode(xdpy); + req->dpsReqType = (secure) ? X_PSCreateSecureContext : X_PSCreateContext; + req->x = x; + req->y = y; + req->drawable = draw; + req->gc = (gc != NULL) ? XGContextFromGC(gc) : None; + cxid = req->cxid = XAllocID(xdpy); + req->sxid = sxid; + req->actual = actual; + + IFNXSETCALL(dpy, xdpy); + (void) (*call->Reply) (dpy, (xReply *)&rep, 0, xTrue); + if (cpsid) + *cpsid = (int)rep.cpsid; + + UnlockDisplay(dpy); + /* If the context creation succeeded and we are CSDPS, send GC values */ + if (rep.cpsid && xdpy != dpy && gc != NULL) + { + DPSCAPInitGC(xdpy, dpy, gc); + } + + SyncHandle(); + + if (dpy != xdpy) + LastXRequest[dpyix] = XNextRequest(xdpy)-1; + return cxid; +} + +SpaceXID +XDPSLCreateSpace(xdpy) + register Display *xdpy; +{ + int dpyix; + register Display *dpy = ShuntMap[dpyix = DPY_NUMBER(xdpy)]; + register xPSCreateSpaceReq *req; + SpaceXID sxid; + + LockDisplay(dpy); + + NXMacroGetReq(PSCreateSpace, req); + req->reqType = MajorOpCode(xdpy); + req->dpsReqType = X_PSCreateSpace; + sxid = req->sxid = XAllocID(xdpy); + + UnlockDisplay(dpy); + SyncHandle(); + if (dpy != xdpy) + LastXRequest[dpyix] = XNextRequest(xdpy)-1; + return sxid; +} + + + +/* + * I'm not sure how portable my coalescing code is, so I've provided the + * below define. If it turns out this code just breaks somewhere, you + * can simply undefine COALESCEGIVEINPUT, and then everything will work + * (but slower). 6/16/89 (tw) + */ + +#define COALESCEGIVEINPUT + +void +XDPSLGiveInput(xdpy, cxid, data, length) +register Display *xdpy; +ContextXID cxid; +char *data; +int length; +{ + int dpyix; + register Display *dpy = ShuntMap[dpyix = DPY_NUMBER(xdpy)]; + register xPSGiveInputReq *req; + int sendlen; + XDPSLIOProcs *call; + Bool didFlush = False; + + if (dpy != xdpy) + { + register int syncMask = displayFlags[dpyix].syncMask; + + if (syncMask & DPSCAP_SYNCMASK_RECONCILE) + { + XDPSLReconcileRequests(xdpy, cxid); + didFlush = True; + } + + /* If this context got paused, no matter how, ignore + mode and resume it */ + if (gTotalPaused && DPSCAPResumeContext(xdpy, cxid)) + { + /* xdpy was flushed by DPSCAPResumeContext */ + if (!didFlush) + { + N_XFlush(dpy); + didFlush = True; + } + } + else if (syncMask & DPSCAP_SYNCMASK_SYNC) + { + didFlush = True; + XSync(xdpy, False); + } + } + LockDisplay(dpy); + +#ifdef COALESCEGIVEINPUT + req = (xPSGiveInputReq *) dpy->last_req; + if (req->reqType == MajorOpCode(xdpy) + && req->dpsReqType == X_PSGiveInput + && req->cxid == cxid + && dpy->bufptr + length + 3 < dpy->bufmax) { + bcopy(data, ((char *) req) + sizeof(xPSGiveInputReq) + req->nunits, + length); + req->nunits += length; + req->length = (sizeof(xPSGiveInputReq) + req->nunits + 3) >> 2; + dpy->bufptr = dpy->last_req + sizeof(xPSGiveInputReq) + + ((req->nunits + 3) & ~3); + } else +#endif /* COALESCEGIVEINPUT */ + { + int flushOnce = 1; + int maxedOutLen = xdpy->max_request_size - sizeof(xPSGiveInputReq) - 4; + int nunits; + + /* We have the rare opportunity to chop up a buffer that is larger + than the max request size into separate requests, unlike + most other X requests (such as DrawText). The -4 is to + force these maxed out requests to be less than the maximum + padding that would ever be needed, and to minimize padding + in the case where the input buffer is several times + larger than max request length. */ + + nunits = maxedOutLen; + do { + if (length < maxedOutLen) + nunits = length; /* Normal size block */ + NXMacroGetReq(PSGiveInput, req); + req->reqType = MajorOpCode(xdpy); + req->dpsReqType = X_PSGiveInput; + req->cxid = cxid; + req->nunits = nunits; + req->length += ((nunits + 3) >> 2); + if (dpy != xdpy) { + if (flushOnce && !didFlush) { + LockDisplay(xdpy); + _XFlush(xdpy); + UnlockDisplay(xdpy); + flushOnce = 0; + } + NXProcData(dpy, (char *) data, nunits); + } else + {Data(dpy, (char *) data, nunits);} + data += nunits; + length -= nunits; + } while (length); + } + + /* In the NX case (didFlush is always False for the non-NX case), + the xdpy may have been flushed, but there is stuff left + buffered in dpy (NX connection). We can't leave the stuff + there, since we may never call a DPS routine again. Until + we can be notified about xdpy being flushed, we have to + clear out the dpy buffer after we cleared out the xdpy + buffer (didFlush == True). */ + + if (dpy != xdpy + && dpy->bufptr != dpy->buffer + && (gForceFlush || didFlush)) + N_XFlush(dpy); + + UnlockDisplay(dpy); + SyncHandle(); + if (dpy != xdpy) + LastXRequest[dpyix] = XNextRequest(xdpy)-1; +} + + +int +XDPSLGetStatus(xdpy, cxid) + register Display *xdpy; + ContextXID cxid; +{ + int dpyix; + Display *dpy = ShuntMap[dpyix = DPY_NUMBER(xdpy)]; + register xPSGetStatusReq *req; + xPSGetStatusReply rep; + XDPSLIOProcs *call; + + if (dpy != xdpy) + { + register int syncMask = displayFlags[dpyix].syncMask; + + /* ASSERT: There is no reason to pause the context for this + request, so just sync. */ + if (syncMask & (DPSCAP_SYNCMASK_SYNC|DPSCAP_SYNCMASK_RECONCILE)) + XSync(xdpy, False); + } + LockDisplay(dpy); + + NXMacroGetReq(PSGetStatus, req); + req->reqType = MajorOpCode(xdpy); + req->dpsReqType = X_PSGetStatus; + req->cxid = cxid; + req->notifyIfChange = 0; + + IFNXSETCALL(dpy, xdpy); + if (! (*call->Reply)(dpy, (xReply *)&rep, 0, xTrue)) + rep.status = PSSTATUSERROR; + UnlockDisplay(dpy); + SyncHandle(); + /* For CSDPS, guarantee that status events arrive just like DPS/X */ + if (dpy != xdpy) + { + XDPSLSync(xdpy); + LastXRequest[dpyix] = XNextRequest(xdpy)-1; + } + return (int) rep.status; +} + +void +XDPSLDestroySpace( xdpy, sxid ) + Display *xdpy; + SpaceXID sxid; +{ + int dpyix; + register Display *dpy = ShuntMap[dpyix = DPY_NUMBER(xdpy)]; + register xPSDestroySpaceReq *req; + + if (dpy != xdpy) + { + int syncMask = displayFlags[dpyix].syncMask; + + /* ASSERT: There is no reason to pause the context for this + request, so just sync. */ + if (syncMask & (DPSCAP_SYNCMASK_SYNC|DPSCAP_SYNCMASK_RECONCILE)) + XSync(xdpy, False); + } + LockDisplay(dpy); + + NXMacroGetReq(PSDestroySpace, req); + req->reqType = MajorOpCode(xdpy); + req->dpsReqType = X_PSDestroySpace; + req->sxid = sxid; + + if (gAutoFlush && dpy != xdpy) + { + N_XFlush(dpy); + } + UnlockDisplay(dpy); + SyncHandle(); + if (dpy != xdpy) + LastXRequest[dpyix] = XNextRequest(xdpy)-1; +} + + +void +XDPSLReset( xdpy, cxid ) + Display *xdpy; + ContextXID cxid; +{ + int dpyix; + register Display *dpy = ShuntMap[dpyix = DPY_NUMBER(xdpy)]; + register xPSResetReq *req; + + if (dpy != xdpy) + { + register int syncMask = displayFlags[dpyix].syncMask; + + /* ASSERT: There is no reason to pause the context for this + request, so just sync. */ + if (syncMask & (DPSCAP_SYNCMASK_SYNC|DPSCAP_SYNCMASK_RECONCILE)) + XSync(xdpy, False); + } + LockDisplay(dpy); + + NXMacroGetReq(PSReset, req); + req->reqType = MajorOpCode(xdpy); + req->dpsReqType = X_PSReset; + req->cxid = cxid; + + if (gAutoFlush && dpy != xdpy) + { + N_XFlush(dpy); + } + UnlockDisplay(dpy); + SyncHandle(); + if (dpy != xdpy) + LastXRequest[dpyix] = XNextRequest(xdpy)-1; +} + +void +XDPSLNotifyContext( xdpy, cxid, ntype ) + Display *xdpy; + ContextXID cxid; + int ntype; /* should this be an enum?? %%% */ +{ + int dpyix; + register Display *dpy = ShuntMap[dpyix = DPY_NUMBER(xdpy)]; + register xPSNotifyContextReq *req; + + if (dpy != xdpy) + { + register int syncMask = displayFlags[dpyix].syncMask; + + /* ASSERT: There is no reason to pause the context for this + request, so just sync. */ + if (syncMask & (DPSCAP_SYNCMASK_SYNC|DPSCAP_SYNCMASK_RECONCILE)) + XSync(xdpy, False); + } + LockDisplay(dpy); + + NXMacroGetReq(PSNotifyContext, req); + req->reqType = MajorOpCode(xdpy); + req->dpsReqType = X_PSNotifyContext; + req->cxid = cxid; + req->notifyType = ntype; + + if (dpy != xdpy) + { + N_XFlush(dpy); /* THIS IS CRITICAL TO AVOID HANGING! */ + } + + UnlockDisplay(dpy); + SyncHandle(); + + if (dpy != xdpy) + { + if (ntype == PSKILL) + XDPSLCleanContext(xdpy, cxid); + LastXRequest[dpyix] = XNextRequest(xdpy)-1; + } +} + + +ContextXID +XDPSLCreateContextFromID( xdpy, cpsid, sxid ) + Display *xdpy; + ContextPSID cpsid; + SpaceXID *sxid; /* RETURN */ +{ + int dpyix; + register Display *dpy = ShuntMap[dpyix = DPY_NUMBER(xdpy)]; + register xPSCreateContextFromIDReq *req; + xPSCreateContextFromIDReply rep; + ContextXID cxid; + XDPSLIOProcs *call; + + if (dpy != xdpy) + { + int syncMask = displayFlags[dpyix].syncMask; + + /* ASSERT: There is no reason to pause the context for this + request, so just sync. */ + if (syncMask & (DPSCAP_SYNCMASK_SYNC|DPSCAP_SYNCMASK_RECONCILE)) + XSync(xdpy, False); + } + LockDisplay(dpy); + + NXMacroGetReq(PSCreateContextFromID, req); + req->reqType = MajorOpCode(xdpy); + req->dpsReqType = X_PSCreateContextFromID; + req->cpsid = cpsid; + cxid = req->cxid = XAllocID(xdpy); + + IFNXSETCALL(dpy, xdpy); + (void) (*call->Reply) (dpy, (xReply *)&rep, 0, xTrue); + if (sxid) + *sxid = (int)rep.sxid; + + UnlockDisplay(dpy); + SyncHandle(); + if (dpy != xdpy) + LastXRequest[dpyix] = XNextRequest(xdpy)-1; + return(cxid); +} + + +/* Returns 1 on success, 0 on failure (cpsid not a valid context). */ + +Status +XDPSLIDFromContext( xdpy, cpsid, cxid, sxid ) + Display *xdpy; + ContextPSID cpsid; + ContextXID *cxid; /* RETURN */ + SpaceXID *sxid; /* RETURN */ +{ + int dpyix; + register Display *dpy = ShuntMap[dpyix = DPY_NUMBER(xdpy)]; + register xPSXIDFromContextReq *req; + xPSXIDFromContextReply rep; + XDPSLIOProcs *call; + + if (dpy != xdpy) + { + int syncMask = displayFlags[dpyix].syncMask; + + /* ASSERT: There is no reason to pause the context for this + request, so just sync. */ + if (syncMask & (DPSCAP_SYNCMASK_SYNC|DPSCAP_SYNCMASK_RECONCILE)) + XSync(xdpy, False); + } + LockDisplay(dpy); + + NXMacroGetReq(PSXIDFromContext, req); + req->reqType = MajorOpCode(xdpy); + req->dpsReqType = X_PSXIDFromContext; + req->cpsid = cpsid; + + IFNXSETCALL(dpy, xdpy); + (void) (*call->Reply) (dpy, (xReply *)&rep, 0, xTrue); + *sxid = (int)rep.sxid; + *cxid = (int)rep.cxid; + + UnlockDisplay(dpy); + SyncHandle(); + + if (dpy != xdpy) + LastXRequest[dpyix] = XNextRequest(xdpy)-1; + return((Status)(*sxid != None && *cxid != None)); +} + + +ContextPSID +XDPSLContextFromXID( xdpy, cxid ) + Display *xdpy; + ContextXID cxid; +{ + int dpyix; + register Display *dpy = ShuntMap[dpyix = DPY_NUMBER(xdpy)]; + register xPSContextFromXIDReq *req; + xPSContextFromXIDReply rep; + XDPSLIOProcs *call; + + if (dpy != xdpy) + { + int syncMask = displayFlags[dpyix].syncMask; + + /* ASSERT: There is no reason to pause the context for this + request, so just sync. */ + if (syncMask & (DPSCAP_SYNCMASK_SYNC|DPSCAP_SYNCMASK_RECONCILE)) + XSync(xdpy, False); + } + LockDisplay(dpy); + + NXMacroGetReq(PSContextFromXID, req); + req->reqType = MajorOpCode(xdpy); + req->dpsReqType = X_PSContextFromXID; + req->cxid = cxid; + + IFNXSETCALL(dpy, xdpy); + (void) (*call->Reply) (dpy, (xReply *)&rep, 0, xTrue); + + UnlockDisplay(dpy); + SyncHandle(); + + if (dpy != xdpy) + LastXRequest[dpyix] = XNextRequest(xdpy)-1; + return (int)rep.cpsid; +} + + +void +XDPSLSetStatusMask( xdpy, cxid, enableMask, disableMask, nextMask ) + Display *xdpy; + ContextXID cxid; + unsigned int enableMask, disableMask, nextMask; +{ + int dpyix; + register Display *dpy = ShuntMap[dpyix = DPY_NUMBER(xdpy)]; + register xPSSetStatusMaskReq *req; + + if (dpy != xdpy) + { + register int syncMask = displayFlags[dpyix].syncMask; + + /* ASSERT: There is no reason to pause the context for this + request, so just sync. */ + if (syncMask & (DPSCAP_SYNCMASK_SYNC|DPSCAP_SYNCMASK_RECONCILE)) + XSync(xdpy, False); + } + LockDisplay(dpy); + + NXMacroGetReq(PSSetStatusMask, req); + req->reqType = MajorOpCode(xdpy); + req->dpsReqType = X_PSSetStatusMask; + req->cxid = cxid; + req->enableMask = enableMask; + req->disableMask = disableMask; + req->nextMask = nextMask; + + if (gAutoFlush && dpy != xdpy) + { + N_XFlush(dpy); + } + UnlockDisplay(dpy); + SyncHandle(); + if (dpy != xdpy) + LastXRequest[dpyix] = XNextRequest(xdpy)-1; +} + + +#ifdef VMS +/* + * _XReadPad - Read bytes from the socket taking into account incomplete + * reads. If the number of bytes is not 0 mod 32, read additional pad + * bytes. This routine may have to be reworked if int < long. + */ + +/* This is really in xlib, but is not in the sharable image transfer vector + * so I am copying it here for now. BF + +The following notice applies only to the functions +_XReadPad and XFlush + +Copyright 1985, 1986, 1987, 1988, 1989 by the +Massachusetts Institute of Technology + +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 M.I.T. not be used in advertising or +publicity pertaining to distribution of the software without specific, +written prior permission. M.I.T. makes no representations about the +suitability of this software for any purpose. It is provided "as is" +without express or implied warranty. + +*/ + +_XReadPad (xdpy, data, size) + register Display *dpy; + register char *data; + register long size; +{ + static int padlength[4] = {0,3,2,1}; + register long bytes_read; + char pad[3]; + + CheckLock(dpy); + if (size == 0) return; + _XRead( dpy, data, size ); + if ( padlength[size & 3] ) { + _XRead( dpy, pad, padlength[size & 3] ); + } + +} +#endif /* VMS */ + +/* _____________ LEVEL 2 DPS/PROTOCOL 9 ADDITIONS _____________ */ + +void +XDPSLNotifyWhenReady( xdpy, cxid, val ) + Display *xdpy; + ContextXID cxid; + int val[4]; +{ + int dpyix; + register Display *dpy = ShuntMap[dpyix = DPY_NUMBER(xdpy)]; + register xPSNotifyWhenReadyReq *req; + + if (version[dpyix] < DPSPROTO_V09) + { + DPSWarnProc(NULL, "Attempted use of XDPSLNotifyWhenReady with incompatible server ignored"); + return; /* PROTO 9 or later only */ + } + + if (dpy != xdpy) + { + register int syncMask = displayFlags[dpyix].syncMask; + + if (syncMask & DPSCAP_SYNCMASK_RECONCILE) + XDPSLReconcileRequests(xdpy, cxid); + + /* If this context got paused, no matter how, ignore + mode and resume it */ + if (gTotalPaused && DPSCAPResumeContext(xdpy, cxid)) + { + /* xdpy was flushed by DPSCAPResumeContext */ + if (gAutoFlush) + N_XFlush(dpy); + } + else if (syncMask & DPSCAP_SYNCMASK_SYNC) + XSync(xdpy, False); + } + LockDisplay(dpy); + + NXMacroGetReq(PSNotifyWhenReady, req); + req->reqType = MajorOpCode(xdpy); + req->dpsReqType = X_PSNotifyWhenReady; + req->cxid = cxid; + req->val1 = val[0]; + req->val2 = val[1]; + req->val3 = val[2]; + req->val4 = val[3]; + + if (gAutoFlush && dpy != xdpy) + { + N_XFlush(dpy); + } + UnlockDisplay(dpy); + SyncHandle(); + if (dpy != xdpy) + LastXRequest[dpyix] = XNextRequest(xdpy)-1; +} + +XDPSLPSErrors +XDPSLTestErrorCode(dpy, ecode) + Display *dpy; + int ecode; +{ + XExtCodes *c = XDPSLGetCodes(dpy); + + if (c == NULL) + return False; /* Not inited on that display; must be False */ + + switch (ecode - c->first_error) + { + case PSERRORBADCONTEXT: return(pserror_badcontext); + case PSERRORBADSPACE: return(pserror_badspace); + case PSERRORABORT: + if (version[DPY_NUMBER(dpy)] < DPSPROTO_V09) + return(not_pserror); + else + return(pserror_abort); + default: return(not_pserror); + } +} + +/* _____________ CLIENT SIDE DPS ADDITIONS _____________ */ + +/* === NEW HOOKS INTO XDPS === */ + +void +XDPSLSetVersion(dpy, ver) + Display *dpy; + unsigned ver; +{ + version[DPY_NUMBER(dpy)] = ver; +} + +void +XDPSLSetCodes(dpy, codes) + Display *dpy; + XExtCodes *codes; +{ + Codes[DPY_NUMBER(dpy)] = codes; +} + +Display * +XDPSLGetShunt(dpy_in) + register Display *dpy_in; +{ + return(ShuntMap[DPY_NUMBER(dpy_in)]); +} + +void +XDPSLSetShunt(dpy_in, dpy_out) + Display *dpy_in, *dpy_out; +{ + ShuntMap[DPY_NUMBER(dpy_in)] = dpy_out; +} + +int +XDPSLGetSyncMask(dpy) + Display *dpy; +{ + return (int)displayFlags[DPY_NUMBER(dpy)].syncMask; +} + +void +XDPSLSetSyncMask(dpy, mask) + Display *dpy; + int mask; +{ + displayFlags[DPY_NUMBER(dpy)].syncMask = (char)mask; + gForceFlush = (mask & DPSCAP_SYNCMASK_RECONCILE); +} + +void +XDPSLFlush(xdpy) + register Display *xdpy; +{ + register Display *dpy = ShuntMap[DPY_NUMBER(xdpy)]; + + _XFlush(xdpy); + if (dpy != xdpy) + N_XFlush(dpy); +} + +void +XDPSLSyncGCClip(xdpy, gc) + register Display *xdpy; + register GC gc; +{ + register unsigned long oldDirty; + register int dpyix; + register Display *dpy = ShuntMap[dpyix = DPY_NUMBER(xdpy)]; + extern int gNXSyncGCMode; + + /* We DON'T want to notice all gc changes, just the clip */ + oldDirty = gc->dirty; + gc->dirty = (GCClipXOrigin|GCClipYOrigin); + XDPSLFlushGC(xdpy, gc); + gc->dirty = oldDirty; + if (dpy == xdpy || gNXSyncGCMode != 1) /* 1 means sync always */ + { + /* For DPS NX and SLOW mode, flushing the gc cache has + the side-effect of synching agent and server connections. + So, to have consistent behavior, we sync for the DPS/X + or FAST cases too. */ + + if (GCFlushMode[dpyix] == XDPSNX_GC_UPDATES_FAST + || dpy == xdpy) + XDPSLSync(xdpy); + } +} + + +#ifdef VMS +void +XDPSLSetDisplay(dpy) + Display *dpy; +{ + dpys[DPY_NUMBER(dpy)] = dpy; +} +#endif /* VMS */ + +char * +XDPSLSetAgentName(dpy, name, deflt) + Display *dpy; + char *name; + int deflt; +{ + char *old; + + if (gCSDPS == NULL) + DPSCAPStartUp(); + if (deflt) + { + old = gCSDPS->defaultAgentName; + gCSDPS->defaultAgentName = name; + } + else + { + old = gCSDPS->map[DPY_NUMBER(dpy)]; + gCSDPS->map[DPY_NUMBER(dpy)] = name; + } + return(old); +} + + +void +XDPSLSetClientMessageHandler(dpy) + Display *dpy; +{ + if (dpy == NULL) return; + ClientMsgProc[DPY_NUMBER(dpy)] = XESetWireToEvent( + dpy, + ClientMessage, + DPSCAPClientMessageProc); +} + +void +XDPSLSetAfterProc(xdpy) + Display *xdpy; +{ + if (xdpy == NULL) return; + AfterProcs[DPY_NUMBER(xdpy)] = (GenericProcPtrReturnsInt) + XSetAfterFunction(xdpy, DPSCAPAfterProc); + /* +++ Consider using agent->synchandler to store old proc */ +} + + +CSDPSFakeEventTypes +XDPSLGetCSDPSFakeEventType(dpy, event) + Display *dpy; + XEvent *event; +{ + XExtCodes *codes = Codes[DPY_NUMBER(dpy)]; + XExtData *extData; + DPSCAPData my; + + if (event->type != ClientMessage || codes == NULL) + return(csdps_not); + extData = XFindOnExtensionList( + CSDPSHeadOfDpyExt(dpy), + codes->extension); + if (!extData) + return(csdps_not); + my = (DPSCAPData) extData->private_data; + + if (event->xclient.message_type == my->typePSOutput) + return(csdps_output); + if (event->xclient.message_type == my->typePSOutputWithLen) + return(csdps_output_with_len); + if (event->xclient.message_type == my->typePSStatus) + return(csdps_status); + if (event->xclient.message_type == my->typeNoop) + return(csdps_noop); + if (event->xclient.message_type == my->typePSReady) + return(csdps_ready); + return(csdps_not); +} + +Bool +XDPSLDispatchCSDPSFakeEvent(dpy, event, t) + Display *dpy; + XEvent *event; + CSDPSFakeEventTypes t; +{ + register XDPSLOutputEvent *oce; + register DPSCAPOutputEvent *oev; + XDPSLOutputEvent fakeOutput; + XExtCodes *codes = Codes[DPY_NUMBER(dpy)]; + + if (codes == NULL) + return(False); + + /* Fake up an event in the client's format. Bypasses + extension wire-to-event conversion */ + switch (t) + { + case csdps_output: + oce = &fakeOutput; + oev = (DPSCAPOutputEvent *)event->xclient.data.b; + oce->length = DPSCAP_BYTESPEROUTPUTEVENT; + goto samo_samo; + case csdps_output_with_len: + oce = &fakeOutput; + oev = (DPSCAPOutputEvent *)event->xclient.data.b; + oce->length = oev->data[DPSCAP_DATA_LEN]; +samo_samo: + oce->type = codes->first_event + PSEVENTOUTPUT; + oce->serial = event->xclient.serial; + oce->send_event = True; /* ??? */ + oce->display = dpy; + oce->cxid = oev->cxid; + bcopy((char *) oev->data, oce->data, oce->length); + XDPSLCallOutputEventHandler(dpy, (XEvent *) oce); + break; + case csdps_status: + { + register XDPSLStatusEvent *sce; + register DPSCAPStatusEvent *sev; + XDPSLStatusEvent fakeStatus; + + sev = (DPSCAPStatusEvent *)event->xclient.data.b; + sce = &fakeStatus; + sce->type = codes->first_event + PSEVENTSTATUS; + sce->serial = event->xclient.serial; + sce->send_event = True; /* ??? */ + sce->display = dpy; + sce->status = sev->status; + sce->cxid = sev->cxid; + XDPSLCallStatusEventHandler(dpy, (XEvent *) sce); + break; + } + case csdps_ready: /* L2-DPS/PROTO 9 addition */ + { + register XDPSLReadyEvent *rce; + XDPSLReadyEvent fakeReady; + + rce = &fakeReady; + rce->type = codes->first_event + PSEVENTREADY; + rce->serial = event->xclient.serial; + rce->send_event = True; + rce->display = dpy; + rce->cxid = event->xclient.data.l[0]; + rce->val[0] = event->xclient.data.l[1]; + rce->val[1] = event->xclient.data.l[2]; + rce->val[2] = event->xclient.data.l[3]; + rce->val[3] = event->xclient.data.l[4]; + XDPSLCallReadyEventHandler(dpy, (XEvent *) rce); + break; + } + default: + return(False); + } + return(True); +} + +extern struct _t_DPSContextRec *XDPSContextFromXID(); + +void +XDPSLGetCSDPSStatus(xdpy, event, ret_ctxt, ret_status) + Display *xdpy; + XEvent *event; + void **ret_ctxt; + int *ret_status; +{ + register DPSCAPStatusEvent *sev; + + /* Assert: event is ClientMessage with typePSStatus */ + sev = (DPSCAPStatusEvent *)event->xclient.data.b; + + if (ret_ctxt != NULL) + *ret_ctxt = XDPSContextFromXID(xdpy, sev->cxid); + if (ret_status != NULL) + *ret_status = sev->status; +} + +void +XDPSLGetCSDPSReady(xdpy, event, ret_ctxt, ret_val) + Display *xdpy; + XEvent *event; + void **ret_ctxt; + int *ret_val; +{ + /* Assert: event is ClientMessage with typePSReady */ + + if (ret_ctxt != NULL) + *ret_ctxt = + XDPSContextFromXID(xdpy, (ContextXID)event->xclient.data.l[0]); + if (ret_val != NULL) + { + ret_val[0] = event->xclient.data.l[1]; + ret_val[1] = event->xclient.data.l[2]; + ret_val[2] = event->xclient.data.l[3]; + ret_val[3] = event->xclient.data.l[4]; + } +} + +void +XDPSLCAPNotify(xdpy, cxid, ntype, data, extra) + Display *xdpy; + ContextXID cxid; + unsigned int ntype; /* should this be an enum?? %%% */ + unsigned int data; + unsigned int extra; +{ + int dpyix; + register Display *dpy = ShuntMap[dpyix = DPY_NUMBER(xdpy)]; + register xCAPNotifyReq *req; + + if (dpy == xdpy) return; + + /* We _have_ to sync client and server here in order to guarantee + correct execution sequencing. We call this procedure alot + to keep track of GC's going away, so this is a major + performance hit. */ + if (ntype == DPSCAPNOTE_FREEGC) + XSync(xdpy, False); + + LockDisplay(dpy); + + NXMacroGetReq(CAPNotify, req); + req->reqType = DPSCAPOPCODEBASE; + req->type = X_CAPNotify; + req->cxid = cxid; + req->notification = ntype; + req->data = data; + req->extra = extra; + + if (gAutoFlush) + N_XFlush(dpy); + + UnlockDisplay(dpy); + SyncHandle(); + LastXRequest[dpyix] = XNextRequest(xdpy)-1; +} + +void +XDPSLSync(xdpy) + Display *xdpy; +{ + register Display *dpy = ShuntMap[DPY_NUMBER(xdpy)]; + + if (dpy == xdpy) + { + /* DPS/X */ + XSync(dpy, False); + } + else + { + /* CSDPS */ + XEvent event; + DPSCAPData my; + XExtData *extData; + void *next; + XExtCodes *codes = Codes[DPY_NUMBER(xdpy)]; + + if (codes == NULL) + return; + /* Get private data */ + extData = XFindOnExtensionList( + CSDPSHeadOfDpyExt(xdpy), + codes->extension); + if (!extData) + return; + my = (DPSCAPData) extData->private_data; + my->saveseq = XNextRequest(dpy)-1; + /* first send notification to agent */ + XDPSLCAPNotify(xdpy, 0, DPSCAPNOTE_SYNC, my->saveseq, 0); +#ifdef XXX +fprintf(stderr, "\nXDPSLSync(DPSCAPNOTE_SYNC) sending ... "); +#endif + _XFlush(xdpy); + N_XFlush(dpy); +#ifdef XXX +fprintf(stderr, "sent.\nWaiting for reply ... "); +#endif + /* agent should send a ClientMessage, so wait for it */ + XIfEvent(xdpy, &event, WaitForSyncProc, (char *) my); + +#ifdef XXX +fprintf(stderr, "received.\n"); +#endif + /* now client, agent, and server are synchronized */ + } +} + +void +XDPSLReconcileRequests(xdpy, cxid) + Display *xdpy; + ContextXID cxid; +{ + int dpyix; + unsigned int seqnum; + register Display *dpy = ShuntMap[dpyix = DPY_NUMBER(xdpy)]; + + if (dpy == xdpy) + return; /* No-op for DPS/X */ + + /* Get the sequence number and set the pause flag + IFF we are sure that some X protocol has occurred + since the last time we did a DPS request. This + minimizes pause/resume requests */ + + if (LastXRequest[dpyix] == XNextRequest(xdpy)-1) + { + if (gAutoFlush) + N_XFlush(dpy); /* This is what XDPSLCAPNotify would do */ + return; + } + else + seqnum = DPSCAPSetPause(xdpy, cxid); + + /* Pause the context specified. */ + XDPSLCAPNotify(xdpy, cxid, DPSCAPNOTE_PAUSE, seqnum, 0); + + /* We don't even need to flush. All we have to do is make + sure that the notify request is queued before any + DPS requests that follow. */ +} + +Status +XDPSLSetAgentArg(xdpy, arg, val) + Display *xdpy; + int arg, val; +{ + int dpyix; + register Display *dpy = ShuntMap[dpyix = DPY_NUMBER(xdpy)]; + CARD32 capArg; + register xCAPSetArgReq *req; + + if (dpy == xdpy) + return(Success); /* No-op for DPS/X */ + + /* dpy will be NIL if we haven't opened a connection yet, + but that's okay since we need to save the value anyway. */ + + if (dpy) + { + int syncMask = displayFlags[dpyix].syncMask; + + /* ASSERT: There is no reason to pause the context for this + request, so just sync. */ + if (syncMask & (DPSCAP_SYNCMASK_SYNC|DPSCAP_SYNCMASK_RECONCILE)) + XSync(xdpy, False); + } + + switch (arg) + { + case AGENT_ARG_SMALLFONTS: + AgentArgs[dpyix].showSmallSizes = val; + capArg = DPSCAP_ARG_SMALLFONTS; + break; + case AGENT_ARG_PIXMEM: + AgentArgs[dpyix].pixMem = val; + capArg = DPSCAP_ARG_PIXMEM; + break; + default: + return(!Success); + } + if (!dpy) + return(Success); + + LockDisplay(dpy); + + NXMacroGetReq(CAPSetArg, req); + req->reqType = DPSCAPOPCODEBASE; + req->type = X_CAPSetArg; + req->arg = capArg; + req->val = val; + + if (gAutoFlush) + N_XFlush(dpy); + + UnlockDisplay(dpy); + SyncHandle(); + LastXRequest[dpyix] = XNextRequest(xdpy)-1; + return(Success); +} + + +void +XDPSLCleanAll(xdpy) + register Display *xdpy; +{ + /* Clean up all state associated with dpy */ + register DPSCAPPausedContextData *slot; + int dpyix = DPY_NUMBER(xdpy); + + /* Clean up paused context list */ + for (slot = PausedPerDisplay[dpyix]; slot; slot = PausedPerDisplay[dpyix]) + { + PausedPerDisplay[dpyix] = slot->next; + Xfree(slot); + } + + /* Clear agent args */ + AgentArgs[dpyix].showSmallSizes = 0; + AgentArgs[dpyix].pixMem = 0; +} + +void +XDPSLUpdateAgentArgs(xdpy) + register Display *xdpy; +{ + int dpyix = DPY_NUMBER(xdpy); + + if (AgentArgs[dpyix].showSmallSizes) + XDPSLSetAgentArg(xdpy, AGENT_ARG_SMALLFONTS, AgentArgs[dpyix].showSmallSizes); + if (AgentArgs[dpyix].pixMem) + XDPSLSetAgentArg(xdpy, AGENT_ARG_PIXMEM, AgentArgs[dpyix].pixMem); +} + +void +XDPSLCleanContext(xdpy, cxid) + Display *xdpy; + ContextXID cxid; +{ + /* Clean up all state associated with cxid on this dpy */ + register DPSCAPPausedContextData *slot, *prev; + int dpyix = DPY_NUMBER(xdpy); + + /* If this is DPS/X, then slot will never have been initialized. + See XDPSLNotifyContext */ + + /* Clean up paused context list */ + prev = (DPSCAPPausedContextData *)NULL; + for (slot = PausedPerDisplay[dpyix]; slot; prev = slot, slot = slot->next) + { + if (slot->cxid != cxid) + continue; + if (!prev) + PausedPerDisplay[dpyix] = slot->next; + else + prev->next = slot->next; + Xfree(slot); + break; + } +} + +/* DPS NX 2.0 */ +void +XDPSLSetGCFlushMode(dpy, value) + Display *dpy; + int value; +{ + int dpyix; + register Display *agent = ShuntMap[dpyix = DPY_NUMBER(dpy)]; + + if (value != XDPSNX_GC_UPDATES_SLOW && value != XDPSNX_GC_UPDATES_FAST) + { + DPSWarnProc(NULL, "DPS NX: Bogus GC flush mode.\n"); + return; + } + /* 0 means no NX */ + GCFlushMode[dpyix] = (agent == dpy) ? 0 : value; +} + +int +XDPSLGetGCFlushMode(dpy) + Display *dpy; +{ + return(GCFlushMode[DPY_NUMBER(dpy)]); +} + +void +XDPSLFlushGC(xdpy, gc) + Display *xdpy; + GC gc; +{ + int dpyix; + register Display *dpy = ShuntMap[dpyix = DPY_NUMBER(xdpy)]; + + if (!gc->dirty) return; + + if (GCFlushMode[dpyix] == XDPSNX_GC_UPDATES_FAST) + { + XGCValues vals; + static unsigned long valuemask = DPSGCBITS & ~(GCClipMask); + + /* Okay to call Xlib, since dpy isn't locked */ + DPSAssertWarn(XGetGCValues(xdpy, gc, valuemask, &vals), + NULL, "DPS NX: XGetGCValues returned False\n"); + vals.clip_mask = gc->values.clip_mask; + LockDisplay(dpy); + DPSCAPChangeGC(dpy, gc, DPSGCBITS, &vals); + UnlockDisplay(dpy); + SyncHandle(); + } + /* Fall thru. Either the GCFlushMode is SLOW, which means + we will DPSCAPChangeGC as a side-effect of FlushGC when + the GC hook is called, or we just did it in the FAST case. */ + FlushGC(xdpy, gc); + XDPSLFlush(xdpy); +} + +/* === PRIVATE CSDPS PROCS === */ + +static Status +DPSCAPClientMessageProc(dpy, re, event) + Display *dpy; + XEvent *re; + register xEvent *event; +{ + register XDPSLOutputEvent *oce; + register DPSCAPOutputEvent *oev; + XDPSLOutputEvent fakeOutput; + XExtCodes *codes = Codes[DPY_NUMBER(dpy)]; + PSCMProc oldProc = ClientMsgProc[DPY_NUMBER(dpy)]; + + if (codes != NULL) + { + /* Get private data */ + XExtData *extData = XFindOnExtensionList( + CSDPSHeadOfDpyExt(dpy), + codes->extension); + DPSCAPData my; + + /* There's no extension, or there is an extension but we are + passing events uninterpreted, so just pass it along + unless it is a DPSCAP error. */ + + if (!extData) + goto pass_the_buck; + my = (DPSCAPData) extData->private_data; + if (XDPSLGetPassEventsFlag(dpy) && + (event->u.clientMessage.u.l.type != my->typeXError)) + goto pass_the_buck; + + /* Fake up a DPS extension event and handle it transparently, + without going through the Xlib event queue */ + + if (event->u.clientMessage.u.b.type == my->typePSOutput) + { + oce = &fakeOutput; + oce->length = DPSCAP_BYTESPEROUTPUTEVENT; + oev = (DPSCAPOutputEvent *)event->u.clientMessage.u.b.bytes; + goto common_stuff; + } + else if (event->u.clientMessage.u.b.type == my->typePSOutputWithLen) + { + oce = &fakeOutput; + oev = (DPSCAPOutputEvent *)event->u.clientMessage.u.b.bytes; + oce->length = oev->data[DPSCAP_DATA_LEN]; +common_stuff: + oce->type = codes->first_event + PSEVENTOUTPUT; + oce->serial = _XSetLastRequestRead(dpy, (xGenericReply *)event); + oce->send_event = True; /* ??? */ + oce->display = dpy; + oce->cxid = oev->cxid; + bcopy((char *) oev->data, oce->data, oce->length); + /* We've converted the event, give it to DPS */ + if (TextProc) + (*TextProc)((XEvent *) oce); + return(False); + } + else if (event->u.clientMessage.u.b.type == my->typePSStatus) + { + register XDPSLStatusEvent *sce; + register DPSCAPStatusEvent *sev; + XDPSLStatusEvent fakeStatus; + + sev = (DPSCAPStatusEvent *)event->u.clientMessage.u.b.bytes; + sce = &fakeStatus; + sce->type = codes->first_event + PSEVENTSTATUS; + sce->serial = _XSetLastRequestRead(dpy, (xGenericReply *)event); + sce->send_event = True; /* ??? */ + sce->display = dpy; + sce->cxid = sev->cxid; + sce->status = sev->status; + /* We've converted the event, give it to DPS */ + if (StatusProc[DPY_NUMBER(dpy)]) + (*(StatusProc[DPY_NUMBER(dpy)]))((XEvent *) sce); + return(False); + } + else if (event->u.clientMessage.u.l.type == my->typeXError) + { + xError err; + register xError *e = &err; + + e->type = X_Error; + e->errorCode = event->u.clientMessage.u.l.longs0; + e->sequenceNumber = event->u.u.sequenceNumber; + e->resourceID = event->u.clientMessage.u.l.longs3; + e->minorCode = event->u.clientMessage.u.l.longs2; + e->majorCode = event->u.clientMessage.u.l.longs1; + /* Smash the wire event here, before going off deep end */ + event->u.clientMessage.u.l.type = my->typeNoop; + /* Jump! */ + return(_XError(dpy, e)); + } + else if (event->u.clientMessage.u.l.type == my->typePSReady) + /* L2-DPS/PROTO 9 addition */ + { + register XDPSLReadyEvent *rce; + XDPSLReadyEvent fakeReady; + + rce = &fakeReady; + rce->type = codes->first_event + PSEVENTREADY; + rce->serial = _XSetLastRequestRead(dpy, (xGenericReply *)event); + rce->send_event = True; + rce->display = dpy; + rce->cxid = event->u.clientMessage.u.l.longs0; + rce->val[0] = event->u.clientMessage.u.l.longs1; + rce->val[1] = event->u.clientMessage.u.l.longs2; + rce->val[2] = event->u.clientMessage.u.l.longs3; + rce->val[3] = event->u.clientMessage.u.l.longs4; + XDPSLCallReadyEventHandler(dpy, (XEvent *) rce); + return(False); + } + } + + /* Put the event on the queue, so that Xlib is happy */ +pass_the_buck: + return(oldProc(dpy, re, event)); +} + + +static void +DPSCAPInitGC(dpy, agent, gc) + Display *dpy, *agent; + GC gc; +{ + XGCValues values; + unsigned long valuemask = DPSGCBITS & ~(GCClipMask); + + /* Okay to call Xlib, since dpy isn't locked */ + DPSAssertWarn(XGetGCValues(dpy, gc, valuemask, &values), + NULL, "DPS NX: XGetGCValues returned False\n"); + values.clip_mask = gc->values.clip_mask; + DPSCAPChangeGC(agent, gc, DPSGCBITS, &values); + SyncHandle(); + XDPSLSync(dpy); +} + + +/* ARGSUSED */ + +static Bool +WaitForSyncProc(xdpy, event, arg) + Display *xdpy; + XEvent *event; + char *arg; +{ + DPSCAPData my = (DPSCAPData)arg; + + if ((event->type & 0x7F) == ClientMessage + && event->xclient.message_type == my->typeSync + && event->xclient.data.l[0] == my->saveseq) { + return(True); + } else { + return(False); + } +} + + +static int +DPSCAPAfterProc(xdpy) + Display *xdpy; +{ + register Display *dpy = ShuntMap[DPY_NUMBER(xdpy)]; + GenericProcPtrReturnsInt proc; + + if (dpy != (Display *)NULL && dpy != xdpy) + { + LockDisplay(dpy); + N_XFlush(dpy); + UnlockDisplay(dpy); + LockDisplay(xdpy); + _XFlush(xdpy); + UnlockDisplay(xdpy); + } + if ((proc = AfterProcs[DPY_NUMBER(xdpy)]) != NULL) + return((*proc)(xdpy)); + else + return(0); +} + + +static unsigned int +DPSCAPSetPause(xdpy, cxid) + register Display *xdpy; + register ContextXID cxid; +{ + register DPSCAPPausedContextData *slot; + int dpyix; + unsigned int ret; + + /* Find or create slot */ + + slot = PausedPerDisplay[dpyix = DPY_NUMBER(xdpy)]; + if (!slot) + { + slot = (DPSCAPPausedContextData *) + Xcalloc(1, sizeof(DPSCAPPausedContextData)); + PausedPerDisplay[dpyix] = slot; + goto common_code; + /* IMPLICATION: it is okay to fall through common_code + and do test_ret. */ + } + while (1) + if (slot->cxid == cxid) + { + if (!slot->paused) + { + slot->paused = True; + ++gTotalPaused; + } + /* Back-to-back pauses get different sequence numbers */ + ret = ++slot->seqnum; + goto test_ret; + } + else if (slot->next) slot = slot->next; + else break; + /* cxid wasn't found, so add it */ + /* ASSERT: slot points to last record of the list */ + slot->next = (DPSCAPPausedContextData *) + Xcalloc(1, sizeof(DPSCAPPausedContextData)); + slot = slot->next; +common_code: + slot->paused = True; + ++gTotalPaused; + slot->cxid = cxid; + ret = ++slot->seqnum; +test_ret: + if (!ret) + { + DPSWarnProc(NULL, "Pause sequence wrapped around!"); + } + return(ret); +} + +static Bool +DPSCAPResumeContext(xdpy, cxid) + register Display *xdpy; + register ContextXID cxid; +{ + register DPSCAPPausedContextData *slot; + unsigned int ret; + int dpyix = DPY_NUMBER(xdpy); + + /* Try to match cxid to list of paused contexts */ + for (slot = PausedPerDisplay[dpyix]; slot; slot = slot->next) + if (slot->cxid == cxid && slot->paused) + { + /* Send resume event */ + register XClientMessageEvent *ee; + XEvent e; + XExtData *extData; + DPSCAPData my; + XExtCodes *codes = Codes[dpyix]; + + extData = XFindOnExtensionList( + CSDPSHeadOfDpyExt(xdpy), + codes->extension); + if (!extData) + return(False); + my = (DPSCAPData) extData->private_data; + + ee = &e.xclient; + ee->type = ClientMessage; + ee->display = xdpy; + ee->window = my->agentWindow; + ee->format = 32; + ee->message_type = my->typeResume; + ee->data.l[0] = cxid; + ee->data.l[1] = slot->seqnum; + (void) XSendEvent( + xdpy, + my->agentWindow, + False, + NoEventMask, + &e); + XFlush(xdpy); + /* Turn off flag */ + slot->paused = False; + --gTotalPaused; + return(True); + } + /* Fall thru */ + return(False); +} + + + + + + |