diff options
Diffstat (limited to 'Tekproc.c')
-rw-r--r-- | Tekproc.c | 1986 |
1 files changed, 1986 insertions, 0 deletions
diff --git a/Tekproc.c b/Tekproc.c new file mode 100644 index 0000000..6a7f668 --- /dev/null +++ b/Tekproc.c @@ -0,0 +1,1986 @@ +/* $XTermId: Tekproc.c,v 1.191 2011/12/27 10:19:51 tom Exp $ */ + +/* + * Copyright 2001-2010,2011 by Thomas E. Dickey + * + * All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name(s) of the above copyright + * holders shall not be used in advertising or otherwise to promote the + * sale, use or other dealings in this Software without prior written + * authorization. + * + * Copyright 1988 The Open Group + * + * 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. + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of The Open Group shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from The Open Group. + * + * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + * + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, + * 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 Digital Equipment + * Corporation not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior permission. + * + * + * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING + * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL + * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR + * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* Tekproc.c */ + +#define RES_OFFSET(field) XtOffsetOf(TekWidgetRec, field) + +#include <xterm.h> + +#include <X11/Xatom.h> +#include <X11/Xutil.h> +#include <X11/cursorfont.h> +#include <X11/Xmu/CharSet.h> + +#if OPT_TOOLBAR + +#if defined(HAVE_LIB_XAW) +#include <X11/Xaw/Form.h> +#elif defined(HAVE_LIB_XAW3D) +#include <X11/Xaw3d/Form.h> +#elif defined(HAVE_LIB_NEXTAW) +#include <X11/neXtaw/Form.h> +#elif defined(HAVE_LIB_XAWPLUS) +#include <X11/XawPlus/Form.h> +#endif + +#endif /* OPT_TOOLBAR */ + +#include <assert.h> +#include <stdio.h> +#include <ctype.h> +#include <signal.h> + +#include <Tekparse.h> +#include <data.h> +#include <error.h> +#include <menu.h> +#include <xstrings.h> + +#define DefaultGCID XGContextFromGC(DefaultGC(XtDisplay(tw), DefaultScreen(XtDisplay(tw)))) + +/* Tek defines */ + +#define DOTDASHEDLINE 2 +#define DOTTEDLINE 1 +#define EAST 01 +#define LINEMASK 07 +#define LONGDASHEDLINE 4 +#define MARGIN1 0 +#define MARGIN2 1 +#define MAX_PTS 150 +#define MAX_VTX 300 +#define NORTH 04 +#define PENDOWN 1 +#define PENUP 0 +#define SHORTDASHEDLINE 3 +#define SOLIDLINE 0 +#define SOUTH 010 +#define TEKBOTTOMPAD 23 +#define TEKDEFHEIGHT 565 +#define TEKDEFWIDTH 750 +#define TEKHEIGHT 3072 +#define TEKHOME ( (TekChar[tekscr->page.fontsize].nlines - 1) \ + * TekChar[tekscr->page.fontsize].vsize) +#define TEKMINHEIGHT 452 +#define TEKMINWIDTH 600 +#define TEKTOPPAD 34 +#define TEKWIDTH 4096 +#define WEST 02 + +#define TekMove(tw,x,y) tekscr->cur_X = x; tekscr->cur_Y = y +#define input() Tinput(tw) +#define unput(c) *Tpushback++ = (Char) c +/* *INDENT-OFF* */ +static struct Tek_Char { + int hsize; /* in Tek units */ + int vsize; /* in Tek units */ + int charsperline; + int nlines; +} TekChar[TEKNUMFONTS] = { + {56, 88, 74, 35}, /* large */ + {51, 82, 81, 38}, /* #2 */ + {34, 53, 121, 58}, /* #3 */ + {31, 48, 133, 64}, /* small */ +}; +/* *INDENT-ON* */ + +static Cursor GINcursor; +static XSegment *line_pt; +static int nplot; +static TekLink Tek0; +static jmp_buf Tekjump; +static TekLink *TekRecord; +static XSegment *Tline; + +static Const int *curstate = Talptable; +static Const int *Tparsestate = Talptable; + +static char defaultTranslations[] = "\ + ~Meta<KeyPress>: insert-seven-bit() \n\ + Meta<KeyPress>: insert-eight-bit() \n\ + !Ctrl <Btn1Down>: popup-menu(mainMenu) \n\ + !Lock Ctrl <Btn1Down>: popup-menu(mainMenu) \n\ +!Lock Ctrl @Num_Lock <Btn1Down>: popup-menu(mainMenu) \n\ + !Ctrl @Num_Lock <Btn1Down>: popup-menu(mainMenu) \n\ + !Ctrl <Btn2Down>: popup-menu(tekMenu) \n\ + !Lock Ctrl <Btn2Down>: popup-menu(tekMenu) \n\ +!Lock Ctrl @Num_Lock <Btn2Down>: popup-menu(tekMenu) \n\ + !Ctrl @Num_Lock <Btn2Down>: popup-menu(tekMenu) \n\ + Shift ~Meta<Btn1Down>: gin-press(L) \n\ + ~Meta<Btn1Down>: gin-press(l) \n\ + Shift ~Meta<Btn2Down>: gin-press(M) \n\ + ~Meta<Btn2Down>: gin-press(m) \n\ + Shift ~Meta<Btn3Down>: gin-press(R) \n\ + ~Meta<Btn3Down>: gin-press(r)"; +/* *INDENT-OFF* */ +static XtActionsRec actionsList[] = { + { "string", HandleStringEvent }, + { "insert", HandleKeyPressed }, /* alias for insert-seven-bit */ + { "insert-seven-bit", HandleKeyPressed }, + { "insert-eight-bit", HandleEightBitKeyPressed }, + { "gin-press", HandleGINInput }, + { "secure", HandleSecure }, + { "create-menu", HandleCreateMenu }, + { "popup-menu", HandlePopupMenu }, + /* menu actions */ + { "allow-send-events", HandleAllowSends }, + { "set-visual-bell", HandleSetVisualBell }, +#ifdef ALLOWLOGGING + { "set-logging", HandleLogging }, +#endif + { "redraw", HandleRedraw }, + { "send-signal", HandleSendSignal }, + { "quit", HandleQuit }, + { "set-scrollbar", HandleScrollbar }, + { "set-jumpscroll", HandleJumpscroll }, + { "set-reverse-video", HandleReverseVideo }, + { "set-autowrap", HandleAutoWrap }, + { "set-reversewrap", HandleReverseWrap }, + { "set-autolinefeed", HandleAutoLineFeed }, + { "set-appcursor", HandleAppCursor }, + { "set-appkeypad", HandleAppKeypad }, + { "set-scroll-on-key", HandleScrollKey }, + { "set-scroll-on-tty-output", HandleScrollTtyOutput }, + { "set-allow132", HandleAllow132 }, + { "set-cursesemul", HandleCursesEmul }, + { "set-marginbell", HandleMarginBell }, + { "set-altscreen", HandleAltScreen }, + { "soft-reset", HandleSoftReset }, + { "hard-reset", HandleHardReset }, + { "set-terminal-type", HandleSetTerminalType }, + { "set-visibility", HandleVisibility }, + { "set-tek-text", HandleSetTekText }, + { "tek-page", HandleTekPage }, + { "tek-reset", HandleTekReset }, + { "tek-copy", HandleTekCopy }, +#if OPT_TOOLBAR + { "set-toolbar", HandleToolbar }, +#endif +}; +/* *INDENT-ON* */ + +static Dimension defOne = 1; + +#define GIN_TERM_NONE_STR "none" +#define GIN_TERM_CR_STR "CRonly" +#define GIN_TERM_EOT_STR "CR&EOT" + +#define GIN_TERM_NONE 0 +#define GIN_TERM_CR 1 +#define GIN_TERM_EOT 2 + +#ifdef VMS +#define DFT_FONT_SMALL "FIXED" +#else +#define DFT_FONT_SMALL "6x10" +#endif + +static XtResource resources[] = +{ + {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension), + XtOffsetOf(CoreRec, core.width), XtRDimension, (caddr_t) & defOne}, + {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension), + XtOffsetOf(CoreRec, core.height), XtRDimension, (caddr_t) & defOne}, + Fres("fontLarge", XtCFont, tek.Tfont[TEK_FONT_LARGE], "9x15"), + Fres("font2", XtCFont, tek.Tfont[TEK_FONT_2], "6x13"), + Fres("font3", XtCFont, tek.Tfont[TEK_FONT_3], "8x13"), + Fres("fontSmall", XtCFont, tek.Tfont[TEK_FONT_SMALL], DFT_FONT_SMALL), + Sres(XtNinitialFont, XtCInitialFont, tek.initial_font, "large"), + Sres("ginTerminator", "GinTerminator", tek.gin_terminator_str, GIN_TERM_NONE_STR), +#if OPT_TOOLBAR + Wres(XtNmenuBar, XtCMenuBar, tek.tb_info.menu_bar, 0), + Ires(XtNmenuHeight, XtCMenuHeight, tek.tb_info.menu_height, 25), +#endif +}; + +static IChar Tinput(TekWidget /* tw */ ); +static int getpoint(TekWidget /* tw */ ); +static void TCursorBack(TekWidget /* tw */ ); +static void TCursorDown(TekWidget /* tw */ ); +static void TCursorForward(TekWidget /* tw */ ); +static void TCursorUp(TekWidget /* tw */ ); +static void TekBackground(TekWidget /* tw */ , + TScreen * /* screen */ ); +static void TekConfigure(Widget /* w */ ); +static void TekDraw(TekWidget /* tw */ , + int /* x */ , + int /* y */ ); +static void TekEnq(TekWidget /* tw */ , + unsigned /* status */ , + int /* x */ , + int /* y */ ); +static void TekFlush(TekWidget /* tw */ ); +static void TekInitialize(Widget /* request */ , + Widget /* wnew */ , + ArgList /* args */ , + Cardinal * /* num_args */ ); +static void TekPage(TekWidget /* tw */ ); +static void TekRealize(Widget /* gw */ , + XtValueMask * /* valuemaskp */ , + XSetWindowAttributes * /* values */ ); + +static WidgetClassRec tekClassRec = +{ + { +/* core_class fields */ + (WidgetClass) & widgetClassRec, /* superclass */ + "Tek4014", /* class_name */ + sizeof(TekWidgetRec), /* widget_size */ + NULL, /* class_initialize */ + NULL, /* class_part_initialize */ + False, /* class_inited */ + TekInitialize, /* initialize */ + NULL, /* initialize_hook */ + TekRealize, /* realize */ + actionsList, /* actions */ + XtNumber(actionsList), /* num_actions */ + resources, /* resources */ + XtNumber(resources), /* num_resources */ + NULLQUARK, /* xrm_class */ + True, /* compress_motion */ + True, /* compress_exposure */ + True, /* compress_enterleave */ + False, /* visible_interest */ + NULL, /* destroy */ + TekConfigure, /* resize */ + TekExpose, /* expose */ + NULL, /* set_values */ + NULL, /* set_values_hook */ + XtInheritSetValuesAlmost, /* set_values_almost */ + NULL, /* get_values_hook */ + NULL, /* accept_focus */ + XtVersion, /* version */ + NULL, /* callback_offsets */ + defaultTranslations, /* tm_table */ + XtInheritQueryGeometry, /* query_geometry */ + XtInheritDisplayAccelerator, /* display_accelerator */ + NULL /* extension */ + } +}; +WidgetClass tekWidgetClass = (WidgetClass) & tekClassRec; + +static Bool Tfailed = False; + +int +TekInit(void) +{ + Widget form_top, menu_top; + Dimension menu_high; + + if (!Tfailed + && tekWidget == 0) { + Cardinal nargs = 0; + Arg myArgs[3]; + Boolean iconic = 0; + + TRACE(("TekInit\n")); + XtSetArg(myArgs[nargs], XtNiconic, &iconic); + ++nargs; + XtGetValues(toplevel, myArgs, nargs); + + nargs = 0; + XtSetArg(myArgs[nargs], XtNiconic, iconic); + ++nargs; + XtSetArg(myArgs[nargs], XtNallowShellResize, True); + ++nargs; + XtSetArg(myArgs[nargs], XtNinput, True); + ++nargs; + + /* this causes the Initialize method to be called */ + tekshellwidget = + XtCreatePopupShell("tektronix", topLevelShellWidgetClass, + toplevel, myArgs, nargs); + + SetupMenus(tekshellwidget, &form_top, &menu_top, &menu_high); + + /* this causes the Realize method to be called */ + tekWidget = (TekWidget) + XtVaCreateManagedWidget("tek4014", + tekWidgetClass, form_top, +#if OPT_TOOLBAR + XtNmenuBar, menu_top, + XtNresizable, True, + XtNfromVert, menu_top, + XtNtop, XawChainTop, + XtNleft, XawChainLeft, + XtNright, XawChainRight, + XtNbottom, XawChainBottom, + XtNmenuHeight, menu_high, +#endif + (XtPointer) 0); +#if OPT_TOOLBAR + ShowToolbar(resource.toolBar); +#endif + } + return (!Tfailed); +} + +/* + * If we haven't allocated the PtyData struct, do so. + */ +int +TekPtyData(void) +{ + if (Tpushb == 0) { + if ((Tpushb = TypeMallocN(Char, 10)) == NULL + || (Tline = TypeMallocN(XSegment, MAX_VTX)) == NULL) { + xtermWarning("Not enough core for Tek mode\n"); + if (Tpushb) + free(Tpushb); + Tfailed = True; + return 0; + } + } + return 1; +} + +static void +Tekparse(TekWidget tw) +{ + XtermWidget xw = term; + TScreen *screen = TScreenOf(xw); + TekScreen *tekscr = TekScreenOf(tw); + int x, y; + IChar c = 0; + IChar ch; + int nextstate; + + for (;;) { + c = input(); + /* + * The parsing tables all have 256 entries. If we're supporting + * wide characters, we handle them by treating them the same as + * printing characters. + */ +#if OPT_WIDE_CHARS + if (c > 255) { + nextstate = (Tparsestate == Talptable) + ? CASE_PRINT + : CASE_IGNORE; + } else +#endif + nextstate = Tparsestate[c]; + TRACE(("Tekparse %04X -> %d\n", c, nextstate)); + + switch (nextstate) { + case CASE_REPORT: + TRACE(("case: report address\n")); + if (tekscr->TekGIN) { + TekGINoff(tw); + TekEnqMouse(tw, 0); + } else { + c = 064; /* has hard copy unit */ + if (tekscr->margin == MARGIN2) + c |= 02; + TekEnq(tw, c, tekscr->cur_X, tekscr->cur_Y); + } + TekRecord->ptr[-1] = ANSI_NAK; /* remove from recording */ + Tparsestate = curstate; + break; + + case CASE_VT_MODE: + TRACE(("case: special return to vt102 mode\n")); + Tparsestate = curstate; + TekRecord->ptr[-1] = ANSI_NAK; /* remove from recording */ + FlushLog(xw); + return; + + case CASE_SPT_STATE: + TRACE(("case: Enter Special Point Plot mode\n")); + if (tekscr->TekGIN) + TekGINoff(tw); + Tparsestate = curstate = Tspttable; + break; + + case CASE_GIN: + TRACE(("case: Do Tek GIN mode\n")); + tekscr->TekGIN = &TekRecord->ptr[-1]; + /* Set cross-hair cursor raster array */ + if ((GINcursor = + make_colored_cursor(XC_tcross, + T_COLOR(screen, MOUSE_FG), + T_COLOR(screen, MOUSE_BG))) != 0) { + XDefineCursor(XtDisplay(tw), TWindow(tekscr), + GINcursor); + } + Tparsestate = Tbyptable; /* Bypass mode */ + break; + + case CASE_BEL: + TRACE(("case: BEL\n")); + if (tekscr->TekGIN) + TekGINoff(tw); + if (!tekRefreshList) + Bell(xw, XkbBI_TerminalBell, 0); + Tparsestate = curstate; /* clear bypass condition */ + break; + + case CASE_BS: + TRACE(("case: BS\n")); + if (tekscr->TekGIN) + TekGINoff(tw); + Tparsestate = curstate; /* clear bypass condition */ + TCursorBack(tw); + break; + + case CASE_PT_STATE: + TRACE(("case: Enter Tek Point Plot mode\n")); + if (tekscr->TekGIN) + TekGINoff(tw); + Tparsestate = curstate = Tpttable; + break; + + case CASE_PLT_STATE: + TRACE(("case: Enter Tek Plot mode\n")); + if (tekscr->TekGIN) + TekGINoff(tw); + Tparsestate = curstate = Tplttable; + if ((c = input()) == ANSI_BEL) + tekscr->pen = PENDOWN; + else { + unput(c); + tekscr->pen = PENUP; + } + break; + + case CASE_TAB: + TRACE(("case: HT\n")); + if (tekscr->TekGIN) + TekGINoff(tw); + Tparsestate = curstate; /* clear bypass condition */ + TCursorForward(tw); + break; + + case CASE_IPL_STATE: + TRACE(("case: Enter Tek Incremental Plot mode\n")); + if (tekscr->TekGIN) + TekGINoff(tw); + Tparsestate = curstate = Tipltable; + break; + + case CASE_ALP_STATE: + TRACE(("case: Enter Tek Alpha mode from any other mode\n")); + if (tekscr->TekGIN) + TekGINoff(tw); + /* if in one of graphics states, move alpha cursor */ + if (nplot > 0) /* flush line VTbuffer */ + TekFlush(tw); + Tparsestate = curstate = Talptable; + break; + + case CASE_UP: + TRACE(("case: cursor up\n")); + if (tekscr->TekGIN) + TekGINoff(tw); + Tparsestate = curstate; /* clear bypass condition */ + TCursorUp(tw); + break; + + case CASE_COPY: + TRACE(("case: make copy\n")); + if (tekscr->TekGIN) + TekGINoff(tw); + TekCopy(tw); + TekRecord->ptr[-1] = ANSI_NAK; /* remove from recording */ + Tparsestate = curstate; /* clear bypass condition */ + break; + + case CASE_PAGE: + TRACE(("case: Page Function\n")); + if (tekscr->TekGIN) + TekGINoff(tw); + TekPage(tw); /* clear bypass condition */ + break; + + case CASE_BES_STATE: + TRACE(("case: Byp: an escape char\n")); + Tparsestate = Tbestable; + break; + + case CASE_BYP_STATE: + TRACE(("case: set bypass condition\n")); + Tparsestate = Tbyptable; + break; + + case CASE_IGNORE: + TRACE(("case: Esc: totally ignore CR, ESC, LF, ~\n")); + break; + + case CASE_ASCII: + TRACE(("case: Select ASCII char set\n")); + /* ignore for now */ + Tparsestate = curstate; + break; + + case CASE_APL: + TRACE(("case: Select APL char set\n")); + /* ignore for now */ + Tparsestate = curstate; + break; + + case CASE_CHAR_SIZE: + TRACE(("case: character size selector\n")); + TekSetFontSize(tw, False, (int) (c & 03)); + Tparsestate = curstate; + break; + + case CASE_BEAM_VEC: + TRACE(("case: beam and vector selector\n")); + /* only line types */ + c = (IChar) (c & LINEMASK); + if (c != tekscr->cur.linetype) { + if (nplot > 0) + TekFlush(tw); + if (c <= TEKNUMLINES) + tekscr->cur.linetype = c; + } + Tparsestate = curstate; + break; + + case CASE_CURSTATE: + Tparsestate = curstate; + break; + + case CASE_PENUP: + TRACE(("case: Ipl: penup\n")); + tekscr->pen = PENUP; + break; + + case CASE_PENDOWN: + TRACE(("case: Ipl: pendown\n")); + tekscr->pen = PENDOWN; + break; + + case CASE_IPL_POINT: + TRACE(("case: Ipl: point\n")); + x = tekscr->cur_X; + y = tekscr->cur_Y; + if (c & NORTH) + y++; + else if (c & SOUTH) + y--; + if (c & EAST) + x++; + else if (c & WEST) + x--; + if (tekscr->pen == PENDOWN) + TekDraw(tw, x, y); + else + TekMove(tw, x, y); + break; + + case CASE_PLT_VEC: + TRACE(("case: Plt: vector\n")); + unput(c); + if (getpoint(tw)) { + if (tekscr->pen == PENDOWN) { + TekDraw(tw, tekscr->cur.x, tekscr->cur.y); + } else { + TekMove(tw, tekscr->cur.x, tekscr->cur.y); + } + tekscr->pen = PENDOWN; + } + break; + + case CASE_PT_POINT: + TRACE(("case: Pt: point\n")); + unput(c); + if (getpoint(tw)) { + TekMove(tw, tekscr->cur.x, tekscr->cur.y); + TekDraw(tw, tekscr->cur.x, tekscr->cur.y); + } + break; + + case CASE_SPT_POINT: + TRACE(("case: Spt: point\n")); + /* ignore intensity character in c */ + if (getpoint(tw)) { + TekMove(tw, tekscr->cur.x, tekscr->cur.y); + TekDraw(tw, tekscr->cur.x, tekscr->cur.y); + } + break; + + case CASE_CR: + TRACE(("case: CR\n")); + if (tekscr->TekGIN) + TekGINoff(tw); + if (nplot > 0) /* flush line VTbuffer */ + TekFlush(tw); + tekscr->cur_X = tekscr->margin == MARGIN1 ? 0 : + TEKWIDTH / 2; + Tparsestate = curstate = Talptable; + break; + + case CASE_ESC_STATE: + TRACE(("case: ESC\n")); + Tparsestate = Tesctable; + break; + + case CASE_LF: + TRACE(("case: LF\n")); + if (tekscr->TekGIN) + TekGINoff(tw); + TCursorDown(tw); + if (!tekRefreshList) + do_xevents(); + break; + + case CASE_SP: + TRACE(("case: SP\n")); + TCursorForward(tw); + break; + + case CASE_PRINT: + TRACE(("case: printable character\n")); + ch = c; + x = (int) (tekscr->cur_X * TekScale(tekscr)) + + screen->border; + y = (int) ((TEKHEIGHT + TEKTOPPAD - tekscr->cur_Y) * TekScale(tekscr)) + + screen->border; + +#if OPT_WIDE_CHARS + if (screen->wide_chars + && (ch > 255)) { + XChar2b sbuf; + sbuf.byte2 = LO_BYTE(ch); + sbuf.byte1 = HI_BYTE(ch); + XDrawImageString16(XtDisplay(tw), + TWindow(tekscr), + tekscr->TnormalGC, + x, + y, + &sbuf, + 1); + } else +#endif + { + char ch2 = (char) ch; + XDrawString(XtDisplay(tw), + TWindow(tekscr), + tekscr->TnormalGC, + x, + y, + &ch2, + 1); + } + TCursorForward(tw); + break; + case CASE_OSC: + /* FIXME: someone should disentangle the input queues + * of this code so that it can be state-driven. + */ + TRACE(("case: do osc escape\n")); + { + /* + * do_osc() can call TekExpose(), which calls TekRefresh(), + * and sends us recurring here - don't do that... + */ + static int nested; + + Char buf2[512]; + IChar c2; + size_t len = 0; + while ((c2 = input()) != ANSI_BEL) { + if (!isprint((int) (c2 & 0x7f)) + || len + 2 >= (int) sizeof(buf2)) + break; + buf2[len++] = (Char) c2; + } + buf2[len] = 0; + if (!nested++) { + if (c2 == ANSI_BEL) + do_osc(xw, buf2, len, ANSI_BEL); + } + --nested; + } + Tparsestate = curstate; + break; + } + } +} + +static int rcnt; +static char *rptr; +static PtySelect Tselect_mask; + +static IChar +Tinput(TekWidget tw) +{ + XtermWidget xw = term; + TekScreen *tekscr = TekScreenOf(tw); + TScreen *screen = TScreenOf(xw); + TekLink *tek; + + if (Tpushback > Tpushb) + return (*--Tpushback); + if (tekRefreshList) { + if (rcnt-- > 0) + return (IChar) (*rptr++); + if ((tek = tekRefreshList->next) != 0) { + tekRefreshList = tek; + rptr = tek->data; + rcnt = tek->count - 1; + TekSetFontSize(tw, False, tek->fontsize); + return (IChar) (*rptr++); + } + tekRefreshList = (TekLink *) 0; + longjmp(Tekjump, 1); + } + again: + if (VTbuffer->next >= VTbuffer->last) { + int update = VTbuffer->update; + + if (nplot > 0) /* flush line */ + TekFlush(tw); +#ifdef VMS + Tselect_mask = pty_mask; /* force a read */ +#else /* VMS */ + XFD_COPYSET(&pty_mask, &Tselect_mask); +#endif /* VMS */ + for (;;) { +#ifdef CRAY + struct timeval crocktimeout; + crocktimeout.tv_sec = 0; + crocktimeout.tv_usec = 0; + (void) Select(max_plus1, + &Tselect_mask, NULL, NULL, + &crocktimeout); +#endif + if (readPtyData(xw, &Tselect_mask, VTbuffer)) { + break; + } + if (Ttoggled && curstate == Talptable) { + TCursorToggle(tw, TOGGLE); + Ttoggled = False; + } + if (xtermAppPending() & XtIMXEvent) { +#ifdef VMS + Tselect_mask = X_mask; +#else /* VMS */ + XFD_COPYSET(&X_mask, &Tselect_mask); +#endif /* VMS */ + } else { + XFlush(XtDisplay(tw)); +#ifdef VMS + Tselect_mask = Select_mask; + +#else /* VMS */ + XFD_COPYSET(&Select_mask, &Tselect_mask); + if (Select(max_plus1, &Tselect_mask, NULL, NULL, NULL) < 0) { + if (errno != EINTR) + SysError(ERROR_TSELECT); + continue; + } +#endif /* VMS */ + } +#ifdef VMS + if (Tselect_mask & X_mask) { + xevents(); + if (VTbuffer->update != update) + goto again; + } +#else /* VMS */ + if (FD_ISSET(ConnectionNumber(XtDisplay(tw)), &Tselect_mask)) { + xevents(); + if (VTbuffer->update != update) + goto again; + } +#endif /* VMS */ + } + if (!Ttoggled && curstate == Talptable) { + TCursorToggle(tw, TOGGLE); + Ttoggled = True; + } + } + tek = TekRecord; + if (tek->count >= TEK_LINK_BLOCK_SIZE + || tek->fontsize != tekscr->cur.fontsize) { + if ((TekRecord = tek->next = CastMalloc(TekLink)) == 0) { + Panic("Tinput: malloc error (%d)\n", errno); + } else { + tek = tek->next; + tek->next = (TekLink *) 0; + tek->fontsize = (unsigned short) tekscr->cur.fontsize; + tek->count = 0; + tek->ptr = tek->data; + } + } + tek->count++; + + (void) morePtyData(screen, VTbuffer); + return (IChar) (*tek->ptr++ = (char) nextPtyData(screen, VTbuffer)); +} + +static void +TekClear(TekWidget tw) +{ + TekScreen *tekscr = TekScreenOf(tw); + + if (TWindow(tekscr)) + XClearWindow(XtDisplay(tw), TWindow(tekscr)); +} + +/* this should become the Tek Widget's Resize proc */ +static void +TekConfigure(Widget w) +{ + TekWidget tw = getTekWidget(w); + if (tw != 0) { + XtermWidget xw = term; + TekScreen *tekscr = TekScreenOf(tw); + TScreen *screen = TScreenOf(xw); + int border = 2 * screen->border; + double d; + + TekClear(tw); + TWidth(tekscr) = w->core.width - border; + THeight(tekscr) = w->core.height - border; + TekScale(tekscr) = (double) TWidth(tekscr) / TEKWIDTH; + if ((d = (double) THeight(tekscr) / (TEKHEIGHT + TEKTOPPAD + TEKBOTTOMPAD)) + < TekScale(tekscr)) + TekScale(tekscr) = d; + TFullWidth(tekscr) = w->core.width; + TFullHeight(tekscr) = w->core.height; + } +} + +/*ARGSUSED*/ +void +TekExpose(Widget w, + XEvent * event GCC_UNUSED, + Region region GCC_UNUSED) +{ + TekWidget tw = getTekWidget(w); + if (tw != 0) { + TekScreen *tekscr = TekScreenOf(tw); + + TRACE(("TekExpose {{\n")); + +#ifdef lint + region = region; +#endif + if (!Ttoggled) + TCursorToggle(tw, CLEAR); + Ttoggled = True; + Tpushback = Tpushb; + tekscr->cur_X = 0; + tekscr->cur_Y = TEKHOME; + tekscr->cur = tekscr->page; + TekSetFontSize(tw, False, tekscr->cur.fontsize); + tekscr->margin = MARGIN1; + if (tekscr->TekGIN) { + tekscr->TekGIN = NULL; + TekGINoff(tw); + } + tekRefreshList = &Tek0; + rptr = tekRefreshList->data; + rcnt = tekRefreshList->count; + Tparsestate = curstate = Talptable; + TRACE(("TekExpose resets data to replay %d bytes\n", rcnt)); + first_map_occurred(); + if (!tekscr->waitrefresh) + TekRefresh(tw); + TRACE(("}} TekExpose\n")); + } +} + +void +TekRefresh(TekWidget tw) +{ + if (tw != 0) { + XtermWidget xw = term; + TScreen *screen = TScreenOf(xw); + TekScreen *tekscr = TekScreenOf(tw); + static Cursor wait_cursor = None; + + if (wait_cursor == None) + wait_cursor = make_colored_cursor(XC_watch, + T_COLOR(screen, MOUSE_FG), + T_COLOR(screen, MOUSE_BG)); + XDefineCursor(XtDisplay(tw), TWindow(tekscr), wait_cursor); + XFlush(XtDisplay(tw)); + if (!setjmp(Tekjump)) + Tekparse(tw); + XDefineCursor(XtDisplay(tw), TWindow(tekscr), + (tekscr->TekGIN && GINcursor) ? GINcursor : tekscr->arrow); + } +} + +void +TekRepaint(TekWidget tw) +{ + TRACE(("TekRepaint\n")); + TekClear(tw); + TekExpose((Widget) tw, (XEvent *) NULL, (Region) NULL); +} + +static void +TekPage(TekWidget tw) +{ + TekScreen *tekscr = TekScreenOf(tw); + TekLink *tek; + + TekClear(tw); + tekscr->cur_X = 0; + tekscr->cur_Y = TEKHOME; + tekscr->margin = MARGIN1; + tekscr->page = tekscr->cur; + if (tekscr->TekGIN) + TekGINoff(tw); + tek = TekRecord = &Tek0; + tek->fontsize = (unsigned short) tekscr->cur.fontsize; + tek->count = 0; + tek->ptr = tek->data; + tek = tek->next; + if (tek) + do { + TekLink *tek2 = tek->next; + + free(tek); + tek = tek2; + } while (tek); + TekRecord->next = (TekLink *) 0; + tekRefreshList = (TekLink *) 0; + Ttoggled = True; + Tparsestate = curstate = Talptable; /* Tek Alpha mode */ +} + +#define EXTRABITS 017 +#define FIVEBITS 037 +#define HIBITS (FIVEBITS << SHIFTHI) +#define LOBITS (FIVEBITS << SHIFTLO) +#define SHIFTHI 7 +#define SHIFTLO 2 +#define TWOBITS 03 + +static int +getpoint(TekWidget tw) +{ + int c, x, y, e, lo_y = 0; + TekScreen *tekscr = TekScreenOf(tw); + + x = tekscr->cur.x; + y = tekscr->cur.y; + for (;;) { + if ((c = (int) input()) < ' ') { /* control character */ + unput(c); + return (0); + } + if (c < '@') { /* Hi X or Hi Y */ + if (lo_y) { /* seen a Lo Y, so this must be Hi X */ + x &= ~HIBITS; + x |= (c & FIVEBITS) << SHIFTHI; + continue; + } + /* else Hi Y */ + y &= ~HIBITS; + y |= (c & FIVEBITS) << SHIFTHI; + continue; + } + if (c < '`') { /* Lo X */ + x &= ~LOBITS; + x |= (c & FIVEBITS) << SHIFTLO; + tekscr->cur.x = x; + tekscr->cur.y = y; + return (1); /* OK */ + } + /* else Lo Y */ + if (lo_y) { /* seen a Lo Y, so other must be extra bits */ + e = (y >> SHIFTLO) & EXTRABITS; + x &= ~TWOBITS; + x |= e & TWOBITS; + y &= ~TWOBITS; + y |= (e >> SHIFTLO) & TWOBITS; + } + y &= ~LOBITS; + y |= (c & FIVEBITS) << SHIFTLO; + lo_y++; + } +} + +static void +TCursorBack(TekWidget tw) +{ + TekScreen *tekscr = TekScreenOf(tw); + struct Tek_Char *t; + int x, l; + + x = (tekscr->cur_X -= + (t = &TekChar[tekscr->cur.fontsize])->hsize + ); + + if (((tekscr->margin == MARGIN1) && (x < 0)) + || ((tekscr->margin == MARGIN2) && (x < TEKWIDTH / 2))) { + if ((l = (tekscr->cur_Y + (t->vsize - 1)) / t->vsize + 1) >= + t->nlines) { + tekscr->margin = !tekscr->margin; + l = 0; + } + tekscr->cur_Y = l * t->vsize; + tekscr->cur_X = (t->charsperline - 1) * t->hsize; + } +} + +static void +TCursorForward(TekWidget tw) +{ + TekScreen *tekscr = TekScreenOf(tw); + struct Tek_Char *t; + int l; + + if ((tekscr->cur_X += + (t = &TekChar[tekscr->cur.fontsize])->hsize + ) > TEKWIDTH + ) { + if ((l = tekscr->cur_Y / t->vsize - 1) < 0) { + tekscr->margin = !tekscr->margin; + l = t->nlines - 1; + } + tekscr->cur_Y = l * t->vsize; + tekscr->cur_X = tekscr->margin == MARGIN1 ? 0 : TEKWIDTH / 2; + } +} + +static void +TCursorUp(TekWidget tw) +{ + TekScreen *tekscr = TekScreenOf(tw); + struct Tek_Char *t; + int l; + + t = &TekChar[tekscr->cur.fontsize]; + + if ((l = (tekscr->cur_Y + (t->vsize - 1)) / t->vsize + 1) >= t->nlines) { + l = 0; + if ((tekscr->margin = !tekscr->margin) != MARGIN1) { + if (tekscr->cur_X < TEKWIDTH / 2) + tekscr->cur_X += TEKWIDTH / 2; + } else if (tekscr->cur_X >= TEKWIDTH / 2) + tekscr->cur_X -= TEKWIDTH / 2; + } + tekscr->cur_Y = l * t->vsize; +} + +static void +TCursorDown(TekWidget tw) +{ + TekScreen *tekscr = TekScreenOf(tw); + struct Tek_Char *t; + int l; + + t = &TekChar[tekscr->cur.fontsize]; + + if ((l = tekscr->cur_Y / t->vsize - 1) < 0) { + l = t->nlines - 1; + if ((tekscr->margin = !tekscr->margin) != MARGIN1) { + if (tekscr->cur_X < TEKWIDTH / 2) + tekscr->cur_X += TEKWIDTH / 2; + } else if (tekscr->cur_X >= TEKWIDTH / 2) + tekscr->cur_X -= TEKWIDTH / 2; + } + tekscr->cur_Y = l * t->vsize; +} + +static void +AddToDraw(TekWidget tw, int x1, int y1, int x2, int y2) +{ + XtermWidget xw = term; + TScreen *screen = TScreenOf(xw); + TekScreen *tekscr = TekScreenOf(tw); + XSegment *lp; + + TRACE(("AddToDraw (%d,%d) (%d,%d)\n", x1, y1, x2, y2)); + if (nplot >= MAX_PTS) { + TekFlush(tw); + } + lp = line_pt++; + lp->x1 = (short) (x1 * TekScale(tekscr) + screen->border); + lp->y1 = (short) ((TEKHEIGHT + TEKTOPPAD - y1) * TekScale(tekscr) + + screen->border); + lp->x2 = (short) (x2 * TekScale(tekscr) + screen->border); + lp->y2 = (short) ((TEKHEIGHT + TEKTOPPAD - y2) * TekScale(tekscr) + + screen->border); + nplot++; + TRACE(("...AddToDraw %d points\n", nplot)); +} + +static void +TekDraw(TekWidget tw, int x, int y) +{ + TekScreen *tekscr = TekScreenOf(tw); + + if (nplot == 0 || T_lastx != tekscr->cur_X || T_lasty != tekscr->cur_Y) { + /* + * We flush on each unconnected line segment if the line + * type is not solid. This solves a bug in X when drawing + * points while the line type is not solid. + */ + if (nplot > 0 && tekscr->cur.linetype != SOLIDLINE) + TekFlush(tw); + } + AddToDraw(tw, tekscr->cur_X, tekscr->cur_Y, x, y); + T_lastx = tekscr->cur_X = x; + T_lasty = tekscr->cur_Y = y; +} + +static void +TekFlush(TekWidget tw) +{ + TekScreen *tekscr = TekScreenOf(tw); + + TRACE(("TekFlush\n")); + XDrawSegments(XtDisplay(tw), TWindow(tekscr), + ((tekscr->cur.linetype == SOLIDLINE) + ? tekscr->TnormalGC + : tekscr->linepat[tekscr->cur.linetype - 1]), + Tline, nplot); + nplot = 0; + line_pt = Tline; +} + +void +TekGINoff(TekWidget tw) +{ + TekScreen *tekscr = TekScreenOf(tw); + + TRACE(("TekGINoff\n")); + XDefineCursor(XtDisplay(tw), TWindow(tekscr), tekscr->arrow); + if (GINcursor) + XFreeCursor(XtDisplay(tw), GINcursor); + if (tekscr->TekGIN) { + *tekscr->TekGIN = ANSI_CAN; /* modify recording */ + tekscr->TekGIN = NULL; + } +} + +void +TekEnqMouse(TekWidget tw, int c) /* character pressed */ +{ + XtermWidget xw = term; + TScreen *screen = TScreenOf(xw); + TekScreen *tekscr = TekScreenOf(tw); + int mousex, mousey, rootx, rooty; + unsigned int mask; /* XQueryPointer */ + Window root, subw; + + TRACE(("TekEnqMouse\n")); + XQueryPointer( + XtDisplay(tw), TWindow(tekscr), + &root, &subw, + &rootx, &rooty, + &mousex, &mousey, + &mask); + if ((mousex = (int) ((mousex - screen->border) / TekScale(tekscr))) < 0) + mousex = 0; + else if (mousex >= TEKWIDTH) + mousex = TEKWIDTH - 1; + if ((mousey = (int) (TEKHEIGHT + TEKTOPPAD - (mousey - screen->border) / + TekScale(tekscr))) < 0) + mousey = 0; + else if (mousey >= TEKHEIGHT) + mousey = TEKHEIGHT - 1; + TekEnq(tw, (unsigned) c, mousex, mousey); +} + +static void +TekEnq(TekWidget tw, + unsigned status, + int x, + int y) +{ + XtermWidget xw = term; + TScreen *screen = TScreenOf(xw); + TekScreen *tekscr = TekScreenOf(tw); + Char cplot[7]; + int len = 5; + int adj = (status != 0) ? 0 : 1; + + TRACE(("TekEnq\n")); + cplot[0] = (Char) status; + /* Translate x and y to Tektronix code */ + cplot[1] = (Char) (040 | ((x >> SHIFTHI) & FIVEBITS)); + cplot[2] = (Char) (040 | ((x >> SHIFTLO) & FIVEBITS)); + cplot[3] = (Char) (040 | ((y >> SHIFTHI) & FIVEBITS)); + cplot[4] = (Char) (040 | ((y >> SHIFTLO) & FIVEBITS)); + + if (tekscr->gin_terminator != GIN_TERM_NONE) + cplot[len++] = '\r'; + if (tekscr->gin_terminator == GIN_TERM_EOT) + cplot[len++] = '\004'; +#ifdef VMS + tt_write(cplot + adj, len - adj); +#else /* VMS */ + v_write(screen->respond, cplot + adj, (unsigned) (len - adj)); +#endif /* VMS */ +} + +void +TekRun(void) +{ + XtermWidget xw = term; + + assert(xw != 0); + if (tekWidget == 0) { + TekInit(); + } + if (tekWidget != 0) { + TRACE(("TekRun ...\n")); + + if (!TEK4014_SHOWN(xw)) { + set_tek_visibility(True); + } + update_vttekmode(); + update_vtshow(); + update_tekshow(); + set_tekhide_sensitivity(); + + Tpushback = Tpushb; + Ttoggled = True; + if (!setjmp(Tekend)) + Tekparse(tekWidget); + if (!Ttoggled) { + TCursorToggle(tekWidget, TOGGLE); + Ttoggled = True; + } + TEK4014_ACTIVE(xw) = False; + } else { + TEK4014_ACTIVE(xw) = False; + if (VWindow(TScreenOf(xw)) == 0) { + Exit(ERROR_TINIT); + } + } +} + +#define DOTTED_LENGTH 2 +#define DOT_DASHED_LENGTH 4 +#define SHORT_DASHED_LENGTH 2 +#define LONG_DASHED_LENGTH 2 + +static int dash_length[TEKNUMLINES] = +{ + DOTTED_LENGTH, + DOT_DASHED_LENGTH, + SHORT_DASHED_LENGTH, + LONG_DASHED_LENGTH, +}; + +static unsigned char dotted[DOTTED_LENGTH] = +{3, 1}; +static unsigned char dot_dashed[DOT_DASHED_LENGTH] = +{3, 4, 3, 1}; +static unsigned char short_dashed[SHORT_DASHED_LENGTH] = +{4, 4}; +static unsigned char long_dashed[LONG_DASHED_LENGTH] = +{4, 7}; + +static unsigned char *dashes[TEKNUMLINES] = +{ + dotted, + dot_dashed, + short_dashed, + long_dashed, +}; + +/* + * The following is called to create the tekWidget + */ + +static void +TekInitialize(Widget wrequest, + Widget new_arg, + ArgList args GCC_UNUSED, + Cardinal *num_args GCC_UNUSED) +{ + TekWidget request = (TekWidget) wrequest; + TekWidget wnew = (TekWidget) new_arg; + Widget tekparent = SHELL_OF(wnew); +#ifndef NO_ACTIVE_ICON + TekScreen *screen = TekScreenOf((TekWidget) wnew); +#endif + int n; + + TRACE(("TekInitialize\n")); + + /* look for focus related events on the shell, because we need + * to care about the shell's border being part of our focus. + */ + XtAddEventHandler(tekparent, EnterWindowMask, False, + HandleEnterWindow, (Opaque) 0); + XtAddEventHandler(tekparent, LeaveWindowMask, False, + HandleLeaveWindow, (Opaque) 0); + XtAddEventHandler(tekparent, FocusChangeMask, False, + HandleFocusChange, (Opaque) 0); + XtAddEventHandler(new_arg, PropertyChangeMask, False, + HandleBellPropertyChange, (Opaque) 0); + +#ifndef NO_ACTIVE_ICON + screen->whichTwin = &(screen->fullTwin); +#endif /* NO_ACTIVE_ICON */ + + for (n = 0; n < TEKNUMFONTS; ++n) { + wnew->tek.Tfont[n] = request->tek.Tfont[n]; + } + + init_Sres(tek.initial_font); + init_Sres(tek.gin_terminator_str); +#if OPT_TOOLBAR + init_Ires(tek.tb_info.menu_height); + wnew->tek.tb_info.menu_bar = request->tek.tb_info.menu_bar; +#endif +} + +static void +TekRealize(Widget gw, + XtValueMask * valuemaskp, + XSetWindowAttributes * values) +{ + XtermWidget xw = term; + TScreen *screen = TScreenOf(xw); + TekWidget tw = (TekWidget) gw; + TekScreen *tekscr = TekScreenOf(tw); + int i; + TekLink *tek; + double d; + int border = 2 * screen->border; + int pr; + XGCValues gcv; + int winX, winY; + unsigned width, height; + char Tdefault[32]; + unsigned long TEKgcFontMask; + + TRACE(("TekRealize\n")); + memset(tekscr, 0, sizeof(*tekscr)); + +#ifndef NO_ACTIVE_ICON + tekscr->whichTwin = &tekscr->fullTwin; +#endif /* NO_ACTIVE_ICON */ + + BorderPixel(tw) = BorderPixel(xw); + + tekscr->arrow = make_colored_cursor(XC_left_ptr, + T_COLOR(screen, MOUSE_FG), + T_COLOR(screen, MOUSE_BG)); + + for (i = 0; i < TEKNUMFONTS; i++) { + if (!tw->tek.Tfont[i]) { + tw->tek.Tfont[i] = XQueryFont(XtDisplay(tw), DefaultGCID); + } + TRACE(("Tfont[%d] %dx%d\n", + i, + tw->tek.Tfont[i]->ascent + + tw->tek.Tfont[i]->descent, + tw->tek.Tfont[i]->max_bounds.width)); + tw->tek.tobaseline[i] = tw->tek.Tfont[i]->ascent; + } + + if (!TekPtyData()) + return; + + if (xw->misc.T_geometry == NULL) { + int defwidth, defheight; + + if (xw->misc.tekSmall) { + defwidth = TEKMINWIDTH; + defheight = TEKMINHEIGHT; + } else { + defwidth = TEKDEFWIDTH; + defheight = TEKDEFHEIGHT; + } + sprintf(Tdefault, "=%dx%d", defwidth + border, defheight + border); + xw->misc.T_geometry = Tdefault; + } + + winX = 1; + winY = 1; + width = (unsigned) (TEKDEFWIDTH + border); + height = (unsigned) (TEKDEFHEIGHT + border); + + TRACE(("parsing T_geometry %s\n", NonNull(xw->misc.T_geometry))); + pr = XParseGeometry(xw->misc.T_geometry, + &winX, + &winY, + &width, + &height); + TRACE(("... position %d,%d size %dx%d\n", winY, winX, height, width)); + if ((pr & XValue) && (pr & XNegative)) + winX += DisplayWidth(XtDisplay(tw), DefaultScreen(XtDisplay(tw))) + - (int) width - (BorderWidth(SHELL_OF(xw)) * 2); + if ((pr & YValue) && (pr & YNegative)) + winY += DisplayHeight(XtDisplay(tw), DefaultScreen(XtDisplay(tw))) + - (int) height - (BorderWidth(SHELL_OF(xw)) * 2); + + /* set up size hints */ + tw->hints.min_width = TEKMINWIDTH + border; + tw->hints.min_height = TEKMINHEIGHT + border; + tw->hints.width_inc = 1; + tw->hints.height_inc = 1; + tw->hints.flags = PMinSize | PResizeInc; + tw->hints.x = winX; + tw->hints.y = winY; + if ((XValue & pr) || (YValue & pr)) { + tw->hints.flags |= USSize | USPosition; + tw->hints.flags |= PWinGravity; + switch (pr & (XNegative | YNegative)) { + case 0: + tw->hints.win_gravity = NorthWestGravity; + break; + case XNegative: + tw->hints.win_gravity = NorthEastGravity; + break; + case YNegative: + tw->hints.win_gravity = SouthWestGravity; + break; + default: + tw->hints.win_gravity = SouthEastGravity; + break; + } + } else { + /* set a default size, but do *not* set position */ + tw->hints.flags |= PSize; + } + tw->hints.width = (int) width; + tw->hints.height = (int) height; + if ((WidthValue & pr) || (HeightValue & pr)) + tw->hints.flags |= USSize; + else + tw->hints.flags |= PSize; + + (void) REQ_RESIZE((Widget) tw, + (Dimension) width, (Dimension) height, + &tw->core.width, &tw->core.height); + + /* XXX This is bogus. We are parsing geometries too late. This + * is information that the shell widget ought to have before we get + * realized, so that it can do the right thing. + */ + if (tw->hints.flags & USPosition) + XMoveWindow(XtDisplay(tw), TShellWindow, tw->hints.x, tw->hints.y); + + XSetWMNormalHints(XtDisplay(tw), TShellWindow, &tw->hints); + XFlush(XtDisplay(tw)); /* get it out to window manager */ + + values->win_gravity = NorthWestGravity; + values->background_pixel = T_COLOR(screen, TEK_BG); + + XtWindow(tw) = TWindow(tekscr) = + XCreateWindow(XtDisplay(tw), + VShellWindow(tw), + tw->core.x, tw->core.y, + tw->core.width, tw->core.height, + BorderWidth(tw), + (int) tw->core.depth, + InputOutput, CopyFromParent, + ((*valuemaskp) | CWBackPixel | CWWinGravity), + values); + + TFullWidth(tekscr) = (Dimension) width; + TFullHeight(tekscr) = (Dimension) height; + TWidth(tekscr) = (int) width - border; + THeight(tekscr) = (int) height - border; + TekScale(tekscr) = (double) TWidth(tekscr) / TEKWIDTH; + if ((d = (double) THeight(tekscr) / (TEKHEIGHT + TEKTOPPAD + + TEKBOTTOMPAD)) < TekScale(tekscr)) + TekScale(tekscr) = d; + + tekscr->cur.fontsize = TEK_FONT_LARGE; + if (tw->tek.initial_font) { + int result = TekGetFontSize(tw->tek.initial_font); + if (result >= 0) + tekscr->cur.fontsize = result; + } +#define TestGIN(s) XmuCompareISOLatin1(tw->tek.gin_terminator_str, s) + + if (TestGIN(GIN_TERM_NONE_STR) == 0) + tekscr->gin_terminator = GIN_TERM_NONE; + else if (TestGIN(GIN_TERM_CR_STR) == 0) + tekscr->gin_terminator = GIN_TERM_CR; + else if (TestGIN(GIN_TERM_EOT_STR) == 0) + tekscr->gin_terminator = GIN_TERM_EOT; + else + xtermWarning("illegal GIN terminator setting \"%s\"\n", + tw->tek.gin_terminator_str); + + gcv.graphics_exposures = True; /* default */ + gcv.font = tw->tek.Tfont[tekscr->cur.fontsize]->fid; + gcv.foreground = T_COLOR(screen, TEK_FG); + gcv.background = T_COLOR(screen, TEK_BG); + + /* if font wasn't successfully opened, then gcv.font will contain + the Default GC's ID, meaning that we must use the server default font. + */ + TEKgcFontMask = (unsigned long) ((gcv.font == DefaultGCID) ? 0 : GCFont); + tekscr->TnormalGC = XCreateGC(XtDisplay(tw), TWindow(tekscr), + (TEKgcFontMask | GCGraphicsExposures | + GCForeground | GCBackground), + &gcv); + + gcv.function = GXinvert; + gcv.plane_mask = (T_COLOR(screen, TEK_BG) ^ + T_COLOR(screen, TEK_CURSOR)); + gcv.join_style = JoinMiter; /* default */ + gcv.line_width = 1; + tekscr->TcursorGC = XCreateGC(XtDisplay(tw), TWindow(tekscr), + (GCFunction | GCPlaneMask), &gcv); + + gcv.foreground = T_COLOR(screen, TEK_FG); + gcv.line_style = LineOnOffDash; + gcv.line_width = 0; + for (i = 0; i < TEKNUMLINES; i++) { + tekscr->linepat[i] = XCreateGC(XtDisplay(tw), TWindow(tekscr), + (GCForeground | GCLineStyle), &gcv); + XSetDashes(XtDisplay(tw), tekscr->linepat[i], 0, + (char *) dashes[i], dash_length[i]); + } + + TekBackground(tw, screen); + + tekscr->margin = MARGIN1; /* Margin 1 */ + tekscr->TekGIN = False; /* GIN off */ + + XDefineCursor(XtDisplay(tw), TWindow(tekscr), tekscr->arrow); + + { /* there's gotta be a better way... */ + static Arg args[] = + { + {XtNtitle, (XtArgVal) NULL}, + {XtNiconName, (XtArgVal) NULL}, + }; + char *icon_name, *title, *tek_icon_name, *tek_title; + + args[0].value = (XtArgVal) & icon_name; + args[1].value = (XtArgVal) & title; + XtGetValues(SHELL_OF(tw), args, 2); + tek_icon_name = XtMalloc((Cardinal) strlen(icon_name) + 7); + strcpy(tek_icon_name, icon_name); + strcat(tek_icon_name, "(Tek)"); + tek_title = XtMalloc((Cardinal) strlen(title) + 7); + strcpy(tek_title, title); + strcat(tek_title, "(Tek)"); + args[0].value = (XtArgVal) tek_icon_name; + args[1].value = (XtArgVal) tek_title; + XtSetValues(SHELL_OF(tw), args, 2); + XtFree(tek_icon_name); + XtFree(tek_title); + } + + tek = TekRecord = &Tek0; + tek->next = (TekLink *) 0; + tek->fontsize = (unsigned short) tekscr->cur.fontsize; + tek->count = 0; + tek->ptr = tek->data; + Tpushback = Tpushb; + tekscr->cur_X = 0; + tekscr->cur_Y = TEKHOME; + line_pt = Tline; + Ttoggled = True; + tekscr->page = tekscr->cur; + return; +} + +int +TekGetFontSize(const char *param) +{ + int result; + + if (XmuCompareISOLatin1(param, "l") == 0 || + XmuCompareISOLatin1(param, "large") == 0) + result = TEK_FONT_LARGE; + else if (XmuCompareISOLatin1(param, "2") == 0 || + XmuCompareISOLatin1(param, "two") == 0) + result = TEK_FONT_2; + else if (XmuCompareISOLatin1(param, "3") == 0 || + XmuCompareISOLatin1(param, "three") == 0) + result = TEK_FONT_3; + else if (XmuCompareISOLatin1(param, "s") == 0 || + XmuCompareISOLatin1(param, "small") == 0) + result = TEK_FONT_SMALL; + else + result = -1; + + return result; +} + +void +TekSetFontSize(TekWidget tw, Bool fromMenu, int newitem) +{ + if (tw != 0) { + XtermWidget xw = term; + TekScreen *tekscr = TekScreenOf(tw); + int oldsize = tekscr->cur.fontsize; + int newsize = MI2FS(newitem); + Font fid; + + TRACE(("TekSetFontSize(%d) size %d ->%d\n", newitem, oldsize, newsize)); + if (newsize < 0 || newsize >= TEKNUMFONTS) { + Bell(xw, XkbBI_MinorError, 0); + } else if (oldsize != newsize) { + if (!Ttoggled) + TCursorToggle(tw, TOGGLE); + set_tekfont_menu_item(oldsize, False); + + tekscr->cur.fontsize = newsize; + if (fromMenu) + tekscr->page.fontsize = newsize; + + fid = tw->tek.Tfont[newsize]->fid; + if (fid == DefaultGCID) { + /* we didn't succeed in opening a real font + for this size. Instead, use server default. */ + XCopyGC(XtDisplay(tw), + DefaultGC(XtDisplay(tw), DefaultScreen(XtDisplay(tw))), + GCFont, tekscr->TnormalGC); + } else { + XSetFont(XtDisplay(tw), tekscr->TnormalGC, fid); + } + + set_tekfont_menu_item(newsize, True); + if (!Ttoggled) + TCursorToggle(tw, TOGGLE); + + if (fromMenu) { + /* we'll get an exposure event after changing fontsize, so we + * have to clear the screen to avoid painting over the previous + * text. + */ + TekClear(tw); + } + } + } +} + +void +ChangeTekColors(TekWidget tw, TScreen * screen, ScrnColors * pNew) +{ + TekScreen *tekscr = TekScreenOf(tw); + int i; + XGCValues gcv; + + if (COLOR_DEFINED(pNew, TEK_FG)) { + T_COLOR(screen, TEK_FG) = COLOR_VALUE(pNew, TEK_FG); + TRACE(("... TEK_FG: %#lx\n", T_COLOR(screen, TEK_FG))); + } + if (COLOR_DEFINED(pNew, TEK_BG)) { + T_COLOR(screen, TEK_BG) = COLOR_VALUE(pNew, TEK_BG); + TRACE(("... TEK_BG: %#lx\n", T_COLOR(screen, TEK_BG))); + } + if (COLOR_DEFINED(pNew, TEK_CURSOR)) { + T_COLOR(screen, TEK_CURSOR) = COLOR_VALUE(pNew, TEK_CURSOR); + TRACE(("... TEK_CURSOR: %#lx\n", T_COLOR(screen, TEK_CURSOR))); + } else { + T_COLOR(screen, TEK_CURSOR) = T_COLOR(screen, TEK_FG); + TRACE(("... TEK_CURSOR: %#lx\n", T_COLOR(screen, TEK_CURSOR))); + } + + if (tw) { + XSetForeground(XtDisplay(tw), tekscr->TnormalGC, + T_COLOR(screen, TEK_FG)); + XSetBackground(XtDisplay(tw), tekscr->TnormalGC, + T_COLOR(screen, TEK_BG)); + if (BorderPixel(tw) == T_COLOR(screen, TEK_BG)) { + BorderPixel(tw) = T_COLOR(screen, TEK_FG); + BorderPixel(XtParent(tw)) = T_COLOR(screen, TEK_FG); + if (XtWindow(XtParent(tw))) + XSetWindowBorder(XtDisplay(tw), + XtWindow(XtParent(tw)), + BorderPixel(tw)); + } + + for (i = 0; i < TEKNUMLINES; i++) { + XSetForeground(XtDisplay(tw), tekscr->linepat[i], + T_COLOR(screen, TEK_FG)); + } + + gcv.plane_mask = (T_COLOR(screen, TEK_BG) ^ + T_COLOR(screen, TEK_CURSOR)); + XChangeGC(XtDisplay(tw), tekscr->TcursorGC, GCPlaneMask, &gcv); + TekBackground(tw, screen); + } + return; +} + +void +TekReverseVideo(TekWidget tw) +{ + XtermWidget xw = term; + TScreen *screen = TScreenOf(xw); + TekScreen *tekscr = TekScreenOf(tw); + int i; + Pixel tmp; + XGCValues gcv; + + EXCHANGE(T_COLOR(screen, TEK_FG), T_COLOR(screen, TEK_BG), tmp); + + T_COLOR(screen, TEK_CURSOR) = T_COLOR(screen, TEK_FG); + + if (tw) { + XSetForeground(XtDisplay(tw), tekscr->TnormalGC, T_COLOR(screen, TEK_FG)); + XSetBackground(XtDisplay(tw), tekscr->TnormalGC, T_COLOR(screen, TEK_BG)); + + if (BorderPixel(tw) == T_COLOR(screen, TEK_BG)) { + BorderPixel(tw) = T_COLOR(screen, TEK_FG); + BorderPixel(XtParent(tw)) = T_COLOR(screen, TEK_FG); + if (XtWindow(XtParent(tw))) + XSetWindowBorder(XtDisplay(tw), + XtWindow(XtParent(tw)), + BorderPixel(tw)); + } + + for (i = 0; i < TEKNUMLINES; i++) { + XSetForeground(XtDisplay(tw), tekscr->linepat[i], + T_COLOR(screen, TEK_FG)); + } + + gcv.plane_mask = (T_COLOR(screen, TEK_BG) ^ + T_COLOR(screen, TEK_CURSOR)); + XChangeGC(XtDisplay(tw), tekscr->TcursorGC, GCPlaneMask, &gcv); + TekBackground(tw, screen); + } +} + +static void +TekBackground(TekWidget tw, TScreen * screen) +{ + TekScreen *tekscr = TekScreenOf(tw); + + if (TWindow(tekscr)) + XSetWindowBackground(XtDisplay(tw), TWindow(tekscr), + T_COLOR(screen, TEK_BG)); +} + +/* + * Toggles cursor on or off at cursor position in screen. + */ +void +TCursorToggle(TekWidget tw, int toggle) /* TOGGLE or CLEAR */ +{ + XtermWidget xw = term; + TekScreen *tekscr = TekScreenOf(tw); + TScreen *screen = TScreenOf(xw); + int c, x, y; + unsigned int cellwidth, cellheight; + + if (!TEK4014_SHOWN(xw)) + return; + + TRACE(("TCursorToggle %s\n", (toggle == TOGGLE) ? "toggle" : "clear")); + c = tekscr->cur.fontsize; + cellwidth = (unsigned) tw->tek.Tfont[c]->max_bounds.width; + cellheight = (unsigned) (tw->tek.Tfont[c]->ascent + + tw->tek.Tfont[c]->descent); + + x = (int) ((tekscr->cur_X * TekScale(tekscr)) + screen->border); + y = (int) (((TEKHEIGHT + TEKTOPPAD - tekscr->cur_Y) * TekScale(tekscr)) + + screen->border - tw->tek.tobaseline[c]); + + if (toggle == TOGGLE) { + if (screen->select || screen->always_highlight) + XFillRectangle(XtDisplay(tw), TWindow(tekscr), + tekscr->TcursorGC, x, y, + cellwidth, cellheight); + else { /* fix to use different GC! */ + XDrawRectangle(XtDisplay(tw), TWindow(tekscr), + tekscr->TcursorGC, x, y, + cellwidth - 1, cellheight - 1); + } + } else { + /* Clear the entire rectangle, even though we may only + * have drawn an outline. This fits with our refresh + * scheme of redrawing the entire window on any expose + * event and is easier than trying to figure out exactly + * which part of the cursor needs to be erased. + */ + XClearArea(XtDisplay(tw), TWindow(tekscr), x, y, + cellwidth, cellheight, False); + } +} + +void +TekSimulatePageButton(TekWidget tw, Bool reset) +{ + if (tw != 0) { + TekScreen *tekscr = TekScreenOf(tw); + + if (reset) { + memset(&tekscr->cur, 0, sizeof tekscr->cur); + } + tekRefreshList = (TekLink *) 0; + TekPage(tw); + tekscr->cur_X = 0; + tekscr->cur_Y = TEKHOME; + } +} + +/* write copy of screen to a file */ + +void +TekCopy(TekWidget tw) +{ + if (tw != 0) { + XtermWidget xw = term; + TekScreen *tekscr = TekScreenOf(tw); + TScreen *screen = TScreenOf(xw); + + TekLink *Tp; + char buf[TIMESTAMP_LEN + 10]; + char initbuf[5]; + int tekcopyfd; + + timestamp_filename(buf, "COPY"); + if (access(buf, F_OK) >= 0 + && access(buf, W_OK) < 0) { + Bell(xw, XkbBI_MinorError, 0); + return; + } +#ifndef VMS + if (access(".", W_OK) < 0) { /* can't write in directory */ + Bell(xw, XkbBI_MinorError, 0); + return; + } +#endif + + tekcopyfd = open_userfile(screen->uid, screen->gid, buf, False); + if (tekcopyfd >= 0) { + sprintf(initbuf, "%c%c%c%c", + ANSI_ESC, (char) (tekscr->page.fontsize + '8'), + ANSI_ESC, (char) (tekscr->page.linetype + '`')); + IGNORE_RC(write(tekcopyfd, initbuf, (size_t) 4)); + Tp = &Tek0; + do { + IGNORE_RC(write(tekcopyfd, Tp->data, (size_t) Tp->count)); + Tp = Tp->next; + } while (Tp); + close(tekcopyfd); + } + } +} + +/*ARGSUSED*/ +void +HandleGINInput(Widget w, + XEvent * event GCC_UNUSED, + String * param_list, + Cardinal *nparamsp) +{ + XtermWidget xw = term; + TekWidget tw = getTekWidget(w); + + if (tw != 0) { + TekScreen *tekscr = TekScreenOf(tw); + + if (tekscr->TekGIN && *nparamsp == 1) { + int c = param_list[0][0]; + switch (c) { + case 'l': + case 'm': + case 'r': + case 'L': + case 'M': + case 'R': + break; + default: + Bell(xw, XkbBI_MinorError, 0); /* let them know they goofed */ + c = 'l'; /* provide a default */ + } + TekEnqMouse(tw, c | 0x80); + TekGINoff(tw); + } else { + Bell(xw, XkbBI_MinorError, 0); + } + } +} + +/* + * Check if the current widget, or any parent, is the VT100 "xterm" widget. + */ +TekWidget +getTekWidget(Widget w) +{ + TekWidget xw; + + if (w == 0) { + xw = (TekWidget) CURRENT_EMU(); + if (!IsTekWidget(xw)) { + xw = 0; + } + } else if (IsTekWidget(w)) { + xw = (TekWidget) w; + } else { + xw = getTekWidget(XtParent(w)); + } + TRACE2(("getTekWidget %p -> %p\n", w, xw)); + return xw; +} |