/*
* 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>
the definition of NOFILE */
#include <stdlib.h>
#include "DPS/XDPSproto.h"
#include "DPS/dpsNXargs.h"
#include "cslibint.h"
#include "dpsassert.h"
#include "DPSCAPClient.h"
#include "publictypes.h"
#include "dpsXpriv.h"
/* === DEFINITIONS === */
#ifndef _NFILE
#else
#endif /* _NFILE */
Punt())
/* === TYPES === */
typedef struct {
char passEvents;
char wrapWaiting;
/* For now DPSDisplayFlags is no larger than a pointer. Revisit this if the
structure grows. */
typedef struct _t_DPSCAPPausedContextData {
unsigned int seqnum;
typedef struct {
char showSmallSizes;
char pixMem;
typedef struct {
} 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 */
/* Force all NX XDPSLGiveInputs to flush independent of gAutoFlush */
/* Quick check for any paused contexts */
int gTotalPaused = 0;
/* === LOCALS === */
/* Common stuff */
/* CSDPS stuff */
#ifdef VMS
static nextDpy = 0;
#endif /* VMS */
};
};
/* === MACROS === */
/* === PRIVATE PROCS === */
static int Punt(void)
{
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%%%%%*/
{
int i;
{
if (i == nextDpy)
{
break;
}
}
return i;
}
#else /* VMS */
#endif /* VMS */
/* === PROCEDURES === */
/* ARGSUSED */
void
{
}
/* ARGSUSED */
void
{
}
void
{
}
void
{
}
void
{
}
void
{
}
int
{
}
/* See CSDPS additions for XDPSLSetVersion */
void
{
int d = DPY_NUMBER(dpy);
/* 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 */
}
{
}
/* ARGSUSED */
static int
{
/* This proc is for native DPS/X only, not CSDPS */
/* Clear list */
#ifdef VMS
/*%%%%Temp till we fix dpy->fd*/
#endif /* VMS */
return 0; /* return-value is ignored */
}
{
}
void
{
}
{
}
void
{
}
static Status
{
(xGenericReply *)wireevent);
return False;
}
return True;
}
static Status
{
(xGenericReply *)wireevent);
return False;
}
return True;
}
static Status
{
(xGenericReply *)wireevent);
return False;
}
return True;
}
/* ARGSUSED */
static int
{
{
*ret_code = 0;
return 1; /* suppress error */
}
else
{
*ret_code = 1;
return 0; /* pass error along */
}
}
int
int *numberType, /* RETURN */
char **floatingName) /* RETURN: CALLER MUST NOT MODIFY OR FREE! */
{
char *ptr;
int first_event;
{
char *ddt;
if (gForceCSDPS)
}
}
if (numberType)
if (floatingName)
return codes->first_event;
} else {
if (gForceCSDPS)
goto try_dps_nx;
/* try DEC UWS 2.2 server */
int myNumberType;
char *myFloatingName;
if (numberType)
if (floatingName)
return first_event;
}
}
/* set procs for native DPS/X */
}
/* 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 libVersion;
while (libVersion >= DPSPROTO_OLDEST)
{
{
break;
}
/* otherwise, try previous version */
--libVersion;
}
if (!doneIt)
{
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 */
{
exit(1);
}
}
if (numberType)
if (floatingName)
*floatingName = ptr;
SyncHandle();
return first_event;
}
static void CopyColorMapsIntoCreateContextReq(
{
}
else {
/* 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 */
}
}
}
/* ARGSUSED */
int x, int y,
unsigned int eventMask,
unsigned int actual,
{
int dpyix;
int index;
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
*
*/
switch (index)
{
default:
case 0: /* Both are default */
&defColorcube, &defGrayramp);
break;
case 1: /* gray specified, Color default */
break;
case 2: /* gray default, Color specified */
break;
case 3: /* Both specified */
break;
}
{
/* Don't worry about pauses here, since we are just
now creating the context! */
}
req->x = x;
req->y = y;
if (sxid)
if (cpsid)
/* If the context creation succeeded and we are CSDPS, send GC values */
{
}
SyncHandle();
return (cxid);
}
/* ARGSUSED */
int x, int y,
unsigned int eventMask,
unsigned int actual,
{
int dpyix;
int index;
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.
*/
switch (index)
{
default:
case 0: /* Both are default */
&defColorcube, &defGrayramp);
break;
case 1: /* gray specified, Color default */
break;
case 2: /* gray default, Color specified */
break;
case 3: /* Both specified */
break;
}
{
/* Don't worry about pauses here, since we are
just now creating this context! */
}
req->x = x;
req->y = y;
if (cpsid)
/* If the context creation succeeded and we are CSDPS, send GC values */
{
}
SyncHandle();
return cxid;
}
{
int dpyix;
SyncHandle();
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
{
int dpyix;
{
{
}
/* If this context got paused, no matter how, ignore
mode and resume it */
{
/* xdpy was flushed by DPSCAPResumeContext */
if (!didFlush)
{
}
}
else if (syncMask & DPSCAP_SYNCMASK_SYNC)
{
}
}
#ifdef COALESCEGIVEINPUT
length);
} else
#endif /* COALESCEGIVEINPUT */
{
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. */
do {
if (length < maxedOutLen)
flushOnce = 0;
}
} else
} 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). */
&& (gForceFlush || didFlush))
SyncHandle();
}
int
{
int dpyix;
{
/* ASSERT: There is no reason to pause the context for this
request, so just sync. */
}
req->notifyIfChange = 0;
SyncHandle();
/* For CSDPS, guarantee that status events arrive just like DPS/X */
{
}
}
void
{
int dpyix;
{
/* ASSERT: There is no reason to pause the context for this
request, so just sync. */
}
{
}
SyncHandle();
}
void
{
int dpyix;
{
/* ASSERT: There is no reason to pause the context for this
request, so just sync. */
}
{
}
SyncHandle();
}
void
int ntype) /* should this be an enum?? %%% */
{
int dpyix;
{
/* ASSERT: There is no reason to pause the context for this
request, so just sync. */
}
{
}
SyncHandle();
{
}
}
{
int dpyix;
{
/* ASSERT: There is no reason to pause the context for this
request, so just sync. */
}
if (sxid)
SyncHandle();
return(cxid);
}
/* Returns 1 on success, 0 on failure (cpsid not a valid context). */
{
int dpyix;
{
/* ASSERT: There is no reason to pause the context for this
request, so just sync. */
}
SyncHandle();
}
{
int dpyix;
{
/* ASSERT: There is no reason to pause the context for this
request, so just sync. */
}
SyncHandle();
}
void
unsigned int enableMask,
unsigned int disableMask,
unsigned int nextMask)
{
int dpyix;
{
/* ASSERT: There is no reason to pause the context for this
request, so just sync. */
}
{
}
SyncHandle();
}
#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
{
register long bytes_read;
if (size == 0) return;
}
}
#endif /* VMS */
void
int val[4])
{
int dpyix;
{
return; /* PROTO 9 or later only */
}
{
/* If this context got paused, no matter how, ignore
mode and resume it */
{
/* xdpy was flushed by DPSCAPResumeContext */
if (gAutoFlush)
}
else if (syncMask & DPSCAP_SYNCMASK_SYNC)
}
{
}
SyncHandle();
}
{
if (c == NULL)
return not_pserror;
switch (ecode - c->first_error)
{
case PSERRORBADCONTEXT: return(pserror_badcontext);
case PSERRORBADSPACE: return(pserror_badspace);
case PSERRORABORT:
return(not_pserror);
else
return(pserror_abort);
default: return(not_pserror);
}
}
/* _____________ CLIENT SIDE DPS ADDITIONS _____________ */
/* === NEW HOOKS INTO XDPS === */
void
{
}
void
{
}
Display *
{
}
void
{
}
int
{
}
void
{
}
void
{
}
void
{
register unsigned long oldDirty;
register int dpyix;
/* We DON'T want to notice all gc changes, just the clip */
{
/* 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. */
}
}
#ifdef VMS
void
{
}
#endif /* VMS */
char *
{
char *old;
if (deflt)
{
}
else
{
}
return(old);
}
void
{
dpy,
}
void
{
/* +++ Consider using agent->synchandler to store old proc */
}
{
return(csdps_not);
if (!extData)
return(csdps_not);
return(csdps_output);
return(csdps_output_with_len);
return(csdps_status);
return(csdps_noop);
return(csdps_ready);
return(csdps_not);
}
{
return(False);
/* Fake up an event in the client's format. Bypasses
extension wire-to-event conversion */
switch (t)
{
case csdps_output:
oce = &fakeOutput;
goto samo_samo;
case csdps_output_with_len:
oce = &fakeOutput;
break;
case csdps_status:
{
sce = &fakeStatus;
break;
}
case csdps_ready: /* L2-DPS/PROTO 9 addition */
{
break;
}
default:
return(False);
}
return(True);
}
void
void **ret_ctxt,
int *ret_status)
{
/* Assert: event is ClientMessage with typePSStatus */
if (ret_status != NULL)
}
void
void **ret_ctxt,
int *ret_val)
{
/* Assert: event is ClientMessage with typePSReady */
*ret_ctxt =
{
}
}
void
unsigned int ntype, /* should this be an enum?? %%% */
unsigned int data,
unsigned int extra)
{
int dpyix;
/* 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)
if (gAutoFlush)
SyncHandle();
}
void
{
{
/* DPS/X */
}
else
{
/* CSDPS */
return;
/* Get private data */
if (!extData)
return;
/* first send notification to agent */
#ifdef XXX
#endif
#ifdef XXX
#endif
/* agent should send a ClientMessage, so wait for it */
#ifdef XXX
#endif
/* now client, agent, and server are synchronized */
}
}
void
{
int dpyix;
unsigned int seqnum;
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
{
if (gAutoFlush)
return;
}
else
/* Pause the context specified. */
/* 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. */
}
{
int dpyix;
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)
{
/* ASSERT: There is no reason to pause the context for this
request, so just sync. */
}
switch (arg)
{
case AGENT_ARG_SMALLFONTS:
break;
case AGENT_ARG_PIXMEM:
break;
default:
return(!Success);
}
if (!dpy)
return(Success);
if (gAutoFlush)
SyncHandle();
return(Success);
}
void
{
/* Clean up all state associated with dpy */
/* Clean up paused context list */
{
}
/* Clear agent args */
}
void
{
}
void
{
/* Clean up all state associated with cxid on this dpy */
/* If this is DPS/X, then slot will never have been initialized.
See XDPSLNotifyContext */
/* Clean up paused context list */
{
continue;
if (!prev)
else
break;
}
}
/* DPS NX 2.0 */
void
int value;
{
int dpyix;
{
return;
}
/* 0 means no NX */
}
int
{
}
void
{
int dpyix;
{
/* Okay to call Xlib, since dpy isn't locked */
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. */
}
/* === PRIVATE CSDPS PROCS === */
static Status
{
{
/* Get private data */
/* 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;
if (XDPSLGetPassEventsFlag(dpy) &&
goto pass_the_buck;
/* Fake up a DPS extension event and handle it transparently,
without going through the Xlib event queue */
{
oce = &fakeOutput;
goto common_stuff;
}
{
oce = &fakeOutput;
/* We've converted the event, give it to DPS */
if (TextProc)
return(False);
}
{
sce = &fakeStatus;
/* We've converted the event, give it to DPS */
return(False);
}
{
/* Smash the wire event here, before going off deep end */
/* Jump! */
}
{
return(False);
}
}
/* Put the event on the queue, so that Xlib is happy */
}
static void
{
/* Okay to call Xlib, since dpy isn't locked */
SyncHandle();
}
/* ARGSUSED */
static Bool
{
return(True);
} else {
return(False);
}
}
static int
{
{
}
else
return(0);
}
static unsigned int
{
int dpyix;
unsigned int ret;
/* Find or create slot */
if (!slot)
{
slot = (DPSCAPPausedContextData *)
goto common_code;
/* IMPLICATION: it is okay to fall through common_code
and do test_ret. */
}
while (1)
{
{
++gTotalPaused;
}
/* Back-to-back pauses get different sequence numbers */
goto test_ret;
}
else break;
/* cxid wasn't found, so add it */
/* ASSERT: slot points to last record of the list */
++gTotalPaused;
if (!ret)
{
}
return(ret);
}
static Bool
{
/* Try to match cxid to list of paused contexts */
{
/* Send resume event */
XEvent e;
if (!extData)
return(False);
(void) XSendEvent(
xdpy,
&e);
/* Turn off flag */
--gTotalPaused;
return(True);
}
/* Fall thru */
return(False);
}