ftp.nice.ch/pub/next/unix/hack/hackkit.2.N.bs.tar.gz#/freebies/source/psh.c

This is psh.c in view mode; [Download] [Up]

/*	psh using the DPS library.

	Written by Bill Spitzak

	If you want to test drawing, first type
	"width height newwindow".
	This will make a movable, orderable window, into which all
	drawing goes.  The window is "retained" and thus all drawing
	appears in it immediately.  "erase" will restore the window to
	its initial blank state with a black border.

	"thiswindow" returns the window the mouse is pointing at.
	Useful for examining appkit windows.

	Several printing routines are modified to flush immediately.

	Except for defining these procedures, NO changes are made to
	the bare postscript server.
*/

#include <dpsclient/dpsclient.h>

void printjunk(DPSContext ctxt, const char *buf, long unsigned int count)
{
    unsigned char c;
    while (count--) {
	c = *buf++;
	if (c < ' ' && c != '\n') {putchar('^'); c ^= 0x40;}
	putchar(c);
	}
    }

void myerrorproc(
    DPSContext ctxt,
    DPSErrorCode errorCode,
    long unsigned int arg1,
    long unsigned int arg2 )
    {
    if (errorCode == 1000) {
	printf("%%%%[ %.*s: %.*s; OffendingCommand: %.*s ]%%%%\n",
	       *(short *)(arg1+14),*(char **)(arg1+16)+arg1+4,
	       *(short *)(arg1+22),*(char **)(arg1+24)+arg1+4,
	       *(short *)(arg1+30),*(char **)(arg1+32)+arg1+4);
	}
    else {
	printf("DPS Error %d:\n",errorCode);
	printjunk(ctxt,(char *)arg1,arg2);
	putchar('\n');
	}
    }

/*============== event tester:
	If you want to test events, use "x currentwindow seteventmask".
	Make sure the 2 bit is on, or it won't get left-down events and
	thus you can't move the window.  All other events are printed:
*/

const char *enames[] = {
    "NULLEVENT",
    "LMOUSEDOWN",
    "LMOUSEUP",
    "RMOUSEDOWN",
    "RMOUSEUP",
    "MOUSEMOVED",
    "LMOUSEDRAGGED",
    "RMOUSEDRAGGED",
    "MOUSEENTERED",
    "MOUSEEXITED",
    "KEYDOWN",
    "KEYUP",
    "FLAGSCHANGED",
    "KITDEFINED",
    "SYSDEFINED",
    "APPDEFINED",
    "TIMER",
    "CURSORUPDATE",
    "RESERVEDEVENT3",
    "RESERVEDEVENT4",
    "RESERVEDEVENT5",
    "RESERVEDEVENT6",
    "RESERVEDEVENT7",
    "RESERVEDEVENT8",
    "RESERVEDEVENT9",
    "RESERVEDEVENT10",
    "RESERVEDEVENT11",
    "RESERVEDEVENT12",
    "RESERVEDEVENT13",
    "RESERVEDEVENT14",
    "RESERVEDEVENT15",
    "RESERVEDEVENT16"};

void reportevent(NXEvent *e)
{
    const char *c;
    if (e->type < 0 || e->type > 31)
	{printf("Event # %d, ",e->type); c="UNKNOWN";}
    else c = enames[e->type];
    printf("%s at %g %g, flags %x, window %d, ",
	   c,e->location.x,e->location.y,e->flags,e->window);
    switch(e->type) {
    case NX_NULLEVENT : break;
    case NX_LMOUSEDOWN :
    case NX_LMOUSEUP :
    case NX_RMOUSEDOWN :
    case NX_RMOUSEUP :
    case NX_MOUSEMOVED :
    case NX_LMOUSEDRAGGED :
    case NX_RMOUSEDRAGGED :
	printf("ev# %d, click %d",
	       e->data.mouse.eventNum,e->data.mouse.click);
	break;
    case NX_KEYDOWN :
    case NX_KEYUP :
    case NX_FLAGSCHANGED :
	printf("repeat %d, set %x, code %x, key %x",
	       e->data.key.repeat,e->data.key.charSet,e->data.key.charCode,e->data.key.keyCode);
	break;
    case NX_MOUSEENTERED :
    case NX_MOUSEEXITED :
	printf("ev# %d, trackingNum %d, userData %d",
	       e->data.tracking.eventNum,e->data.tracking.trackingNum,e->data.tracking.userData);
	break;
    default:
	printf("%g %g (%lX %lX)",
	       e->data.compound.misc.F[0],
	       e->data.compound.misc.F[1],
	       e->data.compound.misc.L[0],
	       e->data.compound.misc.L[1]);
	break;
	}
    printf(".\n");
    }

