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