Tekproc.c revision 5104ee6e
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* */
163static 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
176static Cursor GINcursor;
177static XSegment *line_pt;
178static int nplot;
179static TekLink Tek0;
180static jmp_buf Tekjump;
181static TekLink *TekRecord;
182static XSegment *Tline;
183
184static const int *curstate = Talptable;
185static const int *Tparsestate = Talptable;
186
187static 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* */
205static 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
251static 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
263static 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
281static IChar Tinput(TekWidget /* tw */ );
282static int getpoint(TekWidget /* tw */ );
283static void TCursorBack(TekWidget /* tw */ );
284static void TCursorDown(TekWidget /* tw */ );
285static void TCursorForward(TekWidget /* tw */ );
286static void TCursorUp(TekWidget /* tw */ );
287static void TekBackground(TekWidget /* tw */ ,
288			  TScreen * /* screen */ );
289static void TekResize(Widget /* w */ );
290static void TekDraw(TekWidget /* tw */ ,
291		    int /* x */ ,
292		    int /* y */ );
293static void TekEnq(TekWidget /* tw */ ,
294		   unsigned /* status */ ,
295		   int /* x */ ,
296		   int /* y */ );
297static void TekFlush(TekWidget /* tw */ );
298static void TekInitialize(Widget /* request */ ,
299			  Widget /* wnew */ ,
300			  ArgList /* args */ ,
301			  Cardinal * /* num_args */ );
302static void TekPage(TekWidget /* tw */ );
303static void TekRealize(Widget /* gw */ ,
304		       XtValueMask * /* valuemaskp */ ,
305		       XSetWindowAttributes * /* values */ );
306
307static 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};
345WidgetClass tekWidgetClass = (WidgetClass) & tekClassRec;
346
347static 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 */
354int
355TekInit(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 */
413static int
414TekPtyData(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
427static void
428Tekparse(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
789static int rcnt;
790static char *rptr;
791static PtySelect Tselect_mask;
792
793static IChar
794Tinput(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
879static void
880TekClear(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
891void
892TekSetWinSize(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
907static void
908compute_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
947static void
948TekResize(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*/
963void
964TekExpose(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
1002void
1003TekRefresh(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
1023void
1024TekRepaint(TekWidget tw)
1025{
1026    TRACE(("TekRepaint\n"));
1027    TekClear(tw);
1028    TekExpose((Widget) tw, (XEvent *) NULL, (Region) NULL);
1029}
1030
1031static void
1032TekPage(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
1071static int
1072getpoint(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
1119static void
1120TCursorBack(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
1138static void
1139TCursorForward(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
1155static void
1156TCursorUp(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
1175static void
1176TCursorDown(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
1195static void
1196AddToDraw(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
1213static void
1214TekDraw(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
1232static void
1233TekFlush(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
1247void
1248TekGINoff(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
1262void
1263TekEnqMouse(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
1288static void
1289TekEnq(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
1315void
1316TekRun(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
1358static const int dash_length[TEKNUMLINES] =
1359{
1360    DOTTED_LENGTH,
1361    DOT_DASHED_LENGTH,
1362    SHORT_DASHED_LENGTH,
1363    LONG_DASHED_LENGTH,
1364};
1365
1366static _Xconst char dotted[DOTTED_LENGTH] =
1367{3, 1};
1368static _Xconst char dot_dashed[DOT_DASHED_LENGTH] =
1369{3, 4, 3, 1};
1370static _Xconst char short_dashed[SHORT_DASHED_LENGTH] =
1371{4, 4};
1372static _Xconst char long_dashed[LONG_DASHED_LENGTH] =
1373{4, 7};
1374
1375static _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 */
1386static void
1387TekInitialize(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
1583static void
1584TekRealize(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
1733int
1734TekGetFontSize(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
1756void
1757TekSetFontSize(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
1804void
1805ChangeTekColors(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
1854void
1855TekReverseVideo(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
1892static void
1893TekBackground(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 */
1905void
1906TCursorToggle(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 */
1966void
1967TekSimulatePageButton(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
1984void
1985TekCopy(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*/
2029void
2030HandleGINInput(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 */
2065TekWidget
2066getTekWidget(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