diff options
Diffstat (limited to 'nx-X11/lib/dps/XDPS.c')
-rw-r--r-- | nx-X11/lib/dps/XDPS.c | 2235 |
1 files changed, 2235 insertions, 0 deletions
diff --git a/nx-X11/lib/dps/XDPS.c b/nx-X11/lib/dps/XDPS.c new file mode 100644 index 000000000..5b1614e4c --- /dev/null +++ b/nx-X11/lib/dps/XDPS.c @@ -0,0 +1,2235 @@ +/* + * 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 + */ +/* $XFree86: xc/lib/dps/XDPS.c,v 1.4tsi Exp $ */ + +#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 <stdlib.h> +#include <sys/param.h> +#include <X11/Xlibint.h> +#include <X11/Xatom.h> +#include <X11/Xutil.h> + +#include "DPS/XDPS.h" +#include "DPS/XDPSproto.h" +#include "DPS/XDPSlib.h" +#include "DPS/dpsNXargs.h" + +#include "cslibint.h" +#include "dpsassert.h" +#include "DPSCAPClient.h" + +#include "publictypes.h" +#include "dpsXpriv.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)(Display *, XEvent *, xEvent *); + +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)(Display *); + +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 { + void (*Flush)(Display *); + int (*Read)(Display*, char*, long); + void (*ReadPad)(Display*, char*, long); + Status (*Reply)(Display*, xReply*, int, Bool); + void (*Send)(Display*, _Xconst char*, long); +} 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(Display *dpy, Display *agent, GC gc); +static Status DPSCAPClientMessageProc(Display *dpy, XEvent *re, xEvent *event); +static int DPSCAPAfterProc(Display *xdpy); +static unsigned int DPSCAPSetPause(Display *xdpy, ContextXID cxid); +static Bool DPSCAPResumeContext(Display *xdpy, ContextXID cxid); +static Bool WaitForSyncProc(Display *xdpy, XEvent *event, char *arg); + +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(void) +{ + 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(Display *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(Display *dpy, XDPSLEventHandler proc) +{ + TextProc = proc; +} + +/* ARGSUSED */ +void +XDPSLCallOutputEventHandler(Display *dpy, XEvent *event) +{ + (*TextProc)(event); +} + +void +XDPSLSetStatusEventHandler(Display *dpy, XDPSLEventHandler proc) +{ + StatusProc[DPY_NUMBER(dpy)] = proc; +} + +void +XDPSLCallStatusEventHandler(Display *dpy, XEvent *event) +{ + (*(StatusProc[DPY_NUMBER(dpy)]))(event); +} + +/* Added for L2-DPS/PROTO 9 */ +void +XDPSLSetReadyEventHandler(Display *dpy, XDPSLEventHandler proc) +{ + ReadyProc[DPY_NUMBER(dpy)] = proc; +} + +/* Added for L2-DPS/PROTO 9 */ +void +XDPSLCallReadyEventHandler(Display *dpy, XEvent *event) +{ + (*(ReadyProc[DPY_NUMBER(dpy)]))(event); +} + +/* Added for L2-DPS/PROTO 9 */ +int +XDPSLGetVersion(Display *dpy) +{ + return(version[DPY_NUMBER(dpy)]); +} +/* See CSDPS additions for XDPSLSetVersion */ + +void +XDPSLInitDisplayFlags(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(Display *dpy) +{ + return Codes[DPY_NUMBER(dpy)]; +} + +/* ARGSUSED */ +static int +CloseDisplayProc(Display *dpy, XExtCodes *codes) +{ + /* 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 */ + return 0; /* return-value is ignored */ +} + +Bool +XDPSLGetPassEventsFlag(Display *dpy) +{ + return displayFlags[DPY_NUMBER(dpy)].passEvents; +} + +void +XDPSLSetPassEventsFlag(Display *dpy, Bool flag) +{ + displayFlags[DPY_NUMBER(dpy)].passEvents = flag; +} + +Bool +XDPSLGetWrapWaitingFlag(Display *dpy) +{ + return displayFlags[DPY_NUMBER(dpy)].wrapWaiting; +} + +void +XDPSLSetWrapWaitingFlag(Display *dpy, Bool flag) +{ + displayFlags[DPY_NUMBER(dpy)].wrapWaiting = flag; +} + +static Status +ConvertOutputEvent(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(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(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(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( + 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; + + 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)(Display*, xError*, XExtCodes*, int*); + 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( + xPSCreateContextReq *req, + XStandardColormap *colorcube, + XStandardColormap *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( + register Display *xdpy, + Drawable draw, + GC gc, + int x, int y, + unsigned int eventMask, + XStandardColormap *grayRamp, + XStandardColormap *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) + { + default: + 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( + register Display *xdpy, + SpaceXID sxid, + Drawable draw, + GC gc, + int x, int y, + unsigned int eventMask, + XStandardColormap *grayRamp, + XStandardColormap *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) + { + default: + 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(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(Display *xdpy, ContextXID cxid, char *data, int length) +{ + int dpyix; + register Display *dpy = ShuntMap[dpyix = DPY_NUMBER(xdpy)]; + register xPSGiveInputReq *req; + 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(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(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(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( + 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( + 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( + 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(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( + Display *xdpy, + ContextXID cxid, + unsigned int enableMask, + unsigned int disableMask, + unsigned int 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. + +*/ +void +_XReadPad (Display *dpy, char *data, 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( + 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(Display *dpy, int ecode) +{ + XExtCodes *c = XDPSLGetCodes(dpy); + + if (c == NULL) + return not_pserror; + + 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(Display *dpy, unsigned ver) +{ + version[DPY_NUMBER(dpy)] = ver; +} + +void +XDPSLSetCodes(Display *dpy, XExtCodes *codes) +{ + Codes[DPY_NUMBER(dpy)] = codes; +} + +Display * +XDPSLGetShunt(Display *dpy_in) +{ + return(ShuntMap[DPY_NUMBER(dpy_in)]); +} + +void +XDPSLSetShunt(Display *dpy_in, Display *dpy_out) +{ + ShuntMap[DPY_NUMBER(dpy_in)] = dpy_out; +} + +int +XDPSLGetSyncMask(Display *dpy) +{ + return (int)displayFlags[DPY_NUMBER(dpy)].syncMask; +} + +void +XDPSLSetSyncMask(Display *dpy, int mask) +{ + displayFlags[DPY_NUMBER(dpy)].syncMask = (char)mask; + gForceFlush = (mask & DPSCAP_SYNCMASK_RECONCILE); +} + +void +XDPSLFlush(Display *xdpy) +{ + register Display *dpy = ShuntMap[DPY_NUMBER(xdpy)]; + + _XFlush(xdpy); + if (dpy != xdpy) + N_XFlush(dpy); +} + +void +XDPSLSyncGCClip(Display *xdpy, GC gc) +{ + register unsigned long oldDirty; + register int dpyix; + register Display *dpy = ShuntMap[dpyix = DPY_NUMBER(xdpy)]; + + /* 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(Display *dpy) +{ + dpys[DPY_NUMBER(dpy)] = dpy; +} +#endif /* VMS */ + +char * +XDPSLSetAgentName(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(Display *dpy) +{ + if (dpy == NULL) return; + ClientMsgProc[DPY_NUMBER(dpy)] = XESetWireToEvent( + dpy, + ClientMessage, + DPSCAPClientMessageProc); +} + +void +XDPSLSetAfterProc(Display *xdpy) +{ + if (xdpy == NULL) return; + AfterProcs[DPY_NUMBER(xdpy)] = (GenericProcPtrReturnsInt) + XSetAfterFunction(xdpy, DPSCAPAfterProc); + /* +++ Consider using agent->synchandler to store old proc */ +} + + +CSDPSFakeEventTypes +XDPSLGetCSDPSFakeEventType(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( + 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); +} + +void +XDPSLGetCSDPSStatus( + 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( + 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( + 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(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; + 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(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(Display *xdpy, int arg, int 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( + Display *dpy, + XEvent *re, + 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(Display *dpy, Display *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(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] == (long) my->saveseq) { + return(True); + } else { + return(False); + } +} + + +static int +DPSCAPAfterProc(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(Display *xdpy, 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(Display *xdpy, ContextXID cxid) +{ + register DPSCAPPausedContextData *slot; + 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); +} |