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