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