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