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