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