/* * TrmPS.c: version 3.12 of 8/24/87 * Emacs Source File */ # ifdef SCCS static char *___what = "@(#)TrmPS.c 3.12 8/24/87"; # endif /* D.term/TrmPS.c * * PostScript window system driver. * * HISTORY * {3} 3-Jul-87 James Gosling (jag) at norquay * Updated to take advantage of new server features & added mouse support. * * {2} 11-Oct-86 Glenn Skinner (glenn) at ivrel * Added code for font support; made other revisions to fit * it into T2.11. * * {1} 2-Jun-86 James Gosling (jag) at norquay * Initially written */ #include #include #include #include #include #include #include "psio.h" #include "config.h" #include "defs.h" #include "Trm.h" #include "display.h" #include "window.h" #include "winextern.h" #include "keyboard.h" #include "stringdefs.h" #include "exob.h" #include "TrmPS.h" #include "iselect.h" static int curX, curY; static int miny, charheight, charwidth, lineheight, yoff, DesWindowSize; int OldLen; /* The old length of the current line */ int ScrWidth; int ScrHeight; static SysIntVar MousePixelX, /* Current mouse coordinates in pixels */ MousePixelY, InNeWS; /* TRUE if running under NeWS display server. This is set to TRUE by TrmPS if it decides that this session has access to such a server. This value is externally accessible as the variable 'NeWS'. */ #define DeltX(x) (((short) (x)) * ((short) charwidth)) #define DeltY(y) (((short) (y)) * ((short) lineheight)) #define PosX(x) DeltX ((x) - 1) #define PosY(y) (yoff - DeltY ((y) - 1)) static int CursorState; extern PsReSize (); #define MaxFontNameLen 55 /* 50 + ".ddd" suffix */ /* * Switch to the font named by fontname, if possible, returning a const * pointer to a name for the font actually used. Our convention for font * names is to use a string of the form "font.ps", where font names a font, * such as the default "Courier", and ps names the desired point size. Either * part of the name may be missing (along with the separating "."), in which * case the most recent (or a default) value is used for the omitted piece. */ static char * PsSetFont (fontname) char *fontname; { static char CurrentFontReturn[MaxFontNameLen], CurrentFont[MaxFontNameLen]; static int PointSize; char fnbuf[MaxFontNameLen]; register int newps = 0; register char *cp; /* * The first time through, we must obtain information * about the default font, so that we can handle requests * giving only font name or point size properly. */ if (PointSize == 0) { (void) ps_GetFont (CurrentFont, &PointSize); (void) ps_GetFontInfo (&miny, &charheight, &charwidth); lineheight = charheight + 1; } /* Move our argument to a place where we can modify it. */ if (fontname) { (void) strncpy (fnbuf, fontname, sizeof fnbuf - 1); fnbuf[sizeof fnbuf - 1] = '\0'; } else fnbuf[0] = '\0'; fontname = fnbuf; /* Dissect the argument into fontname and point size pieces. */ if (cp = rindex (fontname, '.')) { /* We've been given both pieces. */ if (strlen (cp) > 0) newps = atoi (cp + 1); *cp = '\0'; } else { /* One or the other piece is missing. */ if (isdigit (*fontname)) { /* Assume pointsize -- rules out numeric font names. */ newps = atoi (fontname); (void) strcpy (fontname, CurrentFont); } else { /* Assume font name, but watch out for null string. */ newps = PointSize; if (! *fontname) (void) strcpy (fontname, CurrentFont); } } /* * Attempt to switch to the new font and then * get current font characteristics. */ ps_SetFont (fontname, newps); (void) ps_GetFont (CurrentFont, &PointSize); if (newps == PointSize && strcmp (fontname, CurrentFont) == SAME) { /* * We have the font we requested. Get its characteristics * and arrange to repaint using it. */ tt.t_ReSize = PsReSize; (void) ps_GetFontInfo (&miny, &charheight, &charwidth); lineheight = charheight + 1; /* * XXX: need to get individual character widths here. */ } /* Tack point size back onto CurrentFont. */ (void) sprintf (CurrentFontReturn, "%s.%d", CurrentFont, PointSize); return (CurrentFontReturn); } static SetCursor (up) { static int SavedX, SavedY; static char str; if (CursorState != up) { CursorState = up; if (up) { SavedX = curX; SavedY = curY; if ((str = PhysScreenAt (SavedX, SavedY)) < 0) str = ' '; ps_CursorUp (&str, 1, PosX (SavedX), PosY (SavedY)); } else ps_CursorDown (&str, 1, PosX (SavedX), PosY (SavedY)); } } static inslines (n) register int n; { register int nlines = DesWindowSize - curY + 1 - n; if (nlines <= 0) return; ps_inslines (PosY (curY) + lineheight + miny, -DeltY (n), -DeltY (nlines)); } static dellines (n) register int n; { register int nlines = DesWindowSize - curY + 1 - n; if (nlines <= 0) return; ps_dellines (PosY (curY) + lineheight + miny, -DeltY (n), -DeltY (nlines)); } static window (n) /* {8} */ int n; { DesWindowSize = n <= 0 ? tt.t_length : n; } static UpdateBegin () { if (window_damage == REPAIR_IN_PROGRESS) ps_beginrepair (); SetCursor (0); } static UpdateEnd () { SetCursor (1); if (window_damage == REPAIR_IN_PROGRESS) ps_endrepair (); ps_flush_PostScript (); } static curHL; static HLmode (on) { if (curHL != on) { curHL = on; if (on) ps_setHL1 (); else ps_setHL0 (); } } static writechars (start, end) register char *start, *end; { register int len, erlen; if ((len = end - start + 1) > 0) { if (curHL) ps_blanks (PosX (curX), PosY (curY), DeltX (len)); else if ((erlen = OldLen + 1 - curX) > 0) ps_blanks (PosX (curX), PosY (curY), DeltX (erlen < len ? erlen : len)); ps_writechars (PosX (curX), PosY (curY), start, end - start + 1); curX += end - start + 1; } } static PsBlanks (n) int n; { ps_blanks (PosX (curX), PosY (curY), DeltX (n)); curX += n; } static PsTopos (row, column) register int row, column; { curX = column; curY = row; } static boolean ScreenDestroyed; static PsInit () { if (ScreenDestroyed) exit (-1); } static PsReset () { /* wipescreen (); */ } static cleanup () { if (ScreenDestroyed) exit (-1); ps_zap_display (); ps_close_PostScript (); ScreenDestroyed = TRUE; } /* ARGSUSED */ static PsWipeline (oldHL, OldWidth) { register n = (curHL || oldHL ? tt.t_width : OldWidth) + 1 - curX; if (n > 0) ps_blanks (PosX (curX), PosY (curY), DeltX (n)); } static wipescreen () { if (ScreenDestroyed) exit (-1); curX = 0; curY = 0; ps_wipescreen (); CursorState = 0; } static flash () { ps_flash (); ps_flush_PostScript (); } static PsReSize () { int pixheight, pixwidth; static boolean BeenHere; tt.t_ReSize = NULL; (void) ps_GetDimensions (&pixheight, &pixwidth); ScrWidth = pixwidth / charwidth; ScrHeight = pixheight / lineheight; yoff = pixheight - lineheight - miny; if (ScrWidth != tt.t_width || ScrHeight != tt.t_length) { tt.t_width = MIN (ScrWidth, MaxDspColumns); tt.t_length = MIN (ScrHeight, MaxDspLines); if (BeenHere) ReSize (); BeenHere = TRUE; } DesWindowSize = tt.t_length; } static WiredFunction AddMenu () { char *s = getstr (TRUE, ": add-menu entry "); if (s) ps_AddMenu (s); return (0); } IntFunc (ReturnCharWidth, charwidth); IntFunc (ReturnLineHeight, lineheight); /* * Send a string to the server. */ static WiredFunction PsSendServer () { char *s = getstr (TRUE, ": ps-send-server "); while (*s != '\0') psio_putc(*s++, PostScript); return (0); } static int PsRead (fd, buffer, size) register int fd; register char *buffer; int size; { int x, y, c; register int n = 0; if (fd != psio_fileno (PostScriptInput)) abort (0); /* * This loop is organized incorrectly in that it's willing * to process more than one mouse event, so that the global * mouse coordinate variables can get out of sync. The interface * between emacs and the PostScript input process needs to be * revised to allow event batching. */ while (n < size) { if (ps_IsChar (&c)) buffer[n++] = c; else if (ps_IsFuncKey (&buffer[n])) n += strlen (&buffer[n]); else if (ps_IsDamage ()) { tt.t_ReSize = PsReSize; window_damage = DAMAGE_PENDING; } else if (ps_IsMouse (&c, &x, &y)) { if ((c & 64) == 0) /* Can't cope with up transition... */ n += EncodeMouseAsKeys (buffer + n, c & 3, /* button */ c & 4, /* ctrl */ c & 8, /* meta */ c & 16, /* shift */ c & 32, /* doubleclick */ x / charwidth + 1, (yoff - y + lineheight * 3 / 4) / lineheight + 1); MousePixelX = x; MousePixelY = yoff - y; if (n) break; } else if (psio_eof (PostScriptInput) || psio_error (PostScriptInput)) { KbdEventCode = EC_EOF; break; } else abort (0); /* DEBUG */ if (PostScriptInput->cnt < 3) { int mask = 1 << psio_fileno (PostScriptInput); struct timeval notime; notime.tv_usec = notime.tv_sec = 0; if (select (16, &mask, 0, 0, ¬ime) <= 0) break; } } return (n == 0 ? -1 : n); } /* * Emulate the select system call, taking into account input on KbdInFd * that's been read, but not as yet consumed. */ PsSelect (nfds, in, out, except, tv) int nfds; fd_set *in, *out, *except; struct timeval *tv; { struct timeval notime; register int i; register int rv; /* * If KbdInFd is not involved, or if we don't already * have unconsumed input piled up on it, simply do a * normal select. */ if (! in || ! FD_ISSET (KbdInFd, in) || PostScriptInput->cnt <= 0) return (select (nfds, in, out, except, tv)); /* * Since keyboard input has "selected true", the select * we're simulating would return immediately. Get info * on the other descriptors by using a polling select. * * There's one other wrinkle. If the only descriptor * set was KbdInFd within in, we must avoid doing the * select. */ FD_CLR (KbdInFd, in); for (i = 0; i < nfds; i++) if (FD_ISSET (i, in) || (out && FD_ISSET (i, out)) || (except && FD_ISSET (i, except))) break; if (i == nfds) { FD_SET (KbdInFd, in); return (1); } notime.tv_usec = notime.tv_sec = 0; rv = select (nfds, in, out, except, ¬ime); FD_SET (KbdInFd, in); return (rv >= 0 ? rv + 1 : rv); } static WiredFunction MouseToDot () { ps_WarpMouse (PosX (curX) + DeltX (1) / 2, PosY (curY) + DeltY (1) / 2); return (0); } /* * Make symbols accessible through the extension language. * This is called by emacs.c$DefWiredSymbols. */ PsDefSyms () { static boolean BeenHere; /* Only do this once, in case of dumped image. */ if (BeenHere) return; BeenHere = TRUE; /* First do the high-level functions available to all drivers. */ SymsOfFont (); SymsOfMouse (); /* Now for the functions defined in this driver. */ defproc (AddMenu, "add-menu"); defproc (ReturnCharWidth, "character-width"); defproc (ReturnLineHeight, "line-height"); defproc (MouseToDot, "mouse-to-dot"); defproc (PsSendServer, "ps-send-server"); /* Now for the functions defined in this driver. */ DefIntVar ("mouse-pixel-x", &MousePixelX); DefIntVar ("mouse-pixel-y", &MousePixelY); DefIntVar ("NeWS", &InNeWS); # if 0 defproc (GetIndexedSelection, "get-indexed-selection"); defproc (SetIndexedSelection, "set-indexed-selection"); # endif 0 tt.t_ReSize = PsReSize; window_damage = DAMAGE_PENDING; } success TrmPS (tname) char *tname; { int pgrp; /* * Check for the NeWS server's availability. */ if (getenv ("NEWSSERVER") == 0 || ps_open_PostScript () == 0) return (FAIL); # if 0 /* not ready for this yet... */ /* * If Trm.c$ChooseDriver has decided to use a character terminal rather * than a bitmap display, it will have set DspIsBitmap to FALSE. Since * we're a well-behaved bitmap driver, we'll respect its wishes. */ if (! DspIsBitmap) return (FAIL); # endif 0 KbdInFd = psio_fileno (PostScript); ps_initialize (80, 50); /* * Establish a process group for us to run in. */ pgrp = getpid (); (void) setpgrp (pgrp); # if 0 (void) ioctl (KbdInFd, SIOCSPGRP, &pgrp); # endif 0 tt.t_HLmode = HLmode; tt.t_INSmode = NoOperation; tt.t_UpdateBegin = UpdateBegin; tt.t_UpdateEnd = UpdateEnd; tt.t_read = PsRead; tt.t_select = PsSelect; tt.t_inslines = NoOperation; tt.t_dellines = NoOperation; tt.t_blanks = PsBlanks; tt.t_init = PsInit; tt.t_cleanup = cleanup; tt.t_wipeline = PsWipeline; tt.t_wipescreen = wipescreen; tt.t_topos = PsTopos; tt.t_reset = PsReset; tt.t_writechars = writechars; tt.t_delchars = NoOperation; tt.t_flash = flash; tt.t_beep = flash; tt.t_window = window; tt.t_inslines = inslines; /* {8} */ tt.t_dellines = dellines; /* {8} */ tt.t_ILpf = 5; tt.t_ILov = 10; tt.t_ICmf = MissingFeature; tt.t_ICov = MissingFeature; tt.t_DCmf = MissingFeature; tt.t_DCov = MissingFeature; tt.t_SetFont = PsSetFont; tt.t_HasMeta = TRUE; tt.t_supfile = "D.term/NeWS.ml"; # if 0 tt.t_DriverName = "TrmPS (PostScript display server driver)"; # endif 0 tt.t_DefSyms = PsDefSyms; /* Initialize the high-level functions and their symbols. */ InitFont (); /* * Make sure font info is valid before calling * other routines that want to use it. */ SetFont (NULL); PsReSize (); InNeWS = DspIsBitmap = TRUE; return (SUCCEED); }