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