1 /* $XTermId: charproc.c,v 1.1852 2021/11/12 22:10:53 tom Exp $ */
2 
3 /*
4  * Copyright 1999-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  *
33  * Copyright 1988  X Consortium
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 X Consortium 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 X Consortium.
54  *
55  */
56 /*
57  * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
58  *
59  *                         All Rights Reserved
60  *
61  * Permission to use, copy, modify, and distribute this software and its
62  * documentation for any purpose and without fee is hereby granted,
63  * provided that the above copyright notice appear in all copies and that
64  * both that copyright notice and this permission notice appear in
65  * supporting documentation, and that the name of Digital Equipment
66  * Corporation not be used in advertising or publicity pertaining to
67  * distribution of the software without specific, written prior permission.
68  *
69  *
70  * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
71  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
72  * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
73  * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
74  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
75  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
76  * SOFTWARE.
77  */
78 
79 /* charproc.c */
80 
81 #include <version.h>
82 #include <xterm.h>
83 
84 #include <X11/Xatom.h>
85 #include <X11/Xutil.h>
86 #include <X11/Xmu/Atoms.h>
87 #include <X11/Xmu/CharSet.h>
88 #include <X11/Xmu/Converters.h>
89 
90 #if OPT_INPUT_METHOD
91 
92 #if defined(HAVE_LIB_XAW)
93 #include <X11/Xaw/XawImP.h>
94 #elif defined(HAVE_LIB_XAW3D)
95 #include <X11/Xaw3d/XawImP.h>
96 #elif defined(HAVE_LIB_XAW3DXFT)
97 #include <X11/Xaw3dxft/XawImP.h>
98 #elif defined(HAVE_LIB_NEXTAW)
99 #include <X11/neXtaw/XawImP.h>
100 #elif defined(HAVE_LIB_XAWPLUS)
101 #include <X11/XawPlus/XawImP.h>
102 #endif
103 
104 #endif
105 
106 #if OPT_WIDE_CHARS
107 #include <xutf8.h>
108 #include <wcwidth.h>
109 #include <precompose.h>
110 #ifdef HAVE_LANGINFO_CODESET
111 #include <langinfo.h>
112 #endif
113 #endif
114 
115 #if USE_DOUBLE_BUFFER
116 #include <X11/extensions/Xdbe.h>
117 #endif
118 
119 #include <stdio.h>
120 #include <ctype.h>
121 #include <assert.h>
122 
123 #if defined(HAVE_SCHED_YIELD)
124 #include <sched.h>
125 #endif
126 
127 #include <VTparse.h>
128 #include <data.h>
129 #include <error.h>
130 #include <menu.h>
131 #include <main.h>
132 #include <fontutils.h>
133 #include <charclass.h>
134 #include <xstrings.h>
135 #include <graphics.h>
136 
137 #ifdef NO_LEAKS
138 #include <xtermcap.h>
139 #endif
140 
141 typedef int (*BitFunc) (unsigned * /* p */ ,
142 			unsigned /* mask */ );
143 
144 static IChar doinput(XtermWidget /* xw */ );
145 static int set_character_class(char * /*s */ );
146 static void FromAlternate(XtermWidget /* xw */ );
147 static void ReallyReset(XtermWidget /* xw */ ,
148 			Bool /* full */ ,
149 			Bool /* saved */ );
150 static void RequestResize(XtermWidget /* xw */ ,
151 			  int /* rows */ ,
152 			  int /* cols */ ,
153 			  Bool /* text */ );
154 static void SwitchBufs(XtermWidget /* xw */ ,
155 		       int /* toBuf */ ,
156 		       Bool /* clearFirst */ );
157 static void ToAlternate(XtermWidget /* xw */ ,
158 			Bool /* clearFirst */ );
159 static void ansi_modes(XtermWidget /* xw */ ,
160 		       BitFunc /* func */ );
161 static int bitclr(unsigned *p, unsigned mask);
162 static int bitcpy(unsigned *p, unsigned q, unsigned mask);
163 static int bitset(unsigned *p, unsigned mask);
164 static void dpmodes(XtermWidget /* xw */ ,
165 		    BitFunc /* func */ );
166 static void restoremodes(XtermWidget /* xw */ );
167 static void savemodes(XtermWidget /* xw */ );
168 static void window_ops(XtermWidget /* xw */ );
169 
170 #if OPT_BLINK_CURS || OPT_BLINK_TEXT
171 #define SettableCursorBlink(screen) \
172 	(((screen)->cursor_blink != cbAlways) && \
173 	 ((screen)->cursor_blink != cbNever))
174 #define UpdateCursorBlink(xw) \
175 	 SetCursorBlink(xw, TScreenOf(xw)->cursor_blink)
176 static void SetCursorBlink(XtermWidget /* xw */ ,
177 			   BlinkOps /* enable */ );
178 static void HandleBlinking(XtPointer /* closure */ ,
179 			   XtIntervalId * /* id */ );
180 static void StartBlinking(XtermWidget /* xw */ );
181 static void StopBlinking(XtermWidget /* xw */ );
182 #else
183 #define StartBlinking(xw)	/* nothing */
184 #define StopBlinking(xw)	/* nothing */
185 #endif
186 
187 #ifndef NO_ACTIVE_ICON
188 static Boolean discount_frame_extents(XtermWidget /* xw */ ,
189 				      int * /* height */ ,
190 				      int * /* width */ );
191 #else
192 #define discount_frame_extents(xw, height, width)	False
193 #endif
194 
195 #if OPT_INPUT_METHOD
196 static void PreeditPosition(XtermWidget /* xw */ );
197 #endif
198 
199 #define	DEFAULT		-1
200 #define BELLSUPPRESSMSEC 200
201 
202 static ANSI reply;
203 static PARAMS parms;
204 
205 #define nparam parms.count
206 
207 #define InitParams()  init_params()
208 #define GetParam(n)   parms.params[(n)]
209 #define SetParam(n,v) parms.params[(n)] = v
210 #define ParamPair(n)  nparam - (n), parms.params + (n)
211 
212 static jmp_buf vtjmpbuf;
213 
214 /* event handlers */
215 static void HandleBell PROTO_XT_ACTIONS_ARGS;
216 static void HandleIgnore PROTO_XT_ACTIONS_ARGS;
217 static void HandleKeymapChange PROTO_XT_ACTIONS_ARGS;
218 static void HandleVisualBell PROTO_XT_ACTIONS_ARGS;
219 #if HANDLE_STRUCT_NOTIFY
220 static void HandleStructNotify PROTO_XT_EV_HANDLER_ARGS;
221 #endif
222 
223 /*
224  * NOTE: VTInitialize zeros out the entire ".screen" component of the
225  * XtermWidget, so make sure to add an assignment statement in VTInitialize()
226  * for each new ".screen" field added to this resource list.
227  */
228 
229 /* Defaults */
230 #if OPT_ISO_COLORS
231 
232 /*
233  * If we default to colorMode enabled, compile-in defaults for the ANSI colors.
234  */
235 #if DFT_COLORMODE
236 #define DFT_COLOR(name) name
237 #else
238 #define DFT_COLOR(name) XtDefaultForeground
239 #endif
240 #endif
241 
242 static char _Font_Selected_[] = "yes";	/* string is arbitrary */
243 
244 static const char *defaultTranslations;
245 /* *INDENT-OFF* */
246 static XtActionsRec actionsList[] = {
247     { "allow-bold-fonts",	HandleAllowBoldFonts },
248     { "allow-send-events",	HandleAllowSends },
249     { "bell",			HandleBell },
250     { "clear-saved-lines",	HandleClearSavedLines },
251     { "copy-selection",		HandleCopySelection },
252     { "create-menu",		HandleCreateMenu },
253     { "delete-is-del",		HandleDeleteIsDEL },
254     { "dired-button",		DiredButton },
255     { "hard-reset",		HandleHardReset },
256     { "ignore",			HandleIgnore },
257     { "insert",			HandleKeyPressed },  /* alias for insert-seven-bit */
258     { "insert-eight-bit",	HandleEightBitKeyPressed },
259     { "insert-selection",	HandleInsertSelection },
260     { "insert-seven-bit",	HandleKeyPressed },
261     { "interpret",		HandleInterpret },
262     { "keymap",			HandleKeymapChange },
263     { "pointer-motion",		HandlePointerMotion },
264     { "pointer-button",		HandlePointerButton },
265     { "popup-menu",		HandlePopupMenu },
266     { "print",			HandlePrintScreen },
267     { "print-everything",	HandlePrintEverything },
268     { "print-redir",		HandlePrintControlMode },
269     { "quit",			HandleQuit },
270     { "redraw",			HandleRedraw },
271     { "scroll-back",		HandleScrollBack },
272     { "scroll-forw",		HandleScrollForward },
273     { "scroll-to",		HandleScrollTo },
274     { "secure",			HandleSecure },
275     { "select-cursor-end",	HandleKeyboardSelectEnd },
276     { "select-cursor-extend",   HandleKeyboardSelectExtend },
277     { "select-cursor-start",	HandleKeyboardSelectStart },
278     { "select-end",		HandleSelectEnd },
279     { "select-extend",		HandleSelectExtend },
280     { "select-set",		HandleSelectSet },
281     { "select-start",		HandleSelectStart },
282     { "send-signal",		HandleSendSignal },
283     { "set-8-bit-control",	Handle8BitControl },
284     { "set-allow132",		HandleAllow132 },
285     { "set-altscreen",		HandleAltScreen },
286     { "set-appcursor",		HandleAppCursor },
287     { "set-appkeypad",		HandleAppKeypad },
288     { "set-autolinefeed",	HandleAutoLineFeed },
289     { "set-autowrap",		HandleAutoWrap },
290     { "set-backarrow",		HandleBackarrow },
291     { "set-bellIsUrgent",	HandleBellIsUrgent },
292     { "set-cursesemul",		HandleCursesEmul },
293     { "set-jumpscroll",		HandleJumpscroll },
294     { "set-keep-clipboard",	HandleKeepClipboard },
295     { "set-keep-selection",	HandleKeepSelection },
296     { "set-marginbell",		HandleMarginBell },
297     { "set-old-function-keys",	HandleOldFunctionKeys },
298     { "set-pop-on-bell",	HandleSetPopOnBell },
299     { "set-reverse-video",	HandleReverseVideo },
300     { "set-reversewrap",	HandleReverseWrap },
301     { "set-scroll-on-key",	HandleScrollKey },
302     { "set-scroll-on-tty-output", HandleScrollTtyOutput },
303     { "set-scrollbar",		HandleScrollbar },
304     { "set-select",		HandleSetSelect },
305     { "set-sun-keyboard",	HandleSunKeyboard },
306     { "set-titeInhibit",	HandleTiteInhibit },
307     { "set-visual-bell",	HandleSetVisualBell },
308     { "set-vt-font",		HandleSetFont },
309     { "soft-reset",		HandleSoftReset },
310     { "start-cursor-extend",	HandleKeyboardStartExtend },
311     { "start-extend",		HandleStartExtend },
312     { "string",			HandleStringEvent },
313     { "vi-button",		ViButton },
314     { "visual-bell",		HandleVisualBell },
315 #ifdef ALLOWLOGGING
316     { "set-logging",		HandleLogging },
317 #endif
318 #if OPT_ALLOW_XXX_OPS
319     { "allow-color-ops",	HandleAllowColorOps },
320     { "allow-font-ops",		HandleAllowFontOps },
321     { "allow-mouse-ops",	HandleAllowMouseOps },
322     { "allow-tcap-ops",		HandleAllowTcapOps },
323     { "allow-title-ops",	HandleAllowTitleOps },
324     { "allow-window-ops",	HandleAllowWindowOps },
325 #endif
326 #if OPT_BLINK_CURS
327     { "set-cursorblink",	HandleCursorBlink },
328 #endif
329 #if OPT_BOX_CHARS
330     { "set-font-linedrawing",	HandleFontBoxChars },
331     { "set-font-packed",	HandleFontPacked },
332 #endif
333 #if OPT_DABBREV
334     { "dabbrev-expand",		HandleDabbrevExpand },
335 #endif
336 #if OPT_DEC_CHRSET
337     { "set-font-doublesize",	HandleFontDoublesize },
338 #endif
339 #if OPT_DEC_SOFTFONT
340     { "set-font-loading",	HandleFontLoading },
341 #endif
342 #if OPT_SCREEN_DUMPS
343     { "dump-html",	        HandleDumpHtml },
344     { "dump-svg",	        HandleDumpSvg },
345 #endif
346 #if OPT_EXEC_XTERM
347     { "spawn-new-terminal",	HandleSpawnTerminal },
348 #endif
349 #if OPT_HP_FUNC_KEYS
350     { "set-hp-function-keys",	HandleHpFunctionKeys },
351 #endif
352 #if OPT_LOAD_VTFONTS
353     { "load-vt-fonts",		HandleLoadVTFonts },
354 #endif
355 #if OPT_MAXIMIZE
356     { "deiconify",		HandleDeIconify },
357     { "fullscreen",		HandleFullscreen },
358     { "iconify",		HandleIconify },
359     { "maximize",		HandleMaximize },
360     { "restore",		HandleRestoreSize },
361 #endif
362 #if OPT_NUM_LOCK
363     { "alt-sends-escape",	HandleAltEsc },
364     { "meta-sends-escape",	HandleMetaEsc },
365     { "set-num-lock",		HandleNumLock },
366 #endif
367 #ifdef OPT_PRINT_ON_EXIT
368     { "print-immediate",	HandlePrintImmediate },
369     { "print-on-error",		HandlePrintOnError },
370 #endif
371 #if OPT_READLINE
372     { "readline-button",	ReadLineButton },
373 #endif
374 #if OPT_RENDERFONT
375     { "set-render-font",	HandleRenderFont },
376 #endif
377 #if OPT_SCO_FUNC_KEYS
378     { "set-sco-function-keys",	HandleScoFunctionKeys },
379 #endif
380 #if OPT_SCROLL_LOCK
381     { "scroll-lock",		HandleScrollLock },
382 #endif
383 #if OPT_SELECTION_OPS
384     { "exec-formatted",		HandleExecFormatted },
385     { "exec-selectable",	HandleExecSelectable },
386     { "insert-formatted",	HandleInsertFormatted },
387     { "insert-selectable",	HandleInsertSelectable },
388 #endif
389 #if OPT_SHIFT_FONTS
390     { "larger-vt-font",		HandleLargerFont },
391     { "smaller-vt-font",	HandleSmallerFont },
392 #endif
393 #if OPT_SIXEL_GRAPHICS
394     { "set-sixel-scrolling",	HandleSixelScrolling },
395 #endif
396 #if OPT_GRAPHICS
397     { "set-private-colors",	HandleSetPrivateColorRegisters },
398 #endif
399 #if OPT_SUN_FUNC_KEYS
400     { "set-sun-function-keys",	HandleSunFunctionKeys },
401 #endif
402 #if OPT_TEK4014
403     { "set-terminal-type",	HandleSetTerminalType },
404     { "set-visibility",		HandleVisibility },
405     { "set-tek-text",		HandleSetTekText },
406     { "tek-page",		HandleTekPage },
407     { "tek-reset",		HandleTekReset },
408     { "tek-copy",		HandleTekCopy },
409 #endif
410 #if OPT_TOOLBAR
411     { "set-toolbar",		HandleToolbar },
412 #endif
413 #if OPT_WIDE_CHARS
414     { "set-utf8-mode",		HandleUTF8Mode },
415     { "set-utf8-fonts",		HandleUTF8Fonts },
416     { "set-utf8-title",		HandleUTF8Title },
417 #endif
418 };
419 /* *INDENT-ON* */
420 
421 #define SPS screen.printer_state
422 
423 static XtResource xterm_resources[] =
424 {
425     Bres(XtNallowPasteControls, XtCAllowPasteControls,
426 	 screen.allowPasteControl0, False),
427     Bres(XtNallowSendEvents, XtCAllowSendEvents, screen.allowSendEvent0, False),
428     Bres(XtNallowColorOps, XtCAllowColorOps, screen.allowColorOp0, DEF_ALLOW_COLOR),
429     Bres(XtNallowFontOps, XtCAllowFontOps, screen.allowFontOp0, DEF_ALLOW_FONT),
430     Bres(XtNallowMouseOps, XtCAllowMouseOps, screen.allowMouseOp0, DEF_ALLOW_MOUSE),
431     Bres(XtNallowTcapOps, XtCAllowTcapOps, screen.allowTcapOp0, DEF_ALLOW_TCAP),
432     Bres(XtNallowTitleOps, XtCAllowTitleOps, screen.allowTitleOp0, DEF_ALLOW_TITLE),
433     Bres(XtNallowWindowOps, XtCAllowWindowOps, screen.allowWindowOp0, DEF_ALLOW_WINDOW),
434     Bres(XtNaltIsNotMeta, XtCAltIsNotMeta, screen.alt_is_not_meta, False),
435     Bres(XtNaltSendsEscape, XtCAltSendsEscape, screen.alt_sends_esc, DEF_ALT_SENDS_ESC),
436     Bres(XtNallowBoldFonts, XtCAllowBoldFonts, screen.allowBoldFonts, True),
437     Bres(XtNalwaysBoldMode, XtCAlwaysBoldMode, screen.always_bold_mode, False),
438     Bres(XtNalwaysHighlight, XtCAlwaysHighlight, screen.always_highlight, False),
439     Bres(XtNappcursorDefault, XtCAppcursorDefault, misc.appcursorDefault, False),
440     Bres(XtNappkeypadDefault, XtCAppkeypadDefault, misc.appkeypadDefault, False),
441     Bres(XtNalternateScroll, XtCScrollCond, screen.alternateScroll, False),
442     Bres(XtNautoWrap, XtCAutoWrap, misc.autoWrap, True),
443     Bres(XtNawaitInput, XtCAwaitInput, screen.awaitInput, False),
444     Bres(XtNfreeBoldBox, XtCFreeBoldBox, screen.free_bold_box, False),
445     Bres(XtNbackarrowKey, XtCBackarrowKey, screen.backarrow_key, DEF_BACKARO_BS),
446     Bres(XtNbellIsUrgent, XtCBellIsUrgent, screen.bellIsUrgent, False),
447     Bres(XtNbellOnReset, XtCBellOnReset, screen.bellOnReset, True),
448     Bres(XtNboldMode, XtCBoldMode, screen.bold_mode, True),
449     Bres(XtNbrokenSelections, XtCBrokenSelections, screen.brokenSelections, False),
450     Bres(XtNc132, XtCC132, screen.c132, False),
451     Sres(XtNcdXtraScroll, XtCCdXtraScroll, misc.cdXtraScroll_s, DEF_CD_XTRA_SCROLL),
452     Bres(XtNcolorInnerBorder, XtCColorInnerBorder, misc.color_inner_border, False),
453     Bres(XtNcurses, XtCCurses, screen.curses, False),
454     Bres(XtNcutNewline, XtCCutNewline, screen.cutNewline, True),
455     Bres(XtNcutToBeginningOfLine, XtCCutToBeginningOfLine,
456 	 screen.cutToBeginningOfLine, True),
457     Bres(XtNdeleteIsDEL, XtCDeleteIsDEL, screen.delete_is_del, DEFDELETE_DEL),
458     Bres(XtNdynamicColors, XtCDynamicColors, misc.dynamicColors, True),
459     Bres(XtNeightBitControl, XtCEightBitControl, screen.control_eight_bits, False),
460     Bres(XtNeightBitInput, XtCEightBitInput, screen.input_eight_bits, True),
461     Bres(XtNeightBitOutput, XtCEightBitOutput, screen.output_eight_bits, True),
462     Bres(XtNeraseSavedLines, XtCEraseSavedLines, screen.eraseSavedLines0, True),
463     Bres(XtNhighlightSelection, XtCHighlightSelection,
464 	 screen.highlight_selection, False),
465     Bres(XtNshowWrapMarks, XtCShowWrapMarks, screen.show_wrap_marks, False),
466     Bres(XtNhpLowerleftBugCompat, XtCHpLowerleftBugCompat, screen.hp_ll_bc, False),
467     Bres(XtNi18nSelections, XtCI18nSelections, screen.i18nSelections, True),
468     Bres(XtNfastScroll, XtCFastScroll, screen.fastscroll, False),
469     Bres(XtNjumpScroll, XtCJumpScroll, screen.jumpscroll, True),
470     Bres(XtNkeepClipboard, XtCKeepClipboard, screen.keepClipboard, False),
471     Bres(XtNkeepSelection, XtCKeepSelection, screen.keepSelection, True),
472     Bres(XtNloginShell, XtCLoginShell, misc.login_shell, False),
473     Bres(XtNmarginBell, XtCMarginBell, screen.marginbell, False),
474     Bres(XtNmetaSendsEscape, XtCMetaSendsEscape, screen.meta_sends_esc, DEF_META_SENDS_ESC),
475     Bres(XtNmultiScroll, XtCMultiScroll, screen.multiscroll, False),
476     Bres(XtNoldXtermFKeys, XtCOldXtermFKeys, screen.old_fkeys, False),
477     Bres(XtNpopOnBell, XtCPopOnBell, screen.poponbell, False),
478     Bres(XtNprinterAutoClose, XtCPrinterAutoClose, SPS.printer_autoclose, False),
479     Bres(XtNprinterExtent, XtCPrinterExtent, SPS.printer_extent, False),
480     Bres(XtNprinterFormFeed, XtCPrinterFormFeed, SPS.printer_formfeed, False),
481     Bres(XtNprinterNewLine, XtCPrinterNewLine, SPS.printer_newline, True),
482     Bres(XtNquietGrab, XtCQuietGrab, screen.quiet_grab, False),
483     Bres(XtNresizeByPixel, XtCResizeByPixel, misc.resizeByPixel, False),
484     Bres(XtNreverseVideo, XtCReverseVideo, misc.re_verse, False),
485     Bres(XtNreverseWrap, XtCReverseWrap, misc.reverseWrap, False),
486     Bres(XtNscrollBar, XtCScrollBar, misc.scrollbar, False),
487     Bres(XtNscrollKey, XtCScrollCond, screen.scrollkey, False),
488     Bres(XtNscrollTtyOutput, XtCScrollCond, screen.scrollttyoutput, True),
489     Bres(XtNselectToClipboard, XtCSelectToClipboard,
490 	 screen.selectToClipboard, False),
491     Bres(XtNsignalInhibit, XtCSignalInhibit, misc.signalInhibit, False),
492     Bres(XtNtiteInhibit, XtCTiteInhibit, misc.titeInhibit, False),
493     Sres(XtNtiXtraScroll, XtCTiXtraScroll, misc.tiXtraScroll_s, DEF_TI_XTRA_SCROLL),
494     Bres(XtNtrimSelection, XtCTrimSelection, screen.trim_selection, False),
495     Bres(XtNunderLine, XtCUnderLine, screen.underline, True),
496     Bres(XtNvisualBell, XtCVisualBell, screen.visualbell, False),
497     Bres(XtNvisualBellLine, XtCVisualBellLine, screen.flash_line, False),
498 
499     Dres(XtNscaleHeight, XtCScaleHeight, screen.scale_height, "1.0"),
500 
501     Ires(XtNbellSuppressTime, XtCBellSuppressTime, screen.bellSuppressTime, BELLSUPPRESSMSEC),
502     Ires(XtNfontWarnings, XtCFontWarnings, misc.fontWarnings, fwResource),
503     Ires(XtNinternalBorder, XtCBorderWidth, screen.border, DEFBORDER),
504     Ires(XtNlimitResize, XtCLimitResize, misc.limit_resize, 1),
505     Ires(XtNlimitResponse, XtCLimitResponse, screen.unparse_max, DEF_LIMIT_RESPONSE),
506     Ires(XtNmultiClickTime, XtCMultiClickTime, screen.multiClickTime, MULTICLICKTIME),
507     Ires(XtNnMarginBell, XtCColumn, screen.nmarginbell, N_MARGINBELL),
508     Ires(XtNpointerMode, XtCPointerMode, screen.pointer_mode, DEF_POINTER_MODE),
509     Ires(XtNprinterControlMode, XtCPrinterControlMode,
510 	 SPS.printer_controlmode, 0),
511     Ires(XtNtitleModes, XtCTitleModes, screen.title_modes, DEF_TITLE_MODES),
512     Ires(XtNnextEventDelay, XtCNextEventDelay, screen.nextEventDelay, 1),
513     Ires(XtNvisualBellDelay, XtCVisualBellDelay, screen.visualBellDelay, 100),
514     Ires(XtNsaveLines, XtCSaveLines, screen.savelines, DEF_SAVE_LINES),
515     Ires(XtNscrollBarBorder, XtCScrollBarBorder, screen.scrollBarBorder, 1),
516     Ires(XtNscrollLines, XtCScrollLines, screen.scrolllines, DEF_SCROLL_LINES),
517 
518     Sres(XtNinitialFont, XtCInitialFont, screen.initial_font, NULL),
519     Sres(XtNfont1, XtCFont1, screen.MenuFontName(fontMenu_font1), NULL),
520     Sres(XtNfont2, XtCFont2, screen.MenuFontName(fontMenu_font2), NULL),
521     Sres(XtNfont3, XtCFont3, screen.MenuFontName(fontMenu_font3), NULL),
522     Sres(XtNfont4, XtCFont4, screen.MenuFontName(fontMenu_font4), NULL),
523     Sres(XtNfont5, XtCFont5, screen.MenuFontName(fontMenu_font5), NULL),
524     Sres(XtNfont6, XtCFont6, screen.MenuFontName(fontMenu_font6), NULL),
525     Sres(XtNfont7, XtCFont7, screen.MenuFontName(fontMenu_font7), NULL),
526 
527     Sres(XtNanswerbackString, XtCAnswerbackString, screen.answer_back, ""),
528     Sres(XtNboldFont, XtCBoldFont, misc.default_font.f_b, DEFBOLDFONT),
529     Sres(XtNcharClass, XtCCharClass, screen.charClass, NULL),
530     Sres(XtNdecTerminalID, XtCDecTerminalID, screen.term_id, DFT_DECID),
531     Sres(XtNdefaultString, XtCDefaultString, screen.default_string, "#"),
532     Sres(XtNdisallowedColorOps, XtCDisallowedColorOps,
533 	 screen.disallowedColorOps, DEF_DISALLOWED_COLOR),
534     Sres(XtNdisallowedFontOps, XtCDisallowedFontOps,
535 	 screen.disallowedFontOps, DEF_DISALLOWED_FONT),
536     Sres(XtNdisallowedMouseOps, XtCDisallowedMouseOps,
537 	 screen.disallowedMouseOps, DEF_DISALLOWED_MOUSE),
538     Sres(XtNdisallowedPasteControls, XtCDisallowedPasteControls,
539 	 screen.disallowedPasteControls, DEF_DISALLOWED_PASTE_CONTROLS),
540     Sres(XtNdisallowedTcapOps, XtCDisallowedTcapOps,
541 	 screen.disallowedTcapOps, DEF_DISALLOWED_TCAP),
542     Sres(XtNdisallowedWindowOps, XtCDisallowedWindowOps,
543 	 screen.disallowedWinOps, DEF_DISALLOWED_WINDOW),
544     Sres(XtNeightBitMeta, XtCEightBitMeta, screen.eight_bit_meta_s, DEF_8BIT_META),
545     Sres(XtNeightBitSelectTypes, XtCEightBitSelectTypes,
546 	 screen.eightbit_select_types, NULL),
547     Sres(XtNfont, XtCFont, misc.default_font.f_n, DEFFONT),
548     Sres(XtNgeometry, XtCGeometry, misc.geo_metry, NULL),
549     Sres(XtNkeyboardDialect, XtCKeyboardDialect, screen.keyboard_dialect, DFT_KBD_DIALECT),
550     Sres(XtNprinterCommand, XtCPrinterCommand, SPS.printer_command, ""),
551     Sres(XtNtekGeometry, XtCGeometry, misc.T_geometry, NULL),
552     Sres(XtNpointerFont, XtCPointerFont, screen.cursor_font_name, NULL),
553 
554     Tres(XtNcursorColor, XtCCursorColor, TEXT_CURSOR, XtDefaultForeground),
555     Tres(XtNforeground, XtCForeground, TEXT_FG, XtDefaultForeground),
556     Tres(XtNpointerColor, XtCPointerColor, MOUSE_FG, XtDefaultForeground),
557     Tres(XtNbackground, XtCBackground, TEXT_BG, XtDefaultBackground),
558     Tres(XtNpointerColorBackground, XtCBackground, MOUSE_BG, XtDefaultBackground),
559 
560     {XtNresizeGravity, XtCResizeGravity, XtRGravity, sizeof(XtGravity),
561      XtOffsetOf(XtermWidgetRec, misc.resizeGravity),
562      XtRImmediate, (XtPointer) SouthWestGravity},
563 
564     Sres(XtNpointerShape, XtCCursor, screen.pointer_shape, "xterm"),
565 
566 #ifdef ALLOWLOGGING
567     Bres(XtNlogInhibit, XtCLogInhibit, misc.logInhibit, False),
568     Bres(XtNlogging, XtCLogging, misc.log_on, False),
569     Sres(XtNlogFile, XtCLogfile, screen.logfile, NULL),
570 #endif
571 
572 #ifndef NO_ACTIVE_ICON
573     Sres("activeIcon", "ActiveIcon", misc.active_icon_s, "default"),
574     Ires("iconBorderWidth", XtCBorderWidth, misc.icon_border_width, 2),
575     Sres("iconFont", "IconFont", screen.icon_fontname, "nil2"),
576     Cres("iconBorderColor", XtCBorderColor, misc.icon_border_pixel, XtDefaultBackground),
577 #endif				/* NO_ACTIVE_ICON */
578 
579 #if OPT_BLINK_CURS
580     Bres(XtNcursorBlinkXOR, XtCCursorBlinkXOR, screen.cursor_blink_xor, True),
581     Sres(XtNcursorBlink, XtCCursorBlink, screen.cursor_blink_s, "false"),
582 #endif
583     Bres(XtNcursorUnderLine, XtCCursorUnderLine, screen.cursor_underline, False),
584 
585 #if OPT_BLINK_TEXT
586     Bres(XtNshowBlinkAsBold, XtCCursorBlink, screen.blink_as_bold, DEFBLINKASBOLD),
587 #endif
588 
589 #if OPT_BLINK_CURS || OPT_BLINK_TEXT
590     Ires(XtNcursorOnTime, XtCCursorOnTime, screen.blink_on, 600),
591     Ires(XtNcursorOffTime, XtCCursorOffTime, screen.blink_off, 300),
592 #endif
593 
594 #if OPT_BOX_CHARS
595     Bres(XtNforceBoxChars, XtCForceBoxChars, screen.force_box_chars, False),
596     Bres(XtNforcePackedFont, XtCForcePackedFont, screen.force_packed, True),
597     Bres(XtNshowMissingGlyphs, XtCShowMissingGlyphs, screen.force_all_chars, False),
598     Bres(XtNassumeAllChars, XtCAssumeAllChars, screen.assume_all_chars, True),
599 #endif
600 
601 #if OPT_BROKEN_OSC
602     Bres(XtNbrokenLinuxOSC, XtCBrokenLinuxOSC, screen.brokenLinuxOSC, True),
603 #endif
604 
605 #if OPT_BROKEN_ST
606     Bres(XtNbrokenStringTerm, XtCBrokenStringTerm, screen.brokenStringTerm, False),
607 #endif
608 
609 #if OPT_C1_PRINT
610     Bres(XtNallowC1Printable, XtCAllowC1Printable, screen.c1_printable, False),
611 #endif
612 
613 #if OPT_CLIP_BOLD
614     Bres(XtNuseClipping, XtCUseClipping, screen.use_clipping, True),
615     Bres(XtNuseBorderClipping, XtCUseBorderClipping,
616 	 screen.use_border_clipping, False),
617 #endif
618 
619 #if OPT_DEC_CHRSET
620     Bres(XtNfontDoublesize, XtCFontDoublesize, screen.font_doublesize, True),
621     Ires(XtNcacheDoublesize, XtCCacheDoublesize, screen.cache_doublesize, NUM_CHRSET),
622 #endif
623 
624 #if OPT_DEC_RECTOPS
625     Ires(XtNchecksumExtension, XtCChecksumExtension, screen.checksum_ext0, csDEC),
626 #endif
627 
628 #if OPT_HIGHLIGHT_COLOR
629     Tres(XtNhighlightColor, XtCHighlightColor, HIGHLIGHT_BG, XtDefaultForeground),
630     Tres(XtNhighlightTextColor, XtCHighlightTextColor, HIGHLIGHT_FG, XtDefaultBackground),
631     Bres(XtNhighlightReverse, XtCHighlightReverse, screen.hilite_reverse, True),
632     Bres(XtNhighlightColorMode, XtCHighlightColorMode, screen.hilite_color, Maybe),
633 #endif				/* OPT_HIGHLIGHT_COLOR */
634 
635 #if OPT_INPUT_METHOD
636     Bres(XtNopenIm, XtCOpenIm, misc.open_im, True),
637     Sres(XtNinputMethod, XtCInputMethod, misc.input_method, NULL),
638     Sres(XtNpreeditType, XtCPreeditType, misc.preedit_type,
639 	 "OverTheSpot,Root"),
640     Ires(XtNretryInputMethod, XtCRetryInputMethod, misc.retry_im, 3),
641 #endif
642 
643 #if OPT_ISO_COLORS
644     Bres(XtNboldColors, XtCColorMode, screen.boldColors, True),
645     Ires(XtNveryBoldColors, XtCVeryBoldColors, screen.veryBoldColors, 0),
646     Bres(XtNcolorMode, XtCColorMode, screen.colorMode, DFT_COLORMODE),
647 
648     Bres(XtNcolorAttrMode, XtCColorAttrMode, screen.colorAttrMode, False),
649     Bres(XtNcolorBDMode, XtCColorAttrMode, screen.colorBDMode, False),
650     Bres(XtNcolorBLMode, XtCColorAttrMode, screen.colorBLMode, False),
651     Bres(XtNcolorRVMode, XtCColorAttrMode, screen.colorRVMode, False),
652     Bres(XtNcolorULMode, XtCColorAttrMode, screen.colorULMode, False),
653     Bres(XtNitalicULMode, XtCColorAttrMode, screen.italicULMode, False),
654 #if OPT_WIDE_ATTRS
655     Bres(XtNcolorITMode, XtCColorAttrMode, screen.colorITMode, False),
656 #endif
657 #if OPT_DIRECT_COLOR
658     Bres(XtNdirectColor, XtCDirectColor, screen.direct_color, True),
659 #endif
660 
661     COLOR_RES("0", screen.Acolors[COLOR_0], DFT_COLOR("black")),
662     COLOR_RES("1", screen.Acolors[COLOR_1], DFT_COLOR("red3")),
663     COLOR_RES("2", screen.Acolors[COLOR_2], DFT_COLOR("green3")),
664     COLOR_RES("3", screen.Acolors[COLOR_3], DFT_COLOR("yellow3")),
665     COLOR_RES("4", screen.Acolors[COLOR_4], DFT_COLOR(DEF_COLOR4)),
666     COLOR_RES("5", screen.Acolors[COLOR_5], DFT_COLOR("magenta3")),
667     COLOR_RES("6", screen.Acolors[COLOR_6], DFT_COLOR("cyan3")),
668     COLOR_RES("7", screen.Acolors[COLOR_7], DFT_COLOR("gray90")),
669     COLOR_RES("8", screen.Acolors[COLOR_8], DFT_COLOR("gray50")),
670     COLOR_RES("9", screen.Acolors[COLOR_9], DFT_COLOR("red")),
671     COLOR_RES("10", screen.Acolors[COLOR_10], DFT_COLOR("green")),
672     COLOR_RES("11", screen.Acolors[COLOR_11], DFT_COLOR("yellow")),
673     COLOR_RES("12", screen.Acolors[COLOR_12], DFT_COLOR(DEF_COLOR12)),
674     COLOR_RES("13", screen.Acolors[COLOR_13], DFT_COLOR("magenta")),
675     COLOR_RES("14", screen.Acolors[COLOR_14], DFT_COLOR("cyan")),
676     COLOR_RES("15", screen.Acolors[COLOR_15], DFT_COLOR("white")),
677     COLOR_RES("BD", screen.Acolors[COLOR_BD], DFT_COLOR(XtDefaultForeground)),
678     COLOR_RES("BL", screen.Acolors[COLOR_BL], DFT_COLOR(XtDefaultForeground)),
679     COLOR_RES("UL", screen.Acolors[COLOR_UL], DFT_COLOR(XtDefaultForeground)),
680     COLOR_RES("RV", screen.Acolors[COLOR_RV], DFT_COLOR(XtDefaultForeground)),
681 
682 #if OPT_WIDE_ATTRS
683     COLOR_RES("IT", screen.Acolors[COLOR_IT], DFT_COLOR(XtDefaultForeground)),
684 #endif
685 
686 #endif				/* OPT_ISO_COLORS */
687 
688     CLICK_RES("2", screen.onClick[1], "word"),
689     CLICK_RES("3", screen.onClick[2], "line"),
690     CLICK_RES("4", screen.onClick[3], 0),
691     CLICK_RES("5", screen.onClick[4], 0),
692 
693     Sres(XtNshiftEscape, XtCShiftEscape, keyboard.shift_escape_s, "false"),
694 
695 #if OPT_MOD_FKEYS
696     Ires(XtNmodifyKeyboard, XtCModifyKeyboard,
697 	 keyboard.modify_1st.allow_keys, 0),
698     Ires(XtNmodifyCursorKeys, XtCModifyCursorKeys,
699 	 keyboard.modify_1st.cursor_keys, 2),
700     Ires(XtNmodifyFunctionKeys, XtCModifyFunctionKeys,
701 	 keyboard.modify_1st.function_keys, 2),
702     Ires(XtNmodifyKeypadKeys, XtCModifyKeypadKeys,
703 	 keyboard.modify_1st.keypad_keys, 0),
704     Ires(XtNmodifyOtherKeys, XtCModifyOtherKeys,
705 	 keyboard.modify_1st.other_keys, 0),
706     Ires(XtNmodifyStringKeys, XtCModifyStringKeys,
707 	 keyboard.modify_1st.string_keys, 0),
708     Ires(XtNformatOtherKeys, XtCFormatOtherKeys,
709 	 keyboard.format_keys, 0),
710 #endif
711 
712 #if OPT_NUM_LOCK
713     Bres(XtNalwaysUseMods, XtCAlwaysUseMods, misc.alwaysUseMods, False),
714     Bres(XtNnumLock, XtCNumLock, misc.real_NumLock, True),
715 #endif
716 
717 #if OPT_PRINT_COLORS
718     Ires(XtNprintAttributes, XtCPrintAttributes, SPS.print_attributes, 1),
719 #endif
720 
721 #if OPT_REGIS_GRAPHICS
722     Sres(XtNregisDefaultFont, XtCRegisDefaultFont,
723 	 screen.graphics_regis_default_font, ""),
724     Sres(XtNregisScreenSize, XtCRegisScreenSize,
725 	 screen.graphics_regis_screensize, "auto"),
726 #endif
727 
728 #if OPT_GRAPHICS
729     Sres(XtNdecGraphicsID, XtCDecGraphicsID, screen.graph_termid, DFT_DECID),
730     Sres(XtNmaxGraphicSize, XtCMaxGraphicSize, screen.graphics_max_size,
731 	 "1000x1000"),
732 #endif
733 
734 #if OPT_SHIFT_FONTS
735     Bres(XtNshiftFonts, XtCShiftFonts, misc.shift_fonts, True),
736 #endif
737 
738 #if OPT_SIXEL_GRAPHICS
739     Bres(XtNsixelScrolling, XtCSixelScrolling, screen.sixel_scrolling, False),
740     Bres(XtNsixelScrollsRight, XtCSixelScrollsRight,
741 	 screen.sixel_scrolls_right, False),
742 #endif
743 
744 #if OPT_GRAPHICS
745     Ires(XtNnumColorRegisters, XtCNumColorRegisters,
746 	 screen.numcolorregisters, 0),
747     Bres(XtNprivateColorRegisters, XtCPrivateColorRegisters,
748 	 screen.privatecolorregisters, True),
749 #endif
750 
751 #if OPT_SUNPC_KBD
752     Ires(XtNctrlFKeys, XtCCtrlFKeys, misc.ctrl_fkeys, 10),
753 #endif
754 
755 #if OPT_TEK4014
756     Bres(XtNtekInhibit, XtCTekInhibit, misc.tekInhibit, False),
757     Bres(XtNtekSmall, XtCTekSmall, misc.tekSmall, False),
758     Bres(XtNtekStartup, XtCTekStartup, misc.TekEmu, False),
759 #endif
760 
761 #if OPT_TOOLBAR
762     Wres(XtNmenuBar, XtCMenuBar, VT100_TB_INFO(menu_bar), 0),
763     Ires(XtNmenuHeight, XtCMenuHeight, VT100_TB_INFO(menu_height), 25),
764 #endif
765 
766 #if OPT_WIDE_CHARS
767     Bres(XtNcjkWidth, XtCCjkWidth, misc.cjk_width, False),
768     Bres(XtNmkWidth, XtCMkWidth, misc.mk_width, False),
769     Bres(XtNprecompose, XtCPrecompose, screen.normalized_c, True),
770     Bres(XtNutf8Latin1, XtCUtf8Latin1, screen.utf8_latin1, False),
771     Bres(XtNutf8Weblike, XtCUtf8Weblike, screen.utf8_weblike, False),
772     Bres(XtNvt100Graphics, XtCVT100Graphics, screen.vt100_graphics, True),
773     Bres(XtNwideChars, XtCWideChars, screen.wide_chars, False),
774     Ires(XtNcombiningChars, XtCCombiningChars, screen.max_combining, 2),
775     Ires(XtNmkSamplePass, XtCMkSamplePass, misc.mk_samplepass, 655),
776     Ires(XtNmkSampleSize, XtCMkSampleSize, misc.mk_samplesize, 65536),
777     Sres(XtNutf8, XtCUtf8, screen.utf8_mode_s, "default"),
778     Sres(XtNutf8Fonts, XtCUtf8Fonts, screen.utf8_fonts_s, "default"),
779     Sres(XtNutf8Title, XtCUtf8Title, screen.utf8_title_s, "default"),
780     Sres(XtNwideBoldFont, XtCWideBoldFont, misc.default_font.f_wb, DEFWIDEBOLDFONT),
781     Sres(XtNwideFont, XtCWideFont, misc.default_font.f_w, DEFWIDEFONT),
782     Sres(XtNutf8SelectTypes, XtCUtf8SelectTypes, screen.utf8_select_types, NULL),
783 #endif
784 
785 #if OPT_LUIT_PROG
786     Sres(XtNlocale, XtCLocale, misc.locale_str, "medium"),
787     Sres(XtNlocaleFilter, XtCLocaleFilter, misc.localefilter, DEFLOCALEFILTER),
788 #endif
789 
790 #if OPT_INPUT_METHOD
791     Sres(XtNximFont, XtCXimFont, misc.f_x, DEFXIMFONT),
792 #endif
793 
794 #if OPT_SCROLL_LOCK
795     Bres(XtNallowScrollLock, XtCAllowScrollLock, screen.allowScrollLock0, False),
796     Bres(XtNautoScrollLock, XtCAutoScrollLock, screen.autoScrollLock, False),
797 #endif
798 
799     /* these are used only for testing ncurses, not in the manual page */
800 #if OPT_XMC_GLITCH
801     Bres(XtNxmcInline, XtCXmcInline, screen.xmc_inline, False),
802     Bres(XtNxmcMoveSGR, XtCXmcMoveSGR, screen.move_sgr_ok, True),
803     Ires(XtNxmcAttributes, XtCXmcAttributes, screen.xmc_attributes, 1),
804     Ires(XtNxmcGlitch, XtCXmcGlitch, screen.xmc_glitch, 0),
805 #endif
806 
807 #ifdef SCROLLBAR_RIGHT
808     Bres(XtNrightScrollBar, XtCRightScrollBar, misc.useRight, False),
809 #endif
810 
811 #if OPT_RENDERFONT
812     Bres(XtNforceXftHeight, XtCForceXftHeight, screen.force_xft_height, False),
813 #define RES_FACESIZE(n) Dres(XtNfaceSize #n, XtCFaceSize #n, misc.face_size[n], "0.0")
814     RES_FACESIZE(1),
815     RES_FACESIZE(2),
816     RES_FACESIZE(3),
817     RES_FACESIZE(4),
818     RES_FACESIZE(5),
819     RES_FACESIZE(6),
820     Dres(XtNfaceSize, XtCFaceSize, misc.face_size[0], DEFFACESIZE),
821     Sres(XtNfaceName, XtCFaceName, misc.default_xft.f_n, DEFFACENAME),
822     Sres(XtNrenderFont, XtCRenderFont, misc.render_font_s, "default"),
823     Ires(XtNlimitFontsets, XtCLimitFontsets, misc.limit_fontsets, DEF_XFT_CACHE),
824 #if OPT_RENDERWIDE
825     Sres(XtNfaceNameDoublesize, XtCFaceNameDoublesize, misc.default_xft.f_w, DEFFACENAME),
826 #endif
827 #endif
828 };
829 
830 static Boolean VTSetValues(Widget cur, Widget request, Widget new_arg,
831 			   ArgList args, Cardinal *num_args);
832 static void VTClassInit(void);
833 static void VTDestroy(Widget w);
834 static void VTExpose(Widget w, XEvent *event, Region region);
835 static void VTInitialize(Widget wrequest, Widget new_arg, ArgList args,
836 			 Cardinal *num_args);
837 static void VTRealize(Widget w, XtValueMask * valuemask,
838 		      XSetWindowAttributes * values);
839 static void VTResize(Widget w);
840 
841 #if OPT_INPUT_METHOD
842 static void VTInitI18N(XtermWidget);
843 #endif
844 
845 #ifdef VMS
846 globaldef {
847     "xtermclassrec"
848 } noshare
849 
850 #else
851 static
852 #endif				/* VMS */
853 WidgetClassRec xtermClassRec =
854 {
855     {
856 	/* core_class fields */
857 	(WidgetClass) & widgetClassRec,		/* superclass   */
858 	"VT100",		/* class_name                   */
859 	sizeof(XtermWidgetRec),	/* widget_size                  */
860 	VTClassInit,		/* class_initialize             */
861 	NULL,			/* class_part_initialize        */
862 	False,			/* class_inited                 */
863 	VTInitialize,		/* initialize                   */
864 	NULL,			/* initialize_hook              */
865 	VTRealize,		/* realize                      */
866 	actionsList,		/* actions                      */
867 	XtNumber(actionsList),	/* num_actions                  */
868 	xterm_resources,	/* resources                    */
869 	XtNumber(xterm_resources),	/* num_resources        */
870 	NULLQUARK,		/* xrm_class                    */
871 	True,			/* compress_motion              */
872 	False,			/* compress_exposure            */
873 	True,			/* compress_enterleave          */
874 	False,			/* visible_interest             */
875 	VTDestroy,		/* destroy                      */
876 	VTResize,		/* resize                       */
877 	VTExpose,		/* expose                       */
878 	VTSetValues,		/* set_values                   */
879 	NULL,			/* set_values_hook              */
880 	XtInheritSetValuesAlmost,	/* set_values_almost    */
881 	NULL,			/* get_values_hook              */
882 	NULL,			/* accept_focus                 */
883 	XtVersion,		/* version                      */
884 	NULL,			/* callback_offsets             */
885 	0,			/* tm_table                     */
886 	XtInheritQueryGeometry,	/* query_geometry               */
887 	XtInheritDisplayAccelerator,	/* display_accelerator  */
888 	NULL			/* extension                    */
889     }
890 };
891 
892 #ifdef VMS
893 globaldef {
894     "xtermwidgetclass"
895 }
896 noshare
897 #endif /* VMS */
898 WidgetClass xtermWidgetClass = (WidgetClass) & xtermClassRec;
899 
900 /*
901  * Add input-actions for widgets that are overlooked (scrollbar and toolbar):
902  *
903  *	a) Sometimes the scrollbar passes through translations, sometimes it
904  *	   doesn't.  We add the KeyPress translations here, just to be sure.
905  *	b) In the normal (non-toolbar) configuration, the xterm widget covers
906  *	   almost all of the window.  With a toolbar, there's a relatively
907  *	   large area that the user would expect to enter keystrokes since the
908  *	   program can get the focus.
909  */
910 void
xtermAddInput(Widget w)911 xtermAddInput(Widget w)
912 {
913     /* *INDENT-OFF* */
914     XtActionsRec input_actions[] = {
915 	{ "insert",		    HandleKeyPressed }, /* alias */
916 	{ "insert-eight-bit",	    HandleEightBitKeyPressed },
917 	{ "insert-seven-bit",	    HandleKeyPressed },
918 	{ "pointer-motion",	    HandlePointerMotion },
919 	{ "pointer-button",	    HandlePointerButton },
920 	{ "secure",		    HandleSecure },
921 	{ "string",		    HandleStringEvent },
922 	{ "scroll-back",	    HandleScrollBack },
923 	{ "scroll-forw",	    HandleScrollForward },
924 	{ "scroll-to",		    HandleScrollTo },
925 	{ "select-cursor-end",	    HandleKeyboardSelectEnd },
926 	{ "select-cursor-extend",   HandleKeyboardSelectExtend },
927 	{ "select-cursor-start",    HandleKeyboardSelectStart },
928 	{ "insert-selection",	    HandleInsertSelection },
929 	{ "select-start",	    HandleSelectStart },
930 	{ "select-extend",	    HandleSelectExtend },
931 	{ "start-extend",	    HandleStartExtend },
932 	{ "select-end",		    HandleSelectEnd },
933 	{ "clear-saved-lines",	    HandleClearSavedLines },
934 	{ "popup-menu",		    HandlePopupMenu },
935 	{ "bell",		    HandleBell },
936 	{ "ignore",		    HandleIgnore },
937 #if OPT_DABBREV
938 	{ "dabbrev-expand",	    HandleDabbrevExpand },
939 #endif
940 #if OPT_MAXIMIZE
941 	{ "fullscreen",		    HandleFullscreen },
942 #endif
943 #if OPT_SCROLL_LOCK
944 	{ "scroll-lock",	    HandleScrollLock },
945 #endif
946 #if OPT_SHIFT_FONTS
947 	{ "larger-vt-font",	    HandleLargerFont },
948 	{ "smaller-vt-font",	    HandleSmallerFont },
949 #endif
950     };
951     /* *INDENT-ON* */
952 
953     TRACE_TRANS("BEFORE", w);
954     XtAppAddActions(app_con, input_actions, XtNumber(input_actions));
955     XtAugmentTranslations(w, XtParseTranslationTable(defaultTranslations));
956     TRACE_TRANS("AFTER:", w);
957 
958 #if OPT_EXTRA_PASTE
959     if (term && term->keyboard.extra_translations)
960 	XtOverrideTranslations((Widget) term, XtParseTranslationTable(term->keyboard.extra_translations));
961 #endif
962 }
963 
964 #if OPT_ISO_COLORS
965 #ifdef EXP_BOGUS_FG
966 static Bool
CheckBogusForeground(TScreen * screen,const char * tag)967 CheckBogusForeground(TScreen *screen, const char *tag)
968 {
969     int row = -1, col = -1, pass;
970     Bool isClear = True;
971 
972     (void) tag;
973     for (pass = 0; pass < 2; ++pass) {
974 	row = screen->cur_row;
975 	for (; isClear && (row <= screen->max_row); ++row) {
976 	    CLineData *ld = getLineData(screen, row);
977 
978 	    if (ld != 0) {
979 		IAttr *attribs = ld->attribs;
980 
981 		col = (row == screen->cur_row) ? screen->cur_col : 0;
982 		for (; isClear && (col <= screen->max_col); ++col) {
983 		    unsigned flags = attribs[col];
984 		    if (pass) {
985 			flags &= ~FG_COLOR;
986 			attribs[col] = (IAttr) flags;
987 		    } else if ((flags & BG_COLOR)) {
988 			isClear = False;
989 		    } else if ((flags & FG_COLOR)) {
990 			unsigned ch = ld->charData[col];
991 			isClear = ((ch == ' ') || (ch == 0));
992 		    } else {
993 			isClear = False;
994 		    }
995 		}
996 	    }
997 	}
998     }
999     TRACE(("%s checked %d,%d to %d,%d %s pass %d\n",
1000 	   tag, screen->cur_row, screen->cur_col,
1001 	   row, col,
1002 	   isClear && pass ? "cleared" : "unchanged",
1003 	   pass));
1004 
1005     return isClear;
1006 }
1007 #endif
1008 
1009 /*
1010  * The terminal's foreground and background colors are set via two mechanisms:
1011  *	text (cur_foreground, cur_background values that are passed down to
1012  *		XDrawImageString and XDrawString)
1013  *	area (X11 graphics context used in XClearArea and XFillRectangle)
1014  */
1015 void
SGR_Foreground(XtermWidget xw,int color)1016 SGR_Foreground(XtermWidget xw, int color)
1017 {
1018     TScreen *screen = TScreenOf(xw);
1019     Pixel fg;
1020 
1021     if (color >= 0) {
1022 	UIntSet(xw->flags, FG_COLOR);
1023     } else {
1024 	UIntClr(xw->flags, FG_COLOR);
1025     }
1026     fg = getXtermFG(xw, xw->flags, color);
1027     xw->cur_foreground = color;
1028 
1029     setCgsFore(xw, WhichVWin(screen), gcNorm, fg);
1030     setCgsBack(xw, WhichVWin(screen), gcNormReverse, fg);
1031 
1032     setCgsFore(xw, WhichVWin(screen), gcBold, fg);
1033     setCgsBack(xw, WhichVWin(screen), gcBoldReverse, fg);
1034 
1035 #ifdef EXP_BOGUS_FG
1036     /*
1037      * If we've just turned off the foreground color, check for blank cells
1038      * which have no background color, but do have foreground color.  This
1039      * could happen due to setting the foreground color just before scrolling.
1040      *
1041      * Those cells look uncolored, but will confuse ShowCursor(), which looks
1042      * for the colors in the current cell, and will see the foreground color.
1043      * In that case, remove the foreground color from the blank cells.
1044      */
1045     if (color < 0) {
1046 	CheckBogusForeground(screen, "SGR_Foreground");
1047     }
1048 #endif
1049 }
1050 
1051 void
SGR_Background(XtermWidget xw,int color)1052 SGR_Background(XtermWidget xw, int color)
1053 {
1054     TScreen *screen = TScreenOf(xw);
1055     Pixel bg;
1056 
1057     /*
1058      * An indexing operation may have set screen->scroll_amt, which would
1059      * normally result in calling FlushScroll() in WriteText().  However,
1060      * if we're changing the background color now, then the new value
1061      * should not apply to the pending blank lines.
1062      */
1063     if (screen->scroll_amt && (color != xw->cur_background))
1064 	FlushScroll(xw);
1065 
1066     if (color >= 0) {
1067 	UIntSet(xw->flags, BG_COLOR);
1068     } else {
1069 	UIntClr(xw->flags, BG_COLOR);
1070     }
1071     bg = getXtermBG(xw, xw->flags, color);
1072     xw->cur_background = color;
1073 
1074     setCgsBack(xw, WhichVWin(screen), gcNorm, bg);
1075     setCgsFore(xw, WhichVWin(screen), gcNormReverse, bg);
1076 
1077     setCgsBack(xw, WhichVWin(screen), gcBold, bg);
1078     setCgsFore(xw, WhichVWin(screen), gcBoldReverse, bg);
1079 }
1080 
1081 /* Invoked after updating bold/underline flags, computes the extended color
1082  * index to use for foreground.  (See also 'extract_fg()').
1083  */
1084 static void
setExtendedFG(XtermWidget xw)1085 setExtendedFG(XtermWidget xw)
1086 {
1087     int fg = xw->sgr_foreground;
1088 
1089     if (TScreenOf(xw)->colorAttrMode
1090 	|| (fg < 0)) {
1091 	fg = MapToColorMode(fg, TScreenOf(xw), xw->flags);
1092     }
1093 
1094     /* This implements the IBM PC-style convention of 8-colors, with one
1095      * bit for bold, thus mapping the 0-7 codes to 8-15.  It won't make
1096      * much sense for 16-color applications, but we keep it to retain
1097      * compatibility with ANSI-color applications.
1098      */
1099 #if OPT_PC_COLORS		/* XXXJTL should be settable at runtime (resource or OSC?) */
1100     if (TScreenOf(xw)->boldColors
1101 	&& (!xw->sgr_38_xcolors)
1102 	&& (fg >= 0)
1103 	&& (fg < 8)
1104 	&& (xw->flags & BOLD))
1105 	fg |= 8;
1106 #endif
1107 
1108     SGR_Foreground(xw, fg);
1109 }
1110 
1111 /* Invoked after updating inverse flag, computes the extended color
1112  * index to use for background.  (See also 'extract_bg()').
1113  */
1114 static void
setExtendedBG(XtermWidget xw)1115 setExtendedBG(XtermWidget xw)
1116 {
1117     int bg = xw->sgr_background;
1118 
1119     if (TScreenOf(xw)->colorAttrMode
1120 	|| (bg < 0)) {
1121 	if (TScreenOf(xw)->colorRVMode && (xw->flags & INVERSE))
1122 	    bg = COLOR_RV;
1123     }
1124 
1125     SGR_Background(xw, bg);
1126 }
1127 
1128 void
setExtendedColors(XtermWidget xw)1129 setExtendedColors(XtermWidget xw)
1130 {
1131     setExtendedFG(xw);
1132     setExtendedBG(xw);
1133 }
1134 
1135 static void
reset_SGR_Foreground(XtermWidget xw)1136 reset_SGR_Foreground(XtermWidget xw)
1137 {
1138     xw->sgr_foreground = -1;
1139     xw->sgr_38_xcolors = False;
1140     clrDirectFG(xw->flags);
1141     setExtendedFG(xw);
1142 }
1143 
1144 static void
reset_SGR_Background(XtermWidget xw)1145 reset_SGR_Background(XtermWidget xw)
1146 {
1147     xw->sgr_background = -1;
1148     clrDirectBG(xw->flags);
1149     setExtendedBG(xw);
1150 }
1151 
1152 static void
reset_SGR_Colors(XtermWidget xw)1153 reset_SGR_Colors(XtermWidget xw)
1154 {
1155     reset_SGR_Foreground(xw);
1156     reset_SGR_Background(xw);
1157 }
1158 #endif /* OPT_ISO_COLORS */
1159 
1160 #if OPT_WIDE_ATTRS
1161 /*
1162  * Call this before changing the state of ATR_ITALIC, to update the GC fonts.
1163  */
1164 static void
setItalicFont(XtermWidget xw,Bool enable)1165 setItalicFont(XtermWidget xw, Bool enable)
1166 {
1167     if (enable) {
1168 	if ((xw->flags & ATR_ITALIC) == 0) {
1169 	    xtermLoadItalics(xw);
1170 	    TRACE(("setItalicFont: enabling Italics\n"));
1171 	    xtermUpdateFontGCs(xw, getItalicFont);
1172 	}
1173     } else if ((xw->flags & ATR_ITALIC) != 0) {
1174 	TRACE(("setItalicFont: disabling Italics\n"));
1175 	xtermUpdateFontGCs(xw, getNormalFont);
1176     }
1177 }
1178 
1179 static void
ResetItalics(XtermWidget xw)1180 ResetItalics(XtermWidget xw)
1181 {
1182     setItalicFont(xw, False);
1183     UIntClr(xw->flags, ATR_ITALIC);
1184 }
1185 
1186 #else
1187 #define ResetItalics(xw)	/* nothing */
1188 #endif
1189 
1190 static void
initCharset(TScreen * screen,int which,DECNRCM_codes code)1191 initCharset(TScreen *screen, int which, DECNRCM_codes code)
1192 {
1193     screen->gsets[which] = code;
1194 }
1195 
1196 void
saveCharsets(TScreen * screen,DECNRCM_codes * target)1197 saveCharsets(TScreen *screen, DECNRCM_codes * target)
1198 {
1199     int g;
1200     for (g = 0; g < NUM_GSETS; ++g) {
1201 	target[g] = screen->gsets[g];
1202     }
1203 }
1204 
1205 void
restoreCharsets(TScreen * screen,DECNRCM_codes * source)1206 restoreCharsets(TScreen *screen, DECNRCM_codes * source)
1207 {
1208     int g;
1209     for (g = 0; g < NUM_GSETS; ++g) {
1210 	screen->gsets[g] = source[g];
1211     }
1212 }
1213 
1214 void
resetCharsets(TScreen * screen)1215 resetCharsets(TScreen *screen)
1216 {
1217     TRACE(("resetCharsets\n"));
1218 
1219     initCharset(screen, 0, nrc_ASCII);
1220     initCharset(screen, 1, nrc_ASCII);
1221     initCharset(screen, 2, nrc_ASCII);
1222     initCharset(screen, 3, nrc_ASCII);
1223 
1224     screen->curgl = 0;		/* G0 => GL.            */
1225     screen->curgr = 2;		/* G2 => GR.            */
1226     screen->curss = 0;		/* No single shift.     */
1227 
1228 #if OPT_VT52_MODE
1229     if (screen->vtXX_level == 0)
1230 	initCharset(screen, 1, nrc_DEC_Spec_Graphic);	/* Graphics */
1231 #endif
1232 }
1233 
1234 static void
modified_DECNRCM(XtermWidget xw)1235 modified_DECNRCM(XtermWidget xw)
1236 {
1237 #if OPT_WIDE_CHARS
1238     TScreen *screen = TScreenOf(xw);
1239     if (screen->wide_chars && (screen->utf8_mode || screen->utf8_nrc_mode)) {
1240 	int enabled = ((xw->flags & NATIONAL) != 0);
1241 	int modefix;
1242 	EXCHANGE(screen->utf8_nrc_mode, screen->utf8_mode, modefix);
1243 	switchPtyData(screen, !enabled);
1244 	TRACE(("UTF8 mode temporarily %s\n", enabled ? "ON" : "OFF"));
1245     }
1246 #else
1247     (void) xw;
1248 #endif
1249 }
1250 
1251 /*
1252  * VT300 and up support three ANSI conformance levels, defined according to
1253  * the dpANSI X3.134.1 standard.  DEC's manuals equate levels 1 and 2, and
1254  * are unclear.  This code is written based on the manuals.
1255  */
1256 static void
set_ansi_conformance(TScreen * screen,int level)1257 set_ansi_conformance(TScreen *screen, int level)
1258 {
1259     TRACE(("set_ansi_conformance(%d) dec_level %d:%d, ansi_level %d\n",
1260 	   level,
1261 	   screen->vtXX_level * 100,
1262 	   screen->terminal_id,
1263 	   screen->ansi_level));
1264     if (screen->vtXX_level >= 3) {
1265 	switch (screen->ansi_level = level) {
1266 	case 1:
1267 	    /* FALLTHRU */
1268 	case 2:
1269 	    initCharset(screen, 0, nrc_ASCII);	/* G0 is ASCII */
1270 	    initCharset(screen, 1, nrc_ASCII);	/* G1 is ISO Latin-1 */
1271 	    screen->curgl = 0;
1272 	    screen->curgr = 1;
1273 	    break;
1274 	case 3:
1275 	    initCharset(screen, 0, nrc_ASCII);	/* G0 is ASCII */
1276 	    screen->curgl = 0;
1277 	    break;
1278 	}
1279     }
1280 }
1281 
1282 /*
1283  * Set scrolling margins.  VTxxx terminals require that the top/bottom are
1284  * different, so we have at least two lines in the scrolling region.
1285  */
1286 static void
set_tb_margins(TScreen * screen,int top,int bottom)1287 set_tb_margins(TScreen *screen, int top, int bottom)
1288 {
1289     TRACE(("set_tb_margins %d..%d, prior %d..%d\n",
1290 	   top, bottom,
1291 	   screen->top_marg,
1292 	   screen->bot_marg));
1293     if (bottom > top) {
1294 	screen->top_marg = top;
1295 	screen->bot_marg = bottom;
1296     }
1297     if (screen->top_marg > screen->max_row)
1298 	screen->top_marg = screen->max_row;
1299     if (screen->bot_marg > screen->max_row)
1300 	screen->bot_marg = screen->max_row;
1301 }
1302 
1303 static void
set_lr_margins(TScreen * screen,int left,int right)1304 set_lr_margins(TScreen *screen, int left, int right)
1305 {
1306     TRACE(("set_lr_margins %d..%d, prior %d..%d\n",
1307 	   left, right,
1308 	   screen->lft_marg,
1309 	   screen->rgt_marg));
1310     if (right > left) {
1311 	screen->lft_marg = left;
1312 	screen->rgt_marg = right;
1313     }
1314     if (screen->lft_marg > screen->max_col)
1315 	screen->lft_marg = screen->max_col;
1316     if (screen->rgt_marg > screen->max_col)
1317 	screen->rgt_marg = screen->max_col;
1318 }
1319 
1320 #define reset_tb_margins(screen) set_tb_margins(screen, 0, screen->max_row)
1321 #define reset_lr_margins(screen) set_lr_margins(screen, 0, screen->max_col)
1322 
1323 void
resetMargins(XtermWidget xw)1324 resetMargins(XtermWidget xw)
1325 {
1326     TScreen *screen = TScreenOf(xw);
1327 
1328     reset_tb_margins(screen);
1329     reset_lr_margins(screen);
1330 }
1331 
1332 static void
resetMarginMode(XtermWidget xw)1333 resetMarginMode(XtermWidget xw)
1334 {
1335     UIntClr(xw->flags, LEFT_RIGHT);
1336     resetMargins(xw);
1337 }
1338 
1339 static void
resetRendition(XtermWidget xw)1340 resetRendition(XtermWidget xw)
1341 {
1342     TScreen *screen = TScreenOf(xw);
1343     (void) screen;
1344     ResetItalics(xw);
1345     UIntClr(xw->flags,
1346 	    (SGR_MASK | SGR_MASK2 | INVISIBLE));
1347 }
1348 
1349 void
set_max_col(TScreen * screen,int cols)1350 set_max_col(TScreen *screen, int cols)
1351 {
1352     TRACE(("set_max_col %d, prior %d\n", cols, screen->max_col));
1353     if (cols < 0)
1354 	cols = 0;
1355     screen->max_col = cols;
1356 }
1357 
1358 void
set_max_row(TScreen * screen,int rows)1359 set_max_row(TScreen *screen, int rows)
1360 {
1361     TRACE(("set_max_row %d, prior %d\n", rows, screen->max_row));
1362     if (rows < 0)
1363 	rows = 0;
1364     screen->max_row = rows;
1365 }
1366 
1367 #if OPT_MOD_FKEYS
1368 static void
set_mod_fkeys(XtermWidget xw,int which,int what,Bool enabled)1369 set_mod_fkeys(XtermWidget xw, int which, int what, Bool enabled)
1370 {
1371 #define SET_MOD_FKEYS(field) \
1372     xw->keyboard.modify_now.field = ((what == DEFAULT) && enabled) \
1373 				     ? xw->keyboard.modify_1st.field \
1374 				     : what; \
1375     TRACE(("set modify_now.%s to %d\n", #field, \
1376 	   xw->keyboard.modify_now.field));
1377 
1378     switch (which) {
1379     case 0:
1380 	SET_MOD_FKEYS(allow_keys);
1381 	break;
1382     case 1:
1383 	SET_MOD_FKEYS(cursor_keys);
1384 	break;
1385     case 2:
1386 	SET_MOD_FKEYS(function_keys);
1387 	break;
1388     case 3:
1389 	SET_MOD_FKEYS(keypad_keys);
1390 	break;
1391     case 4:
1392 	SET_MOD_FKEYS(other_keys);
1393 	break;
1394     case 5:
1395 	SET_MOD_FKEYS(string_keys);
1396 	break;
1397     }
1398 }
1399 #endif /* OPT_MOD_FKEYS */
1400 
1401 #if OPT_TRACE
1402 #define DATA(name) { name, #name }
1403 static const struct {
1404     Const PARSE_T *table;
1405     const char *name;
1406 } all_tables[] = {
1407 
1408     DATA(ansi_table)
1409 	,DATA(cigtable)
1410 	,DATA(csi2_table)
1411 	,DATA(csi_ex_table)
1412 	,DATA(csi_quo_table)
1413 	,DATA(csi_table)
1414 	,DATA(dec2_table)
1415 	,DATA(dec3_table)
1416 	,DATA(dec_table)
1417 	,DATA(eigtable)
1418 	,DATA(esc_sp_table)
1419 	,DATA(esc_table)
1420 	,DATA(scrtable)
1421 	,DATA(scs96table)
1422 	,DATA(scstable)
1423 	,DATA(sos_table)
1424 #if OPT_BLINK_CURS
1425 	,DATA(csi_sp_table)
1426 #endif
1427 #if OPT_DEC_LOCATOR
1428 	,DATA(csi_tick_table)
1429 #endif
1430 #if OPT_DEC_RECTOPS
1431 	,DATA(csi_dollar_table)
1432 	,DATA(csi_star_table)
1433 	,DATA(csi_dec_dollar_table)
1434 #endif
1435 #if OPT_WIDE_CHARS
1436 	,DATA(esc_pct_table)
1437 	,DATA(scs_amp_table)
1438 	,DATA(scs_pct_table)
1439 	,DATA(scs_2qt_table)
1440 #endif
1441 #if OPT_VT52_MODE
1442 	,DATA(vt52_table)
1443 	,DATA(vt52_esc_table)
1444 	,DATA(vt52_ignore_table)
1445 #endif
1446 #if OPT_XTERM_SGR
1447 	,DATA(csi_hash_table)
1448 #endif
1449 #undef DATA
1450 };
1451 
1452 #define WHICH_TABLE(name) if (table == name) result = #name
1453 static const char *
which_table(Const PARSE_T * table)1454 which_table(Const PARSE_T * table)
1455 {
1456     const char *result = "?";
1457     Cardinal n;
1458     for (n = 0; n < XtNumber(all_tables); ++n) {
1459 	if (table == all_tables[n].table) {
1460 	    result = all_tables[n].name;
1461 	    break;
1462 	}
1463     }
1464 
1465     return result;
1466 }
1467 
1468 static void
check_tables(void)1469 check_tables(void)
1470 {
1471     Cardinal n;
1472     int ch;
1473     int total_codes = 0;
1474     int total_ground = 0;
1475     int total_ignored = 0;
1476 
1477     TRACE(("** check_tables\n"));
1478     for (n = 0; n < XtNumber(all_tables); ++n) {
1479 	Const PARSE_T *table = all_tables[n].table;
1480 	TRACE(("*** %s\n", all_tables[n].name));
1481 	/*
1482 	 * Most of the tables should use the same codes in 0..31, 128..159
1483 	 * as the "ansi" table.
1484 	 */
1485 	if (strncmp(all_tables[n].name, "ansi", 4) &&
1486 	    strncmp(all_tables[n].name, "sos_", 4) &&
1487 	    strncmp(all_tables[n].name, "vt52", 4)) {
1488 	    for (ch = 0; ch < 32; ++ch) {
1489 		int c1 = ch + 128;
1490 		PARSE_T st_l = table[ch];
1491 		PARSE_T st_r = table[c1];
1492 		if (st_l != ansi_table[ch]) {
1493 		    TRACE(("  %3d: %d vs %d\n", ch, st_l, ansi_table[ch]));
1494 		}
1495 		if (st_r != ansi_table[c1]) {
1496 		    TRACE(("  %3d: %d vs %d\n", c1, st_r, ansi_table[c1]));
1497 		}
1498 	    }
1499 	}
1500 	/*
1501 	 * All of the tables should have their GL/GR parts encoded the same.
1502 	 */
1503 	for (ch = 32; ch < 127; ++ch) {
1504 	    PARSE_T st_l = table[ch];
1505 	    PARSE_T st_r = table[ch + 128];
1506 	    if (st_l != st_r) {
1507 		if (st_r == CASE_IGNORE &&
1508 		    !strncmp(all_tables[n].name, "vt52", 4)) {
1509 		    ;
1510 		} else {
1511 		    TRACE(("  %3d: %d vs %d\n", ch, st_l, st_r));
1512 		}
1513 	    }
1514 	}
1515 	/*
1516 	 * Just for amusement, show how sparse the encoding tables are.
1517 	 */
1518 	for (ch = 0; ch < 256; ++ch) {
1519 	    ++total_codes;
1520 	    switch (table[ch]) {
1521 	    case CASE_GROUND_STATE:
1522 		total_ground++;
1523 		break;
1524 	    case CASE_ESC_IGNORE:
1525 		/* FALLTHRU */
1526 	    case CASE_IGNORE:
1527 		/* FALLTHRU */
1528 	    case CASE_VT52_IGNORE:
1529 		total_ignored++;
1530 		break;
1531 	    }
1532 	}
1533     }
1534     TRACE(("VTPrsTbl:\n"));
1535     TRACE(("%d total codes\n", total_codes));
1536     TRACE(("%d total ignored\n", total_ignored));
1537     TRACE(("%d total reset/ground\n", total_ground));
1538 }
1539 
1540 static void
check_bitmasks(void)1541 check_bitmasks(void)
1542 {
1543 #define dMSK 0x100
1544 #define DATA(mode,name) { mode, name, #name }
1545 #define DMSK(what) (dMSK | (what))
1546 #define DGRP(offs) (1 << ((offs) - 1))
1547     static struct {
1548 	int mode;
1549 	int code;
1550 	Const char *name;
1551     } table[] = {
1552 	DATA(DGRP(1), INVERSE),
1553 	    DATA(DGRP(1), UNDERLINE),
1554 	    DATA(DGRP(1), BOLD),
1555 	    DATA(DGRP(1), BLINK),
1556 	    DATA(DMSK(DGRP(1)), SGR_MASK),
1557 	    DATA(DGRP(2), BG_COLOR),
1558 	    DATA(DGRP(2), FG_COLOR),
1559 	    DATA(DGRP(2), PROTECTED),
1560 	    DATA(DGRP(4), CHARDRAWN),
1561 #if OPT_WIDE_ATTRS
1562 	    DATA(DGRP(2), ATR_FAINT),
1563 	    DATA(DGRP(2), ATR_ITALIC),
1564 	    DATA(DGRP(2), ATR_STRIKEOUT),
1565 	    DATA(DGRP(2), ATR_DBL_UNDER),
1566 	    DATA(DGRP(2), ATR_DIRECT_FG),
1567 	    DATA(DGRP(2), ATR_DIRECT_BG),
1568 #endif
1569 	    DATA(DMSK(DGRP(2)), SGR_MASK2),
1570 	    DATA(DGRP(3), WRAPAROUND),
1571 	    DATA(DGRP(3), REVERSEWRAP),
1572 	    DATA(DGRP(3), REVERSE_VIDEO),
1573 	    DATA(DGRP(3), LINEFEED),
1574 	    DATA(DGRP(3), ORIGIN),
1575 	    DATA(DGRP(3), INSERT),
1576 	    DATA(DGRP(3), SMOOTHSCROLL),
1577 	    DATA(DGRP(3), IN132COLUMNS),
1578 	    DATA(DGRP(3), INVISIBLE),
1579 	    DATA(DMSK(DGRP(3)), ATTRIBUTES),
1580 	    DATA(DGRP(5), NATIONAL),
1581 	    DATA(DGRP(5), LEFT_RIGHT),
1582 	    DATA(DGRP(5), NOCLEAR_COLM),
1583 	    DATA(DGRP(4), NOBACKGROUND),
1584 	    DATA(DGRP(4), NOTRANSLATION),
1585 	    DATA(DGRP(4), DOUBLEWFONT),
1586 	    DATA(DGRP(4), DOUBLEHFONT),
1587 	    DATA(DGRP(4), CHARBYCHAR),
1588 	    DATA(DGRP(4), NORESOLUTION),
1589 	    DATA(DMSK(DGRP(1) | DGRP(2) | DGRP(4)), DRAWX_MASK),
1590 	    DATA(-1, EOF)
1591     };
1592 #undef DATA
1593     int j, k;
1594     TRACE(("** check_bitmasks:\n"));
1595     for (j = 0; table[j].mode >= 0; ++j) {
1596 	TRACE(("%4X %8X %s\n", table[j].mode, table[j].code, table[j].name));
1597 	if (table[j].mode & dMSK) {
1598 	    int mask = dMSK;
1599 	    for (k = 0; table[k].mode >= 0; ++k) {
1600 		if (j == k)
1601 		    continue;
1602 		if (table[k].mode & dMSK)
1603 		    continue;
1604 		if ((table[j].mode & table[k].mode) != 0)
1605 		    mask |= table[k].mode;
1606 	    }
1607 	    if (mask != table[j].mode) {
1608 		TRACE(("...expected %08X\n", mask));
1609 	    }
1610 	} else {
1611 	    for (k = 0; table[k].mode >= 0; ++k) {
1612 		if (j == k)
1613 		    continue;
1614 		if (table[k].mode & dMSK)
1615 		    continue;
1616 		if ((table[j].code & table[k].code) != 0) {
1617 		    TRACE(("...same bits %s\n", table[k].name));
1618 		}
1619 	    }
1620 	}
1621     }
1622 }
1623 #endif
1624 
1625 static int
init_params(void)1626 init_params(void)
1627 {
1628     while (parms.count-- > 0) {
1629 	parms.is_sub[parms.count] = 0;
1630 	parms.params[parms.count] = 0;
1631     }
1632     parms.count = 0;
1633     parms.has_subparams = 0;
1634     return 0;
1635 }
1636 
1637 #if OPT_TRACE > 0
1638 static void
dump_params(void)1639 dump_params(void)
1640 {
1641     int n;
1642     int arg;
1643     TRACE(("params %d (%d)\n", nparam, parms.has_subparams));
1644     for (arg = 1, n = 0; n < nparam; ++n) {
1645 	TRACE(("%3d.%d %d\n", arg, parms.is_sub[n], parms.params[n]));
1646 	if (!parms.is_sub[n])
1647 	    ++arg;
1648     }
1649 }
1650 #define DumpParams() dump_params()
1651 #else
1652 #define DumpParams()		/* nothing */
1653 #endif
1654 
1655 	/* allocate larger buffer if needed/possible */
1656 #define SafeAlloc(type, area, used, size) \
1657 		type *new_string = area; \
1658 		size_t new_length = size; \
1659 		if (new_length == 0) { \
1660 		    new_length = 1024; \
1661 		    new_string = TypeMallocN(type, new_length); \
1662 		} else if (used+1 >= new_length) { \
1663 		    new_length = size * 2; \
1664 		    new_string = TypeMallocN(type, new_length); \
1665 		    if (new_string != 0 \
1666 		     && area != 0 \
1667 		     && used != 0) { \
1668 			memcpy(new_string, area, used * sizeof(type)); \
1669 		     } \
1670 		}
1671 #define SafeFree(area, size) \
1672 		if (area != new_string) { \
1673 		    free(area); \
1674 		    area = new_string; \
1675 		} \
1676 		size = new_length
1677 
1678 #define WriteNow() {						\
1679 	    unsigned single = 0;				\
1680 								\
1681 	    if (screen->curss) {				\
1682 		dotext(xw,					\
1683 		       screen->gsets[(int) (screen->curss)],	\
1684 		       sp->print_area,				\
1685 		       (Cardinal) 1);				\
1686 		screen->curss = 0;				\
1687 		single++;					\
1688 	    }							\
1689 	    if (sp->print_used > single) {			\
1690 		dotext(xw,					\
1691 		       screen->gsets[(int) (screen->curgl)],	\
1692 		       sp->print_area + single,			\
1693 		       (Cardinal) (sp->print_used - single));	\
1694 	    }							\
1695 	    sp->print_used = 0;					\
1696 	}							\
1697 
1698 #define PARSE_SRM 1
1699 
1700 struct ParseState {
1701     unsigned check_recur;
1702 #if OPT_VT52_MODE
1703     Bool vt52_cup;
1704 #endif
1705     Const PARSE_T *groundtable;
1706     Const PARSE_T *parsestate;
1707     int scstype;
1708     int scssize;
1709     Bool private_function;	/* distinguish private-mode from standard */
1710     int string_mode;		/* nonzero iff we're processing a string */
1711     int lastchar;		/* positive iff we had a graphic character */
1712     int nextstate;
1713 #if OPT_WIDE_CHARS
1714     int last_was_wide;
1715 #endif
1716     /* Buffer for processing printable text */
1717     IChar *print_area;
1718     size_t print_size;
1719     size_t print_used;
1720     /* Buffer for processing strings (e.g., OSC ... ST) */
1721     Char *string_area;
1722     size_t string_size;
1723     size_t string_used;
1724     /* Buffer for deferring input */
1725     Char *defer_area;
1726     size_t defer_size;
1727     size_t defer_used;
1728 };
1729 
1730 static struct ParseState myState;
1731 
1732 static void
init_groundtable(TScreen * screen,struct ParseState * sp)1733 init_groundtable(TScreen *screen, struct ParseState *sp)
1734 {
1735     (void) screen;
1736 
1737 #if OPT_VT52_MODE
1738     if (!(screen->vtXX_level)) {
1739 	sp->groundtable = vt52_table;
1740     } else if (screen->terminal_id >= 100)
1741 #endif
1742     {
1743 	sp->groundtable = ansi_table;
1744     }
1745 }
1746 
1747 static void
select_charset(struct ParseState * sp,int type,int size)1748 select_charset(struct ParseState *sp, int type, int size)
1749 {
1750     TRACE(("select_charset G%d size %d -> G%d size %d\n",
1751 	   sp->scstype, sp->scssize,
1752 	   type, size));
1753 
1754     sp->scstype = type;
1755     sp->scssize = size;
1756     if (size == 94) {
1757 	sp->parsestate = scstable;
1758     } else {
1759 	sp->parsestate = scs96table;
1760     }
1761 }
1762 /* *INDENT-OFF* */
1763 static const struct {
1764     DECNRCM_codes result;
1765     int prefix;
1766     int suffix;
1767     int min_level;
1768     int max_level;
1769     int need_nrc;
1770 } scs_table[] = {
1771     { nrc_ASCII,             0,   'B', 1, 9, 0 },
1772     { nrc_British,           0,   'A', 1, 9, 0 },
1773     { nrc_DEC_Spec_Graphic,  0,   '0', 1, 9, 0 },
1774     { nrc_DEC_Alt_Chars,     0,   '1', 1, 1, 0 },
1775     { nrc_DEC_Alt_Graphics,  0,   '2', 1, 1, 0 },
1776     /* VT2xx */
1777     { nrc_DEC_Supp,          0,   '<', 2, 9, 0 },
1778     { nrc_Dutch,             0,   '4', 2, 9, 1 },
1779     { nrc_Finnish,           0,   '5', 2, 9, 1 },
1780     { nrc_Finnish2,          0,   'C', 2, 9, 1 },
1781     { nrc_French,            0,   'R', 2, 9, 1 },
1782     { nrc_French2,           0,   'f', 2, 9, 1 },
1783     { nrc_French_Canadian,   0,   'Q', 2, 9, 1 },
1784     { nrc_German,            0,   'K', 2, 9, 1 },
1785     { nrc_Italian,           0,   'Y', 2, 9, 1 },
1786     { nrc_Norwegian_Danish2, 0,   'E', 2, 9, 1 },
1787     { nrc_Norwegian_Danish3, 0,   '6', 2, 9, 1 },
1788     { nrc_Spanish,           0,   'Z', 2, 9, 1 },
1789     { nrc_Swedish,           0,   '7', 2, 9, 1 },
1790     { nrc_Swedish2,          0,   'H', 2, 9, 1 },
1791     { nrc_Swiss,             0,   '=', 2, 9, 1 },
1792     /* VT3xx */
1793     { nrc_British_Latin_1,   0,   'A', 3, 9, 1 },
1794     { nrc_DEC_Supp_Graphic,  '%', '5', 3, 9, 0 },
1795     { nrc_DEC_Technical,     0,   '>', 3, 9, 0 },
1796     { nrc_French_Canadian2,  0,   '9', 3, 9, 1 },
1797     { nrc_Norwegian_Danish,  0,   '`', 3, 9, 1 },
1798     { nrc_Portugese,         '%', '6', 3, 9, 1 },
1799     { nrc_ISO_Latin_1_Supp,  0,   'A', 3, 9, 0 },
1800     /* VT5xx */
1801     { nrc_Greek,             '"', '>', 5, 9, 1 },
1802     { nrc_Hebrew,            '%', '=', 5, 9, 1 },
1803     { nrc_Turkish,	     '%', '2', 5, 9, 1 },
1804     { nrc_DEC_Cyrillic,      '&', '4', 5, 9, 0 },
1805     { nrc_DEC_Greek_Supp,    '"', '?', 5, 9, 0 },
1806     { nrc_DEC_Hebrew_Supp,   '"', '4', 5, 9, 0 },
1807     { nrc_DEC_Turkish_Supp,  '%', '0', 5, 9, 0 },
1808     { nrc_ISO_Greek_Supp,    0,   'F', 5, 9, 0 },
1809     { nrc_ISO_Hebrew_Supp,   0,   'H', 5, 9, 0 },
1810     { nrc_ISO_Latin_2_Supp,  0,   'B', 5, 9, 0 },
1811     { nrc_ISO_Latin_5_Supp,  0,   'M', 5, 9, 0 },
1812     { nrc_ISO_Latin_Cyrillic,0,   'L', 5, 9, 0 },
1813     /* VT5xx (not implemented) */
1814 #if 0
1815     { nrc_Russian,           '&', '5', 5, 9, 1 },
1816     { nrc_SCS_NRCS,          '%', '3', 5, 9, 0 },
1817 #endif
1818 };
1819 /* *INDENT-ON* */
1820 
1821 #if OPT_DEC_RECTOPS
1822 static char *
encode_scs(DECNRCM_codes value)1823 encode_scs(DECNRCM_codes value)
1824 {
1825     static char buffer[3];
1826     Cardinal n;
1827     char *result = buffer;
1828     for (n = 0; n < XtNumber(scs_table); ++n) {
1829 	if (scs_table[n].result == value) {
1830 	    if (scs_table[n].prefix)
1831 		*result++ = (char) scs_table[n].prefix;
1832 	    if (scs_table[n].suffix)
1833 		*result++ = (char) scs_table[n].suffix;
1834 	    break;
1835 	}
1836     }
1837     *result = '\0';
1838     return buffer;
1839 }
1840 #endif
1841 
1842 void
xtermDecodeSCS(XtermWidget xw,int which,int sgroup,int prefix,int suffix)1843 xtermDecodeSCS(XtermWidget xw, int which, int sgroup, int prefix, int suffix)
1844 {
1845     TScreen *screen = TScreenOf(xw);
1846     Cardinal n;
1847     DECNRCM_codes result = nrc_Unknown;
1848 
1849     suffix &= 0x7f;
1850     for (n = 0; n < XtNumber(scs_table); ++n) {
1851 	if (prefix == scs_table[n].prefix
1852 	    && suffix == scs_table[n].suffix
1853 	    && sgroup == scs_table[n].min_level
1854 	    && screen->vtXX_level >= scs_table[n].min_level
1855 	    && screen->vtXX_level <= scs_table[n].max_level
1856 	    && (scs_table[n].need_nrc == 0 || (xw->flags & NATIONAL) != 0)) {
1857 	    result = scs_table[n].result;
1858 	    break;
1859 	}
1860     }
1861     if (result != nrc_Unknown) {
1862 	initCharset(screen, which, result);
1863 	TRACE(("setting G%d to table #%d %s",
1864 	       which, n, visibleScsCode((int) result)));
1865     } else {
1866 	TRACE(("...unknown GSET"));
1867 	initCharset(screen, which, nrc_ASCII);
1868     }
1869 #if OPT_TRACE
1870     TRACE((" ("));
1871     if (prefix)
1872 	TRACE(("prefix='%c', ", prefix));
1873     TRACE(("suffix='%c', sgroup=%d", suffix, sgroup));
1874     TRACE((")\n"));
1875 #endif
1876 }
1877 
1878 /*
1879  * Given a parameter number, and subparameter (starting in each case from zero)
1880  * return the corresponding index into the parameter array.  If the combination
1881  * is not found, return -1.
1882  */
1883 static int
subparam_index(int p,int s)1884 subparam_index(int p, int s)
1885 {
1886     int result = -1;
1887     int j, p2, s2;
1888 
1889     for (j = p2 = 0; j < nparam; ++j, ++p2) {
1890 	if (parms.is_sub[j]) {
1891 	    s2 = 0;
1892 
1893 	    do {
1894 		if ((p == p2) && (s == s2)) {
1895 		    result = j;
1896 		    break;
1897 		}
1898 		++s2;
1899 	    } while ((++j < nparam) && (parms.is_sub[j - 1] < parms.is_sub[j]));
1900 
1901 	    if (result >= 0)
1902 		break;
1903 
1904 	    --j;		/* undo the last "while" */
1905 	} else if (p == p2) {
1906 	    if (s == 0) {
1907 		result = j;
1908 	    }
1909 	    break;
1910 	}
1911     }
1912     TRACE2(("...subparam_index %d.%d = %d\n", p + 1, s + 1, result));
1913     return result;
1914 }
1915 
1916 /*
1917  * Check if the given item in the parameter array has subparameters.
1918  * If so, return the number of subparameters to use as a loop limit, etc.
1919  */
1920 static int
param_has_subparams(int item)1921 param_has_subparams(int item)
1922 {
1923     int result = 0;
1924     if (parms.has_subparams) {
1925 	int n = subparam_index(item, 0);
1926 	if (n >= 0 && parms.is_sub[n]) {
1927 	    while (++n < nparam && parms.is_sub[n - 1] < parms.is_sub[n]) {
1928 		result++;
1929 	    }
1930 	}
1931     }
1932     TRACE(("...param_has_subparams(%d) ->%d\n", item, result));
1933     return result;
1934 }
1935 
1936 #if OPT_DIRECT_COLOR || OPT_256_COLORS || OPT_88_COLORS || OPT_ISO_COLORS
1937 /*
1938  * Given an index into the parameter array, return the corresponding parameter
1939  * number (starting from zero).
1940  */
1941 static int
param_number(int item)1942 param_number(int item)
1943 {
1944     int result = -1;
1945     int j, p;
1946 
1947     for (j = p = 0; j < nparam; ++j, ++p) {
1948 	if (p >= item) {
1949 	    result = j;
1950 	    break;
1951 	}
1952 	if (parms.is_sub[j]) {
1953 	    while ((++j < nparam) && (parms.is_sub[j - 1] < parms.is_sub[j])) {
1954 		/* EMPTY */
1955 	    }
1956 	    --j;
1957 	}
1958     }
1959 
1960     TRACE2(("...param_number(%d) = %d\n", item, result));
1961     return result;
1962 }
1963 
1964 static int
get_subparam(int p,int s)1965 get_subparam(int p, int s)
1966 {
1967     int item = subparam_index(p, s);
1968     int result = (item >= 0) ? parms.params[item] : DEFAULT;
1969     TRACE(("...get_subparam[%d] = %d\n", item, result));
1970     return result;
1971 }
1972 
1973 /*
1974  * Some background -
1975  *
1976  * Todd Larason provided the initial changes to support 256-colors in July 1999.
1977  * I pointed out that the description of SGR 38/48 in ECMA-48 was vague, and
1978  * was unsure if there would be some standard using those codes.  His response
1979  * was that this was documented (it turns out, in equally vague terms) in ITU
1980  * T.416
1981  *
1982  * Discussing this with Todd Larason in mid-1999, my point was that given the
1983  * high cost of obtaining ITU T.416 (ISO-8613-6), the standard was not going
1984  * to be effective (more than $100 then, more than $200 in 2012)
1985  *
1986  * We overlooked the detail about ":" as a subparameter delimiter (documented
1987  * in 5.4.2 in ECMA-48).  Some discussion in KDE in mid-2006 led Lars Doelle
1988  * to discuss the issue with me.  Lars' initial concern dealt with the fact
1989  * that a sequence such as
1990  *	CSI 38 ; 5 ; 1 m
1991  * violated the principle that SGR parameters could be used in any order.
1992  * Further discussion (see KDE #107487) resolved that the standard expected
1993  * that the sequence would look like
1994  *	CSI 38 ; 5 : 1 m
1995  * which still violates that principle, since the "5:1" parameter has to
1996  * follow the "38" to be useful.
1997  *
1998  * This function accepts either format (per request by Paul Leonerd Evans).
1999  * It also accepts
2000  *	CSI 38 : 5 : 1 m
2001  * according to Lars' original assumption.  While implementing that, I added
2002  * support for Konsole's interpretation of "CSI 38 : 2" as a 24-bit RGB value.
2003  * ISO-8613-6 documents that as "direct color".
2004  *
2005  * At the time in 2012, no one noticed (or commented) regarding ISO-8613-6's
2006  * quirk in the description of direct color:  it mentions a color space
2007  * identifier parameter which should follow the "2" (as parameter 1).  In the
2008  * same section, ISO-8613-6 mentions a parameter 6 which can be ignored, as
2009  * well as parameters 7 and 8.  Like parameter 1, parameters 7 and 8 are not
2010  * defined clearly in the standard, and a close reading indicates they are
2011  * optional, saying they "may be used".  This implementation ignores parameters
2012  * 6 (and above), and provides for the color space identifier by checking the
2013  * number of parameters:
2014  *	3 after "2" (no color space identifier)
2015  *	4 or more after "2" (color space identifier)
2016  *
2017  * By the way - all of the parameters are decimal integers, and missing
2018  * parameters represent a default value.  ISO-8613-6 is clear about that.
2019  *
2020  * Aside from ISO-8613-3, there is no standard use of ":" as a delimiter.
2021  * ECMA-48 says only:
2022  *
2023  *	5.4.2 Parameter string format
2024  *
2025  *	A parameter string which does not start with a bit combination in the
2026  *	range 03/12 to 03/15 shall have the following format:
2027  *
2028  *	    a) A parameter string consists of one or more parameter
2029  *	       sub-strings, each of which represents a number in decimal
2030  *	       notation.
2031  *
2032  *	    b) Each parameter sub-string consists of one or more bit
2033  *	       combinations from 03/00 to 03/10; the bit combinations from
2034  *	       03/00 to 03/09 represent the digits ZERO to NINE; bit
2035  *	       combination 03/10 may be used as a separator in a parameter
2036  *	       sub-string, for example, to separate the fractional part of a
2037  *	       decimal number from the integer part of that number.
2038  *
2039  * That is, there is no mention in ECMA-48 of the possibility that a parameter
2040  * string might be a list of parameters, as done in ISO-8613-3 (nor does
2041  * ECMA-48 provide an example where the ":" separator might be used).  Because
2042  * of this, xterm treats other cases than those needed for ISO-8613-3 as an
2043  * error, and stops interpreting the sequence.
2044  */
2045 #define extended_colors_limit(n) ((n) == 5 ? 1 : ((n) == 2 ? 3 : 0))
2046 static Boolean
parse_extended_colors(XtermWidget xw,int * colorp,int * itemp,Boolean * extended)2047 parse_extended_colors(XtermWidget xw, int *colorp, int *itemp, Boolean *extended)
2048 {
2049     Boolean result = False;
2050     int item = *itemp;
2051     int next = item;
2052     int base = param_number(item);
2053     int code = -1;
2054     int values[3];		/* maximum number of subparameters */
2055     int need = 0;		/* number of subparameters needed */
2056     int have;
2057     int n;
2058 
2059     /*
2060      * On entry, 'item' points to the 38/48 code in the parameter array.
2061      * If that has subparameters, we will expect all of the values to
2062      * be subparameters of that item.
2063      */
2064     if ((have = param_has_subparams(item)) != 0) {
2065 	/* accept CSI 38 : 5 : 1 m */
2066 	/* accept CSI 38 : 2 : 1 : 2 : 3 m */
2067 	code = get_subparam(base, 1);
2068 	need = extended_colors_limit(code);
2069 	next = item + have;
2070 	for (n = 0; n < need && n < 3; ++n) {
2071 	    values[n] = get_subparam(base, 2 + n + (have > 4));
2072 	}
2073     } else if (++item < nparam) {
2074 	++base;
2075 	if ((have = param_has_subparams(item)) != 0) {
2076 	    /* accept CSI 38 ; 5 : 1 m */
2077 	    /* accept CSI 38 ; 2 : 1 : 2 : 3 m */
2078 	    code = get_subparam(base, 0);
2079 	    need = extended_colors_limit(code);
2080 	    next = base + have;
2081 	    for (n = 0; n < need && n < 3; ++n) {
2082 		values[n] = get_subparam(base, 1 + n + (have > 3));
2083 	    }
2084 	} else {
2085 	    /* accept CSI 38 ; 5 ; 1 m */
2086 	    /* accept CSI 38 ; 2 ; 1 ; 2 ; 3 m */
2087 	    code = GetParam(item);
2088 	    need = extended_colors_limit(code);
2089 	    next = item + need;
2090 	    for (n = 0; n < need && n < 3; ++n) {
2091 		values[n] = GetParam(item + 1 + n);
2092 	    }
2093 	}
2094     }
2095     item = next;
2096 
2097     *extended = False;
2098     switch (code) {
2099     case 2:
2100 	/* direct color in rgb space */
2101 	if ((values[0] >= 0 && values[0] < 256) &&
2102 	    (values[1] >= 0 && values[1] < 256) &&
2103 	    (values[2] >= 0 && values[2] < 256)) {
2104 #if OPT_DIRECT_COLOR
2105 	    if (TScreenOf(xw)->direct_color && xw->has_rgb) {
2106 		*colorp = getDirectColor(xw, values[0], values[1], values[2]);
2107 		result = True;
2108 		*extended = True;
2109 	    } else
2110 #endif
2111 	    {
2112 		*colorp = xtermClosestColor(xw, values[0], values[1], values[2]);
2113 		result = okIndexedColor(*colorp);
2114 	    }
2115 	} else {
2116 	    *colorp = -1;
2117 	}
2118 	break;
2119     case 5:
2120 	/* indexed color */
2121 	*colorp = values[0];
2122 	result = okIndexedColor(*colorp);
2123 	break;
2124     default:
2125 	*colorp = -1;
2126 	break;
2127     }
2128 
2129     TRACE(("...resulting color %d/%d %s\n",
2130 	   *colorp, NUM_ANSI_COLORS,
2131 	   result ? "OK" : "ERR"));
2132 
2133     *itemp = item;
2134     return result;
2135 }
2136 #endif /* ...extended_colors */
2137 
2138 static int
optional_param(int which)2139 optional_param(int which)
2140 {
2141     return (nparam > which) ? GetParam(which) : DEFAULT;
2142 }
2143 
2144 static int
zero_if_default(int which)2145 zero_if_default(int which)
2146 {
2147     int result = (nparam > which) ? GetParam(which) : 0;
2148     if (result <= 0)
2149 	result = 0;
2150     return result;
2151 }
2152 
2153 static int
one_if_default(int which)2154 one_if_default(int which)
2155 {
2156     int result = (nparam > which) ? GetParam(which) : 0;
2157     if (result <= 0)
2158 	result = 1;
2159     return result;
2160 }
2161 
2162 /*
2163  * Color palette changes using the OSC controls require a repaint of the
2164  * screen - but not immediately.  Do the repaint as soon as we detect a
2165  * state which will not lead to another color palette change.
2166  */
2167 static void
repaintWhenPaletteChanged(XtermWidget xw,struct ParseState * sp)2168 repaintWhenPaletteChanged(XtermWidget xw, struct ParseState *sp)
2169 {
2170     Boolean ignore = False;
2171 
2172     switch (sp->nextstate) {
2173     case CASE_ESC:
2174 	ignore = ((sp->parsestate == ansi_table) ||
2175 		  (sp->parsestate == sos_table));
2176 #if USE_DOUBLE_BUFFER
2177 	if (resource.buffered && TScreenOf(xw)->needSwap) {
2178 	    ignore = False;
2179 	}
2180 #endif
2181 	break;
2182     case CASE_OSC:
2183 	ignore = ((sp->parsestate == ansi_table) ||
2184 		  (sp->parsestate == esc_table));
2185 	break;
2186     case CASE_IGNORE:
2187 	ignore = (sp->parsestate == sos_table);
2188 	break;
2189     case CASE_ST:
2190 	ignore = ((sp->parsestate == esc_table) ||
2191 		  (sp->parsestate == sos_table));
2192 	break;
2193     case CASE_ESC_DIGIT:
2194 	ignore = (sp->parsestate == csi_table);
2195 	break;
2196     case CASE_ESC_SEMI:
2197 	ignore = (sp->parsestate == csi2_table);
2198 	break;
2199     }
2200 
2201     if (!ignore) {
2202 	TRACE(("repaintWhenPaletteChanged\n"));
2203 	xw->work.palette_changed = False;
2204 	xtermRepaint(xw);
2205 	xtermFlushDbe(xw);
2206     }
2207 }
2208 
2209 #if OPT_C1_PRINT || OPT_WIDE_CHARS
2210 #define ParseSOS(screen) ((screen)->c1_printable == 0)
2211 #else
2212 #define ParseSOS(screen) 0
2213 #endif
2214 
2215 #define ResetState(sp) InitParams(), (sp)->parsestate = (sp)->groundtable
2216 
2217 static void
illegal_parse(XtermWidget xw,unsigned c,struct ParseState * sp)2218 illegal_parse(XtermWidget xw, unsigned c, struct ParseState *sp)
2219 {
2220     ResetState(sp);
2221     sp->nextstate = sp->parsestate[E2A(c)];
2222     Bell(xw, XkbBI_MinorError, 0);
2223 }
2224 
2225 static void
init_parser(XtermWidget xw,struct ParseState * sp)2226 init_parser(XtermWidget xw, struct ParseState *sp)
2227 {
2228     TScreen *screen = TScreenOf(xw);
2229 
2230     memset(sp, 0, sizeof(*sp));
2231     sp->scssize = 94;		/* number of printable/nonspace ASCII */
2232     sp->lastchar = -1;		/* not a legal IChar */
2233     sp->nextstate = -1;		/* not a legal state */
2234 
2235     init_groundtable(screen, sp);
2236     ResetState(sp);
2237 }
2238 
2239 static void
init_reply(unsigned type)2240 init_reply(unsigned type)
2241 {
2242     memset(&reply, 0, sizeof(reply));
2243     reply.a_type = (Char) type;
2244 }
2245 
2246 static void
deferparsing(unsigned c,struct ParseState * sp)2247 deferparsing(unsigned c, struct ParseState *sp)
2248 {
2249     SafeAlloc(Char, sp->defer_area, sp->defer_used, sp->defer_size);
2250     if (new_string == 0) {
2251 	xtermWarning("Cannot allocate %lu bytes for deferred parsing of %u\n",
2252 		     (unsigned long) new_length, c);
2253 	return;
2254     }
2255     SafeFree(sp->defer_area, sp->defer_size);
2256     sp->defer_area[(sp->defer_used)++] = CharOf(c);
2257 }
2258 
2259 #if OPT_VT52_MODE
2260 static void
update_vt52_vt100_settings(void)2261 update_vt52_vt100_settings(void)
2262 {
2263     update_autowrap();
2264     update_reversewrap();
2265     update_autolinefeed();
2266     update_appcursor();
2267     update_appkeypad();
2268     update_allow132();
2269 }
2270 #endif
2271 
2272 static Boolean
doparsing(XtermWidget xw,unsigned c,struct ParseState * sp)2273 doparsing(XtermWidget xw, unsigned c, struct ParseState *sp)
2274 {
2275     TScreen *screen = TScreenOf(xw);
2276     int item;
2277     int count;
2278     int value;
2279     int laststate;
2280     int thischar = -1;
2281     XTermRect myRect;
2282 #if OPT_DEC_RECTOPS
2283     int thispage = 1;
2284 #endif
2285 
2286     if (sp->check_recur) {
2287 	/* Defer parsing when parser is already running as the parser is not
2288 	 * safe to reenter.
2289 	 */
2290 	deferparsing(c, sp);
2291 	return True;
2292     }
2293     sp->check_recur++;
2294 
2295     do {
2296 #if OPT_WIDE_CHARS
2297 	int this_is_wide = 0;
2298 
2299 	/*
2300 	 * Handle zero-width combining characters.  Make it faster by noting
2301 	 * that according to the Unicode charts, the majority of Western
2302 	 * character sets do not use this feature.  There are some unassigned
2303 	 * codes at 0x242, but no zero-width characters until past 0x300.
2304 	 */
2305 	if (c >= 0x300
2306 	    && screen->wide_chars
2307 	    && CharWidth(screen, c) == 0
2308 	    && !isWideControl(c)) {
2309 	    int prev, test;
2310 	    Boolean used = True;
2311 	    int use_row;
2312 	    int use_col;
2313 
2314 	    WriteNow();
2315 	    use_row = (screen->char_was_written
2316 		       ? screen->last_written_row
2317 		       : screen->cur_row);
2318 	    use_col = (screen->char_was_written
2319 		       ? screen->last_written_col
2320 		       : screen->cur_col);
2321 
2322 	    /*
2323 	     * Check if the latest data can be added to the base character.
2324 	     * If there is already a combining character stored for the cell,
2325 	     * we cannot, since that would change the order.
2326 	     */
2327 	    if (screen->normalized_c
2328 		&& !IsCellCombined(screen, use_row, use_col)) {
2329 		prev = (int) XTERM_CELL(use_row, use_col);
2330 		test = do_precomposition(prev, (int) c);
2331 		TRACE(("do_precomposition (U+%04X [%d], U+%04X [%d]) -> U+%04X [%d]\n",
2332 		       prev, CharWidth(screen, prev),
2333 		       (int) c, CharWidth(screen, c),
2334 		       test, CharWidth(screen, test)));
2335 	    } else {
2336 		prev = -1;
2337 		test = -1;
2338 	    }
2339 
2340 	    /* substitute combined character with precomposed character
2341 	     * only if it does not change the width of the base character
2342 	     */
2343 	    if (test != -1
2344 		&& CharWidth(screen, test) == CharWidth(screen, prev)) {
2345 		putXtermCell(screen, use_row, use_col, test);
2346 	    } else if (screen->char_was_written
2347 		       || getXtermCell(screen, use_row, use_col) >= ' ') {
2348 		addXtermCombining(screen, use_row, use_col, c);
2349 	    } else {
2350 		/*
2351 		 * none of the above... we will add the combining character as
2352 		 * a base character.
2353 		 */
2354 		used = False;
2355 	    }
2356 
2357 	    if (used) {
2358 		if (!screen->scroll_amt)
2359 		    ScrnUpdate(xw, use_row, use_col, 1, 1, 1);
2360 		continue;
2361 	    }
2362 	}
2363 #endif
2364 
2365 	/* Intercept characters for printer controller mode */
2366 	if (PrinterOf(screen).printer_controlmode == 2) {
2367 	    if ((c = (unsigned) xtermPrinterControl(xw, (int) c)) == 0)
2368 		continue;
2369 	}
2370 
2371 	/*
2372 	 * VT52 is a little ugly in the one place it has a parameterized
2373 	 * control sequence, since the parameter falls after the character
2374 	 * that denotes the type of sequence.
2375 	 */
2376 #if OPT_VT52_MODE
2377 	if (sp->vt52_cup) {
2378 	    if (nparam < NPARAM - 1) {
2379 		SetParam(nparam++, (int) (c & 0x7f) - 32);
2380 		parms.is_sub[nparam] = 0;
2381 	    }
2382 	    if (nparam < 2)
2383 		continue;
2384 	    sp->vt52_cup = False;
2385 	    CursorSet(screen, zero_if_default(0), zero_if_default(1), xw->flags);
2386 	    sp->parsestate = vt52_table;
2387 	    SetParam(0, 0);
2388 	    SetParam(1, 0);
2389 	    continue;
2390 	}
2391 #endif
2392 
2393 	laststate = sp->nextstate;
2394 	if (c == ANSI_DEL
2395 	    && sp->parsestate == sp->groundtable
2396 	    && sp->scssize == 96
2397 	    && sp->scstype != 0) {
2398 	    /*
2399 	     * Handle special case of shifts for 96-character sets by checking
2400 	     * if we have a DEL.  The other special case for SPACE will always
2401 	     * be printable.
2402 	     */
2403 	    sp->nextstate = CASE_PRINT;
2404 	} else
2405 #if OPT_WIDE_CHARS
2406 	if (c > 255) {
2407 	    /*
2408 	     * The parsing tables all have 256 entries.  If we're supporting
2409 	     * wide characters, we handle them by treating them the same as
2410 	     * printing characters.
2411 	     */
2412 	    if (sp->parsestate == sp->groundtable) {
2413 		sp->nextstate = CASE_PRINT;
2414 	    } else if (sp->parsestate == sos_table) {
2415 		c &= WIDEST_ICHAR;
2416 		if (c > 255) {
2417 		    TRACE(("Found code > 255 while in SOS state: %04X\n", c));
2418 		    c = BAD_ASCII;
2419 		}
2420 	    } else {
2421 		sp->nextstate = CASE_GROUND_STATE;
2422 	    }
2423 	} else
2424 #endif
2425 	    sp->nextstate = sp->parsestate[E2A(c)];
2426 
2427 #if OPT_BROKEN_OSC
2428 	/*
2429 	 * Linux console palette escape sequences start with an OSC, but do
2430 	 * not terminate correctly.  Some scripts do not check before writing
2431 	 * them, making xterm appear to hang (it's awaiting a valid string
2432 	 * terminator).  Just ignore these if we see them - there's no point
2433 	 * in emulating bad code.
2434 	 */
2435 	if (screen->brokenLinuxOSC
2436 	    && sp->parsestate == sos_table) {
2437 	    if (sp->string_used) {
2438 		switch (sp->string_area[0]) {
2439 		case 'P':
2440 		    if (sp->string_used <= 7)
2441 			break;
2442 		    /* FALLTHRU */
2443 		case 'R':
2444 		    illegal_parse(xw, c, sp);
2445 		    TRACE(("Reset to ground state (brokenLinuxOSC)\n"));
2446 		    break;
2447 		}
2448 	    }
2449 	}
2450 #endif
2451 
2452 #if OPT_BROKEN_ST
2453 	/*
2454 	 * Before patch #171, carriage control embedded within an OSC string
2455 	 * would terminate it.  Some (buggy, of course) applications rely on
2456 	 * this behavior.  Accommodate them by allowing one to compile xterm
2457 	 * and emulate the old behavior.
2458 	 */
2459 	if (screen->brokenStringTerm
2460 	    && sp->parsestate == sos_table
2461 	    && c < 32) {
2462 	    switch (c) {
2463 	    case ANSI_EOT:	/* FALLTHRU */
2464 	    case ANSI_BS:	/* FALLTHRU */
2465 	    case ANSI_HT:	/* FALLTHRU */
2466 	    case ANSI_LF:	/* FALLTHRU */
2467 	    case ANSI_VT:	/* FALLTHRU */
2468 	    case ANSI_FF:	/* FALLTHRU */
2469 	    case ANSI_CR:	/* FALLTHRU */
2470 	    case ANSI_SO:	/* FALLTHRU */
2471 	    case ANSI_SI:	/* FALLTHRU */
2472 	    case ANSI_XON:	/* FALLTHRU */
2473 	    case ANSI_CAN:
2474 		illegal_parse(xw, c, sp);
2475 		TRACE(("Reset to ground state (brokenStringTerm)\n"));
2476 		break;
2477 	    }
2478 	}
2479 #endif
2480 
2481 #if OPT_C1_PRINT
2482 	/*
2483 	 * This is not completely foolproof, but will allow an application
2484 	 * with values in the C1 range to use them as printable characters,
2485 	 * provided that they are not intermixed with an escape sequence.
2486 	 */
2487 	if (screen->c1_printable
2488 	    && (c >= 128 && c < 256)) {
2489 	    sp->nextstate = (sp->parsestate == esc_table
2490 			     ? CASE_ESC_IGNORE
2491 			     : sp->parsestate[E2A(160)]);
2492 	    TRACE(("allowC1Printable %04X %s ->%s\n",
2493 		   c, which_table(sp->parsestate),
2494 		   visibleVTparse(sp->nextstate)));
2495 	}
2496 #endif
2497 
2498 #if OPT_WIDE_CHARS
2499 	/*
2500 	 * If we have a C1 code and the c1_printable flag is not set, simply
2501 	 * ignore it when it was translated from UTF-8.  That is because the
2502 	 * value could not have been present as-is in the UTF-8.
2503 	 *
2504 	 * To see that CASE_IGNORE is a consistent value, note that it is
2505 	 * always used for NUL and other uninteresting C0 controls.
2506 	 */
2507 #if OPT_C1_PRINT
2508 	if (!screen->c1_printable)
2509 #endif
2510 	    if (screen->wide_chars
2511 		&& (c >= 128 && c < 160)) {
2512 		sp->nextstate = CASE_IGNORE;
2513 	    }
2514 
2515 	/*
2516 	 * If this character is a different width than the last one, put the
2517 	 * previous text into the buffer and draw it now.
2518 	 */
2519 	this_is_wide = isWide((int) c);
2520 	if (this_is_wide != sp->last_was_wide) {
2521 	    WriteNow();
2522 	}
2523 #endif
2524 
2525 	/*
2526 	 * Accumulate string for printable text.  This may be 8/16-bit
2527 	 * characters.
2528 	 */
2529 	if (sp->nextstate == CASE_PRINT) {
2530 	    SafeAlloc(IChar, sp->print_area, sp->print_used, sp->print_size);
2531 	    if (new_string == 0) {
2532 		xtermWarning("Cannot allocate %lu bytes for printable text\n",
2533 			     (unsigned long) new_length);
2534 		continue;
2535 	    }
2536 	    SafeFree(sp->print_area, sp->print_size);
2537 #if OPT_VT52_MODE
2538 	    /*
2539 	     * Strip output text to 7-bits for VT52.  We should do this for
2540 	     * VT100 also (which is a 7-bit device), but xterm has been
2541 	     * doing this for so long we shouldn't change this behavior.
2542 	     */
2543 	    if (screen->vtXX_level < 1)
2544 		c &= 0x7f;
2545 #endif
2546 	    sp->print_area[sp->print_used++] = (IChar) c;
2547 	    sp->lastchar = thischar = (int) c;
2548 #if OPT_WIDE_CHARS
2549 	    sp->last_was_wide = this_is_wide;
2550 #endif
2551 	    if (morePtyData(screen, VTbuffer)) {
2552 		continue;
2553 	    }
2554 	}
2555 
2556 	if (sp->nextstate == CASE_PRINT
2557 	    || (laststate == CASE_PRINT && sp->print_used)) {
2558 	    WriteNow();
2559 	}
2560 
2561 	/*
2562 	 * Accumulate string for APC, DCS, PM, OSC, SOS controls
2563 	 * This should always be 8-bit characters.
2564 	 */
2565 	if (sp->parsestate == sos_table) {
2566 	    SafeAlloc(Char, sp->string_area, sp->string_used, sp->string_size);
2567 	    if (new_string == 0) {
2568 		xtermWarning("Cannot allocate %lu bytes for string mode %d\n",
2569 			     (unsigned long) new_length, sp->string_mode);
2570 		continue;
2571 	    }
2572 	    SafeFree(sp->string_area, sp->string_size);
2573 #if OPT_WIDE_CHARS
2574 	    /*
2575 	     * We cannot display codes above 255, but let's try to
2576 	     * accommodate the application a little by not aborting the
2577 	     * string.
2578 	     */
2579 	    if ((c & WIDEST_ICHAR) > 255) {
2580 		sp->nextstate = CASE_PRINT;
2581 		c = BAD_ASCII;
2582 	    }
2583 #endif
2584 	    sp->string_area[(sp->string_used)++] = CharOf(c);
2585 	} else if (sp->parsestate != esc_table) {
2586 	    /* if we were accumulating, we're not any more */
2587 	    sp->string_mode = 0;
2588 	    sp->string_used = 0;
2589 	}
2590 
2591 	DumpParams();
2592 	TRACE(("parse %04X -> %s %s (used=%lu)\n",
2593 	       c, visibleVTparse(sp->nextstate),
2594 	       which_table(sp->parsestate),
2595 	       (unsigned long) sp->string_used));
2596 
2597 	/*
2598 	 * If the parameter list has subparameters (tokens separated by ":")
2599 	 * reject any controls that do not accept subparameters.
2600 	 */
2601 	if (parms.has_subparams) {
2602 	    switch (sp->nextstate) {
2603 	    case CASE_GROUND_STATE:
2604 	    case CASE_CSI_IGNORE:
2605 		/* FALLTHRU */
2606 
2607 	    case CASE_ESC_DIGIT:
2608 	    case CASE_ESC_SEMI:
2609 	    case CASE_ESC_COLON:
2610 		/* these states are required to parse parameter lists */
2611 		break;
2612 
2613 	    case CASE_SGR:
2614 		TRACE(("...possible subparam usage\n"));
2615 		break;
2616 
2617 	    case CASE_CSI_DEC_DOLLAR_STATE:
2618 	    case CASE_CSI_DOLLAR_STATE:
2619 	    case CASE_CSI_HASH_STATE:
2620 	    case CASE_CSI_EX_STATE:
2621 	    case CASE_CSI_QUOTE_STATE:
2622 	    case CASE_CSI_SPACE_STATE:
2623 	    case CASE_CSI_STAR_STATE:
2624 	    case CASE_CSI_TICK_STATE:
2625 	    case CASE_DEC2_STATE:
2626 	    case CASE_DEC3_STATE:
2627 	    case CASE_DEC_STATE:
2628 		/* use this branch when we do not yet have the final character */
2629 		TRACE(("...unexpected subparam usage\n"));
2630 		InitParams();
2631 		sp->nextstate = CASE_CSI_IGNORE;
2632 		break;
2633 
2634 	    default:
2635 		/* use this branch for cases where we have the final character
2636 		 * in the table that processed the parameter list.
2637 		 */
2638 		TRACE(("...unexpected subparam usage\n"));
2639 		ResetState(sp);
2640 		continue;
2641 	    }
2642 	}
2643 
2644 	if (xw->work.palette_changed) {
2645 	    repaintWhenPaletteChanged(xw, sp);
2646 	}
2647 
2648 	switch (sp->nextstate) {
2649 	case CASE_PRINT:
2650 	    TRACE(("CASE_PRINT - printable characters\n"));
2651 	    break;
2652 
2653 	case CASE_GROUND_STATE:
2654 	    TRACE(("CASE_GROUND_STATE - exit ignore mode\n"));
2655 	    ResetState(sp);
2656 	    break;
2657 
2658 	case CASE_IGNORE:
2659 	    TRACE(("CASE_IGNORE - Ignore character %02X\n", c));
2660 	    break;
2661 
2662 	case CASE_ENQ:
2663 	    TRACE(("CASE_ENQ - answerback\n"));
2664 	    if (((xw->keyboard.flags & MODE_SRM) == 0)
2665 		? (sp->check_recur == 0)
2666 		: (sp->check_recur <= 1)) {
2667 		for (count = 0; screen->answer_back[count] != 0; count++)
2668 		    unparseputc(xw, screen->answer_back[count]);
2669 		unparse_end(xw);
2670 	    }
2671 	    break;
2672 
2673 	case CASE_BELL:
2674 	    TRACE(("CASE_BELL - bell\n"));
2675 	    if (sp->string_mode == ANSI_OSC) {
2676 		if (sp->string_used)
2677 		    sp->string_area[--(sp->string_used)] = '\0';
2678 		if (sp->check_recur <= 1)
2679 		    do_osc(xw, sp->string_area, sp->string_used, (int) c);
2680 		ResetState(sp);
2681 	    } else {
2682 		/* bell */
2683 		Bell(xw, XkbBI_TerminalBell, 0);
2684 	    }
2685 	    break;
2686 
2687 	case CASE_BS:
2688 	    TRACE(("CASE_BS - backspace\n"));
2689 	    CursorBack(xw, 1);
2690 	    break;
2691 
2692 	case CASE_CR:
2693 	    TRACE(("CASE_CR\n"));
2694 	    CarriageReturn(xw);
2695 	    break;
2696 
2697 	case CASE_ESC:
2698 	    if_OPT_VT52_MODE(screen, {
2699 		sp->parsestate = vt52_esc_table;
2700 		break;
2701 	    });
2702 	    sp->parsestate = esc_table;
2703 	    break;
2704 
2705 #if OPT_VT52_MODE
2706 	case CASE_VT52_CUP:
2707 	    TRACE(("CASE_VT52_CUP - VT52 cursor addressing\n"));
2708 	    sp->vt52_cup = True;
2709 	    ResetState(sp);
2710 	    break;
2711 
2712 	case CASE_VT52_IGNORE:
2713 	    TRACE(("CASE_VT52_IGNORE - VT52 ignore-character\n"));
2714 	    sp->parsestate = vt52_ignore_table;
2715 	    break;
2716 #endif
2717 
2718 	case CASE_VMOT:
2719 	    TRACE(("CASE_VMOT\n"));
2720 	    /*
2721 	     * form feed, line feed, vertical tab
2722 	     */
2723 	    xtermAutoPrint(xw, c);
2724 	    xtermIndex(xw, 1);
2725 	    if (xw->flags & LINEFEED)
2726 		CarriageReturn(xw);
2727 	    else
2728 		do_xevents(xw);
2729 	    break;
2730 
2731 	case CASE_CBT:
2732 	    TRACE(("CASE_CBT\n"));
2733 	    /* cursor backward tabulation */
2734 	    count = one_if_default(0);
2735 	    while ((count-- > 0)
2736 		   && (TabToPrevStop(xw))) ;
2737 	    ResetState(sp);
2738 	    break;
2739 
2740 	case CASE_CHT:
2741 	    TRACE(("CASE_CHT\n"));
2742 	    /* cursor forward tabulation */
2743 	    count = one_if_default(0);
2744 	    while ((count-- > 0)
2745 		   && (TabToNextStop(xw))) ;
2746 	    ResetState(sp);
2747 	    break;
2748 
2749 	case CASE_TAB:
2750 	    /* tab */
2751 	    TabToNextStop(xw);
2752 	    break;
2753 
2754 	case CASE_SI:
2755 	    screen->curgl = 0;
2756 	    if_OPT_VT52_MODE(screen, {
2757 		ResetState(sp);
2758 	    });
2759 	    break;
2760 
2761 	case CASE_SO:
2762 	    screen->curgl = 1;
2763 	    if_OPT_VT52_MODE(screen, {
2764 		ResetState(sp);
2765 	    });
2766 	    break;
2767 
2768 	case CASE_DECDHL:
2769 	    xterm_DECDHL(xw, c == '3');
2770 	    ResetState(sp);
2771 	    break;
2772 
2773 	case CASE_DECSWL:
2774 	    xterm_DECSWL(xw);
2775 	    ResetState(sp);
2776 	    break;
2777 
2778 	case CASE_DECDWL:
2779 	    xterm_DECDWL(xw);
2780 	    ResetState(sp);
2781 	    break;
2782 
2783 	case CASE_SCR_STATE:
2784 	    /* enter scr state */
2785 	    sp->parsestate = scrtable;
2786 	    break;
2787 
2788 	case CASE_SCS0_STATE:
2789 	    /* enter scs state 0 */
2790 	    select_charset(sp, 0, 94);
2791 	    break;
2792 
2793 	case CASE_SCS1_STATE:
2794 	    /* enter scs state 1 */
2795 	    select_charset(sp, 1, 94);
2796 	    break;
2797 
2798 	case CASE_SCS2_STATE:
2799 	    /* enter scs state 2 */
2800 	    select_charset(sp, 2, 94);
2801 	    break;
2802 
2803 	case CASE_SCS3_STATE:
2804 	    /* enter scs state 3 */
2805 	    select_charset(sp, 3, 94);
2806 	    break;
2807 
2808 	case CASE_SCS1A_STATE:
2809 	    /* enter scs state 1 */
2810 	    select_charset(sp, 1, 96);
2811 	    break;
2812 
2813 	case CASE_SCS2A_STATE:
2814 	    /* enter scs state 2 */
2815 	    select_charset(sp, 2, 96);
2816 	    break;
2817 
2818 	case CASE_SCS3A_STATE:
2819 	    /* enter scs state 3 */
2820 	    select_charset(sp, 3, 96);
2821 	    break;
2822 
2823 	case CASE_ESC_IGNORE:
2824 	    /* unknown escape sequence */
2825 	    sp->parsestate = eigtable;
2826 	    break;
2827 
2828 	case CASE_ESC_DIGIT:
2829 	    /* digit in csi or dec mode */
2830 	    if (nparam > 0) {
2831 		value = zero_if_default(nparam - 1);
2832 		SetParam(nparam - 1, (10 * value) + ((int) c - '0'));
2833 		if (GetParam(nparam - 1) > MAX_I_PARAM)
2834 		    SetParam(nparam - 1, MAX_I_PARAM);
2835 		if (sp->parsestate == csi_table)
2836 		    sp->parsestate = csi2_table;
2837 	    }
2838 	    break;
2839 
2840 	case CASE_ESC_SEMI:
2841 	    /* semicolon in csi or dec mode */
2842 	    if (nparam < NPARAM) {
2843 		parms.is_sub[nparam] = 0;
2844 		SetParam(nparam++, DEFAULT);
2845 	    }
2846 	    if (sp->parsestate == csi_table)
2847 		sp->parsestate = csi2_table;
2848 	    break;
2849 
2850 	    /*
2851 	     * A _few_ commands accept colon-separated subparameters.
2852 	     * Mark the parameter list so that we can exclude (most) bogus
2853 	     * commands with simple/fast checks.
2854 	     */
2855 	case CASE_ESC_COLON:
2856 	    if (nparam < NPARAM) {
2857 		parms.has_subparams = 1;
2858 		if (nparam == 0) {
2859 		    parms.is_sub[nparam] = 1;
2860 		    SetParam(nparam++, DEFAULT);
2861 		} else if (parms.is_sub[nparam - 1] == 0) {
2862 		    parms.is_sub[nparam - 1] = 1;
2863 		    parms.is_sub[nparam] = 2;
2864 		    parms.params[nparam] = 0;
2865 		    ++nparam;
2866 		} else {
2867 		    parms.is_sub[nparam] = 1 + parms.is_sub[nparam - 1];
2868 		    parms.params[nparam] = 0;
2869 		    ++nparam;
2870 		}
2871 	    }
2872 	    break;
2873 
2874 	case CASE_DEC_STATE:
2875 	    /* enter dec mode */
2876 	    sp->parsestate = dec_table;
2877 	    break;
2878 
2879 	case CASE_DEC2_STATE:
2880 	    /* enter dec2 mode */
2881 	    sp->parsestate = dec2_table;
2882 	    break;
2883 
2884 	case CASE_DEC3_STATE:
2885 	    /* enter dec3 mode */
2886 	    sp->parsestate = dec3_table;
2887 	    break;
2888 
2889 	case CASE_ICH:
2890 	    TRACE(("CASE_ICH - insert char\n"));
2891 	    InsertChar(xw, (unsigned) one_if_default(0));
2892 	    ResetState(sp);
2893 	    break;
2894 
2895 	case CASE_CUU:
2896 	    TRACE(("CASE_CUU - cursor up\n"));
2897 	    CursorUp(screen, one_if_default(0));
2898 	    ResetState(sp);
2899 	    break;
2900 
2901 	case CASE_CUD:
2902 	    TRACE(("CASE_CUD - cursor down\n"));
2903 	    CursorDown(screen, one_if_default(0));
2904 	    ResetState(sp);
2905 	    break;
2906 
2907 	case CASE_CUF:
2908 	    TRACE(("CASE_CUF - cursor forward\n"));
2909 	    CursorForward(xw, one_if_default(0));
2910 	    ResetState(sp);
2911 	    break;
2912 
2913 	case CASE_CUB:
2914 	    TRACE(("CASE_CUB - cursor backward\n"));
2915 	    CursorBack(xw, one_if_default(0));
2916 	    ResetState(sp);
2917 	    break;
2918 
2919 	case CASE_CUP:
2920 	    TRACE(("CASE_CUP - cursor position\n"));
2921 	    if_OPT_XMC_GLITCH(screen, {
2922 		Jump_XMC(xw);
2923 	    });
2924 	    CursorSet(screen, one_if_default(0) - 1, one_if_default(1) - 1, xw->flags);
2925 	    ResetState(sp);
2926 	    break;
2927 
2928 	case CASE_VPA:
2929 	    TRACE(("CASE_VPA - vertical position absolute\n"));
2930 	    CursorSet(screen, one_if_default(0) - 1, CursorCol(xw), xw->flags);
2931 	    ResetState(sp);
2932 	    break;
2933 
2934 	case CASE_HPA:
2935 	    TRACE(("CASE_HPA - horizontal position absolute\n"));
2936 	    CursorSet(screen, CursorRow(xw), one_if_default(0) - 1, xw->flags);
2937 	    ResetState(sp);
2938 	    break;
2939 
2940 	case CASE_VPR:
2941 	    TRACE(("CASE_VPR - vertical position relative\n"));
2942 	    CursorSet(screen,
2943 		      CursorRow(xw) + one_if_default(0),
2944 		      CursorCol(xw),
2945 		      xw->flags);
2946 	    ResetState(sp);
2947 	    break;
2948 
2949 	case CASE_HPR:
2950 	    TRACE(("CASE_HPR - horizontal position relative\n"));
2951 	    CursorSet(screen,
2952 		      CursorRow(xw),
2953 		      CursorCol(xw) + one_if_default(0),
2954 		      xw->flags);
2955 	    ResetState(sp);
2956 	    break;
2957 
2958 	case CASE_HP_BUGGY_LL:
2959 	    TRACE(("CASE_HP_BUGGY_LL\n"));
2960 	    /* Some HP-UX applications have the bug that they
2961 	       assume ESC F goes to the lower left corner of
2962 	       the screen, regardless of what terminfo says. */
2963 	    if (screen->hp_ll_bc)
2964 		CursorSet(screen, screen->max_row, 0, xw->flags);
2965 	    ResetState(sp);
2966 	    break;
2967 
2968 	case CASE_ED:
2969 	    TRACE(("CASE_ED - erase display\n"));
2970 	    do_cd_xtra_scroll(xw, zero_if_default(0));
2971 	    do_erase_display(xw, zero_if_default(0), OFF_PROTECT);
2972 	    ResetState(sp);
2973 	    break;
2974 
2975 	case CASE_EL:
2976 	    TRACE(("CASE_EL - erase line\n"));
2977 	    do_erase_line(xw, zero_if_default(0), OFF_PROTECT);
2978 	    ResetState(sp);
2979 	    break;
2980 
2981 	case CASE_ECH:
2982 	    TRACE(("CASE_ECH - erase char\n"));
2983 	    /* ECH */
2984 	    do_erase_char(xw, one_if_default(0), OFF_PROTECT);
2985 	    ResetState(sp);
2986 	    break;
2987 
2988 	case CASE_IL:
2989 	    TRACE(("CASE_IL - insert line\n"));
2990 	    InsertLine(xw, one_if_default(0));
2991 	    ResetState(sp);
2992 	    break;
2993 
2994 	case CASE_DL:
2995 	    TRACE(("CASE_DL - delete line\n"));
2996 	    DeleteLine(xw, one_if_default(0), True);
2997 	    ResetState(sp);
2998 	    break;
2999 
3000 	case CASE_DCH:
3001 	    TRACE(("CASE_DCH - delete char\n"));
3002 	    DeleteChar(xw, (unsigned) one_if_default(0));
3003 	    ResetState(sp);
3004 	    break;
3005 
3006 	case CASE_TRACK_MOUSE:
3007 	    /*
3008 	     * A single parameter other than zero is always scroll-down.
3009 	     * A zero-parameter is used to reset the mouse mode, and is
3010 	     * not useful for scrolling anyway.
3011 	     */
3012 	    if (nparam > 1 || GetParam(0) == 0) {
3013 		CELL start;
3014 
3015 		TRACE(("CASE_TRACK_MOUSE\n"));
3016 		/* Track mouse as long as in window and between
3017 		 * specified rows
3018 		 */
3019 		start.row = one_if_default(2) - 1;
3020 		start.col = GetParam(1) - 1;
3021 		TrackMouse(xw,
3022 			   GetParam(0),
3023 			   &start,
3024 			   GetParam(3) - 1, GetParam(4) - 2);
3025 	    } else {
3026 		TRACE(("CASE_SD - scroll down\n"));
3027 		/* SD */
3028 		RevScroll(xw, one_if_default(0));
3029 		do_xevents(xw);
3030 	    }
3031 	    ResetState(sp);
3032 	    break;
3033 
3034 	case CASE_SD:
3035 	    /*
3036 	     * Cater to ECMA-48's typographical error...
3037 	     */
3038 	    TRACE(("CASE_SD - scroll down\n"));
3039 	    RevScroll(xw, one_if_default(0));
3040 	    do_xevents(xw);
3041 	    ResetState(sp);
3042 	    break;
3043 
3044 	case CASE_DECID:
3045 	    TRACE(("CASE_DECID\n"));
3046 	    if_OPT_VT52_MODE(screen, {
3047 		unparseputc(xw, ANSI_ESC);
3048 		unparseputc(xw, '/');
3049 		unparseputc(xw, 'Z');
3050 		unparse_end(xw);
3051 		ResetState(sp);
3052 		break;
3053 	    });
3054 	    SetParam(0, DEFAULT);	/* Default ID parameter */
3055 	    /* FALLTHRU */
3056 	case CASE_DA1:
3057 	    TRACE(("CASE_DA1\n"));
3058 	    if (GetParam(0) <= 0) {	/* less than means DEFAULT */
3059 		count = 0;
3060 		init_reply(ANSI_CSI);
3061 		reply.a_pintro = '?';
3062 
3063 		/*
3064 		 * The first parameter corresponds to the highest operating
3065 		 * level (i.e., service level) of the emulation.  A DEC
3066 		 * terminal can be setup to respond with a different DA
3067 		 * response, but there's no control sequence that modifies
3068 		 * this.  We set it via a resource.
3069 		 */
3070 		if (screen->terminal_id < 200) {
3071 		    switch (screen->terminal_id) {
3072 		    case 132:
3073 			reply.a_param[count++] = 4;	/* VT132 */
3074 #if OPT_REGIS_GRAPHICS
3075 			reply.a_param[count++] = 6;	/* no STP, AVO, GPO (ReGIS) */
3076 #else
3077 			reply.a_param[count++] = 2;	/* no STP, AVO, no GPO (ReGIS) */
3078 #endif
3079 			break;
3080 		    case 131:
3081 			reply.a_param[count++] = 7;	/* VT131 */
3082 			break;
3083 		    case 125:
3084 			reply.a_param[count++] = 12;	/* VT125 */
3085 #if OPT_REGIS_GRAPHICS
3086 			reply.a_param[count++] = 0 | 2 | 1;	/* no STP, AVO, GPO (ReGIS) */
3087 #else
3088 			reply.a_param[count++] = 0 | 2 | 0;	/* no STP, AVO, no GPO (ReGIS) */
3089 #endif
3090 			reply.a_param[count++] = 0;	/* no printer */
3091 			reply.a_param[count++] = XTERM_PATCH;	/* ROM version */
3092 			break;
3093 		    case 102:
3094 			reply.a_param[count++] = 6;	/* VT102 */
3095 			break;
3096 		    case 101:
3097 			reply.a_param[count++] = 1;	/* VT101 */
3098 			reply.a_param[count++] = 0;	/* no options */
3099 			break;
3100 		    default:	/* VT100 */
3101 			reply.a_param[count++] = 1;	/* VT100 */
3102 			reply.a_param[count++] = 0 | 2 | 0;	/* no STP, AVO, no GPO (ReGIS) */
3103 			break;
3104 		    }
3105 		} else {
3106 		    reply.a_param[count++] = (ParmType) (60
3107 							 + screen->terminal_id
3108 							 / 100);
3109 		    reply.a_param[count++] = 1;		/* 132-columns */
3110 		    reply.a_param[count++] = 2;		/* printer */
3111 #if OPT_REGIS_GRAPHICS
3112 		    if (optRegisGraphics(screen)) {
3113 			reply.a_param[count++] = 3;	/* ReGIS graphics */
3114 		    }
3115 #endif
3116 #if OPT_SIXEL_GRAPHICS
3117 		    if (optSixelGraphics(screen)) {
3118 			reply.a_param[count++] = 4;	/* sixel graphics */
3119 		    }
3120 #endif
3121 		    reply.a_param[count++] = 6;		/* selective-erase */
3122 #if OPT_SUNPC_KBD
3123 		    if (xw->keyboard.type == keyboardIsVT220)
3124 #endif
3125 			reply.a_param[count++] = 8;	/* user-defined-keys */
3126 		    reply.a_param[count++] = 9;		/* national replacement charsets */
3127 		    reply.a_param[count++] = 15;	/* technical characters */
3128 		    reply.a_param[count++] = 16;	/* locator port */
3129 		    if (screen->terminal_id >= 400) {
3130 			reply.a_param[count++] = 17;	/* terminal state interrogation */
3131 			reply.a_param[count++] = 18;	/* windowing extension */
3132 			reply.a_param[count++] = 21;	/* horizontal scrolling */
3133 		    }
3134 		    if_OPT_ISO_COLORS(screen, {
3135 			reply.a_param[count++] = 22;	/* ANSI color, VT525 */
3136 		    });
3137 		    reply.a_param[count++] = 28;	/* rectangular editing */
3138 #if OPT_DEC_LOCATOR
3139 		    reply.a_param[count++] = 29;	/* ANSI text locator */
3140 #endif
3141 		}
3142 		reply.a_nparam = (ParmType) count;
3143 		reply.a_inters = 0;
3144 		reply.a_final = 'c';
3145 		unparseseq(xw, &reply);
3146 	    }
3147 	    ResetState(sp);
3148 	    break;
3149 
3150 	case CASE_DA2:
3151 	    TRACE(("CASE_DA2\n"));
3152 	    if (GetParam(0) <= 0) {	/* less than means DEFAULT */
3153 		count = 0;
3154 		init_reply(ANSI_CSI);
3155 		reply.a_pintro = '>';
3156 
3157 		if (screen->terminal_id >= 200) {
3158 		    switch (screen->terminal_id) {
3159 		    case 220:
3160 		    default:
3161 			reply.a_param[count++] = 1;	/* VT220 */
3162 			break;
3163 		    case 240:
3164 		    case 241:
3165 			/* http://www.decuslib.com/DECUS/vax87a/gendyn/vt200_kind.lis */
3166 			reply.a_param[count++] = 2;	/* VT240 */
3167 			break;
3168 		    case 320:
3169 			/* http://www.vt100.net/docs/vt320-uu/appendixe.html */
3170 			reply.a_param[count++] = 24;	/* VT320 */
3171 			break;
3172 		    case 330:
3173 			reply.a_param[count++] = 18;	/* VT330 */
3174 			break;
3175 		    case 340:
3176 			reply.a_param[count++] = 19;	/* VT340 */
3177 			break;
3178 		    case 382:
3179 			reply.a_param[count++] = 32;	/* VT382 */
3180 			break;
3181 		    case 420:
3182 			reply.a_param[count++] = 41;	/* VT420 */
3183 			break;
3184 		    case 510:
3185 			/* http://www.vt100.net/docs/vt510-rm/DA2 */
3186 			reply.a_param[count++] = 61;	/* VT510 */
3187 			break;
3188 		    case 520:
3189 			reply.a_param[count++] = 64;	/* VT520 */
3190 			break;
3191 		    case 525:
3192 			reply.a_param[count++] = 65;	/* VT525 */
3193 			break;
3194 		    }
3195 		} else {
3196 		    reply.a_param[count++] = 0;		/* VT100 (nonstandard) */
3197 		}
3198 		reply.a_param[count++] = XTERM_PATCH;	/* Version */
3199 		reply.a_param[count++] = 0;	/* options (none) */
3200 		reply.a_nparam = (ParmType) count;
3201 		reply.a_inters = 0;
3202 		reply.a_final = 'c';
3203 		unparseseq(xw, &reply);
3204 	    }
3205 	    ResetState(sp);
3206 	    break;
3207 
3208 	case CASE_DECRPTUI:
3209 	    TRACE(("CASE_DECRPTUI\n"));
3210 	    if ((screen->vtXX_level >= 4)
3211 		&& (GetParam(0) <= 0)) {	/* less than means DEFAULT */
3212 		unparseputc1(xw, ANSI_DCS);
3213 		unparseputc(xw, '!');
3214 		unparseputc(xw, '|');
3215 		/* report the "terminal unit id" as 4 pairs of hexadecimal
3216 		 * digits -- meaningless for a terminal emulator, but some
3217 		 * host may care about the format.
3218 		 */
3219 		for (count = 0; count < 8; ++count) {
3220 		    unparseputc(xw, '0');
3221 		}
3222 		unparseputc1(xw, ANSI_ST);
3223 		unparse_end(xw);
3224 	    }
3225 	    ResetState(sp);
3226 	    break;
3227 
3228 	case CASE_TBC:
3229 	    TRACE(("CASE_TBC - tab clear\n"));
3230 	    if ((value = GetParam(0)) <= 0)	/* less than means default */
3231 		TabClear(xw->tabs, screen->cur_col);
3232 	    else if (value == 3)
3233 		TabZonk(xw->tabs);
3234 	    ResetState(sp);
3235 	    break;
3236 
3237 	case CASE_SET:
3238 	    TRACE(("CASE_SET - set mode\n"));
3239 	    ansi_modes(xw, bitset);
3240 	    ResetState(sp);
3241 	    break;
3242 
3243 	case CASE_RST:
3244 	    TRACE(("CASE_RST - reset mode\n"));
3245 	    ansi_modes(xw, bitclr);
3246 	    ResetState(sp);
3247 	    break;
3248 
3249 	case CASE_SGR:
3250 	    for (item = 0; item < nparam; ++item) {
3251 		int op = GetParam(item);
3252 		int skip;
3253 
3254 		if_OPT_XMC_GLITCH(screen, {
3255 		    Mark_XMC(xw, op);
3256 		});
3257 		TRACE(("CASE_SGR %d\n", op));
3258 
3259 		/*
3260 		 * Only SGR 38/48 accept subparameters, and in those cases
3261 		 * the values will not be seen at this point.
3262 		 */
3263 		if ((skip = param_has_subparams(item))) {
3264 		    switch (op) {
3265 		    case 38:
3266 			/* FALLTHRU */
3267 		    case 48:
3268 			if_OPT_ISO_COLORS(screen, {
3269 			    break;
3270 			});
3271 			/* FALLTHRU */
3272 		    default:
3273 			TRACE(("...unexpected subparameter in SGR\n"));
3274 			item += skip;	/* ignore this */
3275 			op = NPARAM;	/* will never use this, anyway */
3276 			break;
3277 		    }
3278 		}
3279 
3280 		switch (op) {
3281 		case DEFAULT:
3282 		    /* FALLTHRU */
3283 		case 0:
3284 		    resetRendition(xw);
3285 		    if_OPT_ISO_COLORS(screen, {
3286 			reset_SGR_Colors(xw);
3287 		    });
3288 		    break;
3289 		case 1:	/* Bold                 */
3290 		    UIntSet(xw->flags, BOLD);
3291 		    if_OPT_ISO_COLORS(screen, {
3292 			setExtendedFG(xw);
3293 		    });
3294 		    break;
3295 #if OPT_WIDE_ATTRS
3296 		case 2:	/* faint, decreased intensity or second colour */
3297 		    UIntSet(xw->flags, ATR_FAINT);
3298 		    if_OPT_ISO_COLORS(screen, {
3299 			setExtendedFG(xw);
3300 		    });
3301 		    break;
3302 		case 3:	/* italicized */
3303 		    setItalicFont(xw, UseItalicFont(screen));
3304 		    UIntSet(xw->flags, ATR_ITALIC);
3305 		    if_OPT_ISO_COLORS(screen, {
3306 			setExtendedFG(xw);
3307 		    });
3308 		    break;
3309 #endif
3310 		case 4:	/* Underscore           */
3311 		    UIntSet(xw->flags, UNDERLINE);
3312 		    if_OPT_ISO_COLORS(screen, {
3313 			setExtendedFG(xw);
3314 		    });
3315 		    break;
3316 		case 5:	/* Blink (less than 150 per minute) */
3317 		    /* FALLTHRU */
3318 		case 6:	/* Blink (150 per minute, or more) */
3319 		    UIntSet(xw->flags, BLINK);
3320 		    StartBlinking(xw);
3321 		    if_OPT_ISO_COLORS(screen, {
3322 			setExtendedFG(xw);
3323 		    });
3324 		    break;
3325 		case 7:
3326 		    UIntSet(xw->flags, INVERSE);
3327 		    if_OPT_ISO_COLORS(screen, {
3328 			setExtendedBG(xw);
3329 		    });
3330 		    break;
3331 		case 8:
3332 		    UIntSet(xw->flags, INVISIBLE);
3333 		    break;
3334 #if OPT_WIDE_ATTRS
3335 		case 9:	/* crossed-out characters */
3336 		    UIntSet(xw->flags, ATR_STRIKEOUT);
3337 		    break;
3338 #endif
3339 #if OPT_WIDE_ATTRS
3340 		case 21:	/* doubly-underlined */
3341 		    UIntSet(xw->flags, ATR_DBL_UNDER);
3342 		    break;
3343 #endif
3344 		case 22:	/* reset 'bold' */
3345 		    UIntClr(xw->flags, BOLD);
3346 #if OPT_WIDE_ATTRS
3347 		    UIntClr(xw->flags, ATR_FAINT);
3348 #endif
3349 		    if_OPT_ISO_COLORS(screen, {
3350 			setExtendedFG(xw);
3351 		    });
3352 		    break;
3353 #if OPT_WIDE_ATTRS
3354 		case 23:	/* not italicized */
3355 		    ResetItalics(xw);
3356 		    if_OPT_ISO_COLORS(screen, {
3357 			setExtendedFG(xw);
3358 		    });
3359 		    break;
3360 #endif
3361 		case 24:
3362 		    UIntClr(xw->flags, UNDERLINE);
3363 #if OPT_WIDE_ATTRS
3364 		    UIntClr(xw->flags, ATR_DBL_UNDER);
3365 #endif
3366 		    if_OPT_ISO_COLORS(screen, {
3367 			setExtendedFG(xw);
3368 		    });
3369 		    break;
3370 		case 25:	/* reset 'blink' */
3371 		    UIntClr(xw->flags, BLINK);
3372 		    if_OPT_ISO_COLORS(screen, {
3373 			setExtendedFG(xw);
3374 		    });
3375 		    break;
3376 		case 27:
3377 		    UIntClr(xw->flags, INVERSE);
3378 		    if_OPT_ISO_COLORS(screen, {
3379 			setExtendedBG(xw);
3380 		    });
3381 		    break;
3382 		case 28:
3383 		    UIntClr(xw->flags, INVISIBLE);
3384 		    break;
3385 #if OPT_WIDE_ATTRS
3386 		case 29:	/* not crossed out */
3387 		    UIntClr(xw->flags, ATR_STRIKEOUT);
3388 		    break;
3389 #endif
3390 		case 30:
3391 		    /* FALLTHRU */
3392 		case 31:
3393 		    /* FALLTHRU */
3394 		case 32:
3395 		    /* FALLTHRU */
3396 		case 33:
3397 		    /* FALLTHRU */
3398 		case 34:
3399 		    /* FALLTHRU */
3400 		case 35:
3401 		    /* FALLTHRU */
3402 		case 36:
3403 		    /* FALLTHRU */
3404 		case 37:
3405 		    if_OPT_ISO_COLORS(screen, {
3406 			xw->sgr_foreground = (op - 30);
3407 			xw->sgr_38_xcolors = False;
3408 			clrDirectFG(xw->flags);
3409 			setExtendedFG(xw);
3410 		    });
3411 		    break;
3412 		case 38:
3413 		    /* This is more complicated than I'd like, but it should
3414 		     * properly eat all the parameters for unsupported modes.
3415 		     */
3416 		    if_OPT_ISO_COLORS(screen, {
3417 			Boolean extended;
3418 			if (parse_extended_colors(xw, &value, &item,
3419 						  &extended)) {
3420 			    xw->sgr_foreground = value;
3421 			    xw->sgr_38_xcolors = True;
3422 			    setDirectFG(xw->flags, extended);
3423 			    setExtendedFG(xw);
3424 			}
3425 		    });
3426 		    break;
3427 		case 39:
3428 		    if_OPT_ISO_COLORS(screen, {
3429 			reset_SGR_Foreground(xw);
3430 		    });
3431 		    break;
3432 		case 40:
3433 		    /* FALLTHRU */
3434 		case 41:
3435 		    /* FALLTHRU */
3436 		case 42:
3437 		    /* FALLTHRU */
3438 		case 43:
3439 		    /* FALLTHRU */
3440 		case 44:
3441 		    /* FALLTHRU */
3442 		case 45:
3443 		    /* FALLTHRU */
3444 		case 46:
3445 		    /* FALLTHRU */
3446 		case 47:
3447 		    if_OPT_ISO_COLORS(screen, {
3448 			xw->sgr_background = (op - 40);
3449 			clrDirectBG(xw->flags);
3450 			setExtendedBG(xw);
3451 		    });
3452 		    break;
3453 		case 48:
3454 		    if_OPT_ISO_COLORS(screen, {
3455 			Boolean extended;
3456 			if (parse_extended_colors(xw, &value, &item,
3457 						  &extended)) {
3458 			    xw->sgr_background = value;
3459 			    setDirectBG(xw->flags, extended);
3460 			    setExtendedBG(xw);
3461 			}
3462 		    });
3463 		    break;
3464 		case 49:
3465 		    if_OPT_ISO_COLORS(screen, {
3466 			reset_SGR_Background(xw);
3467 		    });
3468 		    break;
3469 		case 90:
3470 		    /* FALLTHRU */
3471 		case 91:
3472 		    /* FALLTHRU */
3473 		case 92:
3474 		    /* FALLTHRU */
3475 		case 93:
3476 		    /* FALLTHRU */
3477 		case 94:
3478 		    /* FALLTHRU */
3479 		case 95:
3480 		    /* FALLTHRU */
3481 		case 96:
3482 		    /* FALLTHRU */
3483 		case 97:
3484 		    if_OPT_AIX_COLORS(screen, {
3485 			xw->sgr_foreground = (op - 90 + 8);
3486 			clrDirectFG(xw->flags);
3487 			setExtendedFG(xw);
3488 		    });
3489 		    break;
3490 		case 100:
3491 #if !OPT_AIX_COLORS
3492 		    if_OPT_ISO_COLORS(screen, {
3493 			reset_SGR_Foreground(xw);
3494 			reset_SGR_Background(xw);
3495 		    });
3496 		    break;
3497 #endif
3498 		case 101:
3499 		    /* FALLTHRU */
3500 		case 102:
3501 		    /* FALLTHRU */
3502 		case 103:
3503 		    /* FALLTHRU */
3504 		case 104:
3505 		    /* FALLTHRU */
3506 		case 105:
3507 		    /* FALLTHRU */
3508 		case 106:
3509 		    /* FALLTHRU */
3510 		case 107:
3511 		    if_OPT_AIX_COLORS(screen, {
3512 			xw->sgr_background = (op - 100 + 8);
3513 			clrDirectBG(xw->flags);
3514 			setExtendedBG(xw);
3515 		    });
3516 		    break;
3517 		default:
3518 		    /* later: skip += NPARAM; */
3519 		    break;
3520 		}
3521 	    }
3522 	    ResetState(sp);
3523 	    break;
3524 
3525 	    /* DSR (except for the '?') is a superset of CPR */
3526 	case CASE_DSR:
3527 	    sp->private_function = True;
3528 
3529 	    /* FALLTHRU */
3530 	case CASE_CPR:
3531 	    TRACE(("CASE_DSR - device status report\n"));
3532 	    count = 0;
3533 	    init_reply(ANSI_CSI);
3534 	    reply.a_pintro = CharOf(sp->private_function ? '?' : 0);
3535 	    reply.a_inters = 0;
3536 	    reply.a_final = 'n';
3537 
3538 	    switch (GetParam(0)) {
3539 	    case 5:
3540 		TRACE(("...request operating status\n"));
3541 		/* operating status */
3542 		reply.a_param[count++] = 0;	/* (no malfunction ;-) */
3543 		break;
3544 	    case 6:
3545 		TRACE(("...request %s\n",
3546 		       (sp->private_function
3547 			? "DECXCPR"
3548 			: "CPR")));
3549 		/* CPR */
3550 		/* DECXCPR (with page=1) */
3551 		value = (screen->cur_row + 1);
3552 		if ((xw->flags & ORIGIN) != 0) {
3553 		    value -= screen->top_marg;
3554 		}
3555 		reply.a_param[count++] = (ParmType) value;
3556 
3557 		value = (screen->cur_col + 1);
3558 		if ((xw->flags & ORIGIN) != 0) {
3559 		    value -= screen->lft_marg;
3560 		}
3561 		reply.a_param[count++] = (ParmType) value;
3562 
3563 		if (sp->private_function
3564 		    && screen->vtXX_level >= 4) {	/* VT420 */
3565 		    reply.a_param[count++] = 1;
3566 		}
3567 		reply.a_final = 'R';
3568 		break;
3569 	    case 15:
3570 		TRACE(("...request printer status\n"));
3571 		if (sp->private_function
3572 		    && screen->vtXX_level >= 2) {	/* VT220 */
3573 		    reply.a_param[count++] = 13;	/* no printer detected */
3574 		}
3575 		break;
3576 	    case 25:
3577 		TRACE(("...request UDK status\n"));
3578 		if (sp->private_function
3579 		    && screen->vtXX_level >= 2) {	/* VT220 */
3580 		    reply.a_param[count++] = 20;	/* UDK always unlocked */
3581 		}
3582 		break;
3583 	    case 26:
3584 		TRACE(("...request keyboard status\n"));
3585 		if (sp->private_function
3586 		    && screen->vtXX_level >= 2) {	/* VT220 */
3587 		    reply.a_param[count++] = 27;
3588 		    reply.a_param[count++] = 1;		/* North American */
3589 		    if (screen->vtXX_level >= 3) {	/* VT320 */
3590 			reply.a_param[count++] = 0;	/* ready */
3591 		    }
3592 		    if (screen->vtXX_level >= 4) {	/* VT420 */
3593 			reply.a_param[count++] = 0;	/* LK201 */
3594 		    }
3595 		}
3596 		break;
3597 	    case 53:		/* according to existing xterm handling */
3598 		/* FALLTHRU */
3599 	    case 55:		/* according to the VT330/VT340 Text Programming Manual */
3600 		TRACE(("...request locator status\n"));
3601 		if (sp->private_function
3602 		    && screen->vtXX_level >= 3) {	/* VT330 */
3603 #if OPT_DEC_LOCATOR
3604 		    reply.a_param[count++] = 50;	/* locator ready */
3605 #else
3606 		    reply.a_param[count++] = 53;	/* no locator */
3607 #endif
3608 		}
3609 		break;
3610 	    case 56:
3611 		TRACE(("...request locator type\n"));
3612 		if (sp->private_function
3613 		    && screen->vtXX_level >= 3) {	/* VT330 */
3614 		    reply.a_param[count++] = 57;
3615 #if OPT_DEC_LOCATOR
3616 		    reply.a_param[count++] = 1;		/* mouse */
3617 #else
3618 		    reply.a_param[count++] = 0;		/* unknown */
3619 #endif
3620 		}
3621 		break;
3622 	    case 62:
3623 		TRACE(("...request DECMSR - macro space\n"));
3624 		if (sp->private_function
3625 		    && screen->vtXX_level >= 4) {	/* VT420 */
3626 		    reply.a_pintro = 0;
3627 		    reply.a_radix[count] = 16;	/* no data */
3628 		    reply.a_param[count++] = 0;		/* no space for macros */
3629 		    reply.a_inters = '*';
3630 		    reply.a_final = L_CURL;
3631 		}
3632 		break;
3633 	    case 63:
3634 		TRACE(("...request DECCKSR - memory checksum\n"));
3635 		/* DECCKSR - Memory checksum */
3636 		if (sp->private_function
3637 		    && screen->vtXX_level >= 4) {	/* VT420 */
3638 		    init_reply(ANSI_DCS);
3639 		    reply.a_param[count++] = (ParmType) GetParam(1);	/* PID */
3640 		    reply.a_delim = "!~";	/* delimiter */
3641 		    reply.a_radix[count] = 16;	/* use hex */
3642 		    reply.a_param[count++] = 0;		/* no data */
3643 		}
3644 		break;
3645 	    case 75:
3646 		TRACE(("...request data integrity\n"));
3647 		if (sp->private_function
3648 		    && screen->vtXX_level >= 4) {	/* VT420 */
3649 		    reply.a_param[count++] = 70;	/* no errors */
3650 		}
3651 		break;
3652 	    case 85:
3653 		TRACE(("...request multi-session configuration\n"));
3654 		if (sp->private_function
3655 		    && screen->vtXX_level >= 4) {	/* VT420 */
3656 		    reply.a_param[count++] = 83;	/* not configured */
3657 		}
3658 		break;
3659 	    default:
3660 		break;
3661 	    }
3662 
3663 	    if ((reply.a_nparam = (ParmType) count) != 0)
3664 		unparseseq(xw, &reply);
3665 
3666 	    ResetState(sp);
3667 	    sp->private_function = False;
3668 	    break;
3669 
3670 	case CASE_MC:
3671 	    TRACE(("CASE_MC - media control\n"));
3672 	    xtermMediaControl(xw, GetParam(0), False);
3673 	    ResetState(sp);
3674 	    break;
3675 
3676 	case CASE_DEC_MC:
3677 	    TRACE(("CASE_DEC_MC - DEC media control\n"));
3678 	    xtermMediaControl(xw, GetParam(0), True);
3679 	    ResetState(sp);
3680 	    break;
3681 
3682 	case CASE_HP_MEM_LOCK:
3683 	    /* FALLTHRU */
3684 	case CASE_HP_MEM_UNLOCK:
3685 	    TRACE(("%s\n", ((sp->parsestate[c] == CASE_HP_MEM_LOCK)
3686 			    ? "CASE_HP_MEM_LOCK"
3687 			    : "CASE_HP_MEM_UNLOCK")));
3688 	    if (screen->scroll_amt)
3689 		FlushScroll(xw);
3690 	    if (sp->parsestate[c] == CASE_HP_MEM_LOCK)
3691 		set_tb_margins(screen, screen->cur_row, screen->bot_marg);
3692 	    else
3693 		set_tb_margins(screen, 0, screen->bot_marg);
3694 	    ResetState(sp);
3695 	    break;
3696 
3697 	case CASE_DECSTBM:
3698 	    TRACE(("CASE_DECSTBM - set scrolling region\n"));
3699 	    {
3700 		int top;
3701 		int bot;
3702 		top = one_if_default(0);
3703 		if (nparam < 2 || (bot = GetParam(1)) == DEFAULT
3704 		    || bot > MaxRows(screen)
3705 		    || bot == 0)
3706 		    bot = MaxRows(screen);
3707 		if (bot > top) {
3708 		    if (screen->scroll_amt)
3709 			FlushScroll(xw);
3710 		    set_tb_margins(screen, top - 1, bot - 1);
3711 		    CursorSet(screen, 0, 0, xw->flags);
3712 		}
3713 		ResetState(sp);
3714 	    }
3715 	    break;
3716 
3717 	case CASE_DECREQTPARM:
3718 	    TRACE(("CASE_DECREQTPARM\n"));
3719 	    if (screen->terminal_id < 200) {	/* VT102 */
3720 		value = zero_if_default(0);
3721 		if (value == 0 || value == 1) {
3722 		    init_reply(ANSI_CSI);
3723 		    reply.a_pintro = 0;
3724 		    reply.a_nparam = 7;
3725 		    reply.a_param[0] = (ParmType) (value + 2);
3726 		    reply.a_param[1] = 1;	/* no parity */
3727 		    reply.a_param[2] = 1;	/* eight bits */
3728 		    reply.a_param[3] = 128;	/* transmit 38.4k baud */
3729 		    reply.a_param[4] = 128;	/* receive 38.4k baud */
3730 		    reply.a_param[5] = 1;	/* clock multiplier ? */
3731 		    reply.a_param[6] = 0;	/* STP flags ? */
3732 		    reply.a_inters = 0;
3733 		    reply.a_final = 'x';
3734 		    unparseseq(xw, &reply);
3735 		}
3736 	    }
3737 	    ResetState(sp);
3738 	    break;
3739 
3740 	case CASE_DECSET:
3741 	    /* DECSET */
3742 #if OPT_VT52_MODE
3743 	    if (screen->vtXX_level != 0)
3744 #endif
3745 		dpmodes(xw, bitset);
3746 	    ResetState(sp);
3747 #if OPT_TEK4014
3748 	    if (TEK4014_ACTIVE(xw)) {
3749 		TRACE(("Tek4014 is now active...\n"));
3750 		if (sp->check_recur)
3751 		    sp->check_recur--;
3752 		return False;
3753 	    }
3754 #endif
3755 	    break;
3756 
3757 	case CASE_DECRST:
3758 	    /* DECRST */
3759 	    dpmodes(xw, bitclr);
3760 	    init_groundtable(screen, sp);
3761 	    ResetState(sp);
3762 	    break;
3763 
3764 	case CASE_DECALN:
3765 	    TRACE(("CASE_DECALN - alignment test\n"));
3766 	    if (screen->cursor_state)
3767 		HideCursor(xw);
3768 	    /*
3769 	     * DEC STD 070 (see pages D-19 to D-20) does not mention left/right
3770 	     * margins.  The section is dated March 1985, not updated for the
3771 	     * VT420 (introduced in 1990).
3772 	     */
3773 	    UIntClr(xw->flags, ORIGIN);
3774 	    screen->do_wrap = False;
3775 	    resetRendition(xw);
3776 	    resetMargins(xw);
3777 	    xterm_ResetDouble(xw);
3778 	    CursorSet(screen, 0, 0, xw->flags);
3779 	    xtermParseRect(xw, 0, 0, &myRect);
3780 	    ScrnFillRectangle(xw, &myRect, 'E', 0, False);
3781 	    ResetState(sp);
3782 	    break;
3783 
3784 	case CASE_GSETS5:
3785 	    if (screen->vtXX_level >= 5) {
3786 		TRACE(("CASE_GSETS5(%d) = '%c'\n", sp->scstype, c));
3787 		xtermDecodeSCS(xw, sp->scstype, 5, 0, (int) c);
3788 	    }
3789 	    ResetState(sp);
3790 	    break;
3791 
3792 	case CASE_GSETS3:
3793 	    if (screen->vtXX_level >= 3) {
3794 		TRACE(("CASE_GSETS3(%d) = '%c'\n", sp->scstype, c));
3795 		xtermDecodeSCS(xw, sp->scstype, 3, 0, (int) c);
3796 	    }
3797 	    ResetState(sp);
3798 	    break;
3799 
3800 	case CASE_GSETS:
3801 	    if (strchr("012AB", (int) c) != 0) {
3802 		TRACE(("CASE_GSETS(%d) = '%c'\n", sp->scstype, c));
3803 		xtermDecodeSCS(xw, sp->scstype, 1, 0, (int) c);
3804 	    } else if (screen->vtXX_level >= 2) {
3805 		TRACE(("CASE_GSETS(%d) = '%c'\n", sp->scstype, c));
3806 		xtermDecodeSCS(xw, sp->scstype, 2, 0, (int) c);
3807 	    }
3808 	    ResetState(sp);
3809 	    break;
3810 
3811 	case CASE_ANSI_SC:
3812 	    if (IsLeftRightMode(xw)) {
3813 		int left;
3814 		int right;
3815 
3816 		TRACE(("CASE_DECSLRM - set left and right margin\n"));
3817 		left = one_if_default(0);
3818 		if (nparam < 2 || (right = GetParam(1)) == DEFAULT
3819 		    || right > MaxCols(screen)
3820 		    || right == 0)
3821 		    right = MaxCols(screen);
3822 		if (right > left) {
3823 		    set_lr_margins(screen, left - 1, right - 1);
3824 		    CursorSet(screen, 0, 0, xw->flags);
3825 		}
3826 	    } else {
3827 		TRACE(("CASE_ANSI_SC - save cursor\n"));
3828 		CursorSave(xw);
3829 	    }
3830 	    ResetState(sp);
3831 	    break;
3832 
3833 	case CASE_DECSC:
3834 	    TRACE(("CASE_DECSC - save cursor\n"));
3835 	    CursorSave(xw);
3836 	    ResetState(sp);
3837 	    break;
3838 
3839 	case CASE_ANSI_RC:
3840 	    /* FALLTHRU */
3841 	case CASE_DECRC:
3842 	    TRACE(("CASE_%sRC - restore cursor\n",
3843 		   (sp->nextstate == CASE_DECRC) ? "DEC" : "ANSI_"));
3844 	    CursorRestore(xw);
3845 	    if_OPT_ISO_COLORS(screen, {
3846 		setExtendedFG(xw);
3847 	    });
3848 	    ResetState(sp);
3849 	    break;
3850 
3851 	case CASE_DECKPAM:
3852 	    TRACE(("CASE_DECKPAM\n"));
3853 	    xw->keyboard.flags |= MODE_DECKPAM;
3854 	    update_appkeypad();
3855 	    ResetState(sp);
3856 	    break;
3857 
3858 	case CASE_DECKPNM:
3859 	    TRACE(("CASE_DECKPNM\n"));
3860 	    UIntClr(xw->keyboard.flags, MODE_DECKPAM);
3861 	    update_appkeypad();
3862 	    ResetState(sp);
3863 	    break;
3864 
3865 	case CASE_CSI_QUOTE_STATE:
3866 	    sp->parsestate = csi_quo_table;
3867 	    break;
3868 
3869 #if OPT_BLINK_CURS
3870 	case CASE_CSI_SPACE_STATE:
3871 	    sp->parsestate = csi_sp_table;
3872 	    break;
3873 
3874 	case CASE_DECSCUSR:
3875 	    TRACE(("CASE_DECSCUSR\n"));
3876 	    {
3877 		Boolean change = True;
3878 		int blinks = screen->cursor_blink_esc;
3879 
3880 		HideCursor(xw);
3881 
3882 		switch (GetParam(0)) {
3883 		case DEFAULT:
3884 		    /* FALLTHRU */
3885 		case DEFAULT_STYLE:
3886 		    /* FALLTHRU */
3887 		case BLINK_BLOCK:
3888 		    blinks = True;
3889 		    screen->cursor_shape = CURSOR_BLOCK;
3890 		    break;
3891 		case STEADY_BLOCK:
3892 		    blinks = False;
3893 		    screen->cursor_shape = CURSOR_BLOCK;
3894 		    break;
3895 		case BLINK_UNDERLINE:
3896 		    blinks = True;
3897 		    screen->cursor_shape = CURSOR_UNDERLINE;
3898 		    break;
3899 		case STEADY_UNDERLINE:
3900 		    blinks = False;
3901 		    screen->cursor_shape = CURSOR_UNDERLINE;
3902 		    break;
3903 		case BLINK_BAR:
3904 		    blinks = True;
3905 		    screen->cursor_shape = CURSOR_BAR;
3906 		    break;
3907 		case STEADY_BAR:
3908 		    blinks = False;
3909 		    screen->cursor_shape = CURSOR_BAR;
3910 		    break;
3911 		default:
3912 		    change = False;
3913 		    break;
3914 		}
3915 		TRACE(("cursor_shape:%d blinks:%s\n",
3916 		       screen->cursor_shape, BtoS(blinks)));
3917 		if (change) {
3918 		    xtermSetCursorBox(screen);
3919 		    if (SettableCursorBlink(screen)) {
3920 			screen->cursor_blink_esc = blinks;
3921 			UpdateCursorBlink(xw);
3922 		    }
3923 		}
3924 	    }
3925 	    ResetState(sp);
3926 	    break;
3927 #endif
3928 
3929 #if OPT_SCROLL_LOCK
3930 	case CASE_DECLL:
3931 	    TRACE(("CASE_DECLL\n"));
3932 	    if (nparam > 0) {
3933 		for (count = 0; count < nparam; ++count) {
3934 		    int op = zero_if_default(count);
3935 		    switch (op) {
3936 		    case 0:
3937 		    case DEFAULT:
3938 			xtermClearLEDs(screen);
3939 			break;
3940 		    case 1:
3941 			/* FALLTHRU */
3942 		    case 2:
3943 			/* FALLTHRU */
3944 		    case 3:
3945 			xtermShowLED(screen,
3946 				     (Cardinal) op,
3947 				     True);
3948 			break;
3949 		    case 21:
3950 			/* FALLTHRU */
3951 		    case 22:
3952 			/* FALLTHRU */
3953 		    case 23:
3954 			xtermShowLED(screen,
3955 				     (Cardinal) (op - 20),
3956 				     True);
3957 			break;
3958 		    }
3959 		}
3960 	    } else {
3961 		xtermClearLEDs(screen);
3962 	    }
3963 	    ResetState(sp);
3964 	    break;
3965 #endif
3966 
3967 #if OPT_VT52_MODE
3968 	case CASE_VT52_FINISH:
3969 	    TRACE(("CASE_VT52_FINISH terminal_id %d, vtXX_level %d\n",
3970 		   screen->terminal_id,
3971 		   screen->vtXX_level));
3972 	    if (screen->terminal_id >= 100
3973 		&& screen->vtXX_level == 0) {
3974 		sp->groundtable =
3975 		    sp->parsestate = ansi_table;
3976 		/*
3977 		 * On restore, the terminal does not recognize DECRQSS for
3978 		 * DECSCL (per vttest).
3979 		 */
3980 		screen->vtXX_level = 1;
3981 		xw->flags = screen->vt52_save_flags;
3982 		screen->curgl = screen->vt52_save_curgl;
3983 		screen->curgr = screen->vt52_save_curgr;
3984 		screen->curss = screen->vt52_save_curss;
3985 		restoreCharsets(screen, screen->vt52_save_gsets);
3986 		update_vt52_vt100_settings();
3987 	    }
3988 	    break;
3989 #endif
3990 
3991 	case CASE_ANSI_LEVEL_1:
3992 	    TRACE(("CASE_ANSI_LEVEL_1\n"));
3993 	    set_ansi_conformance(screen, 1);
3994 	    ResetState(sp);
3995 	    break;
3996 
3997 	case CASE_ANSI_LEVEL_2:
3998 	    TRACE(("CASE_ANSI_LEVEL_2\n"));
3999 	    set_ansi_conformance(screen, 2);
4000 	    ResetState(sp);
4001 	    break;
4002 
4003 	case CASE_ANSI_LEVEL_3:
4004 	    TRACE(("CASE_ANSI_LEVEL_3\n"));
4005 	    set_ansi_conformance(screen, 3);
4006 	    ResetState(sp);
4007 	    break;
4008 
4009 	case CASE_DECSCL:
4010 	    TRACE(("CASE_DECSCL(%d,%d)\n", GetParam(0), GetParam(1)));
4011 	    /*
4012 	     * This changes the emulation level, and is not recognized by
4013 	     * VT100s.  However, a VT220 or above can be set to conformance
4014 	     * level 1 to act like a VT100.
4015 	     */
4016 	    if (screen->terminal_id >= 200) {
4017 		/*
4018 		 * Disallow unrecognized parameters, as well as attempts to set
4019 		 * the operating level higher than the given terminal-id.
4020 		 */
4021 		if (GetParam(0) >= 61
4022 		    && GetParam(0) <= 60 + (screen->terminal_id / 100)) {
4023 		    int new_vtXX_level = GetParam(0) - 60;
4024 		    int case_value = zero_if_default(1);
4025 		    /*
4026 		     * Note:
4027 		     *
4028 		     * The VT300, VT420, VT520 manuals claim that DECSCL does a
4029 		     * hard reset (RIS).
4030 		     *
4031 		     * Both the VT220 manual and DEC STD 070 (which documents
4032 		     * levels 1-4 in detail) state that it is a soft reset.
4033 		     *
4034 		     * Perhaps both sets of manuals are right (unlikely).
4035 		     * Kermit says it's soft.
4036 		     */
4037 		    ReallyReset(xw, False, False);
4038 		    init_parser(xw, sp);
4039 		    screen->vtXX_level = new_vtXX_level;
4040 		    if (new_vtXX_level > 1) {
4041 			switch (case_value) {
4042 			case 1:
4043 			    show_8bit_control(False);
4044 			    break;
4045 			case 0:
4046 			case 2:
4047 			    show_8bit_control(True);
4048 			    break;
4049 			}
4050 		    }
4051 		}
4052 	    }
4053 	    ResetState(sp);
4054 	    break;
4055 
4056 	case CASE_DECSCA:
4057 	    TRACE(("CASE_DECSCA\n"));
4058 	    screen->protected_mode = DEC_PROTECT;
4059 	    if (GetParam(0) <= 0 || GetParam(0) == 2) {
4060 		UIntClr(xw->flags, PROTECTED);
4061 		TRACE(("...clear PROTECTED\n"));
4062 	    } else if (GetParam(0) == 1) {
4063 		xw->flags |= PROTECTED;
4064 		TRACE(("...set PROTECTED\n"));
4065 	    }
4066 	    ResetState(sp);
4067 	    break;
4068 
4069 	case CASE_DECSED:
4070 	    TRACE(("CASE_DECSED\n"));
4071 	    do_erase_display(xw, zero_if_default(0), DEC_PROTECT);
4072 	    ResetState(sp);
4073 	    break;
4074 
4075 	case CASE_DECSEL:
4076 	    TRACE(("CASE_DECSEL\n"));
4077 	    do_erase_line(xw, zero_if_default(0), DEC_PROTECT);
4078 	    ResetState(sp);
4079 	    break;
4080 
4081 	case CASE_GRAPHICS_ATTRIBUTES:
4082 #if OPT_GRAPHICS
4083 	    TRACE(("CASE_GRAPHICS_ATTRIBUTES\n"));
4084 	    {
4085 		/* request: item, action, value */
4086 		/* reply: item, status, value */
4087 		if (nparam != 3) {
4088 		    TRACE(("DATA_ERROR: malformed CASE_GRAPHICS_ATTRIBUTES request with %d parameters\n", nparam));
4089 		} else {
4090 		    int status = 3;	/* assume failure */
4091 		    int result = 0;
4092 		    int result2 = 0;
4093 
4094 		    TRACE(("CASE_GRAPHICS_ATTRIBUTES request: %d, %d, %d\n",
4095 			   GetParam(0), GetParam(1), GetParam(2)));
4096 		    switch (GetParam(0)) {
4097 		    case 1:	/* color register count */
4098 			switch (GetParam(1)) {
4099 			case 1:	/* read */
4100 			    status = 0;		/* success */
4101 			    result = (int) get_color_register_count(screen);
4102 			    break;
4103 			case 2:	/* reset */
4104 			    screen->numcolorregisters = 0;
4105 			    status = 0;		/* success */
4106 			    result = (int) get_color_register_count(screen);
4107 			    break;
4108 			case 3:	/* set */
4109 			    if (GetParam(2) > 1 &&
4110 				(unsigned) GetParam(2) <= MAX_COLOR_REGISTERS) {
4111 				screen->numcolorregisters = GetParam(2);
4112 				status = 0;	/* success */
4113 				result = (int) get_color_register_count(screen);
4114 			    }
4115 			    break;
4116 			case 4:	/* read maximum */
4117 			    status = 0;		/* success */
4118 			    result = MAX_COLOR_REGISTERS;
4119 			    break;
4120 			default:
4121 			    TRACE(("DATA_ERROR: CASE_GRAPHICS_ATTRIBUTES color register count request with unknown action parameter: %d\n",
4122 				   GetParam(1)));
4123 			    status = 2;		/* error in Pa */
4124 			    break;
4125 			}
4126 			if (status == 0 && !(optSixelGraphics(screen)
4127 					     || optRegisGraphics(screen)))
4128 			    status = 3;
4129 			break;
4130 # if OPT_SIXEL_GRAPHICS
4131 		    case 2:	/* graphics geometry */
4132 			switch (GetParam(1)) {
4133 			case 1:	/* read */
4134 			    TRACE(("Get sixel graphics geometry\n"));
4135 			    status = 0;		/* success */
4136 			    result = Min(Width(screen), (int) screen->graphics_max_wide);
4137 			    result2 = Min(Height(screen), (int) screen->graphics_max_high);
4138 			    break;
4139 			case 2:	/* reset */
4140 			    /* FALLTHRU */
4141 			case 3:	/* set */
4142 			    break;
4143 			case 4:	/* read maximum */
4144 			    status = 0;		/* success */
4145 			    result = screen->graphics_max_wide;
4146 			    result2 = screen->graphics_max_high;
4147 			    break;
4148 			default:
4149 			    TRACE(("DATA_ERROR: CASE_GRAPHICS_ATTRIBUTES graphics geometry request with unknown action parameter: %d\n",
4150 				   GetParam(1)));
4151 			    status = 2;		/* error in Pa */
4152 			    break;
4153 			}
4154 			if (status == 0 && !optSixelGraphics(screen))
4155 			    status = 3;
4156 			break;
4157 #endif
4158 # if OPT_REGIS_GRAPHICS
4159 		    case 3:	/* ReGIS geometry */
4160 			switch (GetParam(1)) {
4161 			case 1:	/* read */
4162 			    status = 0;		/* success */
4163 			    result = screen->graphics_regis_def_wide;
4164 			    result2 = screen->graphics_regis_def_high;
4165 			    break;
4166 			case 2:	/* reset */
4167 			    /* FALLTHRU */
4168 			case 3:	/* set */
4169 			    /* FALLTHRU */
4170 			case 4:	/* read maximum */
4171 			    /* not implemented */
4172 			    break;
4173 			default:
4174 			    TRACE(("DATA_ERROR: CASE_GRAPHICS_ATTRIBUTES ReGIS geometry request with unknown action parameter: %d\n",
4175 				   GetParam(1)));
4176 			    status = 2;		/* error in Pa */
4177 			    break;
4178 			}
4179 			if (status == 0 && !optRegisGraphics(screen))
4180 			    status = 3;
4181 			break;
4182 #endif
4183 		    default:
4184 			TRACE(("DATA_ERROR: CASE_GRAPHICS_ATTRIBUTES request with unknown item parameter: %d\n",
4185 			       GetParam(0)));
4186 			status = 1;
4187 			break;
4188 		    }
4189 
4190 		    init_reply(ANSI_CSI);
4191 		    reply.a_pintro = '?';
4192 		    count = 0;
4193 		    reply.a_param[count++] = (ParmType) GetParam(0);
4194 		    reply.a_param[count++] = (ParmType) status;
4195 		    if (status == 0) {
4196 			reply.a_param[count++] = (ParmType) result;
4197 			if (GetParam(0) >= 2)
4198 			    reply.a_param[count++] = (ParmType) result2;
4199 		    }
4200 		    reply.a_nparam = (ParmType) count;
4201 		    reply.a_inters = 0;
4202 		    reply.a_final = 'S';
4203 		    unparseseq(xw, &reply);
4204 		}
4205 	    }
4206 #endif
4207 	    ResetState(sp);
4208 	    break;
4209 
4210 	case CASE_ST:
4211 	    TRACE(("CASE_ST: End of String (%lu bytes) (mode=%d)\n",
4212 		   (unsigned long) sp->string_used,
4213 		   sp->string_mode));
4214 	    ResetState(sp);
4215 	    if (!sp->string_used)
4216 		break;
4217 	    sp->string_area[--(sp->string_used)] = '\0';
4218 	    if (sp->check_recur <= 1)
4219 		switch (sp->string_mode) {
4220 		case ANSI_APC:
4221 		    /* ignored */
4222 		    break;
4223 		case ANSI_DCS:
4224 		    do_dcs(xw, sp->string_area, sp->string_used);
4225 		    break;
4226 		case ANSI_OSC:
4227 		    do_osc(xw, sp->string_area, sp->string_used, ANSI_ST);
4228 		    break;
4229 		case ANSI_PM:
4230 		    /* ignored */
4231 		    break;
4232 		case ANSI_SOS:
4233 		    /* ignored */
4234 		    break;
4235 		default:
4236 		    TRACE(("unknown mode\n"));
4237 		    break;
4238 		}
4239 	    break;
4240 
4241 	case CASE_SOS:
4242 	    TRACE(("CASE_SOS: Start of String\n"));
4243 	    if (ParseSOS(screen)) {
4244 		sp->string_mode = ANSI_SOS;
4245 		sp->parsestate = sos_table;
4246 	    } else {
4247 		illegal_parse(xw, c, sp);
4248 	    }
4249 	    break;
4250 
4251 	case CASE_PM:
4252 	    TRACE(("CASE_PM: Privacy Message\n"));
4253 	    if (ParseSOS(screen)) {
4254 		sp->string_mode = ANSI_PM;
4255 		sp->parsestate = sos_table;
4256 	    } else {
4257 		illegal_parse(xw, c, sp);
4258 	    }
4259 	    break;
4260 
4261 	case CASE_DCS:
4262 	    TRACE(("CASE_DCS: Device Control String\n"));
4263 	    sp->string_mode = ANSI_DCS;
4264 	    sp->parsestate = sos_table;
4265 	    break;
4266 
4267 	case CASE_APC:
4268 	    TRACE(("CASE_APC: Application Program Command\n"));
4269 	    if (ParseSOS(screen)) {
4270 		sp->string_mode = ANSI_APC;
4271 		sp->parsestate = sos_table;
4272 	    } else {
4273 		illegal_parse(xw, c, sp);
4274 	    }
4275 	    break;
4276 
4277 	case CASE_SPA:
4278 	    TRACE(("CASE_SPA - start protected area\n"));
4279 	    screen->protected_mode = ISO_PROTECT;
4280 	    xw->flags |= PROTECTED;
4281 	    ResetState(sp);
4282 	    break;
4283 
4284 	case CASE_EPA:
4285 	    TRACE(("CASE_EPA - end protected area\n"));
4286 	    UIntClr(xw->flags, PROTECTED);
4287 	    ResetState(sp);
4288 	    break;
4289 
4290 	case CASE_SU:
4291 	    TRACE(("CASE_SU - scroll up\n"));
4292 	    xtermScroll(xw, one_if_default(0));
4293 	    ResetState(sp);
4294 	    break;
4295 
4296 	case CASE_SL:		/* ISO 6429, non-DEC */
4297 	    TRACE(("CASE_SL - scroll left\n"));
4298 	    xtermScrollLR(xw, one_if_default(0), True);
4299 	    ResetState(sp);
4300 	    break;
4301 
4302 	case CASE_SR:		/* ISO 6429, non-DEC */
4303 	    TRACE(("CASE_SR - scroll right\n"));
4304 	    xtermScrollLR(xw, one_if_default(0), False);
4305 	    ResetState(sp);
4306 	    break;
4307 
4308 	case CASE_DECDC:
4309 	    TRACE(("CASE_DC - delete column\n"));
4310 	    if (screen->vtXX_level >= 4) {
4311 		xtermColScroll(xw, one_if_default(0), True, screen->cur_col);
4312 	    }
4313 	    ResetState(sp);
4314 	    break;
4315 
4316 	case CASE_DECIC:
4317 	    TRACE(("CASE_IC - insert column\n"));
4318 	    if (screen->vtXX_level >= 4) {
4319 		xtermColScroll(xw, one_if_default(0), False, screen->cur_col);
4320 	    }
4321 	    ResetState(sp);
4322 	    break;
4323 
4324 	case CASE_DECBI:
4325 	    TRACE(("CASE_BI - back index\n"));
4326 	    if (screen->vtXX_level >= 4) {
4327 		xtermColIndex(xw, True);
4328 	    }
4329 	    ResetState(sp);
4330 	    break;
4331 
4332 	case CASE_DECFI:
4333 	    TRACE(("CASE_FI - forward index\n"));
4334 	    if (screen->vtXX_level >= 4) {
4335 		xtermColIndex(xw, False);
4336 	    }
4337 	    ResetState(sp);
4338 	    break;
4339 
4340 	case CASE_IND:
4341 	    TRACE(("CASE_IND - index\n"));
4342 	    xtermIndex(xw, 1);
4343 	    do_xevents(xw);
4344 	    ResetState(sp);
4345 	    break;
4346 
4347 	case CASE_CPL:
4348 	    TRACE(("CASE_CPL - cursor prev line\n"));
4349 	    CursorPrevLine(xw, one_if_default(0));
4350 	    ResetState(sp);
4351 	    break;
4352 
4353 	case CASE_CNL:
4354 	    TRACE(("CASE_CNL - cursor next line\n"));
4355 	    CursorNextLine(xw, one_if_default(0));
4356 	    ResetState(sp);
4357 	    break;
4358 
4359 	case CASE_NEL:
4360 	    TRACE(("CASE_NEL\n"));
4361 	    xtermIndex(xw, 1);
4362 	    CarriageReturn(xw);
4363 	    ResetState(sp);
4364 	    break;
4365 
4366 	case CASE_HTS:
4367 	    TRACE(("CASE_HTS - horizontal tab set\n"));
4368 	    TabSet(xw->tabs, screen->cur_col);
4369 	    ResetState(sp);
4370 	    break;
4371 
4372 	case CASE_REPORT_VERSION:
4373 	    TRACE(("CASE_REPORT_VERSION - report terminal version\n"));
4374 	    if (GetParam(0) <= 0) {
4375 		unparseputc1(xw, ANSI_DCS);
4376 		unparseputc(xw, '>');
4377 		unparseputc(xw, '|');
4378 		unparseputs(xw, xtermVersion());
4379 		unparseputc1(xw, ANSI_ST);
4380 		unparse_end(xw);
4381 	    }
4382 	    ResetState(sp);
4383 	    break;
4384 
4385 	case CASE_RI:
4386 	    TRACE(("CASE_RI - reverse index\n"));
4387 	    RevIndex(xw, 1);
4388 	    ResetState(sp);
4389 	    break;
4390 
4391 	case CASE_SS2:
4392 	    TRACE(("CASE_SS2\n"));
4393 	    screen->curss = 2;
4394 	    ResetState(sp);
4395 	    break;
4396 
4397 	case CASE_SS3:
4398 	    TRACE(("CASE_SS3\n"));
4399 	    screen->curss = 3;
4400 	    ResetState(sp);
4401 	    break;
4402 
4403 	case CASE_CSI_STATE:
4404 	    /* enter csi state */
4405 	    InitParams();
4406 	    SetParam(nparam++, DEFAULT);
4407 	    sp->parsestate = csi_table;
4408 	    break;
4409 
4410 	case CASE_ESC_SP_STATE:
4411 	    /* esc space */
4412 	    sp->parsestate = esc_sp_table;
4413 	    break;
4414 
4415 	case CASE_CSI_EX_STATE:
4416 	    /* csi exclamation */
4417 	    sp->parsestate = csi_ex_table;
4418 	    break;
4419 
4420 	case CASE_CSI_TICK_STATE:
4421 	    /* csi tick (') */
4422 	    sp->parsestate = csi_tick_table;
4423 	    break;
4424 
4425 #if OPT_DEC_LOCATOR
4426 	case CASE_DECEFR:
4427 	    TRACE(("CASE_DECEFR - Enable Filter Rectangle\n"));
4428 	    if (okSendMousePos(xw) == DEC_LOCATOR) {
4429 		MotionOff(screen, xw);
4430 		if ((screen->loc_filter_top = GetParam(0)) < 1)
4431 		    screen->loc_filter_top = LOC_FILTER_POS;
4432 		if (nparam < 2
4433 		    || (screen->loc_filter_left = GetParam(1)) < 1)
4434 		    screen->loc_filter_left = LOC_FILTER_POS;
4435 		if (nparam < 3
4436 		    || (screen->loc_filter_bottom = GetParam(2)) < 1)
4437 		    screen->loc_filter_bottom = LOC_FILTER_POS;
4438 		if (nparam < 4
4439 		    || (screen->loc_filter_right = GetParam(3)) < 1)
4440 		    screen->loc_filter_right = LOC_FILTER_POS;
4441 		InitLocatorFilter(xw);
4442 	    }
4443 	    ResetState(sp);
4444 	    break;
4445 
4446 	case CASE_DECELR:
4447 	    MotionOff(screen, xw);
4448 	    if (GetParam(0) <= 0 || GetParam(0) > 2) {
4449 		screen->send_mouse_pos = MOUSE_OFF;
4450 		TRACE(("DECELR - Disable Locator Reports\n"));
4451 	    } else {
4452 		TRACE(("DECELR - Enable Locator Reports\n"));
4453 		screen->send_mouse_pos = DEC_LOCATOR;
4454 		xtermShowPointer(xw, True);
4455 		if (GetParam(0) == 2) {
4456 		    screen->locator_reset = True;
4457 		} else {
4458 		    screen->locator_reset = False;
4459 		}
4460 		if (nparam < 2 || GetParam(1) != 1) {
4461 		    screen->locator_pixels = False;
4462 		} else {
4463 		    screen->locator_pixels = True;
4464 		}
4465 		screen->loc_filter = False;
4466 	    }
4467 	    ResetState(sp);
4468 	    break;
4469 
4470 	case CASE_DECSLE:
4471 	    TRACE(("DECSLE - Select Locator Events\n"));
4472 	    for (count = 0; count < nparam; ++count) {
4473 		switch (zero_if_default(count)) {
4474 		case 0:
4475 		    MotionOff(screen, xw);
4476 		    screen->loc_filter = False;
4477 		    screen->locator_events = 0;
4478 		    break;
4479 		case 1:
4480 		    screen->locator_events |= LOC_BTNS_DN;
4481 		    break;
4482 		case 2:
4483 		    UIntClr(screen->locator_events, LOC_BTNS_DN);
4484 		    break;
4485 		case 3:
4486 		    screen->locator_events |= LOC_BTNS_UP;
4487 		    break;
4488 		case 4:
4489 		    UIntClr(screen->locator_events, LOC_BTNS_UP);
4490 		    break;
4491 		}
4492 	    }
4493 	    ResetState(sp);
4494 	    break;
4495 
4496 	case CASE_DECRQLP:
4497 	    TRACE(("DECRQLP - Request Locator Position\n"));
4498 	    if (GetParam(0) < 2) {
4499 		/* Issue DECLRP Locator Position Report */
4500 		GetLocatorPosition(xw);
4501 	    }
4502 	    ResetState(sp);
4503 	    break;
4504 #endif /* OPT_DEC_LOCATOR */
4505 
4506 #if OPT_DEC_RECTOPS
4507 	case CASE_CSI_DOLLAR_STATE:
4508 	    TRACE(("CASE_CSI_DOLLAR_STATE\n"));
4509 	    /* csi dollar ($) */
4510 	    if (screen->vtXX_level >= 3)
4511 		sp->parsestate = csi_dollar_table;
4512 	    else
4513 		sp->parsestate = eigtable;
4514 	    break;
4515 
4516 	case CASE_CSI_STAR_STATE:
4517 	    TRACE(("CASE_CSI_STAR_STATE\n"));
4518 	    /* csi star (*) */
4519 	    if (screen->vtXX_level >= 4)
4520 		sp->parsestate = csi_star_table;
4521 	    else
4522 		sp->parsestate = eigtable;
4523 	    break;
4524 
4525 	case CASE_DECRQCRA:
4526 	    if (screen->vtXX_level >= 4 && AllowWindowOps(xw, ewGetChecksum)) {
4527 		int checksum;
4528 		int pid;
4529 
4530 		TRACE(("CASE_DECRQCRA - Request checksum of rectangular area\n"));
4531 		xtermCheckRect(xw, ParamPair(0), &checksum);
4532 		init_reply(ANSI_DCS);
4533 		count = 0;
4534 		checksum &= 0xffff;
4535 		pid = GetParam(0);
4536 		reply.a_param[count++] = (ParmType) pid;
4537 		reply.a_delim = "!~";	/* delimiter */
4538 		reply.a_radix[count] = 16;
4539 		reply.a_param[count++] = (ParmType) checksum;
4540 		reply.a_nparam = (ParmType) count;
4541 		TRACE(("...checksum(%d) = %04X\n", pid, checksum));
4542 		unparseseq(xw, &reply);
4543 	    }
4544 	    ResetState(sp);
4545 	    break;
4546 
4547 	case CASE_DECCRA:
4548 	    if (screen->vtXX_level >= 4) {
4549 		TRACE(("CASE_DECCRA - Copy rectangular area\n"));
4550 		xtermParseRect(xw, ParamPair(0), &myRect);
4551 		ScrnCopyRectangle(xw, &myRect, ParamPair(5));
4552 	    }
4553 	    ResetState(sp);
4554 	    break;
4555 
4556 	case CASE_DECERA:
4557 	    if (screen->vtXX_level >= 4) {
4558 		TRACE(("CASE_DECERA - Erase rectangular area\n"));
4559 		xtermParseRect(xw, ParamPair(0), &myRect);
4560 		ScrnFillRectangle(xw, &myRect, ' ', xw->flags, True);
4561 	    }
4562 	    ResetState(sp);
4563 	    break;
4564 
4565 	case CASE_DECFRA:
4566 	    if (screen->vtXX_level >= 4) {
4567 		value = zero_if_default(0);
4568 
4569 		TRACE(("CASE_DECFRA - Fill rectangular area\n"));
4570 		if (nparam > 0 && CharWidth(screen, value) > 0) {
4571 		    xtermParseRect(xw, ParamPair(1), &myRect);
4572 		    ScrnFillRectangle(xw, &myRect, value, xw->flags, True);
4573 		}
4574 	    }
4575 	    ResetState(sp);
4576 	    break;
4577 
4578 	case CASE_DECSERA:
4579 	    if (screen->vtXX_level >= 4) {
4580 		TRACE(("CASE_DECSERA - Selective erase rectangular area\n"));
4581 		xtermParseRect(xw, ParamPair(0), &myRect);
4582 		ScrnWipeRectangle(xw, &myRect);
4583 	    }
4584 	    ResetState(sp);
4585 	    break;
4586 
4587 	case CASE_DECSACE:
4588 	    TRACE(("CASE_DECSACE - Select attribute change extent\n"));
4589 	    screen->cur_decsace = zero_if_default(0);
4590 	    ResetState(sp);
4591 	    break;
4592 
4593 	case CASE_DECCARA:
4594 	    if (screen->vtXX_level >= 4) {
4595 		TRACE(("CASE_DECCARA - Change attributes in rectangular area\n"));
4596 		xtermParseRect(xw, ParamPair(0), &myRect);
4597 		ScrnMarkRectangle(xw, &myRect, False, ParamPair(4));
4598 	    }
4599 	    ResetState(sp);
4600 	    break;
4601 
4602 	case CASE_DECRARA:
4603 	    if (screen->vtXX_level >= 4) {
4604 		TRACE(("CASE_DECRARA - Reverse attributes in rectangular area\n"));
4605 		xtermParseRect(xw, ParamPair(0), &myRect);
4606 		ScrnMarkRectangle(xw, &myRect, True, ParamPair(4));
4607 	    }
4608 	    ResetState(sp);
4609 	    break;
4610 
4611 	case CASE_DECSCPP:
4612 	    if (screen->vtXX_level >= 3) {
4613 		TRACE(("CASE_DECSCPP\n"));
4614 		/* default and 0 are "80", with "132" as the other legal choice */
4615 		switch (zero_if_default(0)) {
4616 		case 0:
4617 		case 80:
4618 		    value = 80;
4619 		    break;
4620 		case 132:
4621 		    value = 132;
4622 		    break;
4623 		default:
4624 		    value = -1;
4625 		    break;
4626 		}
4627 		if (value > 0) {
4628 		    if (screen->cur_col + 1 > value)
4629 			CursorSet(screen, screen->cur_row, value - 1, xw->flags);
4630 		    UIntClr(xw->flags, IN132COLUMNS);
4631 		    if (value == 132)
4632 			UIntSet(xw->flags, IN132COLUMNS);
4633 		    RequestResize(xw, -1, value, True);
4634 		}
4635 	    }
4636 	    ResetState(sp);
4637 	    break;
4638 
4639 	case CASE_DECSNLS:
4640 	    if (screen->vtXX_level >= 4 && AllowWindowOps(xw, ewSetWinLines)) {
4641 		TRACE(("CASE_DECSNLS\n"));
4642 		value = zero_if_default(0);
4643 		if (value >= 1 && value <= 255) {
4644 		    RequestResize(xw, value, -1, True);
4645 		}
4646 	    }
4647 	    ResetState(sp);
4648 	    break;
4649 
4650 	case CASE_DECRQPSR:
4651 #define reply_char(n,c) do { reply.a_radix[(n)] = 1; reply.a_param[(n)++] = (ParmType)(c); } while (0)
4652 #define reply_bit(n,c) ((n) ? (c) : 0)
4653 	    if (screen->vtXX_level >= 3) {
4654 		TRACE(("CASE_DECRQPSR\n"));
4655 		switch (GetParam(0)) {
4656 		case 1:
4657 		    TRACE(("...DECCIR\n"));
4658 		    init_reply(ANSI_DCS);
4659 		    count = 0;
4660 		    reply_char(count, '1');
4661 		    reply_char(count, '$');
4662 		    reply_char(count, 'u');
4663 		    reply.a_param[count++] = (ParmType) (screen->cur_row + 1);
4664 		    reply.a_param[count++] = (ParmType) (screen->cur_col + 1);
4665 		    reply.a_param[count++] = (ParmType) thispage;
4666 		    reply_char(count, ';');
4667 		    reply_char(count, (0x40
4668 				       | reply_bit(xw->flags & INVERSE, 8)
4669 				       | reply_bit(xw->flags & BLINK, 4)
4670 				       | reply_bit(xw->flags & UNDERLINE, 2)
4671 				       | reply_bit(xw->flags & BOLD, 1)
4672 			       ));
4673 		    reply_char(count, ';');
4674 		    reply_char(count, 0x40 |
4675 			       reply_bit(screen->protected_mode &
4676 					 DEC_PROTECT, 1)
4677 			);
4678 		    reply_char(count, ';');
4679 		    reply_char(count, (0x40
4680 				       | reply_bit(screen->do_wrap, 8)
4681 				       | reply_bit((screen->curss == 3), 4)
4682 				       | reply_bit((screen->curss == 2), 2)
4683 				       | reply_bit(xw->flags & ORIGIN, 1)
4684 			       ));
4685 		    reply_char(count, ';');
4686 		    reply.a_param[count++] = screen->curgl;
4687 		    reply.a_param[count++] = screen->curgr;
4688 		    reply_char(count, ';');
4689 		    reply_char(count, 0x4f);	/* assert all 96's */
4690 		    reply_char(count, ';');
4691 		    for (item = 0; item < NUM_GSETS; ++item) {
4692 			char *temp = encode_scs(screen->gsets[item]);
4693 			while (*temp != '\0') {
4694 			    reply_char(count, *temp++);
4695 			}
4696 		    }
4697 		    reply.a_nparam = (ParmType) count;
4698 		    unparseseq(xw, &reply);
4699 		    break;
4700 		case 2:
4701 		    TRACE(("...DECTABSR\n"));
4702 		    init_reply(ANSI_DCS);
4703 		    reply.a_delim = "/";
4704 		    count = 0;
4705 		    reply_char(count, '2');
4706 		    reply_char(count, '$');
4707 		    reply_char(count, 'u');
4708 		    for (item = 0; item < MAX_TABS; ++item) {
4709 			if (count + 1 >= NPARAM)
4710 			    break;
4711 			if (TabIsSet(xw->tabs, item)) {
4712 			    reply.a_param[count++] = (ParmType) (item + 1);
4713 			}
4714 			if (item > screen->max_col)
4715 			    break;
4716 		    }
4717 		    reply.a_nparam = (ParmType) count;
4718 		    unparseseq(xw, &reply);
4719 		    break;
4720 		}
4721 	    }
4722 	    ResetState(sp);
4723 	    break;
4724 
4725 	case CASE_RQM:
4726 	    TRACE(("CASE_RQM\n"));
4727 	    do_ansi_rqm(xw, ParamPair(0));
4728 	    ResetState(sp);
4729 	    break;
4730 
4731 	case CASE_DECRQM:
4732 	    TRACE(("CASE_DECRQM\n"));
4733 	    do_dec_rqm(xw, ParamPair(0));
4734 	    ResetState(sp);
4735 	    break;
4736 
4737 	case CASE_CSI_DEC_DOLLAR_STATE:
4738 	    TRACE(("CASE_CSI_DEC_DOLLAR_STATE\n"));
4739 	    /* csi ? dollar ($) */
4740 	    sp->parsestate = csi_dec_dollar_table;
4741 	    break;
4742 #else
4743 	case CASE_CSI_DOLLAR_STATE:
4744 	    /* csi dollar ($) */
4745 	    sp->parsestate = eigtable;
4746 	    break;
4747 
4748 	case CASE_CSI_STAR_STATE:
4749 	    /* csi dollar (*) */
4750 	    sp->parsestate = eigtable;
4751 	    break;
4752 
4753 	case CASE_CSI_DEC_DOLLAR_STATE:
4754 	    /* csi ? dollar ($) */
4755 	    sp->parsestate = eigtable;
4756 	    break;
4757 #endif /* OPT_DEC_RECTOPS */
4758 
4759 #if OPT_XTERM_SGR
4760 	case CASE_CSI_HASH_STATE:
4761 	    TRACE(("CASE_CSI_HASH_STATE\n"));
4762 	    /* csi hash (#) */
4763 	    sp->parsestate = csi_hash_table;
4764 	    break;
4765 
4766 	case CASE_XTERM_CHECKSUM:
4767 #if OPT_DEC_RECTOPS
4768 	    if (screen->vtXX_level >= 4 && AllowWindowOps(xw, ewSetChecksum)) {
4769 		TRACE(("CASE_XTERM_CHECKSUM\n"));
4770 		screen->checksum_ext = zero_if_default(0);
4771 	    }
4772 #endif
4773 	    ResetState(sp);
4774 	    break;
4775 
4776 	case CASE_XTERM_PUSH_SGR:
4777 	    TRACE(("CASE_XTERM_PUSH_SGR\n"));
4778 	    value = 0;
4779 	    if (nparam == 0 || (nparam == 1 && GetParam(0) == DEFAULT)) {
4780 		value = DEFAULT;
4781 	    } else if (nparam > 0) {
4782 		for (count = 0; count < nparam; ++count) {
4783 		    item = zero_if_default(count);
4784 		    /* deprecated - for compatibility */
4785 #if OPT_ISO_COLORS
4786 		    if (item == psFG_COLOR_obs) {
4787 			item = psFG_COLOR;
4788 		    } else if (item == psBG_COLOR_obs) {
4789 			item = psBG_COLOR;
4790 		    }
4791 #endif
4792 		    if (item > 0 && item < MAX_PUSH_SGR) {
4793 			value |= (1 << (item - 1));
4794 		    }
4795 		}
4796 	    }
4797 	    xtermPushSGR(xw, value);
4798 	    ResetState(sp);
4799 	    break;
4800 
4801 	case CASE_XTERM_REPORT_SGR:
4802 	    TRACE(("CASE_XTERM_REPORT_SGR\n"));
4803 	    xtermParseRect(xw, ParamPair(0), &myRect);
4804 	    xtermReportSGR(xw, &myRect);
4805 	    ResetState(sp);
4806 	    break;
4807 
4808 	case CASE_XTERM_POP_SGR:
4809 	    TRACE(("CASE_XTERM_POP_SGR\n"));
4810 	    xtermPopSGR(xw);
4811 	    ResetState(sp);
4812 	    break;
4813 
4814 	case CASE_XTERM_PUSH_COLORS:
4815 	    TRACE(("CASE_XTERM_PUSH_COLORS\n"));
4816 	    if (nparam == 0) {
4817 		xtermPushColors(xw, DEFAULT);
4818 	    } else {
4819 		for (count = 0; count < nparam; ++count) {
4820 		    xtermPushColors(xw, GetParam(count));
4821 		}
4822 	    }
4823 	    ResetState(sp);
4824 	    break;
4825 
4826 	case CASE_XTERM_POP_COLORS:
4827 	    TRACE(("CASE_XTERM_POP_COLORS\n"));
4828 	    if (nparam == 0) {
4829 		xtermPopColors(xw, DEFAULT);
4830 	    } else {
4831 		for (count = 0; count < nparam; ++count) {
4832 		    xtermPopColors(xw, GetParam(count));
4833 		}
4834 	    }
4835 	    ResetState(sp);
4836 	    break;
4837 
4838 	case CASE_XTERM_REPORT_COLORS:
4839 	    TRACE(("CASE_XTERM_REPORT_COLORS\n"));
4840 	    xtermReportColors(xw);
4841 	    ResetState(sp);
4842 	    break;
4843 #endif
4844 
4845 	case CASE_S7C1T:
4846 	    TRACE(("CASE_S7C1T\n"));
4847 	    if (screen->vtXX_level >= 2) {
4848 		show_8bit_control(False);
4849 		ResetState(sp);
4850 	    }
4851 	    break;
4852 
4853 	case CASE_S8C1T:
4854 	    TRACE(("CASE_S8C1T\n"));
4855 	    if (screen->vtXX_level >= 2) {
4856 		show_8bit_control(True);
4857 		ResetState(sp);
4858 	    }
4859 	    break;
4860 
4861 	case CASE_OSC:
4862 	    TRACE(("CASE_OSC: Operating System Command\n"));
4863 	    sp->parsestate = sos_table;
4864 	    sp->string_mode = ANSI_OSC;
4865 	    break;
4866 
4867 	case CASE_RIS:
4868 	    TRACE(("CASE_RIS\n"));
4869 	    VTReset(xw, True, True);
4870 	    /* NOTREACHED */
4871 
4872 	case CASE_DECSTR:
4873 	    TRACE(("CASE_DECSTR\n"));
4874 	    VTReset(xw, False, False);
4875 	    /* NOTREACHED */
4876 
4877 	case CASE_REP:
4878 	    TRACE(("CASE_REP\n"));
4879 	    if (CharWidth(screen, sp->lastchar) > 0) {
4880 		IChar repeated[2];
4881 		count = one_if_default(0);
4882 		repeated[0] = (IChar) sp->lastchar;
4883 		while (count-- > 0) {
4884 		    dotext(xw,
4885 			   screen->gsets[(int) (screen->curgl)],
4886 			   repeated, 1);
4887 		}
4888 	    }
4889 	    ResetState(sp);
4890 	    break;
4891 
4892 	case CASE_LS2:
4893 	    TRACE(("CASE_LS2\n"));
4894 	    screen->curgl = 2;
4895 	    ResetState(sp);
4896 	    break;
4897 
4898 	case CASE_LS3:
4899 	    TRACE(("CASE_LS3\n"));
4900 	    screen->curgl = 3;
4901 	    ResetState(sp);
4902 	    break;
4903 
4904 	case CASE_LS3R:
4905 	    TRACE(("CASE_LS3R\n"));
4906 	    screen->curgr = 3;
4907 	    ResetState(sp);
4908 	    break;
4909 
4910 	case CASE_LS2R:
4911 	    TRACE(("CASE_LS2R\n"));
4912 	    screen->curgr = 2;
4913 	    ResetState(sp);
4914 	    break;
4915 
4916 	case CASE_LS1R:
4917 	    TRACE(("CASE_LS1R\n"));
4918 	    screen->curgr = 1;
4919 	    ResetState(sp);
4920 	    break;
4921 
4922 	case CASE_XTERM_SAVE:
4923 	    savemodes(xw);
4924 	    ResetState(sp);
4925 	    break;
4926 
4927 	case CASE_XTERM_RESTORE:
4928 	    restoremodes(xw);
4929 	    ResetState(sp);
4930 	    break;
4931 
4932 	case CASE_XTERM_WINOPS:
4933 	    TRACE(("CASE_XTERM_WINOPS\n"));
4934 	    window_ops(xw);
4935 	    ResetState(sp);
4936 	    break;
4937 #if OPT_WIDE_CHARS
4938 	case CASE_ESC_PERCENT:
4939 	    TRACE(("CASE_ESC_PERCENT\n"));
4940 	    sp->parsestate = esc_pct_table;
4941 	    break;
4942 
4943 	case CASE_UTF8:
4944 	    /* If we did not set UTF-8 mode from resource or the
4945 	     * command-line, allow it to be enabled/disabled by
4946 	     * control sequence.
4947 	     */
4948 	    TRACE(("CASE_UTF8 wide:%d, utf8:%d, req:%s\n",
4949 		   screen->wide_chars,
4950 		   screen->utf8_mode,
4951 		   BtoS(c == 'G')));
4952 	    if ((!screen->wide_chars) && (c == 'G')) {
4953 		WriteNow();
4954 		ChangeToWide(xw);
4955 	    }
4956 	    if (screen->wide_chars
4957 		&& !screen->utf8_always) {
4958 		switchPtyData(screen, c == 'G');
4959 		TRACE(("UTF8 mode %s\n",
4960 		       BtoS(screen->utf8_mode)));
4961 	    } else {
4962 		TRACE(("UTF8 mode NOT turned %s (%s)\n",
4963 		       BtoS(c == 'G'),
4964 		       (screen->utf8_mode == uAlways)
4965 		       ? "UTF-8 mode set from command-line"
4966 		       : "wideChars resource was not set"));
4967 	    }
4968 	    ResetState(sp);
4969 	    break;
4970 
4971 	case CASE_SCS_DQUOTE:
4972 	    TRACE(("CASE_SCS_DQUOTE\n"));
4973 	    sp->parsestate = scs_2qt_table;
4974 	    break;
4975 
4976 	case CASE_GSETS_DQUOTE:
4977 	    if (screen->vtXX_level >= 5) {
4978 		TRACE(("CASE_GSETS_DQUOTE(%d) = '%c'\n", sp->scstype, c));
4979 		xtermDecodeSCS(xw, sp->scstype, 5, '"', (int) c);
4980 	    }
4981 	    ResetState(sp);
4982 	    break;
4983 
4984 	case CASE_SCS_AMPRSND:
4985 	    TRACE(("CASE_SCS_AMPRSND\n"));
4986 	    sp->parsestate = scs_amp_table;
4987 	    break;
4988 
4989 	case CASE_GSETS_AMPRSND:
4990 	    if (screen->vtXX_level >= 5) {
4991 		TRACE(("CASE_GSETS_AMPRSND(%d) = '%c'\n", sp->scstype, c));
4992 		xtermDecodeSCS(xw, sp->scstype, 5, '&', (int) c);
4993 	    }
4994 	    ResetState(sp);
4995 	    break;
4996 
4997 	case CASE_SCS_PERCENT:
4998 	    TRACE(("CASE_SCS_PERCENT\n"));
4999 	    sp->parsestate = scs_pct_table;
5000 	    break;
5001 
5002 	case CASE_GSETS_PERCENT:
5003 	    if (screen->vtXX_level >= 3) {
5004 		TRACE(("CASE_GSETS_PERCENT(%d) = '%c'\n", sp->scstype, c));
5005 		switch (c) {
5006 		case '0':	/* DEC Turkish */
5007 		case '2':	/* Turkish */
5008 		case '=':	/* Hebrew */
5009 		    value = 5;
5010 		    break;
5011 		case '5':	/* DEC Supplemental Graphics */
5012 		case '6':	/* Portuguese */
5013 		default:
5014 		    value = 3;
5015 		    break;
5016 		}
5017 		xtermDecodeSCS(xw, sp->scstype, value, '%', (int) c);
5018 	    }
5019 	    ResetState(sp);
5020 	    break;
5021 #endif
5022 	case CASE_XTERM_SHIFT_ESCAPE:
5023 	    TRACE(("CASE_XTERM_SHIFT_ESCAPE\n"));
5024 	    value = ((nparam == 0)
5025 		     ? 0
5026 		     : one_if_default(0));
5027 	    if (value >= 0 && value <= 1)
5028 		xw->keyboard.shift_escape = value;
5029 	    ResetState(sp);
5030 	    break;
5031 
5032 #if OPT_MOD_FKEYS
5033 	case CASE_SET_MOD_FKEYS:
5034 	    TRACE(("CASE_SET_MOD_FKEYS\n"));
5035 	    if (nparam >= 1) {
5036 		set_mod_fkeys(xw,
5037 			      GetParam(0),
5038 			      ((nparam > 1)
5039 			       ? GetParam(1)
5040 			       : DEFAULT),
5041 			      True);
5042 	    } else {
5043 		for (value = 1; value <= 5; ++value)
5044 		    set_mod_fkeys(xw, value, DEFAULT, True);
5045 	    }
5046 	    ResetState(sp);
5047 	    break;
5048 
5049 	case CASE_SET_MOD_FKEYS0:
5050 	    TRACE(("CASE_SET_MOD_FKEYS0\n"));
5051 	    if (nparam >= 1 && GetParam(0) != DEFAULT) {
5052 		set_mod_fkeys(xw, GetParam(0), -1, False);
5053 	    } else {
5054 		xw->keyboard.modify_now.function_keys = -1;
5055 	    }
5056 	    ResetState(sp);
5057 	    break;
5058 #endif
5059 	case CASE_HIDE_POINTER:
5060 	    TRACE(("CASE_HIDE_POINTER\n"));
5061 	    if (nparam >= 1 && GetParam(0) != DEFAULT) {
5062 		screen->pointer_mode = GetParam(0);
5063 	    } else {
5064 		screen->pointer_mode = DEF_POINTER_MODE;
5065 	    }
5066 	    ResetState(sp);
5067 	    break;
5068 
5069 	case CASE_XTERM_SM_TITLE:
5070 	    TRACE(("CASE_XTERM_SM_TITLE\n"));
5071 	    if (nparam >= 1) {
5072 		int n;
5073 		for (n = 0; n < nparam; ++n) {
5074 		    if (GetParam(n) != DEFAULT)
5075 			screen->title_modes |= (1 << GetParam(n));
5076 		}
5077 	    } else {
5078 		screen->title_modes = DEF_TITLE_MODES;
5079 	    }
5080 	    TRACE(("...title_modes %#x\n", screen->title_modes));
5081 	    ResetState(sp);
5082 	    break;
5083 
5084 	case CASE_XTERM_RM_TITLE:
5085 	    TRACE(("CASE_XTERM_RM_TITLE\n"));
5086 	    if (nparam >= 1) {
5087 		int n;
5088 		for (n = 0; n < nparam; ++n) {
5089 		    if (GetParam(n) != DEFAULT)
5090 			screen->title_modes &= ~(1 << GetParam(n));
5091 		}
5092 	    } else {
5093 		screen->title_modes = DEF_TITLE_MODES;
5094 	    }
5095 	    TRACE(("...title_modes %#x\n", screen->title_modes));
5096 	    ResetState(sp);
5097 	    break;
5098 
5099 	case CASE_CSI_IGNORE:
5100 	    sp->parsestate = cigtable;
5101 	    break;
5102 
5103 	case CASE_DECSWBV:
5104 	    TRACE(("CASE_DECSWBV\n"));
5105 	    switch (zero_if_default(0)) {
5106 	    case 2:
5107 		/* FALLTHRU */
5108 	    case 3:
5109 		/* FALLTHRU */
5110 	    case 4:
5111 		screen->warningVolume = bvLow;
5112 		break;
5113 	    case 5:
5114 		/* FALLTHRU */
5115 	    case 6:
5116 		/* FALLTHRU */
5117 	    case 7:
5118 		/* FALLTHRU */
5119 	    case 8:
5120 		screen->warningVolume = bvHigh;
5121 		break;
5122 	    default:
5123 		screen->warningVolume = bvOff;
5124 		break;
5125 	    }
5126 	    TRACE(("...warningVolume %d\n", screen->warningVolume));
5127 	    ResetState(sp);
5128 	    break;
5129 
5130 	case CASE_DECSMBV:
5131 	    TRACE(("CASE_DECSMBV\n"));
5132 	    switch (zero_if_default(0)) {
5133 	    case 2:
5134 		/* FALLTHRU */
5135 	    case 3:
5136 		/* FALLTHRU */
5137 	    case 4:
5138 		screen->marginVolume = bvLow;
5139 		break;
5140 	    case 0:
5141 		/* FALLTHRU */
5142 	    case 5:
5143 		/* FALLTHRU */
5144 	    case 6:
5145 		/* FALLTHRU */
5146 	    case 7:
5147 		/* FALLTHRU */
5148 	    case 8:
5149 		screen->marginVolume = bvHigh;
5150 		break;
5151 	    default:
5152 		screen->marginVolume = bvOff;
5153 		break;
5154 	    }
5155 	    TRACE(("...marginVolume %d\n", screen->marginVolume));
5156 	    ResetState(sp);
5157 	    break;
5158 	}
5159 	if (sp->parsestate == sp->groundtable)
5160 	    sp->lastchar = thischar;
5161     } while (0);
5162 
5163 #if OPT_WIDE_CHARS
5164     screen->utf8_inparse = (Boolean) ((screen->utf8_mode != uFalse)
5165 				      && (sp->parsestate != sos_table));
5166 #endif
5167 
5168     if (sp->check_recur)
5169 	sp->check_recur--;
5170     return True;
5171 }
5172 
5173 static void
VTparse(XtermWidget xw)5174 VTparse(XtermWidget xw)
5175 {
5176     Boolean keep_running;
5177 
5178     /* We longjmp back to this point in VTReset() */
5179     (void) setjmp(vtjmpbuf);
5180     init_parser(xw, &myState);
5181 
5182     do {
5183 	keep_running = doparsing(xw, doinput(xw), &myState);
5184 	if (myState.check_recur == 0 && myState.defer_used != 0) {
5185 	    while (myState.defer_used) {
5186 		Char *deferred = myState.defer_area;
5187 		size_t len = myState.defer_used;
5188 		size_t i;
5189 		myState.defer_area = NULL;
5190 		myState.defer_size = 0;
5191 		myState.defer_used = 0;
5192 		for (i = 0; i < len; i++) {
5193 		    (void) doparsing(xw, deferred[i], &myState);
5194 		}
5195 		free(deferred);
5196 	    }
5197 	} else {
5198 	    free(myState.defer_area);
5199 	}
5200 	myState.defer_area = NULL;
5201 	myState.defer_size = 0;
5202 	myState.defer_used = 0;
5203     } while (keep_running);
5204 }
5205 
5206 static Char *v_buffer;		/* pointer to physical buffer */
5207 static Char *v_bufstr = NULL;	/* beginning of area to write */
5208 static Char *v_bufptr;		/* end of area to write */
5209 static Char *v_bufend;		/* end of physical buffer */
5210 
5211 /* Write data to the pty as typed by the user, pasted with the mouse,
5212    or generated by us in response to a query ESC sequence. */
5213 
5214 void
v_write(int f,const Char * data,unsigned len)5215 v_write(int f, const Char *data, unsigned len)
5216 {
5217     TRACE2(("v_write(%d:%s)\n", len, visibleChars(data, len)));
5218     if (v_bufstr == NULL) {
5219 	if (len > 0) {
5220 	    v_buffer = (Char *) XtMalloc((Cardinal) len);
5221 	    v_bufstr = v_buffer;
5222 	    v_bufptr = v_buffer;
5223 	    v_bufend = v_buffer + len;
5224 	}
5225 	if (v_bufstr == NULL) {
5226 	    return;
5227 	}
5228     }
5229     if_DEBUG({
5230 	fprintf(stderr, "v_write called with %u bytes (%ld left over)",
5231 		len, (long) (v_bufptr - v_bufstr));
5232 	if (len > 1 && len < 10)
5233 	    fprintf(stderr, " \"%.*s\"", len, (const char *) data);
5234 	fprintf(stderr, "\n");
5235     });
5236 
5237 #ifdef VMS
5238     if ((1 << f) != pty_mask) {
5239 	tt_write((const char *) data, len);
5240 	return;
5241     }
5242 #else /* VMS */
5243     if (!FD_ISSET(f, &pty_mask)) {
5244 	IGNORE_RC(write(f, (const char *) data, (size_t) len));
5245 	return;
5246     }
5247 #endif /* VMS */
5248 
5249     /*
5250      * Append to the block we already have.
5251      * Always doing this simplifies the code, and
5252      * isn't too bad, either.  If this is a short
5253      * block, it isn't too expensive, and if this is
5254      * a long block, we won't be able to write it all
5255      * anyway.
5256      */
5257 
5258     if (len > 0) {
5259 #if OPT_DABBREV
5260 	TScreenOf(term)->dabbrev_working = False;	/* break dabbrev sequence */
5261 #endif
5262 	if (v_bufend < v_bufptr + len) {	/* we've run out of room */
5263 	    if (v_bufstr != v_buffer) {
5264 		/* there is unused space, move everything down */
5265 		/* possibly overlapping memmove here */
5266 		if_DEBUG({
5267 		    fprintf(stderr, "moving data down %ld\n",
5268 			    (long) (v_bufstr - v_buffer));
5269 		});
5270 		memmove(v_buffer, v_bufstr, (size_t) (v_bufptr - v_bufstr));
5271 		v_bufptr -= v_bufstr - v_buffer;
5272 		v_bufstr = v_buffer;
5273 	    }
5274 	    if (v_bufend < v_bufptr + len) {
5275 		/* still won't fit: get more space */
5276 		/* Don't use XtRealloc because an error is not fatal. */
5277 		unsigned size = (unsigned) (v_bufptr - v_buffer);
5278 		v_buffer = TypeRealloc(Char, size + len, v_buffer);
5279 		if (v_buffer) {
5280 		    if_DEBUG({
5281 			fprintf(stderr, "expanded buffer to %u\n",
5282 				size + len);
5283 		    });
5284 		    v_bufstr = v_buffer;
5285 		    v_bufptr = v_buffer + size;
5286 		    v_bufend = v_bufptr + len;
5287 		} else {
5288 		    /* no memory: ignore entire write request */
5289 		    xtermWarning("cannot allocate buffer space\n");
5290 		    v_buffer = v_bufstr;	/* restore clobbered pointer */
5291 		}
5292 	    }
5293 	}
5294 	if (v_bufend >= v_bufptr + len) {
5295 	    /* new stuff will fit */
5296 	    memmove(v_bufptr, data, (size_t) len);
5297 	    v_bufptr += len;
5298 	}
5299     }
5300 
5301     /*
5302      * Write out as much of the buffer as we can.
5303      * Be careful not to overflow the pty's input silo.
5304      * We are conservative here and only write
5305      * a small amount at a time.
5306      *
5307      * If we can't push all the data into the pty yet, we expect write
5308      * to return a non-negative number less than the length requested
5309      * (if some data written) or -1 and set errno to EAGAIN,
5310      * EWOULDBLOCK, or EINTR (if no data written).
5311      *
5312      * (Not all systems do this, sigh, so the code is actually
5313      * a little more forgiving.)
5314      */
5315 
5316 #define MAX_PTY_WRITE 128	/* 1/2 POSIX minimum MAX_INPUT */
5317 
5318     if (v_bufptr > v_bufstr) {
5319 	int riten;
5320 
5321 #ifdef VMS
5322 	riten = tt_write(v_bufstr,
5323 			 ((v_bufptr - v_bufstr <= VMS_TERM_BUFFER_SIZE)
5324 			  ? v_bufptr - v_bufstr
5325 			  : VMS_TERM_BUFFER_SIZE));
5326 	if (riten == 0)
5327 	    return (riten);
5328 #else /* VMS */
5329 	riten = (int) write(f, v_bufstr,
5330 			    (size_t) ((v_bufptr - v_bufstr <= MAX_PTY_WRITE)
5331 				      ? v_bufptr - v_bufstr
5332 				      : MAX_PTY_WRITE));
5333 	if (riten < 0)
5334 #endif /* VMS */
5335 	{
5336 	    if_DEBUG({
5337 		perror("write");
5338 	    });
5339 	    riten = 0;
5340 	}
5341 	if_DEBUG({
5342 	    fprintf(stderr, "write called with %ld, wrote %d\n",
5343 		    ((long) ((v_bufptr - v_bufstr) <= MAX_PTY_WRITE)
5344 		     ? (long) (v_bufptr - v_bufstr)
5345 		     : MAX_PTY_WRITE),
5346 		    riten);
5347 	});
5348 	v_bufstr += riten;
5349 	if (v_bufstr >= v_bufptr)	/* we wrote it all */
5350 	    v_bufstr = v_bufptr = v_buffer;
5351     }
5352 
5353     /*
5354      * If we have lots of unused memory allocated, return it
5355      */
5356     if (v_bufend - v_bufptr > 1024) {	/* arbitrary hysteresis */
5357 	/* save pointers across realloc */
5358 	int start = (int) (v_bufstr - v_buffer);
5359 	int size = (int) (v_bufptr - v_buffer);
5360 	unsigned allocsize = (unsigned) (size ? size : 1);
5361 
5362 	v_buffer = TypeRealloc(Char, allocsize, v_buffer);
5363 	if (v_buffer) {
5364 	    v_bufstr = v_buffer + start;
5365 	    v_bufptr = v_buffer + size;
5366 	    v_bufend = v_buffer + allocsize;
5367 	    if_DEBUG({
5368 		fprintf(stderr, "shrunk buffer to %u\n", allocsize);
5369 	    });
5370 	} else {
5371 	    /* should we print a warning if couldn't return memory? */
5372 	    v_buffer = v_bufstr - start;	/* restore clobbered pointer */
5373 	}
5374     }
5375 }
5376 
5377 static void
updateCursor(XtermWidget xw)5378 updateCursor(XtermWidget xw)
5379 {
5380     TScreen *screen = TScreenOf(xw);
5381 
5382     if (screen->cursor_set != screen->cursor_state) {
5383 	if (screen->cursor_set)
5384 	    ShowCursor(xw);
5385 	else
5386 	    HideCursor(xw);
5387     }
5388 }
5389 
5390 #if OPT_BLINK_CURS || OPT_BLINK_TEXT
5391 static void
reallyStopBlinking(XtermWidget xw)5392 reallyStopBlinking(XtermWidget xw)
5393 {
5394     TScreen *screen = TScreenOf(xw);
5395 
5396     if (screen->cursor_state == BLINKED_OFF) {
5397 	/* force cursor to display if it is enabled */
5398 	screen->cursor_state = !screen->cursor_set;
5399 	updateCursor(xw);
5400 	xevents(xw);
5401     }
5402 }
5403 #endif
5404 
5405 static void
update_the_screen(XtermWidget xw)5406 update_the_screen(XtermWidget xw)
5407 {
5408     TScreen *screen = TScreenOf(xw);
5409     Boolean moved;
5410 
5411     if (screen->scroll_amt)
5412 	FlushScroll(xw);
5413     moved = CursorMoved(screen);
5414     if (screen->cursor_set && moved) {
5415 	if (screen->cursor_state)
5416 	    HideCursor(xw);
5417 	ShowCursor(xw);
5418 #if OPT_INPUT_METHOD
5419 	PreeditPosition(xw);
5420 #endif
5421     } else {
5422 #if OPT_INPUT_METHOD
5423 	if (moved)
5424 	    PreeditPosition(xw);
5425 #endif
5426 	updateCursor(xw);
5427     }
5428 }
5429 
5430 #ifdef VMS
5431 #define	ptymask()	(v_bufptr > v_bufstr ? pty_mask : 0)
5432 
5433 static void
in_put(XtermWidget xw)5434 in_put(XtermWidget xw)
5435 {
5436     static PtySelect select_mask;
5437     static PtySelect write_mask;
5438     int update = VTbuffer->update;
5439     int size;
5440 
5441     int status;
5442     Dimension replyWidth, replyHeight;
5443     XtGeometryResult stat;
5444 
5445     TScreen *screen = TScreenOf(xw);
5446     char *cp;
5447     int i;
5448 
5449     select_mask = pty_mask;	/* force initial read */
5450     for (;;) {
5451 
5452 	/* if the terminal changed size, resize the widget */
5453 	if (tt_changed) {
5454 	    tt_changed = False;
5455 
5456 	    stat = REQ_RESIZE((Widget) xw,
5457 			      ((Dimension) FontWidth(screen)
5458 			       * (tt_width)
5459 			       + 2 * screen->border
5460 			       + screen->fullVwin.sb_info.width),
5461 			      ((Dimension) FontHeight(screen)
5462 			       * (tt_length)
5463 			       + 2 * screen->border),
5464 			      &replyWidth, &replyHeight);
5465 
5466 	    if (stat == XtGeometryYes || stat == XtGeometryDone) {
5467 		xw->core.width = replyWidth;
5468 		xw->core.height = replyHeight;
5469 
5470 		ScreenResize(xw, replyWidth, replyHeight, &xw->flags);
5471 	    }
5472 	    repairSizeHints();
5473 	}
5474 
5475 	if (screen->eventMode == NORMAL
5476 	    && readPtyData(xw, &select_mask, VTbuffer)) {
5477 	    if (screen->scrollWidget
5478 		&& screen->scrollttyoutput
5479 		&& screen->topline < 0)
5480 		/* Scroll to bottom */
5481 		WindowScroll(xw, 0, False);
5482 	    break;
5483 	}
5484 	update_the_screen(xw);
5485 
5486 	if (QLength(screen->display)) {
5487 	    select_mask = X_mask;
5488 	} else {
5489 	    write_mask = ptymask();
5490 	    XFlush(screen->display);
5491 	    select_mask = Select_mask;
5492 	    if (screen->eventMode != NORMAL)
5493 		select_mask = X_mask;
5494 	}
5495 	if (write_mask & ptymask()) {
5496 	    v_write(screen->respond, 0, 0);	/* flush buffer */
5497 	}
5498 
5499 	if (select_mask & X_mask) {
5500 	    xevents(xw);
5501 	    if (VTbuffer->update != update)
5502 		break;
5503 	}
5504     }
5505 }
5506 #else /* VMS */
5507 
5508 static void
in_put(XtermWidget xw)5509 in_put(XtermWidget xw)
5510 {
5511     static PtySelect select_mask;
5512     static PtySelect write_mask;
5513 
5514     TScreen *screen = TScreenOf(xw);
5515     int i;
5516     int update = VTbuffer->update;
5517 #if USE_DOUBLE_BUFFER
5518     int should_wait = 1;
5519 #endif
5520 
5521     static struct timeval select_timeout;
5522 
5523 #if OPT_BLINK_CURS
5524     /*
5525      * Compute the timeout for the blinking cursor to be much smaller than
5526      * the "on" or "off" interval.
5527      */
5528     int tick = ((screen->blink_on < screen->blink_off)
5529 		? screen->blink_on
5530 		: screen->blink_off);
5531     tick *= (1000 / 8);		/* 1000 for msec/usec, 8 for "much" smaller */
5532     if (tick < 1)
5533 	tick = 1;
5534 #endif
5535 
5536     for (;;) {
5537 	int size;
5538 	int time_select;
5539 
5540 	if (screen->eventMode == NORMAL
5541 	    && (size = readPtyData(xw, &select_mask, VTbuffer)) != 0) {
5542 	    if (screen->scrollWidget
5543 		&& screen->scrollttyoutput
5544 		&& screen->topline < 0)
5545 		WindowScroll(xw, 0, False);	/* Scroll to bottom */
5546 	    /* stop speed reading at some point to look for X stuff */
5547 	    TRACE(("VTbuffer uses %ld/%d\n",
5548 		   (long) (VTbuffer->last - VTbuffer->buffer),
5549 		   BUF_SIZE));
5550 	    if ((VTbuffer->last - VTbuffer->buffer) > BUF_SIZE) {
5551 		FD_CLR(screen->respond, &select_mask);
5552 		break;
5553 	    }
5554 #if USE_DOUBLE_BUFFER
5555 	    if (resource.buffered && should_wait) {
5556 		/* wait for potential extra data (avoids some flickering) */
5557 		usleep((unsigned) DbeMsecs(xw));
5558 		should_wait = 0;
5559 	    }
5560 #endif
5561 #if defined(HAVE_SCHED_YIELD)
5562 	    /*
5563 	     * If we've read a full (small/fragment) buffer, let the operating
5564 	     * system have a turn, and we'll resume reading until we've either
5565 	     * read only a fragment of the buffer, or we've filled the large
5566 	     * buffer (see above).  Doing this helps keep up with large bursts
5567 	     * of output.
5568 	     */
5569 	    if (size == FRG_SIZE) {
5570 		select_timeout.tv_sec = 0;
5571 		i = Select(max_plus1, &select_mask, &write_mask, 0,
5572 			   &select_timeout);
5573 		if (i > 0 && FD_ISSET(screen->respond, &select_mask)) {
5574 		    sched_yield();
5575 		} else
5576 		    break;
5577 	    } else {
5578 		break;
5579 	    }
5580 #else
5581 	    (void) size;	/* unused in this branch */
5582 	    break;
5583 #endif
5584 	}
5585 	update_the_screen(xw);
5586 
5587 	XFlush(screen->display);	/* always flush writes before waiting */
5588 
5589 	/* Update the masks and, unless X events are already in the queue,
5590 	   wait for I/O to be possible. */
5591 	XFD_COPYSET(&Select_mask, &select_mask);
5592 	/* in selection mode xterm does not read pty */
5593 	if (screen->eventMode != NORMAL)
5594 	    FD_CLR(screen->respond, &select_mask);
5595 
5596 	if (v_bufptr > v_bufstr) {
5597 	    XFD_COPYSET(&pty_mask, &write_mask);
5598 	} else
5599 	    FD_ZERO(&write_mask);
5600 	select_timeout.tv_sec = 0;
5601 	time_select = 0;
5602 
5603 	/*
5604 	 * if there's either an XEvent or an XtTimeout pending, just take
5605 	 * a quick peek, i.e. timeout from the select() immediately.  If
5606 	 * there's nothing pending, let select() block a little while, but
5607 	 * for a shorter interval than the arrow-style scrollbar timeout.
5608 	 * The blocking is optional, because it tends to increase the load
5609 	 * on the host.
5610 	 */
5611 	if (xtermAppPending()) {
5612 	    select_timeout.tv_usec = 0;
5613 	    time_select = 1;
5614 	} else if (screen->awaitInput) {
5615 	    select_timeout.tv_usec = 50000;
5616 	    time_select = 1;
5617 #if OPT_BLINK_CURS
5618 	} else if ((screen->blink_timer != 0 &&
5619 		    ((screen->select & FOCUS) || screen->always_highlight)) ||
5620 		   (screen->cursor_state == BLINKED_OFF)) {
5621 	    select_timeout.tv_usec = tick;
5622 	    while (select_timeout.tv_usec > 1000000) {
5623 		select_timeout.tv_usec -= 1000000;
5624 		select_timeout.tv_sec++;
5625 	    }
5626 	    time_select = 1;
5627 #endif
5628 #if OPT_SESSION_MGT
5629 	} else if (resource.sessionMgt) {
5630 	    if (ice_fd >= 0)
5631 		FD_SET(ice_fd, &select_mask);
5632 #endif
5633 	}
5634 	if (need_cleanup)
5635 	    NormalExit();
5636 	xtermFlushDbe(xw);
5637 	i = Select(max_plus1, &select_mask, &write_mask, 0,
5638 		   (time_select ? &select_timeout : 0));
5639 	if (i < 0) {
5640 	    if (errno != EINTR)
5641 		SysError(ERROR_SELECT);
5642 	    continue;
5643 	}
5644 
5645 	/* if there is room to write more data to the pty, go write more */
5646 	if (FD_ISSET(screen->respond, &write_mask)) {
5647 	    v_write(screen->respond, (Char *) 0, 0);	/* flush buffer */
5648 	}
5649 
5650 	/* if there are X events already in our queue, it
5651 	   counts as being readable */
5652 	if (xtermAppPending() ||
5653 	    FD_ISSET(ConnectionNumber(screen->display), &select_mask)) {
5654 	    xevents(xw);
5655 	    if (VTbuffer->update != update)	/* HandleInterpret */
5656 		break;
5657 	}
5658 
5659     }
5660 }
5661 #endif /* VMS */
5662 
5663 static IChar
doinput(XtermWidget xw)5664 doinput(XtermWidget xw)
5665 {
5666     TScreen *screen = TScreenOf(xw);
5667 
5668     while (!morePtyData(screen, VTbuffer))
5669 	in_put(xw);
5670     return nextPtyData(screen, VTbuffer);
5671 }
5672 
5673 #if OPT_INPUT_METHOD
5674 /*
5675  *  For OverTheSpot, client has to inform the position for XIM preedit.
5676  */
5677 static void
PreeditPosition(XtermWidget xw)5678 PreeditPosition(XtermWidget xw)
5679 {
5680     TInput *input = lookupTInput(xw, (Widget) xw);
5681     TScreen *screen = TScreenOf(xw);
5682     CLineData *ld;
5683     XPoint spot;
5684     XVaNestedList list;
5685 
5686     if (input && input->xic
5687 	&& (ld = getLineData(screen, screen->cur_row)) != 0) {
5688 	spot.x = (short) LineCursorX(screen, ld, screen->cur_col);
5689 	spot.y = (short) (CursorY(screen, screen->cur_row) + xw->work.xim_fs_ascent);
5690 	list = XVaCreateNestedList(0,
5691 				   XNSpotLocation, &spot,
5692 				   XNForeground, T_COLOR(screen, TEXT_FG),
5693 				   XNBackground, T_COLOR(screen, TEXT_BG),
5694 				   (void *) 0);
5695 	XSetICValues(input->xic, XNPreeditAttributes, list, (void *) 0);
5696 	XFree(list);
5697     }
5698 }
5699 #endif
5700 
5701 static void
WrapLine(XtermWidget xw)5702 WrapLine(XtermWidget xw)
5703 {
5704     TScreen *screen = TScreenOf(xw);
5705     LineData *ld = getLineData(screen, screen->cur_row);
5706 
5707     if (ld != 0) {
5708 	/* mark that we had to wrap this line */
5709 	LineSetFlag(ld, LINEWRAPPED);
5710 	ShowWrapMarks(xw, screen->cur_row, ld);
5711 	xtermAutoPrint(xw, '\n');
5712 	xtermIndex(xw, 1);
5713 	set_cur_col(screen, ScrnLeftMargin(xw));
5714     }
5715 }
5716 
5717 /*
5718  * Process a string of characters according to the character set indicated by
5719  * charset.  Worry about end of line conditions (wraparound if selected).
5720  *
5721  * It is possible to use CUP, etc., to move outside margins.  In that case, the
5722  * right-margin is ineffective until the text (may) wrap and get within the
5723  * margins.
5724  */
5725 void
dotext(XtermWidget xw,DECNRCM_codes charset,IChar * buf,Cardinal len)5726 dotext(XtermWidget xw,
5727        DECNRCM_codes charset,
5728        IChar *buf,		/* start of characters to process */
5729        Cardinal len)		/* end */
5730 {
5731     TScreen *screen = TScreenOf(xw);
5732 #if OPT_WIDE_CHARS
5733     Cardinal chars_chomped = 1;
5734     int next_col = screen->cur_col;
5735 #else
5736     int next_col, this_col;	/* must be signed */
5737 #endif
5738     Cardinal offset;
5739     int rmargin = ScrnRightMargin(xw);
5740 
5741 #if OPT_WIDE_CHARS
5742     if (screen->vt100_graphics)
5743 #endif
5744 	if (!(len = (Cardinal) xtermCharSetOut(xw, buf, buf + len, charset)))
5745 	    return;
5746 
5747     if_OPT_XMC_GLITCH(screen, {
5748 	Cardinal n;
5749 	if (charset != '?') {
5750 	    for (n = 0; n < len; n++) {
5751 		if (buf[n] == XMC_GLITCH)
5752 		    buf[n] = XMC_GLITCH + 1;
5753 	    }
5754 	}
5755     });
5756 
5757 #if OPT_WIDE_CHARS
5758     for (offset = 0;
5759 	 offset < len && (chars_chomped > 0 || screen->do_wrap);
5760 	 offset += chars_chomped) {
5761 #if OPT_DEC_CHRSET
5762 	CLineData *ld = getLineData(screen, screen->cur_row);
5763 	int real_rmargin = (CSET_DOUBLE(GetLineDblCS(ld))
5764 			    ? (rmargin / 2)
5765 			    : rmargin);
5766 #else
5767 	int real_rmargin = rmargin;
5768 #endif
5769 	int last_col = LineMaxCol(screen, ld);
5770 	int width_here = 0;
5771 	int last_chomp = 0;
5772 	Boolean force_wrap;
5773 
5774 	chars_chomped = 0;
5775 	do {
5776 	    int right = ((screen->cur_col > real_rmargin)
5777 			 ? last_col
5778 			 : real_rmargin);
5779 	    int width_available = right + 1 - screen->cur_col;
5780 	    Boolean need_wrap = False;
5781 	    Boolean did_wrap = False;
5782 
5783 	    force_wrap = False;
5784 
5785 	    if (screen->do_wrap) {
5786 		screen->do_wrap = False;
5787 		if ((xw->flags & WRAPAROUND)) {
5788 		    WrapLine(xw);
5789 		    right = ((screen->cur_col > real_rmargin)
5790 			     ? last_col
5791 			     : real_rmargin);
5792 		    width_available = right + 1 - screen->cur_col;
5793 		    next_col = screen->cur_col;
5794 		    did_wrap = True;
5795 		}
5796 	    }
5797 
5798 	    /*
5799 	     * This can happen with left/right margins...
5800 	     */
5801 	    if (width_available <= 0) {
5802 		break;
5803 	    }
5804 
5805 	    /*
5806 	     * Regarding the soft-hyphen aberration, see
5807 	     * http://archives.miloush.net/michkap/archive/2006/09/02/736881.html
5808 	     */
5809 	    while (width_here <= width_available
5810 		   && chars_chomped < (len - offset)) {
5811 		Cardinal n = chars_chomped + offset;
5812 		if (!screen->utf8_mode
5813 		    || (screen->vt100_graphics && charset == '0')) {
5814 		    last_chomp = 1;
5815 		} else if (screen->c1_printable &&
5816 			   buf[n] >= 0x80 &&
5817 			   buf[n] <= 0xa0) {
5818 		    last_chomp = 1;
5819 		} else {
5820 		    last_chomp = CharWidth(screen, buf[n]);
5821 		    if (last_chomp <= 0) {
5822 			IChar ch = buf[n];
5823 			Bool eat_it = !screen->utf8_mode && (ch > 127);
5824 			if (ch == 0xad) {
5825 			    /*
5826 			     * Only display soft-hyphen if it happens to be at
5827 			     * the right-margin.  While that means that only
5828 			     * the displayed character could be selected for
5829 			     * pasting, a well-behaved application would never
5830 			     * send this, anyway...
5831 			     */
5832 			    if (width_here < width_available - 1) {
5833 				eat_it = True;
5834 			    } else {
5835 				last_chomp = 1;
5836 				eat_it = False;
5837 			    }
5838 			    TRACE(("...will%s display soft-hyphen\n",
5839 				   eat_it ? " not" : ""));
5840 			}
5841 			/*
5842 			 * Supposedly we dealt with combining characters and
5843 			 * control characters in doparse().  Anything left over
5844 			 * is junk that we will not attempt to display.
5845 			 */
5846 			if (eat_it) {
5847 			    TRACE(("...will not display U+%04X\n", ch));
5848 			    --len;
5849 			    while (n < len) {
5850 				buf[n] = buf[n + 1];
5851 				++n;
5852 			    }
5853 			    last_chomp = 0;
5854 			    chars_chomped--;
5855 			}
5856 		    }
5857 		}
5858 		width_here += last_chomp;
5859 		chars_chomped++;
5860 	    }
5861 
5862 	    if (width_here > width_available) {
5863 		if (last_chomp > right + 1) {
5864 		    break;	/* give up - it is too big */
5865 		} else if (chars_chomped-- == 0) {
5866 		    /* This can happen with left/right margins... */
5867 		    break;
5868 		}
5869 		width_here -= last_chomp;
5870 		if (chars_chomped > 0) {
5871 		    if (!(xw->flags & WRAPAROUND)) {
5872 			buf[chars_chomped + offset - 1] = buf[len - 1];
5873 		    } else {
5874 			need_wrap = True;
5875 		    }
5876 		}
5877 	    } else if (width_here == width_available) {
5878 		need_wrap = True;
5879 	    } else if (chars_chomped != (len - offset)) {
5880 		need_wrap = True;
5881 	    }
5882 
5883 	    if (chars_chomped != 0 && next_col <= last_col) {
5884 		WriteText(xw, buf + offset, chars_chomped);
5885 	    } else if (!did_wrap
5886 		       && len > 0
5887 		       && (xw->flags & WRAPAROUND)
5888 		       && screen->cur_col > ScrnLeftMargin(xw)) {
5889 		force_wrap = True;
5890 		need_wrap = True;
5891 	    }
5892 	    next_col += width_here;
5893 	    screen->do_wrap = need_wrap;
5894 	} while (force_wrap);
5895     }
5896 
5897     /*
5898      * Remember that we wrote something to the screen, for use as a base of
5899      * combining characters.  The logic above may have called cursor-forward
5900      * or carriage-return operations which resets this flag, so we set it at
5901      * the very end.
5902      */
5903     screen->char_was_written = True;
5904 #else /* ! OPT_WIDE_CHARS */
5905 
5906     for (offset = 0; offset < len; offset += (Cardinal) this_col) {
5907 #if OPT_DEC_CHRSET
5908 	CLineData *ld = getLineData(screen, screen->cur_row);
5909 #endif
5910 	int right = ((screen->cur_col > rmargin)
5911 		     ? screen->max_col
5912 		     : rmargin);
5913 
5914 	int last_col = LineMaxCol(screen, ld);
5915 	if (last_col > right)
5916 	    last_col = right;
5917 	this_col = last_col - screen->cur_col + 1;
5918 	if (screen->do_wrap) {
5919 	    screen->do_wrap = False;
5920 	    if ((xw->flags & WRAPAROUND)) {
5921 		WrapLine(xw);
5922 	    }
5923 	    this_col = 1;
5924 	}
5925 	if (offset + (Cardinal) this_col > len) {
5926 	    this_col = (int) (len - offset);
5927 	}
5928 	next_col = screen->cur_col + this_col;
5929 
5930 	WriteText(xw, buf + offset, (unsigned) this_col);
5931 
5932 	/*
5933 	 * The call to WriteText updates screen->cur_col.
5934 	 * If screen->cur_col is less than next_col, we must have
5935 	 * hit the right margin - so set the do_wrap flag.
5936 	 */
5937 	screen->do_wrap = (Boolean) (screen->cur_col < next_col);
5938     }
5939 
5940 #endif /* OPT_WIDE_CHARS */
5941 }
5942 
5943 #if OPT_WIDE_CHARS
5944 unsigned
visual_width(const IChar * str,Cardinal len)5945 visual_width(const IChar *str, Cardinal len)
5946 {
5947     /* returns the visual width of a string (doublewide characters count
5948        as 2, normalwide characters count as 1) */
5949     unsigned my_len = 0;
5950     while (len) {
5951 	int ch = (int) *str++;
5952 	if (isWide(ch))
5953 	    my_len += 2;
5954 	else
5955 	    my_len++;
5956 	len--;
5957     }
5958     return my_len;
5959 }
5960 #endif
5961 
5962 #if HANDLE_STRUCT_NOTIFY
5963 /* Flag icon name with "***" on window output when iconified.
5964  */
5965 static void
HandleStructNotify(Widget w GCC_UNUSED,XtPointer closure GCC_UNUSED,XEvent * event,Boolean * cont GCC_UNUSED)5966 HandleStructNotify(Widget w GCC_UNUSED,
5967 		   XtPointer closure GCC_UNUSED,
5968 		   XEvent *event,
5969 		   Boolean *cont GCC_UNUSED)
5970 {
5971     XtermWidget xw = term;
5972     TScreen *screen = TScreenOf(xw);
5973 
5974     (void) screen;
5975     TRACE_EVENT("HandleStructNotify", event, NULL, 0);
5976     switch (event->type) {
5977     case MapNotify:
5978 	resetZIconBeep(xw);
5979 	mapstate = !IsUnmapped;
5980 	break;
5981     case UnmapNotify:
5982 	mapstate = IsUnmapped;
5983 	break;
5984     case MappingNotify:
5985 	XRefreshKeyboardMapping(&(event->xmapping));
5986 	VTInitModifiers(xw);
5987 	break;
5988     case ConfigureNotify:
5989 	if (event->xconfigure.window == XtWindow(toplevel)) {
5990 #if !OPT_TOOLBAR
5991 	    int height = event->xconfigure.height;
5992 	    int width = event->xconfigure.width;
5993 #endif
5994 
5995 #if USE_DOUBLE_BUFFER
5996 	    discardRenderDraw(screen);
5997 #endif /* USE_DOUBLE_BUFFER */
5998 #if OPT_TOOLBAR
5999 	    /*
6000 	     * The notification is for the top-level widget, but we care about
6001 	     * vt100 (ignore the tek4014 window).
6002 	     */
6003 	    if (screen->Vshow) {
6004 		VTwin *Vwin = WhichVWin(screen);
6005 		TbInfo *info = &(Vwin->tb_info);
6006 		TbInfo save = *info;
6007 
6008 		if (info->menu_bar) {
6009 		    XtVaGetValues(info->menu_bar,
6010 				  XtNheight, &info->menu_height,
6011 				  XtNborderWidth, &info->menu_border,
6012 				  (XtPointer) 0);
6013 
6014 		    if (save.menu_height != info->menu_height
6015 			|| save.menu_border != info->menu_border) {
6016 
6017 			TRACE(("...menu_height %d\n", info->menu_height));
6018 			TRACE(("...menu_border %d\n", info->menu_border));
6019 			TRACE(("...had height  %d, border %d\n",
6020 			       save.menu_height,
6021 			       save.menu_border));
6022 
6023 			/*
6024 			 * Window manager still may be using the old values.
6025 			 * Try to fool it.
6026 			 */
6027 			REQ_RESIZE((Widget) xw,
6028 				   screen->fullVwin.fullwidth,
6029 				   (Dimension) (info->menu_height
6030 						- save.menu_height
6031 						+ screen->fullVwin.fullheight),
6032 				   NULL, NULL);
6033 			repairSizeHints();
6034 		    }
6035 		}
6036 	    }
6037 #else
6038 	    if (!xw->work.doing_resize
6039 #if OPT_RENDERFONT && USE_DOUBLE_BUFFER
6040 		&& !(resource.buffered && UsingRenderFont(xw))	/* buggyXft */
6041 #endif
6042 		&& (height != xw->hints.height
6043 		    || width != xw->hints.width)) {
6044 		/*
6045 		 * This is a special case: other calls to RequestResize that
6046 		 * could set the screensize arbitrarily are via escape
6047 		 * sequences, and we've limited resizing.  But a configure
6048 		 * notify is from the window manager, presumably under control
6049 		 * of the interactive user (ignoring abuse of wmctrl).  Ignore
6050 		 * the limit for this case.
6051 		 */
6052 		int saved_limit = xw->misc.limit_resize;
6053 		xw->misc.limit_resize = 0;
6054 		RequestResize(xw, height, width, False);
6055 		xw->misc.limit_resize = saved_limit;
6056 	    }
6057 #endif /* OPT_TOOLBAR */
6058 	}
6059 	break;
6060     }
6061 }
6062 #endif /* HANDLE_STRUCT_NOTIFY */
6063 
6064 #if OPT_BLINK_CURS
6065 static int
DoStartBlinking(TScreen * screen)6066 DoStartBlinking(TScreen *screen)
6067 {
6068     int actual = ((screen->cursor_blink == cbTrue ||
6069 		   screen->cursor_blink == cbAlways)
6070 		  ? 1
6071 		  : 0);
6072     int wanted = screen->cursor_blink_esc ? 1 : 0;
6073     int result;
6074     if (screen->cursor_blink_xor) {
6075 	result = actual ^ wanted;
6076     } else {
6077 	result = actual | wanted;
6078     }
6079     return result;
6080 }
6081 
6082 static void
SetCursorBlink(XtermWidget xw,BlinkOps enable)6083 SetCursorBlink(XtermWidget xw, BlinkOps enable)
6084 {
6085     TScreen *screen = TScreenOf(xw);
6086 
6087     if (SettableCursorBlink(screen)) {
6088 	screen->cursor_blink = enable;
6089     }
6090     if (DoStartBlinking(screen)) {
6091 	StartBlinking(xw);
6092     } else {
6093 	/* EMPTY */
6094 #if OPT_BLINK_TEXT
6095 	reallyStopBlinking(xw);
6096 #else
6097 	StopBlinking(xw);
6098 #endif
6099     }
6100     update_cursorblink();
6101 }
6102 
6103 void
ToggleCursorBlink(XtermWidget xw)6104 ToggleCursorBlink(XtermWidget xw)
6105 {
6106     TScreen *screen = TScreenOf(xw);
6107 
6108     if (screen->cursor_blink == cbTrue) {
6109 	SetCursorBlink(xw, cbFalse);
6110     } else if (screen->cursor_blink == cbFalse) {
6111 	SetCursorBlink(xw, cbTrue);
6112     }
6113 }
6114 #endif
6115 
6116 /*
6117  * process ANSI modes set, reset
6118  */
6119 static void
ansi_modes(XtermWidget xw,BitFunc func)6120 ansi_modes(XtermWidget xw, BitFunc func)
6121 {
6122     int i;
6123 
6124     for (i = 0; i < nparam; ++i) {
6125 	switch (GetParam(i)) {
6126 	case 2:		/* KAM (if set, keyboard locked */
6127 	    (*func) (&xw->keyboard.flags, MODE_KAM);
6128 	    break;
6129 
6130 	case 4:		/* IRM                          */
6131 	    (*func) (&xw->flags, INSERT);
6132 	    break;
6133 
6134 	case 12:		/* SRM (if set, local echo      */
6135 	    (*func) (&xw->keyboard.flags, MODE_SRM);
6136 	    break;
6137 
6138 	case 20:		/* LNM                          */
6139 	    (*func) (&xw->flags, LINEFEED);
6140 	    update_autolinefeed();
6141 	    break;
6142 	}
6143     }
6144 }
6145 
6146 #define IsSM() (func == bitset)
6147 
6148 #define set_bool_mode(flag) \
6149 	flag = (Boolean) IsSM()
6150 
6151 static void
really_set_mousemode(XtermWidget xw,Bool enabled,XtermMouseModes mode)6152 really_set_mousemode(XtermWidget xw,
6153 		     Bool enabled,
6154 		     XtermMouseModes mode)
6155 {
6156     TScreenOf(xw)->send_mouse_pos = enabled ? mode : MOUSE_OFF;
6157     if (okSendMousePos(xw) != MOUSE_OFF)
6158 	xtermShowPointer(xw, True);
6159 }
6160 
6161 #define set_mousemode(mode) really_set_mousemode(xw, IsSM(), mode)
6162 
6163 #if OPT_PASTE64 || OPT_READLINE
6164 #define set_mouseflag(f)		\
6165 	(IsSM()				\
6166 	 ? SCREEN_FLAG_set(screen, f)	\
6167 	 : SCREEN_FLAG_unset(screen, f))
6168 #endif
6169 
6170 /*
6171  * DEC 070, pp 5-71 to 5-72.
6172  */
6173 static void
set_column_mode(XtermWidget xw)6174 set_column_mode(XtermWidget xw)
6175 {
6176     TScreen *screen = TScreenOf(xw);
6177 
6178     xterm_ResetDouble(xw);
6179     resetMargins(xw);
6180     UIntSet(xw->flags, LEFT_RIGHT);
6181     CursorSet(screen, 0, 0, xw->flags);
6182 }
6183 
6184 /*
6185  * DEC 070, pp 5-29 to 5-30.
6186  */
6187 static void
set_left_right_margin_mode(XtermWidget xw)6188 set_left_right_margin_mode(XtermWidget xw)
6189 {
6190     TScreen *screen = TScreenOf(xw);
6191 
6192     if (screen->vtXX_level >= 4) {
6193 	if (IsLeftRightMode(xw)) {
6194 	    xterm_ResetDouble(xw);
6195 	} else {
6196 	    reset_lr_margins(screen);
6197 	}
6198     }
6199 }
6200 
6201 /*
6202  * process DEC private modes set, reset
6203  */
6204 static void
dpmodes(XtermWidget xw,BitFunc func)6205 dpmodes(XtermWidget xw, BitFunc func)
6206 {
6207     TScreen *screen = TScreenOf(xw);
6208     int i, j;
6209     unsigned myflags;
6210 
6211     TRACE(("changing %d DEC private modes\n", nparam));
6212     for (i = 0; i < nparam; ++i) {
6213 	int code = GetParam(i);
6214 
6215 	TRACE(("%s %d\n", IsSM()? "DECSET" : "DECRST", code));
6216 	switch ((DECSET_codes) code) {
6217 	case srm_DECCKM:
6218 	    (*func) (&xw->keyboard.flags, MODE_DECCKM);
6219 	    update_appcursor();
6220 	    break;
6221 	case srm_DECANM:	/* ANSI/VT52 mode      */
6222 	    if (IsSM()) {	/* ANSI (VT100) */
6223 		/*
6224 		 * Setting DECANM should have no effect, since this function
6225 		 * cannot be reached from vt52 mode.
6226 		 */
6227 		/* EMPTY */ ;
6228 	    }
6229 #if OPT_VT52_MODE
6230 	    else if (screen->terminal_id >= 100) {	/* VT52 */
6231 		TRACE(("DECANM terminal_id %d, vtXX_level %d\n",
6232 		       screen->terminal_id,
6233 		       screen->vtXX_level));
6234 		/*
6235 		 * According to DEC STD 070 section A.5.5, the various VT100
6236 		 * modes have undefined behavior when entering/exiting VT52
6237 		 * mode.  xterm saves/restores/initializes the most commonly
6238 		 * used settings, but a real VT100 or VT520 may differ.
6239 		 *
6240 		 * For instance, DEC's documentation goes on to comment that
6241 		 * while the VT52 uses hardware tabs (8 columns), the emulation
6242 		 * (e.g., a VT420) does not alter those tab settings when
6243 		 * switching modes.
6244 		 */
6245 		screen->vtXX_level = 0;
6246 		screen->vt52_save_flags = xw->flags;
6247 		xw->flags = 0;
6248 		screen->vt52_save_curgl = screen->curgl;
6249 		screen->vt52_save_curgr = screen->curgr;
6250 		screen->vt52_save_curss = screen->curss;
6251 		saveCharsets(screen, screen->vt52_save_gsets);
6252 		resetCharsets(screen);
6253 		InitParams();	/* ignore the remaining params, if any */
6254 		update_vt52_vt100_settings();
6255 		RequestResize(xw, -1, 80, True);
6256 	    }
6257 #endif
6258 	    break;
6259 	case srm_DECCOLM:
6260 	    if (screen->c132) {
6261 		Boolean willResize = ((j = IsSM()
6262 				       ? 132
6263 				       : 80)
6264 				      != ((xw->flags & IN132COLUMNS)
6265 					  ? 132
6266 					  : 80)
6267 				      || j != MaxCols(screen));
6268 		if (!(xw->flags & NOCLEAR_COLM))
6269 		    ClearScreen(xw);
6270 		if (willResize)
6271 		    RequestResize(xw, -1, j, True);
6272 		(*func) (&xw->flags, IN132COLUMNS);
6273 		set_column_mode(xw);
6274 	    }
6275 	    break;
6276 	case srm_DECSCLM:	/* (slow scroll)        */
6277 	    if (IsSM()) {
6278 		screen->jumpscroll = 0;
6279 		if (screen->scroll_amt)
6280 		    FlushScroll(xw);
6281 	    } else
6282 		screen->jumpscroll = 1;
6283 	    (*func) (&xw->flags, SMOOTHSCROLL);
6284 	    update_jumpscroll();
6285 	    break;
6286 	case srm_DECSCNM:
6287 	    myflags = xw->flags;
6288 	    (*func) (&xw->flags, REVERSE_VIDEO);
6289 	    if ((xw->flags ^ myflags) & REVERSE_VIDEO)
6290 		ReverseVideo(xw);
6291 	    /* update_reversevideo done in RevVid */
6292 	    break;
6293 
6294 	case srm_DECOM:
6295 	    (*func) (&xw->flags, ORIGIN);
6296 	    CursorSet(screen, 0, 0, xw->flags);
6297 	    break;
6298 
6299 	case srm_DECAWM:
6300 	    (*func) (&xw->flags, WRAPAROUND);
6301 	    update_autowrap();
6302 	    break;
6303 	case srm_DECARM:
6304 	    /* ignore autorepeat
6305 	     * XAutoRepeatOn() and XAutoRepeatOff() can do this, but only
6306 	     * for the whole display - not limited to a given window.
6307 	     */
6308 	    break;
6309 	case srm_X10_MOUSE:	/* MIT bogus sequence           */
6310 	    MotionOff(screen, xw);
6311 	    set_mousemode(X10_MOUSE);
6312 	    break;
6313 #if OPT_TOOLBAR
6314 	case srm_RXVT_TOOLBAR:
6315 	    ShowToolbar(IsSM());
6316 	    break;
6317 #endif
6318 #if OPT_BLINK_CURS
6319 	case srm_ATT610_BLINK:	/* AT&T 610: Start/stop blinking cursor */
6320 	    if (SettableCursorBlink(screen)) {
6321 		set_bool_mode(screen->cursor_blink_esc);
6322 		UpdateCursorBlink(xw);
6323 	    }
6324 	    break;
6325 	case srm_CURSOR_BLINK_OPS:
6326 	    /* intentionally ignored (this is user-preference) */
6327 	    break;
6328 	case srm_XOR_CURSOR_BLINKS:
6329 	    /* intentionally ignored (this is user-preference) */
6330 	    break;
6331 #endif
6332 	case srm_DECPFF:	/* print form feed */
6333 	    set_bool_mode(PrinterOf(screen).printer_formfeed);
6334 	    break;
6335 	case srm_DECPEX:	/* print extent */
6336 	    set_bool_mode(PrinterOf(screen).printer_extent);
6337 	    break;
6338 	case srm_DECTCEM:	/* Show/hide cursor (VT200) */
6339 	    set_bool_mode(screen->cursor_set);
6340 	    break;
6341 	case srm_RXVT_SCROLLBAR:
6342 	    if (screen->fullVwin.sb_info.width != (IsSM()? ON : OFF))
6343 		ToggleScrollBar(xw);
6344 	    break;
6345 #if OPT_SHIFT_FONTS
6346 	case srm_RXVT_FONTSIZE:
6347 	    set_bool_mode(xw->misc.shift_fonts);
6348 	    break;
6349 #endif
6350 #if OPT_TEK4014
6351 	case srm_DECTEK:
6352 	    if (IsSM() && !(screen->inhibit & I_TEK)) {
6353 		FlushLog(xw);
6354 		TEK4014_ACTIVE(xw) = True;
6355 		TRACE(("Tek4014 is now active...\n"));
6356 		update_vttekmode();
6357 	    }
6358 	    break;
6359 #endif
6360 	case srm_132COLS:	/* 132 column mode              */
6361 	    set_bool_mode(screen->c132);
6362 	    update_allow132();
6363 	    break;
6364 	case srm_CURSES_HACK:
6365 	    set_bool_mode(screen->curses);
6366 	    update_cursesemul();
6367 	    break;
6368 	case srm_DECNRCM:	/* national charset (VT220) */
6369 	    if (screen->vtXX_level >= 2) {
6370 		if ((*func) (&xw->flags, NATIONAL)) {
6371 		    modified_DECNRCM(xw);
6372 		}
6373 	    }
6374 	    break;
6375 #if OPT_PRINT_GRAPHICS
6376 	case srm_DECGEPM:	/* Graphics Expanded Print Mode */
6377 	    set_bool_mode(screen->graphics_expanded_print_mode);
6378 	    break;
6379 #endif
6380 	case srm_MARGIN_BELL:	/* margin bell (xterm) also DECGPCM (Graphics Print Color Mode) */
6381 	    if_PRINT_GRAPHICS2(set_bool_mode(screen->graphics_print_color_mode)) {
6382 		set_bool_mode(screen->marginbell);
6383 		if (!screen->marginbell)
6384 		    screen->bellArmed = -1;
6385 		update_marginbell();
6386 	    }
6387 	    break;
6388 	case srm_REVERSEWRAP:	/* reverse wraparound (xterm) also DECGPCS (Graphics Print Color Syntax) */
6389 	    if_PRINT_GRAPHICS2(set_bool_mode(screen->graphics_print_color_syntax)) {
6390 		(*func) (&xw->flags, REVERSEWRAP);
6391 		update_reversewrap();
6392 	    }
6393 	    break;
6394 #ifdef ALLOWLOGGING
6395 	case srm_ALLOWLOGGING:	/* logging (xterm) also DECGPBM (Graphics Print Background Mode) */
6396 	    if_PRINT_GRAPHICS2(set_bool_mode(screen->graphics_print_background_mode)) {
6397 #ifdef ALLOWLOGFILEONOFF
6398 		/*
6399 		 * if this feature is enabled, logging may be
6400 		 * enabled and disabled via escape sequences.
6401 		 */
6402 		if (IsSM())
6403 		    StartLog(xw);
6404 		else
6405 		    CloseLog(xw);
6406 #else
6407 		Bell(xw, XkbBI_Info, 0);
6408 		Bell(xw, XkbBI_Info, 0);
6409 #endif /* ALLOWLOGFILEONOFF */
6410 	    }
6411 	    break;
6412 #elif OPT_PRINT_GRAPHICS
6413 	case srm_DECGPBM:	/* Graphics Print Background Mode */
6414 	    set_bool_mode(screen->graphics_print_background_mode);
6415 	    break;
6416 #endif /* ALLOWLOGGING */
6417 	case srm_OPT_ALTBUF_CURSOR:	/* optional alternate buffer and clear (xterm) */
6418 	    if (!xw->misc.titeInhibit) {
6419 		if (IsSM()) {
6420 		    CursorSave(xw);
6421 		    ToAlternate(xw, True);
6422 		    ClearScreen(xw);
6423 		} else {
6424 		    FromAlternate(xw);
6425 		    CursorRestore(xw);
6426 		}
6427 	    } else if (IsSM()) {
6428 		do_ti_xtra_scroll(xw);
6429 	    }
6430 	    break;
6431 	case srm_OPT_ALTBUF:	/* optional alternate buffer and clear (xterm) */
6432 	    if (!xw->misc.titeInhibit) {
6433 		if (IsSM()) {
6434 		    ToAlternate(xw, False);
6435 		} else {
6436 		    if (screen->whichBuf)
6437 			ClearScreen(xw);
6438 		    FromAlternate(xw);
6439 		}
6440 	    } else if (IsSM()) {
6441 		do_ti_xtra_scroll(xw);
6442 	    }
6443 	    break;
6444 	case srm_ALTBUF:	/* alternate buffer (xterm) also DECGRPM (Graphics Rotated Print Mode) */
6445 	    if_PRINT_GRAPHICS2(set_bool_mode(screen->graphics_rotated_print_mode)) {
6446 		if (!xw->misc.titeInhibit) {
6447 		    if (IsSM()) {
6448 			ToAlternate(xw, False);
6449 		    } else {
6450 			FromAlternate(xw);
6451 		    }
6452 		} else if (IsSM()) {
6453 		    do_ti_xtra_scroll(xw);
6454 		}
6455 	    }
6456 	    break;
6457 	case srm_DECNKM:
6458 	    (*func) (&xw->keyboard.flags, MODE_DECKPAM);
6459 	    update_appkeypad();
6460 	    break;
6461 	case srm_DECBKM:
6462 	    /* back-arrow mapped to backspace or delete(D) */
6463 	    (*func) (&xw->keyboard.flags, MODE_DECBKM);
6464 	    TRACE(("DECSET DECBKM %s\n",
6465 		   BtoS(xw->keyboard.flags & MODE_DECBKM)));
6466 	    update_decbkm();
6467 	    break;
6468 	case srm_DECLRMM:
6469 	    if (screen->vtXX_level >= 4) {	/* VT420 */
6470 		(*func) (&xw->flags, LEFT_RIGHT);
6471 		set_left_right_margin_mode(xw);
6472 	    }
6473 	    break;
6474 #if OPT_SIXEL_GRAPHICS
6475 	case srm_DECSDM:	/* sixel scrolling */
6476 	    if (optSixelGraphics(screen)) {	/* FIXME: VT24x did not scroll sixel graphics */
6477 		(*func) (&xw->keyboard.flags, MODE_DECSDM);
6478 		TRACE(("DECSET/DECRST DECSDM %s (resource default is %d)\n",
6479 		       BtoS(xw->keyboard.flags & MODE_DECSDM),
6480 		       TScreenOf(xw)->sixel_scrolling));
6481 		update_decsdm();
6482 	    }
6483 	    break;
6484 #endif
6485 	case srm_DECNCSM:
6486 	    if (screen->vtXX_level >= 5) {	/* VT510 */
6487 		(*func) (&xw->flags, NOCLEAR_COLM);
6488 	    }
6489 	    break;
6490 	case srm_VT200_MOUSE:	/* xterm bogus sequence         */
6491 	    MotionOff(screen, xw);
6492 	    set_mousemode(VT200_MOUSE);
6493 	    break;
6494 	case srm_VT200_HIGHLIGHT_MOUSE:	/* xterm sequence w/hilite tracking */
6495 	    MotionOff(screen, xw);
6496 	    set_mousemode(VT200_HIGHLIGHT_MOUSE);
6497 	    break;
6498 	case srm_BTN_EVENT_MOUSE:
6499 	    MotionOff(screen, xw);
6500 	    set_mousemode(BTN_EVENT_MOUSE);
6501 	    break;
6502 	case srm_ANY_EVENT_MOUSE:
6503 	    set_mousemode(ANY_EVENT_MOUSE);
6504 	    if (screen->send_mouse_pos == MOUSE_OFF) {
6505 		MotionOff(screen, xw);
6506 	    } else {
6507 		MotionOn(screen, xw);
6508 	    }
6509 	    break;
6510 #if OPT_FOCUS_EVENT
6511 	case srm_FOCUS_EVENT_MOUSE:
6512 	    set_bool_mode(screen->send_focus_pos);
6513 	    break;
6514 #endif
6515 	case srm_EXT_MODE_MOUSE:
6516 	    /* FALLTHRU */
6517 	case srm_SGR_EXT_MODE_MOUSE:
6518 	    /* FALLTHRU */
6519 	case srm_URXVT_EXT_MODE_MOUSE:
6520 	    /* FALLTHRU */
6521 	case srm_PIXEL_POSITION_MOUSE:
6522 	    /*
6523 	     * Rather than choose an arbitrary precedence among the coordinate
6524 	     * modes, they are mutually exclusive.  For consistency, a reset is
6525 	     * only effective against the matching mode.
6526 	     */
6527 	    if (IsSM()) {
6528 		screen->extend_coords = code;
6529 	    } else if (screen->extend_coords == code) {
6530 		screen->extend_coords = 0;
6531 	    }
6532 	    break;
6533 	case srm_ALTERNATE_SCROLL:
6534 	    set_bool_mode(screen->alternateScroll);
6535 	    break;
6536 	case srm_RXVT_SCROLL_TTY_OUTPUT:
6537 	    set_bool_mode(screen->scrollttyoutput);
6538 	    update_scrollttyoutput();
6539 	    break;
6540 	case srm_RXVT_SCROLL_TTY_KEYPRESS:
6541 	    set_bool_mode(screen->scrollkey);
6542 	    update_scrollkey();
6543 	    break;
6544 	case srm_EIGHT_BIT_META:
6545 	    if (screen->eight_bit_meta != ebNever) {
6546 		set_bool_mode(screen->eight_bit_meta);
6547 	    }
6548 	    break;
6549 #if OPT_NUM_LOCK
6550 	case srm_REAL_NUMLOCK:
6551 	    set_bool_mode(xw->misc.real_NumLock);
6552 	    update_num_lock();
6553 	    break;
6554 	case srm_META_SENDS_ESC:
6555 	    set_bool_mode(screen->meta_sends_esc);
6556 	    update_meta_esc();
6557 	    break;
6558 #endif
6559 	case srm_DELETE_IS_DEL:
6560 	    set_bool_mode(screen->delete_is_del);
6561 	    update_delete_del();
6562 	    break;
6563 #if OPT_NUM_LOCK
6564 	case srm_ALT_SENDS_ESC:
6565 	    set_bool_mode(screen->alt_sends_esc);
6566 	    update_alt_esc();
6567 	    break;
6568 #endif
6569 	case srm_KEEP_SELECTION:
6570 	    set_bool_mode(screen->keepSelection);
6571 	    update_keepSelection();
6572 	    break;
6573 	case srm_SELECT_TO_CLIPBOARD:
6574 	    set_bool_mode(screen->selectToClipboard);
6575 	    update_selectToClipboard();
6576 	    break;
6577 	case srm_BELL_IS_URGENT:
6578 	    set_bool_mode(screen->bellIsUrgent);
6579 	    update_bellIsUrgent();
6580 	    break;
6581 	case srm_POP_ON_BELL:
6582 	    set_bool_mode(screen->poponbell);
6583 	    update_poponbell();
6584 	    break;
6585 	case srm_KEEP_CLIPBOARD:
6586 	    set_bool_mode(screen->keepClipboard);
6587 	    update_keepClipboard();
6588 	    break;
6589 	case srm_ALLOW_ALTBUF:
6590 	    if (IsSM()) {
6591 		xw->misc.titeInhibit = False;
6592 	    } else if (!xw->misc.titeInhibit) {
6593 		xw->misc.titeInhibit = True;
6594 		FromAlternate(xw);
6595 	    }
6596 	    update_titeInhibit();
6597 	    break;
6598 	case srm_SAVE_CURSOR:
6599 	    if (!xw->misc.titeInhibit) {
6600 		if (IsSM())
6601 		    CursorSave(xw);
6602 		else
6603 		    CursorRestore(xw);
6604 	    }
6605 	    break;
6606 #if OPT_TCAP_FKEYS
6607 	case srm_TCAP_FKEYS:
6608 	    set_keyboard_type(xw, keyboardIsTermcap, IsSM());
6609 	    break;
6610 #endif
6611 #if OPT_SUN_FUNC_KEYS
6612 	case srm_SUN_FKEYS:
6613 	    set_keyboard_type(xw, keyboardIsSun, IsSM());
6614 	    break;
6615 #endif
6616 #if OPT_HP_FUNC_KEYS
6617 	case srm_HP_FKEYS:
6618 	    set_keyboard_type(xw, keyboardIsHP, IsSM());
6619 	    break;
6620 #endif
6621 #if OPT_SCO_FUNC_KEYS
6622 	case srm_SCO_FKEYS:
6623 	    set_keyboard_type(xw, keyboardIsSCO, IsSM());
6624 	    break;
6625 #endif
6626 	case srm_LEGACY_FKEYS:
6627 	    set_keyboard_type(xw, keyboardIsLegacy, IsSM());
6628 	    break;
6629 #if OPT_SUNPC_KBD
6630 	case srm_VT220_FKEYS:
6631 	    set_keyboard_type(xw, keyboardIsVT220, IsSM());
6632 	    break;
6633 #endif
6634 #if OPT_PASTE64 || OPT_READLINE
6635 	case srm_PASTE_IN_BRACKET:
6636 	    set_mouseflag(paste_brackets);
6637 	    break;
6638 #endif
6639 #if OPT_READLINE
6640 	case srm_BUTTON1_MOVE_POINT:
6641 	    set_mouseflag(click1_moves);
6642 	    break;
6643 	case srm_BUTTON2_MOVE_POINT:
6644 	    set_mouseflag(paste_moves);
6645 	    break;
6646 	case srm_DBUTTON3_DELETE:
6647 	    set_mouseflag(dclick3_deletes);
6648 	    break;
6649 	case srm_PASTE_QUOTE:
6650 	    set_mouseflag(paste_quotes);
6651 	    break;
6652 	case srm_PASTE_LITERAL_NL:
6653 	    set_mouseflag(paste_literal_nl);
6654 	    break;
6655 #endif /* OPT_READLINE */
6656 #if OPT_GRAPHICS
6657 	case srm_PRIVATE_COLOR_REGISTERS:	/* private color registers for each graphic */
6658 	    TRACE(("DECSET/DECRST PRIVATE_COLOR_REGISTERS to %s (resource default is %s)\n",
6659 		   BtoS(screen->privatecolorregisters),
6660 		   BtoS(TScreenOf(xw)->privatecolorregisters)));
6661 	    set_bool_mode(screen->privatecolorregisters);
6662 	    update_privatecolorregisters();
6663 	    break;
6664 #endif
6665 #if OPT_SIXEL_GRAPHICS
6666 	case srm_SIXEL_SCROLLS_RIGHT:	/* sixel scrolling moves cursor to right */
6667 	    if (optSixelGraphics(screen)) {	/* FIXME: VT24x did not scroll sixel graphics */
6668 		set_bool_mode(screen->sixel_scrolls_right);
6669 		TRACE(("DECSET/DECRST SIXEL_SCROLLS_RIGHT to %s (resource default is %s)\n",
6670 		       BtoS(screen->sixel_scrolls_right),
6671 		       BtoS(TScreenOf(xw)->sixel_scrolls_right)));
6672 	    }
6673 	    break;
6674 #endif
6675 	default:
6676 	    TRACE(("DATA_ERROR: unknown private code %d\n", code));
6677 	    break;
6678 	}
6679     }
6680 }
6681 
6682 /*
6683  * process xterm private modes save
6684  */
6685 static void
savemodes(XtermWidget xw)6686 savemodes(XtermWidget xw)
6687 {
6688     TScreen *screen = TScreenOf(xw);
6689     int i;
6690 
6691     for (i = 0; i < nparam; i++) {
6692 	int code = GetParam(i);
6693 
6694 	TRACE(("savemodes %d\n", code));
6695 	switch ((DECSET_codes) code) {
6696 	case srm_DECCKM:
6697 	    DoSM(DP_DECCKM, xw->keyboard.flags & MODE_DECCKM);
6698 	    break;
6699 	case srm_DECANM:	/* ANSI/VT52 mode      */
6700 	    /* no effect */
6701 	    break;
6702 	case srm_DECCOLM:
6703 	    if (screen->c132)
6704 		DoSM(DP_DECCOLM, xw->flags & IN132COLUMNS);
6705 	    break;
6706 	case srm_DECSCLM:	/* (slow scroll)        */
6707 	    DoSM(DP_DECSCLM, xw->flags & SMOOTHSCROLL);
6708 	    break;
6709 	case srm_DECSCNM:
6710 	    DoSM(DP_DECSCNM, xw->flags & REVERSE_VIDEO);
6711 	    break;
6712 	case srm_DECOM:
6713 	    DoSM(DP_DECOM, xw->flags & ORIGIN);
6714 	    break;
6715 	case srm_DECAWM:
6716 	    DoSM(DP_DECAWM, xw->flags & WRAPAROUND);
6717 	    break;
6718 	case srm_DECARM:
6719 	    /* ignore autorepeat */
6720 	    break;
6721 	case srm_X10_MOUSE:	/* mouse bogus sequence */
6722 	    DoSM(DP_X_X10MSE, screen->send_mouse_pos);
6723 	    break;
6724 #if OPT_TOOLBAR
6725 	case srm_RXVT_TOOLBAR:
6726 	    DoSM(DP_TOOLBAR, resource.toolBar);
6727 	    break;
6728 #endif
6729 #if OPT_BLINK_CURS
6730 	case srm_ATT610_BLINK:	/* AT&T 610: Start/stop blinking cursor */
6731 	    if (SettableCursorBlink(screen)) {
6732 		DoSM(DP_CRS_BLINK, screen->cursor_blink_esc);
6733 	    }
6734 	    break;
6735 	case srm_CURSOR_BLINK_OPS:
6736 	    /* intentionally ignored (this is user-preference) */
6737 	    break;
6738 	case srm_XOR_CURSOR_BLINKS:
6739 	    /* intentionally ignored (this is user-preference) */
6740 	    break;
6741 #endif
6742 	case srm_DECPFF:	/* print form feed */
6743 	    DoSM(DP_PRN_FORMFEED, PrinterOf(screen).printer_formfeed);
6744 	    break;
6745 	case srm_DECPEX:	/* print extent */
6746 	    DoSM(DP_PRN_EXTENT, PrinterOf(screen).printer_extent);
6747 	    break;
6748 	case srm_DECTCEM:	/* Show/hide cursor (VT200) */
6749 	    DoSM(DP_CRS_VISIBLE, screen->cursor_set);
6750 	    break;
6751 	case srm_RXVT_SCROLLBAR:
6752 	    DoSM(DP_RXVT_SCROLLBAR, (screen->fullVwin.sb_info.width != 0));
6753 	    break;
6754 #if OPT_SHIFT_FONTS
6755 	case srm_RXVT_FONTSIZE:
6756 	    DoSM(DP_RXVT_FONTSIZE, xw->misc.shift_fonts);
6757 	    break;
6758 #endif
6759 #if OPT_TEK4014
6760 	case srm_DECTEK:
6761 	    DoSM(DP_DECTEK, TEK4014_ACTIVE(xw));
6762 	    break;
6763 #endif
6764 	case srm_132COLS:	/* 132 column mode              */
6765 	    DoSM(DP_X_DECCOLM, screen->c132);
6766 	    break;
6767 	case srm_CURSES_HACK:	/* curses hack                  */
6768 	    DoSM(DP_X_MORE, screen->curses);
6769 	    break;
6770 	case srm_DECNRCM:	/* national charset (VT220) */
6771 	    if (screen->vtXX_level >= 2) {
6772 		DoSM(DP_DECNRCM, xw->flags & NATIONAL);
6773 	    }
6774 	    break;
6775 #if OPT_PRINT_GRAPHICS
6776 	case srm_DECGEPM:	/* Graphics Expanded Print Mode */
6777 	    DoSM(DP_DECGEPM, screen->graphics_expanded_print_mode);
6778 	    break;
6779 #endif
6780 	case srm_MARGIN_BELL:	/* margin bell (xterm) also DECGPCM (Graphics Print Color Mode) */
6781 	    if_PRINT_GRAPHICS2(DoSM(DP_DECGPCM, screen->graphics_print_color_mode)) {
6782 		DoSM(DP_X_MARGIN, screen->marginbell);
6783 	    }
6784 	    break;
6785 	case srm_REVERSEWRAP:	/* reverse wraparound (xterm) also DECGPCS (Graphics Print Color Syntax) */
6786 	    if_PRINT_GRAPHICS2(DoSM(DP_DECGPCS, screen->graphics_print_color_syntax)) {
6787 		DoSM(DP_X_REVWRAP, xw->flags & REVERSEWRAP);
6788 	    }
6789 	    break;
6790 #ifdef ALLOWLOGGING
6791 	case srm_ALLOWLOGGING:	/* logging (xterm) also DECGPBM (Graphics Print Background Mode) */
6792 	    if_PRINT_GRAPHICS2(DoSM(DP_DECGPBM, screen->graphics_print_background_mode)) {
6793 #ifdef ALLOWLOGFILEONOFF
6794 		DoSM(DP_X_LOGGING, screen->logging);
6795 #endif /* ALLOWLOGFILEONOFF */
6796 	    }
6797 	    break;
6798 #elif OPT_PRINT_GRAPHICS
6799 	case srm_DECGPBM:	/* Graphics Print Background Mode */
6800 	    DoSM(DP_DECGPBM, screen->graphics_print_background_mode);
6801 	    break;
6802 #endif /* ALLOWLOGGING */
6803 	case srm_OPT_ALTBUF_CURSOR:	/* optional alternate buffer and clear (xterm) */
6804 	    /* FALLTHRU */
6805 	case srm_OPT_ALTBUF:	/* optional alternate buffer and clear (xterm) */
6806 	    DoSM(DP_X_ALTBUF, screen->whichBuf);
6807 	    break;
6808 	case srm_ALTBUF:	/* alternate buffer (xterm) also DECGRPM (Graphics Rotated Print Mode) */
6809 	    if_PRINT_GRAPHICS2(DoSM(DP_DECGRPM, screen->graphics_rotated_print_mode)) {
6810 		DoSM(DP_X_ALTBUF, screen->whichBuf);
6811 	    }
6812 	    break;
6813 	case srm_DECNKM:
6814 	    DoSM(DP_DECKPAM, xw->keyboard.flags & MODE_DECKPAM);
6815 	    break;
6816 	case srm_DECBKM:	/* backarrow mapping */
6817 	    DoSM(DP_DECBKM, xw->keyboard.flags & MODE_DECBKM);
6818 	    break;
6819 	case srm_DECLRMM:	/* left-right */
6820 	    DoSM(DP_X_LRMM, LEFT_RIGHT);
6821 	    break;
6822 #if OPT_SIXEL_GRAPHICS
6823 	case srm_DECSDM:	/* sixel scrolling */
6824 	    DoSM(DP_DECSDM, xw->keyboard.flags & MODE_DECSDM);
6825 	    update_decsdm();
6826 	    break;
6827 #endif
6828 	case srm_DECNCSM:	/* noclear */
6829 	    DoSM(DP_X_NCSM, NOCLEAR_COLM);
6830 	    break;
6831 	case srm_VT200_MOUSE:	/* mouse bogus sequence         */
6832 	    /* FALLTHRU */
6833 	case srm_VT200_HIGHLIGHT_MOUSE:
6834 	    /* FALLTHRU */
6835 	case srm_BTN_EVENT_MOUSE:
6836 	    /* FALLTHRU */
6837 	case srm_ANY_EVENT_MOUSE:
6838 	    DoSM(DP_X_MOUSE, screen->send_mouse_pos);
6839 	    break;
6840 #if OPT_FOCUS_EVENT
6841 	case srm_FOCUS_EVENT_MOUSE:
6842 	    DoSM(DP_X_FOCUS, screen->send_focus_pos);
6843 	    break;
6844 #endif
6845 	case srm_EXT_MODE_MOUSE:
6846 	    /* FALLTHRU */
6847 	case srm_SGR_EXT_MODE_MOUSE:
6848 	    /* FALLTHRU */
6849 	case srm_URXVT_EXT_MODE_MOUSE:
6850 	    /* FALLTHRU */
6851 	case srm_PIXEL_POSITION_MOUSE:
6852 	    DoSM(DP_X_EXT_MOUSE, screen->extend_coords);
6853 	    break;
6854 	case srm_ALTERNATE_SCROLL:
6855 	    DoSM(DP_ALTERNATE_SCROLL, screen->alternateScroll);
6856 	    break;
6857 	case srm_RXVT_SCROLL_TTY_OUTPUT:
6858 	    DoSM(DP_RXVT_SCROLL_TTY_OUTPUT, screen->scrollttyoutput);
6859 	    break;
6860 	case srm_RXVT_SCROLL_TTY_KEYPRESS:
6861 	    DoSM(DP_RXVT_SCROLL_TTY_KEYPRESS, screen->scrollkey);
6862 	    break;
6863 	case srm_EIGHT_BIT_META:
6864 	    DoSM(DP_EIGHT_BIT_META, screen->eight_bit_meta);
6865 	    break;
6866 #if OPT_NUM_LOCK
6867 	case srm_REAL_NUMLOCK:
6868 	    DoSM(DP_REAL_NUMLOCK, xw->misc.real_NumLock);
6869 	    break;
6870 	case srm_META_SENDS_ESC:
6871 	    DoSM(DP_META_SENDS_ESC, screen->meta_sends_esc);
6872 	    break;
6873 #endif
6874 	case srm_DELETE_IS_DEL:
6875 	    DoSM(DP_DELETE_IS_DEL, screen->delete_is_del);
6876 	    break;
6877 #if OPT_NUM_LOCK
6878 	case srm_ALT_SENDS_ESC:
6879 	    DoSM(DP_ALT_SENDS_ESC, screen->alt_sends_esc);
6880 	    break;
6881 #endif
6882 	case srm_KEEP_SELECTION:
6883 	    DoSM(DP_KEEP_SELECTION, screen->keepSelection);
6884 	    break;
6885 	case srm_SELECT_TO_CLIPBOARD:
6886 	    DoSM(DP_SELECT_TO_CLIPBOARD, screen->selectToClipboard);
6887 	    break;
6888 	case srm_BELL_IS_URGENT:
6889 	    DoSM(DP_BELL_IS_URGENT, screen->bellIsUrgent);
6890 	    break;
6891 	case srm_POP_ON_BELL:
6892 	    DoSM(DP_POP_ON_BELL, screen->poponbell);
6893 	    break;
6894 	case srm_KEEP_CLIPBOARD:
6895 	    DoSM(DP_KEEP_CLIPBOARD, screen->keepClipboard);
6896 	    break;
6897 #if OPT_TCAP_FKEYS
6898 	case srm_TCAP_FKEYS:
6899 	    /* FALLTHRU */
6900 #endif
6901 #if OPT_SUN_FUNC_KEYS
6902 	case srm_SUN_FKEYS:
6903 	    /* FALLTHRU */
6904 #endif
6905 #if OPT_HP_FUNC_KEYS
6906 	case srm_HP_FKEYS:
6907 	    /* FALLTHRU */
6908 #endif
6909 #if OPT_SCO_FUNC_KEYS
6910 	case srm_SCO_FKEYS:
6911 	    /* FALLTHRU */
6912 #endif
6913 #if OPT_SUNPC_KBD
6914 	case srm_VT220_FKEYS:
6915 	    /* FALLTHRU */
6916 #endif
6917 	case srm_LEGACY_FKEYS:
6918 	    DoSM(DP_KEYBOARD_TYPE, xw->keyboard.type);
6919 	    break;
6920 	case srm_ALLOW_ALTBUF:
6921 	    DoSM(DP_ALLOW_ALTBUF, xw->misc.titeInhibit);
6922 	    break;
6923 	case srm_SAVE_CURSOR:
6924 	    if (!xw->misc.titeInhibit) {
6925 		CursorSave(xw);
6926 	    }
6927 	    break;
6928 #if OPT_PASTE64 || OPT_READLINE
6929 	case srm_PASTE_IN_BRACKET:
6930 	    SCREEN_FLAG_save(screen, paste_brackets);
6931 	    break;
6932 #endif
6933 #if OPT_READLINE
6934 	case srm_BUTTON1_MOVE_POINT:
6935 	    SCREEN_FLAG_save(screen, click1_moves);
6936 	    break;
6937 	case srm_BUTTON2_MOVE_POINT:
6938 	    SCREEN_FLAG_save(screen, paste_moves);
6939 	    break;
6940 	case srm_DBUTTON3_DELETE:
6941 	    SCREEN_FLAG_save(screen, dclick3_deletes);
6942 	    break;
6943 	case srm_PASTE_QUOTE:
6944 	    SCREEN_FLAG_save(screen, paste_quotes);
6945 	    break;
6946 	case srm_PASTE_LITERAL_NL:
6947 	    SCREEN_FLAG_save(screen, paste_literal_nl);
6948 	    break;
6949 #endif /* OPT_READLINE */
6950 #if OPT_GRAPHICS
6951 	case srm_PRIVATE_COLOR_REGISTERS:	/* private color registers for each graphic */
6952 	    TRACE(("save PRIVATE_COLOR_REGISTERS %s\n",
6953 		   BtoS(screen->privatecolorregisters)));
6954 	    DoSM(DP_X_PRIVATE_COLOR_REGISTERS, screen->privatecolorregisters);
6955 	    update_privatecolorregisters();
6956 	    break;
6957 #endif
6958 #if OPT_SIXEL_GRAPHICS
6959 	case srm_SIXEL_SCROLLS_RIGHT:
6960 	    TRACE(("save SIXEL_SCROLLS_RIGHT %s\n",
6961 		   BtoS(screen->sixel_scrolls_right)));
6962 	    DoSM(DP_SIXEL_SCROLLS_RIGHT, screen->sixel_scrolls_right);
6963 	    break;
6964 #endif
6965 	}
6966     }
6967 }
6968 
6969 /*
6970  * process xterm private modes restore
6971  */
6972 static void
restoremodes(XtermWidget xw)6973 restoremodes(XtermWidget xw)
6974 {
6975     TScreen *screen = TScreenOf(xw);
6976     int i, j;
6977 
6978     for (i = 0; i < nparam; i++) {
6979 	int code = GetParam(i);
6980 
6981 	TRACE(("restoremodes %d\n", code));
6982 	switch ((DECSET_codes) code) {
6983 	case srm_DECCKM:
6984 	    bitcpy(&xw->keyboard.flags,
6985 		   screen->save_modes[DP_DECCKM], MODE_DECCKM);
6986 	    update_appcursor();
6987 	    break;
6988 	case srm_DECANM:	/* ANSI/VT52 mode      */
6989 	    /* no effect */
6990 	    break;
6991 	case srm_DECCOLM:
6992 	    if (screen->c132) {
6993 		if (!(xw->flags & NOCLEAR_COLM))
6994 		    ClearScreen(xw);
6995 		CursorSet(screen, 0, 0, xw->flags);
6996 		if ((j = (screen->save_modes[DP_DECCOLM] & IN132COLUMNS)
6997 		     ? 132 : 80) != ((xw->flags & IN132COLUMNS)
6998 				     ? 132 : 80) || j != MaxCols(screen))
6999 		    RequestResize(xw, -1, j, True);
7000 		bitcpy(&xw->flags,
7001 		       screen->save_modes[DP_DECCOLM],
7002 		       IN132COLUMNS);
7003 	    }
7004 	    break;
7005 	case srm_DECSCLM:	/* (slow scroll)        */
7006 	    if (screen->save_modes[DP_DECSCLM] & SMOOTHSCROLL) {
7007 		screen->jumpscroll = 0;
7008 		if (screen->scroll_amt)
7009 		    FlushScroll(xw);
7010 	    } else
7011 		screen->jumpscroll = 1;
7012 	    bitcpy(&xw->flags, screen->save_modes[DP_DECSCLM], SMOOTHSCROLL);
7013 	    update_jumpscroll();
7014 	    break;
7015 	case srm_DECSCNM:
7016 	    if ((screen->save_modes[DP_DECSCNM] ^ xw->flags) & REVERSE_VIDEO) {
7017 		bitcpy(&xw->flags, screen->save_modes[DP_DECSCNM], REVERSE_VIDEO);
7018 		ReverseVideo(xw);
7019 		/* update_reversevideo done in RevVid */
7020 	    }
7021 	    break;
7022 	case srm_DECOM:
7023 	    bitcpy(&xw->flags, screen->save_modes[DP_DECOM], ORIGIN);
7024 	    CursorSet(screen, 0, 0, xw->flags);
7025 	    break;
7026 
7027 	case srm_DECAWM:
7028 	    bitcpy(&xw->flags, screen->save_modes[DP_DECAWM], WRAPAROUND);
7029 	    update_autowrap();
7030 	    break;
7031 	case srm_DECARM:
7032 	    /* ignore autorepeat */
7033 	    break;
7034 	case srm_X10_MOUSE:	/* MIT bogus sequence           */
7035 	    DoRM0(DP_X_X10MSE, screen->send_mouse_pos);
7036 	    really_set_mousemode(xw,
7037 				 screen->send_mouse_pos != MOUSE_OFF,
7038 				 (XtermMouseModes) screen->send_mouse_pos);
7039 	    break;
7040 #if OPT_TOOLBAR
7041 	case srm_RXVT_TOOLBAR:
7042 	    DoRM(DP_TOOLBAR, resource.toolBar);
7043 	    ShowToolbar(resource.toolBar);
7044 	    break;
7045 #endif
7046 #if OPT_BLINK_CURS
7047 	case srm_ATT610_BLINK:	/* Start/stop blinking cursor */
7048 	    if (SettableCursorBlink(screen)) {
7049 		DoRM(DP_CRS_BLINK, screen->cursor_blink_esc);
7050 		UpdateCursorBlink(xw);
7051 	    }
7052 	    break;
7053 	case srm_CURSOR_BLINK_OPS:
7054 	    /* intentionally ignored (this is user-preference) */
7055 	    break;
7056 	case srm_XOR_CURSOR_BLINKS:
7057 	    /* intentionally ignored (this is user-preference) */
7058 	    break;
7059 #endif
7060 	case srm_DECPFF:	/* print form feed */
7061 	    DoRM(DP_PRN_FORMFEED, PrinterOf(screen).printer_formfeed);
7062 	    break;
7063 	case srm_DECPEX:	/* print extent */
7064 	    DoRM(DP_PRN_EXTENT, PrinterOf(screen).printer_extent);
7065 	    break;
7066 	case srm_DECTCEM:	/* Show/hide cursor (VT200) */
7067 	    DoRM(DP_CRS_VISIBLE, screen->cursor_set);
7068 	    updateCursor(xw);
7069 	    break;
7070 	case srm_RXVT_SCROLLBAR:
7071 	    if ((screen->fullVwin.sb_info.width != 0) !=
7072 		screen->save_modes[DP_RXVT_SCROLLBAR]) {
7073 		ToggleScrollBar(xw);
7074 	    }
7075 	    break;
7076 #if OPT_SHIFT_FONTS
7077 	case srm_RXVT_FONTSIZE:
7078 	    DoRM(DP_RXVT_FONTSIZE, xw->misc.shift_fonts);
7079 	    break;
7080 #endif
7081 #if OPT_TEK4014
7082 	case srm_DECTEK:
7083 	    if (!(screen->inhibit & I_TEK) &&
7084 		(TEK4014_ACTIVE(xw) != (Boolean) screen->save_modes[DP_DECTEK])) {
7085 		FlushLog(xw);
7086 		TEK4014_ACTIVE(xw) = (Boolean) screen->save_modes[DP_DECTEK];
7087 		update_vttekmode();
7088 	    }
7089 	    break;
7090 #endif
7091 	case srm_132COLS:	/* 132 column mode              */
7092 	    DoRM(DP_X_DECCOLM, screen->c132);
7093 	    update_allow132();
7094 	    break;
7095 	case srm_CURSES_HACK:	/* curses hack                  */
7096 	    DoRM(DP_X_MORE, screen->curses);
7097 	    update_cursesemul();
7098 	    break;
7099 	case srm_DECNRCM:	/* national charset (VT220) */
7100 	    if (screen->vtXX_level >= 2) {
7101 		if (bitcpy(&xw->flags, screen->save_modes[DP_DECNRCM], NATIONAL))
7102 		    modified_DECNRCM(xw);
7103 	    }
7104 	    break;
7105 #if OPT_PRINT_GRAPHICS
7106 	case srm_DECGEPM:	/* Graphics Expanded Print Mode */
7107 	    DoRM(DP_DECGEPM, screen->graphics_expanded_print_mode);
7108 	    break;
7109 #endif
7110 	case srm_MARGIN_BELL:	/* margin bell (xterm) also DECGPCM (Graphics Print Color Mode) */
7111 	    if_PRINT_GRAPHICS2(DoRM(DP_DECGPCM, screen->graphics_print_color_mode)) {
7112 		if ((DoRM(DP_X_MARGIN, screen->marginbell)) == 0)
7113 		    screen->bellArmed = -1;
7114 		update_marginbell();
7115 	    }
7116 	    break;
7117 	case srm_REVERSEWRAP:	/* reverse wraparound (xterm) also DECGPCS (Graphics Print Color Syntax) */
7118 	    if_PRINT_GRAPHICS2(DoRM(DP_DECGPCS, screen->graphics_print_color_syntax)) {
7119 		bitcpy(&xw->flags, screen->save_modes[DP_X_REVWRAP], REVERSEWRAP);
7120 		update_reversewrap();
7121 	    }
7122 	    break;
7123 #ifdef ALLOWLOGGING
7124 	case srm_ALLOWLOGGING:	/* logging (xterm) also DECGPBM (Graphics Print Background Mode) */
7125 	    if_PRINT_GRAPHICS2(DoRM(DP_DECGPBM, screen->graphics_print_background_mode)) {
7126 #ifdef ALLOWLOGFILEONOFF
7127 		if (screen->save_modes[DP_X_LOGGING])
7128 		    StartLog(xw);
7129 		else
7130 		    CloseLog(xw);
7131 #endif /* ALLOWLOGFILEONOFF */
7132 		/* update_logging done by StartLog and CloseLog */
7133 	    }
7134 	    break;
7135 #elif OPT_PRINT_GRAPHICS
7136 	case srm_DECGPBM:	/* Graphics Print Background Mode */
7137 	    DoRM(DP_DECGPBM, screen->graphics_print_background_mode);
7138 	    break;
7139 #endif /* ALLOWLOGGING */
7140 	case srm_OPT_ALTBUF_CURSOR:	/* optional alternate buffer and clear (xterm) */
7141 	    /* FALLTHRU */
7142 	case srm_OPT_ALTBUF:	/* optional alternate buffer and clear (xterm) */
7143 	    if (!xw->misc.titeInhibit) {
7144 		if (screen->save_modes[DP_X_ALTBUF])
7145 		    ToAlternate(xw, False);
7146 		else
7147 		    FromAlternate(xw);
7148 		/* update_altscreen done by ToAlt and FromAlt */
7149 	    } else if (screen->save_modes[DP_X_ALTBUF]) {
7150 		do_ti_xtra_scroll(xw);
7151 	    }
7152 	    break;
7153 	case srm_ALTBUF:	/* alternate buffer (xterm) also DECGRPM (Graphics Rotated Print Mode) */
7154 	    if_PRINT_GRAPHICS2(DoRM(DP_DECGRPM, screen->graphics_rotated_print_mode)) {
7155 		if (!xw->misc.titeInhibit) {
7156 		    if (screen->save_modes[DP_X_ALTBUF])
7157 			ToAlternate(xw, False);
7158 		    else
7159 			FromAlternate(xw);
7160 		    /* update_altscreen done by ToAlt and FromAlt */
7161 		} else if (screen->save_modes[DP_X_ALTBUF]) {
7162 		    do_ti_xtra_scroll(xw);
7163 		}
7164 	    }
7165 	    break;
7166 	case srm_DECNKM:
7167 	    bitcpy(&xw->flags, screen->save_modes[DP_DECKPAM], MODE_DECKPAM);
7168 	    update_appkeypad();
7169 	    break;
7170 	case srm_DECBKM:	/* backarrow mapping */
7171 	    bitcpy(&xw->flags, screen->save_modes[DP_DECBKM], MODE_DECBKM);
7172 	    update_decbkm();
7173 	    break;
7174 	case srm_DECLRMM:	/* left-right */
7175 	    bitcpy(&xw->flags, screen->save_modes[DP_X_LRMM], LEFT_RIGHT);
7176 	    if (IsLeftRightMode(xw)) {
7177 		xterm_ResetDouble(xw);
7178 	    } else {
7179 		reset_lr_margins(screen);
7180 	    }
7181 	    break;
7182 #if OPT_SIXEL_GRAPHICS
7183 	case srm_DECSDM:	/* sixel scrolling */
7184 	    bitcpy(&xw->keyboard.flags, screen->save_modes[DP_DECSDM], MODE_DECSDM);
7185 	    update_decsdm();
7186 	    break;
7187 #endif
7188 	case srm_DECNCSM:	/* noclear */
7189 	    bitcpy(&xw->flags, screen->save_modes[DP_X_NCSM], NOCLEAR_COLM);
7190 	    break;
7191 	case srm_VT200_MOUSE:	/* mouse bogus sequence         */
7192 	    /* FALLTHRU */
7193 	case srm_VT200_HIGHLIGHT_MOUSE:
7194 	    /* FALLTHRU */
7195 	case srm_BTN_EVENT_MOUSE:
7196 	    /* FALLTHRU */
7197 	case srm_ANY_EVENT_MOUSE:
7198 	    DoRM0(DP_X_MOUSE, screen->send_mouse_pos);
7199 	    really_set_mousemode(xw,
7200 				 screen->send_mouse_pos != MOUSE_OFF,
7201 				 (XtermMouseModes) screen->send_mouse_pos);
7202 	    break;
7203 #if OPT_FOCUS_EVENT
7204 	case srm_FOCUS_EVENT_MOUSE:
7205 	    DoRM(DP_X_FOCUS, screen->send_focus_pos);
7206 	    break;
7207 #endif
7208 	case srm_EXT_MODE_MOUSE:
7209 	    /* FALLTHRU */
7210 	case srm_SGR_EXT_MODE_MOUSE:
7211 	    /* FALLTHRU */
7212 	case srm_URXVT_EXT_MODE_MOUSE:
7213 	    /* FALLTHRU */
7214 	case srm_PIXEL_POSITION_MOUSE:
7215 	    DoRM(DP_X_EXT_MOUSE, screen->extend_coords);
7216 	    break;
7217 	case srm_ALLOW_ALTBUF:
7218 	    DoRM(DP_ALLOW_ALTBUF, xw->misc.titeInhibit);
7219 	    if (xw->misc.titeInhibit)
7220 		FromAlternate(xw);
7221 	    update_titeInhibit();
7222 	    break;
7223 	case srm_SAVE_CURSOR:
7224 	    if (!xw->misc.titeInhibit) {
7225 		CursorRestore(xw);
7226 	    }
7227 	    break;
7228 	case srm_ALTERNATE_SCROLL:
7229 	    DoRM(DP_ALTERNATE_SCROLL, screen->alternateScroll);
7230 	    break;
7231 	case srm_RXVT_SCROLL_TTY_OUTPUT:
7232 	    DoRM(DP_RXVT_SCROLL_TTY_OUTPUT, screen->scrollttyoutput);
7233 	    update_scrollttyoutput();
7234 	    break;
7235 	case srm_RXVT_SCROLL_TTY_KEYPRESS:
7236 	    DoRM(DP_RXVT_SCROLL_TTY_KEYPRESS, screen->scrollkey);
7237 	    update_scrollkey();
7238 	    break;
7239 	case srm_EIGHT_BIT_META:
7240 	    DoRM(DP_EIGHT_BIT_META, screen->eight_bit_meta);
7241 	    break;
7242 #if OPT_NUM_LOCK
7243 	case srm_REAL_NUMLOCK:
7244 	    DoRM(DP_REAL_NUMLOCK, xw->misc.real_NumLock);
7245 	    update_num_lock();
7246 	    break;
7247 	case srm_META_SENDS_ESC:
7248 	    DoRM(DP_META_SENDS_ESC, screen->meta_sends_esc);
7249 	    update_meta_esc();
7250 	    break;
7251 #endif
7252 	case srm_DELETE_IS_DEL:
7253 	    DoRM(DP_DELETE_IS_DEL, screen->delete_is_del);
7254 	    update_delete_del();
7255 	    break;
7256 #if OPT_NUM_LOCK
7257 	case srm_ALT_SENDS_ESC:
7258 	    DoRM(DP_ALT_SENDS_ESC, screen->alt_sends_esc);
7259 	    update_alt_esc();
7260 	    break;
7261 #endif
7262 	case srm_KEEP_SELECTION:
7263 	    DoRM(DP_KEEP_SELECTION, screen->keepSelection);
7264 	    update_keepSelection();
7265 	    break;
7266 	case srm_SELECT_TO_CLIPBOARD:
7267 	    DoRM(DP_SELECT_TO_CLIPBOARD, screen->selectToClipboard);
7268 	    update_selectToClipboard();
7269 	    break;
7270 	case srm_BELL_IS_URGENT:
7271 	    DoRM(DP_BELL_IS_URGENT, screen->bellIsUrgent);
7272 	    update_bellIsUrgent();
7273 	    break;
7274 	case srm_POP_ON_BELL:
7275 	    DoRM(DP_POP_ON_BELL, screen->poponbell);
7276 	    update_poponbell();
7277 	    break;
7278 	case srm_KEEP_CLIPBOARD:
7279 	    DoRM(DP_KEEP_CLIPBOARD, screen->keepClipboard);
7280 	    update_keepClipboard();
7281 	    break;
7282 #if OPT_TCAP_FKEYS
7283 	case srm_TCAP_FKEYS:
7284 	    /* FALLTHRU */
7285 #endif
7286 #if OPT_SUN_FUNC_KEYS
7287 	case srm_SUN_FKEYS:
7288 	    /* FALLTHRU */
7289 #endif
7290 #if OPT_HP_FUNC_KEYS
7291 	case srm_HP_FKEYS:
7292 	    /* FALLTHRU */
7293 #endif
7294 #if OPT_SCO_FUNC_KEYS
7295 	case srm_SCO_FKEYS:
7296 	    /* FALLTHRU */
7297 #endif
7298 #if OPT_SUNPC_KBD
7299 	case srm_VT220_FKEYS:
7300 	    /* FALLTHRU */
7301 #endif
7302 	case srm_LEGACY_FKEYS:
7303 	    xw->keyboard.type = (xtermKeyboardType) screen->save_modes[DP_KEYBOARD_TYPE];
7304 	    break;
7305 #if OPT_PASTE64 || OPT_READLINE
7306 	case srm_PASTE_IN_BRACKET:
7307 	    SCREEN_FLAG_restore(screen, paste_brackets);
7308 	    break;
7309 #endif
7310 #if OPT_READLINE
7311 	case srm_BUTTON1_MOVE_POINT:
7312 	    SCREEN_FLAG_restore(screen, click1_moves);
7313 	    break;
7314 	case srm_BUTTON2_MOVE_POINT:
7315 	    SCREEN_FLAG_restore(screen, paste_moves);
7316 	    break;
7317 	case srm_DBUTTON3_DELETE:
7318 	    SCREEN_FLAG_restore(screen, dclick3_deletes);
7319 	    break;
7320 	case srm_PASTE_QUOTE:
7321 	    SCREEN_FLAG_restore(screen, paste_quotes);
7322 	    break;
7323 	case srm_PASTE_LITERAL_NL:
7324 	    SCREEN_FLAG_restore(screen, paste_literal_nl);
7325 	    break;
7326 #endif /* OPT_READLINE */
7327 #if OPT_GRAPHICS
7328 	case srm_PRIVATE_COLOR_REGISTERS:	/* private color registers for each graphic */
7329 	    TRACE(("restore PRIVATE_COLOR_REGISTERS before: %s\n",
7330 		   BtoS(screen->privatecolorregisters)));
7331 	    DoRM(DP_X_PRIVATE_COLOR_REGISTERS, screen->privatecolorregisters);
7332 	    TRACE(("restore PRIVATE_COLOR_REGISTERS after: %s\n",
7333 		   BtoS(screen->privatecolorregisters)));
7334 	    update_privatecolorregisters();
7335 	    break;
7336 #endif
7337 #if OPT_SIXEL_GRAPHICS
7338 	case srm_SIXEL_SCROLLS_RIGHT:
7339 	    TRACE(("restore SIXEL_SCROLLS_RIGHT before: %s\n",
7340 		   BtoS(screen->sixel_scrolls_right)));
7341 	    DoRM(DP_SIXEL_SCROLLS_RIGHT, screen->sixel_scrolls_right);
7342 	    TRACE(("restore SIXEL_SCROLLS_RIGHT after: %s\n",
7343 		   BtoS(screen->sixel_scrolls_right)));
7344 	    break;
7345 #endif
7346 	}
7347     }
7348 }
7349 
7350 /*
7351  * Convert an XTextProperty to a string.
7352  *
7353  * This frees the data owned by the XTextProperty, and returns in its place the
7354  * string, which must be freed by the caller.
7355  */
7356 static char *
property_to_string(XtermWidget xw,XTextProperty * text)7357 property_to_string(XtermWidget xw, XTextProperty * text)
7358 {
7359     TScreen *screen = TScreenOf(xw);
7360     Display *dpy = screen->display;
7361     char *result = 0;
7362     char **list = NULL;
7363     int length = 0;
7364     int rc;
7365 
7366     TRACE(("property_to_string value %p, encoding %s, format %d, nitems %ld\n",
7367 	   text->value,
7368 	   TraceAtomName(dpy, text->encoding),
7369 	   text->format,
7370 	   text->nitems));
7371 
7372 #if OPT_WIDE_CHARS
7373     /*
7374      * We will use the XmbTextPropertyToTextList call to extract UTF-8 data.
7375      * The xtermUtf8ToTextList() call is used to convert UTF-8 explicitly to
7376      * ISO-8859-1.
7377      */
7378     rc = -1;
7379     if ((text->format != 8)
7380 	|| IsTitleMode(xw, tmGetUtf8)
7381 	|| (text->encoding == XA_UTF8_STRING(dpy) &&
7382 	    !(screen->wide_chars || screen->c1_printable) &&
7383 	    (rc = xtermUtf8ToTextList(xw, text, &list, &length)) < 0)
7384 	|| (rc < 0))
7385 #endif
7386 	if ((rc = XmbTextPropertyToTextList(dpy, text, &list, &length)) < 0)
7387 	    rc = XTextPropertyToStringList(text, &list, &length);
7388 
7389     if (rc >= 0) {
7390 	int n, c, pass;
7391 	size_t need;
7392 
7393 	for (pass = 0; pass < 2; ++pass) {
7394 	    for (n = 0, need = 0; n < length; n++) {
7395 		char *s = list[n];
7396 		while ((c = *s++) != '\0') {
7397 		    if (pass)
7398 			result[need] = (char) c;
7399 		    ++need;
7400 		}
7401 	    }
7402 	    if (pass)
7403 		result[need] = '\0';
7404 	    else
7405 		result = malloc(need + 1);
7406 	    if (result == 0)
7407 		break;
7408 	}
7409 	XFreeStringList(list);
7410     }
7411     if (text->value != 0)
7412 	XFree(text->value);
7413 
7414     return result;
7415 }
7416 
7417 static char *
get_icon_label(XtermWidget xw)7418 get_icon_label(XtermWidget xw)
7419 {
7420     XTextProperty text;
7421     char *result = 0;
7422 
7423     if (XGetWMIconName(TScreenOf(xw)->display, VShellWindow(xw), &text)) {
7424 	result = property_to_string(xw, &text);
7425     }
7426     return result;
7427 }
7428 
7429 static char *
get_window_label(XtermWidget xw)7430 get_window_label(XtermWidget xw)
7431 {
7432     XTextProperty text;
7433     char *result = 0;
7434 
7435     if (XGetWMName(TScreenOf(xw)->display, VShellWindow(xw), &text)) {
7436 	result = property_to_string(xw, &text);
7437     }
7438     return result;
7439 }
7440 
7441 /*
7442  * Report window label (icon or title) in dtterm protocol
7443  * ESC ] code label ESC backslash
7444  */
7445 static void
report_win_label(XtermWidget xw,int code,char * text)7446 report_win_label(XtermWidget xw,
7447 		 int code,
7448 		 char *text)
7449 {
7450     unparseputc(xw, ANSI_ESC);
7451     unparseputc(xw, ']');
7452     unparseputc(xw, code);
7453 
7454     if (text != 0) {
7455 	int copy = IsTitleMode(xw, tmGetBase16);
7456 	if (copy) {
7457 	    TRACE(("Encoding hex:%s\n", text));
7458 	    text = x_encode_hex(text);
7459 	}
7460 	unparseputs(xw, text);
7461 	if (copy)
7462 	    free(text);
7463     }
7464 
7465     unparseputc(xw, ANSI_ESC);
7466     unparseputc(xw, '\\');	/* should be ST */
7467     unparse_end(xw);
7468 }
7469 
7470 /*
7471  * Window operations (from CDE dtterm description, as well as extensions).
7472  * See also "allowWindowOps" resource.
7473  */
7474 static void
window_ops(XtermWidget xw)7475 window_ops(XtermWidget xw)
7476 {
7477     TScreen *screen = TScreenOf(xw);
7478     XWindowChanges values;
7479     XWindowAttributes win_attrs;
7480 #if OPT_MAXIMIZE
7481     unsigned root_width;
7482     unsigned root_height;
7483 #endif
7484     int code = zero_if_default(0);
7485     char *label;
7486 
7487     TRACE(("window_ops %d\n", code));
7488     switch (code) {
7489     case ewRestoreWin:		/* Restore (de-iconify) window */
7490 	if (AllowWindowOps(xw, ewRestoreWin)) {
7491 	    xtermDeiconify(xw);
7492 	}
7493 	break;
7494 
7495     case ewMinimizeWin:	/* Minimize (iconify) window */
7496 	if (AllowWindowOps(xw, ewMinimizeWin)) {
7497 	    xtermIconify(xw);
7498 	}
7499 	break;
7500 
7501     case ewSetWinPosition:	/* Move the window to the given position */
7502 	if (AllowWindowOps(xw, ewSetWinPosition)) {
7503 	    unsigned value_mask;
7504 
7505 	    values.x = (Position) zero_if_default(1);
7506 	    values.y = (Position) zero_if_default(2);
7507 	    TRACE(("...move window to %d,%d\n", values.x, values.y));
7508 	    value_mask = (CWX | CWY);
7509 	    XReconfigureWMWindow(screen->display,
7510 				 VShellWindow(xw),
7511 				 DefaultScreen(screen->display),
7512 				 value_mask,
7513 				 &values);
7514 	}
7515 	break;
7516 
7517     case ewSetWinSizePixels:	/* Resize the window to given size in pixels */
7518 	if (AllowWindowOps(xw, ewSetWinSizePixels)) {
7519 	    RequestResize(xw, optional_param(1), optional_param(2), False);
7520 	}
7521 	break;
7522 
7523     case ewRaiseWin:		/* Raise the window to the front of the stack */
7524 	if (AllowWindowOps(xw, ewRaiseWin)) {
7525 	    TRACE(("...raise window\n"));
7526 	    XRaiseWindow(screen->display, VShellWindow(xw));
7527 	}
7528 	break;
7529 
7530     case ewLowerWin:		/* Lower the window to the bottom of the stack */
7531 	if (AllowWindowOps(xw, ewLowerWin)) {
7532 	    TRACE(("...lower window\n"));
7533 	    XLowerWindow(screen->display, VShellWindow(xw));
7534 	}
7535 	break;
7536 
7537     case ewRefreshWin:		/* Refresh the window */
7538 	if (AllowWindowOps(xw, ewRefreshWin)) {
7539 	    TRACE(("...redraw window\n"));
7540 	    Redraw();
7541 	}
7542 	break;
7543 
7544     case ewSetWinSizeChars:	/* Resize the text-area, in characters */
7545 	if (AllowWindowOps(xw, ewSetWinSizeChars)) {
7546 	    RequestResize(xw, optional_param(1), optional_param(2), True);
7547 	}
7548 	break;
7549 
7550 #if OPT_MAXIMIZE
7551     case ewMaximizeWin:	/* Maximize or restore */
7552 	if (AllowWindowOps(xw, ewMaximizeWin)) {
7553 	    RequestMaximize(xw, zero_if_default(1));
7554 	}
7555 	break;
7556     case ewFullscreenWin:	/* Fullscreen or restore */
7557 	if (AllowWindowOps(xw, ewFullscreenWin)) {
7558 	    switch (zero_if_default(1)) {
7559 	    default:
7560 		RequestMaximize(xw, 0);
7561 		break;
7562 	    case 1:
7563 		RequestMaximize(xw, 1);
7564 		break;
7565 	    case 2:
7566 		RequestMaximize(xw, !(screen->restore_data));
7567 		break;
7568 	    }
7569 	}
7570 	break;
7571 #endif
7572 
7573     case ewGetWinState:	/* Report the window's state */
7574 	if (AllowWindowOps(xw, ewGetWinState)) {
7575 	    TRACE(("...get window attributes\n"));
7576 	    init_reply(ANSI_CSI);
7577 	    reply.a_pintro = 0;
7578 	    reply.a_nparam = 1;
7579 	    reply.a_param[0] = (ParmType) (xtermIsIconified(xw) ? 2 : 1);
7580 	    reply.a_inters = 0;
7581 	    reply.a_final = 't';
7582 	    unparseseq(xw, &reply);
7583 	}
7584 	break;
7585 
7586     case ewGetWinPosition:	/* Report the window's position */
7587 	if (AllowWindowOps(xw, ewGetWinPosition)) {
7588 	    Window win;
7589 	    Window result_win;
7590 	    int result_y, result_x;
7591 
7592 	    TRACE(("...get window position\n"));
7593 	    init_reply(ANSI_CSI);
7594 	    reply.a_pintro = 0;
7595 	    reply.a_nparam = 3;
7596 	    reply.a_param[0] = 3;
7597 	    switch (zero_if_default(1)) {
7598 	    case 2:		/* report the text-window's position */
7599 		result_y = 0;
7600 		result_x = 0;
7601 		{
7602 		    Widget mw;
7603 		    for (mw = (Widget) xw; mw != 0; mw = XtParent(mw)) {
7604 			result_x += mw->core.x;
7605 			result_y += mw->core.y;
7606 			if (mw == SHELL_OF(xw))
7607 			    break;
7608 		    }
7609 		}
7610 		result_x += OriginX(screen);
7611 		result_y += OriginY(screen);
7612 		break;
7613 	    default:
7614 		win = WMFrameWindow(xw);
7615 		xtermGetWinAttrs(screen->display,
7616 				 win,
7617 				 &win_attrs);
7618 		XTranslateCoordinates(screen->display,
7619 				      VShellWindow(xw),
7620 				      win_attrs.root,
7621 				      -win_attrs.border_width,
7622 				      -win_attrs.border_width,
7623 				      &result_x, &result_y, &result_win);
7624 		TRACE(("translated position %d,%d vs %d,%d\n",
7625 		       result_y, result_x,
7626 		       win_attrs.y, win_attrs.x));
7627 		if (!discount_frame_extents(xw, &result_y, &result_x)) {
7628 		    TRACE(("...cancelled translation\n"));
7629 		    result_y = win_attrs.y;
7630 		    result_x = win_attrs.x;
7631 		}
7632 		break;
7633 	    }
7634 	    reply.a_param[1] = (ParmType) result_x;
7635 	    reply.a_param[2] = (ParmType) result_y;
7636 	    reply.a_inters = 0;
7637 	    reply.a_final = 't';
7638 	    unparseseq(xw, &reply);
7639 	}
7640 	break;
7641 
7642     case ewGetWinSizePixels:	/* Report the window's size in pixels */
7643 	if (AllowWindowOps(xw, ewGetWinSizePixels)) {
7644 	    ParmType high = (ParmType) Height(screen);
7645 	    ParmType wide = (ParmType) Width(screen);
7646 
7647 	    TRACE(("...get window size in pixels\n"));
7648 	    init_reply(ANSI_CSI);
7649 	    reply.a_pintro = 0;
7650 	    reply.a_nparam = 3;
7651 	    reply.a_param[0] = 4;
7652 	    switch (zero_if_default(1)) {
7653 	    case 2:		/* report the shell-window's size */
7654 		xtermGetWinAttrs(screen->display,
7655 				 WMFrameWindow(xw),
7656 				 &win_attrs);
7657 		high = (ParmType) win_attrs.height;
7658 		wide = (ParmType) win_attrs.width;
7659 		/* FALLTHRU */
7660 	    default:
7661 		reply.a_param[1] = high;
7662 		reply.a_param[2] = wide;
7663 		break;
7664 	    }
7665 	    reply.a_inters = 0;
7666 	    reply.a_final = 't';
7667 	    unparseseq(xw, &reply);
7668 	}
7669 	break;
7670 
7671 #if OPT_MAXIMIZE
7672     case ewGetScreenSizePixels:	/* Report the screen's size, in Pixels */
7673 	if (AllowWindowOps(xw, ewGetScreenSizePixels)) {
7674 	    TRACE(("...get screen size in pixels\n"));
7675 	    (void) QueryMaximize(xw, &root_width, &root_height);
7676 	    init_reply(ANSI_CSI);
7677 	    reply.a_pintro = 0;
7678 	    reply.a_nparam = 3;
7679 	    reply.a_param[0] = 5;
7680 	    reply.a_param[1] = (ParmType) root_height;
7681 	    reply.a_param[2] = (ParmType) root_width;
7682 	    reply.a_inters = 0;
7683 	    reply.a_final = 't';
7684 	    unparseseq(xw, &reply);
7685 	}
7686 	break;
7687     case ewGetCharSizePixels:	/* Report the font's size, in pixel */
7688 	if (AllowWindowOps(xw, ewGetScreenSizeChars)) {
7689 	    TRACE(("...get font size in pixels\n"));
7690 	    TRACE(("...using font size %dx%d\n",
7691 		   FontHeight(screen),
7692 		   FontWidth(screen)));
7693 	    init_reply(ANSI_CSI);
7694 	    reply.a_pintro = 0;
7695 	    reply.a_nparam = 3;
7696 	    reply.a_param[0] = 6;
7697 	    reply.a_param[1] = (ParmType) FontHeight(screen);
7698 	    reply.a_param[2] = (ParmType) FontWidth(screen);
7699 	    reply.a_inters = 0;
7700 	    reply.a_final = 't';
7701 	    unparseseq(xw, &reply);
7702 	}
7703 	break;
7704 #endif
7705 
7706     case ewGetWinSizeChars:	/* Report the text's size in characters */
7707 	if (AllowWindowOps(xw, ewGetWinSizeChars)) {
7708 	    TRACE(("...get window size in characters\n"));
7709 	    init_reply(ANSI_CSI);
7710 	    reply.a_pintro = 0;
7711 	    reply.a_nparam = 3;
7712 	    reply.a_param[0] = 8;
7713 	    reply.a_param[1] = (ParmType) MaxRows(screen);
7714 	    reply.a_param[2] = (ParmType) MaxCols(screen);
7715 	    reply.a_inters = 0;
7716 	    reply.a_final = 't';
7717 	    unparseseq(xw, &reply);
7718 	}
7719 	break;
7720 
7721 #if OPT_MAXIMIZE
7722     case ewGetScreenSizeChars:	/* Report the screen's size, in characters */
7723 	if (AllowWindowOps(xw, ewGetScreenSizeChars)) {
7724 	    TRACE(("...get screen size in characters\n"));
7725 	    TRACE(("...using font size %dx%d\n",
7726 		   FontHeight(screen),
7727 		   FontWidth(screen)));
7728 	    (void) QueryMaximize(xw, &root_width, &root_height);
7729 	    init_reply(ANSI_CSI);
7730 	    reply.a_pintro = 0;
7731 	    reply.a_nparam = 3;
7732 	    reply.a_param[0] = 9;
7733 	    reply.a_param[1] = (ParmType) (root_height
7734 					   / (unsigned) FontHeight(screen));
7735 	    reply.a_param[2] = (ParmType) (root_width
7736 					   / (unsigned) FontWidth(screen));
7737 	    reply.a_inters = 0;
7738 	    reply.a_final = 't';
7739 	    unparseseq(xw, &reply);
7740 	}
7741 	break;
7742 #endif
7743 
7744     case ewGetIconTitle:	/* Report the icon's label */
7745 	if (AllowWindowOps(xw, ewGetIconTitle)) {
7746 	    TRACE(("...get icon's label\n"));
7747 	    report_win_label(xw, 'L', label = get_icon_label(xw));
7748 	    free(label);
7749 	}
7750 	break;
7751 
7752     case ewGetWinTitle:	/* Report the window's title */
7753 	if (AllowWindowOps(xw, ewGetWinTitle)) {
7754 	    TRACE(("...get window's label\n"));
7755 	    report_win_label(xw, 'l', label = get_window_label(xw));
7756 	    free(label);
7757 	}
7758 	break;
7759 
7760     case ewPushTitle:		/* save the window's title(s) on stack */
7761 	if (AllowWindowOps(xw, ewPushTitle)) {
7762 	    SaveTitle *last = screen->save_title;
7763 	    SaveTitle *item = TypeCalloc(SaveTitle);
7764 
7765 	    TRACE(("...push title onto stack\n"));
7766 	    if (item != 0) {
7767 		switch (zero_if_default(1)) {
7768 		case 0:
7769 		    item->iconName = get_icon_label(xw);
7770 		    item->windowName = get_window_label(xw);
7771 		    break;
7772 		case 1:
7773 		    item->iconName = get_icon_label(xw);
7774 		    break;
7775 		case 2:
7776 		    item->windowName = get_window_label(xw);
7777 		    break;
7778 		}
7779 		item->next = last;
7780 		if (item->iconName == 0) {
7781 		    item->iconName = ((last == 0)
7782 				      ? get_icon_label(xw)
7783 				      : x_strdup(last->iconName));
7784 		}
7785 		if (item->windowName == 0) {
7786 		    item->windowName = ((last == 0)
7787 					? get_window_label(xw)
7788 					: x_strdup(last->windowName));
7789 		}
7790 		screen->save_title = item;
7791 	    }
7792 	}
7793 	break;
7794 
7795     case ewPopTitle:		/* restore the window's title(s) from stack */
7796 	if (AllowWindowOps(xw, ewPopTitle)) {
7797 	    SaveTitle *item = screen->save_title;
7798 
7799 	    TRACE(("...pop title off stack\n"));
7800 	    if (item != 0) {
7801 		switch (zero_if_default(1)) {
7802 		case 0:
7803 		    ChangeIconName(xw, item->iconName);
7804 		    ChangeTitle(xw, item->windowName);
7805 		    break;
7806 		case 1:
7807 		    ChangeIconName(xw, item->iconName);
7808 		    break;
7809 		case 2:
7810 		    ChangeTitle(xw, item->windowName);
7811 		    break;
7812 		}
7813 		screen->save_title = item->next;
7814 		free(item->iconName);
7815 		free(item->windowName);
7816 		free(item);
7817 	    }
7818 	}
7819 	break;
7820 
7821     default:			/* DECSLPP (24, 25, 36, 48, 72, 144) */
7822 	if (AllowWindowOps(xw, ewSetWinLines)) {
7823 	    if (code >= 24)
7824 		RequestResize(xw, code, -1, True);
7825 	}
7826 	break;
7827     }
7828 }
7829 
7830 /*
7831  * set a bit in a word given a pointer to the word and a mask.
7832  */
7833 static int
bitset(unsigned * p,unsigned mask)7834 bitset(unsigned *p, unsigned mask)
7835 {
7836     unsigned before = *p;
7837     *p |= mask;
7838     return (before != *p);
7839 }
7840 
7841 /*
7842  * clear a bit in a word given a pointer to the word and a mask.
7843  */
7844 static int
bitclr(unsigned * p,unsigned mask)7845 bitclr(unsigned *p, unsigned mask)
7846 {
7847     unsigned before = *p;
7848     *p &= ~mask;
7849     return (before != *p);
7850 }
7851 
7852 /*
7853  * Copy bits from one word to another, given a mask
7854  */
7855 static int
bitcpy(unsigned * p,unsigned q,unsigned mask)7856 bitcpy(unsigned *p, unsigned q, unsigned mask)
7857 {
7858     unsigned before = *p;
7859     bitclr(p, mask);
7860     bitset(p, q & mask);
7861     return (before != *p);
7862 }
7863 
7864 void
unparseputc1(XtermWidget xw,int c)7865 unparseputc1(XtermWidget xw, int c)
7866 {
7867     if (c >= 0x80 && c <= 0x9F) {
7868 	if (!TScreenOf(xw)->control_eight_bits) {
7869 	    unparseputc(xw, A2E(ANSI_ESC));
7870 	    c = A2E(c - 0x40);
7871 	}
7872     }
7873     unparseputc(xw, c);
7874 }
7875 
7876 void
unparseseq(XtermWidget xw,ANSI * ap)7877 unparseseq(XtermWidget xw, ANSI *ap)
7878 {
7879     int c;
7880 
7881     assert(ap->a_nparam < NPARAM);
7882     unparseputc1(xw, c = ap->a_type);
7883     if (c == ANSI_ESC
7884 	|| c == ANSI_DCS
7885 	|| c == ANSI_CSI
7886 	|| c == ANSI_OSC
7887 	|| c == ANSI_PM
7888 	|| c == ANSI_APC
7889 	|| c == ANSI_SS3) {
7890 	int i;
7891 	int inters;
7892 	char temp[8];
7893 
7894 	if (ap->a_pintro != 0)
7895 	    unparseputc(xw, ap->a_pintro);
7896 	for (i = 0; i < ap->a_nparam; ++i) {
7897 	    if (i != 0) {
7898 		if (ap->a_radix[i] == 1 || ap->a_radix[i - 1] == 1) {
7899 		    ;
7900 		} else if (ap->a_delim) {
7901 		    unparseputs(xw, ap->a_delim);
7902 		} else {
7903 		    unparseputc(xw, ';');
7904 		}
7905 	    }
7906 	    switch (ap->a_radix[i]) {
7907 	    case 16:
7908 		sprintf(temp, "%04X", ap->a_param[i] & 0xffff);
7909 		unparseputs(xw, temp);
7910 		break;
7911 	    case 1:
7912 		unparseputc(xw, ap->a_param[i]);
7913 		break;
7914 	    default:
7915 		unparseputn(xw, (unsigned) (UParm) ap->a_param[i]);
7916 		break;
7917 	    }
7918 	}
7919 	if ((inters = ap->a_inters) != 0) {
7920 	    for (i = 3; i >= 0; --i) {
7921 		c = CharOf(inters >> (8 * i));
7922 		if (c != 0)
7923 		    unparseputc(xw, c);
7924 	    }
7925 	}
7926 	switch (ap->a_type) {
7927 	case ANSI_DCS:
7928 	    /* FALLTHRU */
7929 	case ANSI_OSC:
7930 	    /* FALLTHRU */
7931 	case ANSI_PM:
7932 	    /* FALLTHRU */
7933 	case ANSI_APC:
7934 	    unparseputc1(xw, ANSI_ST);
7935 	    break;
7936 	default:
7937 	    unparseputc(xw, (char) ap->a_final);
7938 	    break;
7939 	}
7940     }
7941     unparse_end(xw);
7942 }
7943 
7944 void
unparseputn(XtermWidget xw,unsigned n)7945 unparseputn(XtermWidget xw, unsigned n)
7946 {
7947     unsigned q;
7948 
7949     q = n / 10;
7950     if (q != 0)
7951 	unparseputn(xw, q);
7952     unparseputc(xw, (char) ('0' + (n % 10)));
7953 }
7954 
7955 void
unparseputs(XtermWidget xw,const char * s)7956 unparseputs(XtermWidget xw, const char *s)
7957 {
7958     if (s != 0) {
7959 	while (*s)
7960 	    unparseputc(xw, *s++);
7961     }
7962 }
7963 
7964 void
unparseputc(XtermWidget xw,int c)7965 unparseputc(XtermWidget xw, int c)
7966 {
7967     TScreen *screen = TScreenOf(xw);
7968     IChar *buf = screen->unparse_bfr;
7969     unsigned len;
7970 
7971     if ((screen->unparse_len + 2) >= screen->unparse_max)
7972 	unparse_end(xw);
7973 
7974     len = screen->unparse_len;
7975 
7976 #if OPT_TCAP_QUERY
7977     /*
7978      * If we're returning a termcap string, it has to be translated since
7979      * a DCS must not contain any characters except for the normal 7-bit
7980      * printable ASCII (counting tab, carriage return, etc).  For now,
7981      * just use hexadecimal for the whole thing.
7982      */
7983     if (screen->tc_query_code >= 0) {
7984 	char tmp[3];
7985 	sprintf(tmp, "%02X", c & 0xFF);
7986 	buf[len++] = CharOf(tmp[0]);
7987 	buf[len++] = CharOf(tmp[1]);
7988     } else
7989 #endif
7990     if ((buf[len++] = (IChar) c) == '\r' && (xw->flags & LINEFEED)) {
7991 	buf[len++] = '\n';
7992     }
7993 
7994     screen->unparse_len = len;
7995 
7996     /* If send/receive mode is reset, we echo characters locally */
7997     if ((xw->keyboard.flags & MODE_SRM) == 0) {
7998 	doparsing(xw, (unsigned) c, &myState);
7999     }
8000 }
8001 
8002 void
unparse_end(XtermWidget xw)8003 unparse_end(XtermWidget xw)
8004 {
8005     TScreen *screen = TScreenOf(xw);
8006 
8007 #if OPT_TCAP_QUERY
8008     /*
8009      * tcap-query works by simulating key-presses, which ordinarily would be
8010      * flushed out at the end of each key.  For better efficiency, do not do
8011      * the flush unless we are about to fill the buffer used to capture the
8012      * response.
8013      */
8014     if ((screen->tc_query_code >= 0)
8015 	&& (screen->unparse_len + 2 < screen->unparse_max)) {
8016 	return;
8017     }
8018 #endif
8019     if (screen->unparse_len) {
8020 	TRACE(("unparse_end %u:%s\n",
8021 	       screen->unparse_len,
8022 	       visibleIChars(screen->unparse_bfr, screen->unparse_len)));
8023 #ifdef VMS
8024 	tt_write(screen->unparse_bfr, screen->unparse_len);
8025 #else /* VMS */
8026 	writePtyData(screen->respond, screen->unparse_bfr, screen->unparse_len);
8027 #endif /* VMS */
8028 	screen->unparse_len = 0;
8029     }
8030 }
8031 
8032 void
ToggleAlternate(XtermWidget xw)8033 ToggleAlternate(XtermWidget xw)
8034 {
8035     if (TScreenOf(xw)->whichBuf)
8036 	FromAlternate(xw);
8037     else
8038 	ToAlternate(xw, False);
8039 }
8040 
8041 static void
ToAlternate(XtermWidget xw,Bool clearFirst)8042 ToAlternate(XtermWidget xw, Bool clearFirst)
8043 {
8044     TScreen *screen = TScreenOf(xw);
8045 
8046     if (screen->whichBuf == 0) {
8047 	TRACE(("ToAlternate\n"));
8048 	if (!screen->editBuf_index[1]) {
8049 	    screen->editBuf_index[1] = allocScrnBuf(xw,
8050 						    (unsigned) MaxRows(screen),
8051 						    (unsigned) MaxCols(screen),
8052 						    &screen->editBuf_data[1]);
8053 	}
8054 	SwitchBufs(xw, 1, clearFirst);
8055 	screen->visbuf = screen->editBuf_index[screen->whichBuf];
8056 	update_altscreen();
8057     }
8058 }
8059 
8060 static void
FromAlternate(XtermWidget xw)8061 FromAlternate(XtermWidget xw)
8062 {
8063     TScreen *screen = TScreenOf(xw);
8064 
8065     if (screen->whichBuf != 0) {
8066 	TRACE(("FromAlternate\n"));
8067 	if (screen->scroll_amt) {
8068 	    FlushScroll(xw);
8069 	}
8070 	SwitchBufs(xw, 0, False);
8071 	screen->visbuf = screen->editBuf_index[screen->whichBuf];
8072 	update_altscreen();
8073     }
8074 }
8075 
8076 static void
SwitchBufs(XtermWidget xw,int toBuf,Bool clearFirst)8077 SwitchBufs(XtermWidget xw, int toBuf, Bool clearFirst)
8078 {
8079     TScreen *screen = TScreenOf(xw);
8080     int rows, top;
8081 
8082     screen->whichBuf = toBuf;
8083     if (screen->cursor_state)
8084 	HideCursor(xw);
8085 
8086     rows = MaxRows(screen);
8087     SwitchBufPtrs(screen, toBuf);
8088 
8089     if ((top = INX2ROW(screen, 0)) < rows) {
8090 	if (screen->scroll_amt) {
8091 	    FlushScroll(xw);
8092 	}
8093 	xtermClear2(xw,
8094 		    (int) OriginX(screen),
8095 		    (int) top * FontHeight(screen) + screen->border,
8096 		    (unsigned) Width(screen),
8097 		    (unsigned) ((rows - top) * FontHeight(screen)));
8098 	if (clearFirst) {
8099 	    ClearBufRows(xw, top, rows);
8100 	}
8101     }
8102     ScrnUpdate(xw, 0, 0, rows, MaxCols(screen), False);
8103 }
8104 
8105 Bool
CheckBufPtrs(TScreen * screen)8106 CheckBufPtrs(TScreen *screen)
8107 {
8108     return (screen->visbuf != 0
8109 	    && screen->editBuf_index[0] != 0
8110 	    && screen->editBuf_index[1] != 0);
8111 }
8112 
8113 /*
8114  * Swap buffer line pointers between alternate and regular screens.
8115  */
8116 void
SwitchBufPtrs(TScreen * screen,int toBuf)8117 SwitchBufPtrs(TScreen *screen, int toBuf)
8118 {
8119     if (CheckBufPtrs(screen)) {
8120 	screen->visbuf = screen->editBuf_index[toBuf];
8121     }
8122 }
8123 
8124 void
VTRun(XtermWidget xw)8125 VTRun(XtermWidget xw)
8126 {
8127     TScreen *screen = TScreenOf(xw);
8128 
8129     TRACE(("VTRun ...\n"));
8130 
8131     if (!screen->Vshow) {
8132 	set_vt_visibility(True);
8133     }
8134     update_vttekmode();
8135     update_vtshow();
8136     update_tekshow();
8137     set_vthide_sensitivity();
8138 
8139     ScrnAllocBuf(xw);
8140 
8141     screen->cursor_state = OFF;
8142     screen->cursor_set = ON;
8143 #if OPT_BLINK_CURS
8144     if (DoStartBlinking(screen))
8145 	StartBlinking(xw);
8146 #endif
8147 
8148 #if OPT_TEK4014
8149     if (Tpushb > Tpushback) {
8150 	fillPtyData(xw, VTbuffer, (char *) Tpushback, (int) (Tpushb - Tpushback));
8151 	Tpushb = Tpushback;
8152     }
8153 #endif
8154     screen->is_running = True;
8155     if (screen->embed_high && screen->embed_wide) {
8156 	ScreenResize(xw, screen->embed_wide, screen->embed_high, &(xw->flags));
8157     }
8158 #if OPT_MAXIMIZE
8159     else if (resource.fullscreen == esTrue || resource.fullscreen == esAlways)
8160 	FullScreen(xw, True);
8161 #endif
8162     if (!setjmp(VTend))
8163 	VTparse(xw);
8164     StopBlinking(xw);
8165     HideCursor(xw);
8166     screen->cursor_set = OFF;
8167     TRACE(("... VTRun\n"));
8168 }
8169 
8170 /*ARGSUSED*/
8171 static void
VTExpose(Widget w GCC_UNUSED,XEvent * event,Region region GCC_UNUSED)8172 VTExpose(Widget w GCC_UNUSED,
8173 	 XEvent *event,
8174 	 Region region GCC_UNUSED)
8175 {
8176     DEBUG_MSG("Expose\n");
8177     if (event->type == Expose)
8178 	HandleExposure(term, event);
8179 }
8180 
8181 static void
VTGraphicsOrNoExpose(XEvent * event)8182 VTGraphicsOrNoExpose(XEvent *event)
8183 {
8184     XtermWidget xw = term;
8185     TScreen *screen = TScreenOf(xw);
8186     if (screen->incopy <= 0) {
8187 	screen->incopy = 1;
8188 	if (screen->scrolls > 0)
8189 	    screen->scrolls--;
8190     }
8191     if (event->type == GraphicsExpose)
8192 	if (HandleExposure(xw, event))
8193 	    screen->cursor_state = OFF;
8194     if ((event->type == NoExpose)
8195 	|| ((XGraphicsExposeEvent *) event)->count == 0) {
8196 	if (screen->incopy <= 0 && screen->scrolls > 0)
8197 	    screen->scrolls--;
8198 	if (screen->scrolls)
8199 	    screen->incopy = -1;
8200 	else
8201 	    screen->incopy = 0;
8202     }
8203 }
8204 
8205 /*ARGSUSED*/
8206 static void
VTNonMaskableEvent(Widget w GCC_UNUSED,XtPointer closure GCC_UNUSED,XEvent * event,Boolean * cont GCC_UNUSED)8207 VTNonMaskableEvent(Widget w GCC_UNUSED,
8208 		   XtPointer closure GCC_UNUSED,
8209 		   XEvent *event,
8210 		   Boolean *cont GCC_UNUSED)
8211 {
8212     switch (event->type) {
8213     case GraphicsExpose:
8214 	/* FALLTHRU */
8215     case NoExpose:
8216 	VTGraphicsOrNoExpose(event);
8217 	break;
8218     }
8219 }
8220 
8221 static void
VTResize(Widget w)8222 VTResize(Widget w)
8223 {
8224     if (XtIsRealized(w)) {
8225 	XtermWidget xw = (XtermWidget) w;
8226 	ScreenResize(xw, xw->core.width, xw->core.height, &xw->flags);
8227     }
8228 }
8229 
8230 #define okDimension(src,dst) ((src <= MAX_U_COORD) \
8231 			  && ((dst = (Dimension) src) == src))
8232 
8233 static void
RequestResize(XtermWidget xw,int rows,int cols,Bool text)8234 RequestResize(XtermWidget xw, int rows, int cols, Bool text)
8235 {
8236     TScreen *screen = TScreenOf(xw);
8237     Dimension replyWidth, replyHeight;
8238     Dimension askedWidth, askedHeight;
8239     XtGeometryResult status;
8240     XWindowAttributes attrs;
8241 #if OPT_RENDERFONT && USE_DOUBLE_BUFFER
8242     Boolean buggyXft = False;
8243     Cardinal ignore = 0;
8244 #endif
8245 
8246     TRACE(("RequestResize(rows=%d, cols=%d, text=%d)\n", rows, cols, text));
8247 
8248     /* check first if the row/column values fit into a Dimension */
8249     if (cols > 0) {
8250 	if ((int) (askedWidth = (Dimension) cols) < cols) {
8251 	    TRACE(("... cols too large for Dimension\n"));
8252 	    return;
8253 	}
8254     } else {
8255 	askedWidth = 0;
8256     }
8257     if (rows > 0) {
8258 	if ((int) (askedHeight = (Dimension) rows) < rows) {
8259 	    TRACE(("... rows too large for Dimension\n"));
8260 	    return;
8261 	}
8262     } else {
8263 	askedHeight = 0;
8264     }
8265 
8266     xw->work.doing_resize = True;
8267 
8268 #if OPT_RENDERFONT && USE_DOUBLE_BUFFER
8269     /*
8270      * Work around a bug seen when vttest switches from 132 columns back to 80
8271      * columns, while double-buffering is active.  If Xft is active during the
8272      * resize, the screen will be blank thereafter.  This workaround causes
8273      * some extra flickering, but that is preferable to a blank screen.
8274      *
8275      * Since the bitmap- and TrueType-fonts do not always have identical sizes,
8276      * do this switching early, to use the updated font-sizes in the request
8277      * for resizing the window.
8278      */
8279 #define ToggleXft() HandleRenderFont((Widget)xw, (XEvent *)0, (String *)0, &ignore)
8280     if (resource.buffered
8281 	&& UsingRenderFont(xw)) {
8282 	ToggleXft();
8283 	buggyXft = True;
8284     }
8285 #endif
8286 
8287     /*
8288      * If the requested values will fit into a Dimension, and one or both are
8289      * zero, get the current corresponding screen dimension to use as a limit.
8290      */
8291     if (askedHeight == 0
8292 	|| askedWidth == 0
8293 	|| xw->misc.limit_resize > 0) {
8294 	xtermGetWinAttrs(XtDisplay(xw),
8295 			 RootWindowOfScreen(XtScreen(xw)), &attrs);
8296     }
8297 
8298     /*
8299      * Using the current font metrics, translate the requested character
8300      * rows/columns into pixels.
8301      */
8302     if (text) {
8303 	unsigned long value;
8304 
8305 	if ((value = (unsigned long) rows) != 0) {
8306 	    if (rows < 0)
8307 		value = (unsigned long) MaxRows(screen);
8308 	    value *= (unsigned long) FontHeight(screen);
8309 	    value += (unsigned long) (2 * screen->border);
8310 	    if (!okDimension(value, askedHeight))
8311 		goto give_up;
8312 	}
8313 
8314 	if ((value = (unsigned long) cols) != 0) {
8315 	    if (cols < 0)
8316 		value = (unsigned long) MaxCols(screen);
8317 	    value *= (unsigned long) FontWidth(screen);
8318 	    value += (unsigned long) ((2 * screen->border)
8319 				      + ScrollbarWidth(screen));
8320 	    if (!okDimension(value, askedWidth))
8321 		goto give_up;
8322 	}
8323 
8324     } else {
8325 	if (rows < 0)
8326 	    askedHeight = FullHeight(screen);
8327 	if (cols < 0)
8328 	    askedWidth = FullWidth(screen);
8329     }
8330 
8331     if (rows == 0) {
8332 	askedHeight = (Dimension) attrs.height;
8333     }
8334     if (cols == 0) {
8335 	askedWidth = (Dimension) attrs.width;
8336     }
8337 
8338     if (xw->misc.limit_resize > 0) {
8339 	Dimension high = (Dimension) (xw->misc.limit_resize * attrs.height);
8340 	Dimension wide = (Dimension) (xw->misc.limit_resize * attrs.width);
8341 	if ((int) high < attrs.height)
8342 	    high = (Dimension) attrs.height;
8343 	if (askedHeight > high)
8344 	    askedHeight = high;
8345 	if ((int) wide < attrs.width)
8346 	    wide = (Dimension) attrs.width;
8347 	if (askedWidth > wide)
8348 	    askedWidth = wide;
8349     }
8350 #ifndef nothack
8351     getXtermSizeHints(xw);
8352 #endif
8353 
8354     TRACE(("...requesting resize %dx%d\n", askedHeight, askedWidth));
8355     status = REQ_RESIZE((Widget) xw,
8356 			askedWidth, askedHeight,
8357 			&replyWidth, &replyHeight);
8358 
8359     if (status == XtGeometryYes ||
8360 	status == XtGeometryDone) {
8361 	ScreenResize(xw, replyWidth, replyHeight, &xw->flags);
8362     }
8363 #ifndef nothack
8364     /*
8365      * XtMakeResizeRequest() has the undesirable side-effect of clearing
8366      * the window manager's hints, even on a failed request.  This would
8367      * presumably be fixed if the shell did its own work.
8368      */
8369     if (xw->hints.flags
8370 	&& replyHeight
8371 	&& replyWidth) {
8372 	xw->hints.height = replyHeight;
8373 	xw->hints.width = replyWidth;
8374 
8375 	TRACE(("%s@%d -- ", __FILE__, __LINE__));
8376 	TRACE_HINTS(&xw->hints);
8377 	XSetWMNormalHints(screen->display, VShellWindow(xw), &xw->hints);
8378 	TRACE(("%s@%d -- ", __FILE__, __LINE__));
8379 	TRACE_WM_HINTS(xw);
8380     }
8381 #endif
8382 
8383     XSync(screen->display, False);	/* synchronize */
8384     if (xtermAppPending()) {
8385 	xevents(xw);
8386     }
8387 
8388   give_up:
8389 #if OPT_RENDERFONT && USE_DOUBLE_BUFFER
8390     if (buggyXft) {
8391 	ToggleXft();
8392 	if (xtermAppPending()) {
8393 	    xevents(xw);
8394 	}
8395     }
8396 #endif
8397 
8398     xw->work.doing_resize = False;
8399 
8400     TRACE(("...RequestResize done\n"));
8401     return;
8402 }
8403 
8404 static String xterm_trans =
8405 "<ClientMessage>WM_PROTOCOLS: DeleteWindow()\n\
8406      <MappingNotify>: KeyboardMapping()\n";
8407 
8408 int
VTInit(XtermWidget xw)8409 VTInit(XtermWidget xw)
8410 {
8411     Widget vtparent = SHELL_OF(xw);
8412 
8413     TRACE(("VTInit " TRACE_L "\n"));
8414 
8415     XtRealizeWidget(vtparent);
8416     XtOverrideTranslations(vtparent, XtParseTranslationTable(xterm_trans));
8417     (void) XSetWMProtocols(XtDisplay(vtparent), XtWindow(vtparent),
8418 			   &wm_delete_window, 1);
8419 
8420     if (IsEmpty(xw->keyboard.print_translations)) {
8421 	TRACE_TRANS("shell", vtparent);
8422 	TRACE_TRANS("vt100", (Widget) (xw));
8423 	xtermButtonInit(xw);
8424     }
8425 
8426     ScrnAllocBuf(xw);
8427 
8428     TRACE(("..." TRACE_R " VTInit\n"));
8429     return (1);
8430 }
8431 
8432 static void
VTClassInit(void)8433 VTClassInit(void)
8434 {
8435     XtAddConverter(XtRString, XtRGravity, XmuCvtStringToGravity,
8436 		   (XtConvertArgList) NULL, (Cardinal) 0);
8437 }
8438 
8439 /*
8440  * Override the use of XtDefaultForeground/XtDefaultBackground to make some
8441  * colors, such as cursor color, use the actual foreground/background value
8442  * if there is no explicit resource value used.
8443  */
8444 static Pixel
fill_Tres(XtermWidget target,XtermWidget source,int offset)8445 fill_Tres(XtermWidget target, XtermWidget source, int offset)
8446 {
8447     char *name;
8448     ScrnColors temp;
8449     TScreen *src = TScreenOf(source);
8450     TScreen *dst = TScreenOf(target);
8451 
8452     dst->Tcolors[offset] = src->Tcolors[offset];
8453     dst->Tcolors[offset].mode = False;
8454 
8455     if ((name = x_strtrim(dst->Tcolors[offset].resource)) != 0)
8456 	dst->Tcolors[offset].resource = name;
8457 
8458     if (name == 0) {
8459 	dst->Tcolors[offset].value = target->dft_foreground;
8460     } else if (isDefaultForeground(name)) {
8461 	dst->Tcolors[offset].value = ((offset == TEXT_FG || offset == TEXT_BG)
8462 				      ? target->dft_foreground
8463 				      : dst->Tcolors[TEXT_FG].value);
8464     } else if (isDefaultBackground(name)) {
8465 	dst->Tcolors[offset].value = ((offset == TEXT_FG || offset == TEXT_BG)
8466 				      ? target->dft_background
8467 				      : dst->Tcolors[TEXT_BG].value);
8468     } else {
8469 	memset(&temp, 0, sizeof(temp));
8470 	if (AllocateTermColor(target, &temp, offset, name, True)) {
8471 	    if (COLOR_DEFINED(&(temp), offset))
8472 		free(temp.names[offset]);
8473 	    dst->Tcolors[offset].value = temp.colors[offset];
8474 	} else if (offset == TEXT_FG || offset == TEXT_BG) {
8475 	    free(name);
8476 	    dst->Tcolors[offset].resource = 0;
8477 	}
8478     }
8479     return dst->Tcolors[offset].value;
8480 }
8481 
8482 /*
8483  * If one or both of the foreground/background colors cannot be allocated,
8484  * e.g., due to gross misconfiguration, recover by setting both to the
8485  * display's default values.
8486  */
8487 static void
repairColors(XtermWidget target)8488 repairColors(XtermWidget target)
8489 {
8490     TScreen *screen = TScreenOf(target);
8491 
8492     if (screen->Tcolors[TEXT_FG].resource == 0 ||
8493 	screen->Tcolors[TEXT_BG].resource == 0) {
8494 	xtermWarning("unable to allocate fg/bg colors\n");
8495 	screen->Tcolors[TEXT_FG].resource = x_strdup(XtDefaultForeground);
8496 	screen->Tcolors[TEXT_BG].resource = x_strdup(XtDefaultBackground);
8497 	if (screen->Tcolors[TEXT_FG].resource == 0 ||
8498 	    screen->Tcolors[TEXT_BG].resource == 0) {
8499 	    Exit(1);
8500 	}
8501 	screen->Tcolors[TEXT_FG].value = target->dft_foreground;
8502 	screen->Tcolors[TEXT_BG].value = target->dft_background;
8503     }
8504 }
8505 
8506 #if OPT_WIDE_CHARS
8507 static void
set_utf8_feature(TScreen * screen,int * feature)8508 set_utf8_feature(TScreen *screen, int *feature)
8509 {
8510     if (*feature == uDefault) {
8511 	switch (screen->utf8_mode) {
8512 	case uFalse:
8513 	    /* FALLTHRU */
8514 	case uTrue:
8515 	    *feature = screen->utf8_mode;
8516 	    break;
8517 	case uDefault:
8518 	    /* should not happen */
8519 	    *feature = uTrue;
8520 	    break;
8521 	case uAlways:
8522 	    /* use this to disable menu entry */
8523 	    break;
8524 	}
8525     }
8526 }
8527 
8528 static void
VTInitialize_locale(XtermWidget xw)8529 VTInitialize_locale(XtermWidget xw)
8530 {
8531     TScreen *screen = TScreenOf(xw);
8532     Bool is_utf8 = xtermEnvUTF8();
8533 
8534     TRACE(("VTInitialize_locale\n"));
8535     TRACE(("... request screen.utf8_mode = %d\n", screen->utf8_mode));
8536     TRACE(("... request screen.utf8_fonts = %d\n", screen->utf8_fonts));
8537     TRACE(("... request screen.utf8_title = %d\n", screen->utf8_title));
8538 
8539     screen->utf8_always = (screen->utf8_mode == uAlways);
8540     if (screen->utf8_mode < 0)
8541 	screen->utf8_mode = uFalse;
8542 
8543     if (screen->utf8_mode > 3)
8544 	screen->utf8_mode = uDefault;
8545 
8546     screen->latin9_mode = 0;
8547     screen->unicode_font = 0;
8548 #if OPT_LUIT_PROG
8549     xw->misc.callfilter = 0;
8550     xw->misc.use_encoding = 0;
8551 
8552     TRACE(("... setup for luit:\n"));
8553     TRACE(("... request misc.locale_str = \"%s\"\n", xw->misc.locale_str));
8554 
8555     if (screen->utf8_mode == uFalse) {
8556 	TRACE(("... command-line +u8 overrides\n"));
8557     } else
8558 #if OPT_MINI_LUIT
8559     if (x_strcasecmp(xw->misc.locale_str, "CHECKFONT") == 0) {
8560 	int fl = (int) strlen(DefaultFontN(xw));
8561 	if (fl > 11
8562 	    && x_strcasecmp(DefaultFontN(xw) + fl - 11, "-ISO10646-1") == 0) {
8563 	    screen->unicode_font = 1;
8564 	    /* unicode font, use True */
8565 #ifdef HAVE_LANGINFO_CODESET
8566 	    if (!strcmp(xtermEnvEncoding(), "ANSI_X3.4-1968")
8567 		|| !strcmp(xtermEnvEncoding(), "ISO-8859-1")) {
8568 		if (screen->utf8_mode == uDefault)
8569 		    screen->utf8_mode = uFalse;
8570 	    } else if (!strcmp(xtermEnvEncoding(), "ISO-8859-15")) {
8571 		if (screen->utf8_mode == uDefault)
8572 		    screen->utf8_mode = uFalse;
8573 		screen->latin9_mode = 1;
8574 	    } else {
8575 		xw->misc.callfilter = (Boolean) (is_utf8 ? 0 : 1);
8576 		screen->utf8_mode = uAlways;
8577 	    }
8578 #else
8579 	    xw->misc.callfilter = is_utf8 ? 0 : 1;
8580 	    screen->utf8_mode = uAlways;
8581 #endif
8582 	} else {
8583 	    /* other encoding, use False */
8584 	    if (screen->utf8_mode == uDefault) {
8585 		screen->utf8_mode = is_utf8 ? uAlways : uFalse;
8586 	    }
8587 	}
8588     } else
8589 #endif /* OPT_MINI_LUIT */
8590 	if (x_strcasecmp(xw->misc.locale_str, "TRUE") == 0 ||
8591 	    x_strcasecmp(xw->misc.locale_str, "ON") == 0 ||
8592 	    x_strcasecmp(xw->misc.locale_str, "YES") == 0 ||
8593 	    x_strcasecmp(xw->misc.locale_str, "AUTO") == 0 ||
8594 	    strcmp(xw->misc.locale_str, "1") == 0) {
8595 	/* when true ... fully obeying LC_CTYPE locale */
8596 	xw->misc.callfilter = (Boolean) (is_utf8 ? 0 : 1);
8597 	screen->utf8_mode = uAlways;
8598     } else if (x_strcasecmp(xw->misc.locale_str, "FALSE") == 0 ||
8599 	       x_strcasecmp(xw->misc.locale_str, "OFF") == 0 ||
8600 	       x_strcasecmp(xw->misc.locale_str, "NO") == 0 ||
8601 	       strcmp(xw->misc.locale_str, "0") == 0) {
8602 	/* when false ... original value of utf8_mode is effective */
8603 	if (screen->utf8_mode == uDefault) {
8604 	    screen->utf8_mode = is_utf8 ? uAlways : uFalse;
8605 	}
8606     } else if (x_strcasecmp(xw->misc.locale_str, "MEDIUM") == 0 ||
8607 	       x_strcasecmp(xw->misc.locale_str, "SEMIAUTO") == 0) {
8608 	/* when medium ... obeying locale only for UTF-8 and Asian */
8609 	if (is_utf8) {
8610 	    screen->utf8_mode = uAlways;
8611 	} else if (
8612 #ifdef MB_CUR_MAX
8613 		      MB_CUR_MAX > 1 ||
8614 #else
8615 		      !strncmp(xtermEnvLocale(), "ja", (size_t) 2) ||
8616 		      !strncmp(xtermEnvLocale(), "ko", (size_t) 2) ||
8617 		      !strncmp(xtermEnvLocale(), "zh", (size_t) 2) ||
8618 #endif
8619 		      !strncmp(xtermEnvLocale(), "th", (size_t) 2) ||
8620 		      !strncmp(xtermEnvLocale(), "vi", (size_t) 2)) {
8621 	    xw->misc.callfilter = 1;
8622 	    screen->utf8_mode = uAlways;
8623 	} else {
8624 	    screen->utf8_mode = uFalse;
8625 	}
8626     } else if (x_strcasecmp(xw->misc.locale_str, "UTF-8") == 0 ||
8627 	       x_strcasecmp(xw->misc.locale_str, "UTF8") == 0) {
8628 	/* when UTF-8 ... UTF-8 mode */
8629 	screen->utf8_mode = uAlways;
8630     } else {
8631 	/* other words are regarded as encoding name passed to luit */
8632 	xw->misc.callfilter = 1;
8633 	screen->utf8_mode = uAlways;
8634 	xw->misc.use_encoding = 1;
8635     }
8636     TRACE(("... updated misc.callfilter = %s\n", BtoS(xw->misc.callfilter)));
8637     TRACE(("... updated misc.use_encoding = %s\n", BtoS(xw->misc.use_encoding)));
8638 #else
8639     if (screen->utf8_mode == uDefault) {
8640 	screen->utf8_mode = is_utf8 ? uAlways : uFalse;
8641     }
8642 #endif /* OPT_LUIT_PROG */
8643 
8644     set_utf8_feature(screen, &screen->utf8_fonts);
8645     set_utf8_feature(screen, &screen->utf8_title);
8646 
8647     screen->utf8_inparse = (Boolean) (screen->utf8_mode != uFalse);
8648 
8649     TRACE(("... updated screen.utf8_mode = %d\n", screen->utf8_mode));
8650     TRACE(("... updated screen.utf8_fonts = %d\n", screen->utf8_fonts));
8651     TRACE(("... updated screen.utf8_title = %d\n", screen->utf8_title));
8652     TRACE(("...VTInitialize_locale done\n"));
8653 }
8654 #endif
8655 
8656 void
lookupSelectUnit(XtermWidget xw,Cardinal item,String value)8657 lookupSelectUnit(XtermWidget xw, Cardinal item, String value)
8658 {
8659     /* *INDENT-OFF* */
8660     static const struct {
8661 	const char *	name;
8662 	SelectUnit	code;
8663     } table[] = {
8664     	{ "char",	Select_CHAR },
8665     	{ "word",	Select_WORD },
8666     	{ "line",	Select_LINE },
8667     	{ "group",	Select_GROUP },
8668     	{ "page",	Select_PAGE },
8669     	{ "all",	Select_ALL },
8670 #if OPT_SELECT_REGEX
8671     	{ "regex",	Select_REGEX },
8672 #endif
8673     };
8674     /* *INDENT-ON* */
8675 
8676     TScreen *screen = TScreenOf(xw);
8677     String next = x_skip_nonblanks(value);
8678     Cardinal n;
8679 
8680     screen->selectMap[item] = NSELECTUNITS;
8681     for (n = 0; n < XtNumber(table); ++n) {
8682 	if (!x_strncasecmp(table[n].name, value, (unsigned) (next - value))) {
8683 	    screen->selectMap[item] = table[n].code;
8684 #if OPT_SELECT_REGEX
8685 	    if (table[n].code == Select_REGEX) {
8686 		screen->selectExpr[item] = x_strtrim(next);
8687 		TRACE(("Parsed regex \"%s\"\n", screen->selectExpr[item]));
8688 	    }
8689 #endif
8690 	    break;
8691 	}
8692     }
8693 }
8694 
8695 static void
ParseOnClicks(XtermWidget wnew,XtermWidget wreq,Cardinal item)8696 ParseOnClicks(XtermWidget wnew, XtermWidget wreq, Cardinal item)
8697 {
8698     lookupSelectUnit(wnew, item, TScreenOf(wreq)->onClick[item]);
8699 }
8700 
8701 /*
8702  * Parse a comma-separated list, returning a string which the caller must
8703  * free, and updating the source pointer.
8704  */
8705 static char *
ParseList(const char ** source)8706 ParseList(const char **source)
8707 {
8708     const char *base = *source;
8709     const char *next;
8710     char *value = 0;
8711     char *result;
8712 
8713     /* ignore empty values */
8714     while (*base == ',')
8715 	++base;
8716 
8717     if (*base != '\0') {
8718 	size_t size;
8719 
8720 	next = base;
8721 	while (*next != '\0' && *next != ',')
8722 	    ++next;
8723 	size = (size_t) (1 + next - base);
8724 	value = malloc(size);
8725 	if (value != 0) {
8726 	    memcpy(value, base, size);
8727 	    value[size - 1] = '\0';
8728 	}
8729 	*source = next;
8730     } else {
8731 	*source = base;
8732     }
8733     result = x_strtrim(value);
8734     free(value);
8735     return result;
8736 }
8737 
8738 static void
set_flags_from_list(char * target,const char * source,const FlagList * list)8739 set_flags_from_list(char *target,
8740 		    const char *source,
8741 		    const FlagList * list)
8742 {
8743     Cardinal n;
8744 
8745     while (!IsEmpty(source)) {
8746 	char *next = ParseList(&source);
8747 	Boolean found = False;
8748 	char flag = 1;
8749 
8750 	if (next == 0)
8751 	    break;
8752 	if (*next == '~') {
8753 	    flag = 0;
8754 	    next++;
8755 	}
8756 	if (isdigit(CharOf(*next))) {
8757 	    char *temp;
8758 	    int value = (int) strtol(next, &temp, 0);
8759 	    if (!FullS2L(next, temp)) {
8760 		xtermWarning("Expected a number: %s\n", next);
8761 	    } else {
8762 		for (n = 0; list[n].name != 0; ++n) {
8763 		    if (list[n].code == value) {
8764 			target[value] = flag;
8765 			found = True;
8766 			TRACE(("...found %s (%d)\n", list[n].name, value));
8767 			break;
8768 		    }
8769 		}
8770 	    }
8771 	} else {
8772 	    for (n = 0; list[n].name != 0; ++n) {
8773 		if (!x_wildstrcmp(next, list[n].name)) {
8774 		    int value = list[n].code;
8775 		    target[value] = flag;
8776 		    found = True;
8777 		    TRACE(("...found %s (%d)\n", list[n].name, value));
8778 		}
8779 	    }
8780 	}
8781 	if (!found) {
8782 	    xtermWarning("Unrecognized keyword: %s\n", next);
8783 	}
8784 	free(next);
8785     }
8786 }
8787 
8788 #define InitCursorShape(target, source) \
8789     target->cursor_shape = source->cursor_underline \
8790 	? CURSOR_UNDERLINE \
8791 	: CURSOR_BLOCK
8792 
8793 #if OPT_XRES_QUERY
8794 static XtResource *
findVT100Resource(const char * name)8795 findVT100Resource(const char *name)
8796 {
8797     Cardinal n;
8798     XtResource *result = 0;
8799 
8800     if (!IsEmpty(name)) {
8801 	XrmQuark quarkName = XrmPermStringToQuark(name);
8802 	for (n = 0; n < XtNumber(xterm_resources); ++n) {
8803 	    if ((int) xterm_resources[n].resource_offset >= 0
8804 		&& !strcmp(xterm_resources[n].resource_name, name)) {
8805 		result = &xterm_resources[n];
8806 		break;
8807 	    } else if (xterm_resources[n].resource_name
8808 		       == (String) (intptr_t) quarkName) {
8809 		result = &xterm_resources[n];
8810 		break;
8811 	    }
8812 	}
8813     }
8814     return result;
8815 }
8816 
8817 static int
cmp_resources(const void * a,const void * b)8818 cmp_resources(const void *a, const void *b)
8819 {
8820     return strcmp((*(const String *) a),
8821 		  (*(const String *) b));
8822 }
8823 
8824 static void
reportResources(XtermWidget xw)8825 reportResources(XtermWidget xw)
8826 {
8827     String *list = TypeMallocN(String, XtNumber(xterm_resources));
8828     Cardinal n;
8829     int widest = 0;
8830 
8831     if (list == NULL)
8832 	return;
8833 
8834     for (n = 0; n < XtNumber(xterm_resources); ++n) {
8835 	int width;
8836 	list[n] = (((int) xterm_resources[n].resource_offset < 0)
8837 		   ? XrmQuarkToString((XrmQuark) (intptr_t)
8838 				      xterm_resources[n].resource_name)
8839 		   : xterm_resources[n].resource_name);
8840 	width = (int) strlen(list[n]);
8841 	if (widest < width)
8842 	    widest = width;
8843     }
8844     qsort(list, (size_t) XtNumber(xterm_resources), sizeof(String), cmp_resources);
8845     for (n = 0; n < XtNumber(xterm_resources); ++n) {
8846 	char *value = vt100ResourceToString(xw, list[n]);
8847 	printf("%-*s : %s\n", widest, list[n], value ? value : "(skip)");
8848 	free(value);
8849     }
8850     free(list);
8851 }
8852 
8853 char *
vt100ResourceToString(XtermWidget xw,const char * name)8854 vt100ResourceToString(XtermWidget xw, const char *name)
8855 {
8856     XtResource *data;
8857     char *result = NULL;
8858 
8859     if ((data = findVT100Resource(name)) != 0) {
8860 	int fake_offset = (int) data->resource_offset;
8861 	void *res_addr;
8862 	int real_offset;
8863 	String res_type;
8864 
8865 	/*
8866 	 * X Toolkit "compiles" the resource-list into quarks and changes the
8867 	 * resource-offset at the same time to a negative value.
8868 	 */
8869 	if (fake_offset < 0) {
8870 	    real_offset = -(fake_offset + 1);
8871 	    res_type = XrmQuarkToString((XrmQuark) (intptr_t) data->resource_type);
8872 	} else {
8873 	    real_offset = fake_offset;
8874 	    res_type = data->resource_type;
8875 	}
8876 	res_addr = (void *) ((char *) xw + real_offset);
8877 
8878 	if (!strcmp(res_type, XtRString)) {
8879 	    char *value = *(char **) res_addr;
8880 	    if (value != NULL) {
8881 		size_t need = strlen(value);
8882 		if ((result = malloc(1 + need)) != 0)
8883 		    strcpy(result, value);
8884 	    }
8885 	} else if (!strcmp(res_type, XtRInt)) {
8886 	    if ((result = malloc(1 + (size_t) (3 * data->resource_size))) != 0)
8887 		sprintf(result, "%d", *(int *) res_addr);
8888 	} else if (!strcmp(res_type, XtRFloat)) {
8889 	    if ((result = malloc(1 + (size_t) (3 * data->resource_size))) != 0)
8890 		sprintf(result, "%f", (double) (*(float *) res_addr));
8891 	} else if (!strcmp(res_type, XtRBoolean)) {
8892 	    if ((result = malloc((size_t) 6)) != 0)
8893 		strcpy(result, *(Boolean *) res_addr ? "true" : "false");
8894 	}
8895     }
8896     TRACE(("vt100ResourceToString(%s) %s\n", name, NonNull(result)));
8897     return result;
8898 }
8899 #endif /* OPT_XRES_QUERY */
8900 
8901 /*
8902  * Decode a terminal-ID or graphics-terminal-ID, using the default terminal-ID
8903  * if the value is outside a (looser) range than limitedTerminalID.  This uses
8904  * a wider range, to avoid being a nuisance when using X resources with
8905  * different configurations of xterm.
8906  */
8907 static int
decodeTerminalID(const char * value)8908 decodeTerminalID(const char *value)
8909 {
8910     const char *s;
8911     char *t;
8912     long result;
8913 
8914     for (s = value; *s; s++) {
8915 	if (!isalpha(CharOf(*s)))
8916 	    break;
8917     }
8918     result = strtol(s, &t, 10);
8919     if (t == s || *t != '\0' || result <= 0L || result > 1000L) {
8920 	xtermWarning("unexpected value for terminalID: \"%s\"\n", value);
8921 	result = atoi(DFT_DECID);
8922     }
8923     TRACE(("decodeTerminalID \"%s\" ->%d\n", value, (int) result));
8924     return (int) result;
8925 }
8926 
8927 /*
8928  * Ensures that the value returned by decodeTerminalID is either in the range
8929  * of IDs matching a known terminal, or (failing that), set to the built-in
8930  * default.  The DA response relies on having the ID being set to a known
8931  * value.
8932  */
8933 static int
limitedTerminalID(int terminal_id)8934 limitedTerminalID(int terminal_id)
8935 {
8936     if (terminal_id < MIN_DECID)
8937 	terminal_id = MIN_DECID;
8938     else if (terminal_id > MAX_DECID)
8939 	terminal_id = MAX_DECID;
8940     else
8941 	terminal_id = atoi(DFT_DECID);
8942     return terminal_id;
8943 }
8944 
8945 /* ARGSUSED */
8946 static void
VTInitialize(Widget wrequest,Widget new_arg,ArgList args GCC_UNUSED,Cardinal * num_args GCC_UNUSED)8947 VTInitialize(Widget wrequest,
8948 	     Widget new_arg,
8949 	     ArgList args GCC_UNUSED,
8950 	     Cardinal *num_args GCC_UNUSED)
8951 {
8952 #define Kolor(name) TScreenOf(wnew)->name.resource
8953 #define TxtFg(name) !x_strcasecmp(Kolor(Tcolors[TEXT_FG]), Kolor(name))
8954 #define TxtBg(name) !x_strcasecmp(Kolor(Tcolors[TEXT_BG]), Kolor(name))
8955 #define DftFg(name) isDefaultForeground(Kolor(name))
8956 #define DftBg(name) isDefaultBackground(Kolor(name))
8957 
8958 #define DATA_END   { NULL,  -1       }
8959 
8960 #if OPT_BLINK_CURS
8961 #define DATA(name) { #name, cb##name }
8962     static const FlagList tblBlinkOps[] =
8963     {
8964 	DATA(Always)
8965 	,DATA(Never)
8966 	,DATA_END
8967     };
8968 #undef DATA
8969 #endif
8970 
8971 #define DATA(name) { #name, ec##name }
8972     static const FlagList tblColorOps[] =
8973     {
8974 	DATA(SetColor)
8975 	,DATA(GetColor)
8976 	,DATA(GetAnsiColor)
8977 	,DATA_END
8978     };
8979 #undef DATA
8980 
8981 #define DATA(name) { #name, ef##name }
8982     static const FlagList tblFontOps[] =
8983     {
8984 	DATA(SetFont)
8985 	,DATA(GetFont)
8986 	,DATA_END
8987     };
8988 #undef DATA
8989 
8990 #define DATA(name) { #name, em##name }
8991     static const FlagList tblMouseOps[] =
8992     {
8993 	DATA(X10)
8994 	,DATA(Locator)
8995 	,DATA(VT200Click)
8996 	,DATA(VT200Hilite)
8997 	,DATA(AnyButton)
8998 	,DATA(AnyEvent)
8999 	,DATA(FocusEvent)
9000 	,DATA(Extended)
9001 	,DATA(SGR)
9002 	,DATA(URXVT)
9003 	,DATA(AlternateScroll)
9004 	,DATA_END
9005     };
9006 #undef DATA
9007 
9008 #define DATA(name) { #name, ep##name }
9009 #define DATA2(alias,name) { #alias, ep##name }
9010     static const FlagList tblPasteControls[] =
9011     {
9012 	DATA(NUL)
9013 	,DATA(SOH)
9014 	,DATA(STX)
9015 	,DATA(ETX)
9016 	,DATA(EOT)
9017 	,DATA(ENQ)
9018 	,DATA(ACK)
9019 	,DATA(BEL)
9020 	,DATA(BS)
9021 	,DATA(HT)
9022 	,DATA(LF)
9023 	,DATA(VT)
9024 	,DATA(FF)
9025 	,DATA(CR)
9026 	,DATA(SO)
9027 	,DATA(SI)
9028 	,DATA(DLE)
9029 	,DATA(DC1)
9030 	,DATA(DC2)
9031 	,DATA(DC3)
9032 	,DATA(DC4)
9033 	,DATA(NAK)
9034 	,DATA(SYN)
9035 	,DATA(ETB)
9036 	,DATA(CAN)
9037 	,DATA(EM)
9038 	,DATA(SUB)
9039 	,DATA(ESC)
9040 	,DATA(FS)
9041 	,DATA(GS)
9042 	,DATA(RS)
9043 	,DATA(US)
9044     /* aliases */
9045 	,DATA2(NL, LF)
9046 	,DATA(C0)
9047 	,DATA(DEL)
9048 	,DATA_END
9049     };
9050 #undef DATA
9051 #undef DATA2
9052 
9053 #define DATA(name) { #name, et##name }
9054     static const FlagList tblTcapOps[] =
9055     {
9056 	DATA(SetTcap)
9057 	,DATA(GetTcap)
9058 	,DATA_END
9059     };
9060 #undef DATA
9061 
9062 #define DATA(name) { #name, ew##name }
9063     static const FlagList tblWindowOps[] =
9064     {
9065 	DATA(RestoreWin)
9066 	,DATA(MinimizeWin)
9067 	,DATA(SetWinPosition)
9068 	,DATA(SetWinSizePixels)
9069 	,DATA(RaiseWin)
9070 	,DATA(LowerWin)
9071 	,DATA(RefreshWin)
9072 	,DATA(SetWinSizeChars)
9073 #if OPT_MAXIMIZE
9074 	,DATA(MaximizeWin)
9075 	,DATA(FullscreenWin)
9076 #endif
9077 	,DATA(GetWinState)
9078 	,DATA(GetWinPosition)
9079 	,DATA(GetWinSizePixels)
9080 	,DATA(GetWinSizeChars)
9081 #if OPT_MAXIMIZE
9082 	,DATA(GetScreenSizeChars)
9083 #endif
9084 	,DATA(GetIconTitle)
9085 	,DATA(GetWinTitle)
9086 	,DATA(PushTitle)
9087 	,DATA(PopTitle)
9088     /* this item uses all remaining numbers in the sequence */
9089 	,DATA(SetWinLines)
9090     /* starting at this point, numbers do not apply */
9091 	,DATA(SetXprop)
9092 	,DATA(GetSelection)
9093 	,DATA(SetSelection)
9094 	,DATA(GetChecksum)
9095 	,DATA(SetChecksum)
9096 	,DATA_END
9097     };
9098 #undef DATA
9099 
9100 #if OPT_RENDERFONT
9101 #define DATA(name) { #name, er##name }
9102     static const FlagList tblRenderFont[] =
9103     {
9104 	DATA(Default)
9105 	,DATA(DefaultOff)
9106 	,DATA_END
9107     };
9108 #undef DATA
9109 #endif
9110 
9111 #define DATA(name) { #name, ss##name }
9112     static const FlagList tblShift2S[] =
9113     {
9114 	DATA(Always)
9115 	,DATA(Never)
9116 	,DATA_END
9117     };
9118 #undef DATA
9119 
9120 #if OPT_WIDE_CHARS
9121 #define DATA(name) { #name, u##name }
9122     static const FlagList tblUtf8Mode[] =
9123     {
9124 	DATA(Always)
9125 	,DATA(Default)
9126 	,DATA_END
9127     };
9128 #undef DATA
9129 #endif
9130 
9131 #ifndef NO_ACTIVE_ICON
9132 #define DATA(name) { #name, ei##name }
9133     static const FlagList tblAIconOps[] =
9134     {
9135 	DATA(Default)
9136 	,DATA_END
9137     };
9138 #undef DATA
9139 #endif
9140 
9141 #define DATA(name) { #name, eb##name }
9142     static const FlagList tbl8BitMeta[] =
9143     {
9144 	DATA(Never)
9145 	,DATA(Locale)
9146 	,DATA_END
9147     };
9148 #undef DATA
9149 
9150 #define DATA(name) { #name, ed##name }
9151     static const FlagList tblCdXtraScroll[] =
9152     {
9153 	DATA(Trim)
9154 	,DATA_END
9155     };
9156 #undef DATA
9157 
9158     XtermWidget request = (XtermWidget) wrequest;
9159     XtermWidget wnew = (XtermWidget) new_arg;
9160     Widget my_parent = SHELL_OF(wnew);
9161     int i;
9162 
9163 #if OPT_ISO_COLORS
9164     Bool color_ok;
9165 #endif
9166 
9167 #if OPT_ISO_COLORS
9168     static XtResource fake_resources[] =
9169     {
9170 #if OPT_256_COLORS
9171 # include <256colres.h>
9172 #elif OPT_88_COLORS
9173 # include <88colres.h>
9174 #endif
9175     };
9176 #endif
9177 
9178     TScreen *screen = TScreenOf(wnew);
9179     char *saveLocale = xtermSetLocale(LC_NUMERIC, "C");
9180 #if OPT_BLINK_CURS
9181     int ebValue;
9182 #endif
9183 
9184 #if OPT_TRACE
9185     check_bitmasks();
9186     check_tables();
9187 #endif
9188 
9189     TRACE(("VTInitialize wnew %p, %d / %d resources " TRACE_L "\n",
9190 	   (void *) wnew, XtNumber(xterm_resources), MAXRESOURCES));
9191     assert(XtNumber(xterm_resources) < MAXRESOURCES);
9192 
9193     /* Zero out the entire "screen" component of "wnew" widget, then do
9194      * field-by-field assignment of "screen" fields that are named in the
9195      * resource list.
9196      */
9197     memset(screen, 0, sizeof(wnew->screen));
9198 
9199     /* DESCO Sys#67660
9200      * Zero out the entire "keyboard" component of "wnew" widget.
9201      */
9202     memset(&wnew->keyboard, 0, sizeof(wnew->keyboard));
9203 
9204     /*
9205      * The workspace has no resources - clear it.
9206      */
9207     memset(&wnew->work, 0, sizeof(wnew->work));
9208 
9209     /* dummy values so that we don't try to Realize the parent shell with height
9210      * or width of 0, which is illegal in X.  The real size is computed in the
9211      * xtermWidget's Realize proc, but the shell's Realize proc is called first,
9212      * and must see a valid size.
9213      */
9214     wnew->core.height = wnew->core.width = 1;
9215 
9216     /*
9217      * The definition of -rv now is that it changes the definition of
9218      * XtDefaultForeground and XtDefaultBackground.  So, we no longer
9219      * need to do anything special.
9220      */
9221     screen->display = wnew->core.screen->display;
9222 
9223     /* prep getVisualInfo() */
9224     wnew->visInfo = 0;
9225     wnew->numVisuals = 0;
9226     (void) getVisualInfo(wnew);
9227 
9228     /*
9229      * We use the default foreground/background colors to compare/check if a
9230      * color-resource has been set.
9231      */
9232 #define MyBlackPixel(dpy) BlackPixel(dpy,DefaultScreen(dpy))
9233 #define MyWhitePixel(dpy) WhitePixel(dpy,DefaultScreen(dpy))
9234 
9235     if (request->misc.re_verse) {
9236 	wnew->dft_foreground = MyWhitePixel(screen->display);
9237 	wnew->dft_background = MyBlackPixel(screen->display);
9238     } else {
9239 	wnew->dft_foreground = MyBlackPixel(screen->display);
9240 	wnew->dft_background = MyWhitePixel(screen->display);
9241     }
9242 
9243     init_Tres(TEXT_FG);
9244     init_Tres(TEXT_BG);
9245     repairColors(wnew);
9246 
9247     wnew->old_foreground = T_COLOR(screen, TEXT_FG);
9248     wnew->old_background = T_COLOR(screen, TEXT_BG);
9249 
9250     TRACE(("Color resource initialization:\n"));
9251     TRACE(("   Default foreground 0x%06lx\n", wnew->dft_foreground));
9252     TRACE(("   Default background 0x%06lx\n", wnew->dft_background));
9253     TRACE(("   Screen foreground  0x%06lx\n", T_COLOR(screen, TEXT_FG)));
9254     TRACE(("   Screen background  0x%06lx\n", T_COLOR(screen, TEXT_BG)));
9255     TRACE(("   Actual  foreground 0x%06lx\n", wnew->old_foreground));
9256     TRACE(("   Actual  background 0x%06lx\n", wnew->old_background));
9257 
9258     screen->mouse_button = 0;
9259     screen->mouse_row = -1;
9260     screen->mouse_col = -1;
9261 
9262 #if OPT_BOX_CHARS
9263     init_Bres(screen.force_box_chars);
9264     init_Bres(screen.force_packed);
9265     init_Bres(screen.force_all_chars);
9266     init_Bres(screen.assume_all_chars);
9267 #endif
9268     init_Bres(screen.free_bold_box);
9269     init_Bres(screen.allowBoldFonts);
9270 
9271     init_Bres(screen.c132);
9272     init_Bres(screen.curses);
9273     init_Bres(screen.hp_ll_bc);
9274 #if OPT_XMC_GLITCH
9275     init_Ires(screen.xmc_glitch);
9276     init_Ires(screen.xmc_attributes);
9277     init_Bres(screen.xmc_inline);
9278     init_Bres(screen.move_sgr_ok);
9279 #endif
9280 #if OPT_BLINK_CURS
9281     init_Sres(screen.cursor_blink_s);
9282     ebValue = extendedBoolean(wnew->screen.cursor_blink_s, tblBlinkOps, cbLAST);
9283     wnew->screen.cursor_blink = (BlinkOps) ebValue;
9284     init_Bres(screen.cursor_blink_xor);
9285     init_Ires(screen.blink_on);
9286     init_Ires(screen.blink_off);
9287     screen->cursor_blink_i = screen->cursor_blink;
9288 #endif
9289     init_Bres(screen.cursor_underline);
9290     /* resources allow for underline or block, not (yet) bar */
9291     InitCursorShape(screen, TScreenOf(request));
9292 #if OPT_BLINK_CURS
9293     TRACE(("cursor_shape:%d blinks:%d\n",
9294 	   screen->cursor_shape,
9295 	   screen->cursor_blink));
9296 #endif
9297 #if OPT_BLINK_TEXT
9298     init_Ires(screen.blink_as_bold);
9299 #endif
9300     init_Ires(screen.border);
9301     init_Bres(screen.jumpscroll);
9302     init_Bres(screen.fastscroll);
9303 
9304     init_Bres(screen.old_fkeys);
9305     wnew->screen.old_fkeys0 = wnew->screen.old_fkeys;
9306     wnew->keyboard.type = screen->old_fkeys
9307 	? keyboardIsLegacy
9308 	: keyboardIsDefault;
9309 
9310     init_Mres(screen.delete_is_del);
9311 #ifdef ALLOWLOGGING
9312     init_Bres(misc.logInhibit);
9313     init_Bres(misc.log_on);
9314     init_Sres(screen.logfile);
9315 #endif
9316     init_Bres(screen.bellIsUrgent);
9317     init_Bres(screen.bellOnReset);
9318     init_Bres(screen.marginbell);
9319     init_Bres(screen.multiscroll);
9320     init_Ires(screen.nmarginbell);
9321     init_Ires(screen.savelines);
9322     init_Ires(screen.scrollBarBorder);
9323     init_Ires(screen.scrolllines);
9324     init_Bres(screen.alternateScroll);
9325     init_Bres(screen.scrollttyoutput);
9326     init_Bres(screen.scrollkey);
9327 
9328     init_Dres(screen.scale_height);
9329     if (screen->scale_height < MIN_SCALE_HEIGHT)
9330 	screen->scale_height = MIN_SCALE_HEIGHT;
9331     if (screen->scale_height > MAX_SCALE_HEIGHT)
9332 	screen->scale_height = MAX_SCALE_HEIGHT;
9333 
9334     init_Bres(misc.autoWrap);
9335     init_Bres(misc.login_shell);
9336     init_Bres(misc.reverseWrap);
9337     init_Bres(misc.scrollbar);
9338     init_Sres(misc.geo_metry);
9339     init_Sres(misc.T_geometry);
9340 
9341     init_Sres(screen.term_id);
9342     screen->terminal_id = decodeTerminalID(TScreenOf(request)->term_id);
9343     /*
9344      * (1) If a known terminal model, and not a graphical terminal, preserve
9345      *     the terminal id.
9346      * (2) Otherwise, if ReGIS or sixel graphics are enabled, preserve the ID,
9347      *     even if it is not a known terminal.
9348      * (3) Otherwise force the terminal ID to the min, max, or VT420 depending
9349      *     on the input.
9350      */
9351     switch (screen->terminal_id) {
9352     case 52:			/* MIN_DECID */
9353     case 100:
9354     case 101:
9355     case 102:
9356     case 131:
9357     case 132:
9358     case 220:
9359     case 320:
9360     case 420:			/* DFT_DECID, unless overridden in configure */
9361     case 510:
9362     case 520:
9363     case 525:			/* MAX_DECID */
9364 	break;
9365     default:
9366 #if OPT_REGIS_GRAPHICS
9367 	if (optRegisGraphics(screen))
9368 	    break;
9369 #endif
9370 #if OPT_SIXEL_GRAPHICS
9371 	if (optSixelGraphics(screen))
9372 	    break;
9373 #endif
9374 	screen->terminal_id = limitedTerminalID(screen->terminal_id);
9375 	break;
9376     }
9377     TRACE(("term_id '%s' -> terminal_id %d\n",
9378 	   screen->term_id,
9379 	   screen->terminal_id));
9380 
9381     screen->vtXX_level = (screen->terminal_id / 100);
9382 
9383     init_Ires(screen.title_modes);
9384     screen->title_modes0 = screen->title_modes;
9385 
9386     init_Ires(screen.nextEventDelay);
9387     if (screen->nextEventDelay <= 0)
9388 	screen->nextEventDelay = 1;
9389 
9390     init_Bres(screen.visualbell);
9391     init_Bres(screen.flash_line);
9392     init_Ires(screen.visualBellDelay);
9393     init_Bres(screen.poponbell);
9394 
9395     init_Bres(screen.eraseSavedLines0);
9396     screen->eraseSavedLines = screen->eraseSavedLines0;
9397 
9398     init_Ires(misc.limit_resize);
9399 
9400 #if OPT_NUM_LOCK
9401     init_Bres(misc.real_NumLock);
9402     init_Bres(misc.alwaysUseMods);
9403 #endif
9404 
9405 #if OPT_INPUT_METHOD
9406     init_Bres(misc.open_im);
9407     init_Ires(misc.retry_im);
9408     init_Sres(misc.f_x);
9409     init_Sres(misc.input_method);
9410     init_Sres(misc.preedit_type);
9411 #endif
9412 
9413 #if OPT_SHIFT_FONTS
9414     init_Bres(misc.shift_fonts);
9415 #endif
9416 #if OPT_SUNPC_KBD
9417     init_Ires(misc.ctrl_fkeys);
9418 #endif
9419 #if OPT_TEK4014
9420     TEK4014_SHOWN(wnew) = False;	/* not a resource... */
9421     init_Bres(misc.tekInhibit);
9422     init_Bres(misc.tekSmall);
9423     init_Bres(misc.TekEmu);
9424 #endif
9425 #if OPT_TCAP_QUERY
9426     screen->tc_query_code = -1;
9427 #endif
9428     wnew->misc.re_verse0 = request->misc.re_verse;
9429     init_Bres(misc.re_verse);
9430     init_Ires(screen.multiClickTime);
9431     init_Ires(screen.bellSuppressTime);
9432     init_Sres(screen.charClass);
9433 
9434     init_Bres(screen.always_highlight);
9435     init_Bres(screen.brokenSelections);
9436     init_Bres(screen.cutNewline);
9437     init_Bres(screen.cutToBeginningOfLine);
9438     init_Bres(screen.highlight_selection);
9439     init_Bres(screen.show_wrap_marks);
9440     init_Bres(screen.i18nSelections);
9441     init_Bres(screen.keepClipboard);
9442     init_Bres(screen.keepSelection);
9443     init_Bres(screen.selectToClipboard);
9444     init_Bres(screen.trim_selection);
9445 
9446     screen->pointer_cursor = TScreenOf(request)->pointer_cursor;
9447     init_Ires(screen.pointer_mode);
9448     wnew->screen.pointer_mode0 = wnew->screen.pointer_mode;
9449 
9450     init_Sres(screen.answer_back);
9451 
9452     wnew->SPS.printer_checked = False;
9453     init_Sres(SPS.printer_command);
9454     init_Bres(SPS.printer_autoclose);
9455     init_Bres(SPS.printer_extent);
9456     init_Bres(SPS.printer_formfeed);
9457     init_Bres(SPS.printer_newline);
9458     init_Ires(SPS.printer_controlmode);
9459 #if OPT_PRINT_COLORS
9460     init_Ires(SPS.print_attributes);
9461 #endif
9462 
9463     init_Sres(screen.keyboard_dialect);
9464 
9465     init_Sres(screen.cursor_font_name);
9466     init_Sres(screen.pointer_shape);
9467 
9468     init_Bres(screen.input_eight_bits);
9469     init_Bres(screen.output_eight_bits);
9470     init_Bres(screen.control_eight_bits);
9471     init_Bres(screen.backarrow_key);
9472     init_Bres(screen.alt_is_not_meta);
9473     init_Bres(screen.alt_sends_esc);
9474     init_Bres(screen.meta_sends_esc);
9475 
9476     init_Bres(screen.allowPasteControl0);
9477     init_Bres(screen.allowSendEvent0);
9478     init_Bres(screen.allowColorOp0);
9479     init_Bres(screen.allowFontOp0);
9480     init_Bres(screen.allowMouseOp0);
9481     init_Bres(screen.allowTcapOp0);
9482     init_Bres(screen.allowTitleOp0);
9483     init_Bres(screen.allowWindowOp0);
9484 
9485 #if OPT_SCROLL_LOCK
9486     init_Bres(screen.allowScrollLock0);
9487     init_Bres(screen.autoScrollLock);
9488 #endif
9489 
9490     init_Sres(screen.disallowedColorOps);
9491 
9492     set_flags_from_list(screen->disallow_color_ops,
9493 			screen->disallowedColorOps,
9494 			tblColorOps);
9495 
9496     init_Sres(screen.disallowedFontOps);
9497 
9498     set_flags_from_list(screen->disallow_font_ops,
9499 			screen->disallowedFontOps,
9500 			tblFontOps);
9501 
9502     init_Sres(screen.disallowedMouseOps);
9503 
9504     set_flags_from_list(screen->disallow_mouse_ops,
9505 			screen->disallowedMouseOps,
9506 			tblMouseOps);
9507 
9508     init_Sres(screen.disallowedPasteControls);
9509 
9510     set_flags_from_list(screen->disallow_paste_controls,
9511 			screen->disallowedPasteControls,
9512 			tblPasteControls);
9513 
9514     init_Sres(screen.disallowedTcapOps);
9515 
9516     set_flags_from_list(screen->disallow_tcap_ops,
9517 			screen->disallowedTcapOps,
9518 			tblTcapOps);
9519 
9520     init_Sres(screen.disallowedWinOps);
9521 
9522     set_flags_from_list(screen->disallow_win_ops,
9523 			screen->disallowedWinOps,
9524 			tblWindowOps);
9525 
9526     init_Sres(screen.default_string);
9527     init_Sres(screen.eightbit_select_types);
9528 #if OPT_WIDE_CHARS
9529     init_Sres(screen.utf8_select_types);
9530 #endif
9531 
9532     /* make a copy so that editres cannot change the resource after startup */
9533     screen->allowPasteControls = screen->allowPasteControl0;
9534     screen->allowSendEvents = screen->allowSendEvent0;
9535     screen->allowColorOps = screen->allowColorOp0;
9536     screen->allowFontOps = screen->allowFontOp0;
9537     screen->allowMouseOps = screen->allowMouseOp0;
9538     screen->allowTcapOps = screen->allowTcapOp0;
9539     screen->allowTitleOps = screen->allowTitleOp0;
9540     screen->allowWindowOps = screen->allowWindowOp0;
9541 
9542 #if OPT_SCROLL_LOCK
9543     screen->allowScrollLock = screen->allowScrollLock0;
9544 #endif
9545 
9546     init_Bres(screen.quiet_grab);
9547 
9548 #ifndef NO_ACTIVE_ICON
9549     init_Sres(screen.icon_fontname);
9550     getIconicFont(screen)->fs = xtermLoadQueryFont(wnew,
9551 						   screen->icon_fontname);
9552     TRACE(("iconFont '%s' %sloaded successfully\n",
9553 	   screen->icon_fontname,
9554 	   getIconicFont(screen)->fs ? "" : "NOT "));
9555     init_Sres(misc.active_icon_s);
9556     wnew->work.active_icon =
9557 	(Boolean) extendedBoolean(wnew->misc.active_icon_s,
9558 				  tblAIconOps, eiLAST);
9559     init_Ires(misc.icon_border_width);
9560     wnew->misc.icon_border_pixel = request->misc.icon_border_pixel;
9561 #endif /* NO_ACTIVE_ICON */
9562 
9563     init_Bres(misc.signalInhibit);
9564     init_Bres(misc.titeInhibit);
9565     init_Bres(misc.color_inner_border);
9566     init_Bres(misc.dynamicColors);
9567     init_Bres(misc.resizeByPixel);
9568 
9569     init_Sres(misc.cdXtraScroll_s);
9570     wnew->misc.cdXtraScroll =
9571 	extendedBoolean(request->misc.cdXtraScroll_s, tblCdXtraScroll, edLast);
9572 
9573     init_Sres(misc.tiXtraScroll_s);
9574     wnew->misc.tiXtraScroll =
9575 	extendedBoolean(request->misc.tiXtraScroll_s, tblCdXtraScroll, edLast);
9576 
9577 #if OPT_DEC_CHRSET
9578     for (i = 0; i < NUM_CHRSET; i++) {
9579 	screen->double_fonts[i].warn = fwResource;
9580     }
9581 #endif
9582     for (i = fontMenu_font1; i <= fontMenu_lastBuiltin; i++) {
9583 	init_Sres2(screen.MenuFontName, i);
9584     }
9585     for (i = 0; i < fMAX; i++) {
9586 	screen->fnts[i].warn = fwResource;
9587 #if OPT_WIDE_ATTRS
9588 	screen->ifnts[i].warn = fwResource;
9589 #endif
9590     }
9591 #ifndef NO_ACTIVE_ICON
9592     screen->fnt_icon.warn = fwResource;
9593 #endif
9594 
9595     init_Ires(misc.fontWarnings);
9596 
9597     initFontLists(wnew);
9598 
9599 #define DefaultFontNames screen->menu_font_names[fontMenu_default]
9600 
9601     /*
9602      * Process Xft font resources first, since faceName may contain X11 fonts
9603      * that should override the "font" resource.
9604      */
9605 #if OPT_RENDERFONT
9606     init_Bres(screen.force_xft_height);
9607     for (i = 0; i <= fontMenu_lastBuiltin; ++i) {
9608 	init_Dres2(misc.face_size, i);
9609     }
9610 
9611 #define ALLOC_FONTLIST(name,which,field) \
9612     init_Sres(misc.default_xft.field);\
9613     allocFontList(wnew,\
9614 		  name,\
9615 		  &(wnew->work.fonts),\
9616 		  which,\
9617 		  wnew->misc.default_xft.field,\
9618 		  True)
9619 
9620     ALLOC_FONTLIST(XtNfaceName, fNorm, f_n);
9621 
9622 #if OPT_WIDE_CHARS
9623     ALLOC_FONTLIST(XtNfaceNameDoublesize, fWide, f_w);
9624 #endif
9625 
9626 #undef ALLOC_FONTLIST
9627 
9628 #endif
9629 
9630     /*
9631      * Process X11 (XLFD) font specifications.
9632      */
9633 #define ALLOC_FONTLIST(name,which,field) \
9634     init_Sres(misc.default_font.field);\
9635     allocFontList(wnew,\
9636 		  name,\
9637 		  &(wnew->work.fonts),\
9638 		  which,\
9639 		  wnew->misc.default_font.field,\
9640 		  False)
9641 
9642     ALLOC_FONTLIST(XtNfont, fNorm, f_n);
9643     ALLOC_FONTLIST(XtNboldFont, fBold, f_b);
9644 
9645     DefaultFontNames[fNorm] = x_strdup(DefaultFontN(wnew));
9646     DefaultFontNames[fBold] = x_strdup(DefaultFontB(wnew));
9647 
9648 #if OPT_WIDE_CHARS
9649     ALLOC_FONTLIST(XtNwideFont, fWide, f_w);
9650     ALLOC_FONTLIST(XtNwideBoldFont, fWBold, f_wb);
9651 
9652     DefaultFontNames[fWide] = x_strdup(DefaultFontW(wnew));
9653     DefaultFontNames[fWBold] = x_strdup(DefaultFontWB(wnew));
9654 #endif
9655 
9656 #undef ALLOC_FONTLIST
9657 
9658     screen->EscapeFontName() = NULL;
9659     screen->SelectFontName() = NULL;
9660 
9661     screen->menu_font_number = fontMenu_default;
9662     init_Sres(screen.initial_font);
9663     if (screen->initial_font != 0) {
9664 	int result = xtermGetFont(screen->initial_font);
9665 	if (result >= 0)
9666 	    screen->menu_font_number = result;
9667     }
9668 #if OPT_BROKEN_OSC
9669     init_Bres(screen.brokenLinuxOSC);
9670 #endif
9671 
9672 #if OPT_BROKEN_ST
9673     init_Bres(screen.brokenStringTerm);
9674 #endif
9675 
9676 #if OPT_C1_PRINT
9677     init_Bres(screen.c1_printable);
9678 #endif
9679 
9680 #if OPT_CLIP_BOLD
9681     init_Bres(screen.use_border_clipping);
9682     init_Bres(screen.use_clipping);
9683 #endif
9684 
9685 #if OPT_DEC_CHRSET
9686     init_Bres(screen.font_doublesize);
9687     init_Ires(screen.cache_doublesize);
9688     if (screen->cache_doublesize > NUM_CHRSET)
9689 	screen->cache_doublesize = NUM_CHRSET;
9690     if (screen->cache_doublesize == 0)
9691 	screen->font_doublesize = False;
9692     TRACE(("Doublesize%s enabled, up to %d fonts\n",
9693 	   screen->font_doublesize ? "" : " not",
9694 	   screen->cache_doublesize));
9695 #endif
9696 #if OPT_DEC_RECTOPS
9697     init_Ires(screen.checksum_ext0);
9698     screen->checksum_ext = screen->checksum_ext0;
9699 #endif
9700 
9701 #if OPT_ISO_COLORS
9702     init_Ires(screen.veryBoldColors);
9703     init_Bres(screen.boldColors);
9704     init_Bres(screen.colorAttrMode);
9705     init_Bres(screen.colorBDMode);
9706     init_Bres(screen.colorBLMode);
9707     init_Bres(screen.colorMode);
9708     init_Bres(screen.colorULMode);
9709     init_Bres(screen.italicULMode);
9710     init_Bres(screen.colorRVMode);
9711 
9712 #if OPT_WIDE_ATTRS
9713     init_Bres(screen.colorITMode);
9714 #endif
9715 #if OPT_DIRECT_COLOR
9716     init_Bres(screen.direct_color);
9717 #endif
9718 
9719     TRACE(("...will fake resources for color%d to color%d\n",
9720 	   MIN_ANSI_COLORS,
9721 	   NUM_ANSI_COLORS - 1));
9722 
9723     for (i = 0, color_ok = False; i < MAXCOLORS; i++) {
9724 	/*
9725 	 * Xt has a hardcoded limit on the maximum number of resources that can
9726 	 * be used in a widget.  If we configured both luit (which implies
9727 	 * wide-characters) and 256-colors, it goes over that limit.  Most
9728 	 * people would not need a resource-file with 256-colors; the default
9729 	 * values in our table are sufficient.  Fake the resource setting by
9730 	 * copying the default value from the table.  The #define's can be
9731 	 * overridden to make these true resources.
9732 	 */
9733 	if (i >= MIN_ANSI_COLORS && i < NUM_ANSI_COLORS) {
9734 	    screen->Acolors[i].resource =
9735 		x_strtrim(fake_resources[i - MIN_ANSI_COLORS].default_addr);
9736 	    if (screen->Acolors[i].resource == 0)
9737 		screen->Acolors[i].resource = XtDefaultForeground;
9738 	} else {
9739 	    screen->Acolors[i] = TScreenOf(request)->Acolors[i];
9740 	    screen->Acolors[i].resource =
9741 		x_strtrim(screen->Acolors[i].resource);
9742 	}
9743 
9744 	TRACE(("Acolors[%d] = %s\n", i, screen->Acolors[i].resource));
9745 	screen->Acolors[i].mode = False;
9746 	if (DftFg(Acolors[i])) {
9747 	    screen->Acolors[i].value = T_COLOR(screen, TEXT_FG);
9748 	    screen->Acolors[i].mode = True;
9749 	} else if (DftBg(Acolors[i])) {
9750 	    screen->Acolors[i].value = T_COLOR(screen, TEXT_BG);
9751 	    screen->Acolors[i].mode = True;
9752 	} else {
9753 	    color_ok = True;
9754 	}
9755     }
9756 
9757     /*
9758      * Check if we're trying to use color in a monochrome screen.  Disable
9759      * color in that case, since that would make ANSI colors unusable.  A 4-bit
9760      * or 8-bit display is usable, so we do not have to check for anything more
9761      * specific.
9762      */
9763     if (color_ok) {
9764 	if (getVisualDepth(wnew) <= 1) {
9765 	    TRACE(("disabling color since screen is monochrome\n"));
9766 	    color_ok = False;
9767 	}
9768     }
9769 
9770     /* If none of the colors are anything other than the foreground or
9771      * background, we'll assume this isn't color, no matter what the colorMode
9772      * resource says.  (There doesn't seem to be any good way to determine if
9773      * the resource lookup failed versus the user having misconfigured this).
9774      */
9775     if (!color_ok) {
9776 	screen->colorMode = False;
9777 	TRACE(("All colors are foreground or background: disable colorMode\n"));
9778     }
9779     wnew->sgr_foreground = -1;
9780     wnew->sgr_background = -1;
9781     wnew->sgr_38_xcolors = False;
9782     clrDirectFG(wnew->flags);
9783     clrDirectFG(wnew->flags);
9784 #endif /* OPT_ISO_COLORS */
9785 
9786     /*
9787      * Decode the resources that control the behavior on multiple mouse clicks.
9788      * A single click is always bound to normal character selection, but the
9789      * other flavors can be changed.
9790      */
9791     for (i = 0; i < NSELECTUNITS; ++i) {
9792 	int ck = (i + 1);
9793 	screen->maxClicks = ck;
9794 	if (i == Select_CHAR)
9795 	    screen->selectMap[i] = Select_CHAR;
9796 	else if (TScreenOf(request)->onClick[i] != 0)
9797 	    ParseOnClicks(wnew, request, (unsigned) i);
9798 	else if (i <= Select_LINE)
9799 	    screen->selectMap[i] = (SelectUnit) i;
9800 	else
9801 	    break;
9802 #if OPT_XRES_QUERY
9803 	init_Sres(screen.onClick[i]);
9804 #endif
9805 	TRACE(("on%dClicks %s=%d\n", ck,
9806 	       NonNull(TScreenOf(request)->onClick[i]),
9807 	       screen->selectMap[i]));
9808 	if (screen->selectMap[i] == NSELECTUNITS)
9809 	    break;
9810     }
9811     TRACE(("maxClicks %d\n", screen->maxClicks));
9812 
9813     init_Tres(MOUSE_FG);
9814     init_Tres(MOUSE_BG);
9815     init_Tres(TEXT_CURSOR);
9816 #if OPT_HIGHLIGHT_COLOR
9817     init_Tres(HIGHLIGHT_BG);
9818     init_Tres(HIGHLIGHT_FG);
9819     init_Bres(screen.hilite_reverse);
9820     init_Mres(screen.hilite_color);
9821     if (screen->hilite_color == Maybe) {
9822 	screen->hilite_color = False;
9823 	/*
9824 	 * If the highlight text/background are both set, and if they are
9825 	 * not equal to either the text/background or background/text, then
9826 	 * set the highlightColorMode automatically.
9827 	 */
9828 	if (!DftFg(Tcolors[HIGHLIGHT_BG])
9829 	    && !DftBg(Tcolors[HIGHLIGHT_FG])
9830 	    && !TxtFg(Tcolors[HIGHLIGHT_BG])
9831 	    && !TxtBg(Tcolors[HIGHLIGHT_FG])
9832 	    && !TxtBg(Tcolors[HIGHLIGHT_BG])
9833 	    && !TxtFg(Tcolors[HIGHLIGHT_FG])) {
9834 	    TRACE(("...setting hilite_color automatically\n"));
9835 	    screen->hilite_color = True;
9836 	}
9837     }
9838 #endif
9839 
9840 #if OPT_TEK4014
9841     /*
9842      * The Tek4014 window has no separate resources for foreground, background
9843      * and cursor color.  Since xterm always creates the vt100 widget first, we
9844      * can set the Tektronix colors here.  That lets us use escape sequences to
9845      * set its dynamic colors and get consistent behavior whether or not the
9846      * window is displayed.
9847      */
9848     screen->Tcolors[TEK_BG] = screen->Tcolors[TEXT_BG];
9849     screen->Tcolors[TEK_FG] = screen->Tcolors[TEXT_FG];
9850     screen->Tcolors[TEK_CURSOR] = screen->Tcolors[TEXT_CURSOR];
9851 #endif
9852 
9853 #ifdef SCROLLBAR_RIGHT
9854     init_Bres(misc.useRight);
9855 #endif
9856 
9857 #if OPT_RENDERFONT
9858     init_Ires(misc.limit_fontsets);
9859     wnew->work.max_fontsets = (unsigned) wnew->misc.limit_fontsets;
9860 
9861     init_Sres(misc.render_font_s);
9862     wnew->work.render_font =
9863 	(Boolean) extendedBoolean(wnew->misc.render_font_s,
9864 				  tblRenderFont, erLast);
9865     if (wnew->work.render_font == erDefault) {
9866 	if (IsEmpty(CurrentXftFont(wnew))) {
9867 	    free((void *) CurrentXftFont(wnew));
9868 	    CurrentXftFont(wnew) = x_strdup(DEFFACENAME_AUTO);
9869 	    TRACE(("will allow runtime switch to render_font using \"%s\"\n",
9870 		   CurrentXftFont(wnew)));
9871 	} else {
9872 	    wnew->work.render_font = erTrue;
9873 	    TRACE(("initially using TrueType font\n"));
9874 	}
9875     } else if (wnew->work.render_font == erDefaultOff) {
9876 	wnew->work.render_font = erFalse;
9877     }
9878     /* minor tweak to make debug traces consistent: */
9879     if (wnew->work.render_font) {
9880 	if (IsEmpty(CurrentXftFont(wnew))) {
9881 	    wnew->work.render_font = False;
9882 	    TRACE(("reset render_font since there is no face_name\n"));
9883 	}
9884     }
9885 #endif
9886 
9887 #if OPT_WIDE_CHARS
9888     /* setup data for next call */
9889     init_Sres(screen.utf8_mode_s);
9890     request->screen.utf8_mode =
9891 	extendedBoolean(request->screen.utf8_mode_s, tblUtf8Mode, uLast);
9892 
9893     init_Sres(screen.utf8_fonts_s);
9894     request->screen.utf8_fonts =
9895 	extendedBoolean(request->screen.utf8_fonts_s, tblUtf8Mode, uLast);
9896 
9897     init_Sres(screen.utf8_title_s);
9898     request->screen.utf8_title =
9899 	extendedBoolean(request->screen.utf8_title_s, tblUtf8Mode, uLast);
9900 
9901     /*
9902      * Make a copy in the input/request so that DefaultFontN() works for
9903      * the "CHECKFONT" option.
9904      */
9905     copyFontList(&(request->work.fonts.x11.list_n),
9906 		 wnew->work.fonts.x11.list_n);
9907 
9908     VTInitialize_locale(request);
9909     init_Bres(screen.normalized_c);
9910     init_Bres(screen.utf8_latin1);
9911     init_Bres(screen.utf8_weblike);
9912 
9913 #if OPT_LUIT_PROG
9914     init_Bres(misc.callfilter);
9915     init_Bres(misc.use_encoding);
9916     init_Sres(misc.locale_str);
9917     init_Sres(misc.localefilter);
9918 #endif
9919 
9920     init_Ires(screen.utf8_inparse);
9921     init_Ires(screen.utf8_mode);
9922     init_Ires(screen.utf8_fonts);
9923     init_Ires(screen.utf8_title);
9924     init_Ires(screen.max_combining);
9925 
9926     init_Ires(screen.utf8_always);	/* from utf8_mode, used in doparse */
9927 
9928     if (screen->max_combining < 0) {
9929 	screen->max_combining = 0;
9930     }
9931     if (screen->max_combining > 5) {
9932 	screen->max_combining = 5;
9933     }
9934 
9935     init_Bres(screen.vt100_graphics);
9936     init_Bres(screen.wide_chars);
9937     init_Bres(misc.mk_width);
9938     init_Bres(misc.cjk_width);
9939 
9940     init_Ires(misc.mk_samplesize);
9941     init_Ires(misc.mk_samplepass);
9942 
9943     if (wnew->misc.mk_samplesize > 0xffff)
9944 	wnew->misc.mk_samplesize = 0xffff;
9945     if (wnew->misc.mk_samplesize < 0)
9946 	wnew->misc.mk_samplesize = 0;
9947 
9948     if (wnew->misc.mk_samplepass > wnew->misc.mk_samplesize)
9949 	wnew->misc.mk_samplepass = wnew->misc.mk_samplesize;
9950     if (wnew->misc.mk_samplepass < 0)
9951 	wnew->misc.mk_samplepass = 0;
9952 
9953     if (TScreenOf(request)->utf8_mode) {
9954 	TRACE(("setting wide_chars on\n"));
9955 	screen->wide_chars = True;
9956     } else {
9957 	TRACE(("setting utf8_mode to 0\n"));
9958 	screen->utf8_mode = uFalse;
9959     }
9960     mk_wcwidth_init(screen->utf8_mode);
9961     TRACE(("initialized UTF-8 mode to %d\n", screen->utf8_mode));
9962 
9963 #if OPT_MINI_LUIT
9964     if (TScreenOf(request)->latin9_mode) {
9965 	screen->latin9_mode = True;
9966     }
9967     if (TScreenOf(request)->unicode_font) {
9968 	screen->unicode_font = True;
9969     }
9970     TRACE(("initialized Latin9 mode to %d\n", screen->latin9_mode));
9971     TRACE(("initialized unicode_font to %d\n", screen->unicode_font));
9972 #endif
9973 
9974     decode_wcwidth(wnew);
9975     xtermSaveVTFonts(wnew);
9976 #endif /* OPT_WIDE_CHARS */
9977 
9978     init_Sres(screen.eight_bit_meta_s);
9979     wnew->screen.eight_bit_meta =
9980 	extendedBoolean(request->screen.eight_bit_meta_s, tbl8BitMeta, ebLast);
9981     if (wnew->screen.eight_bit_meta == ebLocale) {
9982 #if OPT_WIDE_CHARS
9983 	if (xtermEnvUTF8()) {
9984 	    wnew->screen.eight_bit_meta = ebFalse;
9985 	    TRACE(("...eightBitMeta is false due to locale\n"));
9986 	} else
9987 #endif /* OPT_WIDE_CHARS */
9988 	{
9989 	    wnew->screen.eight_bit_meta = ebTrue;
9990 	    TRACE(("...eightBitMeta is true due to locale\n"));
9991 	}
9992     }
9993 
9994     init_Bres(screen.always_bold_mode);
9995     init_Bres(screen.bold_mode);
9996     init_Bres(screen.underline);
9997 
9998     wnew->cur_foreground = 0;
9999     wnew->cur_background = 0;
10000 
10001     wnew->keyboard.flags = MODE_SRM;
10002 
10003     if (screen->backarrow_key)
10004 	wnew->keyboard.flags |= MODE_DECBKM;
10005     TRACE(("initialized DECBKM %s\n",
10006 	   BtoS(wnew->keyboard.flags & MODE_DECBKM)));
10007 
10008 #if OPT_SIXEL_GRAPHICS
10009     init_Bres(screen.sixel_scrolling);
10010     if (screen->sixel_scrolling)
10011 	wnew->keyboard.flags |= MODE_DECSDM;
10012     TRACE(("initialized DECSDM %s\n",
10013 	   BtoS(wnew->keyboard.flags & MODE_DECSDM)));
10014 #endif
10015 
10016 #if OPT_GRAPHICS
10017     init_Sres(screen.graph_termid);
10018     screen->graphics_termid = decodeTerminalID(TScreenOf(request)->graph_termid);
10019     switch (screen->graphics_termid) {
10020     case 125:
10021     case 240:
10022     case 241:
10023     case 330:
10024     case 340:
10025     case 382:
10026 	break;
10027     default:
10028 	screen->graphics_termid = 0;
10029 	break;
10030     }
10031     TRACE(("graph_termid '%s' -> graphics_termid %d\n",
10032 	   screen->graph_termid,
10033 	   screen->graphics_termid));
10034 
10035     init_Ires(screen.numcolorregisters);
10036     TRACE(("initialized NUM_COLOR_REGISTERS to resource default: %d\n",
10037 	   screen->numcolorregisters));
10038 
10039     init_Bres(screen.privatecolorregisters);	/* FIXME: should this be off unconditionally here? */
10040     TRACE(("initialized PRIVATE_COLOR_REGISTERS to resource default: %s\n",
10041 	   BtoS(screen->privatecolorregisters)));
10042 #endif
10043 
10044 #if OPT_GRAPHICS
10045     {
10046 	int native_w, native_h;
10047 
10048 	switch (GraphicsTermId(screen)) {
10049 	case 125:
10050 	    native_w = 768;
10051 	    native_h = 460;
10052 	    break;
10053 	case 240:
10054 	    /* FALLTHRU */
10055 	case 241:
10056 	    native_w = 800;
10057 	    native_h = 460;
10058 	    break;
10059 	case 330:
10060 	    /* FALLTHRU */
10061 	case 340:
10062 	    native_w = 800;
10063 	    native_h = 480;
10064 	    break;
10065 	default:
10066 	    native_w = 800;
10067 	    native_h = 480;
10068 	    break;
10069 	case 382:
10070 	    native_w = 960;
10071 	    native_h = 750;
10072 	    break;
10073 	}
10074 
10075 # if OPT_REGIS_GRAPHICS
10076 	init_Sres(screen.graphics_regis_default_font);
10077 	TRACE(("default ReGIS font: %s\n",
10078 	       screen->graphics_regis_default_font));
10079 
10080 	init_Sres(screen.graphics_regis_screensize);
10081 	screen->graphics_regis_def_high = 1000;
10082 	screen->graphics_regis_def_wide = 1000;
10083 	if (!x_strcasecmp(screen->graphics_regis_screensize, "auto")) {
10084 	    TRACE(("setting default ReGIS screensize based on graphics_id %d\n",
10085 		   GraphicsTermId(screen)));
10086 	    screen->graphics_regis_def_high = (Dimension) native_h;
10087 	    screen->graphics_regis_def_wide = (Dimension) native_w;
10088 	} else {
10089 	    int conf_high;
10090 	    int conf_wide;
10091 	    char ignore;
10092 
10093 	    if (sscanf(screen->graphics_regis_screensize,
10094 		       "%dx%d%c",
10095 		       &conf_wide,
10096 		       &conf_high,
10097 		       &ignore) == 2) {
10098 		if (conf_high > 0 && conf_wide > 0) {
10099 		    screen->graphics_regis_def_high =
10100 			(Dimension) conf_high;
10101 		    screen->graphics_regis_def_wide =
10102 			(Dimension) conf_wide;
10103 		} else {
10104 		    TRACE(("ignoring invalid regisScreenSize %s\n",
10105 			   screen->graphics_regis_screensize));
10106 		}
10107 	    } else {
10108 		TRACE(("ignoring invalid regisScreenSize %s\n",
10109 		       screen->graphics_regis_screensize));
10110 	    }
10111 	}
10112 	TRACE(("default ReGIS graphics screensize %dx%d\n",
10113 	       (int) screen->graphics_regis_def_wide,
10114 	       (int) screen->graphics_regis_def_high));
10115 # endif
10116 
10117 	init_Sres(screen.graphics_max_size);
10118 	screen->graphics_max_high = 1000;
10119 	screen->graphics_max_wide = 1000;
10120 	if (!x_strcasecmp(screen->graphics_max_size, "auto")) {
10121 	    TRACE(("setting max graphics screensize based on graphics_id %d\n",
10122 		   GraphicsTermId(screen)));
10123 	    screen->graphics_max_high = (Dimension) native_h;
10124 	    screen->graphics_max_wide = (Dimension) native_w;
10125 	} else {
10126 	    int conf_high;
10127 	    int conf_wide;
10128 	    char ignore;
10129 
10130 	    if (sscanf(screen->graphics_max_size,
10131 		       "%dx%d%c",
10132 		       &conf_wide,
10133 		       &conf_high,
10134 		       &ignore) == 2) {
10135 		if (conf_high > 0 && conf_wide > 0) {
10136 		    screen->graphics_max_high = (Dimension) conf_high;
10137 		    screen->graphics_max_wide = (Dimension) conf_wide;
10138 		} else {
10139 		    TRACE(("ignoring invalid maxGraphicSize %s\n",
10140 			   screen->graphics_max_size));
10141 		}
10142 	    } else {
10143 		TRACE(("ignoring invalid maxGraphicSize %s\n",
10144 		       screen->graphics_max_size));
10145 	    }
10146 	}
10147 # if OPT_REGIS_GRAPHICS
10148 	/* Make sure the max is large enough for the default ReGIS size. */
10149 	if (screen->graphics_regis_def_high >
10150 	    screen->graphics_max_high) {
10151 	    screen->graphics_max_high =
10152 		screen->graphics_regis_def_high;
10153 	}
10154 	if (screen->graphics_regis_def_wide >
10155 	    screen->graphics_max_wide) {
10156 	    screen->graphics_max_wide =
10157 		screen->graphics_regis_def_wide;
10158 	}
10159 # endif
10160 	TRACE(("max graphics screensize %dx%d\n",
10161 	       (int) screen->graphics_max_wide,
10162 	       (int) screen->graphics_max_high));
10163     }
10164 #endif
10165 
10166 #if OPT_SIXEL_GRAPHICS
10167     init_Bres(screen.sixel_scrolls_right);
10168 #endif
10169 #if OPT_PRINT_GRAPHICS
10170     init_Bres(screen.graphics_print_to_host);
10171     init_Bres(screen.graphics_expanded_print_mode);
10172     init_Bres(screen.graphics_print_color_mode);
10173     init_Bres(screen.graphics_print_color_syntax);
10174     init_Bres(screen.graphics_print_background_mode);
10175     init_Bres(screen.graphics_rotated_print_mode);
10176 #endif
10177 
10178     /* look for focus related events on the shell, because we need
10179      * to care about the shell's border being part of our focus.
10180      */
10181     TRACE(("adding event handlers for my_parent %p\n", (void *) my_parent));
10182     XtAddEventHandler(my_parent, EnterWindowMask, False,
10183 		      HandleEnterWindow, (Opaque) NULL);
10184     XtAddEventHandler(my_parent, LeaveWindowMask, False,
10185 		      HandleLeaveWindow, (Opaque) NULL);
10186     XtAddEventHandler(my_parent, FocusChangeMask, False,
10187 		      HandleFocusChange, (Opaque) NULL);
10188     XtAddEventHandler((Widget) wnew, 0L, True,
10189 		      VTNonMaskableEvent, (Opaque) NULL);
10190     XtAddEventHandler((Widget) wnew, PropertyChangeMask, False,
10191 		      HandleBellPropertyChange, (Opaque) NULL);
10192 
10193 #if HANDLE_STRUCT_NOTIFY
10194 #if OPT_TOOLBAR
10195     wnew->VT100_TB_INFO(menu_bar) = request->VT100_TB_INFO(menu_bar);
10196     init_Ires(VT100_TB_INFO(menu_height));
10197 #endif
10198     XtAddEventHandler(my_parent, MappingNotify | StructureNotifyMask, False,
10199 		      HandleStructNotify, (Opaque) 0);
10200 #endif /* HANDLE_STRUCT_NOTIFY */
10201 
10202     screen->bellInProgress = False;
10203 
10204     set_character_class(screen->charClass);
10205 #if OPT_REPORT_CCLASS
10206     if (resource.reportCClass)
10207 	report_char_class(wnew);
10208 #endif
10209 
10210     /* create it, but don't realize it */
10211     ScrollBarOn(wnew, True);
10212 
10213     /* make sure that the resize gravity acceptable */
10214     if (!GravityIsNorthWest(wnew) &&
10215 	!GravityIsSouthWest(wnew)) {
10216 	char value[80];
10217 	String temp[2];
10218 	Cardinal nparams = 1;
10219 
10220 	sprintf(value, "%d", wnew->misc.resizeGravity);
10221 	temp[0] = value;
10222 	temp[1] = 0;
10223 	XtAppWarningMsg(app_con, "rangeError", "resizeGravity", "XTermError",
10224 			"unsupported resizeGravity resource value (%s)",
10225 			temp, &nparams);
10226 	wnew->misc.resizeGravity = SouthWestGravity;
10227     }
10228 #ifndef NO_ACTIVE_ICON
10229     screen->whichVwin = &screen->fullVwin;
10230 #endif /* NO_ACTIVE_ICON */
10231 
10232     init_Ires(screen.unparse_max);
10233     if ((int) screen->unparse_max < 256)
10234 	screen->unparse_max = 256;
10235     screen->unparse_bfr = (IChar *) (void *) XtCalloc(screen->unparse_max,
10236 						      (Cardinal) sizeof(IChar));
10237 
10238     if (screen->savelines < 0)
10239 	screen->savelines = 0;
10240 
10241     init_Bres(screen.awaitInput);
10242 
10243     wnew->flags = 0;
10244     if (!screen->jumpscroll)
10245 	wnew->flags |= SMOOTHSCROLL;
10246     if (wnew->misc.reverseWrap)
10247 	wnew->flags |= REVERSEWRAP;
10248     if (wnew->misc.autoWrap)
10249 	wnew->flags |= WRAPAROUND;
10250     if (wnew->misc.re_verse != wnew->misc.re_verse0)
10251 	wnew->flags |= REVERSE_VIDEO;
10252     if (screen->c132)
10253 	wnew->flags |= IN132COLUMNS;
10254 
10255     wnew->initflags = wnew->flags;
10256 
10257     init_Sres(keyboard.shift_escape_s);
10258     wnew->keyboard.shift_escape =
10259 	extendedBoolean(wnew->keyboard.shift_escape_s, tblShift2S, ssLAST);
10260 
10261 #if OPT_MOD_FKEYS
10262     init_Ires(keyboard.modify_1st.allow_keys);
10263     init_Ires(keyboard.modify_1st.cursor_keys);
10264     init_Ires(keyboard.modify_1st.function_keys);
10265     init_Ires(keyboard.modify_1st.keypad_keys);
10266     init_Ires(keyboard.modify_1st.other_keys);
10267     init_Ires(keyboard.modify_1st.string_keys);
10268     init_Ires(keyboard.format_keys);
10269     wnew->keyboard.modify_now = wnew->keyboard.modify_1st;
10270 #endif
10271 
10272     init_Ires(misc.appcursorDefault);
10273     if (wnew->misc.appcursorDefault)
10274 	wnew->keyboard.flags |= MODE_DECCKM;
10275 
10276     init_Ires(misc.appkeypadDefault);
10277     if (wnew->misc.appkeypadDefault)
10278 	wnew->keyboard.flags |= MODE_DECKPAM;
10279 
10280     initLineData(wnew);
10281 #if OPT_WIDE_CHARS
10282     freeFontList(&(request->work.fonts.x11.list_n));
10283 #endif
10284 #if OPT_XRES_QUERY
10285     if (resource.reportXRes)
10286 	reportResources(wnew);
10287 #endif
10288     xtermResetLocale(LC_NUMERIC, saveLocale);
10289     TRACE(("" TRACE_R " VTInitialize\n"));
10290     return;
10291 }
10292 
10293 void
releaseCursorGCs(XtermWidget xw)10294 releaseCursorGCs(XtermWidget xw)
10295 {
10296     TScreen *screen = TScreenOf(xw);
10297     VTwin *win = WhichVWin(screen);
10298     int n;
10299 
10300     for_each_curs_gc(n) {
10301 	freeCgs(xw, win, (CgsEnum) n);
10302     }
10303 }
10304 
10305 void
releaseWindowGCs(XtermWidget xw,VTwin * win)10306 releaseWindowGCs(XtermWidget xw, VTwin *win)
10307 {
10308     int n;
10309 
10310     for_each_text_gc(n) {
10311 	switch (n) {
10312 	case gcBorder:
10313 	case gcFiller:
10314 	    break;
10315 	default:
10316 	    freeCgs(xw, win, (CgsEnum) n);
10317 	    break;
10318 	}
10319     }
10320 }
10321 
10322 #define TRACE_FREE_LEAK(name) \
10323 	if (name) { \
10324 	    TRACE(("freed " #name ": %p\n", (const void *) name)); \
10325 	    FreeAndNull(name); \
10326 	}
10327 
10328 #define TRACE_FREE_GC(name,part) \
10329 	if (part) { \
10330 	    TRACE(("freed %s " #part ": %p\n", name, (const void *) part)); \
10331 	    XFreeGC(dpy, part); \
10332 	    part = 0; \
10333 	}
10334 
10335 #if OPT_INPUT_METHOD
10336 static void
cleanupInputMethod(XtermWidget xw)10337 cleanupInputMethod(XtermWidget xw)
10338 {
10339     TInput *input = lookupTInput(xw, (Widget) xw);
10340 
10341     if (input && input->xim) {
10342 	XCloseIM(input->xim);
10343 	input->xim = 0;
10344 	TRACE(("freed screen->xim\n"));
10345     }
10346 }
10347 #else
10348 #define cleanupInputMethod(xw)	/* nothing */
10349 #endif
10350 
10351 #ifdef NO_LEAKS
10352 #define FREE_VT_WIN(name) freeVTwin(dpy, #name, &(screen->name))
10353 static void
freeVTwin(Display * dpy,const char * whichWin,VTwin * win)10354 freeVTwin(Display *dpy, const char *whichWin, VTwin *win)
10355 {
10356     (void) whichWin;
10357     TRACE_FREE_GC(whichWin, win->filler_gc);
10358     TRACE_FREE_GC(whichWin, win->border_gc);
10359     TRACE_FREE_GC(whichWin, win->marker_gc[0]);
10360     TRACE_FREE_GC(whichWin, win->marker_gc[1]);
10361 }
10362 #endif
10363 
10364 static void
VTDestroy(Widget w GCC_UNUSED)10365 VTDestroy(Widget w GCC_UNUSED)
10366 {
10367 #ifdef NO_LEAKS
10368     XtermWidget xw = (XtermWidget) w;
10369     TScreen *screen = TScreenOf(xw);
10370     Display *dpy = screen->display;
10371     Cardinal n, k;
10372 
10373     StopBlinking(xw);
10374 
10375     if (screen->scrollWidget) {
10376 	XtUninstallTranslations(screen->scrollWidget);
10377 	XtDestroyWidget(screen->scrollWidget);
10378     }
10379 
10380     while (screen->saved_fifo > 0) {
10381 	deleteScrollback(screen);
10382     }
10383 
10384     while (screen->save_title != 0) {
10385 	SaveTitle *last = screen->save_title;
10386 	screen->save_title = last->next;
10387 	free(last->iconName);
10388 	free(last->windowName);
10389 	free(last);
10390     }
10391 #ifndef NO_ACTIVE_ICON
10392     TRACE_FREE_LEAK(xw->misc.active_icon_s);
10393 #endif
10394 #if OPT_ISO_COLORS
10395     TRACE_FREE_LEAK(screen->cmap_data);
10396     for (n = 0; n < MAXCOLORS; n++) {
10397 	TRACE_FREE_LEAK(screen->Acolors[n].resource);
10398     }
10399     for (n = 0; n < MAX_SAVED_SGR; n++) {
10400 	TRACE_FREE_LEAK(xw->saved_colors.palettes[n]);
10401     }
10402 #endif
10403     for (n = 0; n < NCOLORS; n++) {
10404 	switch (n) {
10405 #if OPT_TEK4014
10406 	case TEK_BG:
10407 	    /* FALLTHRU */
10408 	case TEK_FG:
10409 	    /* FALLTHRU */
10410 	case TEK_CURSOR:
10411 	    break;
10412 #endif
10413 	default:
10414 	    TRACE_FREE_LEAK(screen->Tcolors[n].resource);
10415 	    break;
10416 	}
10417     }
10418     FreeMarkGCs(xw);
10419     TRACE_FREE_LEAK(screen->unparse_bfr);
10420     TRACE_FREE_LEAK(screen->save_ptr);
10421     TRACE_FREE_LEAK(screen->saveBuf_data);
10422     TRACE_FREE_LEAK(screen->saveBuf_index);
10423     for (n = 0; n < 2; ++n) {
10424 	TRACE_FREE_LEAK(screen->editBuf_data[n]);
10425 	TRACE_FREE_LEAK(screen->editBuf_index[n]);
10426     }
10427     TRACE_FREE_LEAK(screen->keyboard_dialect);
10428     TRACE_FREE_LEAK(screen->cursor_font_name);
10429     TRACE_FREE_LEAK(screen->pointer_shape);
10430     TRACE_FREE_LEAK(screen->term_id);
10431 #if OPT_WIDE_CHARS
10432     TRACE_FREE_LEAK(screen->utf8_mode_s);
10433     TRACE_FREE_LEAK(screen->utf8_fonts_s);
10434     TRACE_FREE_LEAK(screen->utf8_title_s);
10435 #if OPT_LUIT_PROG
10436     TRACE_FREE_LEAK(xw->misc.locale_str);
10437     TRACE_FREE_LEAK(xw->misc.localefilter);
10438 #endif
10439 #endif
10440     TRACE_FREE_LEAK(xw->misc.T_geometry);
10441     TRACE_FREE_LEAK(xw->misc.geo_metry);
10442 #if OPT_INPUT_METHOD
10443     cleanupInputMethod(xw);
10444     TRACE_FREE_LEAK(xw->misc.f_x);
10445     TRACE_FREE_LEAK(xw->misc.input_method);
10446     TRACE_FREE_LEAK(xw->misc.preedit_type);
10447 #endif
10448     releaseCursorGCs(xw);
10449     releaseWindowGCs(xw, &(screen->fullVwin));
10450 #ifndef NO_ACTIVE_ICON
10451     XFreeFont(screen->display, getIconicFont(screen)->fs);
10452     releaseWindowGCs(xw, &(screen->iconVwin));
10453 #endif
10454     XtUninstallTranslations((Widget) xw);
10455 #if OPT_TOOLBAR
10456     XtUninstallTranslations((Widget) XtParent(xw));
10457 #endif
10458     XtUninstallTranslations((Widget) SHELL_OF(xw));
10459 
10460     if (screen->hidden_cursor)
10461 	XFreeCursor(screen->display, screen->hidden_cursor);
10462 
10463     xtermCloseFonts(xw, screen->fnts);
10464 #if OPT_WIDE_ATTRS
10465     xtermCloseFonts(xw, screen->ifnts);
10466 #endif
10467     noleaks_cachedCgs(xw);
10468     free_termcap(xw);
10469 
10470     FREE_VT_WIN(fullVwin);
10471 #ifndef NO_ACTIVE_ICON
10472     FREE_VT_WIN(iconVwin);
10473 #endif /* NO_ACTIVE_ICON */
10474 
10475     TRACE_FREE_LEAK(screen->selection_targets_8bit);
10476 #if OPT_SELECT_REGEX
10477     for (n = 0; n < NSELECTUNITS; ++n) {
10478 	if (screen->selectMap[n] == Select_REGEX) {
10479 	    TRACE_FREE_LEAK(screen->selectExpr[n]);
10480 	}
10481     }
10482 #endif
10483 
10484 #if OPT_RENDERFONT
10485     for (n = 0; n < NMENUFONTS; ++n) {
10486 	int e;
10487 	for (e = 0; e < fMAX; ++e) {
10488 	    xtermCloseXft(screen, getMyXftFont(xw, e, (int) n));
10489 	}
10490     }
10491     discardRenderDraw(screen);
10492     {
10493 	ListXftFonts *p;
10494 	while ((p = screen->list_xft_fonts) != 0) {
10495 	    screen->list_xft_fonts = p->next;
10496 	    free(p);
10497 	}
10498     }
10499 #endif
10500 
10501     /* free things allocated via init_Sres or Init_Sres2 */
10502 #ifndef NO_ACTIVE_ICON
10503     TRACE_FREE_LEAK(screen->icon_fontname);
10504 #endif
10505 #ifdef ALLOWLOGGING
10506     TRACE_FREE_LEAK(screen->logfile);
10507 #endif
10508     TRACE_FREE_LEAK(screen->eight_bit_meta_s);
10509     TRACE_FREE_LEAK(screen->charClass);
10510     TRACE_FREE_LEAK(screen->answer_back);
10511     TRACE_FREE_LEAK(screen->printer_state.printer_command);
10512     TRACE_FREE_LEAK(screen->disallowedColorOps);
10513     TRACE_FREE_LEAK(screen->disallowedFontOps);
10514     TRACE_FREE_LEAK(screen->disallowedMouseOps);
10515     TRACE_FREE_LEAK(screen->disallowedPasteControls);
10516     TRACE_FREE_LEAK(screen->disallowedTcapOps);
10517     TRACE_FREE_LEAK(screen->disallowedWinOps);
10518     TRACE_FREE_LEAK(screen->default_string);
10519     TRACE_FREE_LEAK(screen->eightbit_select_types);
10520 
10521 #if OPT_WIDE_CHARS
10522     TRACE_FREE_LEAK(screen->utf8_select_types);
10523 #endif
10524 
10525 #if 0
10526     for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; n++) {
10527 	TRACE_FREE_LEAK(screen->MenuFontName(n));
10528     }
10529 #endif
10530 
10531     TRACE_FREE_LEAK(screen->initial_font);
10532 
10533 #if OPT_LUIT_PROG
10534     TRACE_FREE_LEAK(xw->misc.locale_str);
10535     TRACE_FREE_LEAK(xw->misc.localefilter);
10536 #endif
10537 
10538 #if OPT_RENDERFONT
10539     TRACE_FREE_LEAK(xw->misc.default_xft.f_n);
10540 #if OPT_WIDE_CHARS
10541     TRACE_FREE_LEAK(xw->misc.default_xft.f_w);
10542 #endif
10543     TRACE_FREE_LEAK(xw->misc.render_font_s);
10544 #endif
10545 
10546     TRACE_FREE_LEAK(xw->misc.default_font.f_n);
10547     TRACE_FREE_LEAK(xw->misc.default_font.f_b);
10548 
10549 #if OPT_WIDE_CHARS
10550     TRACE_FREE_LEAK(xw->misc.default_font.f_w);
10551     TRACE_FREE_LEAK(xw->misc.default_font.f_wb);
10552 #endif
10553 
10554     TRACE_FREE_LEAK(xw->work.wm_name);
10555     freeFontLists(&(xw->work.fonts.x11));
10556 #if OPT_RENDERFONT
10557     freeFontLists(&(xw->work.fonts.xft));
10558 #endif
10559 
10560     xtermFontName(NULL);
10561 #if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS
10562     TRACE_FREE_LEAK(screen->cacheVTFonts.default_font.f_n);
10563     TRACE_FREE_LEAK(screen->cacheVTFonts.default_font.f_b);
10564 #if OPT_WIDE_CHARS
10565     TRACE_FREE_LEAK(screen->cacheVTFonts.default_font.f_w);
10566     TRACE_FREE_LEAK(screen->cacheVTFonts.default_font.f_wb);
10567 #endif
10568     freeFontLists(&(screen->cacheVTFonts.fonts.x11));
10569     for (n = 0; n < NMENUFONTS; ++n) {
10570 	for (k = 0; k < fMAX; ++k) {
10571 	    if (screen->menu_font_names[n][k] !=
10572 		screen->cacheVTFonts.menu_font_names[n][k]) {
10573 		if (screen->menu_font_names[n][k] != _Font_Selected_) {
10574 		    TRACE_FREE_LEAK(screen->menu_font_names[n][k]);
10575 		}
10576 		TRACE_FREE_LEAK(screen->cacheVTFonts.menu_font_names[n][k]);
10577 	    } else {
10578 		TRACE_FREE_LEAK(screen->menu_font_names[n][k]);
10579 	    }
10580 	}
10581     }
10582 #endif
10583 
10584 #if OPT_BLINK_CURS
10585     TRACE_FREE_LEAK(screen->cursor_blink_s);
10586 #endif
10587 
10588 #if OPT_REGIS_GRAPHICS
10589     TRACE_FREE_LEAK(screen->graphics_regis_default_font);
10590     TRACE_FREE_LEAK(screen->graphics_regis_screensize);
10591 #endif
10592 #if OPT_GRAPHICS
10593     TRACE_FREE_LEAK(screen->graph_termid);
10594     TRACE_FREE_LEAK(screen->graphics_max_size);
10595 #endif
10596 
10597     for (n = 0; n < NSELECTUNITS; ++n) {
10598 #if OPT_SELECT_REGEX
10599 	TRACE_FREE_LEAK(screen->selectExpr[n]);
10600 #endif
10601 #if OPT_XRES_QUERY
10602 	TRACE_FREE_LEAK(screen->onClick[n]);
10603 #endif
10604     }
10605 
10606     XtFree((void *) (screen->selection_atoms));
10607 
10608     for (n = 0; n < MAX_SELECTIONS; ++n) {
10609 	free(screen->selected_cells[n].data_buffer);
10610     }
10611 
10612     if (defaultTranslations != xtermClassRec.core_class.tm_table) {
10613 	TRACE_FREE_LEAK(defaultTranslations);
10614     }
10615     TRACE_FREE_LEAK(xtermClassRec.core_class.tm_table);
10616     TRACE_FREE_LEAK(xw->keyboard.shift_escape_s);
10617     TRACE_FREE_LEAK(xw->keyboard.extra_translations);
10618     TRACE_FREE_LEAK(xw->keyboard.shell_translations);
10619     TRACE_FREE_LEAK(xw->keyboard.xterm_translations);
10620     TRACE_FREE_LEAK(xw->keyboard.print_translations);
10621     UnmapSelections(xw);
10622 
10623     XtFree((void *) (xw->visInfo));
10624 
10625 #if OPT_WIDE_CHARS
10626     FreeTypedBuffer(XChar2b);
10627     FreeTypedBuffer(char);
10628 #endif
10629 #if OPT_RENDERFONT
10630 #if OPT_RENDERWIDE
10631     FreeTypedBuffer(XftCharSpec);
10632 #else
10633     FreeTypedBuffer(XftChar8);
10634 #endif
10635 #endif
10636 
10637     TRACE_FREE_LEAK(myState.print_area);
10638     TRACE_FREE_LEAK(myState.string_area);
10639     memset(&myState, 0, sizeof(myState));
10640 
10641 #endif /* defined(NO_LEAKS) */
10642 }
10643 
10644 #ifndef NO_ACTIVE_ICON
10645 static void *
getProperty(Display * dpy,Window w,Atom req_type,const char * prop_name)10646 getProperty(Display *dpy,
10647 	    Window w,
10648 	    Atom req_type,
10649 	    const char *prop_name)
10650 {
10651     Atom property;
10652     Atom actual_return_type;
10653     int actual_format_return = 0;
10654     unsigned long nitems_return = 0;
10655     unsigned long bytes_after_return = 0;
10656     unsigned char *prop_return = 0;
10657     long long_length = 1024;
10658     size_t limit;
10659     char *result = 0;
10660 
10661     TRACE(("getProperty %s(%s)\n", prop_name,
10662 	   req_type ? TraceAtomName(dpy, req_type) : "?"));
10663     property = XInternAtom(dpy, prop_name, False);
10664 
10665     if (!xtermGetWinProp(dpy,
10666 			 w,
10667 			 property,
10668 			 0L,
10669 			 long_length,
10670 			 req_type,
10671 			 &actual_return_type,
10672 			 &actual_format_return,
10673 			 &nitems_return,
10674 			 &bytes_after_return,
10675 			 &prop_return)) {
10676 	TRACE((".. Cannot get %s property.\n", prop_name));
10677     } else if (prop_return != 0) {
10678 
10679 	if (nitems_return != 0 &&
10680 	    actual_format_return != 0 &&
10681 	    actual_return_type == req_type) {
10682 	    /*
10683 	     * Null-terminate the result to make string handling easier.
10684 	     * The format==8 corresponds to strings, and the number of items
10685 	     * is the number of characters.
10686 	     */
10687 	    if (actual_format_return == 8) {
10688 		limit = nitems_return;
10689 	    } else {
10690 		/* manpage is misleading - X really uses 'long', not 32-bits */
10691 		limit = sizeof(long) * nitems_return;
10692 	    }
10693 	    if ((result = malloc(limit + 1)) != 0) {
10694 		memcpy(result, prop_return, limit);
10695 		result[limit] = '\0';
10696 	    }
10697 	    TRACE(("... result %s\n", result ? ("ok") : "null"));
10698 	}
10699 	XFree(prop_return);
10700     } else {
10701 	TRACE((".. no property returned\n"));
10702     }
10703     return (void *) result;
10704 }
10705 
10706 /*
10707  * Active icons are supported by fvwm.  This feature is not supported by
10708  * metacity (gnome) or kwin (kde).  Both metacity and kwin support (in
10709  * incompatible ways, e.g., one uses the icon theme as a fallback for window
10710  * decorations but the other does not, etc, ...) an icon as part of the window
10711  * decoration (usually on the upper-left of the window).
10712  *
10713  * In either case, xterm's icon will only be shown in the window decorations if
10714  * xterm does not use the active icon feature.
10715  *
10716  * This function (tries to) determine the window manager's name, so that we can
10717  * provide a useful automatic default for active icons.  It is based on reading
10718  * wmctrl, which covers most of EWMH and ICCM.
10719  */
10720 static char *
getWindowManagerName(XtermWidget xw)10721 getWindowManagerName(XtermWidget xw)
10722 {
10723     TScreen *screen = TScreenOf(xw);
10724     Display *dpy = screen->display;
10725     Window *sup_window = NULL;
10726     char *result = 0;
10727 
10728     TRACE(("getWindowManagerName\n"));
10729 #define getWinProp(type, name) \
10730     (Window *)getProperty(dpy, DefaultRootWindow(dpy), type, name)
10731     if ((sup_window = getWinProp(XA_WINDOW, "_NET_SUPPORTING_WM_CHECK")) == 0) {
10732 	sup_window = getWinProp(XA_CARDINAL, "_WIN_SUPPORTING_WM_CHECK");
10733     }
10734 
10735     /*
10736      * If we found the supporting window, get the property containing the
10737      * window manager's name.  EWMH defines _NET_WM_NAME, while ICCM defines
10738      * WM_CLASS.  There is no standard for the names stored there;
10739      * conventionally it is mixed case.  In practice, the former is more often
10740      * set; the latter is not given (or is a lowercased version of the former).
10741      */
10742     if (sup_window != 0) {
10743 #define getStringProp(type,name) \
10744 	(char *)getProperty(dpy, *sup_window, type, name)
10745 	if ((result = getStringProp(XA_UTF8_STRING(dpy), "_NET_WM_NAME")) == 0
10746 	    && (result = getStringProp(XA_STRING, "_NET_WM_NAME")) == 0
10747 	    && (result = getStringProp(XA_STRING, "WM_CLASS")) == 0) {
10748 	    TRACE(("... window manager does not tell its name\n"));
10749 	}
10750 	free(sup_window);
10751     } else {
10752 	TRACE(("... Cannot get window manager info properties\n"));
10753     }
10754     if (result == 0)
10755 	result = x_strdup("unknown");
10756     TRACE(("... window manager name is %s\n", result));
10757     return result;
10758 }
10759 
10760 static Boolean
discount_frame_extents(XtermWidget xw,int * high,int * wide)10761 discount_frame_extents(XtermWidget xw, int *high, int *wide)
10762 {
10763     TScreen *screen = TScreenOf(xw);
10764     Display *dpy = screen->display;
10765 
10766     Atom atom_supported = XInternAtom(dpy, "_NET_FRAME_EXTENTS", False);
10767     Atom actual_type;
10768     int actual_format;
10769     long long_offset = 0;
10770     long long_length = 128;	/* number of items to ask for at a time */
10771     unsigned long nitems;
10772     unsigned long bytes_after;
10773     unsigned char *args;
10774     Boolean rc;
10775 
10776     rc = xtermGetWinProp(dpy,
10777 			 VShellWindow(xw),
10778 			 atom_supported,
10779 			 long_offset,
10780 			 long_length,
10781 			 XA_CARDINAL,	/* req_type */
10782 			 &actual_type,	/* actual_type_return */
10783 			 &actual_format,	/* actual_format_return */
10784 			 &nitems,	/* nitems_return */
10785 			 &bytes_after,	/* bytes_after_return */
10786 			 &args	/* prop_return */
10787 	);
10788 
10789     if (rc && args && (nitems == 4) && (actual_format == 32)) {
10790 	long *extents = (long *) (void *) args;
10791 
10792 	TRACE(("_NET_FRAME_EXTENTS:\n"));
10793 	TRACE(("   left:   %ld\n", extents[0]));
10794 	TRACE(("   right:  %ld\n", extents[1]));
10795 	TRACE(("   top:    %ld\n", extents[2]));
10796 	TRACE(("   bottom: %ld\n", extents[3]));
10797 
10798 	if (!x_strncasecmp(xw->work.wm_name, "gnome shell", 11)) {
10799 	    *wide -= (int) (extents[0] + extents[1]);	/* -= (left+right) */
10800 	    *high -= (int) (extents[2] + extents[3]);	/* -= (top+bottom) */
10801 	    TRACE(("...applied extents %d,%d\n", *high, *wide));
10802 	} else if (!x_strncasecmp(xw->work.wm_name, "compiz", 6)) {
10803 	    /* Ubuntu 16.04 is really off-by-one */
10804 	    *wide -= (int) (extents[0] + extents[1] - 1);
10805 	    *high -= (int) (extents[2] + extents[3] - 1);
10806 	    TRACE(("...applied extents %d,%d\n", *high, *wide));
10807 	} else if (!x_strncasecmp(xw->work.wm_name, "fvwm", 4)) {
10808 	    TRACE(("...skipping extents\n"));
10809 	} else {
10810 	    TRACE(("...ignoring extents\n"));
10811 	    rc = False;
10812 	}
10813     } else {
10814 	rc = False;
10815     }
10816     return rc;
10817 }
10818 #endif /* !NO_ACTIVE_ICON */
10819 
10820 void
initBorderGC(XtermWidget xw,VTwin * win)10821 initBorderGC(XtermWidget xw, VTwin *win)
10822 {
10823     TScreen *screen = TScreenOf(xw);
10824     Pixel filler;
10825 
10826     TRACE(("initBorderGC(%s) core bg %#lx, bd %#lx text fg %#lx, bg %#lx %s\n",
10827 	   (win == &(screen->fullVwin)) ? "full" : "icon",
10828 	   xw->core.background_pixel,
10829 	   xw->core.border_pixel,
10830 	   T_COLOR(screen, TEXT_FG),
10831 	   T_COLOR(screen, TEXT_BG),
10832 	   xw->misc.re_verse ? "reverse" : "normal"));
10833     if (xw->misc.color_inner_border
10834 	&& (xw->core.background_pixel != xw->core.border_pixel)) {
10835 	/*
10836 	 * By default, try to match the inner window's background.
10837 	 */
10838 	if ((xw->core.background_pixel == T_COLOR(screen, TEXT_BG)) &&
10839 	    (xw->core.border_pixel == T_COLOR(screen, TEXT_FG))) {
10840 	    filler = T_COLOR(screen, TEXT_BG);
10841 	} else {
10842 	    filler = xw->core.border_pixel;
10843 	}
10844 	TRACE((" border %#lx\n", filler));
10845 	setCgsFore(xw, win, gcBorder, filler);
10846 	setCgsBack(xw, win, gcBorder, filler);
10847 	win->border_gc = getCgsGC(xw, win, gcBorder);
10848     }
10849 #if USE_DOUBLE_BUFFER
10850     else if (resource.buffered) {
10851 	filler = T_COLOR(screen, TEXT_BG);
10852 	TRACE((" border %#lx (buffered)\n", filler));
10853 	setCgsFore(xw, win, gcBorder, filler);
10854 	setCgsBack(xw, win, gcBorder, filler);
10855 	win->border_gc = getCgsGC(xw, win, gcBorder);
10856     }
10857 #endif
10858     else {
10859 	TRACE((" border unused\n"));
10860 	win->border_gc = 0;
10861     }
10862 
10863     /*
10864      * Initialize a GC for double-buffering, needed for XFillRectangle call
10865      * in xtermClear2().  When not double-buffering, the XClearArea call works,
10866      * without requiring a separate GC.
10867      */
10868 #if USE_DOUBLE_BUFFER
10869     if (resource.buffered) {
10870 	filler = (((xw->flags & BG_COLOR) && (xw->cur_background >= 0))
10871 		  ? getXtermBG(xw, xw->flags, xw->cur_background)
10872 		  : T_COLOR(screen, TEXT_BG));
10873 
10874 	TRACE((" filler %#lx %s\n",
10875 	       filler,
10876 	       xw->misc.re_verse ? "reverse" : "normal"));
10877 
10878 	setCgsFore(xw, win, gcFiller, filler);
10879 	setCgsBack(xw, win, gcFiller, filler);
10880 
10881 	win->filler_gc = getCgsGC(xw, win, gcFiller);
10882     }
10883 #endif
10884 }
10885 #if USE_DOUBLE_BUFFER
10886 static Boolean
allocateDbe(XtermWidget xw,VTwin * target)10887 allocateDbe(XtermWidget xw, VTwin *target)
10888 {
10889     TScreen *screen = TScreenOf(xw);
10890     Boolean result = False;
10891 
10892     target->drawable = target->window;
10893 
10894     if (resource.buffered) {
10895 	Window win = target->window;
10896 	Drawable d;
10897 	int major, minor;
10898 	if (XdbeQueryExtension(XtDisplay(xw), &major, &minor)) {
10899 	    d = XdbeAllocateBackBufferName(XtDisplay(xw), win,
10900 					   (XdbeSwapAction) XdbeCopied);
10901 	    if (d == None) {
10902 		fprintf(stderr, "Couldn't allocate a back buffer!\n");
10903 		exit(3);
10904 	    }
10905 	    target->drawable = d;
10906 	    screen->needSwap = 1;
10907 	    TRACE(("initialized double-buffering\n"));
10908 	    result = True;
10909 	} else {
10910 	    resource.buffered = False;
10911 	}
10912     }
10913     return result;
10914 }
10915 #endif /* USE_DOUBLE_BUFFER */
10916 
10917 /*ARGSUSED*/
10918 static void
VTRealize(Widget w,XtValueMask * valuemask,XSetWindowAttributes * values)10919 VTRealize(Widget w,
10920 	  XtValueMask * valuemask,
10921 	  XSetWindowAttributes * values)
10922 {
10923     XtermWidget xw = (XtermWidget) w;
10924     TScreen *screen = TScreenOf(xw);
10925 
10926     const VTFontNames *myfont;
10927     struct Xinerama_geometry pos;
10928     int pr;
10929     Atom pid_atom;
10930     int i;
10931 
10932     TRACE(("VTRealize " TRACE_L "\n"));
10933 
10934     TabReset(xw->tabs);
10935 
10936     if (screen->menu_font_number == fontMenu_default) {
10937 	myfont = defaultVTFontNames(xw);
10938     } else {
10939 	myfont = xtermFontName(screen->MenuFontName(screen->menu_font_number));
10940     }
10941     memset(screen->fnts, 0, sizeof(screen->fnts));
10942 
10943     if (!xtermLoadFont(xw,
10944 		       myfont,
10945 		       False,
10946 		       screen->menu_font_number)) {
10947 	if (XmuCompareISOLatin1(myfont->f_n, DEFFONT) != 0) {
10948 	    char *use_font = x_strdup(DEFFONT);
10949 	    xtermWarning("unable to open font \"%s\", trying \"%s\"....\n",
10950 			 myfont->f_n, use_font);
10951 	    (void) xtermLoadFont(xw,
10952 				 xtermFontName(use_font),
10953 				 False,
10954 				 screen->menu_font_number);
10955 	    screen->MenuFontName(screen->menu_font_number) = use_font;
10956 	}
10957     }
10958 
10959     /* really screwed if we couldn't open default font */
10960     if (!GetNormalFont(screen, fNorm)->fs) {
10961 	xtermWarning("unable to locate a suitable font\n");
10962 	Exit(1);
10963     }
10964 #if OPT_WIDE_CHARS
10965     if (screen->utf8_mode) {
10966 	TRACE(("check if this is a wide font, if not try again\n"));
10967 	if (xtermLoadWideFonts(xw, False)) {
10968 	    SetVTFont(xw, screen->menu_font_number, True, NULL);
10969 	    /* we will not be able to switch to ISO-8859-1 */
10970 	    if (!screen->mergedVTFonts) {
10971 		screen->utf8_fonts = uAlways;
10972 		update_font_utf8_fonts();
10973 	    }
10974 	}
10975     }
10976 #endif
10977 
10978     xtermSetupPointer(xw, screen->pointer_shape);
10979 
10980     /* set defaults */
10981     pos.x = 1;
10982     pos.y = 1;
10983     pos.w = 80;
10984     pos.h = 24;
10985 
10986     TRACE(("parsing geo_metry %s\n", NonNull(xw->misc.geo_metry)));
10987     pr = XParseXineramaGeometry(screen->display, xw->misc.geo_metry, &pos);
10988     TRACE(("... position %d,%d size %dx%d\n", pos.y, pos.x, pos.h, pos.w));
10989 
10990     set_max_col(screen, (int) (pos.w - 1));	/* units in character cells */
10991     set_max_row(screen, (int) (pos.h - 1));	/* units in character cells */
10992     xtermUpdateFontInfo(xw, False);
10993 
10994     pos.w = screen->fullVwin.fullwidth;
10995     pos.h = screen->fullVwin.fullheight;
10996 
10997     TRACE(("... BorderWidth: widget %d parent %d shell %d\n",
10998 	   BorderWidth(xw),
10999 	   BorderWidth(XtParent(xw)),
11000 	   BorderWidth(SHELL_OF(xw))));
11001 
11002     if ((pr & XValue) && (XNegative & pr)) {
11003 	pos.x = (Position) (pos.x + (pos.scr_w
11004 				     - (int) pos.w
11005 				     - (BorderWidth(XtParent(xw)) * 2)));
11006     }
11007     if ((pr & YValue) && (YNegative & pr)) {
11008 	pos.y = (Position) (pos.y + (pos.scr_h
11009 				     - (int) pos.h
11010 				     - (BorderWidth(XtParent(xw)) * 2)));
11011     }
11012     pos.x = (Position) (pos.x + pos.scr_x);
11013     pos.y = (Position) (pos.y + pos.scr_y);
11014 
11015     /* set up size hints for window manager; min 1 char by 1 char */
11016     getXtermSizeHints(xw);
11017     xtermSizeHints(xw, (xw->misc.scrollbar
11018 			? (screen->scrollWidget->core.width
11019 			   + BorderWidth(screen->scrollWidget))
11020 			: 0));
11021 
11022     xw->hints.x = pos.x;
11023     xw->hints.y = pos.y;
11024 #if OPT_MAXIMIZE
11025     /* assure single-increment resize for fullscreen */
11026     if (xw->work.ewmh[0].mode) {
11027 	xw->hints.width_inc = 1;
11028 	xw->hints.height_inc = 1;
11029     }
11030 #endif
11031     if ((XValue & pr) || (YValue & pr)) {
11032 	xw->hints.flags |= USSize | USPosition;
11033 	xw->hints.flags |= PWinGravity;
11034 	switch (pr & (XNegative | YNegative)) {
11035 	case 0:
11036 	    xw->hints.win_gravity = NorthWestGravity;
11037 	    break;
11038 	case XNegative:
11039 	    xw->hints.win_gravity = NorthEastGravity;
11040 	    break;
11041 	case YNegative:
11042 	    xw->hints.win_gravity = SouthWestGravity;
11043 	    break;
11044 	default:
11045 	    xw->hints.win_gravity = SouthEastGravity;
11046 	    break;
11047 	}
11048     } else {
11049 	/* set a default size, but do *not* set position */
11050 	xw->hints.flags |= PSize;
11051     }
11052     xw->hints.height = xw->hints.base_height
11053 	+ xw->hints.height_inc * MaxRows(screen);
11054     xw->hints.width = xw->hints.base_width
11055 	+ xw->hints.width_inc * MaxCols(screen);
11056 
11057     if ((WidthValue & pr) || (HeightValue & pr))
11058 	xw->hints.flags |= USSize;
11059     else
11060 	xw->hints.flags |= PSize;
11061 
11062     /*
11063      * Note that the size-hints are for the shell, while the resize-request
11064      * is for the vt100 widget.  They are not the same size.
11065      */
11066     (void) REQ_RESIZE((Widget) xw,
11067 		      (Dimension) pos.w, (Dimension) pos.h,
11068 		      &xw->core.width, &xw->core.height);
11069 
11070     /* XXX This is bogus.  We are parsing geometries too late.  This
11071      * is information that the shell widget ought to have before we get
11072      * realized, so that it can do the right thing.
11073      */
11074     if (xw->hints.flags & USPosition)
11075 	XMoveWindow(XtDisplay(xw), VShellWindow(xw),
11076 		    xw->hints.x, xw->hints.y);
11077 
11078     TRACE(("%s@%d -- ", __FILE__, __LINE__));
11079     TRACE_HINTS(&xw->hints);
11080     XSetWMNormalHints(XtDisplay(xw), VShellWindow(xw), &xw->hints);
11081     TRACE(("%s@%d -- ", __FILE__, __LINE__));
11082     TRACE_WM_HINTS(xw);
11083 
11084     if ((pid_atom = XInternAtom(XtDisplay(xw), "_NET_WM_PID", False)) != None) {
11085 	/* XChangeProperty format 32 really is "long" */
11086 	unsigned long pid_l = (unsigned long) getpid();
11087 	TRACE(("Setting _NET_WM_PID property to %lu\n", pid_l));
11088 	XChangeProperty(XtDisplay(xw), VShellWindow(xw),
11089 			pid_atom, XA_CARDINAL, 32, PropModeReplace,
11090 			(unsigned char *) &pid_l, 1);
11091     }
11092 
11093     XFlush(XtDisplay(xw));	/* get it out to window manager */
11094 
11095     /* use ForgetGravity instead of SouthWestGravity because translating
11096        the Expose events for ConfigureNotifys is too hard */
11097     values->bit_gravity = (GravityIsNorthWest(xw)
11098 			   ? NorthWestGravity
11099 			   : ForgetGravity);
11100     screen->fullVwin.window = XtWindow(xw) =
11101 	XCreateWindow(XtDisplay(xw), XtWindow(XtParent(xw)),
11102 		      xw->core.x, xw->core.y,
11103 		      xw->core.width, xw->core.height, BorderWidth(xw),
11104 		      (int) xw->core.depth,
11105 		      InputOutput, CopyFromParent,
11106 		      *valuemask | CWBitGravity, values);
11107 #if USE_DOUBLE_BUFFER
11108     if (allocateDbe(xw, &(screen->fullVwin))) {
11109 	screen->needSwap = 1;
11110 	TRACE(("initialized full double-buffering\n"));
11111     } else {
11112 	resource.buffered = False;
11113 	screen->fullVwin.drawable = screen->fullVwin.window;
11114     }
11115 #endif /* USE_DOUBLE_BUFFER */
11116     screen->event_mask = values->event_mask;
11117 
11118 #ifndef NO_ACTIVE_ICON
11119     /*
11120      * Normally, the font-number for icon fonts does not correspond with any of
11121      * the menu-selectable fonts.  If we cannot load the font given for the
11122      * iconFont resource, try with font1 aka "Unreadable".
11123      */
11124     screen->icon_fontnum = -1;
11125     if (getIconicFont(screen)->fs == 0) {
11126 	getIconicFont(screen)->fs =
11127 	    xtermLoadQueryFont(xw, screen->MenuFontName(fontMenu_font1));
11128 	ReportIcons(("%susing font1 '%s' as iconFont\n",
11129 		     (getIconicFont(screen)->fs
11130 		      ? ""
11131 		      : "NOT "),
11132 		     screen->MenuFontName(fontMenu_font1)));
11133     }
11134 #if OPT_RENDERFONT
11135     /*
11136      * If we still have no result from iconFont resource (perhaps because fonts
11137      * are missing) but are using Xft, try to use that instead.  We prefer
11138      * bitmap fonts in any case, since scaled fonts are usually less readable,
11139      * particularly at small sizes.
11140      */
11141     if (UsingRenderFont(xw)
11142 	&& getIconicFont(screen)->fs == 0) {
11143 	screen->icon_fontnum = fontMenu_default;
11144 	getIconicFont(screen)->fs = GetNormalFont(screen, fNorm)->fs;	/* need for next-if */
11145 	ReportIcons(("using TrueType font as iconFont\n"));
11146     }
11147 #endif
11148     xw->work.wm_name = getWindowManagerName(xw);
11149     if ((xw->work.active_icon == eiDefault) && getIconicFont(screen)->fs) {
11150 	ReportIcons(("window manager name is %s\n", xw->work.wm_name));
11151 	if (x_strncasecmp(xw->work.wm_name, "fvwm", 4) &&
11152 	    x_strncasecmp(xw->work.wm_name, "window maker", 12)) {
11153 	    xw->work.active_icon = eiFalse;
11154 	    TRACE(("... disable active_icon\n"));
11155 	}
11156     }
11157     TRACE((".. if active_icon (%d), get its font\n", xw->work.active_icon));
11158     if (xw->work.active_icon && getIconicFont(screen)->fs) {
11159 	int iconX = 0, iconY = 0;
11160 	Widget shell = SHELL_OF(xw);
11161 	VTwin *win = &(screen->iconVwin);
11162 	int save_fontnum = screen->menu_font_number;
11163 
11164 	ReportIcons(("initializing active-icon %d\n", screen->icon_fontnum));
11165 	screen->menu_font_number = screen->icon_fontnum;
11166 	XtVaGetValues(shell,
11167 		      XtNiconX, &iconX,
11168 		      XtNiconY, &iconY,
11169 		      (XtPointer) 0);
11170 	xtermComputeFontInfo(xw, &(screen->iconVwin),
11171 			     getIconicFont(screen)->fs, 0);
11172 	screen->menu_font_number = save_fontnum;
11173 
11174 	/* since only one client is permitted to select for Button
11175 	 * events, we have to let the window manager get 'em...
11176 	 */
11177 	values->event_mask &= ~(ButtonPressMask | ButtonReleaseMask);
11178 	values->border_pixel = xw->misc.icon_border_pixel;
11179 
11180 	screen->iconVwin.window =
11181 	    XCreateWindow(XtDisplay(xw),
11182 			  RootWindowOfScreen(XtScreen(shell)),
11183 			  iconX, iconY,
11184 			  screen->iconVwin.fullwidth,
11185 			  screen->iconVwin.fullheight,
11186 			  xw->misc.icon_border_width,
11187 			  (int) xw->core.depth,
11188 			  InputOutput, CopyFromParent,
11189 			  *valuemask | CWBitGravity | CWBorderPixel,
11190 			  values);
11191 #if USE_DOUBLE_BUFFER
11192 	if (allocateDbe(xw, &(screen->iconVwin))) {
11193 	    TRACE(("initialized icon double-buffering\n"));
11194 	} else {
11195 	    resource.buffered = False;
11196 	    screen->iconVwin.drawable = screen->iconVwin.window;
11197 	    screen->fullVwin.drawable = screen->fullVwin.window;
11198 	}
11199 #endif /* USE_DOUBLE_BUFFER */
11200 	XtVaSetValues(shell,
11201 		      XtNiconWindow, screen->iconVwin.window,
11202 		      (XtPointer) 0);
11203 	XtRegisterDrawable(XtDisplay(xw), screen->iconVwin.window, w);
11204 
11205 	setCgsFont(xw, win, gcNorm, getIconicFont(screen));
11206 	setCgsFore(xw, win, gcNorm, T_COLOR(screen, TEXT_FG));
11207 	setCgsBack(xw, win, gcNorm, T_COLOR(screen, TEXT_BG));
11208 
11209 	copyCgs(xw, win, gcBold, gcNorm);
11210 
11211 	setCgsFont(xw, win, gcNormReverse, getIconicFont(screen));
11212 	setCgsFore(xw, win, gcNormReverse, T_COLOR(screen, TEXT_BG));
11213 	setCgsBack(xw, win, gcNormReverse, T_COLOR(screen, TEXT_FG));
11214 
11215 	copyCgs(xw, win, gcBoldReverse, gcNormReverse);
11216 
11217 	initBorderGC(xw, win);
11218 
11219 #if OPT_TOOLBAR
11220 	/*
11221 	 * Toolbar is initialized before we get here.  Enable the menu item
11222 	 * and set it properly.
11223 	 */
11224 	SetItemSensitivity(vtMenuEntries[vtMenu_activeicon].widget, True);
11225 	update_activeicon();
11226 #endif
11227     } else {
11228 	ReportIcons(("disabled active-icon\n"));
11229 	xw->work.active_icon = eiFalse;
11230     }
11231 #endif /* NO_ACTIVE_ICON */
11232 
11233 #if OPT_INPUT_METHOD
11234     VTInitI18N(xw);
11235 #endif
11236 #if OPT_NUM_LOCK
11237     VTInitModifiers(xw);
11238 #if OPT_EXTRA_PASTE
11239     if (xw->keyboard.extra_translations) {
11240 	XtOverrideTranslations((Widget) xw,
11241 			       XtParseTranslationTable(xw->keyboard.extra_translations));
11242     }
11243 #endif
11244 #endif
11245 
11246     set_cursor_gcs(xw);
11247     initBorderGC(xw, &(screen->fullVwin));
11248 
11249     /* Reset variables used by ANSI emulation. */
11250 
11251     resetCharsets(screen);
11252 
11253     XDefineCursor(screen->display, VShellWindow(xw), screen->pointer_cursor);
11254 
11255     set_cur_col(screen, 0);
11256     set_cur_row(screen, 0);
11257     set_max_col(screen, Width(screen) / screen->fullVwin.f_width - 1);
11258     set_max_row(screen, Height(screen) / screen->fullVwin.f_height - 1);
11259     resetMarginMode(xw);
11260 
11261     memset(screen->sc, 0, sizeof(screen->sc));
11262 
11263     /* Mark screen buffer as unallocated.  We wait until the run loop so
11264        that the child process does not fork and exec with all the dynamic
11265        memory it will never use.  If we were to do it here, the
11266        swap space for new process would be huge for huge savelines. */
11267 #if OPT_TEK4014
11268     if (!tekWidget)		/* if not called after fork */
11269 #endif
11270     {
11271 	screen->visbuf = NULL;
11272 	screen->saveBuf_index = NULL;
11273     }
11274 
11275     ResetWrap(screen);
11276     screen->scrolls = screen->incopy = 0;
11277     xtermSetCursorBox(screen);
11278 
11279     screen->savedlines = 0;
11280 
11281     for (i = 0; i < 2; ++i) {
11282 	screen->whichBuf = !screen->whichBuf;
11283 	CursorSave(xw);
11284     }
11285 
11286 #ifndef NO_ACTIVE_ICON
11287     if (!xw->work.active_icon)
11288 #endif
11289 	xtermLoadIcon(xw, resource.icon_hint);
11290 
11291     /*
11292      * Do this last, since it may change the layout via a resize.
11293      */
11294     if (xw->misc.scrollbar) {
11295 	screen->fullVwin.sb_info.width = 0;
11296 	ScrollBarOn(xw, False);
11297     }
11298 
11299     xtermSetWinSize(xw);
11300     TRACE(("" TRACE_R " VTRealize\n"));
11301 }
11302 
11303 #if OPT_INPUT_METHOD
11304 
11305 /* limit this feature to recent XFree86 since X11R6.x core dumps */
11306 #if defined(XtSpecificationRelease) && XtSpecificationRelease >= 6 && defined(X_HAVE_UTF8_STRING)
11307 #define USE_XIM_INSTANTIATE_CB
11308 
11309 static void
xim_instantiate_cb(Display * display,XPointer client_data GCC_UNUSED,XPointer call_data GCC_UNUSED)11310 xim_instantiate_cb(Display *display,
11311 		   XPointer client_data GCC_UNUSED,
11312 		   XPointer call_data GCC_UNUSED)
11313 {
11314     XtermWidget xw = term;
11315 
11316     TRACE(("xim_instantiate_cb client=%p, call=%p\n", client_data, call_data));
11317 
11318     if (display == XtDisplay(xw)) {
11319 	VTInitI18N(xw);
11320     }
11321 }
11322 
11323 static void
xim_destroy_cb(XIM im GCC_UNUSED,XPointer client_data GCC_UNUSED,XPointer call_data GCC_UNUSED)11324 xim_destroy_cb(XIM im GCC_UNUSED,
11325 	       XPointer client_data GCC_UNUSED,
11326 	       XPointer call_data GCC_UNUSED)
11327 {
11328     XtermWidget xw = term;
11329     TInput *input = lookupTInput(xw, (Widget) xw);
11330 
11331     TRACE(("xim_destroy_cb im=%lx, client=%p, call=%p\n",
11332 	   (long) im, client_data, call_data));
11333     if (input)
11334 	input->xic = NULL;
11335     XRegisterIMInstantiateCallback(XtDisplay(xw), NULL, NULL, NULL,
11336 				   xim_instantiate_cb, NULL);
11337 }
11338 #endif /* X11R6+ */
11339 
11340 static Boolean
xim_create_fs(XtermWidget xw)11341 xim_create_fs(XtermWidget xw)
11342 {
11343     XFontStruct **fonts;
11344     char **font_name_list;
11345     char **missing_charset_list;
11346     char *def_string;
11347     int missing_charset_count;
11348     unsigned i, j;
11349 
11350     if (xw->work.xim_fs == 0) {
11351 	xw->work.xim_fs = XCreateFontSet(XtDisplay(xw),
11352 					 xw->misc.f_x,
11353 					 &missing_charset_list,
11354 					 &missing_charset_count,
11355 					 &def_string);
11356 	if (xw->work.xim_fs == NULL) {
11357 	    xtermWarning("Preparation of font set "
11358 			 "\"%s\" for XIM failed.\n", xw->misc.f_x);
11359 	    xw->work.xim_fs = XCreateFontSet(XtDisplay(xw),
11360 					     DEFXIMFONT,
11361 					     &missing_charset_list,
11362 					     &missing_charset_count,
11363 					     &def_string);
11364 	}
11365     }
11366     if (xw->work.xim_fs == NULL) {
11367 	xtermWarning("Preparation of default font set "
11368 		     "\"%s\" for XIM failed.\n", DEFXIMFONT);
11369 	cleanupInputMethod(xw);
11370 	xw->work.cannot_im = True;
11371     } else {
11372 	(void) XExtentsOfFontSet(xw->work.xim_fs);
11373 	j = (unsigned) XFontsOfFontSet(xw->work.xim_fs, &fonts, &font_name_list);
11374 	for (i = 0, xw->work.xim_fs_ascent = 0; i < j; i++) {
11375 	    if (xw->work.xim_fs_ascent < (*fonts)->ascent)
11376 		xw->work.xim_fs_ascent = (*fonts)->ascent;
11377 	}
11378     }
11379     return (Boolean) !(xw->work.cannot_im);
11380 }
11381 
11382 static void
xim_create_xic(XtermWidget xw,Widget theInput)11383 xim_create_xic(XtermWidget xw, Widget theInput)
11384 {
11385     Display *myDisplay = XtDisplay(theInput);
11386     Window myWindow = XtWindow(theInput);
11387     unsigned i, j;
11388     char *p = NULL, *s, *t, *ns, *end, buf[32];
11389     XIMStyles *xim_styles;
11390     XIMStyle input_style = 0;
11391     Bool found;
11392     static struct {
11393 	const char *name;
11394 	unsigned long code;
11395     } known_style[] = {
11396 	{
11397 	    "OverTheSpot", (XIMPreeditPosition | XIMStatusNothing)
11398 	},
11399 	{
11400 	    "OffTheSpot", (XIMPreeditArea | XIMStatusArea)
11401 	},
11402 	{
11403 	    "Root", (XIMPreeditNothing | XIMStatusNothing)
11404 	},
11405     };
11406     TInput *input = lookupTInput(xw, theInput);
11407 
11408     if (xw->work.cannot_im) {
11409 	return;
11410     }
11411 
11412     if (input == 0) {
11413 	for (i = 0; i < NINPUTWIDGETS; ++i) {
11414 	    if (xw->work.inputs[i].w == 0) {
11415 		input = xw->work.inputs + i;
11416 		input->w = theInput;
11417 		break;
11418 	    }
11419 	}
11420     }
11421 
11422     if (input == 0) {
11423 	xtermWarning("attempted to add too many input widgets\n");
11424 	return;
11425     }
11426 
11427     TRACE(("xim_real_init\n"));
11428 
11429     if (IsEmpty(xw->misc.input_method)) {
11430 	if ((p = XSetLocaleModifiers("")) != NULL && *p) {
11431 	    input->xim = XOpenIM(myDisplay, NULL, NULL, NULL);
11432 	}
11433     } else {
11434 	s = xw->misc.input_method;
11435 	i = 5 + (unsigned) strlen(s);
11436 
11437 	t = (char *) MyStackAlloc(i, buf);
11438 	if (t == NULL) {
11439 	    SysError(ERROR_VINIT);
11440 	} else {
11441 
11442 	    for (ns = s; ns && *s;) {
11443 		while (*s && isspace(CharOf(*s)))
11444 		    s++;
11445 		if (!*s)
11446 		    break;
11447 		if ((ns = end = strchr(s, ',')) == 0)
11448 		    end = s + strlen(s);
11449 		while ((end != s) && isspace(CharOf(end[-1])))
11450 		    end--;
11451 
11452 		if (end != s) {
11453 		    strcpy(t, "@im=");
11454 		    strncat(t, s, (size_t) (end - s));
11455 
11456 		    if ((p = XSetLocaleModifiers(t)) != 0 && *p
11457 			&& (input->xim = XOpenIM(myDisplay,
11458 						 NULL,
11459 						 NULL,
11460 						 NULL)) != 0) {
11461 			break;
11462 		    }
11463 
11464 		}
11465 		s = ns + 1;
11466 	    }
11467 	    MyStackFree(t, buf);
11468 	}
11469     }
11470 
11471     if (input->xim == NULL
11472 	&& (p = XSetLocaleModifiers("@im=none")) != NULL
11473 	&& *p) {
11474 	input->xim = XOpenIM(myDisplay, NULL, NULL, NULL);
11475     }
11476 
11477     if (!input->xim) {
11478 	xtermWarning("Failed to open input method\n");
11479 	return;
11480     }
11481     TRACE(("VTInitI18N opened input method:%s\n", NonNull(p)));
11482 
11483     if (XGetIMValues(input->xim, XNQueryInputStyle, &xim_styles, (void *) 0)
11484 	|| !xim_styles
11485 	|| !xim_styles->count_styles) {
11486 	xtermWarning("input method doesn't support any style\n");
11487 	cleanupInputMethod(xw);
11488 	xw->work.cannot_im = True;
11489 	return;
11490     }
11491 
11492     found = False;
11493     for (s = xw->misc.preedit_type; s && !found;) {
11494 	while (*s && isspace(CharOf(*s)))
11495 	    s++;
11496 	if (!*s)
11497 	    break;
11498 	if ((ns = end = strchr(s, ',')) != 0)
11499 	    ns++;
11500 	else
11501 	    end = s + strlen(s);
11502 	while ((end != s) && isspace(CharOf(end[-1])))
11503 	    end--;
11504 
11505 	if (end != s) {		/* just in case we have a spurious comma */
11506 	    TRACE(("looking for style '%.*s'\n", (int) (end - s), s));
11507 	    for (i = 0; i < XtNumber(known_style); i++) {
11508 		if ((int) strlen(known_style[i].name) == (end - s)
11509 		    && !strncmp(s, known_style[i].name, (size_t) (end - s))) {
11510 		    input_style = known_style[i].code;
11511 		    for (j = 0; j < xim_styles->count_styles; j++) {
11512 			if (input_style == xim_styles->supported_styles[j]) {
11513 			    found = True;
11514 			    break;
11515 			}
11516 		    }
11517 		    if (found)
11518 			break;
11519 		}
11520 	    }
11521 	}
11522 
11523 	s = ns;
11524     }
11525     XFree(xim_styles);
11526 
11527     if (!found) {
11528 	xtermWarning("input method doesn't support my preedit type (%s)\n",
11529 		     xw->misc.preedit_type);
11530 	cleanupInputMethod(xw);
11531 	xw->work.cannot_im = True;
11532 	return;
11533     }
11534 
11535     /*
11536      * Check for styles we do not yet support.
11537      */
11538     TRACE(("input_style %#lx\n", input_style));
11539     if (input_style == (XIMPreeditArea | XIMStatusArea)) {
11540 	xtermWarning("This program doesn't support the 'OffTheSpot' preedit type\n");
11541 	cleanupInputMethod(xw);
11542 	xw->work.cannot_im = True;
11543 	return;
11544     }
11545 
11546     /*
11547      * For XIMPreeditPosition (or OverTheSpot), XIM client has to
11548      * prepare a font.
11549      * The font has to be locale-dependent XFontSet, whereas
11550      * XTerm use Unicode font.  This leads a problem that the
11551      * same font cannot be used for XIM preedit.
11552      */
11553     if (input_style != (XIMPreeditNothing | XIMStatusNothing)) {
11554 	XVaNestedList p_list;
11555 	XPoint spot =
11556 	{0, 0};
11557 
11558 	if (xim_create_fs(xw)) {
11559 	    p_list = XVaCreateNestedList(0,
11560 					 XNSpotLocation, &spot,
11561 					 XNFontSet, xw->work.xim_fs,
11562 					 (void *) 0);
11563 	    input->xic = XCreateIC(input->xim,
11564 				   XNInputStyle, input_style,
11565 				   XNClientWindow, myWindow,
11566 				   XNFocusWindow, myWindow,
11567 				   XNPreeditAttributes, p_list,
11568 				   (void *) 0);
11569 	}
11570     } else {
11571 	input->xic = XCreateIC(input->xim, XNInputStyle, input_style,
11572 			       XNClientWindow, myWindow,
11573 			       XNFocusWindow, myWindow,
11574 			       (void *) 0);
11575     }
11576 
11577     if (!input->xic) {
11578 	xtermWarning("Failed to create input context\n");
11579 	cleanupInputMethod(xw);
11580     }
11581 #if defined(USE_XIM_INSTANTIATE_CB)
11582     else {
11583 	XIMCallback destroy_cb;
11584 
11585 	destroy_cb.callback = xim_destroy_cb;
11586 	destroy_cb.client_data = NULL;
11587 	if (XSetIMValues(input->xim,
11588 			 XNDestroyCallback,
11589 			 &destroy_cb,
11590 			 (void *) 0)) {
11591 	    xtermWarning("Could not set destroy callback to IM\n");
11592 	}
11593     }
11594 #endif
11595 
11596     return;
11597 }
11598 
11599 static void
xim_real_init(XtermWidget xw)11600 xim_real_init(XtermWidget xw)
11601 {
11602     xim_create_xic(xw, (Widget) xw);
11603 }
11604 
11605 static void
VTInitI18N(XtermWidget xw)11606 VTInitI18N(XtermWidget xw)
11607 {
11608     if (xw->misc.open_im) {
11609 	xim_real_init(xw);
11610 
11611 #if defined(USE_XIM_INSTANTIATE_CB)
11612 	if (lookupTInput(xw, (Widget) xw) == NULL
11613 	    && !xw->work.cannot_im
11614 	    && xw->misc.retry_im-- > 0) {
11615 	    sleep(3);
11616 	    XRegisterIMInstantiateCallback(XtDisplay(xw), NULL, NULL, NULL,
11617 					   xim_instantiate_cb, NULL);
11618 	}
11619 #endif
11620     }
11621 }
11622 
11623 TInput *
lookupTInput(XtermWidget xw,Widget w)11624 lookupTInput(XtermWidget xw, Widget w)
11625 {
11626     TInput *result = 0;
11627     unsigned n;
11628 
11629     for (n = 0; n < NINPUTWIDGETS; ++n) {
11630 	if (xw->work.inputs[n].w == w) {
11631 	    result = xw->work.inputs + n;
11632 	    break;
11633 	}
11634     }
11635 
11636     return result;
11637 }
11638 #endif /* OPT_INPUT_METHOD */
11639 
11640 static void
set_cursor_outline_gc(XtermWidget xw,Bool filled,Pixel fg,Pixel bg,Pixel cc)11641 set_cursor_outline_gc(XtermWidget xw,
11642 		      Bool filled,
11643 		      Pixel fg,
11644 		      Pixel bg,
11645 		      Pixel cc)
11646 {
11647     TScreen *screen = TScreenOf(xw);
11648     VTwin *win = WhichVWin(screen);
11649     CgsEnum cgsId = gcVTcursOutline;
11650 
11651     if (cc == bg)
11652 	cc = fg;
11653 
11654     if (filled) {
11655 	setCgsFore(xw, win, cgsId, bg);
11656 	setCgsBack(xw, win, cgsId, cc);
11657     } else {
11658 	setCgsFore(xw, win, cgsId, cc);
11659 	setCgsBack(xw, win, cgsId, bg);
11660     }
11661 }
11662 
11663 static Boolean
VTSetValues(Widget cur,Widget request GCC_UNUSED,Widget wnew,ArgList args GCC_UNUSED,Cardinal * num_args GCC_UNUSED)11664 VTSetValues(Widget cur,
11665 	    Widget request GCC_UNUSED,
11666 	    Widget wnew,
11667 	    ArgList args GCC_UNUSED,
11668 	    Cardinal *num_args GCC_UNUSED)
11669 {
11670     XtermWidget curvt = (XtermWidget) cur;
11671     XtermWidget newvt = (XtermWidget) wnew;
11672     Boolean refresh_needed = False;
11673     Boolean fonts_redone = False;
11674 
11675     if ((T_COLOR(TScreenOf(curvt), TEXT_BG) !=
11676 	 T_COLOR(TScreenOf(newvt), TEXT_BG)) ||
11677 	(T_COLOR(TScreenOf(curvt), TEXT_FG) !=
11678 	 T_COLOR(TScreenOf(newvt), TEXT_FG)) ||
11679 	(TScreenOf(curvt)->MenuFontName(TScreenOf(curvt)->menu_font_number) !=
11680 	 TScreenOf(newvt)->MenuFontName(TScreenOf(newvt)->menu_font_number)) ||
11681 	strcmp(DefaultFontN(curvt), DefaultFontN(newvt))) {
11682 	if (strcmp(DefaultFontN(curvt), DefaultFontN(newvt))) {
11683 	    TScreenOf(newvt)->MenuFontName(fontMenu_default) = DefaultFontN(newvt);
11684 	}
11685 	if (xtermLoadFont(newvt,
11686 			  xtermFontName(TScreenOf(newvt)->MenuFontName(TScreenOf(curvt)->menu_font_number)),
11687 			  True, TScreenOf(newvt)->menu_font_number)) {
11688 	    /* resizing does the redisplay, so don't ask for it here */
11689 	    refresh_needed = True;
11690 	    fonts_redone = True;
11691 	} else if (strcmp(DefaultFontN(curvt), DefaultFontN(newvt))) {
11692 	    TScreenOf(newvt)->MenuFontName(fontMenu_default) = DefaultFontN(curvt);
11693 	}
11694     }
11695     if (!fonts_redone
11696 	&& (T_COLOR(TScreenOf(curvt), TEXT_CURSOR) !=
11697 	    T_COLOR(TScreenOf(newvt), TEXT_CURSOR))) {
11698 	if (set_cursor_gcs(newvt))
11699 	    refresh_needed = True;
11700     }
11701     if (curvt->misc.re_verse != newvt->misc.re_verse) {
11702 	newvt->flags ^= REVERSE_VIDEO;
11703 	ReverseVideo(newvt);
11704 	/* ReverseVideo toggles */
11705 	newvt->misc.re_verse = (Boolean) (!newvt->misc.re_verse);
11706 	refresh_needed = True;
11707     }
11708     if ((T_COLOR(TScreenOf(curvt), MOUSE_FG) !=
11709 	 T_COLOR(TScreenOf(newvt), MOUSE_FG)) ||
11710 	(T_COLOR(TScreenOf(curvt), MOUSE_BG) !=
11711 	 T_COLOR(TScreenOf(newvt), MOUSE_BG))) {
11712 	recolor_cursor(TScreenOf(newvt),
11713 		       TScreenOf(newvt)->pointer_cursor,
11714 		       T_COLOR(TScreenOf(newvt), MOUSE_FG),
11715 		       T_COLOR(TScreenOf(newvt), MOUSE_BG));
11716 	refresh_needed = True;
11717     }
11718     if (curvt->misc.scrollbar != newvt->misc.scrollbar) {
11719 	ToggleScrollBar(newvt);
11720     }
11721 
11722     return refresh_needed;
11723 }
11724 
11725 /*
11726  * Given a font-slot and information about selection/reverse, find the
11727  * corresponding cached-GC slot.
11728  */
11729 #if OPT_WIDE_ATTRS
11730 static int
reverseCgs(XtermWidget xw,unsigned attr_flags,Bool hilite,int font)11731 reverseCgs(XtermWidget xw, unsigned attr_flags, Bool hilite, int font)
11732 {
11733     TScreen *screen = TScreenOf(xw);
11734     CgsEnum result = gcMAX;
11735 
11736     (void) screen;
11737     if (ReverseOrHilite(screen, attr_flags, hilite)) {
11738 	switch (font) {
11739 	case fNorm:
11740 	    result = gcNormReverse;
11741 	    break;
11742 	case fBold:
11743 	    result = gcBoldReverse;
11744 	    break;
11745 #if OPT_WIDE_ATTRS || OPT_RENDERWIDE
11746 	case fItal:
11747 	    result = gcNormReverse;	/* FIXME */
11748 	    break;
11749 #endif
11750 #if OPT_WIDE_CHARS
11751 	case fWide:
11752 	    result = gcWideReverse;
11753 	    break;
11754 	case fWBold:
11755 	    result = gcWBoldReverse;
11756 	    break;
11757 	case fWItal:
11758 	    result = gcWideReverse;	/* FIXME */
11759 	    break;
11760 #endif
11761 	}
11762     } else {
11763 	switch (font) {
11764 	case fNorm:
11765 	    result = gcNorm;
11766 	    break;
11767 	case fBold:
11768 	    result = gcBold;
11769 	    break;
11770 #if OPT_WIDE_ATTRS || OPT_RENDERWIDE
11771 	case fItal:
11772 	    result = gcNorm;	/* FIXME */
11773 	    break;
11774 #endif
11775 #if OPT_WIDE_CHARS
11776 	case fWide:
11777 	    result = gcWide;
11778 	    break;
11779 	case fWBold:
11780 	    result = gcWBold;
11781 	    break;
11782 	case fWItal:
11783 	    result = gcWide;	/* FIXME */
11784 	    break;
11785 #endif
11786 	}
11787     }
11788     return (int) result;
11789 }
11790 #endif
11791 
11792 #define setGC(code) set_at = __LINE__, currentCgs = code
11793 
11794 #define OutsideSelection(screen,srow,scol)  \
11795 	 ((srow) > (screen)->endH.row || \
11796 	  ((srow) == (screen)->endH.row && \
11797 	   (scol) >= (screen)->endH.col) || \
11798 	  (srow) < (screen)->startH.row || \
11799 	  ((srow) == (screen)->startH.row && \
11800 	   (scol) < (screen)->startH.col))
11801 
11802 /*
11803  * Shows cursor at new cursor position in screen.
11804  */
11805 void
ShowCursor(XtermWidget xw)11806 ShowCursor(XtermWidget xw)
11807 {
11808     TScreen *screen = TScreenOf(xw);
11809     XTermDraw params;
11810     IChar base;
11811     unsigned flags;
11812     CellColor fg_bg = initCColor;
11813     GC currentGC;
11814     GC outlineGC;
11815     CgsEnum currentCgs = gcMAX;
11816     VTwin *currentWin = WhichVWin(screen);
11817     int set_at;
11818     Bool in_selection;
11819     Bool reversed;
11820     Bool filled;
11821     Pixel fg_pix;
11822     Pixel bg_pix;
11823     Pixel tmp;
11824 #if OPT_HIGHLIGHT_COLOR
11825     Pixel selbg_pix = T_COLOR(screen, HIGHLIGHT_BG);
11826     Pixel selfg_pix = T_COLOR(screen, HIGHLIGHT_FG);
11827     Boolean use_selbg;
11828     Boolean use_selfg;
11829 #endif
11830 #if OPT_WIDE_CHARS
11831     int my_col = 0;
11832 #endif
11833     int cursor_col;
11834     CLineData *ld = 0;
11835 
11836     if (screen->cursor_state == BLINKED_OFF)
11837 	return;
11838 
11839     if (screen->eventMode != NORMAL)
11840 	return;
11841 
11842     if (INX2ROW(screen, screen->cur_row) > screen->max_row)
11843 	return;
11844 
11845     screen->cursorp.row = screen->cur_row;
11846     cursor_col = screen->cursorp.col = screen->cur_col;
11847     screen->cursor_moved = False;
11848 
11849 #ifndef NO_ACTIVE_ICON
11850     if (IsIcon(screen)) {
11851 	screen->cursor_state = ON;
11852 	return;
11853     }
11854 #endif /* NO_ACTIVE_ICON */
11855 
11856     ld = getLineData(screen, screen->cur_row);
11857 
11858     base = ld->charData[cursor_col];
11859     flags = ld->attribs[cursor_col];
11860 
11861     if_OPT_WIDE_CHARS(screen, {
11862 	if (base == HIDDEN_CHAR && cursor_col > 0) {
11863 	    /* if cursor points to non-initial part of wide character,
11864 	     * back it up
11865 	     */
11866 	    --cursor_col;
11867 	    base = ld->charData[cursor_col];
11868 	}
11869 	my_col = cursor_col;
11870 	if (base == 0)
11871 	    base = ' ';
11872 	if (isWide((int) base))
11873 	    my_col += 1;
11874     });
11875 
11876     if (base == 0) {
11877 	base = ' ';
11878     }
11879 #if OPT_ISO_COLORS
11880 #ifdef EXP_BOGUS_FG
11881     /*
11882      * If the cursor happens to be on blanks, and we have not set both
11883      * foreground and background color, do not treat it as a colored cell.
11884      */
11885     if (base == ' ') {
11886 	if ((flags & (FG_COLOR | BG_COLOR)) == BG_COLOR) {
11887 	    TRACE(("ShowCursor - do not treat as a colored cell\n"));
11888 	    flags &= ~(FG_COLOR | BG_COLOR);
11889 	} else if ((flags & (FG_COLOR | BG_COLOR)) == FG_COLOR) {
11890 	    TRACE(("ShowCursor - should we treat as a colored cell?\n"));
11891 	    if (!(xw->flags & FG_COLOR)) {
11892 		if (CheckBogusForeground(screen, "ShowCursor")) {
11893 		    flags &= ~(FG_COLOR | BG_COLOR);
11894 		}
11895 	    }
11896 	}
11897     }
11898 #else /* !EXP_BOGUS_FG */
11899     /*
11900      * If the cursor happens to be on blanks, and the foreground color is set
11901      * but not the background, do not treat it as a colored cell.
11902      */
11903     if ((flags & TERM_COLOR_FLAGS(xw)) == FG_COLOR
11904 	&& base == ' ') {
11905 	flags &= ~TERM_COLOR_FLAGS(xw);
11906     }
11907 #endif
11908 #endif
11909 
11910     /*
11911      * Compare the current cell to the last set of colors used for the
11912      * cursor and update the GC's if needed.
11913      */
11914     (void) fg_bg;
11915     if_OPT_ISO_COLORS(screen, {
11916 	fg_bg = ld->color[cursor_col];
11917     });
11918 
11919     fg_pix = getXtermFG(xw, flags, (int) extract_fg(xw, fg_bg, flags));
11920     bg_pix = getXtermBG(xw, flags, (int) extract_bg(xw, fg_bg, flags));
11921 
11922     /*
11923      * If we happen to have the same foreground/background colors, choose
11924      * a workable foreground color from which we can obtain a visible cursor.
11925      */
11926     if (fg_pix == bg_pix) {
11927 	long bg_diff = (long) (bg_pix - T_COLOR(TScreenOf(xw), TEXT_BG));
11928 	long fg_diff = (long) (bg_pix - T_COLOR(TScreenOf(xw), TEXT_FG));
11929 	if (bg_diff < 0)
11930 	    bg_diff = -bg_diff;
11931 	if (fg_diff < 0)
11932 	    fg_diff = -fg_diff;
11933 	if (bg_diff < fg_diff) {
11934 	    fg_pix = T_COLOR(TScreenOf(xw), TEXT_FG);
11935 	} else {
11936 	    fg_pix = T_COLOR(TScreenOf(xw), TEXT_BG);
11937 	}
11938     }
11939 
11940     if (OutsideSelection(screen, screen->cur_row, screen->cur_col))
11941 	in_selection = False;
11942     else
11943 	in_selection = True;
11944 
11945     reversed = ReverseOrHilite(screen, flags, in_selection);
11946 
11947     /* This is like updatedXtermGC(), except that we have to worry about
11948      * whether the window has focus, since in that case we want just an
11949      * outline for the cursor.
11950      */
11951     filled = (screen->select || screen->always_highlight) && isCursorBlock(screen);
11952 #if OPT_HIGHLIGHT_COLOR
11953     use_selbg = isNotForeground(xw, fg_pix, bg_pix, selbg_pix);
11954     use_selfg = isNotBackground(xw, fg_pix, bg_pix, selfg_pix);
11955 #endif
11956     if (filled) {
11957 	if (reversed) {		/* text is reverse video */
11958 	    if (getCgsGC(xw, currentWin, gcVTcursNormal)) {
11959 		setGC(gcVTcursNormal);
11960 	    } else {
11961 		if (flags & BOLDATTR(screen)) {
11962 		    setGC(gcBold);
11963 		} else {
11964 		    setGC(gcNorm);
11965 		}
11966 	    }
11967 	    EXCHANGE(fg_pix, bg_pix, tmp);
11968 #if OPT_HIGHLIGHT_COLOR
11969 	    if (screen->hilite_reverse) {
11970 		if (use_selbg && !use_selfg)
11971 		    fg_pix = bg_pix;
11972 		if (use_selfg && !use_selbg)
11973 		    bg_pix = fg_pix;
11974 		if (use_selbg)
11975 		    bg_pix = selbg_pix;
11976 		if (use_selfg)
11977 		    fg_pix = selfg_pix;
11978 	    }
11979 #endif
11980 	} else {		/* normal video */
11981 	    if (getCgsGC(xw, currentWin, gcVTcursReverse)) {
11982 		setGC(gcVTcursReverse);
11983 	    } else {
11984 		if (flags & BOLDATTR(screen)) {
11985 		    setGC(gcBoldReverse);
11986 		} else {
11987 		    setGC(gcNormReverse);
11988 		}
11989 	    }
11990 	}
11991 
11992 #define CUR_XX T_COLOR(screen, TEXT_CURSOR)
11993 #define CGS_FG getCgsFore(xw, currentWin, getCgsGC(xw, currentWin, currentCgs))
11994 #define CGS_BG getCgsBack(xw, currentWin, getCgsGC(xw, currentWin, currentCgs))
11995 
11996 #define FIX_311 (CUR_XX == (reversed ? xw->dft_background : xw->dft_foreground))
11997 #define FIX_328 (CUR_XX == bg_pix)
11998 #define FIX_330 (FIX_328 && reversed && in_selection)
11999 
12000 	if (FIX_330 || FIX_311) {
12001 	    setCgsBack(xw, currentWin, currentCgs, fg_pix);
12002 	}
12003 	setCgsFore(xw, currentWin, currentCgs, bg_pix);
12004     } else {			/* not selected */
12005 	if (reversed) {		/* text is reverse video */
12006 	    EXCHANGE(fg_pix, bg_pix, tmp);
12007 	    setGC(gcNormReverse);
12008 	} else {		/* normal video */
12009 	    setGC(gcNorm);
12010 	}
12011 #if OPT_HIGHLIGHT_COLOR
12012 	if (screen->hilite_reverse) {
12013 	    if (in_selection && !reversed) {
12014 		/* EMPTY */
12015 		/* really INVERSE ... */
12016 		;
12017 	    } else if (in_selection || reversed) {
12018 		if (use_selbg) {
12019 		    if (use_selfg) {
12020 			bg_pix = fg_pix;
12021 		    } else {
12022 			fg_pix = bg_pix;
12023 			bg_pix = selbg_pix;
12024 		    }
12025 		}
12026 		if (use_selfg) {
12027 		    fg_pix = selfg_pix;
12028 		}
12029 	    }
12030 	} else {
12031 	    if (in_selection) {
12032 		if (use_selbg) {
12033 		    bg_pix = selbg_pix;
12034 		}
12035 		if (use_selfg) {
12036 		    fg_pix = selfg_pix;
12037 		}
12038 	    }
12039 	}
12040 #endif
12041 	setCgsFore(xw, currentWin, currentCgs, fg_pix);
12042 	setCgsBack(xw, currentWin, currentCgs, bg_pix);
12043     }
12044 
12045     if (screen->cursor_busy == 0
12046 	&& (screen->cursor_state != ON || screen->cursor_GC != set_at)) {
12047 	int x, y;
12048 
12049 	screen->cursor_GC = set_at;
12050 	TRACE(("ShowCursor calling drawXtermText cur(%d,%d) %s-%s, set_at %d\n",
12051 	       screen->cur_row, screen->cur_col,
12052 	       (filled ? "filled" : "outline"),
12053 	       (isCursorBlock(screen) ? "box" :
12054 		isCursorUnderline(screen) ? "underline" : "bar"),
12055 	       set_at));
12056 
12057 	currentGC = getCgsGC(xw, currentWin, currentCgs);
12058 	x = LineCursorX(screen, ld, cursor_col);
12059 	y = CursorY(screen, screen->cur_row);
12060 
12061 	if (!isCursorBlock(screen)) {
12062 	    /*
12063 	     * Overriding the combination of filled, reversed, in_selection is
12064 	     * too complicated since the underline or bar and the text-cell use
12065 	     * different rules.  Just redraw the text-cell, and draw the
12066 	     * underline or bar on top of it.
12067 	     */
12068 	    HideCursor(xw);
12069 
12070 	    /*
12071 	     * Our current-GC is likely to have been modified in HideCursor().
12072 	     * Set up a new request.
12073 	     */
12074 	    if (filled) {
12075 		if (FIX_330 || FIX_311) {
12076 		    setCgsBack(xw, currentWin, currentCgs, fg_pix);
12077 		}
12078 		setCgsFore(xw, currentWin, currentCgs, bg_pix);
12079 	    } else {
12080 		setCgsFore(xw, currentWin, currentCgs, fg_pix);
12081 		setCgsBack(xw, currentWin, currentCgs, bg_pix);
12082 	    }
12083 	}
12084 
12085 	/*
12086 	 * Update the outline-gc, to keep the cursor color distinct from the
12087 	 * background color.
12088 	 */
12089 	set_cursor_outline_gc(xw,
12090 			      filled,
12091 			      fg_pix,
12092 			      bg_pix,
12093 			      T_COLOR(screen, TEXT_CURSOR));
12094 
12095 	outlineGC = getCgsGC(xw, currentWin, gcVTcursOutline);
12096 	if (outlineGC == 0)
12097 	    outlineGC = currentGC;
12098 
12099 	if (isCursorUnderline(screen)) {
12100 
12101 	    /*
12102 	     * Finally, draw the underline.
12103 	     */
12104 	    screen->box->x = (short) x;
12105 	    screen->box->y = (short) (y + FontHeight(screen) - 2);
12106 	    XDrawLines(screen->display, VDrawable(screen), outlineGC,
12107 		       screen->box, NBOX, CoordModePrevious);
12108 	} else if (isCursorBar(screen)) {
12109 
12110 	    /*
12111 	     * Or draw the bar.
12112 	     */
12113 	    screen->box->x = (short) x;
12114 	    screen->box->y = (short) y;
12115 	    XDrawLines(screen->display, VDrawable(screen), outlineGC,
12116 		       screen->box, NBOX, CoordModePrevious);
12117 	} else {
12118 #if OPT_WIDE_ATTRS
12119 	    int italics_on = ((ld->attribs[cursor_col] & ATR_ITALIC) != 0);
12120 	    int italics_off = ((xw->flags & ATR_ITALIC) != 0);
12121 	    int fix_italics = (italics_on != italics_off);
12122 	    int which_font = ((xw->flags & BOLD) ? fBold : fNorm);
12123 	    MyGetFont getter = italics_on ? getItalicFont : getNormalFont;
12124 
12125 	    if_OPT_WIDE_CHARS(screen, {
12126 		if (isWide((int) base)) {
12127 		    which_font = ((xw->flags & BOLD) ? fWBold : fWide);
12128 		}
12129 	    });
12130 
12131 	    if (fix_italics && UseItalicFont(screen)) {
12132 		xtermLoadItalics(xw);
12133 		setCgsFont(xw, currentWin, currentCgs,
12134 			   getter(screen, which_font));
12135 		getter = (((xw->flags & ATR_ITALIC) && UseItalicFont(screen))
12136 			  ? getItalicFont
12137 			  : getNormalFont);
12138 	    }
12139 	    currentGC = getCgsGC(xw, currentWin, currentCgs);
12140 #endif /* OPT_WIDE_ATTRS */
12141 
12142 	    /* *INDENT-EQLS* */
12143 	    params.xw          = xw;
12144 	    params.attr_flags  = (flags & DRAWX_MASK);
12145 	    params.draw_flags  = 0;
12146 	    params.this_chrset = LineCharSet(screen, ld);
12147 	    params.real_chrset = CSET_SWL;
12148 	    params.on_wide     = 0;
12149 
12150 	    drawXtermText(&params,
12151 			  currentGC, x, y,
12152 			  &base, 1);
12153 
12154 #if OPT_WIDE_CHARS
12155 	    if_OPT_WIDE_CHARS(screen, {
12156 		size_t off;
12157 
12158 		/* *INDENT-EQLS* */
12159 		params.draw_flags = NOBACKGROUND;
12160 		params.on_wide    = isWide((int) base);
12161 
12162 		for_each_combData(off, ld) {
12163 		    if (!(ld->combData[off][my_col]))
12164 			break;
12165 		    drawXtermText(&params,
12166 				  currentGC, x, y,
12167 				  ld->combData[off] + my_col, 1);
12168 		}
12169 	    });
12170 #endif
12171 
12172 	    if (!filled) {
12173 		screen->box->x = (short) x;
12174 		screen->box->y = (short) y;
12175 		XDrawLines(screen->display, VDrawable(screen), outlineGC,
12176 			   screen->box, NBOX, CoordModePrevious);
12177 	    }
12178 #if OPT_WIDE_ATTRS
12179 	    if (fix_italics && UseItalicFont(screen)) {
12180 		setCgsFont(xw, currentWin, currentCgs,
12181 			   getter(screen, which_font));
12182 	    }
12183 #endif
12184 	}
12185     }
12186     screen->cursor_state = ON;
12187 
12188     return;
12189 }
12190 
12191 /*
12192  * hide cursor at previous cursor position in screen.
12193  */
12194 void
HideCursor(XtermWidget xw)12195 HideCursor(XtermWidget xw)
12196 {
12197     TScreen *screen = TScreenOf(xw);
12198     XTermDraw params;
12199     GC currentGC;
12200     int x, y;
12201     IChar base;
12202     unsigned flags;
12203     CellColor fg_bg = initCColor;
12204     Bool in_selection;
12205 #if OPT_WIDE_CHARS
12206     int my_col = 0;
12207 #endif
12208     int cursor_col;
12209     CLineData *ld = 0;
12210 #if OPT_WIDE_ATTRS
12211     int which_Cgs = gcMAX;
12212     unsigned attr_flags;
12213     int which_font = fNorm;
12214     MyGetFont getter = getNormalFont;
12215 #endif
12216 
12217     if (screen->cursor_state == OFF)
12218 	return;
12219     if (INX2ROW(screen, screen->cursorp.row) > screen->max_row)
12220 	return;
12221 
12222     cursor_col = screen->cursorp.col;
12223 
12224 #ifndef NO_ACTIVE_ICON
12225     if (IsIcon(screen)) {
12226 	screen->cursor_state = OFF;
12227 	return;
12228     }
12229 #endif /* NO_ACTIVE_ICON */
12230 
12231     ld = getLineData(screen, screen->cursorp.row);
12232 
12233     base = ld->charData[cursor_col];
12234     flags = ld->attribs[cursor_col];
12235 
12236     if_OPT_WIDE_CHARS(screen, {
12237 	if (base == HIDDEN_CHAR && cursor_col > 0) {
12238 	    /* if cursor points to non-initial part of wide character,
12239 	     * back it up
12240 	     */
12241 	    --cursor_col;
12242 	    base = ld->charData[cursor_col];
12243 	}
12244 	my_col = cursor_col;
12245 	if (base == 0)
12246 	    base = ' ';
12247 	if (isWide((int) base))
12248 	    my_col += 1;
12249     });
12250 
12251     if (base == 0) {
12252 	base = ' ';
12253     }
12254 #ifdef EXP_BOGUS_FG
12255     /*
12256      * If the cursor happens to be on blanks, and we have not set both
12257      * foreground and background color, do not treat it as a colored cell.
12258      */
12259 #if OPT_ISO_COLORS
12260     if (base == ' ') {
12261 	if ((flags & (FG_COLOR | BG_COLOR)) == BG_COLOR) {
12262 	    TRACE(("HideCursor - do not treat as a colored cell\n"));
12263 	    flags &= ~(FG_COLOR | BG_COLOR);
12264 	} else if ((flags & (FG_COLOR | BG_COLOR)) == FG_COLOR) {
12265 	    TRACE(("HideCursor - should we treat as a colored cell?\n"));
12266 	    if (!(xw->flags & FG_COLOR))
12267 		if (CheckBogusForeground(screen, "HideCursor"))
12268 		    flags &= ~(FG_COLOR | BG_COLOR);
12269 	}
12270     }
12271 #endif
12272 #endif
12273 
12274     /*
12275      * Compare the current cell to the last set of colors used for the
12276      * cursor and update the GC's if needed.
12277      */
12278     if_OPT_ISO_COLORS(screen, {
12279 	fg_bg = ld->color[cursor_col];
12280     });
12281 
12282     if (OutsideSelection(screen, screen->cursorp.row, screen->cursorp.col))
12283 	in_selection = False;
12284     else
12285 	in_selection = True;
12286 
12287 #if OPT_WIDE_ATTRS
12288     attr_flags = ld->attribs[cursor_col];
12289     if ((attr_flags & ATR_ITALIC) ^ (xw->flags & ATR_ITALIC)) {
12290 	which_font = ((attr_flags & BOLD) ? fBold : fNorm);
12291 	if ((attr_flags & ATR_ITALIC) && UseItalicFont(screen))
12292 	    getter = getItalicFont;
12293 
12294 	if_OPT_WIDE_CHARS(screen, {
12295 	    if (isWide((int) base)) {
12296 		which_font = ((attr_flags & BOLD) ? fWBold : fWide);
12297 	    }
12298 	});
12299 
12300 	which_Cgs = reverseCgs(xw, attr_flags, in_selection, which_font);
12301 	if (which_Cgs != gcMAX) {
12302 	    setCgsFont(xw, WhichVWin(screen),
12303 		       (CgsEnum) which_Cgs,
12304 		       getter(screen, which_font));
12305 	    getter = (((xw->flags & ATR_ITALIC) && UseItalicFont(screen))
12306 		      ? getItalicFont
12307 		      : getNormalFont);
12308 	}
12309     }
12310 #endif
12311 
12312     currentGC = updatedXtermGC(xw, flags, fg_bg, in_selection);
12313 
12314     TRACE(("HideCursor calling drawXtermText cur(%d,%d)\n",
12315 	   screen->cursorp.row, screen->cursorp.col));
12316 
12317     x = LineCursorX(screen, ld, cursor_col);
12318     y = CursorY(screen, screen->cursorp.row);
12319 
12320     /* *INDENT-EQLS* */
12321     params.xw          = xw;
12322     params.attr_flags  = (flags & DRAWX_MASK);
12323     params.draw_flags  = 0;
12324     params.this_chrset = LineCharSet(screen, ld);
12325     params.real_chrset = CSET_SWL;
12326     params.on_wide     = 0;
12327 
12328     drawXtermText(&params,
12329 		  currentGC, x, y,
12330 		  &base, 1);
12331 
12332 #if OPT_WIDE_CHARS
12333     if_OPT_WIDE_CHARS(screen, {
12334 	size_t off;
12335 
12336 	/* *INDENT-EQLS* */
12337 	params.draw_flags  = NOBACKGROUND;
12338 	params.on_wide     = isWide((int) base);
12339 
12340 	for_each_combData(off, ld) {
12341 	    if (!(ld->combData[off][my_col]))
12342 		break;
12343 	    drawXtermText(&params,
12344 			  currentGC, x, y,
12345 			  ld->combData[off] + my_col, 1);
12346 	}
12347     });
12348 #endif
12349     screen->cursor_state = OFF;
12350 
12351 #if OPT_WIDE_ATTRS
12352     if (which_Cgs != gcMAX) {
12353 	setCgsFont(xw, WhichVWin(screen),
12354 		   (CgsEnum) which_Cgs,
12355 		   getter(screen, which_font));
12356     }
12357 #endif
12358     resetXtermGC(xw, flags, in_selection);
12359 
12360     refresh_displayed_graphics(xw,
12361 			       screen->cursorp.col,
12362 			       screen->cursorp.row,
12363 			       1, 1);
12364 
12365     return;
12366 }
12367 
12368 #if OPT_BLINK_CURS || OPT_BLINK_TEXT
12369 static void
StartBlinking(XtermWidget xw)12370 StartBlinking(XtermWidget xw)
12371 {
12372     TScreen *screen = TScreenOf(xw);
12373 
12374     if (screen->blink_timer == 0) {
12375 	unsigned long interval = (unsigned long) ((screen->cursor_state == ON)
12376 						  ? screen->blink_on
12377 						  : screen->blink_off);
12378 	if (interval == 0)	/* wow! */
12379 	    interval = 1;	/* let's humor him anyway */
12380 	screen->blink_timer = XtAppAddTimeOut(app_con,
12381 					      interval,
12382 					      HandleBlinking,
12383 					      xw);
12384     }
12385 }
12386 
12387 static void
StopBlinking(XtermWidget xw)12388 StopBlinking(XtermWidget xw)
12389 {
12390     TScreen *screen = TScreenOf(xw);
12391 
12392     if (screen->blink_timer) {
12393 	XtRemoveTimeOut(screen->blink_timer);
12394 	screen->blink_timer = 0;
12395 	reallyStopBlinking(xw);
12396     } else {
12397 	screen->blink_timer = 0;
12398     }
12399 }
12400 
12401 #if OPT_BLINK_TEXT
12402 Bool
LineHasBlinking(TScreen * screen,CLineData * ld)12403 LineHasBlinking(TScreen *screen, CLineData *ld)
12404 {
12405     Bool result = False;
12406     if (ld != 0) {
12407 	int col;
12408 
12409 	for (col = 0; col < MaxCols(screen); ++col) {
12410 	    if (ld->attribs[col] & BLINK) {
12411 		result = True;
12412 		break;
12413 	    }
12414 	}
12415     }
12416     return result;
12417 }
12418 #endif
12419 
12420 /*
12421  * Blink the cursor by alternately showing/hiding cursor.  We leave the timer
12422  * running all the time (even though that's a little inefficient) to make the
12423  * logic simple.
12424  */
12425 static void
HandleBlinking(XtPointer closure,XtIntervalId * id GCC_UNUSED)12426 HandleBlinking(XtPointer closure, XtIntervalId * id GCC_UNUSED)
12427 {
12428     XtermWidget xw = (XtermWidget) closure;
12429     TScreen *screen = TScreenOf(xw);
12430     Bool resume = False;
12431 
12432     screen->blink_timer = 0;
12433     screen->blink_state = !screen->blink_state;
12434 
12435 #if OPT_BLINK_CURS
12436     if (DoStartBlinking(screen)) {
12437 	if (screen->cursor_state == ON) {
12438 	    if (screen->select || screen->always_highlight) {
12439 		HideCursor(xw);
12440 		if (screen->cursor_state == OFF)
12441 		    screen->cursor_state = BLINKED_OFF;
12442 	    }
12443 	} else if (screen->cursor_state == BLINKED_OFF) {
12444 	    screen->cursor_state = OFF;
12445 	    ShowCursor(xw);
12446 	    if (screen->cursor_state == OFF)
12447 		screen->cursor_state = BLINKED_OFF;
12448 	}
12449 	resume = True;
12450     }
12451 #endif
12452 
12453 #if OPT_BLINK_TEXT
12454     /*
12455      * Inspect the lines on the current screen to see if any have the BLINK flag
12456      * associated with them.  Prune off any that have had the corresponding
12457      * cells reset.  If any are left, repaint those lines with ScrnRefresh().
12458      */
12459     if (!(screen->blink_as_bold)) {
12460 	int row;
12461 	int first_row = screen->max_row;
12462 	int last_row = -1;
12463 
12464 	for (row = screen->max_row; row >= 0; row--) {
12465 	    LineData *ld = getLineData(screen, ROW2INX(screen, row));
12466 
12467 	    if (ld != 0 && LineTstBlinked(ld)) {
12468 		if (LineHasBlinking(screen, ld)) {
12469 		    resume = True;
12470 		    if (row > last_row)
12471 			last_row = row;
12472 		    if (row < first_row)
12473 			first_row = row;
12474 		} else {
12475 		    LineClrBlinked(ld);
12476 		}
12477 	    }
12478 	}
12479 	/*
12480 	 * FIXME: this could be a little more efficient, e.g,. by limiting the
12481 	 * columns which are updated.
12482 	 */
12483 	if (first_row <= last_row) {
12484 	    ScrnRefresh(xw,
12485 			first_row,
12486 			0,
12487 			last_row + 1 - first_row,
12488 			MaxCols(screen),
12489 			True);
12490 	}
12491     }
12492 #endif
12493 
12494     /*
12495      * If either the cursor or text is blinking, restart the timer.
12496      */
12497     if (resume)
12498 	StartBlinking(xw);
12499 }
12500 #endif /* OPT_BLINK_CURS || OPT_BLINK_TEXT */
12501 
12502 void
RestartBlinking(XtermWidget xw)12503 RestartBlinking(XtermWidget xw)
12504 {
12505 #if OPT_BLINK_CURS || OPT_BLINK_TEXT
12506     TScreen *screen = TScreenOf(xw);
12507 
12508     if (screen->blink_timer == 0) {
12509 	Bool resume = False;
12510 
12511 #if OPT_BLINK_CURS
12512 	if (DoStartBlinking(screen)) {
12513 	    resume = True;
12514 	}
12515 #endif
12516 #if OPT_BLINK_TEXT
12517 	if (!resume) {
12518 	    int row;
12519 
12520 	    for (row = screen->max_row; row >= 0; row--) {
12521 		CLineData *ld = getLineData(screen, ROW2INX(screen, row));
12522 
12523 		if (ld != 0 && LineTstBlinked(ld)) {
12524 		    if (LineHasBlinking(screen, ld)) {
12525 			resume = True;
12526 			break;
12527 		    }
12528 		}
12529 	    }
12530 	}
12531 #endif
12532 	if (resume)
12533 	    StartBlinking(xw);
12534     }
12535 #else
12536     (void) xw;
12537 #endif
12538 }
12539 
12540 /*
12541  * Implement soft or hard (full) reset of the VTxxx emulation.  There are a
12542  * couple of differences from real DEC VTxxx terminals (to avoid breaking
12543  * applications which have come to rely on xterm doing this):
12544  *
12545  *	+ autowrap mode should be reset (instead it's reset to the resource
12546  *	  default).
12547  *	+ the popup menu offers a choice of resetting the savedLines, or not.
12548  *	  (but the control sequence does this anyway).
12549  */
12550 static void
ReallyReset(XtermWidget xw,Bool full,Bool saved)12551 ReallyReset(XtermWidget xw, Bool full, Bool saved)
12552 {
12553     TScreen *screen = TScreenOf(xw);
12554     IFlags saveflags = xw->flags;
12555 
12556     TRACE(("ReallyReset %s, %s\n",
12557 	   full ? "hard" : "soft",
12558 	   saved ? "clear savedLines" : "keep savedLines"));
12559 
12560     if (!XtIsRealized((Widget) xw) || (CURRENT_EMU() != (Widget) xw)) {
12561 	Bell(xw, XkbBI_MinorError, 0);
12562 	return;
12563     }
12564 
12565     if (saved) {
12566 	screen->savedlines = 0;
12567 	ScrollBarDrawThumb(xw, 0);
12568     }
12569 
12570     /* make cursor visible */
12571     screen->cursor_set = ON;
12572     InitCursorShape(screen, screen);
12573     xtermSetCursorBox(screen);
12574 #if OPT_BLINK_CURS
12575     screen->cursor_blink = screen->cursor_blink_i;
12576     screen->cursor_blink_esc = 0;
12577     TRACE(("cursor_shape:%d blinks:%d\n",
12578 	   screen->cursor_shape,
12579 	   screen->cursor_blink));
12580 #endif
12581 
12582     /* reset scrolling region */
12583     resetMarginMode(xw);
12584 
12585     bitclr(&xw->flags, ORIGIN);
12586 
12587     if_OPT_ISO_COLORS(screen, {
12588 	static char empty[1];
12589 	reset_SGR_Colors(xw);
12590 	if (ResetAnsiColorRequest(xw, empty, 0))
12591 	    xtermRepaint(xw);
12592     });
12593 
12594     /* Reset character-sets to initial state */
12595     resetCharsets(screen);
12596 
12597 #if OPT_MOD_FKEYS
12598     /* Reset modifier-resources to initial state */
12599     xw->keyboard.modify_now = xw->keyboard.modify_1st;
12600 #endif
12601 #if OPT_DEC_RECTOPS
12602     screen->checksum_ext = screen->checksum_ext0;
12603 #endif
12604 
12605     /* Reset DECSCA */
12606     bitclr(&xw->flags, PROTECTED);
12607     screen->protected_mode = OFF_PROTECT;
12608 
12609     if (full) {			/* RIS */
12610 	if (screen->bellOnReset)
12611 	    Bell(xw, XkbBI_TerminalBell, 0);
12612 
12613 	reset_displayed_graphics(screen);
12614 
12615 	/* reset the mouse mode */
12616 	screen->send_mouse_pos = MOUSE_OFF;
12617 	screen->send_focus_pos = OFF;
12618 	screen->extend_coords = 0;
12619 	screen->waitingForTrackInfo = False;
12620 	screen->eventMode = NORMAL;
12621 
12622 	xtermShowPointer(xw, True);
12623 
12624 	TabReset(xw->tabs);
12625 	xw->keyboard.flags = MODE_SRM;
12626 
12627 	guard_keyboard_type = False;
12628 	screen->old_fkeys = screen->old_fkeys0;
12629 	decode_keyboard_type(xw, &resource);
12630 	update_keyboard_type();
12631 
12632 #if OPT_INITIAL_ERASE
12633 	if (xw->keyboard.reset_DECBKM == 1)
12634 	    xw->keyboard.flags |= MODE_DECBKM;
12635 	else if (xw->keyboard.reset_DECBKM == 2)
12636 #endif
12637 	    if (TScreenOf(xw)->backarrow_key)
12638 		xw->keyboard.flags |= MODE_DECBKM;
12639 	TRACE(("full reset DECBKM %s\n",
12640 	       BtoS(xw->keyboard.flags & MODE_DECBKM)));
12641 
12642 #if OPT_SCROLL_LOCK
12643 	xtermClearLEDs(screen);
12644 #endif
12645 	screen->title_modes = screen->title_modes0;
12646 	screen->pointer_mode = screen->pointer_mode0;
12647 #if OPT_SIXEL_GRAPHICS
12648 	if (TScreenOf(xw)->sixel_scrolling)
12649 	    xw->keyboard.flags |= MODE_DECSDM;
12650 	TRACE(("full reset DECSDM to %s (resource default is %s)\n",
12651 	       BtoS(xw->keyboard.flags & MODE_DECSDM),
12652 	       BtoS(TScreenOf(xw)->sixel_scrolling)));
12653 #endif
12654 
12655 #if OPT_GRAPHICS
12656 	screen->privatecolorregisters = TScreenOf(xw)->privatecolorregisters;
12657 	TRACE(("full reset PRIVATE_COLOR_REGISTERS to %s (resource default is %s)\n",
12658 	       BtoS(screen->privatecolorregisters),
12659 	       BtoS(TScreenOf(xw)->privatecolorregisters)));
12660 #endif
12661 
12662 #if OPT_SIXEL_GRAPHICS
12663 	screen->sixel_scrolls_right = TScreenOf(xw)->sixel_scrolls_right;
12664 	TRACE(("full reset SIXEL_SCROLLS_RIGHT to %s (resource default is %s)\n",
12665 	       BtoS(screen->sixel_scrolls_right),
12666 	       BtoS(TScreenOf(xw)->sixel_scrolls_right)));
12667 #endif
12668 
12669 	update_appcursor();
12670 	update_appkeypad();
12671 	update_decbkm();
12672 	update_decsdm();
12673 	show_8bit_control(False);
12674 	reset_decudk(xw);
12675 
12676 	FromAlternate(xw);
12677 	ClearScreen(xw);
12678 	screen->cursor_state = OFF;
12679 
12680 	if (xw->flags & REVERSE_VIDEO)
12681 	    ReverseVideo(xw);
12682 	ResetItalics(xw);
12683 	xw->flags = xw->initflags;
12684 
12685 	update_reversevideo();
12686 	update_autowrap();
12687 	update_reversewrap();
12688 	update_autolinefeed();
12689 
12690 	screen->jumpscroll = (Boolean) (!(xw->flags & SMOOTHSCROLL));
12691 	update_jumpscroll();
12692 
12693 #if OPT_DEC_RECTOPS
12694 	screen->cur_decsace = 0;
12695 #endif
12696 #if OPT_PASTE64 || OPT_READLINE
12697 	screen->paste_brackets = OFF;
12698 #endif
12699 #if OPT_READLINE
12700 	screen->click1_moves = OFF;
12701 	screen->paste_moves = OFF;
12702 	screen->dclick3_deletes = OFF;
12703 	screen->paste_quotes = OFF;
12704 	screen->paste_literal_nl = OFF;
12705 #endif /* OPT_READLINE */
12706 
12707 	if (screen->c132 && (saveflags & IN132COLUMNS)) {
12708 	    TRACE(("Making resize-request to restore 80-columns %dx%d\n",
12709 		   MaxRows(screen), MaxCols(screen)));
12710 	    RequestResize(xw, MaxRows(screen), 80, True);
12711 	    repairSizeHints();
12712 	    XSync(screen->display, False);	/* synchronize */
12713 	    if (xtermAppPending())
12714 		xevents(xw);
12715 	}
12716 
12717 	CursorSet(screen, 0, 0, xw->flags);
12718 	CursorSave(xw);
12719     } else {			/* DECSTR */
12720 	/*
12721 	 * There's a tiny difference, to accommodate usage of xterm.
12722 	 * We reset autowrap to the resource values rather than turning
12723 	 * it off.
12724 	 */
12725 	UIntClr(xw->keyboard.flags, (MODE_DECCKM | MODE_KAM | MODE_DECKPAM));
12726 	bitcpy(&xw->flags, xw->initflags, WRAPAROUND | REVERSEWRAP);
12727 	bitclr(&xw->flags, INSERT | INVERSE | BOLD | BLINK | UNDERLINE | INVISIBLE);
12728 	ResetItalics(xw);
12729 	if_OPT_ISO_COLORS(screen, {
12730 	    reset_SGR_Colors(xw);
12731 	});
12732 	update_appcursor();
12733 	update_autowrap();
12734 	update_reversewrap();
12735 
12736 	CursorSave(xw);
12737 	screen->sc[screen->whichBuf].row =
12738 	    screen->sc[screen->whichBuf].col = 0;
12739     }
12740 }
12741 
12742 void
VTReset(XtermWidget xw,Bool full,Bool saved)12743 VTReset(XtermWidget xw, Bool full, Bool saved)
12744 {
12745     ReallyReset(xw, full, saved);
12746 
12747     FreeAndNull(myState.string_area);
12748     FreeAndNull(myState.print_area);
12749 
12750     longjmp(vtjmpbuf, 1);	/* force ground state in parser */
12751 }
12752 
12753 typedef enum {
12754     ccLO,
12755     ccDASH,
12756     ccHI,
12757     ccCOLON,
12758     ccID,
12759     ccCOMMA
12760 } CCLASS;
12761 
12762 /*
12763  * set_character_class - takes a string of the form
12764  *
12765  *   low[-high][:id][,low[-high][:id][...]]
12766  *
12767  * and sets the indicated ranges to the indicated values.
12768  */
12769 static int
set_character_class(char * s)12770 set_character_class(char *s)
12771 {
12772 #define FMT "%s in range string \"%s\" (position %d)\n"
12773 
12774     TRACE(("set_character_class(%s) " TRACE_L "\n", NonNull(s)));
12775     if (IsEmpty(s)) {
12776 	TRACE((TRACE_R " ERR set_character_class\n"));
12777 	return -1;
12778     } else {
12779 	CCLASS state = ccLO;
12780 	int arg[3];
12781 	int i;
12782 	int len = (int) strlen(s);
12783 
12784 	arg[0] =
12785 	    arg[1] =
12786 	    arg[2] = -1;
12787 
12788 	for (i = 0; i < len; ++i) {
12789 	    int ch = CharOf(s[i]);
12790 	    char *t = 0;
12791 	    long value = 0;
12792 
12793 	    if (isspace(ch))
12794 		continue;
12795 
12796 	    switch (state) {
12797 	    case ccLO:
12798 	    case ccHI:
12799 	    case ccID:
12800 		if (!isdigit(ch)) {
12801 		    xtermWarning(FMT, "missing number", s, i);
12802 		    TRACE((TRACE_R " ERR set_character_class\n"));
12803 		    return (-1);
12804 		}
12805 		value = strtol(s + i, &t, 0);
12806 		i = (int) (t - s - 1);
12807 		break;
12808 	    case ccDASH:
12809 	    case ccCOLON:
12810 	    case ccCOMMA:
12811 		break;
12812 	    }
12813 
12814 	    switch (state) {
12815 	    case ccLO:
12816 		arg[0] =
12817 		    arg[1] = (int) value;
12818 		arg[2] = -1;
12819 		state = ccDASH;
12820 		break;
12821 
12822 	    case ccDASH:
12823 		if (ch == '-') {
12824 		    state = ccHI;
12825 		} else {
12826 		    goto parse_class;
12827 		}
12828 		break;
12829 
12830 	    case ccHI:
12831 		arg[1] = (int) value;
12832 		state = ccCOLON;
12833 		break;
12834 
12835 	      parse_class:
12836 	    case ccCOLON:
12837 		if (ch == ':') {
12838 		    state = ccID;
12839 		} else if (ch == ',') {
12840 		    goto apply_class;
12841 		} else {
12842 		    xtermWarning(FMT, "unexpected character", s, i);
12843 		    TRACE((TRACE_R " ERR set_character_class\n"));
12844 		    return (-1);
12845 		}
12846 		break;
12847 
12848 	    case ccID:
12849 		arg[2] = (int) value;
12850 		state = ccCOMMA;
12851 		break;
12852 
12853 	      apply_class:
12854 	    case ccCOMMA:
12855 		if (SetCharacterClassRange(arg[0], arg[1], arg[2]) != 0) {
12856 		    xtermWarning(FMT, "bad range", s, i);
12857 		    TRACE((TRACE_R " ERR set_character_class\n"));
12858 		    return -1;
12859 		}
12860 		state = ccLO;
12861 		break;
12862 	    }
12863 	}
12864 	if (state >= ccDASH) {
12865 	    if (SetCharacterClassRange(arg[0], arg[1], arg[2]) != 0) {
12866 		xtermWarning(FMT, "bad range", s, i);
12867 		TRACE((TRACE_R " ERR set_character_class\n"));
12868 		return -1;
12869 	    }
12870 	}
12871     }
12872 
12873     TRACE((TRACE_R " OK set_character_class\n"));
12874     return (0);
12875 #undef FMT
12876 }
12877 
12878 void
getKeymapResources(Widget w,const char * mapName,const char * mapClass,const char * type,void * result,size_t size)12879 getKeymapResources(Widget w,
12880 		   const char *mapName,
12881 		   const char *mapClass,
12882 		   const char *type,
12883 		   void *result,
12884 		   size_t size)
12885 {
12886     XtResource key_resources[1];
12887     key_resources[0].resource_name = XtNtranslations;
12888     key_resources[0].resource_class = XtCTranslations;
12889     key_resources[0].resource_type = (char *) type;
12890     key_resources[0].resource_size = (Cardinal) size;
12891     key_resources[0].resource_offset = 0;
12892     key_resources[0].default_type = key_resources[0].resource_type;
12893     key_resources[0].default_addr = 0;
12894     XtGetSubresources(w, (XtPointer) result, mapName, mapClass,
12895 		      key_resources, (Cardinal) 1, NULL, (Cardinal) 0);
12896 }
12897 
12898 /* ARGSUSED */
12899 static void
HandleKeymapChange(Widget w,XEvent * event GCC_UNUSED,String * params,Cardinal * param_count)12900 HandleKeymapChange(Widget w,
12901 		   XEvent *event GCC_UNUSED,
12902 		   String *params,
12903 		   Cardinal *param_count)
12904 {
12905     static XtTranslations keymap, original;
12906 
12907     TRACE(("HandleKeymapChange(%#lx, %s)\n",
12908 	   (unsigned long) w,
12909 	   (*param_count
12910 	    ? params[0]
12911 	    : "missing")));
12912 
12913     if (*param_count != 1)
12914 	return;
12915 
12916     if (original == NULL) {
12917 	TRACE(("...saving original keymap-translations\n"));
12918 	original = w->core.tm.translations;
12919     }
12920 
12921     if (strcmp(params[0], "None") == 0) {
12922 	TRACE(("...restoring original keymap-translations\n"));
12923 	XtOverrideTranslations(w, original);
12924     } else {
12925 	char mapName[1000];
12926 	char mapClass[1000];
12927 	char *pmapName;
12928 	char *pmapClass;
12929 	size_t len;
12930 
12931 	len = strlen(params[0]) + 7;
12932 
12933 	pmapName = (char *) MyStackAlloc(len, mapName);
12934 	pmapClass = (char *) MyStackAlloc(len, mapClass);
12935 	if (pmapName == NULL
12936 	    || pmapClass == NULL) {
12937 	    SysError(ERROR_KMMALLOC1);
12938 	} else {
12939 
12940 	    (void) sprintf(pmapName, "%sKeymap", params[0]);
12941 	    (void) strcpy(pmapClass, pmapName);
12942 	    if (islower(CharOf(pmapClass[0])))
12943 		pmapClass[0] = x_toupper(pmapClass[0]);
12944 	    getKeymapResources(w, pmapName, pmapClass, XtRTranslationTable,
12945 			       &keymap, sizeof(keymap));
12946 	    if (keymap != NULL) {
12947 		TRACE(("...applying keymap \"%s\"\n", pmapName));
12948 		XtOverrideTranslations(w, keymap);
12949 	    } else {
12950 		TRACE(("...found no match for keymap \"%s\"\n", pmapName));
12951 	    }
12952 
12953 	    MyStackFree(pmapName, mapName);
12954 	    MyStackFree(pmapClass, mapClass);
12955 	}
12956     }
12957 }
12958 
12959 /* ARGSUSED */
12960 static void
HandleBell(Widget w GCC_UNUSED,XEvent * event GCC_UNUSED,String * params,Cardinal * param_count)12961 HandleBell(Widget w GCC_UNUSED,
12962 	   XEvent *event GCC_UNUSED,
12963 	   String *params,	/* [0] = volume */
12964 	   Cardinal *param_count)	/* 0 or 1 */
12965 {
12966     int percent = (*param_count) ? atoi(params[0]) : 0;
12967 
12968     Bell(term, XkbBI_TerminalBell, percent);
12969 }
12970 
12971 /* ARGSUSED */
12972 static void
HandleVisualBell(Widget w GCC_UNUSED,XEvent * event GCC_UNUSED,String * params GCC_UNUSED,Cardinal * param_count GCC_UNUSED)12973 HandleVisualBell(Widget w GCC_UNUSED,
12974 		 XEvent *event GCC_UNUSED,
12975 		 String *params GCC_UNUSED,
12976 		 Cardinal *param_count GCC_UNUSED)
12977 {
12978     VisualBell();
12979 }
12980 
12981 /* ARGSUSED */
12982 static void
HandleIgnore(Widget w,XEvent * event,String * params GCC_UNUSED,Cardinal * param_count GCC_UNUSED)12983 HandleIgnore(Widget w,
12984 	     XEvent *event,
12985 	     String *params GCC_UNUSED,
12986 	     Cardinal *param_count GCC_UNUSED)
12987 {
12988     XtermWidget xw;
12989 
12990     TRACE(("Handle ignore for %p %s\n",
12991 	   (void *) w, visibleEventType(event->type)));
12992     if ((xw = getXtermWidget(w)) != 0) {
12993 	/* do nothing, but check for funny escape sequences */
12994 	switch (event->type) {
12995 	case ButtonPress:
12996 	case ButtonRelease:
12997 	case MotionNotify:
12998 	    (void) SendMousePosition(xw, event);
12999 	    break;
13000 	}
13001     }
13002 }
13003 
13004 /* ARGSUSED */
13005 static void
DoSetSelectedFont(Widget w,XtPointer client_data GCC_UNUSED,Atom * selection GCC_UNUSED,Atom * type,XtPointer value,unsigned long * length,int * format)13006 DoSetSelectedFont(Widget w,
13007 		  XtPointer client_data GCC_UNUSED,
13008 		  Atom *selection GCC_UNUSED,
13009 		  Atom *type,
13010 		  XtPointer value,
13011 		  unsigned long *length,
13012 		  int *format)
13013 {
13014     XtermWidget xw = getXtermWidget(w);
13015 
13016     if (xw == 0) {
13017 	xtermWarning("unexpected widget in DoSetSelectedFont\n");
13018     } else if (*type != XA_STRING || *format != 8) {
13019 	Bell(xw, XkbBI_MinorError, 0);
13020     } else {
13021 	Boolean failed = False;
13022 	int oldFont = TScreenOf(xw)->menu_font_number;
13023 	char *save = TScreenOf(xw)->SelectFontName();
13024 	char *val;
13025 	char *test;
13026 	unsigned len = (unsigned) *length;
13027 	unsigned tst;
13028 
13029 	/*
13030 	 * Some versions of X deliver null-terminated selections, some do not.
13031 	 */
13032 	for (tst = 0; tst < len; ++tst) {
13033 	    if (((char *) value)[tst] == '\0') {
13034 		len = tst;
13035 		break;
13036 	    }
13037 	}
13038 
13039 	if (len > 0 && (val = TypeMallocN(char, len + 1)) != 0) {
13040 	    char *used;
13041 
13042 	    memcpy(val, value, (size_t) len);
13043 	    val[len] = '\0';
13044 	    used = x_strtrim(val);
13045 	    TRACE(("DoSetSelectedFont(%s)\n", used));
13046 	    /* Do some sanity checking to avoid sending a long selection
13047 	       back to the server in an OpenFont that is unlikely to succeed.
13048 	       XLFD allows up to 255 characters and no control characters;
13049 	       we are a little more liberal here. */
13050 	    if (len < 1000
13051 		&& used != 0
13052 		&& !strchr(used, '\n')
13053 		&& (test = x_strdup(used)) != 0) {
13054 		TScreenOf(xw)->SelectFontName() = test;
13055 		if (!xtermLoadFont(xw,
13056 				   xtermFontName(used),
13057 				   True,
13058 				   fontMenu_fontsel)) {
13059 		    failed = True;
13060 		    free(test);
13061 		    TScreenOf(xw)->SelectFontName() = save;
13062 		}
13063 	    } else {
13064 		failed = True;
13065 	    }
13066 	    if (failed) {
13067 		(void) xtermLoadFont(xw,
13068 				     xtermFontName(TScreenOf(xw)->MenuFontName(oldFont)),
13069 				     True,
13070 				     oldFont);
13071 		Bell(xw, XkbBI_MinorError, 0);
13072 	    }
13073 	    free(used);
13074 	    free(val);
13075 	}
13076     }
13077 }
13078 
13079 void
FindFontSelection(XtermWidget xw,const char * atom_name,Bool justprobe)13080 FindFontSelection(XtermWidget xw, const char *atom_name, Bool justprobe)
13081 {
13082     TScreen *screen = TScreenOf(xw);
13083     static AtomPtr *atoms;
13084     static unsigned int atomCount = 0;
13085     AtomPtr *pAtom;
13086     unsigned a;
13087     Atom target;
13088 
13089     if (!atom_name)
13090 	atom_name = ((screen->mappedSelect && atomCount)
13091 		     ? screen->mappedSelect[0]
13092 		     : "PRIMARY");
13093     TRACE(("FindFontSelection(%s)\n", atom_name));
13094 
13095     for (pAtom = atoms, a = atomCount; a; a--, pAtom++) {
13096 	if (strcmp(atom_name, XmuNameOfAtom(*pAtom)) == 0) {
13097 	    TRACE(("...found atom %d:%s\n", a + 1, atom_name));
13098 	    break;
13099 	}
13100     }
13101     if (!a) {
13102 	atoms = TypeXtReallocN(AtomPtr, atoms, atomCount + 1);
13103 	*(pAtom = &atoms[atomCount]) = XmuMakeAtom(atom_name);
13104 	++atomCount;
13105 	TRACE(("...added atom %d:%s\n", atomCount, atom_name));
13106     }
13107 
13108     target = XmuInternAtom(XtDisplay(xw), *pAtom);
13109     if (justprobe) {
13110 	screen->SelectFontName() =
13111 	    XGetSelectionOwner(XtDisplay(xw), target) ? _Font_Selected_ : 0;
13112 	TRACE(("...selected fontname '%s'\n",
13113 	       NonNull(screen->SelectFontName())));
13114     } else {
13115 	XtGetSelectionValue((Widget) xw, target, XA_STRING,
13116 			    DoSetSelectedFont, NULL,
13117 			    XtLastTimestampProcessed(XtDisplay(xw)));
13118     }
13119     return;
13120 }
13121 
13122 Bool
set_cursor_gcs(XtermWidget xw)13123 set_cursor_gcs(XtermWidget xw)
13124 {
13125     TScreen *screen = TScreenOf(xw);
13126     VTwin *win = WhichVWin(screen);
13127 
13128     Pixel cc = T_COLOR(screen, TEXT_CURSOR);
13129     Pixel fg = T_COLOR(screen, TEXT_FG);
13130     Pixel bg = T_COLOR(screen, TEXT_BG);
13131     Bool changed = False;
13132 
13133     /*
13134      * Let's see, there are three things that have "color":
13135      *
13136      *     background
13137      *     text
13138      *     cursorblock
13139      *
13140      * And, there are four situations when drawing a cursor, if we decide
13141      * that we like have a solid block of cursor color with the letter
13142      * that it is highlighting shown in the background color to make it
13143      * stand out:
13144      *
13145      *     selected window, normal video - background on cursor
13146      *     selected window, reverse video - foreground on cursor
13147      *     unselected window, normal video - foreground on background
13148      *     unselected window, reverse video - background on foreground
13149      *
13150      * Since the last two are really just normalGC and reverseGC, we only
13151      * need two new GC's.  Under monochrome, we get the same effect as
13152      * above by setting cursor color to foreground.
13153      */
13154 
13155     TRACE(("set_cursor_gcs cc=%#lx, fg=%#lx, bg=%#lx\n", cc, fg, bg));
13156     if (win != 0 && (cc != bg)) {
13157 	Pixel xx = ((fg == cc) ? bg : cc);
13158 
13159 	/* set the fonts to the current one */
13160 	setCgsFont(xw, win, gcVTcursNormal, 0);
13161 	setCgsFont(xw, win, gcVTcursFilled, 0);
13162 	setCgsFont(xw, win, gcVTcursReverse, 0);
13163 	setCgsFont(xw, win, gcVTcursOutline, 0);
13164 
13165 	/* we have a colored cursor */
13166 	setCgsFore(xw, win, gcVTcursNormal, fg);
13167 	setCgsBack(xw, win, gcVTcursNormal, xx);
13168 
13169 	setCgsFore(xw, win, gcVTcursFilled, xx);
13170 	setCgsBack(xw, win, gcVTcursFilled, fg);
13171 
13172 	if (screen->always_highlight) {
13173 	    /* both GC's use the same color */
13174 	    setCgsFore(xw, win, gcVTcursReverse, bg);
13175 	    setCgsBack(xw, win, gcVTcursReverse, cc);
13176 	} else {
13177 	    setCgsFore(xw, win, gcVTcursReverse, bg);
13178 	    setCgsBack(xw, win, gcVTcursReverse, cc);
13179 	}
13180 	set_cursor_outline_gc(xw, screen->always_highlight, fg, bg, cc);
13181 	changed = True;
13182 	FreeMarkGCs(xw);
13183     }
13184 
13185     if (changed) {
13186 	TRACE(("...set_cursor_gcs - done\n"));
13187     }
13188     return changed;
13189 }
13190 
13191 /*
13192  * Build up the default translations string, allowing the user to suppress
13193  * some of the features.
13194  */
13195 void
VTInitTranslations(void)13196 VTInitTranslations(void)
13197 {
13198     /* *INDENT-OFF* */
13199     static struct {
13200 	Boolean wanted;
13201 	const char *name;
13202 	const char *value;
13203     } table[] = {
13204 #define DATA(name,value) { False, name, value }
13205 	DATA("select",
13206 "\
13207          Shift <KeyPress> Select:select-cursor-start() select-cursor-end(SELECT, CUT_BUFFER0) \n\
13208          Shift <KeyPress> Insert:insert-selection(SELECT, CUT_BUFFER0) \n\
13209 "
13210 	),
13211 #if OPT_MAXIMIZE
13212 	DATA("fullscreen",
13213 "\
13214                  Alt <Key>Return:fullscreen() \n\
13215 "
13216 	),
13217 #endif
13218 #if OPT_SCROLL_LOCK
13219 	DATA("scroll-lock",
13220 "\
13221         <KeyRelease> Scroll_Lock:scroll-lock() \n\
13222 "
13223 	),
13224 #endif
13225 #if OPT_SHIFT_FONTS
13226 	DATA("shift-fonts",
13227 "\
13228     Shift~Ctrl <KeyPress> KP_Add:larger-vt-font() \n\
13229     Shift Ctrl <KeyPress> KP_Add:smaller-vt-font() \n\
13230     Shift <KeyPress> KP_Subtract:smaller-vt-font() \n\
13231 "
13232 	),
13233 #endif
13234 	DATA("paging",
13235 "\
13236           Shift <KeyPress> Prior:scroll-back(1,halfpage) \n\
13237            Shift <KeyPress> Next:scroll-forw(1,halfpage) \n\
13238 "
13239 	),
13240 	/* This must be the last set mentioning "KeyPress" */
13241 	DATA("keypress",
13242 "\
13243                 ~Meta <KeyPress>:insert-seven-bit() \n\
13244                  Meta <KeyPress>:insert-eight-bit() \n\
13245 "
13246 	),
13247 	DATA("popup-menu",
13248 "\
13249                 !Ctrl <Btn1Down>:popup-menu(mainMenu) \n\
13250            !Lock Ctrl <Btn1Down>:popup-menu(mainMenu) \n\
13251  !Lock Ctrl @Num_Lock <Btn1Down>:popup-menu(mainMenu) \n\
13252      ! @Num_Lock Ctrl <Btn1Down>:popup-menu(mainMenu) \n\
13253                 !Ctrl <Btn2Down>:popup-menu(vtMenu) \n\
13254            !Lock Ctrl <Btn2Down>:popup-menu(vtMenu) \n\
13255  !Lock Ctrl @Num_Lock <Btn2Down>:popup-menu(vtMenu) \n\
13256      ! @Num_Lock Ctrl <Btn2Down>:popup-menu(vtMenu) \n\
13257                 !Ctrl <Btn3Down>:popup-menu(fontMenu) \n\
13258            !Lock Ctrl <Btn3Down>:popup-menu(fontMenu) \n\
13259  !Lock Ctrl @Num_Lock <Btn3Down>:popup-menu(fontMenu) \n\
13260      ! @Num_Lock Ctrl <Btn3Down>:popup-menu(fontMenu) \n\
13261 "
13262 	),
13263 	/* PROCURA added "Meta <Btn2Down>:clear-saved-lines()" */
13264 	DATA("reset",
13265 "\
13266                  Meta <Btn2Down>:clear-saved-lines() \n\
13267 "
13268 	),
13269 	DATA("select",
13270 "\
13271                 ~Meta <Btn1Down>:select-start() \n\
13272               ~Meta <Btn1Motion>:select-extend() \n\
13273           ~Ctrl ~Meta <Btn2Down>:ignore() \n\
13274             ~Ctrl ~Meta <Btn2Up>:insert-selection(SELECT, CUT_BUFFER0) \n\
13275           ~Ctrl ~Meta <Btn3Down>:start-extend() \n\
13276               ~Meta <Btn3Motion>:select-extend() \n\
13277                          <BtnUp>:select-end(SELECT, CUT_BUFFER0) \n\
13278 "
13279 	),
13280 	DATA("wheel-mouse",
13281 "\
13282                  Ctrl <Btn4Down>:scroll-back(1,halfpage,m) \n\
13283             Lock Ctrl <Btn4Down>:scroll-back(1,halfpage,m) \n\
13284   Lock @Num_Lock Ctrl <Btn4Down>:scroll-back(1,halfpage,m) \n\
13285        @Num_Lock Ctrl <Btn4Down>:scroll-back(1,halfpage,m) \n\
13286                       <Btn4Down>:scroll-back(5,line,m)     \n\
13287                  Ctrl <Btn5Down>:scroll-forw(1,halfpage,m) \n\
13288             Lock Ctrl <Btn5Down>:scroll-forw(1,halfpage,m) \n\
13289   Lock @Num_Lock Ctrl <Btn5Down>:scroll-forw(1,halfpage,m) \n\
13290        @Num_Lock Ctrl <Btn5Down>:scroll-forw(1,halfpage,m) \n\
13291                       <Btn5Down>:scroll-forw(5,line,m)     \n\
13292 "
13293 	),
13294 	DATA("pointer",
13295 "\
13296                      <BtnMotion>:pointer-motion() \n\
13297                        <BtnDown>:pointer-button() \n\
13298                          <BtnUp>:pointer-button() \n\
13299 "
13300 	),
13301 	DATA("default",
13302 "\
13303                          <BtnUp>:ignore() \n\
13304 "
13305 	)
13306     };
13307 #undef DATA
13308     /* *INDENT-ON* */
13309 
13310     char *result = 0;
13311 
13312     int pass;
13313     Cardinal item;
13314 
13315     TRACE(("VTInitTranslations\n"));
13316     for (item = 0; item < XtNumber(table); ++item) {
13317 	table[item].wanted = True;
13318     }
13319 #if OPT_MAXIMIZE
13320     /*
13321      * As a special case, allow for disabling the alt-enter translation if
13322      * the resource settings prevent fullscreen from being used.  We would
13323      * do the same for scroll-lock and shift-fonts if they were application
13324      * resources too, rather than in the widget.
13325      */
13326     if (resource.fullscreen == esNever) {
13327 	for (item = 0; item < XtNumber(table); ++item) {
13328 	    if (!strcmp(table[item].name, "fullscreen")) {
13329 		table[item].wanted = False;
13330 		TRACE(("omit(%s):\n%s\n", table[item].name, table[item].value));
13331 	    }
13332 	}
13333     }
13334 #endif
13335     if (!IsEmpty(resource.omitTranslation)) {
13336 	char *value;
13337 	const char *source = resource.omitTranslation;
13338 
13339 	while (*source != '\0' && (value = ParseList(&source)) != 0) {
13340 	    size_t len = strlen(value);
13341 
13342 	    TRACE(("parsed:%s\n", value));
13343 	    for (item = 0; item < XtNumber(table); ++item) {
13344 		if (strlen(table[item].name) >= len
13345 		    && x_strncasecmp(table[item].name,
13346 				     value,
13347 				     (unsigned) len) == 0) {
13348 		    table[item].wanted = False;
13349 		    TRACE(("omit(%s):\n%s\n", table[item].name, table[item].value));
13350 		    /* continue: "select", for instance is two chunks */
13351 		}
13352 	    }
13353 	    free(value);
13354 	}
13355     }
13356 
13357     for (pass = 0; pass < 2; ++pass) {
13358 	size_t needed = 0;
13359 	for (item = 0; item < XtNumber(table); ++item) {
13360 	    if (table[item].wanted) {
13361 		if (pass) {
13362 		    strcat(result, table[item].value);
13363 		} else {
13364 		    needed += strlen(table[item].value) + 1;
13365 		}
13366 	    }
13367 	}
13368 	if (!pass) {
13369 	    result = XtMalloc((Cardinal) needed);
13370 	    *result = '\0';
13371 	}
13372     }
13373 
13374     TRACE(("result:\n%s\n", result));
13375 
13376     defaultTranslations = result;
13377     free((void *) xtermClassRec.core_class.tm_table);
13378     xtermClassRec.core_class.tm_table = result;
13379 }
13380 
13381 #ifdef NO_LEAKS
13382 void
noleaks_charproc(void)13383 noleaks_charproc(void)
13384 {
13385     free(v_buffer);
13386 }
13387 #endif
13388