/*================ main program ==================*/

/* Note yuckiness due to bad addfd implementation!  This is the only
   way I have ever found to sync the main loop of a program with the
   input from a file.  Since it requires posting event 0 it pretty much
   precludes any use of the "App Kit" which will choke or at least ignore
   such events.  Use of DPSAddFD results in an annoying slowdown and
   is avoided except for the "interactive" use of stdin.
   I am mystified as to why such an interface was ever born.  Far better
   and so obvious I can't believe they did not consider it, is a routine
   like "FDCausesEvent(int fd, int event)" so that DPSGetEvent will return
   immediately when an fd is ready.
*/

#define BUFLEN 0x2000

int doneflag;
DPSContext d;
char buf[BUFLEN];

void posteof(void) {
    NXEvent e;
    doneflag = 1;
    e.type = 0;
    e.ctxt = d;
    DPSPostEvent(&e,1);
    }

void typedtext(int fd, void *userData) {
    int n;
    if (!gets(buf)) {posteof(); return;}
    n = strlen(buf); buf[n++] = '\n';
    DPSWriteData(d,buf,n);
    DPSFlushContext(d);
    }

main(int argc, char **argv) {
    NXEvent e;
    int i,n,fd;
    int hadinteractive=0;
    char *p;

    static const char send[] =
	"/= {//= exec flush} bind def\n"
	"/== {//== exec flush} bind def\n"
	"/stack {//stack exec flush} bind def\n"
	"/pstack {//pstack exec flush} bind def\n"
	/* print is NOT 'fixed', because it would cause NL between each */

	"/erase {"
	"erasepage\n"
	"0 1 currentwindow currentwindowbounds\n"
	"4 -2 roll pop pop exch 1 sub exch 1 sub rectstroke"
	"} bind def\n"
	    
	"/newwindow {"
	"0 0 4 2 roll 0 window windowdeviceround\n"
	"1 0 currentwindow orderwindow\n"
	"2 currentwindow seteventmask\n"
	"erase"
	"} bind def\n"

	"/thiswindow {"
	"workspaceWindow currentmouse Above 0 findwindow\n"
	"pop exch pop exch pop} bind def"

	;

    d = DPSCreateContext(0,0,printjunk,myerrorproc);

    i = 1;
    do {
	if (i >= argc) {
	GETSTDIN:
	    fd = 0;
	    if (!isatty(0)) goto PIPED;
	    if (hadinteractive) clearerr(stdin);
	    else {DPSWriteData(d,send,sizeof(send)); hadinteractive = 1;}
	    doneflag = 0;
	    DPSAddFD(fd,typedtext,0,1);
	    for (;;) {
		DPSGetEvent(d,&e,-1,NX_FOREVER,0);
		if (doneflag) break;
		if (e.type == NX_LMOUSEDOWN) {
		    DPSPrintf(d,"1 0 %d orderwindow "
			      "{%d stilldown not {exit} if\n"
			      "workspaceWindow currentmouse %g sub exch %g sub exch\n"
			      "%d movewindow} loop\n",
			      e.window,e.data.mouse.eventNum,
			      e.location.y,e.location.x,e.window);
		    }
		else reportevent(&e);
		}
	    DPSRemoveFD(fd);
	    }
	else if (argv[i][0] == '-') {
	    if (!argv[i][1]) goto GETSTDIN;
	    printf("Unknown switch %s\n",argv[i]); continue;
	    }
	else {
	    fd = open(argv[i],0);
	    if (fd < 0) {printf("%s : %s\n",argv[i],strerror(errno)); continue;}
	PIPED:
	    n = read(fd,buf,BUFLEN); p = buf;
	    if (n > 0 && *buf=='#') { /* strip #! at start of executables */
		for (;p<buf+n;) if (*p++ == '\n') break;
		n -= (p-buf);
		}
	    if (n > 0) DPSWriteData(d,p,n);
	    while ((n = read(fd,buf,BUFLEN))>0) DPSWriteData(d,buf,n);
	    close(fd);
	    DPSWriteData(d,"\nflush\n",7); /* don't botch if file missing eol */
	    DPSWaitContext(d);	/* let downloaded program finish before exit */
	    }
	} while (++i < argc);
/*  DPSDestroyContext(d); */
    }

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.