Home | History | Annotate | Line # | Download | only in dist
      1 /* $XTermId: Tekproc.c,v 1.254 2024/12/01 20:21:19 tom Exp $ */
      2 
      3 /*
      4  * Copyright 2001-2022,2024 by Thomas E. Dickey
      5  *
      6  *                         All Rights Reserved
      7  *
      8  * Permission is hereby granted, free of charge, to any person obtaining a
      9  * copy of this software and associated documentation files (the
     10  * "Software"), to deal in the Software without restriction, including
     11  * without limitation the rights to use, copy, modify, merge, publish,
     12  * distribute, sublicense, and/or sell copies of the Software, and to
     13  * permit persons to whom the Software is furnished to do so, subject to
     14  * the following conditions:
     15  *
     16  * The above copyright notice and this permission notice shall be included
     17  * in all copies or substantial portions of the Software.
     18  *
     19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     20  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     22  * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
     23  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     24  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     25  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     26  *
     27  * Except as contained in this notice, the name(s) of the above copyright
     28  * holders shall not be used in advertising or otherwise to promote the
     29  * sale, use or other dealings in this Software without prior written
     30  * authorization.
     31  *
     32  * Copyright 1988  X Consortium
     33  *
     34  * Permission to use, copy, modify, distribute, and sell this software and its
     35  * documentation for any purpose is hereby granted without fee, provided that
     36  * the above copyright notice appear in all copies and that both that
     37  * copyright notice and this permission notice appear in supporting
     38  * documentation.
     39  *
     40  * The above copyright notice and this permission notice shall be included in
     41  * all copies or substantial portions of the Software.
     42  *
     43  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     44  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     45  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
     46  * OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     47  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     48  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     49  *
     50  * Except as contained in this notice, the name of the X Consortium shall not be
     51  * used in advertising or otherwise to promote the sale, use or other dealings
     52  * in this Software without prior written authorization from the X Consortium.
     53  *
     54  * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
     55  *
     56  *                         All Rights Reserved
     57  *
     58  * Permission to use, copy, modify, and distribute this software and its
     59  * documentation for any purpose and without fee is hereby granted,
     60  * provided that the above copyright notice appear in all copies and that
     61  * both that copyright notice and this permission notice appear in
     62  * supporting documentation, and that the name of Digital Equipment
     63  * Corporation not be used in advertising or publicity pertaining to
     64  * distribution of the software without specific, written prior permission.
     65  *
     66  *
     67  * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
     68  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
     69  * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
     70  * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
     71  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
     72  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
     73  * SOFTWARE.
     74  */
     75 
     76 /* Tekproc.c */
     77 
     78 #define RES_OFFSET(field)	XtOffsetOf(TekWidgetRec, field)
     79 
     80 #include <xterm.h>
     81 
     82 #include <X11/Xatom.h>
     83 #include <X11/Xutil.h>
     84 #include <X11/Xmu/CharSet.h>
     85 
     86 #if OPT_TOOLBAR
     87 
     88 #if defined(HAVE_LIB_XAW)
     89 #include <X11/Xaw/Form.h>
     90 #elif defined(HAVE_LIB_XAW3D)
     91 #include <X11/Xaw3d/Form.h>
     92 #elif defined(HAVE_LIB_XAW3DXFT)
     93 #include <X11/Xaw3dxft/Form.h>
     94 #elif defined(HAVE_LIB_NEXTAW)
     95 #include <X11/neXtaw/Form.h>
     96 #elif defined(HAVE_LIB_XAWPLUS)
     97 #include <X11/XawPlus/Form.h>
     98 #endif
     99 
    100 #endif /* OPT_TOOLBAR */
    101 
    102 #include <assert.h>
    103 #include <stdio.h>
    104 #include <ctype.h>
    105 #include <signal.h>
    106 
    107 #include <Tekparse.h>
    108 #include <data.h>
    109 #include <error.h>
    110 #include <menu.h>
    111 #include <xstrings.h>
    112 
    113 #define DefaultGCID(tw) \
    114 	XGContextFromGC(DefaultGC(XtDisplay(tw), \
    115 			DefaultScreen(XtDisplay(tw))))
    116 
    117 /* Tek defines */
    118 
    119 #define MY_CLASS "Tek4014"
    120 #define MY_NAME  "tek4014"
    121 
    122 #define	SOLIDLINE	0
    123 #define	DOTTEDLINE	1
    124 #define	DOTDASHEDLINE	2
    125 #define	SHORTDASHEDLINE	3
    126 #define	LONGDASHEDLINE	4
    127 
    128 #define	EAST		001
    129 #define	WEST		002
    130 #define	NORTH		004
    131 #define	SOUTH		010
    132 
    133 #define	LINEMASK	07
    134 #define	MARGIN1		0
    135 #define	MARGIN2		1
    136 #define MAX_PTS		150
    137 #define MAX_VTX		300
    138 #define	PENDOWN		1
    139 #define	PENUP		0
    140 #define	TEKBOTTOMPAD	23
    141 #define	TEKDEFHEIGHT	565
    142 #define	TEKDEFWIDTH	750
    143 #define	TEKHEIGHT	3072
    144 #define	TEKHOME		( (TekChar[tekscr->page.fontsize].nlines - 1) \
    145 			 * TekChar[tekscr->page.fontsize].vsize)
    146 #define	TEKMINHEIGHT	452
    147 #define	TEKMINWIDTH	600
    148 #define	TEKTOPPAD	34
    149 #define	TEKWIDTH	4096
    150 
    151 #define	FULL_HEIGHT	(TEKHEIGHT + TEKTOPPAD + TEKBOTTOMPAD)
    152 
    153 #define	BottomY(y)	(TEKHEIGHT + TEKTOPPAD - (y))
    154 #define	BorderOf(tw)	(TScreenOf((tw)->vt)->border)
    155 #define	ScaleOf(tw)	TekScale(TekScreenOf(tw))
    156 #define	ScaledX(tw,x)	(((x) * ScaleOf(tw)) + BorderOf(tw))
    157 #define	ScaledY(tw,y)	((BottomY(y) * ScaleOf(tw)) + BorderOf(tw))
    158 
    159 #define	TekMove(tw,x,y)	do { tekscr->cur_X = x; tekscr->cur_Y = y; } while (0)
    160 #define	input()		Tinput(tw)
    161 #define	unput(c)	*Tpushback++ = (Char) c
    162 /* *INDENT-OFF* */
    163 static const struct Tek_Char {
    164     int hsize;			/* in Tek units */
    165     int vsize;			/* in Tek units */
    166     int charsperline;
    167     int nlines;
    168 } TekChar[TEKNUMFONTS] = {
    169     {56, 88, 74, 35},		/* large */
    170     {51, 82, 81, 38},		/* #2 */
    171     {34, 53, 121, 58},		/* #3 */
    172     {31, 48, 133, 64},		/* small */
    173 };
    174 /* *INDENT-ON* */
    175 
    176 static Cursor GINcursor;
    177 static XSegment *line_pt;
    178 static int nplot;
    179 static TekLink Tek0;
    180 static jmp_buf Tekjump;
    181 static TekLink *TekRecord;
    182 static XSegment *Tline;
    183 
    184 static const int *curstate = Talptable;
    185 static const int *Tparsestate = Talptable;
    186 
    187 static char defaultTranslations[] = "\
    188                 ~Meta<KeyPress>: insert-seven-bit() \n\
    189                  Meta<KeyPress>: insert-eight-bit() \n\
    190                !Ctrl <Btn1Down>: popup-menu(mainMenu) \n\
    191           !Lock Ctrl <Btn1Down>: popup-menu(mainMenu) \n\
    192 !Lock Ctrl @Num_Lock <Btn1Down>: popup-menu(mainMenu) \n\
    193      !Ctrl @Num_Lock <Btn1Down>: popup-menu(mainMenu) \n\
    194                !Ctrl <Btn2Down>: popup-menu(tekMenu) \n\
    195           !Lock Ctrl <Btn2Down>: popup-menu(tekMenu) \n\
    196 !Lock Ctrl @Num_Lock <Btn2Down>: popup-menu(tekMenu) \n\
    197      !Ctrl @Num_Lock <Btn2Down>: popup-menu(tekMenu) \n\
    198           Shift ~Meta<Btn1Down>: gin-press(L) \n\
    199                 ~Meta<Btn1Down>: gin-press(l) \n\
    200           Shift ~Meta<Btn2Down>: gin-press(M) \n\
    201                 ~Meta<Btn2Down>: gin-press(m) \n\
    202           Shift ~Meta<Btn3Down>: gin-press(R) \n\
    203                 ~Meta<Btn3Down>: gin-press(r)";
    204 /* *INDENT-OFF* */
    205 static XtActionsRec actionsList[] = {
    206     { "string",			HandleStringEvent },
    207     { "insert",			HandleKeyPressed },	/* alias for insert-seven-bit */
    208     { "insert-seven-bit",	HandleKeyPressed },
    209     { "insert-eight-bit",	HandleEightBitKeyPressed },
    210     { "gin-press",		HandleGINInput },
    211     { "secure",			HandleSecure },
    212     { "create-menu",		HandleCreateMenu },
    213     { "popup-menu",		HandlePopupMenu },
    214     /* menu actions */
    215     { "allow-send-events",	HandleAllowSends },
    216     { "set-visual-bell",	HandleSetVisualBell },
    217 #ifdef ALLOWLOGGING
    218     { "set-logging",		HandleLogging },
    219 #endif
    220     { "redraw",			HandleRedraw },
    221     { "send-signal",		HandleSendSignal },
    222     { "quit",			HandleQuit },
    223     { "set-scrollbar",		HandleScrollbar },
    224     { "set-jumpscroll",		HandleJumpscroll },
    225     { "set-reverse-video",	HandleReverseVideo },
    226     { "set-autowrap",		HandleAutoWrap },
    227     { "set-reversewrap",	HandleReverseWrap },
    228     { "set-autolinefeed",	HandleAutoLineFeed },
    229     { "set-appcursor",		HandleAppCursor },
    230     { "set-appkeypad",		HandleAppKeypad },
    231     { "set-scroll-on-key",	HandleScrollKey },
    232     { "set-scroll-on-tty-output", HandleScrollTtyOutput },
    233     { "set-allow132",		HandleAllow132 },
    234     { "set-cursesemul",		HandleCursesEmul },
    235     { "set-marginbell",		HandleMarginBell },
    236     { "set-altscreen",		HandleAltScreen },
    237     { "soft-reset",		HandleSoftReset },
    238     { "hard-reset",		HandleHardReset },
    239     { "set-terminal-type",	HandleSetTerminalType },
    240     { "set-visibility",		HandleVisibility },
    241     { "set-tek-text",		HandleSetTekText },
    242     { "tek-page",		HandleTekPage },
    243     { "tek-reset",		HandleTekReset },
    244     { "tek-copy",		HandleTekCopy },
    245 #if OPT_TOOLBAR
    246     { "set-toolbar",		HandleToolbar },
    247 #endif
    248 };
    249 /* *INDENT-ON* */
    250 
    251 static Dimension defOne = 1;
    252 
    253 #define GIN_TERM_NONE_STR	"none"
    254 #define GIN_TERM_CR_STR		"CRonly"
    255 #define GIN_TERM_EOT_STR	"CR&EOT"
    256 
    257 #define GIN_TERM_NONE	0
    258 #define GIN_TERM_CR	1
    259 #define GIN_TERM_EOT	2
    260 
    261 #define DFT_FONT_SMALL "6x10"
    262 
    263 static XtResource resources[] =
    264 {
    265     {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
    266      XtOffsetOf(CoreRec, core.width), XtRDimension, (caddr_t) & defOne},
    267     {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
    268      XtOffsetOf(CoreRec, core.height), XtRDimension, (caddr_t) & defOne},
    269     Fres("fontLarge", XtCFont, tek.Tfont[TEK_FONT_LARGE], "9x15"),
    270     Fres("font2", XtCFont, tek.Tfont[TEK_FONT_2], "6x13"),
    271     Fres("font3", XtCFont, tek.Tfont[TEK_FONT_3], "8x13"),
    272     Fres("fontSmall", XtCFont, tek.Tfont[TEK_FONT_SMALL], DFT_FONT_SMALL),
    273     Sres(XtNinitialFont, XtCInitialFont, tek.initial_font, "large"),
    274     Sres("ginTerminator", "GinTerminator", tek.gin_terminator_str, GIN_TERM_NONE_STR),
    275 #if OPT_TOOLBAR
    276     Wres(XtNmenuBar, XtCMenuBar, tek.tb_info.menu_bar, 0),
    277     Ires(XtNmenuHeight, XtCMenuHeight, tek.tb_info.menu_height, 25),
    278 #endif
    279 };
    280 
    281 static IChar Tinput(TekWidget /* tw */ );
    282 static int getpoint(TekWidget /* tw */ );
    283 static void TCursorBack(TekWidget /* tw */ );
    284 static void TCursorDown(TekWidget /* tw */ );
    285 static void TCursorForward(TekWidget /* tw */ );
    286 static void TCursorUp(TekWidget /* tw */ );
    287 static void TekBackground(TekWidget /* tw */ ,
    288 			  TScreen * /* screen */ );
    289 static void TekResize(Widget /* w */ );
    290 static void TekDraw(TekWidget /* tw */ ,
    291 		    int /* x */ ,
    292 		    int /* y */ );
    293 static void TekEnq(TekWidget /* tw */ ,
    294 		   unsigned /* status */ ,
    295 		   int /* x */ ,
    296 		   int /* y */ );
    297 static void TekFlush(TekWidget /* tw */ );
    298 static void TekInitialize(Widget /* request */ ,
    299 			  Widget /* wnew */ ,
    300 			  ArgList /* args */ ,
    301 			  Cardinal * /* num_args */ );
    302 static void TekPage(TekWidget /* tw */ );
    303 static void TekRealize(Widget /* gw */ ,
    304 		       XtValueMask * /* valuemaskp */ ,
    305 		       XSetWindowAttributes * /* values */ );
    306 
    307 static WidgetClassRec tekClassRec =
    308 {
    309     {
    310 /* core_class fields */
    311 	(WidgetClass) & widgetClassRec,		/* superclass     */
    312 	MY_CLASS,		/* class_name                   */
    313 	sizeof(TekWidgetRec),	/* widget_size                  */
    314 	NULL,			/* class_initialize             */
    315 	NULL,			/* class_part_initialize        */
    316 	False,			/* class_inited                 */
    317 	TekInitialize,		/* initialize                   */
    318 	NULL,			/* initialize_hook              */
    319 	TekRealize,		/* realize                      */
    320 	actionsList,		/* actions                      */
    321 	XtNumber(actionsList),	/* num_actions                  */
    322 	resources,		/* resources                    */
    323 	XtNumber(resources),	/* num_resources                */
    324 	NULLQUARK,		/* xrm_class                    */
    325 	True,			/* compress_motion              */
    326 	True,			/* compress_exposure            */
    327 	True,			/* compress_enterleave          */
    328 	False,			/* visible_interest             */
    329 	NULL,			/* destroy                      */
    330 	TekResize,		/* resize                       */
    331 	TekExpose,		/* expose                       */
    332 	NULL,			/* set_values                   */
    333 	NULL,			/* set_values_hook              */
    334 	XtInheritSetValuesAlmost,	/* set_values_almost    */
    335 	NULL,			/* get_values_hook              */
    336 	NULL,			/* accept_focus                 */
    337 	XtVersion,		/* version                      */
    338 	NULL,			/* callback_offsets             */
    339 	defaultTranslations,	/* tm_table                     */
    340 	XtInheritQueryGeometry,	/* query_geometry               */
    341 	XtInheritDisplayAccelerator,	/* display_accelerator  */
    342 	NULL			/* extension                    */
    343     }
    344 };
    345 WidgetClass tekWidgetClass = (WidgetClass) & tekClassRec;
    346 
    347 static Bool Tfailed = False;
    348 
    349 /*
    350  * TekInit/TekRun are called after the VT100 widget has been initialized, but
    351  * may be before VT100 is realized, depending upon whether Tek4014 is the
    352  * first window to be shown.
    353  */
    354 int
    355 TekInit(void)
    356 {
    357     Widget form_top, menu_top;
    358     Dimension menu_high;
    359 
    360     if (!Tfailed
    361 	&& tekWidget == NULL) {
    362 	Cardinal nargs = 0;
    363 	Arg myArgs[3];
    364 	Boolean iconic = 0;
    365 
    366 	TRACE(("TekInit\n"));
    367 	XtSetArg(myArgs[nargs], XtNiconic, &iconic);
    368 	++nargs;
    369 	XtGetValues(toplevel, myArgs, nargs);
    370 
    371 	nargs = 0;
    372 	XtSetArg(myArgs[nargs], XtNiconic, iconic);
    373 	++nargs;
    374 	XtSetArg(myArgs[nargs], XtNallowShellResize, True);
    375 	++nargs;
    376 	XtSetArg(myArgs[nargs], XtNinput, True);
    377 	++nargs;
    378 
    379 	/* this causes the Initialize method to be called */
    380 	tekshellwidget =
    381 	    XtCreatePopupShell("tektronix", topLevelShellWidgetClass,
    382 			       toplevel, myArgs, nargs);
    383 
    384 	SetupMenus(tekshellwidget, &form_top, &menu_top, &menu_high);
    385 
    386 	/* this causes the Realize method to be called */
    387 	tekWidget = (TekWidget)
    388 	    XtVaCreateManagedWidget(MY_NAME,
    389 				    tekWidgetClass, form_top,
    390 #if OPT_TOOLBAR
    391 				    XtNmenuBar, menu_top,
    392 				    XtNresizable, True,
    393 				    XtNfromVert, menu_top,
    394 				    XtNtop, XawChainTop,
    395 				    XtNleft, XawChainLeft,
    396 				    XtNright, XawChainRight,
    397 				    XtNbottom, XawChainBottom,
    398 				    XtNmenuHeight, menu_high,
    399 #endif
    400 				    (XtPointer) 0);
    401 	TRACE(("created tek4014 widget %p, window %#lx\n",
    402 	       (void *) tekWidget, XtWindow(tekWidget)));
    403 #if OPT_TOOLBAR
    404 	ShowToolbar(resource.toolBar);
    405 #endif
    406     }
    407     return (!Tfailed);
    408 }
    409 
    410 /*
    411  * If we haven't allocated the PtyData struct, do so.
    412  */
    413 static int
    414 TekPtyData(void)
    415 {
    416     if (Tpushb == NULL && !Tfailed) {
    417 	if ((Tpushb = TypeMallocN(Char, 10)) == NULL
    418 	    || (Tline = TypeMallocN(XSegment, MAX_VTX)) == NULL) {
    419 	    xtermWarning("Not enough core for Tek mode\n");
    420 	    free(Tpushb);
    421 	    Tfailed = True;
    422 	}
    423     }
    424     return (Tfailed ? 0 : 1);
    425 }
    426 
    427 static void
    428 Tekparse(TekWidget tw)
    429 {
    430     TekScreen *tekscr = TekScreenOf(tw);
    431     TScreen *screen = TScreenOf(tw->vt);
    432     int x, y;
    433     IChar ch;
    434     int nextstate;
    435 
    436     for (;;) {
    437 	IChar c = input();
    438 	/*
    439 	 * The parsing tables all have 256 entries.  If we're supporting
    440 	 * wide characters, we handle them by treating them the same as
    441 	 * printing characters.
    442 	 */
    443 #if OPT_WIDE_CHARS
    444 	if (c > 255) {
    445 	    nextstate = (Tparsestate == Talptable)
    446 		? CASE_PRINT
    447 		: CASE_IGNORE;
    448 	} else
    449 #endif
    450 	    nextstate = Tparsestate[c];
    451 	TRACE(("Tekparse %04X -> %d\n", c, nextstate));
    452 
    453 	switch (nextstate) {
    454 	case CASE_REPORT:
    455 	    TRACE(("case: report address\n"));
    456 	    if (tekscr->TekGIN) {
    457 		TekGINoff(tw);
    458 		TekEnqMouse(tw, 0);
    459 	    } else {
    460 		c = 064;	/* has hard copy unit */
    461 		if (tekscr->margin == MARGIN2)
    462 		    c |= 02;
    463 		TekEnq(tw, c, tekscr->cur_X, tekscr->cur_Y);
    464 	    }
    465 	    TekRecord->ptr[-1] = ANSI_NAK;	/* remove from recording */
    466 	    Tparsestate = curstate;
    467 	    break;
    468 
    469 	case CASE_VT_MODE:
    470 	    TRACE(("case: special return to vt102 mode\n"));
    471 	    Tparsestate = curstate;
    472 	    TekRecord->ptr[-1] = ANSI_NAK;	/* remove from recording */
    473 	    FlushLog(tw->vt);
    474 	    return;
    475 
    476 	case CASE_SPT_STATE:
    477 	    TRACE(("case: Enter Special Point Plot mode\n"));
    478 	    if (tekscr->TekGIN)
    479 		TekGINoff(tw);
    480 	    Tparsestate = curstate = Tspttable;
    481 	    break;
    482 
    483 	case CASE_GIN:
    484 	    TRACE(("case: Do Tek GIN mode\n"));
    485 	    tekscr->TekGIN = &TekRecord->ptr[-1];
    486 	    /* Set cross-hair cursor raster array */
    487 	    if ((GINcursor =
    488 		 make_colored_cursor(XC_tcross,
    489 				     T_COLOR(screen, MOUSE_FG),
    490 				     T_COLOR(screen, MOUSE_BG))) != 0) {
    491 		XDefineCursor(XtDisplay(tw), TWindow(tekscr),
    492 			      GINcursor);
    493 	    }
    494 	    Tparsestate = Tbyptable;	/* Bypass mode */
    495 	    break;
    496 
    497 	case CASE_BEL:
    498 	    TRACE(("case: BEL\n"));
    499 	    if (tekscr->TekGIN)
    500 		TekGINoff(tw);
    501 	    if (!tekRefreshList)
    502 		Bell(tw->vt, XkbBI_TerminalBell, 0);
    503 	    Tparsestate = curstate;	/* clear bypass condition */
    504 	    break;
    505 
    506 	case CASE_BS:
    507 	    TRACE(("case: BS\n"));
    508 	    if (tekscr->TekGIN)
    509 		TekGINoff(tw);
    510 	    Tparsestate = curstate;	/* clear bypass condition */
    511 	    TCursorBack(tw);
    512 	    break;
    513 
    514 	case CASE_PT_STATE:
    515 	    TRACE(("case: Enter Tek Point Plot mode\n"));
    516 	    if (tekscr->TekGIN)
    517 		TekGINoff(tw);
    518 	    Tparsestate = curstate = Tpttable;
    519 	    break;
    520 
    521 	case CASE_PLT_STATE:
    522 	    TRACE(("case: Enter Tek Plot mode\n"));
    523 	    if (tekscr->TekGIN)
    524 		TekGINoff(tw);
    525 	    Tparsestate = curstate = Tplttable;
    526 	    if ((c = input()) == ANSI_BEL)
    527 		tekscr->pen = PENDOWN;
    528 	    else {
    529 		unput(c);
    530 		tekscr->pen = PENUP;
    531 	    }
    532 	    break;
    533 
    534 	case CASE_TAB:
    535 	    TRACE(("case: HT\n"));
    536 	    if (tekscr->TekGIN)
    537 		TekGINoff(tw);
    538 	    Tparsestate = curstate;	/* clear bypass condition */
    539 	    TCursorForward(tw);
    540 	    break;
    541 
    542 	case CASE_IPL_STATE:
    543 	    TRACE(("case: Enter Tek Incremental Plot mode\n"));
    544 	    if (tekscr->TekGIN)
    545 		TekGINoff(tw);
    546 	    Tparsestate = curstate = Tipltable;
    547 	    break;
    548 
    549 	case CASE_ALP_STATE:
    550 	    TRACE(("case: Enter Tek Alpha mode from any other mode\n"));
    551 	    if (tekscr->TekGIN)
    552 		TekGINoff(tw);
    553 	    /* if in one of graphics states, move alpha cursor */
    554 	    if (nplot > 0)	/* flush line VTbuffer */
    555 		TekFlush(tw);
    556 	    Tparsestate = curstate = Talptable;
    557 	    break;
    558 
    559 	case CASE_UP:
    560 	    TRACE(("case: cursor up\n"));
    561 	    if (tekscr->TekGIN)
    562 		TekGINoff(tw);
    563 	    Tparsestate = curstate;	/* clear bypass condition */
    564 	    TCursorUp(tw);
    565 	    break;
    566 
    567 	case CASE_COPY:
    568 	    TRACE(("case: make copy\n"));
    569 	    if (tekscr->TekGIN)
    570 		TekGINoff(tw);
    571 	    TekCopy(tw);
    572 	    TekRecord->ptr[-1] = ANSI_NAK;	/* remove from recording */
    573 	    Tparsestate = curstate;	/* clear bypass condition */
    574 	    break;
    575 
    576 	case CASE_PAGE:
    577 	    TRACE(("case: Page Function\n"));
    578 	    if (tekscr->TekGIN)
    579 		TekGINoff(tw);
    580 	    TekPage(tw);	/* clear bypass condition */
    581 	    break;
    582 
    583 	case CASE_BES_STATE:
    584 	    TRACE(("case: Byp: an escape char\n"));
    585 	    Tparsestate = Tbestable;
    586 	    break;
    587 
    588 	case CASE_BYP_STATE:
    589 	    TRACE(("case: set bypass condition\n"));
    590 	    Tparsestate = Tbyptable;
    591 	    break;
    592 
    593 	case CASE_IGNORE:
    594 	    TRACE(("case: Esc: totally ignore CR, ESC, LF, ~\n"));
    595 	    break;
    596 
    597 	case CASE_ASCII:
    598 	    TRACE(("case: Select ASCII char set\n"));
    599 	    /* ignore for now */
    600 	    Tparsestate = curstate;
    601 	    break;
    602 
    603 	case CASE_APL:
    604 	    TRACE(("case: Select APL char set\n"));
    605 	    /* ignore for now */
    606 	    Tparsestate = curstate;
    607 	    break;
    608 
    609 	case CASE_CHAR_SIZE:
    610 	    TRACE(("case: character size selector\n"));
    611 	    TekSetFontSize(tw, False, (int) (c & 03));
    612 	    Tparsestate = curstate;
    613 	    break;
    614 
    615 	case CASE_BEAM_VEC:
    616 	    TRACE(("case: beam and vector selector\n"));
    617 	    /* only line types */
    618 	    c = (IChar) (c & LINEMASK);
    619 	    if (c != tekscr->cur.linetype) {
    620 		if (nplot > 0)
    621 		    TekFlush(tw);
    622 		if (c <= TEKNUMLINES)
    623 		    tekscr->cur.linetype = c;
    624 	    }
    625 	    Tparsestate = curstate;
    626 	    break;
    627 
    628 	case CASE_CURSTATE:
    629 	    Tparsestate = curstate;
    630 	    break;
    631 
    632 	case CASE_PENUP:
    633 	    TRACE(("case: Ipl: penup\n"));
    634 	    tekscr->pen = PENUP;
    635 	    break;
    636 
    637 	case CASE_PENDOWN:
    638 	    TRACE(("case: Ipl: pendown\n"));
    639 	    tekscr->pen = PENDOWN;
    640 	    break;
    641 
    642 	case CASE_IPL_POINT:
    643 	    TRACE(("case: Ipl: point\n"));
    644 	    x = tekscr->cur_X;
    645 	    y = tekscr->cur_Y;
    646 	    if (c & NORTH)
    647 		y++;
    648 	    else if (c & SOUTH)
    649 		y--;
    650 	    if (c & EAST)
    651 		x++;
    652 	    else if (c & WEST)
    653 		x--;
    654 	    if (tekscr->pen == PENDOWN) {
    655 		TekDraw(tw, x, y);
    656 	    } else {
    657 		TekMove(tw, x, y);
    658 	    }
    659 	    break;
    660 
    661 	case CASE_PLT_VEC:
    662 	    TRACE(("case: Plt: vector\n"));
    663 	    unput(c);
    664 	    if (getpoint(tw)) {
    665 		if (tekscr->pen == PENDOWN) {
    666 		    TekDraw(tw, tekscr->cur.x, tekscr->cur.y);
    667 		} else {
    668 		    TekMove(tw, tekscr->cur.x, tekscr->cur.y);
    669 		}
    670 		tekscr->pen = PENDOWN;
    671 	    }
    672 	    break;
    673 
    674 	case CASE_PT_POINT:
    675 	    TRACE(("case: Pt: point\n"));
    676 	    unput(c);
    677 	    if (getpoint(tw)) {
    678 		TekMove(tw, tekscr->cur.x, tekscr->cur.y);
    679 		TekDraw(tw, tekscr->cur.x, tekscr->cur.y);
    680 	    }
    681 	    break;
    682 
    683 	case CASE_SPT_POINT:
    684 	    TRACE(("case: Spt: point\n"));
    685 	    /* ignore intensity character in c */
    686 	    if (getpoint(tw)) {
    687 		TekMove(tw, tekscr->cur.x, tekscr->cur.y);
    688 		TekDraw(tw, tekscr->cur.x, tekscr->cur.y);
    689 	    }
    690 	    break;
    691 
    692 	case CASE_CR:
    693 	    TRACE(("case: CR\n"));
    694 	    if (tekscr->TekGIN)
    695 		TekGINoff(tw);
    696 	    if (nplot > 0)	/* flush line VTbuffer */
    697 		TekFlush(tw);
    698 	    tekscr->cur_X = tekscr->margin == MARGIN1 ? 0 :
    699 		TEKWIDTH / 2;
    700 	    Tparsestate = curstate = Talptable;
    701 	    break;
    702 
    703 	case CASE_ESC_STATE:
    704 	    TRACE(("case: ESC\n"));
    705 	    Tparsestate = Tesctable;
    706 	    break;
    707 
    708 	case CASE_LF:
    709 	    TRACE(("case: LF\n"));
    710 	    if (tekscr->TekGIN)
    711 		TekGINoff(tw);
    712 	    TCursorDown(tw);
    713 	    if (!tekRefreshList)
    714 		do_xevents(tw->vt);
    715 	    break;
    716 
    717 	case CASE_SP:
    718 	    TRACE(("case: SP\n"));
    719 	    TCursorForward(tw);
    720 	    break;
    721 
    722 	case CASE_PRINT:
    723 	    TRACE(("case: printable character\n"));
    724 	    ch = c;
    725 	    x = (int) ScaledX(tw, tekscr->cur_X);
    726 	    y = (int) ScaledY(tw, tekscr->cur_Y);
    727 
    728 #if OPT_WIDE_CHARS
    729 	    if (screen->wide_chars
    730 		&& (ch > 255)) {
    731 		XChar2b sbuf;
    732 		sbuf.byte2 = LO_BYTE(ch);
    733 		sbuf.byte1 = HI_BYTE(ch);
    734 		XDrawImageString16(XtDisplay(tw),
    735 				   TWindow(tekscr),
    736 				   tekscr->TnormalGC,
    737 				   x,
    738 				   y,
    739 				   &sbuf,
    740 				   1);
    741 	    } else
    742 #endif
    743 	    {
    744 		char ch2 = (char) ch;
    745 		XDrawString(XtDisplay(tw),
    746 			    TWindow(tekscr),
    747 			    tekscr->TnormalGC,
    748 			    x,
    749 			    y,
    750 			    &ch2,
    751 			    1);
    752 	    }
    753 	    TCursorForward(tw);
    754 	    break;
    755 	case CASE_OSC:
    756 	    /* FIXME:  someone should disentangle the input queues
    757 	     * of this code so that it can be state-driven.
    758 	     */
    759 	    TRACE(("case: do osc escape\n"));
    760 	    {
    761 		/*
    762 		 * do_osc() can call TekExpose(), which calls TekRefresh(),
    763 		 * and sends us recurring here - don't do that...
    764 		 */
    765 		static int nested;
    766 
    767 		Char buf2[512];
    768 		IChar c2;
    769 		size_t len = 0;
    770 		while ((c2 = input()) != ANSI_BEL) {
    771 		    if (!isprint(CharOf(c2 & 0x7f))
    772 			|| len + 2 >= (int) sizeof(buf2))
    773 			break;
    774 		    buf2[len++] = (Char) c2;
    775 		}
    776 		buf2[len] = 0;
    777 		if (!nested++) {
    778 		    if (c2 == ANSI_BEL)
    779 			do_osc(tw->vt, buf2, len, ANSI_BEL);
    780 		}
    781 		--nested;
    782 	    }
    783 	    Tparsestate = curstate;
    784 	    break;
    785 	}
    786     }
    787 }
    788 
    789 static int rcnt;
    790 static char *rptr;
    791 static PtySelect Tselect_mask;
    792 
    793 static IChar
    794 Tinput(TekWidget tw)
    795 {
    796     TekScreen *tekscr = TekScreenOf(tw);
    797     TScreen *screen = TScreenOf(tw->vt);
    798     TekLink *tek;
    799 
    800     if (Tpushback > Tpushb)
    801 	return (*--Tpushback);
    802     if (tekRefreshList) {
    803 	if (rcnt-- > 0)
    804 	    return (IChar) (*rptr++);
    805 	if ((tek = tekRefreshList->next) != NULL) {
    806 	    tekRefreshList = tek;
    807 	    rptr = tek->data;
    808 	    rcnt = tek->count - 1;
    809 	    TekSetFontSize(tw, False, tek->fontsize);
    810 	    return (IChar) (*rptr++);
    811 	}
    812 	tekRefreshList = (TekLink *) 0;
    813 	longjmp(Tekjump, 1);
    814     }
    815   again:
    816     if (VTbuffer->next >= VTbuffer->last) {
    817 	int update = VTbuffer->update;
    818 
    819 	if (nplot > 0)		/* flush line */
    820 	    TekFlush(tw);
    821 	XFD_COPYSET(&pty_mask, &Tselect_mask);
    822 	for (;;) {
    823 #ifdef CRAY
    824 	    struct timeval crocktimeout;
    825 	    crocktimeout.tv_sec = 0;
    826 	    crocktimeout.tv_usec = 0;
    827 	    (void) Select(max_plus1,
    828 			  &Tselect_mask, NULL, NULL,
    829 			  &crocktimeout);
    830 #endif
    831 	    if (readPtyData(tw->vt, &Tselect_mask, VTbuffer)) {
    832 		break;
    833 	    }
    834 	    if (Ttoggled && curstate == Talptable) {
    835 		TCursorToggle(tw, TOGGLE);
    836 		Ttoggled = False;
    837 	    }
    838 	    if (xtermAppPending() & XtIMXEvent) {
    839 		XFD_COPYSET(&X_mask, &Tselect_mask);
    840 	    } else {
    841 		XFlush(XtDisplay(tw));
    842 		XFD_COPYSET(&Select_mask, &Tselect_mask);
    843 		if (Select(max_plus1, &Tselect_mask, NULL, NULL, NULL) < 0) {
    844 		    if (errno != EINTR)
    845 			SysError(ERROR_TSELECT);
    846 		    continue;
    847 		}
    848 	    }
    849 	    if (FD_ISSET(ConnectionNumber(XtDisplay(tw)), &Tselect_mask)) {
    850 		xevents(tw->vt);
    851 		if (VTbuffer->update != update)
    852 		    goto again;
    853 	    }
    854 	}
    855 	if (!Ttoggled && curstate == Talptable) {
    856 	    TCursorToggle(tw, TOGGLE);
    857 	    Ttoggled = True;
    858 	}
    859     }
    860     tek = TekRecord;
    861     if (tek->count >= TEK_LINK_BLOCK_SIZE
    862 	|| tek->fontsize != tekscr->cur.fontsize) {
    863 	if ((TekRecord = tek->next = CastMalloc(TekLink)) == NULL) {
    864 	    Panic("Tinput: malloc error (%d)\n", errno);
    865 	} else {
    866 	    tek = tek->next;
    867 	    tek->next = (TekLink *) 0;
    868 	    tek->fontsize = (unsigned short) tekscr->cur.fontsize;
    869 	    tek->count = 0;
    870 	    tek->ptr = tek->data;
    871 	}
    872     }
    873     tek->count++;
    874 
    875     (void) morePtyData(screen, VTbuffer);
    876     return (IChar) (*tek->ptr++ = (char) nextPtyData(screen, VTbuffer));
    877 }
    878 
    879 static void
    880 TekClear(TekWidget tw)
    881 {
    882     TekScreen *tekscr = TekScreenOf(tw);
    883 
    884     TRACE(("TekClear\n"));
    885     nplot = 0;
    886     line_pt = Tline;
    887     if (TWindow(tekscr))
    888 	XClearWindow(XtDisplay(tw), TWindow(tekscr));
    889 }
    890 
    891 void
    892 TekSetWinSize(TekWidget tw)
    893 {
    894     if (TEK4014_ACTIVE(tw->vt)) {
    895 	TekScreen *tekscr = TekScreenOf(tw);
    896 	const struct Tek_Char *t = &TekChar[tekscr->cur.fontsize];
    897 	int rows = THeight(tekscr) / (int) (ScaleOf(tw) * t->vsize);
    898 	int cols = TWidth(tekscr) / (int) (ScaleOf(tw) * t->hsize);
    899 
    900 	update_winsize(TScreenOf(tw->vt),
    901 		       rows, cols,
    902 		       TFullHeight(tekscr),
    903 		       TFullWidth(tekscr));
    904     }
    905 }
    906 
    907 static void
    908 compute_sizes(TekWidget tw)
    909 {
    910     TekScreen *tekscr = TekScreenOf(tw);
    911     int border = 2 * BorderOf(tw);
    912     double d;
    913 #if OPT_TRACE
    914     const struct Tek_Char *t = &TekChar[tekscr->cur.fontsize];
    915     const XFontStruct *fs = tw->tek.Tfont[tekscr->cur.fontsize];
    916 #endif
    917 
    918     /* *INDENT-EQLS* */
    919     TWidth(tekscr)  = tw->core.width - border;
    920     THeight(tekscr) = tw->core.height - border;
    921     ScaleOf(tw)     = (double) TWidth(tekscr) / TEKWIDTH;
    922 
    923     if ((d = (double) THeight(tekscr) / FULL_HEIGHT) < ScaleOf(tw))
    924 	ScaleOf(tw) = d;
    925 
    926     TFullWidth(tekscr) = tw->core.width;
    927     TFullHeight(tekscr) = tw->core.height;
    928 
    929     TRACE(("%s size %dx%d full %dx%d scale %.2f\n", MY_NAME,
    930 	   THeight(tekscr), TWidth(tekscr),
    931 	   TFullHeight(tekscr), TFullWidth(tekscr),
    932 	   ScaleOf(tw)));
    933 
    934     /* The tek4014 fonts always look odd since their spacing is overridden to
    935      * get the "same" size as a real Tektronix terminal.  TrueType fonts for
    936      * these small sizes would be no better...
    937      */
    938     TRACE(("unscaled font %dx%d\n", t->vsize, t->hsize));
    939     TRACE(("scaled   font %.1fx%.1f\n", d * t->vsize, d * t->hsize));
    940     TRACE(("actual   font %dx%d\n",
    941 	   fs->max_bounds.ascent + fs->max_bounds.descent,
    942 	   fs->max_bounds.width));
    943 
    944     TekSetWinSize(tw);
    945 }
    946 
    947 static void
    948 TekResize(Widget w)
    949 {
    950     TekWidget tw = getTekWidget(w);
    951     if (tw != NULL) {
    952 
    953 	TRACE(("TekResize " TRACE_L "\n"));
    954 	TekClear(tw);
    955 
    956 	compute_sizes(tw);
    957 
    958 	TRACE((TRACE_R " TekResize\n"));
    959     }
    960 }
    961 
    962 /*ARGSUSED*/
    963 void
    964 TekExpose(Widget w,
    965 	  XEvent *event GCC_UNUSED,
    966 	  Region region GCC_UNUSED)
    967 {
    968     TekWidget tw = getTekWidget(w);
    969     if (tw != NULL) {
    970 	TekScreen *tekscr = TekScreenOf(tw);
    971 
    972 	TRACE(("TekExpose " TRACE_L "\n"));
    973 
    974 #ifdef lint
    975 	region = region;
    976 #endif
    977 	if (!Ttoggled)
    978 	    TCursorToggle(tw, CLEAR);
    979 	Ttoggled = True;
    980 	Tpushback = Tpushb;
    981 	tekscr->cur_X = 0;
    982 	tekscr->cur_Y = TEKHOME;
    983 	tekscr->cur = tekscr->page;
    984 	TekSetFontSize(tw, False, tekscr->cur.fontsize);
    985 	tekscr->margin = MARGIN1;
    986 	if (tekscr->TekGIN) {
    987 	    tekscr->TekGIN = NULL;
    988 	    TekGINoff(tw);
    989 	}
    990 	tekRefreshList = &Tek0;
    991 	rptr = tekRefreshList->data;
    992 	rcnt = tekRefreshList->count;
    993 	Tparsestate = curstate = Talptable;
    994 	TRACE(("TekExpose resets data to replay %d bytes\n", rcnt));
    995 	first_map_occurred();
    996 	if (!tekscr->waitrefresh)
    997 	    TekRefresh(tw);
    998 	TRACE((TRACE_R " TekExpose\n"));
    999     }
   1000 }
   1001 
   1002 void
   1003 TekRefresh(TekWidget tw)
   1004 {
   1005     if (tw != NULL) {
   1006 	TScreen *screen = TScreenOf(tw->vt);
   1007 	TekScreen *tekscr = TekScreenOf(tw);
   1008 	static Cursor wait_cursor = None;
   1009 
   1010 	if (wait_cursor == None)
   1011 	    wait_cursor = make_colored_cursor(XC_watch,
   1012 					      T_COLOR(screen, MOUSE_FG),
   1013 					      T_COLOR(screen, MOUSE_BG));
   1014 	XDefineCursor(XtDisplay(tw), TWindow(tekscr), wait_cursor);
   1015 	XFlush(XtDisplay(tw));
   1016 	if (!setjmp(Tekjump))
   1017 	    Tekparse(tw);
   1018 	XDefineCursor(XtDisplay(tw), TWindow(tekscr),
   1019 		      (tekscr->TekGIN && GINcursor) ? GINcursor : tekscr->arrow);
   1020     }
   1021 }
   1022 
   1023 void
   1024 TekRepaint(TekWidget tw)
   1025 {
   1026     TRACE(("TekRepaint\n"));
   1027     TekClear(tw);
   1028     TekExpose((Widget) tw, (XEvent *) NULL, (Region) NULL);
   1029 }
   1030 
   1031 static void
   1032 TekPage(TekWidget tw)
   1033 {
   1034     TekScreen *tekscr = TekScreenOf(tw);
   1035     TekLink *tek;
   1036 
   1037     TRACE(("TekPage\n"));
   1038     TekClear(tw);
   1039     tekscr->cur_X = 0;
   1040     tekscr->cur_Y = TEKHOME;
   1041     tekscr->margin = MARGIN1;
   1042     tekscr->page = tekscr->cur;
   1043     if (tekscr->TekGIN)
   1044 	TekGINoff(tw);
   1045     tek = TekRecord = &Tek0;
   1046     tek->fontsize = (unsigned short) tekscr->cur.fontsize;
   1047     tek->count = 0;
   1048     tek->ptr = tek->data;
   1049     tek = tek->next;
   1050     if (tek)
   1051 	do {
   1052 	    TekLink *tek2 = tek->next;
   1053 
   1054 	    free(tek);
   1055 	    tek = tek2;
   1056 	} while (tek);
   1057     TekRecord->next = (TekLink *) 0;
   1058     tekRefreshList = (TekLink *) 0;
   1059     Ttoggled = True;
   1060     Tparsestate = curstate = Talptable;		/* Tek Alpha mode */
   1061 }
   1062 
   1063 #define	EXTRABITS	017
   1064 #define	FIVEBITS	037
   1065 #define	HIBITS		(FIVEBITS << SHIFTHI)
   1066 #define	LOBITS		(FIVEBITS << SHIFTLO)
   1067 #define	SHIFTHI		7
   1068 #define	SHIFTLO		2
   1069 #define	TWOBITS		03
   1070 
   1071 static int
   1072 getpoint(TekWidget tw)
   1073 {
   1074     int x, y, e, lo_y = 0;
   1075     TekScreen *tekscr = TekScreenOf(tw);
   1076 
   1077     x = tekscr->cur.x;
   1078     y = tekscr->cur.y;
   1079 
   1080     for (;;) {
   1081 	int c;
   1082 
   1083 	if ((c = (int) input()) < ' ') {	/* control character */
   1084 	    unput(c);
   1085 	    return (0);
   1086 	}
   1087 	if (c < '@') {		/* Hi X or Hi Y */
   1088 	    if (lo_y) {		/* seen a Lo Y, so this must be Hi X */
   1089 		x &= ~HIBITS;
   1090 		x |= (c & FIVEBITS) << SHIFTHI;
   1091 		continue;
   1092 	    }
   1093 	    /* else Hi Y */
   1094 	    y &= ~HIBITS;
   1095 	    y |= (c & FIVEBITS) << SHIFTHI;
   1096 	    continue;
   1097 	}
   1098 	if (c < '`') {		/* Lo X */
   1099 	    x &= ~LOBITS;
   1100 	    x |= (c & FIVEBITS) << SHIFTLO;
   1101 	    tekscr->cur.x = x;
   1102 	    tekscr->cur.y = y;
   1103 	    return (1);		/* OK */
   1104 	}
   1105 	/* else Lo Y */
   1106 	if (lo_y) {		/* seen a Lo Y, so other must be extra bits */
   1107 	    e = (y >> SHIFTLO) & EXTRABITS;
   1108 	    x &= ~TWOBITS;
   1109 	    x |= e & TWOBITS;
   1110 	    y &= ~TWOBITS;
   1111 	    y |= (e >> SHIFTLO) & TWOBITS;
   1112 	}
   1113 	y &= ~LOBITS;
   1114 	y |= (c & FIVEBITS) << SHIFTLO;
   1115 	lo_y++;
   1116     }
   1117 }
   1118 
   1119 static void
   1120 TCursorBack(TekWidget tw)
   1121 {
   1122     TekScreen *tekscr = TekScreenOf(tw);
   1123     const struct Tek_Char *t;
   1124     int x = (tekscr->cur_X -= (t = &TekChar[tekscr->cur.fontsize])->hsize);
   1125 
   1126     if (((tekscr->margin == MARGIN1) && (x < 0))
   1127 	|| ((tekscr->margin == MARGIN2) && (x < TEKWIDTH / 2))) {
   1128 	int l = ((tekscr->cur_Y + (t->vsize - 1)) / t->vsize + 1);
   1129 	if (l >= t->nlines) {
   1130 	    tekscr->margin = !tekscr->margin;
   1131 	    l = 0;
   1132 	}
   1133 	tekscr->cur_Y = l * t->vsize;
   1134 	tekscr->cur_X = (t->charsperline - 1) * t->hsize;
   1135     }
   1136 }
   1137 
   1138 static void
   1139 TCursorForward(TekWidget tw)
   1140 {
   1141     TekScreen *tekscr = TekScreenOf(tw);
   1142     const struct Tek_Char *t = &TekChar[tekscr->cur.fontsize];
   1143 
   1144     if ((tekscr->cur_X += t->hsize) > TEKWIDTH) {
   1145 	int l = (tekscr->cur_Y / t->vsize - 1);
   1146 	if (l < 0) {
   1147 	    tekscr->margin = !tekscr->margin;
   1148 	    l = t->nlines - 1;
   1149 	}
   1150 	tekscr->cur_Y = l * t->vsize;
   1151 	tekscr->cur_X = tekscr->margin == MARGIN1 ? 0 : TEKWIDTH / 2;
   1152     }
   1153 }
   1154 
   1155 static void
   1156 TCursorUp(TekWidget tw)
   1157 {
   1158     TekScreen *tekscr = TekScreenOf(tw);
   1159     const struct Tek_Char *t;
   1160     int l;
   1161 
   1162     t = &TekChar[tekscr->cur.fontsize];
   1163 
   1164     if ((l = (tekscr->cur_Y + (t->vsize - 1)) / t->vsize + 1) >= t->nlines) {
   1165 	l = 0;
   1166 	if ((tekscr->margin = !tekscr->margin) != MARGIN1) {
   1167 	    if (tekscr->cur_X < TEKWIDTH / 2)
   1168 		tekscr->cur_X += TEKWIDTH / 2;
   1169 	} else if (tekscr->cur_X >= TEKWIDTH / 2)
   1170 	    tekscr->cur_X -= TEKWIDTH / 2;
   1171     }
   1172     tekscr->cur_Y = l * t->vsize;
   1173 }
   1174 
   1175 static void
   1176 TCursorDown(TekWidget tw)
   1177 {
   1178     TekScreen *tekscr = TekScreenOf(tw);
   1179     const struct Tek_Char *t;
   1180     int l;
   1181 
   1182     t = &TekChar[tekscr->cur.fontsize];
   1183 
   1184     if ((l = tekscr->cur_Y / t->vsize - 1) < 0) {
   1185 	l = t->nlines - 1;
   1186 	if ((tekscr->margin = !tekscr->margin) != MARGIN1) {
   1187 	    if (tekscr->cur_X < TEKWIDTH / 2)
   1188 		tekscr->cur_X += TEKWIDTH / 2;
   1189 	} else if (tekscr->cur_X >= TEKWIDTH / 2)
   1190 	    tekscr->cur_X -= TEKWIDTH / 2;
   1191     }
   1192     tekscr->cur_Y = l * t->vsize;
   1193 }
   1194 
   1195 static void
   1196 AddToDraw(TekWidget tw, int x1, int y1, int x2, int y2)
   1197 {
   1198     XSegment *lp;
   1199 
   1200     TRACE(("AddToDraw (%d,%d) (%d,%d)\n", x1, y1, x2, y2));
   1201     if (nplot >= MAX_PTS) {
   1202 	TekFlush(tw);
   1203     }
   1204     lp = line_pt++;
   1205     lp->x1 = (short) ScaledX(tw, x1);
   1206     lp->y1 = (short) ScaledY(tw, y1);
   1207     lp->x2 = (short) ScaledX(tw, x2);
   1208     lp->y2 = (short) ScaledY(tw, y2);
   1209     nplot++;
   1210     TRACE(("...AddToDraw %d points\n", nplot));
   1211 }
   1212 
   1213 static void
   1214 TekDraw(TekWidget tw, int x, int y)
   1215 {
   1216     TekScreen *tekscr = TekScreenOf(tw);
   1217 
   1218     if (nplot == 0 || T_lastx != tekscr->cur_X || T_lasty != tekscr->cur_Y) {
   1219 	/*
   1220 	 * We flush on each unconnected line segment if the line
   1221 	 * type is not solid.  This solves a bug in X when drawing
   1222 	 * points while the line type is not solid.
   1223 	 */
   1224 	if (nplot > 0 && tekscr->cur.linetype != SOLIDLINE)
   1225 	    TekFlush(tw);
   1226     }
   1227     AddToDraw(tw, tekscr->cur_X, tekscr->cur_Y, x, y);
   1228     T_lastx = tekscr->cur_X = x;
   1229     T_lasty = tekscr->cur_Y = y;
   1230 }
   1231 
   1232 static void
   1233 TekFlush(TekWidget tw)
   1234 {
   1235     TekScreen *tekscr = TekScreenOf(tw);
   1236 
   1237     TRACE(("TekFlush\n"));
   1238     XDrawSegments(XtDisplay(tw), TWindow(tekscr),
   1239 		  ((tekscr->cur.linetype == SOLIDLINE)
   1240 		   ? tekscr->TnormalGC
   1241 		   : tekscr->linepat[tekscr->cur.linetype - 1]),
   1242 		  Tline, nplot);
   1243     nplot = 0;
   1244     line_pt = Tline;
   1245 }
   1246 
   1247 void
   1248 TekGINoff(TekWidget tw)
   1249 {
   1250     TekScreen *tekscr = TekScreenOf(tw);
   1251 
   1252     TRACE(("TekGINoff\n"));
   1253     XDefineCursor(XtDisplay(tw), TWindow(tekscr), tekscr->arrow);
   1254     if (GINcursor)
   1255 	XFreeCursor(XtDisplay(tw), GINcursor);
   1256     if (tekscr->TekGIN) {
   1257 	*tekscr->TekGIN = ANSI_CAN;	/* modify recording */
   1258 	tekscr->TekGIN = NULL;
   1259     }
   1260 }
   1261 
   1262 void
   1263 TekEnqMouse(TekWidget tw, int c)	/* character pressed */
   1264 {
   1265     TekScreen *tekscr = TekScreenOf(tw);
   1266     int mousex, mousey, rootx, rooty;
   1267     unsigned int mask;		/* XQueryPointer */
   1268     Window root, subw;
   1269 
   1270     TRACE(("TekEnqMouse\n"));
   1271     XQueryPointer(
   1272 		     XtDisplay(tw), TWindow(tekscr),
   1273 		     &root, &subw,
   1274 		     &rootx, &rooty,
   1275 		     &mousex, &mousey,
   1276 		     &mask);
   1277     if ((mousex = (int) ((mousex - BorderOf(tw)) / ScaleOf(tw))) < 0)
   1278 	mousex = 0;
   1279     else if (mousex >= TEKWIDTH)
   1280 	mousex = TEKWIDTH - 1;
   1281     if ((mousey = (int) BottomY((mousey - BorderOf(tw)) / ScaleOf(tw))) < 0)
   1282 	mousey = 0;
   1283     else if (mousey >= TEKHEIGHT)
   1284 	mousey = TEKHEIGHT - 1;
   1285     TekEnq(tw, (unsigned) c, mousex, mousey);
   1286 }
   1287 
   1288 static void
   1289 TekEnq(TekWidget tw,
   1290        unsigned status,
   1291        int x,
   1292        int y)
   1293 {
   1294     TScreen *screen = TScreenOf(tw->vt);
   1295     TekScreen *tekscr = TekScreenOf(tw);
   1296     Char cplot[7];
   1297     int len = 5;
   1298     int adj = (status != 0) ? 0 : 1;
   1299 
   1300     TRACE(("TekEnq\n"));
   1301     cplot[0] = (Char) status;
   1302     /* Translate x and y to Tektronix code */
   1303     cplot[1] = (Char) (040 | ((x >> SHIFTHI) & FIVEBITS));
   1304     cplot[2] = (Char) (040 | ((x >> SHIFTLO) & FIVEBITS));
   1305     cplot[3] = (Char) (040 | ((y >> SHIFTHI) & FIVEBITS));
   1306     cplot[4] = (Char) (040 | ((y >> SHIFTLO) & FIVEBITS));
   1307 
   1308     if (tekscr->gin_terminator != GIN_TERM_NONE)
   1309 	cplot[len++] = '\r';
   1310     if (tekscr->gin_terminator == GIN_TERM_EOT)
   1311 	cplot[len++] = '\004';
   1312     v_write(screen->respond, cplot + adj, (size_t) (len - adj));
   1313 }
   1314 
   1315 void
   1316 TekRun(void)
   1317 {
   1318     XtermWidget xw = term;
   1319 
   1320     assert(xw != NULL);
   1321     if (tekWidget == NULL) {
   1322 	TekInit();
   1323     }
   1324     if (tekWidget != NULL) {
   1325 	TRACE(("TekRun ...\n"));
   1326 
   1327 	if (!TEK4014_SHOWN(xw) && !resource.notMapped) {
   1328 	    set_tek_visibility(True);
   1329 	}
   1330 	update_vttekmode();
   1331 	update_vtshow();
   1332 	update_tekshow();
   1333 	set_tekhide_sensitivity();
   1334 
   1335 	Tpushback = Tpushb;
   1336 	Ttoggled = True;
   1337 	if (!setjmp(Tekend))
   1338 	    Tekparse(tekWidget);
   1339 	if (!Ttoggled) {
   1340 	    TCursorToggle(tekWidget, TOGGLE);
   1341 	    Ttoggled = True;
   1342 	}
   1343 	TEK4014_ACTIVE(xw) = False;
   1344 	xtermSetWinSize(xw);
   1345     } else {
   1346 	TEK4014_ACTIVE(xw) = False;
   1347 	if (VWindow(TScreenOf(xw)) == 0) {
   1348 	    Exit(ERROR_TINIT);
   1349 	}
   1350     }
   1351 }
   1352 
   1353 #define DOTTED_LENGTH 2
   1354 #define DOT_DASHED_LENGTH 4
   1355 #define SHORT_DASHED_LENGTH 2
   1356 #define LONG_DASHED_LENGTH 2
   1357 
   1358 static const int dash_length[TEKNUMLINES] =
   1359 {
   1360     DOTTED_LENGTH,
   1361     DOT_DASHED_LENGTH,
   1362     SHORT_DASHED_LENGTH,
   1363     LONG_DASHED_LENGTH,
   1364 };
   1365 
   1366 static _Xconst char dotted[DOTTED_LENGTH] =
   1367 {3, 1};
   1368 static _Xconst char dot_dashed[DOT_DASHED_LENGTH] =
   1369 {3, 4, 3, 1};
   1370 static _Xconst char short_dashed[SHORT_DASHED_LENGTH] =
   1371 {4, 4};
   1372 static _Xconst char long_dashed[LONG_DASHED_LENGTH] =
   1373 {4, 7};
   1374 
   1375 static _Xconst char *dashes[TEKNUMLINES] =
   1376 {
   1377     dotted,
   1378     dot_dashed,
   1379     short_dashed,
   1380     long_dashed,
   1381 };
   1382 
   1383 /*
   1384  * The following functions are called to initialize and realize the tekWidget
   1385  */
   1386 static void
   1387 TekInitialize(Widget wrequest,
   1388 	      Widget new_arg,
   1389 	      ArgList args,
   1390 	      Cardinal *num_args)
   1391 {
   1392     XtermWidget xw = term;
   1393     TScreen *vtscr = TScreenOf(xw);
   1394 
   1395     TekWidget request = (TekWidget) wrequest;
   1396     TekWidget wnew = (TekWidget) new_arg;
   1397 
   1398     Widget tekparent = SHELL_OF(wnew);
   1399     TekScreen *tekscr = TekScreenOf((TekWidget) wnew);
   1400 
   1401     int i;
   1402     int border;
   1403     int pr;
   1404     int winX, winY;
   1405     unsigned min_width, min_height;
   1406     unsigned width, height;
   1407     char Tdefault[32];
   1408 
   1409     (void) args;
   1410     (void) num_args;
   1411 
   1412     TRACE(("TekInitialize " TRACE_L "\n"));
   1413     memset(tekscr, 0, sizeof(*tekscr));
   1414 
   1415     /*
   1416      * Eliminate 'term' as global from other functions.
   1417      */
   1418     wnew->vt = xw;
   1419     border = 2 * BorderOf(wnew);
   1420     TRACE(("... border*2: %d\n", border));
   1421 
   1422     /* look for focus related events on the shell, because we need
   1423      * to care about the shell's border being part of our focus.
   1424      */
   1425     XtAddEventHandler(tekparent, EnterWindowMask, False,
   1426 		      HandleEnterWindow, (Opaque) 0);
   1427     XtAddEventHandler(tekparent, LeaveWindowMask, False,
   1428 		      HandleLeaveWindow, (Opaque) 0);
   1429     XtAddEventHandler(tekparent, FocusChangeMask, False,
   1430 		      HandleFocusChange, (Opaque) 0);
   1431     XtAddEventHandler(new_arg, PropertyChangeMask, False,
   1432 		      HandleBellPropertyChange, (Opaque) 0);
   1433 
   1434 #ifndef NO_ACTIVE_ICON
   1435     tekscr->whichTwin = &(tekscr->fullTwin);
   1436 #endif /* NO_ACTIVE_ICON */
   1437 
   1438     init_Sres(tek.initial_font);
   1439     init_Sres(tek.gin_terminator_str);
   1440 #if OPT_TOOLBAR
   1441     init_Ires(tek.tb_info.menu_height);
   1442     wnew->tek.tb_info.menu_bar = request->tek.tb_info.menu_bar;
   1443 #endif
   1444 
   1445     BorderPixel(wnew) = BorderPixel(xw);
   1446 
   1447     tekscr->arrow = make_colored_cursor(XC_left_ptr,
   1448 					T_COLOR(vtscr, MOUSE_FG),
   1449 					T_COLOR(vtscr, MOUSE_BG));
   1450 
   1451     for (i = 0; i < TEKNUMFONTS; i++) {
   1452 	if (!wnew->tek.Tfont[i]) {
   1453 	    wnew->tek.Tfont[i] = XQueryFont(XtDisplay(wnew), DefaultGCID(wnew));
   1454 	}
   1455 	if (wnew->tek.Tfont[i]) {
   1456 	    TRACE(("Tfont[%d] %dx%d\n",
   1457 		   i,
   1458 		   wnew->tek.Tfont[i]->max_bounds.width,
   1459 		   wnew->tek.Tfont[i]->ascent +
   1460 		   wnew->tek.Tfont[i]->descent));
   1461 	    wnew->tek.tobaseline[i] = wnew->tek.Tfont[i]->ascent;
   1462 	} else {
   1463 	    TRACE(("Tfont[%d] disabled\n", i));
   1464 	    SetItemSensitivity(tekMenuEntries[i].widget, False);
   1465 	}
   1466     }
   1467 
   1468     if (xw->misc.T_geometry == NULL) {
   1469 	int def_width, def_height;
   1470 
   1471 	if (xw->misc.tekSmall) {
   1472 	    def_width = TEKMINWIDTH;
   1473 	    def_height = TEKMINHEIGHT;
   1474 	} else {
   1475 	    def_width = TEKDEFWIDTH;
   1476 	    def_height = TEKDEFHEIGHT;
   1477 	}
   1478 	sprintf(Tdefault, "=%dx%d", def_width + border, def_height + border);
   1479 	xw->misc.T_geometry = Tdefault;
   1480     }
   1481 
   1482     winX = 1;
   1483     winY = 1;
   1484     width = (unsigned) (TEKDEFWIDTH + border);
   1485     height = (unsigned) (TEKDEFHEIGHT + border);
   1486     min_width = (unsigned) (TEKMINWIDTH + border);
   1487     min_height = (unsigned) (TEKMINHEIGHT + border);
   1488 
   1489     TRACE(("parsing T_geometry %s\n", NonNull(xw->misc.T_geometry)));
   1490     if (strlen(xw->misc.T_geometry) <= MAX_U_STRING) {
   1491 	pr = XParseGeometry(xw->misc.T_geometry,
   1492 			    &winX,
   1493 			    &winY,
   1494 			    &width,
   1495 			    &height);
   1496     } else {
   1497 	pr = 0;
   1498     }
   1499 
   1500     /* window-manager hints will do this anyway... */
   1501     if (height < min_height) {
   1502 	TRACE(("... override height from %d to %d\n", height, min_height));
   1503 	height = min_height;
   1504     }
   1505     if (width < min_width) {
   1506 	TRACE(("... override width from %d to %d\n", width, min_width));
   1507 	width = min_width;
   1508     }
   1509 
   1510     TRACE(("... position %d,%d size %dx%d\n", winY, winX, height, width));
   1511     if ((pr & XValue) && (pr & XNegative)) {
   1512 	winX += DisplayWidth(XtDisplay(wnew), DefaultScreen(XtDisplay(wnew)))
   1513 	    - (int) width - (BorderWidth(SHELL_OF(xw)) * 2);
   1514     }
   1515     if ((pr & YValue) && (pr & YNegative)) {
   1516 	winY += DisplayHeight(XtDisplay(wnew), DefaultScreen(XtDisplay(wnew)))
   1517 	    - (int) height - (BorderWidth(SHELL_OF(xw)) * 2);
   1518     }
   1519 
   1520     /* set up size hints */
   1521 
   1522     /* *INDENT-EQLS* */
   1523     wnew->hints.min_width  = (int) min_width;
   1524     wnew->hints.min_height = (int) min_height;
   1525     wnew->hints.width_inc  = 1;
   1526     wnew->hints.height_inc = 1;
   1527     wnew->hints.flags      = PMinSize | PResizeInc;
   1528     wnew->hints.x          = winX;
   1529     wnew->hints.y          = winY;
   1530 
   1531     if ((XValue & pr) || (YValue & pr)) {
   1532 	wnew->hints.flags |= USSize | USPosition;
   1533 	wnew->hints.flags |= PWinGravity;
   1534 	switch (pr & (XNegative | YNegative)) {
   1535 	case 0:
   1536 	    wnew->hints.win_gravity = NorthWestGravity;
   1537 	    break;
   1538 	case XNegative:
   1539 	    wnew->hints.win_gravity = NorthEastGravity;
   1540 	    break;
   1541 	case YNegative:
   1542 	    wnew->hints.win_gravity = SouthWestGravity;
   1543 	    break;
   1544 	default:
   1545 	    wnew->hints.win_gravity = SouthEastGravity;
   1546 	    break;
   1547 	}
   1548     } else {
   1549 	/* set a default size, but do *not* set position */
   1550 	wnew->hints.flags |= PSize;
   1551     }
   1552     wnew->hints.width = (int) width;
   1553     wnew->hints.height = (int) height;
   1554     if ((WidthValue & pr) || (HeightValue & pr))
   1555 	wnew->hints.flags |= USSize;
   1556     else
   1557 	wnew->hints.flags |= PSize;
   1558 
   1559     tekscr->cur.fontsize = TEK_FONT_LARGE;
   1560     if (wnew->tek.initial_font) {
   1561 	int result = TekGetFontSize(wnew->tek.initial_font);
   1562 	if (result >= 0)
   1563 	    tekscr->cur.fontsize = result;
   1564     }
   1565     TRACE(("Tek cur.fontsize=%d\n", tekscr->cur.fontsize));
   1566 
   1567 #define TestGIN(s) XmuCompareISOLatin1(wnew->tek.gin_terminator_str, s)
   1568 
   1569     if (TestGIN(GIN_TERM_NONE_STR) == 0)
   1570 	tekscr->gin_terminator = GIN_TERM_NONE;
   1571     else if (TestGIN(GIN_TERM_CR_STR) == 0)
   1572 	tekscr->gin_terminator = GIN_TERM_CR;
   1573     else if (TestGIN(GIN_TERM_EOT_STR) == 0)
   1574 	tekscr->gin_terminator = GIN_TERM_EOT;
   1575     else
   1576 	xtermWarning("illegal GIN terminator setting \"%s\"\n",
   1577 		     wnew->tek.gin_terminator_str);
   1578     TRACE(("Tek gin_terminator=%d\n", tekscr->gin_terminator));
   1579 
   1580     TRACE((TRACE_R " TekInitialize\n"));
   1581 }
   1582 
   1583 static void
   1584 TekRealize(Widget gw,
   1585 	   XtValueMask * valuemaskp,
   1586 	   XSetWindowAttributes * values)
   1587 {
   1588     TekWidget tw = (TekWidget) gw;
   1589     TekScreen *tekscr = TekScreenOf(tw);
   1590     TScreen *vtscr = TScreenOf(tw->vt);
   1591 
   1592     int i;
   1593     TekLink *tek;
   1594     XGCValues gcv;
   1595     unsigned width, height;
   1596     unsigned long TEKgcFontMask;
   1597 
   1598     TRACE(("TekRealize " TRACE_L "\n"));
   1599 
   1600     if (!TekPtyData())
   1601 	return;
   1602 
   1603     /* use values from TekInitialize... */
   1604     height = (unsigned) tw->hints.height;
   1605     width = (unsigned) tw->hints.width;
   1606 
   1607     (void) REQ_RESIZE((Widget) tw,
   1608 		      (Dimension) width, (Dimension) height,
   1609 		      &tw->core.width, &tw->core.height);
   1610 
   1611     /* XXX This is bogus.  We are parsing geometries too late.  This
   1612      * is information that the shell widget ought to have before we get
   1613      * realized, so that it can do the right thing.
   1614      */
   1615     if (tw->hints.flags & USPosition)
   1616 	XMoveWindow(XtDisplay(tw), TShellWindow, tw->hints.x, tw->hints.y);
   1617 
   1618     XSetWMNormalHints(XtDisplay(tw), TShellWindow, &tw->hints);
   1619     XFlush(XtDisplay(tw));	/* get it out to window manager */
   1620 
   1621     values->win_gravity = NorthWestGravity;
   1622     values->background_pixel = T_COLOR(vtscr, TEK_BG);
   1623 
   1624     XtWindow(tw) = TWindow(tekscr) =
   1625 	XCreateWindow(XtDisplay(tw),
   1626 		      VShellWindow(tw),
   1627 		      tw->core.x, tw->core.y,
   1628 		      tw->core.width, tw->core.height,
   1629 		      BorderWidth(tw),
   1630 		      (int) tw->core.depth,
   1631 		      InputOutput, CopyFromParent,
   1632 		      ((*valuemaskp) | CWBackPixel | CWWinGravity),
   1633 		      values);
   1634 
   1635     compute_sizes(tw);
   1636 
   1637     gcv.graphics_exposures = True;	/* default */
   1638     gcv.font = tw->tek.Tfont[tekscr->cur.fontsize]->fid;
   1639     gcv.foreground = T_COLOR(vtscr, TEK_FG);
   1640     gcv.background = T_COLOR(vtscr, TEK_BG);
   1641 
   1642     /* if font wasn't successfully opened, then gcv.font will contain
   1643        the Default GC's ID, meaning that we must use the server default font.
   1644      */
   1645     TEKgcFontMask = (unsigned long) ((gcv.font == DefaultGCID(tw))
   1646 				     ? 0
   1647 				     : GCFont);
   1648     tekscr->TnormalGC = XCreateGC(XtDisplay(tw), TWindow(tekscr),
   1649 				  (TEKgcFontMask | GCGraphicsExposures |
   1650 				   GCForeground | GCBackground),
   1651 				  &gcv);
   1652 
   1653     gcv.function = GXinvert;
   1654     gcv.plane_mask = (T_COLOR(vtscr, TEK_BG) ^
   1655 		      T_COLOR(vtscr, TEK_CURSOR));
   1656     gcv.join_style = JoinMiter;	/* default */
   1657     gcv.line_width = 1;
   1658     tekscr->TcursorGC = XCreateGC(XtDisplay(tw), TWindow(tekscr),
   1659 				  (GCFunction | GCPlaneMask), &gcv);
   1660 
   1661     gcv.foreground = T_COLOR(vtscr, TEK_FG);
   1662     gcv.line_style = LineOnOffDash;
   1663     gcv.line_width = 0;
   1664     for (i = 0; i < TEKNUMLINES; i++) {
   1665 	tekscr->linepat[i] = XCreateGC(XtDisplay(tw), TWindow(tekscr),
   1666 				       (GCForeground | GCLineStyle), &gcv);
   1667 	XSetDashes(XtDisplay(tw), tekscr->linepat[i], 0,
   1668 		   dashes[i], dash_length[i]);
   1669     }
   1670 
   1671     TekBackground(tw, vtscr);
   1672 
   1673     tekscr->margin = MARGIN1;	/* Margin 1             */
   1674     tekscr->TekGIN = NULL;	/* GIN off              */
   1675 
   1676     XDefineCursor(XtDisplay(tw), TWindow(tekscr), tekscr->arrow);
   1677 
   1678     {				/* there's gotta be a better way... */
   1679 	static char empty_string[1];
   1680 	static Arg args[] =
   1681 	{
   1682 	    {XtNtitle, (XtArgVal) NULL},
   1683 	    {XtNiconName, (XtArgVal) NULL},
   1684 	};
   1685 	char *icon_name = NULL;
   1686 	char *title = NULL;
   1687 	char *tek_icon_name = NULL;
   1688 	char *tek_title = NULL;
   1689 
   1690 	args[0].value = (XtArgVal) & icon_name;
   1691 	args[1].value = (XtArgVal) & title;
   1692 	XtGetValues(SHELL_OF(tw), args, 2);
   1693 
   1694 	if (IsEmpty(title)) {
   1695 	    title = empty_string;
   1696 	}
   1697 
   1698 	if (IsEmpty(icon_name)) {
   1699 	    icon_name = empty_string;
   1700 	}
   1701 
   1702 	TRACE(("TekShell title='%s', iconName='%s'\n", title, icon_name));
   1703 	tek_icon_name = XtMalloc((Cardinal) strlen(icon_name) + 7);
   1704 	strcpy(tek_icon_name, icon_name);
   1705 	strcat(tek_icon_name, "(Tek)");
   1706 	tek_title = XtMalloc((Cardinal) strlen(title) + 7);
   1707 	strcpy(tek_title, title);
   1708 	strcat(tek_title, "(Tek)");
   1709 	args[0].value = (XtArgVal) tek_icon_name;
   1710 	args[1].value = (XtArgVal) tek_title;
   1711 	TRACE(("Tek title='%s', iconName='%s'\n", tek_title, tek_icon_name));
   1712 	XtSetValues(SHELL_OF(tw), args, 2);
   1713 	XtFree(tek_icon_name);
   1714 	XtFree(tek_title);
   1715     }
   1716 
   1717     /* *INDENT-EQLS* */
   1718     tek           = TekRecord = &Tek0;
   1719     tek->next     = (TekLink *) 0;
   1720     tek->fontsize = (unsigned short) tekscr->cur.fontsize;
   1721     tek->count    = 0;
   1722     tek->ptr      = tek->data;
   1723     Tpushback     = Tpushb;
   1724     tekscr->cur_X = 0;
   1725     tekscr->cur_Y = TEKHOME;
   1726     line_pt       = Tline;
   1727     Ttoggled      = True;
   1728     tekscr->page  = tekscr->cur;
   1729 
   1730     TRACE((TRACE_R " TekRealize\n"));
   1731 }
   1732 
   1733 int
   1734 TekGetFontSize(const char *param)
   1735 {
   1736     int result;
   1737 
   1738     if (XmuCompareISOLatin1(param, "l") == 0 ||
   1739 	XmuCompareISOLatin1(param, "large") == 0)
   1740 	result = TEK_FONT_LARGE;
   1741     else if (XmuCompareISOLatin1(param, "2") == 0 ||
   1742 	     XmuCompareISOLatin1(param, "two") == 0)
   1743 	result = TEK_FONT_2;
   1744     else if (XmuCompareISOLatin1(param, "3") == 0 ||
   1745 	     XmuCompareISOLatin1(param, "three") == 0)
   1746 	result = TEK_FONT_3;
   1747     else if (XmuCompareISOLatin1(param, "s") == 0 ||
   1748 	     XmuCompareISOLatin1(param, "small") == 0)
   1749 	result = TEK_FONT_SMALL;
   1750     else
   1751 	result = -1;
   1752 
   1753     return result;
   1754 }
   1755 
   1756 void
   1757 TekSetFontSize(TekWidget tw, Bool fromMenu, int newitem)
   1758 {
   1759     if (tw != NULL) {
   1760 	TekScreen *tekscr = TekScreenOf(tw);
   1761 	int oldsize = tekscr->cur.fontsize;
   1762 	int newsize = MI2FS(newitem);
   1763 	Font fid;
   1764 
   1765 	TRACE(("TekSetFontSize(%d) size %d ->%d\n", newitem, oldsize, newsize));
   1766 	if (newsize < 0 || newsize >= TEKNUMFONTS) {
   1767 	    Bell(tw->vt, XkbBI_MinorError, 0);
   1768 	} else if (oldsize != newsize) {
   1769 	    if (!Ttoggled)
   1770 		TCursorToggle(tw, TOGGLE);
   1771 	    set_tekfont_menu_item(oldsize, False);
   1772 
   1773 	    tekscr->cur.fontsize = newsize;
   1774 	    TekSetWinSize(tw);
   1775 	    if (fromMenu)
   1776 		tekscr->page.fontsize = newsize;
   1777 
   1778 	    fid = tw->tek.Tfont[newsize]->fid;
   1779 	    if (fid == DefaultGCID(tw)) {
   1780 		/* we didn't succeed in opening a real font
   1781 		   for this size.  Instead, use server default. */
   1782 		XCopyGC(XtDisplay(tw),
   1783 			DefaultGC(XtDisplay(tw), DefaultScreen(XtDisplay(tw))),
   1784 			GCFont, tekscr->TnormalGC);
   1785 	    } else {
   1786 		XSetFont(XtDisplay(tw), tekscr->TnormalGC, fid);
   1787 	    }
   1788 
   1789 	    set_tekfont_menu_item(newsize, True);
   1790 	    if (!Ttoggled)
   1791 		TCursorToggle(tw, TOGGLE);
   1792 
   1793 	    if (fromMenu) {
   1794 		/* we'll get an exposure event after changing fontsize, so we
   1795 		 * have to clear the screen to avoid painting over the previous
   1796 		 * text.
   1797 		 */
   1798 		TekClear(tw);
   1799 	    }
   1800 	}
   1801     }
   1802 }
   1803 
   1804 void
   1805 ChangeTekColors(TekWidget tw, TScreen *screen, ScrnColors * pNew)
   1806 {
   1807     if (tw && screen) {
   1808 	TekScreen *tekscr = TekScreenOf(tw);
   1809 	XGCValues gcv;
   1810 	int i;
   1811 
   1812 	if (COLOR_DEFINED(pNew, TEK_FG)) {
   1813 	    T_COLOR(screen, TEK_FG) = COLOR_VALUE(pNew, TEK_FG);
   1814 	    TRACE(("... TEK_FG: %#lx\n", T_COLOR(screen, TEK_FG)));
   1815 	}
   1816 	if (COLOR_DEFINED(pNew, TEK_BG)) {
   1817 	    T_COLOR(screen, TEK_BG) = COLOR_VALUE(pNew, TEK_BG);
   1818 	    TRACE(("... TEK_BG: %#lx\n", T_COLOR(screen, TEK_BG)));
   1819 	}
   1820 	if (COLOR_DEFINED(pNew, TEK_CURSOR)) {
   1821 	    T_COLOR(screen, TEK_CURSOR) = COLOR_VALUE(pNew, TEK_CURSOR);
   1822 	    TRACE(("... TEK_CURSOR: %#lx\n", T_COLOR(screen, TEK_CURSOR)));
   1823 	} else {
   1824 	    T_COLOR(screen, TEK_CURSOR) = T_COLOR(screen, TEK_FG);
   1825 	    TRACE(("... TEK_CURSOR: %#lx\n", T_COLOR(screen, TEK_CURSOR)));
   1826 	}
   1827 
   1828 	XSetForeground(XtDisplay(tw), tekscr->TnormalGC,
   1829 		       T_COLOR(screen, TEK_FG));
   1830 	XSetBackground(XtDisplay(tw), tekscr->TnormalGC,
   1831 		       T_COLOR(screen, TEK_BG));
   1832 	if (BorderPixel(tw) == T_COLOR(screen, TEK_BG)) {
   1833 	    BorderPixel(tw) = T_COLOR(screen, TEK_FG);
   1834 	    BorderPixel(XtParent(tw)) = T_COLOR(screen, TEK_FG);
   1835 	    if (XtWindow(XtParent(tw)))
   1836 		XSetWindowBorder(XtDisplay(tw),
   1837 				 XtWindow(XtParent(tw)),
   1838 				 BorderPixel(tw));
   1839 	}
   1840 
   1841 	for (i = 0; i < TEKNUMLINES; i++) {
   1842 	    XSetForeground(XtDisplay(tw), tekscr->linepat[i],
   1843 			   T_COLOR(screen, TEK_FG));
   1844 	}
   1845 
   1846 	gcv.plane_mask = (T_COLOR(screen, TEK_BG) ^
   1847 			  T_COLOR(screen, TEK_CURSOR));
   1848 	XChangeGC(XtDisplay(tw), tekscr->TcursorGC, GCPlaneMask, &gcv);
   1849 	TekBackground(tw, screen);
   1850     }
   1851     return;
   1852 }
   1853 
   1854 void
   1855 TekReverseVideo(XtermWidget xw, TekWidget tw)
   1856 {
   1857     if (tw) {
   1858 	TScreen *screen = TScreenOf(xw);
   1859 	TekScreen *tekscr = TekScreenOf(tw);
   1860 	Pixel tmp;
   1861 	XGCValues gcv;
   1862 	int i;
   1863 
   1864 	EXCHANGE(T_COLOR(screen, TEK_FG), T_COLOR(screen, TEK_BG), tmp);
   1865 
   1866 	T_COLOR(screen, TEK_CURSOR) = T_COLOR(screen, TEK_FG);
   1867 
   1868 	XSetForeground(XtDisplay(tw), tekscr->TnormalGC, T_COLOR(screen, TEK_FG));
   1869 	XSetBackground(XtDisplay(tw), tekscr->TnormalGC, T_COLOR(screen, TEK_BG));
   1870 
   1871 	if (BorderPixel(tw) == T_COLOR(screen, TEK_BG)) {
   1872 	    BorderPixel(tw) = T_COLOR(screen, TEK_FG);
   1873 	    BorderPixel(XtParent(tw)) = T_COLOR(screen, TEK_FG);
   1874 	    if (XtWindow(XtParent(tw)))
   1875 		XSetWindowBorder(XtDisplay(tw),
   1876 				 XtWindow(XtParent(tw)),
   1877 				 BorderPixel(tw));
   1878 	}
   1879 
   1880 	for (i = 0; i < TEKNUMLINES; i++) {
   1881 	    XSetForeground(XtDisplay(tw), tekscr->linepat[i],
   1882 			   T_COLOR(screen, TEK_FG));
   1883 	}
   1884 
   1885 	gcv.plane_mask = (T_COLOR(screen, TEK_BG) ^
   1886 			  T_COLOR(screen, TEK_CURSOR));
   1887 	XChangeGC(XtDisplay(tw), tekscr->TcursorGC, GCPlaneMask, &gcv);
   1888 	TekBackground(tw, screen);
   1889     }
   1890 }
   1891 
   1892 static void
   1893 TekBackground(TekWidget tw, TScreen *screen)
   1894 {
   1895     TekScreen *tekscr = TekScreenOf(tw);
   1896 
   1897     if (TWindow(tekscr))
   1898 	XSetWindowBackground(XtDisplay(tw), TWindow(tekscr),
   1899 			     T_COLOR(screen, TEK_BG));
   1900 }
   1901 
   1902 /*
   1903  * Toggles cursor on or off at cursor position in screen.
   1904  */
   1905 void
   1906 TCursorToggle(TekWidget tw, int toggle)		/* TOGGLE or CLEAR */
   1907 {
   1908     TekScreen *tekscr;
   1909     XtermWidget xw;
   1910     int c, x, y;
   1911     unsigned cellwidth, cellheight;
   1912 
   1913     if (tw == NULL)
   1914 	return;
   1915     if ((tekscr = TekScreenOf(tw)) == NULL)
   1916 	return;
   1917     if ((xw = tw->vt) == NULL)
   1918 	return;
   1919     if (!TEK4014_SHOWN(xw))
   1920 	return;
   1921 
   1922     TRACE(("TCursorToggle %s\n", (toggle == TOGGLE) ? "toggle" : "clear"));
   1923     c = tekscr->cur.fontsize;
   1924     cellwidth = (unsigned) tw->tek.Tfont[c]->max_bounds.width;
   1925     cellheight = (unsigned) (tw->tek.Tfont[c]->ascent +
   1926 			     tw->tek.Tfont[c]->descent);
   1927 
   1928     x = (int) ScaledX(tw, tekscr->cur_X);
   1929     y = (int) ScaledY(tw, tekscr->cur_Y) - tw->tek.tobaseline[c];
   1930 
   1931     if (toggle == TOGGLE) {
   1932 	TScreen *screen = TScreenOf(xw);
   1933 	if (screen->select || screen->always_highlight)
   1934 	    XFillRectangle(XtDisplay(tw), TWindow(tekscr),
   1935 			   tekscr->TcursorGC, x, y,
   1936 			   cellwidth, cellheight);
   1937 	else {			/* fix to use different GC! */
   1938 	    XDrawRectangle(XtDisplay(tw), TWindow(tekscr),
   1939 			   tekscr->TcursorGC, x, y,
   1940 			   cellwidth - 1, cellheight - 1);
   1941 	}
   1942     } else {
   1943 	/* Clear the entire rectangle, even though we may only
   1944 	 * have drawn an outline.  This fits with our refresh
   1945 	 * scheme of redrawing the entire window on any expose
   1946 	 * event and is easier than trying to figure out exactly
   1947 	 * which part of the cursor needs to be erased.
   1948 	 */
   1949 	XClearArea(XtDisplay(tw), TWindow(tekscr), x, y,
   1950 		   cellwidth, cellheight, False);
   1951     }
   1952 }
   1953 
   1954 /*
   1955  * The Tektronix manual describes the PAGE/RESET button.  For PAGE:
   1956  *	Erases the display, resets to Alpha Mode and home position;
   1957  *	resets to Margin 1 and cancels Bypass condition.
   1958  * For the RESET function:
   1959  *	Entered with SHIFT held down; creates a "home" function,
   1960  *	resetting the Terminal to initial status; does not erase.
   1961  *
   1962  * The reset done here is different, changing the modes (which changes
   1963  * the line-type and font to default values) as well as erasing the screen
   1964  * (like PAGE).
   1965  */
   1966 void
   1967 TekSimulatePageButton(TekWidget tw, Bool reset)
   1968 {
   1969     if (tw != NULL) {
   1970 	TekScreen *tekscr = TekScreenOf(tw);
   1971 
   1972 	if (reset) {
   1973 	    memset(&tekscr->cur, 0, sizeof tekscr->cur);
   1974 	}
   1975 	tekRefreshList = (TekLink *) 0;
   1976 	TekPage(tw);
   1977 	tekscr->cur_X = 0;
   1978 	tekscr->cur_Y = TEKHOME;
   1979     }
   1980 }
   1981 
   1982 /* write copy of screen to a file */
   1983 
   1984 void
   1985 TekCopy(TekWidget tw)
   1986 {
   1987 #ifdef ALLOWLOGGING
   1988     if (tw != NULL) {
   1989 	TekScreen *tekscr = TekScreenOf(tw);
   1990 	TScreen *screen = TScreenOf(tw->vt);
   1991 
   1992 	TekLink *Tp;
   1993 	char buf[TIMESTAMP_LEN + 10];
   1994 	int tekcopyfd;
   1995 
   1996 	timestamp_filename(buf, "COPY");
   1997 	if (access(buf, F_OK) >= 0
   1998 	    && access(buf, W_OK) < 0) {
   1999 	    Bell(tw->vt, XkbBI_MinorError, 0);
   2000 	    return;
   2001 	}
   2002 	if (access(".", W_OK) < 0) {	/* can't write in directory */
   2003 	    Bell(tw->vt, XkbBI_MinorError, 0);
   2004 	    return;
   2005 	}
   2006 
   2007 	tekcopyfd = open_userfile(screen->uid, screen->gid, buf, False);
   2008 	if (tekcopyfd >= 0) {
   2009 	    char initbuf[5];
   2010 
   2011 	    sprintf(initbuf, "%c%c%c%c",
   2012 		    ANSI_ESC, (char) (tekscr->page.fontsize + '8'),
   2013 		    ANSI_ESC, (char) (tekscr->page.linetype + '`'));
   2014 	    IGNORE_RC(write(tekcopyfd, initbuf, (size_t) 4));
   2015 	    Tp = &Tek0;
   2016 	    do {
   2017 		IGNORE_RC(write(tekcopyfd, Tp->data, (size_t) Tp->count));
   2018 		Tp = Tp->next;
   2019 	    } while (Tp);
   2020 	    close(tekcopyfd);
   2021 	}
   2022     }
   2023 #else
   2024     (void) tw;
   2025 #endif /* ALLOWLOGGING */
   2026 }
   2027 
   2028 /*ARGSUSED*/
   2029 void
   2030 HandleGINInput(Widget w,
   2031 	       XEvent *event GCC_UNUSED,
   2032 	       String *param_list,
   2033 	       Cardinal *nparamsp)
   2034 {
   2035     TekWidget tw = getTekWidget(w);
   2036 
   2037     if (tw != NULL) {
   2038 	TekScreen *tekscr = TekScreenOf(tw);
   2039 
   2040 	if (tekscr->TekGIN && *nparamsp == 1) {
   2041 	    int c = param_list[0][0];
   2042 	    switch (c) {
   2043 	    case 'l':
   2044 	    case 'm':
   2045 	    case 'r':
   2046 	    case 'L':
   2047 	    case 'M':
   2048 	    case 'R':
   2049 		break;
   2050 	    default:
   2051 		Bell(tw->vt, XkbBI_MinorError, 0);	/* let them know they goofed */
   2052 		c = 'l';	/* provide a default */
   2053 	    }
   2054 	    TekEnqMouse(tw, c | 0x80);
   2055 	    TekGINoff(tw);
   2056 	} else {
   2057 	    Bell(tw->vt, XkbBI_MinorError, 0);
   2058 	}
   2059     }
   2060 }
   2061 
   2062 /*
   2063  * Check if the current widget, or any parent, is the "tek4014" widget.
   2064  */
   2065 TekWidget
   2066 getTekWidget(Widget w)
   2067 {
   2068     TekWidget tw;
   2069 
   2070     if (w == NULL) {
   2071 	tw = (TekWidget) CURRENT_EMU();
   2072 	if (!IsTekWidget(tw)) {
   2073 	    tw = NULL;
   2074 	}
   2075     } else if (IsTekWidget(w)) {
   2076 	tw = (TekWidget) w;
   2077     } else {
   2078 	tw = getTekWidget(XtParent(w));
   2079     }
   2080     TRACE2(("getTekWidget %p -> %p\n", w, tw));
   2081     return tw;
   2082 }
   2083