charproc.c revision 5104ee6e
1/* $XTermId: charproc.c,v 1.2060 2025/01/05 20:45:50 tom Exp $ */
2
3/*
4 * Copyright 1999-2024,2025 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#include <graphics_sixel.h>
137
138#ifdef NO_LEAKS
139#include <xtermcap.h>
140#endif
141
142typedef int (*BitFunc) (unsigned * /* p */ ,
143			unsigned /* mask */ );
144
145static IChar doinput(XtermWidget /* xw */ );
146static int set_character_class(char * /*s */ );
147static void FromAlternate(XtermWidget /* xw */ ,
148			  Bool /* clearFirst */ );
149static void ReallyReset(XtermWidget /* xw */ ,
150			Bool /* full */ ,
151			Bool /* saved */ );
152static void RequestResize(XtermWidget /* xw */ ,
153			  int /* rows */ ,
154			  int /* cols */ ,
155			  Bool /* text */ );
156static void SwitchBufs(XtermWidget /* xw */ ,
157		       int /* toBuf */ ,
158		       Bool /* clearFirst */ );
159static void ToAlternate(XtermWidget /* xw */ ,
160			Bool /* clearFirst */ );
161static void ansi_modes(XtermWidget /* xw */ ,
162		       BitFunc /* func */ );
163static int bitclr(unsigned *p, unsigned mask);
164static int bitcpy(unsigned *p, unsigned q, unsigned mask);
165static int bitset(unsigned *p, unsigned mask);
166static void dpmodes(XtermWidget /* xw */ ,
167		    BitFunc /* func */ );
168static void restoremodes(XtermWidget /* xw */ );
169static void savemodes(XtermWidget /* xw */ );
170static void window_ops(XtermWidget /* xw */ );
171
172#if OPT_BLINK_CURS || OPT_BLINK_TEXT
173#define SettableCursorBlink(screen) \
174	(((screen)->cursor_blink != cbAlways) && \
175	 ((screen)->cursor_blink != cbNever))
176#define UpdateCursorBlink(xw) \
177	 SetCursorBlink(xw, TScreenOf(xw)->cursor_blink)
178static void SetCursorBlink(XtermWidget /* xw */ ,
179			   BlinkOps /* enable */ );
180static void HandleBlinking(XtPointer /* closure */ ,
181			   XtIntervalId * /* id */ );
182static void StartBlinking(XtermWidget /* xw */ );
183static void StopBlinking(XtermWidget /* xw */ );
184#else
185#define StartBlinking(xw)	/* nothing */
186#define StopBlinking(xw)	/* nothing */
187#endif
188
189#ifndef NO_ACTIVE_ICON
190static Boolean discount_frame_extents(XtermWidget /* xw */ ,
191				      int * /* height */ ,
192				      int * /* width */ );
193#else
194#define discount_frame_extents(xw, height, width)	False
195#endif
196
197#if OPT_INPUT_METHOD
198static void PreeditPosition(XtermWidget /* xw */ );
199#endif
200
201#define	DEFAULT		-1
202#define BELLSUPPRESSMSEC 200
203
204static ANSI reply;
205static PARAMS parms;
206
207#define nparam parms.count
208
209#define InitParams()  init_params()
210#define GetParam(n)   parms.params[(n)]
211#define SetParam(n,v) parms.params[(n)] = v
212#define ParamPair(n)  nparam - (n), parms.params + (n)
213
214static jmp_buf vtjmpbuf;
215
216/* event handlers */
217static void HandleBell PROTO_XT_ACTIONS_ARGS;
218static void HandleIgnore PROTO_XT_ACTIONS_ARGS;
219static void HandleKeymapChange PROTO_XT_ACTIONS_ARGS;
220static void HandleVisualBell PROTO_XT_ACTIONS_ARGS;
221#if HANDLE_STRUCT_NOTIFY
222static void HandleStructNotify PROTO_XT_EV_HANDLER_ARGS;
223#endif
224
225/*
226 * NOTE: VTInitialize zeros out the entire ".screen" component of the
227 * XtermWidget, so make sure to add an assignment statement in VTInitialize()
228 * for each new ".screen" field added to this resource list.
229 */
230
231/* Defaults */
232#if OPT_ISO_COLORS
233
234/*
235 * If we default to colorMode enabled, compile-in defaults for the ANSI colors.
236 */
237#if DFT_COLORMODE
238#define DFT_COLOR(name) name
239#else
240#define DFT_COLOR(name) XtDefaultForeground
241#endif
242#endif
243
244static char _Font_Selected_[] = "yes";	/* string is arbitrary */
245
246static const char *defaultTranslations;
247/* *INDENT-OFF* */
248static XtActionsRec actionsList[] = {
249    { "allow-bold-fonts",	HandleAllowBoldFonts },
250    { "allow-send-events",	HandleAllowSends },
251    { "bell",			HandleBell },
252    { "clear-saved-lines",	HandleClearSavedLines },
253    { "copy-selection",		HandleCopySelection },
254    { "create-menu",		HandleCreateMenu },
255    { "delete-is-del",		HandleDeleteIsDEL },
256    { "dired-button",		DiredButton },
257    { "hard-reset",		HandleHardReset },
258    { "ignore",			HandleIgnore },
259    { "insert",			HandleKeyPressed },  /* alias for insert-seven-bit */
260    { "insert-eight-bit",	HandleEightBitKeyPressed },
261    { "insert-selection",	HandleInsertSelection },
262    { "insert-seven-bit",	HandleKeyPressed },
263    { "interpret",		HandleInterpret },
264    { "keymap",			HandleKeymapChange },
265    { "pointer-motion",		HandlePointerMotion },
266    { "pointer-button",		HandlePointerButton },
267    { "popup-menu",		HandlePopupMenu },
268    { "print",			HandlePrintScreen },
269    { "print-everything",	HandlePrintEverything },
270    { "print-redir",		HandlePrintControlMode },
271    { "quit",			HandleQuit },
272    { "redraw",			HandleRedraw },
273    { "scroll-back",		HandleScrollBack },
274    { "scroll-forw",		HandleScrollForward },
275    { "scroll-to",		HandleScrollTo },
276    { "secure",			HandleSecure },
277    { "select-cursor-end",	HandleKeyboardSelectEnd },
278    { "select-cursor-extend",   HandleKeyboardSelectExtend },
279    { "select-cursor-start",	HandleKeyboardSelectStart },
280    { "select-end",		HandleSelectEnd },
281    { "select-extend",		HandleSelectExtend },
282    { "select-set",		HandleSelectSet },
283    { "select-start",		HandleSelectStart },
284    { "send-signal",		HandleSendSignal },
285    { "set-8-bit-control",	Handle8BitControl },
286    { "set-allow132",		HandleAllow132 },
287    { "set-altscreen",		HandleAltScreen },
288    { "set-appcursor",		HandleAppCursor },
289    { "set-appkeypad",		HandleAppKeypad },
290    { "set-autolinefeed",	HandleAutoLineFeed },
291    { "set-autowrap",		HandleAutoWrap },
292    { "set-backarrow",		HandleBackarrow },
293    { "set-bellIsUrgent",	HandleBellIsUrgent },
294    { "set-cursesemul",		HandleCursesEmul },
295    { "set-jumpscroll",		HandleJumpscroll },
296    { "set-keep-clipboard",	HandleKeepClipboard },
297    { "set-keep-selection",	HandleKeepSelection },
298    { "set-marginbell",		HandleMarginBell },
299    { "set-old-function-keys",	HandleOldFunctionKeys },
300    { "set-pop-on-bell",	HandleSetPopOnBell },
301    { "set-reverse-video",	HandleReverseVideo },
302    { "set-reversewrap",	HandleReverseWrap },
303    { "set-scroll-on-key",	HandleScrollKey },
304    { "set-scroll-on-tty-output", HandleScrollTtyOutput },
305    { "set-scrollbar",		HandleScrollbar },
306    { "set-select",		HandleSetSelect },
307    { "set-sun-keyboard",	HandleSunKeyboard },
308    { "set-titeInhibit",	HandleTiteInhibit },
309    { "set-visual-bell",	HandleSetVisualBell },
310    { "set-vt-font",		HandleSetFont },
311    { "soft-reset",		HandleSoftReset },
312    { "start-cursor-extend",	HandleKeyboardStartExtend },
313    { "start-extend",		HandleStartExtend },
314    { "string",			HandleStringEvent },
315    { "vi-button",		ViButton },
316    { "visual-bell",		HandleVisualBell },
317#ifdef ALLOWLOGGING
318    { "set-logging",		HandleLogging },
319#endif
320#if OPT_ALLOW_XXX_OPS
321    { "allow-color-ops",	HandleAllowColorOps },
322    { "allow-font-ops",		HandleAllowFontOps },
323    { "allow-mouse-ops",	HandleAllowMouseOps },
324    { "allow-tcap-ops",		HandleAllowTcapOps },
325    { "allow-title-ops",	HandleAllowTitleOps },
326    { "allow-window-ops",	HandleAllowWindowOps },
327#endif
328#if OPT_BLINK_CURS
329    { "set-cursorblink",	HandleCursorBlink },
330#endif
331#if OPT_BOX_CHARS
332    { "set-font-linedrawing",	HandleFontBoxChars },
333    { "set-font-packed",	HandleFontPacked },
334#endif
335#if OPT_DABBREV
336    { "dabbrev-expand",		HandleDabbrevExpand },
337#endif
338#if OPT_DEC_CHRSET
339    { "set-font-doublesize",	HandleFontDoublesize },
340#endif
341#if OPT_DEC_SOFTFONT
342    { "set-font-loading",	HandleFontLoading },
343#endif
344#if OPT_EXEC_XTERM
345    { "spawn-new-terminal",	HandleSpawnTerminal },
346#endif
347#if OPT_GRAPHICS
348    { "set-private-colors",	HandleSetPrivateColorRegisters },
349#endif
350#if OPT_HP_FUNC_KEYS
351    { "set-hp-function-keys",	HandleHpFunctionKeys },
352#endif
353#if OPT_LOAD_VTFONTS
354    { "load-vt-fonts",		HandleLoadVTFonts },
355#endif
356#if OPT_MAXIMIZE
357    { "deiconify",		HandleDeIconify },
358    { "fullscreen",		HandleFullscreen },
359    { "iconify",		HandleIconify },
360    { "maximize",		HandleMaximize },
361    { "restore",		HandleRestoreSize },
362#endif
363#if OPT_NUM_LOCK
364    { "alt-sends-escape",	HandleAltEsc },
365    { "meta-sends-escape",	HandleMetaEsc },
366    { "set-num-lock",		HandleNumLock },
367#endif
368#if OPT_PRINT_ON_EXIT
369    { "print-immediate",	HandlePrintImmediate },
370    { "print-on-error",		HandlePrintOnError },
371#endif
372#if OPT_READLINE
373    { "readline-button",	ReadLineButton },
374#endif
375#if OPT_RENDERFONT
376    { "set-render-font",	HandleRenderFont },
377#endif
378#if OPT_SCO_FUNC_KEYS
379    { "set-sco-function-keys",	HandleScoFunctionKeys },
380#endif
381#if OPT_SCREEN_DUMPS
382    { "dump-html",	        HandleDumpHtml },
383    { "dump-svg",	        HandleDumpSvg },
384#endif
385#if OPT_SCROLL_LOCK
386    { "scroll-lock",		HandleScrollLock },
387#endif
388#if OPT_SELECTION_OPS
389#if OPT_EXEC_SELECTION
390    { "exec-formatted",		HandleExecFormatted },
391    { "exec-selectable",	HandleExecSelectable },
392#endif
393    { "insert-formatted",	HandleInsertFormatted },
394    { "insert-selectable",	HandleInsertSelectable },
395#endif
396#if OPT_SHIFT_FONTS
397    { "larger-vt-font",		HandleLargerFont },
398    { "smaller-vt-font",	HandleSmallerFont },
399#endif
400#if OPT_SIXEL_GRAPHICS
401    { "set-sixel-scrolling",	HandleSixelScrolling },
402#endif
403#if OPT_SUN_FUNC_KEYS
404    { "set-sun-function-keys",	HandleSunFunctionKeys },
405#endif
406#if OPT_TEK4014
407    { "set-terminal-type",	HandleSetTerminalType },
408    { "set-visibility",		HandleVisibility },
409    { "set-tek-text",		HandleSetTekText },
410    { "tek-page",		HandleTekPage },
411    { "tek-reset",		HandleTekReset },
412    { "tek-copy",		HandleTekCopy },
413#endif
414#if OPT_TOOLBAR
415    { "set-toolbar",		HandleToolbar },
416#endif
417#if OPT_WIDE_CHARS
418    { "set-utf8-mode",		HandleUTF8Mode },
419    { "set-utf8-fonts",		HandleUTF8Fonts },
420    { "set-utf8-title",		HandleUTF8Title },
421#endif
422};
423/* *INDENT-ON* */
424
425#define SPS screen.printer_state
426
427static XtResource xterm_resources[] =
428{
429    Bres(XtNallowPasteControls, XtCAllowPasteControls,
430	 screen.allowPasteControl0, False),
431    Bres(XtNallowSendEvents, XtCAllowSendEvents, screen.allowSendEvent0, False),
432    Bres(XtNallowColorOps, XtCAllowColorOps, screen.allowColorOp0, DEF_ALLOW_COLOR),
433    Bres(XtNallowFontOps, XtCAllowFontOps, screen.allowFontOp0, DEF_ALLOW_FONT),
434    Bres(XtNallowMouseOps, XtCAllowMouseOps, screen.allowMouseOp0, DEF_ALLOW_MOUSE),
435    Bres(XtNallowTcapOps, XtCAllowTcapOps, screen.allowTcapOp0, DEF_ALLOW_TCAP),
436    Bres(XtNallowTitleOps, XtCAllowTitleOps, screen.allowTitleOp0, DEF_ALLOW_TITLE),
437    Bres(XtNallowWindowOps, XtCAllowWindowOps, screen.allowWindowOp0, DEF_ALLOW_WINDOW),
438    Bres(XtNaltIsNotMeta, XtCAltIsNotMeta, screen.alt_is_not_meta, False),
439    Bres(XtNaltSendsEscape, XtCAltSendsEscape, screen.alt_sends_esc, DEF_ALT_SENDS_ESC),
440    Bres(XtNallowBoldFonts, XtCAllowBoldFonts, screen.allowBoldFonts, True),
441    Bres(XtNalwaysBoldMode, XtCAlwaysBoldMode, screen.always_bold_mode, False),
442    Bres(XtNalwaysHighlight, XtCAlwaysHighlight, screen.always_highlight, False),
443    Bres(XtNappcursorDefault, XtCAppcursorDefault, misc.appcursorDefault, False),
444    Bres(XtNappkeypadDefault, XtCAppkeypadDefault, misc.appkeypadDefault, False),
445    Bres(XtNalternateScroll, XtCScrollCond, screen.alternateScroll, False),
446    Bres(XtNautoWrap, XtCAutoWrap, misc.autoWrap, True),
447    Bres(XtNawaitInput, XtCAwaitInput, screen.awaitInput, False),
448    Bres(XtNfreeBoldBox, XtCFreeBoldBox, screen.free_bold_box, False),
449    Bres(XtNbackarrowKey, XtCBackarrowKey, screen.backarrow_key, DEF_BACKARO_BS),
450    Bres(XtNbellIsUrgent, XtCBellIsUrgent, screen.bellIsUrgent, False),
451    Bres(XtNbellOnReset, XtCBellOnReset, screen.bellOnReset, True),
452    Bres(XtNboldMode, XtCBoldMode, screen.bold_mode, True),
453    Bres(XtNbrokenSelections, XtCBrokenSelections, screen.brokenSelections, False),
454    Bres(XtNc132, XtCC132, screen.c132, False),
455    Sres(XtNcdXtraScroll, XtCCdXtraScroll, misc.cdXtraScroll_s, DEF_CD_XTRA_SCROLL),
456    Bres(XtNcolorInnerBorder, XtCColorInnerBorder, misc.color_inner_border, False),
457    Bres(XtNcurses, XtCCurses, screen.curses, False),
458    Bres(XtNcutNewline, XtCCutNewline, screen.cutNewline, True),
459    Bres(XtNcutToBeginningOfLine, XtCCutToBeginningOfLine,
460	 screen.cutToBeginningOfLine, True),
461    Bres(XtNdeleteIsDEL, XtCDeleteIsDEL, screen.delete_is_del, DEFDELETE_DEL),
462    Bres(XtNdynamicColors, XtCDynamicColors, misc.dynamicColors, True),
463    Bres(XtNeightBitControl, XtCEightBitControl, screen.control_eight_bits, False),
464    Bres(XtNeightBitInput, XtCEightBitInput, screen.input_eight_bits, True),
465    Bres(XtNeightBitOutput, XtCEightBitOutput, screen.output_eight_bits, True),
466    Bres(XtNeraseSavedLines, XtCEraseSavedLines, screen.eraseSavedLines0, True),
467    Bres(XtNhighlightSelection, XtCHighlightSelection,
468	 screen.highlight_selection, False),
469    Bres(XtNshowWrapMarks, XtCShowWrapMarks, screen.show_wrap_marks, False),
470    Bres(XtNhpLowerleftBugCompat, XtCHpLowerleftBugCompat, screen.hp_ll_bc, False),
471    Bres(XtNi18nSelections, XtCI18nSelections, screen.i18nSelections, True),
472    Bres(XtNfastScroll, XtCFastScroll, screen.fastscroll, True),
473    Bres(XtNjumpScroll, XtCJumpScroll, screen.jumpscroll, True),
474    Bres(XtNkeepClipboard, XtCKeepClipboard, screen.keepClipboard, False),
475    Bres(XtNkeepSelection, XtCKeepSelection, screen.keepSelection, True),
476    Bres(XtNloginShell, XtCLoginShell, misc.login_shell, False),
477    Bres(XtNmarginBell, XtCMarginBell, screen.marginbell, False),
478    Bres(XtNmetaSendsEscape, XtCMetaSendsEscape, screen.meta_sends_esc, DEF_META_SENDS_ESC),
479    Bres(XtNmultiScroll, XtCMultiScroll, screen.multiscroll, False),
480    Bres(XtNoldXtermFKeys, XtCOldXtermFKeys, screen.old_fkeys, False),
481    Bres(XtNpopOnBell, XtCPopOnBell, screen.poponbell, False),
482    Bres(XtNpreferLatin1, XtCPreferLatin1, screen.prefer_latin1, True),
483    Bres(XtNprintRawChars, XtCPrintRawChars, screen.print_rawchars, False),
484    Bres(XtNprinterAutoClose, XtCPrinterAutoClose, SPS.printer_autoclose, False),
485    Bres(XtNprinterExtent, XtCPrinterExtent, SPS.printer_extent, False),
486    Bres(XtNprinterFormFeed, XtCPrinterFormFeed, SPS.printer_formfeed, False),
487    Bres(XtNprinterNewLine, XtCPrinterNewLine, SPS.printer_newline, True),
488    Bres(XtNquietGrab, XtCQuietGrab, screen.quiet_grab, False),
489    Bres(XtNresizeByPixel, XtCResizeByPixel, misc.resizeByPixel, False),
490    Bres(XtNreverseVideo, XtCReverseVideo, misc.re_verse, False),
491    Bres(XtNreverseWrap, XtCReverseWrap, misc.reverseWrap, False),
492    Bres(XtNscrollBar, XtCScrollBar, misc.scrollbar, False),
493    Bres(XtNscrollKey, XtCScrollCond, screen.scrollkey, False),
494    Bres(XtNscrollTtyOutput, XtCScrollCond, screen.scrollttyoutput, True),
495    Bres(XtNselectToClipboard, XtCSelectToClipboard,
496	 screen.selectToClipboard, False),
497    Bres(XtNsignalInhibit, XtCSignalInhibit, misc.signalInhibit, False),
498    Bres(XtNtiteInhibit, XtCTiteInhibit, misc.titeInhibit, False),
499    Sres(XtNtiXtraScroll, XtCTiXtraScroll, misc.tiXtraScroll_s, DEF_TI_XTRA_SCROLL),
500    Bres(XtNtrimSelection, XtCTrimSelection, screen.trim_selection, False),
501    Bres(XtNunderLine, XtCUnderLine, screen.underline, True),
502    Bres(XtNvisualBell, XtCVisualBell, screen.visualbell, False),
503    Bres(XtNvisualBellLine, XtCVisualBellLine, screen.flash_line, False),
504
505    Dres(XtNscaleHeight, XtCScaleHeight, screen.scale_height, "1.0"),
506
507    Ires(XtNbellSuppressTime, XtCBellSuppressTime, screen.bellSuppressTime, BELLSUPPRESSMSEC),
508    Ires(XtNfontWarnings, XtCFontWarnings, misc.fontWarnings, fwResource),
509    Ires(XtNinternalBorder, XtCBorderWidth, screen.border, DEFBORDER),
510    Ires(XtNlimitResize, XtCLimitResize, misc.limit_resize, 1),
511    Ires(XtNlimitResponse, XtCLimitResponse, screen.unparse_max, DEF_LIMIT_RESPONSE),
512    Ires(XtNmaxStringParse, XtCMaxStringParse, screen.strings_max, DEF_STRINGS_MAX),
513    Ires(XtNmultiClickTime, XtCMultiClickTime, screen.multiClickTime, MULTICLICKTIME),
514    Ires(XtNnMarginBell, XtCColumn, screen.nmarginbell, N_MARGINBELL),
515    Ires(XtNpointerMode, XtCPointerMode, screen.pointer_mode, DEF_POINTER_MODE),
516    Ires(XtNprinterControlMode, XtCPrinterControlMode,
517	 SPS.printer_controlmode, 0),
518    Ires(XtNtitleModes, XtCTitleModes, screen.title_modes, DEF_TITLE_MODES),
519    Ires(XtNnextEventDelay, XtCNextEventDelay, screen.nextEventDelay, 1),
520    Ires(XtNvisualBellDelay, XtCVisualBellDelay, screen.visualBellDelay, 100),
521    Ires(XtNsaveLines, XtCSaveLines, screen.savelines, DEF_SAVE_LINES),
522    Ires(XtNscrollBarBorder, XtCScrollBarBorder, screen.scrollBarBorder, 1),
523    Ires(XtNscrollLines, XtCScrollLines, screen.scrolllines, DEF_SCROLL_LINES),
524
525    Sres(XtNinitialFont, XtCInitialFont, screen.initial_font, NULL),
526    Sres(XtNfont1, XtCFont1, screen.MenuFontName(fontMenu_font1), NULL),
527    Sres(XtNfont2, XtCFont2, screen.MenuFontName(fontMenu_font2), NULL),
528    Sres(XtNfont3, XtCFont3, screen.MenuFontName(fontMenu_font3), NULL),
529    Sres(XtNfont4, XtCFont4, screen.MenuFontName(fontMenu_font4), NULL),
530    Sres(XtNfont5, XtCFont5, screen.MenuFontName(fontMenu_font5), NULL),
531    Sres(XtNfont6, XtCFont6, screen.MenuFontName(fontMenu_font6), NULL),
532    Sres(XtNfont7, XtCFont7, screen.MenuFontName(fontMenu_font7), NULL),
533
534    Sres(XtNanswerbackString, XtCAnswerbackString, screen.answer_back, ""),
535    Sres(XtNboldFont, XtCBoldFont, misc.default_font.f_b, DEFBOLDFONT),
536    Sres(XtNcharClass, XtCCharClass, screen.charClass, NULL),
537    Sres(XtNdecTerminalID, XtCDecTerminalID, screen.term_id, DFT_DECID),
538    Sres(XtNdefaultString, XtCDefaultString, screen.default_string, "#"),
539    Sres(XtNdisallowedColorOps, XtCDisallowedColorOps,
540	 screen.disallowedColorOps, DEF_DISALLOWED_COLOR),
541    Sres(XtNdisallowedFontOps, XtCDisallowedFontOps,
542	 screen.disallowedFontOps, DEF_DISALLOWED_FONT),
543    Sres(XtNdisallowedMouseOps, XtCDisallowedMouseOps,
544	 screen.disallowedMouseOps, DEF_DISALLOWED_MOUSE),
545    Sres(XtNdisallowedPasteControls, XtCDisallowedPasteControls,
546	 screen.disallowedPasteOps, DEF_DISALLOWED_PASTE_CONTROLS),
547    Sres(XtNdisallowedTcapOps, XtCDisallowedTcapOps,
548	 screen.disallowedTcapOps, DEF_DISALLOWED_TCAP),
549    Sres(XtNdisallowedWindowOps, XtCDisallowedWindowOps,
550	 screen.disallowedWinOps, DEF_DISALLOWED_WINDOW),
551    Sres(XtNeightBitMeta, XtCEightBitMeta, screen.eight_bit_meta_s, DEF_8BIT_META),
552    Sres(XtNeightBitSelectTypes, XtCEightBitSelectTypes,
553	 screen.eightbit_select_types, NULL),
554    Sres(XtNfont, XtCFont, misc.default_font.f_n, DEFFONT),
555    Sres(XtNgeometry, XtCGeometry, misc.geo_metry, NULL),
556    Sres(XtNkeyboardDialect, XtCKeyboardDialect, screen.keyboard_dialect, DFT_KBD_DIALECT),
557    Sres(XtNprinterCommand, XtCPrinterCommand, SPS.printer_command, ""),
558    Sres(XtNtekGeometry, XtCGeometry, misc.T_geometry, NULL),
559    Sres(XtNpointerFont, XtCPointerFont, screen.cursor_font_name, NULL),
560
561    Tres(XtNcursorColor, XtCCursorColor, TEXT_CURSOR, XtDefaultForeground),
562    Tres(XtNforeground, XtCForeground, TEXT_FG, XtDefaultForeground),
563    Tres(XtNpointerColor, XtCPointerColor, MOUSE_FG, XtDefaultForeground),
564    Tres(XtNbackground, XtCBackground, TEXT_BG, XtDefaultBackground),
565    Tres(XtNpointerColorBackground, XtCBackground, MOUSE_BG, XtDefaultBackground),
566
567    {XtNresizeGravity, XtCResizeGravity, XtRGravity, sizeof(XtGravity),
568     XtOffsetOf(XtermWidgetRec, misc.resizeGravity),
569     XtRImmediate, (XtPointer) SouthWestGravity},
570
571    Sres(XtNpointerShape, XtCCursor, screen.pointer_shape, "xterm"),
572
573#ifdef ALLOWLOGGING
574    Bres(XtNlogInhibit, XtCLogInhibit, misc.logInhibit, False),
575    Bres(XtNlogging, XtCLogging, misc.log_on, False),
576    Sres(XtNlogFile, XtCLogfile, screen.logfile, NULL),
577#endif
578
579#ifndef NO_ACTIVE_ICON
580    Sres(XtNactiveIcon, XtCActiveIcon, misc.active_icon_s, "default"),
581    Ires(XtNiconBorderWidth, XtCBorderWidth, misc.icon_border_width, 2),
582    Sres(XtNiconFont, XtCIconFont, screen.icon_fontname, "nil2"),
583    Cres(XtNiconBorderColor, XtCBorderColor, misc.icon_border_pixel, XtDefaultBackground),
584#endif				/* NO_ACTIVE_ICON */
585
586#if OPT_BLINK_CURS
587    Bres(XtNcursorBlinkXOR, XtCCursorBlinkXOR, screen.cursor_blink_xor, True),
588    Sres(XtNcursorBlink, XtCCursorBlink, screen.cursor_blink_s, "false"),
589#endif
590    Bres(XtNcursorUnderLine, XtCCursorUnderLine, screen.cursor_underline, False),
591    Bres(XtNcursorBar, XtCCursorBar, screen.cursor_bar, False),
592
593#if OPT_BLINK_TEXT
594    Bres(XtNshowBlinkAsBold, XtCCursorBlink, screen.blink_as_bold, DEFBLINKASBOLD),
595#endif
596
597#if OPT_BLINK_CURS || OPT_BLINK_TEXT
598    Ires(XtNcursorOnTime, XtCCursorOnTime, screen.blink_on, 600),
599    Ires(XtNcursorOffTime, XtCCursorOffTime, screen.blink_off, 300),
600#endif
601
602#if OPT_BOX_CHARS
603    Bres(XtNforceBoxChars, XtCForceBoxChars, screen.force_box_chars, False),
604    Bres(XtNforcePackedFont, XtCForcePackedFont, screen.force_packed, True),
605    Bres(XtNassumeAllChars, XtCAssumeAllChars, screen.assume_all_chars, True),
606#endif
607#if OPT_BOX_CHARS || OPT_WIDE_CHARS
608    Bres(XtNshowMissingGlyphs, XtCShowMissingGlyphs, screen.force_all_chars, True),
609#endif
610
611#if OPT_BROKEN_OSC
612    Bres(XtNbrokenLinuxOSC, XtCBrokenLinuxOSC, screen.brokenLinuxOSC, True),
613#endif
614
615#if OPT_BROKEN_ST
616    Bres(XtNbrokenStringTerm, XtCBrokenStringTerm, screen.brokenStringTerm, False),
617#endif
618
619#if OPT_C1_PRINT
620    Bres(XtNallowC1Printable, XtCAllowC1Printable, screen.c1_printable, False),
621#endif
622
623#if OPT_CLIP_BOLD
624    Bres(XtNuseClipping, XtCUseClipping, screen.use_clipping, True),
625    Bres(XtNuseBorderClipping, XtCUseBorderClipping,
626	 screen.use_border_clipping, False),
627#endif
628
629#if OPT_DEC_CHRSET
630    Bres(XtNfontDoublesize, XtCFontDoublesize, screen.font_doublesize, True),
631    Ires(XtNcacheDoublesize, XtCCacheDoublesize, screen.cache_doublesize, NUM_CHRSET),
632#endif
633
634#if OPT_DEC_RECTOPS
635    Ires(XtNchecksumExtension, XtCChecksumExtension, screen.checksum_ext0, csDEC),
636#endif
637
638#if OPT_HIGHLIGHT_COLOR
639    Tres(XtNhighlightColor, XtCHighlightColor, HIGHLIGHT_BG, XtDefaultForeground),
640    Tres(XtNhighlightTextColor, XtCHighlightTextColor, HIGHLIGHT_FG, XtDefaultBackground),
641    Bres(XtNhighlightReverse, XtCHighlightReverse, screen.hilite_reverse, True),
642    Bres(XtNhighlightColorMode, XtCHighlightColorMode, screen.hilite_color, Maybe),
643#endif				/* OPT_HIGHLIGHT_COLOR */
644
645#if OPT_INPUT_METHOD
646    Bres(XtNopenIm, XtCOpenIm, misc.open_im, True),
647    Sres(XtNinputMethod, XtCInputMethod, misc.input_method, NULL),
648    Sres(XtNpreeditType, XtCPreeditType, misc.preedit_type,
649	 "OverTheSpot,Root"),
650    Ires(XtNretryInputMethod, XtCRetryInputMethod, misc.retry_im, 3),
651#endif
652
653#if OPT_ISO_COLORS
654    Bres(XtNboldColors, XtCColorMode, screen.boldColors, True),
655    Ires(XtNveryBoldColors, XtCVeryBoldColors, screen.veryBoldColors, 0),
656    Bres(XtNcolorMode, XtCColorMode, screen.colorMode, DFT_COLORMODE),
657
658    Bres(XtNcolorAttrMode, XtCColorAttrMode, screen.colorAttrMode, False),
659    Bres(XtNcolorBDMode, XtCColorAttrMode, screen.colorBDMode, False),
660    Bres(XtNcolorBLMode, XtCColorAttrMode, screen.colorBLMode, False),
661    Bres(XtNcolorRVMode, XtCColorAttrMode, screen.colorRVMode, False),
662    Bres(XtNcolorULMode, XtCColorAttrMode, screen.colorULMode, False),
663    Bres(XtNitalicULMode, XtCColorAttrMode, screen.italicULMode, False),
664#if OPT_WIDE_ATTRS
665    Bres(XtNcolorITMode, XtCColorAttrMode, screen.colorITMode, False),
666#endif
667#if OPT_DIRECT_COLOR
668    Bres(XtNdirectColor, XtCDirectColor, screen.direct_color, True),
669#endif
670
671    COLOR_RES("0", screen.Acolors[COLOR_0], DFT_COLOR("black")),
672    COLOR_RES("1", screen.Acolors[COLOR_1], DFT_COLOR("red3")),
673    COLOR_RES("2", screen.Acolors[COLOR_2], DFT_COLOR("green3")),
674    COLOR_RES("3", screen.Acolors[COLOR_3], DFT_COLOR("yellow3")),
675    COLOR_RES("4", screen.Acolors[COLOR_4], DFT_COLOR(DEF_COLOR4)),
676    COLOR_RES("5", screen.Acolors[COLOR_5], DFT_COLOR("magenta3")),
677    COLOR_RES("6", screen.Acolors[COLOR_6], DFT_COLOR("cyan3")),
678    COLOR_RES("7", screen.Acolors[COLOR_7], DFT_COLOR("gray90")),
679    COLOR_RES("8", screen.Acolors[COLOR_8], DFT_COLOR("gray50")),
680    COLOR_RES("9", screen.Acolors[COLOR_9], DFT_COLOR("red")),
681    COLOR_RES("10", screen.Acolors[COLOR_10], DFT_COLOR("green")),
682    COLOR_RES("11", screen.Acolors[COLOR_11], DFT_COLOR("yellow")),
683    COLOR_RES("12", screen.Acolors[COLOR_12], DFT_COLOR(DEF_COLOR12)),
684    COLOR_RES("13", screen.Acolors[COLOR_13], DFT_COLOR("magenta")),
685    COLOR_RES("14", screen.Acolors[COLOR_14], DFT_COLOR("cyan")),
686    COLOR_RES("15", screen.Acolors[COLOR_15], DFT_COLOR("white")),
687    COLOR_RES("BD", screen.Acolors[COLOR_BD], DFT_COLOR(XtDefaultForeground)),
688    COLOR_RES("BL", screen.Acolors[COLOR_BL], DFT_COLOR(XtDefaultForeground)),
689    COLOR_RES("UL", screen.Acolors[COLOR_UL], DFT_COLOR(XtDefaultForeground)),
690    COLOR_RES("RV", screen.Acolors[COLOR_RV], DFT_COLOR(XtDefaultForeground)),
691
692#if OPT_WIDE_ATTRS
693    COLOR_RES("IT", screen.Acolors[COLOR_IT], DFT_COLOR(XtDefaultForeground)),
694#endif
695
696#endif				/* OPT_ISO_COLORS */
697
698    CLICK_RES("2", screen.onClick[1], "word"),
699    CLICK_RES("3", screen.onClick[2], "line"),
700    CLICK_RES("4", screen.onClick[3], 0),
701    CLICK_RES("5", screen.onClick[4], 0),
702
703    Sres(XtNshiftEscape, XtCShiftEscape, keyboard.shift_escape_s, "false"),
704
705#if OPT_MOD_FKEYS
706    Ires(XtNmodifyKeyboard, XtCModifyKeyboard,
707	 keyboard.modify_1st.allow_keys, 0),
708    Ires(XtNmodifyCursorKeys, XtCModifyCursorKeys,
709	 keyboard.modify_1st.cursor_keys, 2),
710    Ires(XtNmodifyFunctionKeys, XtCModifyFunctionKeys,
711	 keyboard.modify_1st.function_keys, 2),
712    Ires(XtNmodifyKeypadKeys, XtCModifyKeypadKeys,
713	 keyboard.modify_1st.keypad_keys, 0),
714    Ires(XtNmodifyOtherKeys, XtCModifyOtherKeys,
715	 keyboard.modify_1st.other_keys, 0),
716    Ires(XtNmodifyStringKeys, XtCModifyStringKeys,
717	 keyboard.modify_1st.string_keys, 0),
718    Ires(XtNformatOtherKeys, XtCFormatOtherKeys,
719	 keyboard.format_keys, 0),
720#endif
721
722#if OPT_NUM_LOCK
723    Bres(XtNalwaysUseMods, XtCAlwaysUseMods, misc.alwaysUseMods, False),
724    Bres(XtNnumLock, XtCNumLock, misc.real_NumLock, True),
725#endif
726
727#if OPT_PRINT_COLORS
728    Ires(XtNprintAttributes, XtCPrintAttributes, SPS.print_attributes, 1),
729#endif
730
731#if OPT_REGIS_GRAPHICS
732    Sres(XtNregisDefaultFont, XtCRegisDefaultFont,
733	 screen.graphics_regis_default_font, ""),
734    Sres(XtNregisScreenSize, XtCRegisScreenSize,
735	 screen.graphics_regis_screensize, "auto"),
736#endif
737
738#if OPT_GRAPHICS
739    Sres(XtNdecGraphicsID, XtCDecGraphicsID, screen.graph_termid, DFT_DECID),
740    Sres(XtNmaxGraphicSize, XtCMaxGraphicSize, screen.graphics_max_size,
741	 "1000x1000"),
742#endif
743
744#if OPT_ISO_COLORS && OPT_WIDE_ATTRS && OPT_SGR2_HASH
745    Bres(XtNfaintIsRelative, XtCFaintIsRelative, screen.faint_relative, False),
746#endif
747
748#if OPT_SHIFT_FONTS
749    Bres(XtNshiftFonts, XtCShiftFonts, misc.shift_fonts, True),
750#endif
751
752#if OPT_SIXEL_GRAPHICS
753    Bres(XtNsixelScrolling, XtCSixelScrolling, screen.sixel_scrolling, True),
754    Bres(XtNsixelScrollsRight, XtCSixelScrollsRight,
755	 screen.sixel_scrolls_right, False),
756#endif
757
758#if OPT_GRAPHICS
759    Ires(XtNnumColorRegisters, XtCNumColorRegisters,
760	 screen.numcolorregisters, 0),
761    Bres(XtNprivateColorRegisters, XtCPrivateColorRegisters,
762	 screen.privatecolorregisters, True),
763    Bres(XtNincrementalGraphics, XtCIncrementalGraphics,
764	 screen.incremental_graphics, False),
765#endif
766
767#if OPT_STATUS_LINE
768    Sres(XtNindicatorFormat, XtCIndicatorFormat, screen.status_fmt, DEF_SL_FORMAT),
769#endif
770
771#if OPT_SUNPC_KBD
772    Ires(XtNctrlFKeys, XtCCtrlFKeys, misc.ctrl_fkeys, 10),
773#endif
774
775#if OPT_TEK4014
776    Bres(XtNtekInhibit, XtCTekInhibit, misc.tekInhibit, False),
777    Bres(XtNtekSmall, XtCTekSmall, misc.tekSmall, False),
778    Bres(XtNtekStartup, XtCTekStartup, misc.TekEmu, False),
779#endif
780
781#if OPT_TOOLBAR
782    Wres(XtNmenuBar, XtCMenuBar, VT100_TB_INFO(menu_bar), 0),
783    Ires(XtNmenuHeight, XtCMenuHeight, VT100_TB_INFO(menu_height), 25),
784#endif
785
786#if OPT_WIDE_CHARS
787    Bres(XtNcjkWidth, XtCCjkWidth, misc.cjk_width, False),
788    Bres(XtNmkWidth, XtCMkWidth, misc.mk_width, False),
789    Bres(XtNprecompose, XtCPrecompose, screen.normalized_c, True),
790    Bres(XtNutf8Latin1, XtCUtf8Latin1, screen.utf8_latin1, False),
791    Bres(XtNutf8Weblike, XtCUtf8Weblike, screen.utf8_weblike, False),
792    Bres(XtNvt100Graphics, XtCVT100Graphics, screen.vt100_graphics, True),
793    Bres(XtNwideChars, XtCWideChars, screen.wide_chars, False),
794    Ires(XtNcombiningChars, XtCCombiningChars, screen.max_combining, 2),
795    Ires(XtNmkSamplePass, XtCMkSamplePass, misc.mk_samplepass, 655),
796    Ires(XtNmkSampleSize, XtCMkSampleSize, misc.mk_samplesize, 65536),
797    Sres(XtNutf8, XtCUtf8, screen.utf8_mode_s, "default"),
798    Sres(XtNutf8Fonts, XtCUtf8Fonts, screen.utf8_fonts_s, "default"),
799    Sres(XtNutf8Title, XtCUtf8Title, screen.utf8_title_s, "default"),
800    Sres(XtNwideBoldFont, XtCWideBoldFont, misc.default_font.f_wb, DEFWIDEBOLDFONT),
801    Sres(XtNwideFont, XtCWideFont, misc.default_font.f_w, DEFWIDEFONT),
802    Sres(XtNutf8SelectTypes, XtCUtf8SelectTypes, screen.utf8_select_types, NULL),
803#endif
804
805#if OPT_LUIT_PROG
806    Sres(XtNlocale, XtCLocale, misc.locale_str, "medium"),
807    Sres(XtNlocaleFilter, XtCLocaleFilter, misc.localefilter, DEFLOCALEFILTER),
808#endif
809
810#if OPT_INPUT_METHOD
811    Sres(XtNximFont, XtCXimFont, misc.f_x, DEFXIMFONT),
812#endif
813
814#if OPT_SCROLL_LOCK
815    Bres(XtNallowScrollLock, XtCAllowScrollLock, screen.allowScrollLock0, False),
816    Bres(XtNautoScrollLock, XtCAutoScrollLock, screen.autoScrollLock, False),
817#endif
818
819    /* these are used only for testing ncurses, not in the manual page */
820#if OPT_XMC_GLITCH
821    Bres(XtNxmcInline, XtCXmcInline, screen.xmc_inline, False),
822    Bres(XtNxmcMoveSGR, XtCXmcMoveSGR, screen.move_sgr_ok, True),
823    Ires(XtNxmcAttributes, XtCXmcAttributes, screen.xmc_attributes, 1),
824    Ires(XtNxmcGlitch, XtCXmcGlitch, screen.xmc_glitch, 0),
825#endif
826
827#ifdef SCROLLBAR_RIGHT
828    Bres(XtNrightScrollBar, XtCRightScrollBar, misc.useRight, False),
829#endif
830
831#if OPT_RENDERFONT
832    Bres(XtNforceXftHeight, XtCForceXftHeight, screen.force_xft_height, False),
833    Ires(XtNxftMaxGlyphMemory, XtCXftMaxGlyphMemory,
834	 screen.xft_max_glyph_memory, 0),
835    Ires(XtNxftMaxUnrefFonts, XtCXftMaxUnrefFonts,
836	 screen.xft_max_unref_fonts, 0),
837    Bres(XtNxftTrackMemUsage, XtCXftTrackMemUsage,
838	 screen.xft_track_mem_usage, DEF_TRACK_USAGE),
839#define RES_FACESIZE(n) Dres(XtNfaceSize #n, XtCFaceSize #n, misc.face_size[n], "0.0")
840    RES_FACESIZE(1),
841    RES_FACESIZE(2),
842    RES_FACESIZE(3),
843    RES_FACESIZE(4),
844    RES_FACESIZE(5),
845    RES_FACESIZE(6),
846    RES_FACESIZE(7),
847    Dres(XtNfaceSize, XtCFaceSize, misc.face_size[0], DEFFACESIZE),
848    Sres(XtNfaceName, XtCFaceName, misc.default_xft.f_n, DEFFACENAME),
849    Sres(XtNrenderFont, XtCRenderFont, misc.render_font_s, "default"),
850    Ires(XtNlimitFontsets, XtCLimitFontsets, misc.limit_fontsets, DEF_XFT_CACHE),
851    Ires(XtNlimitFontHeight, XtCLimitFontHeight, misc.limit_fontheight, 10),
852    Ires(XtNlimitFontWidth, XtCLimitFontWidth, misc.limit_fontwidth, 10),
853#if OPT_RENDERWIDE
854    Sres(XtNfaceNameDoublesize, XtCFaceNameDoublesize, misc.default_xft.f_w, DEFFACENAME),
855#endif
856#endif
857};
858
859static Boolean VTSetValues(Widget cur, Widget request, Widget new_arg,
860			   ArgList args, Cardinal *num_args);
861static void VTClassInit(void);
862static void VTDestroy(Widget w);
863static void VTExpose(Widget w, XEvent *event, Region region);
864static void VTInitialize(Widget wrequest, Widget new_arg, ArgList args,
865			 Cardinal *num_args);
866static void VTRealize(Widget w, XtValueMask * valuemask,
867		      XSetWindowAttributes * values);
868static void VTResize(Widget w);
869
870#if OPT_INPUT_METHOD
871static void VTInitI18N(XtermWidget);
872#endif
873
874static
875WidgetClassRec xtermClassRec =
876{
877    {
878	/* core_class fields */
879	(WidgetClass) & widgetClassRec,		/* superclass   */
880	"VT100",		/* class_name                   */
881	sizeof(XtermWidgetRec),	/* widget_size                  */
882	VTClassInit,		/* class_initialize             */
883	NULL,			/* class_part_initialize        */
884	False,			/* class_inited                 */
885	VTInitialize,		/* initialize                   */
886	NULL,			/* initialize_hook              */
887	VTRealize,		/* realize                      */
888	actionsList,		/* actions                      */
889	XtNumber(actionsList),	/* num_actions                  */
890	xterm_resources,	/* resources                    */
891	XtNumber(xterm_resources),	/* num_resources        */
892	NULLQUARK,		/* xrm_class                    */
893	True,			/* compress_motion              */
894	False,			/* compress_exposure            */
895	True,			/* compress_enterleave          */
896	False,			/* visible_interest             */
897	VTDestroy,		/* destroy                      */
898	VTResize,		/* resize                       */
899	VTExpose,		/* expose                       */
900	VTSetValues,		/* set_values                   */
901	NULL,			/* set_values_hook              */
902	XtInheritSetValuesAlmost,	/* set_values_almost    */
903	NULL,			/* get_values_hook              */
904	NULL,			/* accept_focus                 */
905	XtVersion,		/* version                      */
906	NULL,			/* callback_offsets             */
907	NULL,			/* tm_table                     */
908	XtInheritQueryGeometry,	/* query_geometry               */
909	XtInheritDisplayAccelerator,	/* display_accelerator  */
910	NULL			/* extension                    */
911    }
912};
913
914WidgetClass xtermWidgetClass = (WidgetClass) & xtermClassRec;
915
916/*
917 * Add input-actions for widgets that are overlooked (scrollbar and toolbar):
918 *
919 *	a) Sometimes the scrollbar passes through translations, sometimes it
920 *	   doesn't.  We add the KeyPress translations here, just to be sure.
921 *	b) In the normal (non-toolbar) configuration, the xterm widget covers
922 *	   almost all of the window.  With a toolbar, there's a relatively
923 *	   large area that the user would expect to enter keystrokes since the
924 *	   program can get the focus.
925 */
926void
927xtermAddInput(Widget w)
928{
929    /* *INDENT-OFF* */
930    XtActionsRec input_actions[] = {
931	{ "insert",		    HandleKeyPressed }, /* alias */
932	{ "insert-eight-bit",	    HandleEightBitKeyPressed },
933	{ "insert-seven-bit",	    HandleKeyPressed },
934	{ "pointer-motion",	    HandlePointerMotion },
935	{ "pointer-button",	    HandlePointerButton },
936	{ "secure",		    HandleSecure },
937	{ "string",		    HandleStringEvent },
938	{ "scroll-back",	    HandleScrollBack },
939	{ "scroll-forw",	    HandleScrollForward },
940	{ "scroll-to",		    HandleScrollTo },
941	{ "select-cursor-end",	    HandleKeyboardSelectEnd },
942	{ "select-cursor-extend",   HandleKeyboardSelectExtend },
943	{ "select-cursor-start",    HandleKeyboardSelectStart },
944	{ "insert-selection",	    HandleInsertSelection },
945	{ "select-start",	    HandleSelectStart },
946	{ "select-extend",	    HandleSelectExtend },
947	{ "start-extend",	    HandleStartExtend },
948	{ "select-end",		    HandleSelectEnd },
949	{ "clear-saved-lines",	    HandleClearSavedLines },
950	{ "popup-menu",		    HandlePopupMenu },
951	{ "bell",		    HandleBell },
952	{ "ignore",		    HandleIgnore },
953#if OPT_DABBREV
954	{ "dabbrev-expand",	    HandleDabbrevExpand },
955#endif
956#if OPT_MAXIMIZE
957	{ "fullscreen",		    HandleFullscreen },
958#endif
959#if OPT_SCROLL_LOCK
960	{ "scroll-lock",	    HandleScrollLock },
961#endif
962#if OPT_SHIFT_FONTS
963	{ "larger-vt-font",	    HandleLargerFont },
964	{ "smaller-vt-font",	    HandleSmallerFont },
965#endif
966    };
967    /* *INDENT-ON* */
968
969    TRACE_TRANS("BEFORE", w);
970    XtAppAddActions(app_con, input_actions, XtNumber(input_actions));
971    XtAugmentTranslations(w, XtParseTranslationTable(defaultTranslations));
972    TRACE_TRANS("AFTER:", w);
973
974#if OPT_EXTRA_PASTE
975    if (term && term->keyboard.extra_translations)
976	XtOverrideTranslations((Widget) term, XtParseTranslationTable(term->keyboard.extra_translations));
977#endif
978}
979
980#if OPT_ISO_COLORS
981#ifdef EXP_BOGUS_FG
982static Bool
983CheckBogusForeground(TScreen *screen, const char *tag)
984{
985    int row = -1, col = -1, pass;
986    Bool isClear = True;
987
988    (void) tag;
989    for (pass = 0; pass < 2; ++pass) {
990	row = screen->cur_row;
991	for (; isClear && (row <= screen->max_row); ++row) {
992	    CLineData *ld = getLineData(screen, row);
993
994	    if (ld != 0) {
995		IAttr *attribs = ld->attribs;
996
997		col = (row == screen->cur_row) ? screen->cur_col : 0;
998		for (; isClear && (col <= screen->max_col); ++col) {
999		    unsigned flags = attribs[col];
1000		    if (pass) {
1001			flags &= ~FG_COLOR;
1002			attribs[col] = (IAttr) flags;
1003		    } else if ((flags & BG_COLOR)) {
1004			isClear = False;
1005		    } else if ((flags & FG_COLOR)) {
1006			unsigned ch = ld->charData[col];
1007			isClear = ((ch == ' ') || (ch == 0));
1008		    } else {
1009			isClear = False;
1010		    }
1011		}
1012	    }
1013	}
1014    }
1015    TRACE(("%s checked %d,%d to %d,%d %s pass %d\n",
1016	   tag, screen->cur_row, screen->cur_col,
1017	   row, col,
1018	   isClear && pass ? "cleared" : "unchanged",
1019	   pass));
1020
1021    return isClear;
1022}
1023#endif
1024
1025/*
1026 * The terminal's foreground and background colors are set via two mechanisms:
1027 *	text (cur_foreground, cur_background values that are passed down to
1028 *		XDrawImageString and XDrawString)
1029 *	area (X11 graphics context used in XClearArea and XFillRectangle)
1030 */
1031void
1032SGR_Foreground(XtermWidget xw, int color)
1033{
1034    TScreen *screen = TScreenOf(xw);
1035    Pixel fg;
1036
1037    if (color >= 0) {
1038	UIntSet(xw->flags, FG_COLOR);
1039    } else {
1040	UIntClr(xw->flags, FG_COLOR);
1041    }
1042    fg = getXtermFG(xw, xw->flags, color);
1043    xw->cur_foreground = color;
1044
1045    setCgsFore(xw, WhichVWin(screen), gcNorm, fg);
1046    setCgsBack(xw, WhichVWin(screen), gcNormReverse, fg);
1047
1048    setCgsFore(xw, WhichVWin(screen), gcBold, fg);
1049    setCgsBack(xw, WhichVWin(screen), gcBoldReverse, fg);
1050
1051#ifdef EXP_BOGUS_FG
1052    /*
1053     * If we've just turned off the foreground color, check for blank cells
1054     * which have no background color, but do have foreground color.  This
1055     * could happen due to setting the foreground color just before scrolling.
1056     *
1057     * Those cells look uncolored, but will confuse ShowCursor(), which looks
1058     * for the colors in the current cell, and will see the foreground color.
1059     * In that case, remove the foreground color from the blank cells.
1060     */
1061    if (color < 0) {
1062	CheckBogusForeground(screen, "SGR_Foreground");
1063    }
1064#endif
1065}
1066
1067void
1068SGR_Background(XtermWidget xw, int color)
1069{
1070    TScreen *screen = TScreenOf(xw);
1071    Pixel bg;
1072
1073    /*
1074     * An indexing operation may have set screen->scroll_amt, which would
1075     * normally result in calling FlushScroll() in WriteText().  However,
1076     * if we're changing the background color now, then the new value
1077     * should not apply to the pending blank lines.
1078     */
1079    if (screen->scroll_amt && (color != xw->cur_background))
1080	FlushScroll(xw);
1081
1082    if (color >= 0) {
1083	UIntSet(xw->flags, BG_COLOR);
1084    } else {
1085	UIntClr(xw->flags, BG_COLOR);
1086    }
1087    bg = getXtermBG(xw, xw->flags, color);
1088    xw->cur_background = color;
1089
1090    setCgsBack(xw, WhichVWin(screen), gcNorm, bg);
1091    setCgsFore(xw, WhichVWin(screen), gcNormReverse, bg);
1092
1093    setCgsBack(xw, WhichVWin(screen), gcBold, bg);
1094    setCgsFore(xw, WhichVWin(screen), gcBoldReverse, bg);
1095}
1096
1097/* Invoked after updating bold/underline flags, computes the extended color
1098 * index to use for foreground.  (See also 'extract_fg()').
1099 */
1100static void
1101setExtendedFG(XtermWidget xw)
1102{
1103    int fg = xw->sgr_foreground;
1104
1105    if (TScreenOf(xw)->colorAttrMode
1106	|| (fg < 0)) {
1107	fg = MapToColorMode(fg, TScreenOf(xw), xw->flags);
1108    }
1109
1110    /* This implements the IBM PC-style convention of 8-colors, with one
1111     * bit for bold, thus mapping the 0-7 codes to 8-15.  It won't make
1112     * much sense for 16-color applications, but we keep it to retain
1113     * compatibility with ANSI-color applications.
1114     */
1115#if OPT_PC_COLORS		/* XXXJTL should be settable at runtime (resource or OSC?) */
1116    if (TScreenOf(xw)->boldColors
1117	&& (!xw->sgr_38_xcolors)
1118	&& (fg >= 0)
1119	&& (fg < 8)
1120	&& (xw->flags & BOLD))
1121	fg |= 8;
1122#endif
1123
1124    SGR_Foreground(xw, fg);
1125}
1126
1127/* Invoked after updating inverse flag, computes the extended color
1128 * index to use for background.  (See also 'extract_bg()').
1129 */
1130static void
1131setExtendedBG(XtermWidget xw)
1132{
1133    int bg = xw->sgr_background;
1134
1135    if (TScreenOf(xw)->colorAttrMode
1136	|| (bg < 0)) {
1137	if (TScreenOf(xw)->colorRVMode && (xw->flags & INVERSE))
1138	    bg = COLOR_RV;
1139    }
1140
1141    SGR_Background(xw, bg);
1142}
1143
1144void
1145setExtendedColors(XtermWidget xw)
1146{
1147    setExtendedFG(xw);
1148    setExtendedBG(xw);
1149}
1150
1151static void
1152reset_SGR_Foreground(XtermWidget xw)
1153{
1154    xw->sgr_foreground = -1;
1155    xw->sgr_38_xcolors = False;
1156    clrDirectFG(xw->flags);
1157    setExtendedFG(xw);
1158}
1159
1160static void
1161reset_SGR_Background(XtermWidget xw)
1162{
1163    xw->sgr_background = -1;
1164    clrDirectBG(xw->flags);
1165    setExtendedBG(xw);
1166}
1167
1168static void
1169reset_SGR_Colors(XtermWidget xw)
1170{
1171    reset_SGR_Foreground(xw);
1172    reset_SGR_Background(xw);
1173}
1174#endif /* OPT_ISO_COLORS */
1175
1176#if OPT_WIDE_ATTRS
1177/*
1178 * Call this before changing the state of ATR_ITALIC, to update the GC fonts.
1179 */
1180static void
1181setItalicFont(XtermWidget xw, Bool enable)
1182{
1183    if (enable) {
1184	if ((xw->flags & ATR_ITALIC) == 0) {
1185	    xtermLoadItalics(xw);
1186	    TRACE(("setItalicFont: enabling Italics\n"));
1187	    xtermUpdateFontGCs(xw, getItalicFont);
1188	}
1189    } else if ((xw->flags & ATR_ITALIC) != 0) {
1190	TRACE(("setItalicFont: disabling Italics\n"));
1191	xtermUpdateFontGCs(xw, getNormalFont);
1192    }
1193}
1194
1195static void
1196ResetItalics(XtermWidget xw)
1197{
1198    setItalicFont(xw, False);
1199    UIntClr(xw->flags, ATR_ITALIC);
1200}
1201
1202#else
1203#define ResetItalics(xw)	/* nothing */
1204#endif
1205
1206static void
1207initCharset(TScreen *screen, int which, DECNRCM_codes code)
1208{
1209    screen->gsets[which] = code;
1210}
1211
1212void
1213saveCharsets(TScreen *screen, DECNRCM_codes * target)
1214{
1215    int g;
1216    for (g = 0; g < NUM_GSETS2; ++g) {
1217	target[g] = screen->gsets[g];
1218    }
1219}
1220
1221void
1222restoreCharsets(TScreen *screen, const DECNRCM_codes * source)
1223{
1224    int g;
1225    for (g = 0; g < NUM_GSETS2; ++g) {
1226	screen->gsets[g] = source[g];
1227    }
1228}
1229
1230void
1231resetCharsets(TScreen *screen)
1232{
1233    int dft_upss = ((screen->ansi_level >= 2)
1234		    ? PreferredUPSS(screen)
1235		    : nrc_ASCII);
1236
1237#if OPT_WIDE_CHARS
1238    /*
1239     * User-preferred selection set makes a choice between ISO-8859-1 and
1240     * a precursor to it.  Those are both single-byte encodings.  Because the
1241     * multibyte UTF-8 equates to ISO-8859-1, the default (DEC Supplemental)
1242     * cannot be used as a default in UTF-8 mode.  But we cannot use ISO-8859-1
1243     * either, because that would break the special case in decodeUtf8() that
1244     * checks if NRCS is being used, passing 8-bit characters as is.
1245     *
1246     * In short, UPSS is not available with UTF-8, but DECRQUPSS will say that
1247     * ISO-Latin1 is selected.
1248     */
1249    if (screen->wide_chars && (screen->utf8_mode || screen->utf8_nrc_mode)) {
1250	dft_upss = nrc_ASCII;
1251    }
1252#endif
1253
1254    TRACE(("resetCharsets: UPSS=%s\n", visibleScsCode(dft_upss)));
1255
1256    /*
1257     * The assignments for G2/G3 to ASCII differ from the documented DEC
1258     * terminal, because xterm also checks GR to decide whether or not to
1259     * handle non-Unicode character sets, e.g., NRCS.
1260     */
1261    initCharset(screen, 0, nrc_ASCII);
1262    initCharset(screen, 1, nrc_ASCII);
1263    initCharset(screen, 2, dft_upss);
1264    initCharset(screen, 3, dft_upss);
1265    initCharset(screen, 4, dft_upss);	/* gsets_upss */
1266
1267    screen->curgl = 0;		/* G0 => GL.            */
1268    screen->curgr = 2;		/* G2 => GR.            */
1269    screen->curss = 0;		/* No single shift.     */
1270
1271#if OPT_VT52_MODE
1272    if (screen->vtXX_level == 0)
1273	initCharset(screen, 1, nrc_DEC_Spec_Graphic);	/* Graphics */
1274#endif
1275}
1276
1277static void
1278modified_DECNRCM(XtermWidget xw)
1279{
1280#if OPT_WIDE_CHARS
1281    TScreen *screen = TScreenOf(xw);
1282    if (screen->wide_chars && (screen->utf8_mode || screen->utf8_nrc_mode)) {
1283	int enabled = ((xw->flags & NATIONAL) != 0);
1284	int modefix;
1285	EXCHANGE(screen->utf8_nrc_mode, screen->utf8_mode, modefix);
1286	switchPtyData(screen, !enabled);
1287	TRACE(("UTF8 mode temporarily %s\n", enabled ? "ON" : "OFF"));
1288    }
1289#else
1290    (void) xw;
1291#endif
1292}
1293
1294/*
1295 * VT300 and up support three ANSI conformance levels, defined according to
1296 * ECMA-43 (originally dpANSI X3.134.1).
1297 *
1298 * VSRM - Documented Exceptions EL-00070-D
1299 */
1300static void
1301set_ansi_conformance(TScreen *screen, int level)
1302{
1303    TRACE(("set_ansi_conformance(%d) dec_level %d:%d, ansi_level %d\n",
1304	   level,
1305	   screen->vtXX_level * 100,
1306	   screen->terminal_id,
1307	   screen->ansi_level));
1308    if (screen->vtXX_level >= 3) {
1309	screen->ansi_level = level;
1310    }
1311}
1312
1313static void
1314set_vtXX_level(TScreen *screen, int level)
1315{
1316    screen->vtXX_level = level;
1317    screen->ansi_level = (level > 1) ? 3 : 1;
1318}
1319
1320/*
1321 * Set scrolling margins.  VTxxx terminals require that the top/bottom are
1322 * different, so we have at least two lines in the scrolling region.
1323 */
1324static void
1325set_tb_margins(TScreen *screen, int top, int bottom)
1326{
1327    TRACE(("set_tb_margins %d..%d, prior %d..%d\n",
1328	   top, bottom,
1329	   screen->top_marg,
1330	   screen->bot_marg));
1331    if (bottom > top) {
1332	screen->top_marg = top;
1333	screen->bot_marg = bottom;
1334    }
1335    if (screen->top_marg > screen->max_row)
1336	screen->top_marg = screen->max_row;
1337    if (screen->bot_marg > screen->max_row)
1338	screen->bot_marg = screen->max_row;
1339}
1340
1341static void
1342set_lr_margins(TScreen *screen, int left, int right)
1343{
1344    TRACE(("set_lr_margins %d..%d, prior %d..%d\n",
1345	   left, right,
1346	   screen->lft_marg,
1347	   screen->rgt_marg));
1348    if (right > left) {
1349	screen->lft_marg = left;
1350	screen->rgt_marg = right;
1351    }
1352    if (screen->lft_marg > screen->max_col)
1353	screen->lft_marg = screen->max_col;
1354    if (screen->rgt_marg > screen->max_col)
1355	screen->rgt_marg = screen->max_col;
1356}
1357
1358#define reset_tb_margins(screen) set_tb_margins(screen, 0, screen->max_row)
1359#define reset_lr_margins(screen) set_lr_margins(screen, 0, screen->max_col)
1360
1361void
1362resetMargins(XtermWidget xw)
1363{
1364    TScreen *screen = TScreenOf(xw);
1365
1366    reset_tb_margins(screen);
1367    reset_lr_margins(screen);
1368}
1369
1370static void
1371resetMarginMode(XtermWidget xw)
1372{
1373    UIntClr(xw->flags, LEFT_RIGHT);
1374    resetMargins(xw);
1375}
1376
1377static void
1378resetRendition(XtermWidget xw)
1379{
1380    TScreen *screen = TScreenOf(xw);
1381    (void) screen;
1382    ResetItalics(xw);
1383    UIntClr(xw->flags,
1384	    (SGR_MASK | SGR_MASK2 | INVISIBLE));
1385}
1386
1387void
1388set_max_col(TScreen *screen, int cols)
1389{
1390    TRACE(("set_max_col %d, prior %d\n", cols, screen->max_col));
1391    if (cols < 0)
1392	cols = 0;
1393    screen->max_col = cols;
1394}
1395
1396void
1397set_max_row(TScreen *screen, int rows)
1398{
1399    TRACE(("set_max_row %d, prior %d\n", rows, screen->max_row));
1400    if (rows < 0)
1401	rows = 0;
1402    screen->max_row = rows;
1403}
1404
1405#if OPT_TRACE
1406#define DATA(name) { name, #name }
1407static const struct {
1408    const PARSE_T *table;
1409    const char *name;
1410} all_tables[] = {
1411
1412    DATA(ansi_table)
1413	,DATA(cigtable)
1414	,DATA(csi2_table)
1415	,DATA(csi_ex_table)
1416	,DATA(csi_amp_table)
1417	,DATA(csi_quo_table)
1418	,DATA(csi_table)
1419	,DATA(dec2_table)
1420	,DATA(dec3_table)
1421	,DATA(dec_table)
1422	,DATA(eigtable)
1423	,DATA(esc_sp_table)
1424	,DATA(esc_table)
1425	,DATA(scrtable)
1426	,DATA(scs96table)
1427	,DATA(scstable)
1428	,DATA(sos_table)
1429#if OPT_BLINK_CURS
1430	,DATA(csi_sp_table)
1431#endif
1432#if OPT_DEC_LOCATOR
1433	,DATA(csi_tick_table)
1434#endif
1435#if OPT_DEC_RECTOPS
1436	,DATA(csi_dollar_table)
1437	,DATA(csi_star_table)
1438	,DATA(csi_dec_dollar_table)
1439#endif
1440#if OPT_VT52_MODE
1441	,DATA(vt52_table)
1442	,DATA(vt52_esc_table)
1443	,DATA(vt52_ignore_table)
1444#endif
1445#if OPT_VT525_COLORS
1446	,DATA(csi_comma_table)
1447#endif
1448#if OPT_WIDE_CHARS
1449	,DATA(esc_pct_table)
1450	,DATA(scs_amp_table)
1451	,DATA(scs_pct_table)
1452	,DATA(scs_2qt_table)
1453#endif
1454#if OPT_XTERM_SGR
1455	,DATA(csi_hash_table)
1456#endif
1457#undef DATA
1458};
1459
1460#define WHICH_TABLE(name) if (table == name) result = #name
1461static const char *
1462which_table(const PARSE_T * table)
1463{
1464    const char *result = "?";
1465    Cardinal n;
1466    for (n = 0; n < XtNumber(all_tables); ++n) {
1467	if (table == all_tables[n].table) {
1468	    result = all_tables[n].name;
1469	    break;
1470	}
1471    }
1472
1473    return result;
1474}
1475
1476static void
1477check_tables(void)
1478{
1479    Cardinal n;
1480    int ch;
1481    int total_codes = 0;
1482    int total_ground = 0;
1483    int total_ignored = 0;
1484
1485    TRACE(("** check_tables\n"));
1486    for (n = 0; n < XtNumber(all_tables); ++n) {
1487	const PARSE_T *table = all_tables[n].table;
1488	TRACE(("*** %s\n", all_tables[n].name));
1489	/*
1490	 * Most of the tables should use the same codes in 0..31, 128..159
1491	 * as the "ansi" table.
1492	 */
1493	if (strncmp(all_tables[n].name, "ansi", 4) &&
1494	    strncmp(all_tables[n].name, "sos_", 4) &&
1495	    strncmp(all_tables[n].name, "vt52", 4)) {
1496	    for (ch = 0; ch < 32; ++ch) {
1497		int c1 = ch + 128;
1498		PARSE_T st_l = table[ch];
1499		PARSE_T st_r = table[c1];
1500		if (st_l != ansi_table[ch]) {
1501		    TRACE(("  %3d: %d vs %d\n", ch, st_l, ansi_table[ch]));
1502		}
1503		if (st_r != ansi_table[c1]) {
1504		    TRACE(("  %3d: %d vs %d\n", c1, st_r, ansi_table[c1]));
1505		}
1506	    }
1507	}
1508	/*
1509	 * All of the tables should have their GL/GR parts encoded the same.
1510	 *
1511	 * Originally reported by Paul Williams (patch #171), this is a
1512	 * standard feature of DEC's terminals, documented in DEC 070 section
1513	 * 3.5.4.5 "GR Graphic Characters Within Control Strings".
1514	 */
1515	for (ch = 32; ch < 127; ++ch) {
1516	    PARSE_T st_l = table[ch];
1517	    PARSE_T st_r = table[ch + 128];
1518	    if (st_l != st_r) {
1519		if (st_r == CASE_IGNORE &&
1520		    !strncmp(all_tables[n].name, "vt52", 4)) {
1521		    ;
1522		} else {
1523		    TRACE(("  %3d: %d vs %d\n", ch, st_l, st_r));
1524		}
1525	    }
1526	}
1527	/*
1528	 * Just for amusement, show how sparse the encoding tables are.
1529	 */
1530	for (ch = 0; ch < 256; ++ch) {
1531	    ++total_codes;
1532	    switch (table[ch]) {
1533	    case CASE_GROUND_STATE:
1534		total_ground++;
1535		break;
1536	    case CASE_ESC_IGNORE:
1537		/* FALLTHRU */
1538	    case CASE_IGNORE:
1539		/* FALLTHRU */
1540	    case CASE_VT52_IGNORE:
1541		total_ignored++;
1542		break;
1543	    }
1544	}
1545    }
1546    TRACE(("VTPrsTbl:\n"));
1547    TRACE(("%d total codes\n", total_codes));
1548    TRACE(("%d total ignored\n", total_ignored));
1549    TRACE(("%d total reset/ground\n", total_ground));
1550}
1551
1552static void
1553check_bitmasks(void)
1554{
1555#define dMSK 0x100
1556#define DATA(mode,name) { mode, name, #name }
1557#define DMSK(what) (dMSK | (what))
1558#define DGRP(offs) (1 << ((offs) - 1))
1559    static struct {
1560	int mode;
1561	int code;
1562	const char *name;
1563    } table[] = {
1564	DATA(DGRP(1), INVERSE),
1565	    DATA(DGRP(1), UNDERLINE),
1566	    DATA(DGRP(1), BOLD),
1567	    DATA(DGRP(1), BLINK),
1568	    DATA(DMSK(DGRP(1)), SGR_MASK),
1569	    DATA(DGRP(2), BG_COLOR),
1570	    DATA(DGRP(2), FG_COLOR),
1571	    DATA(DGRP(2), PROTECTED),
1572	    DATA(DGRP(4), CHARDRAWN),
1573	    DATA(DGRP(2), INVISIBLE),
1574#if OPT_WIDE_ATTRS
1575	    DATA(DGRP(2), ATR_FAINT),
1576	    DATA(DGRP(2), ATR_ITALIC),
1577	    DATA(DGRP(2), ATR_STRIKEOUT),
1578	    DATA(DGRP(2), ATR_DBL_UNDER),
1579	    DATA(DGRP(2), ATR_DIRECT_FG),
1580	    DATA(DGRP(2), ATR_DIRECT_BG),
1581#endif
1582	    DATA(DMSK(DGRP(2)), SGR_MASK2),
1583	    DATA(DMSK(DGRP(3)), ATTRIBUTES),
1584	    DATA(DGRP(3), REVERSE_VIDEO),
1585	    DATA(DGRP(3), WRAPAROUND),
1586	    DATA(DGRP(3), REVERSEWRAP),
1587	    DATA(DGRP(3), REVERSEWRAP2),
1588	    DATA(DGRP(3), LINEFEED),
1589	    DATA(DGRP(3), ORIGIN),
1590	    DATA(DGRP(3), INSERT),
1591	    DATA(DGRP(3), SMOOTHSCROLL),
1592	    DATA(DGRP(3), IN132COLUMNS),
1593	    DATA(DGRP(5), NATIONAL),
1594	    DATA(DGRP(5), LEFT_RIGHT),
1595	    DATA(DGRP(5), NOCLEAR_COLM),
1596	    DATA(DGRP(4), NOBACKGROUND),
1597	    DATA(DGRP(4), NOTRANSLATION),
1598	    DATA(DGRP(4), DOUBLEWFONT),
1599	    DATA(DGRP(4), DOUBLEHFONT),
1600	    DATA(DGRP(4), CHARBYCHAR),
1601	    DATA(DGRP(4), NORESOLUTION),
1602	    DATA(DMSK(DGRP(1) | DGRP(2) | DGRP(4)), DRAWX_MASK),
1603	    DATA(-1, EOF)
1604    };
1605#undef DATA
1606    int j, k;
1607    TRACE(("** check_bitmasks:\n"));
1608    for (j = 0; table[j].mode >= 0; ++j) {
1609	TRACE(("%4X %8X %s\n", table[j].mode, table[j].code, table[j].name));
1610	if (table[j].mode & dMSK) {
1611	    int mask = dMSK;
1612	    for (k = 0; table[k].mode >= 0; ++k) {
1613		if (j == k)
1614		    continue;
1615		if (table[k].mode & dMSK)
1616		    continue;
1617		if ((table[j].mode & table[k].mode) != 0)
1618		    mask |= table[k].mode;
1619	    }
1620	    if (mask != table[j].mode) {
1621		TRACE(("...expected %08X\n", mask));
1622	    }
1623	} else {
1624	    for (k = 0; table[k].mode >= 0; ++k) {
1625		if (j == k)
1626		    continue;
1627		if (table[k].mode & dMSK)
1628		    continue;
1629		if ((table[j].code & table[k].code) != 0) {
1630		    TRACE(("...same bits %s\n", table[k].name));
1631		}
1632	    }
1633	}
1634    }
1635}
1636#endif
1637
1638static int
1639init_params(void)
1640{
1641    while (parms.count-- > 0) {
1642	parms.is_sub[parms.count] = 0;
1643	parms.params[parms.count] = 0;
1644    }
1645    parms.count = 0;
1646    parms.has_subparams = 0;
1647    return 0;
1648}
1649
1650#if OPT_TRACE > 0
1651static void
1652dump_params(void)
1653{
1654    int n;
1655    int arg;
1656    TRACE(("params %d (%d)\n", nparam, parms.has_subparams));
1657    for (arg = 1, n = 0; n < nparam; ++n) {
1658	TRACE(("%3d.%d %d\n", arg, parms.is_sub[n], parms.params[n]));
1659	if (!parms.is_sub[n])
1660	    ++arg;
1661    }
1662}
1663#define DumpParams() dump_params()
1664#else
1665#define DumpParams()		/* nothing */
1666#endif
1667
1668	/* allocate larger buffer if needed/possible */
1669#define SafeAlloc(type, area, used, size) \
1670		type *new_string = area; \
1671		size_t new_length = size; \
1672		if (new_length == 0) { \
1673		    new_length = 1024; \
1674		    new_string = TypeMallocN(type, new_length); \
1675		} else if (used+1 >= new_length) { \
1676		    new_length = size * 2; \
1677		    new_string = TypeMallocN(type, new_length); \
1678		    if (new_string != NULL \
1679		     && area != NULL \
1680		     && used != 0) { \
1681			memcpy(new_string, area, used * sizeof(type)); \
1682		     } \
1683		}
1684#define SafeFree(area, size) \
1685		if (area != new_string) { \
1686		    free(area); \
1687		    area = new_string; \
1688		} \
1689		size = new_length
1690
1691#define WriteNow() {							\
1692	    unsigned single = 0;					\
1693									\
1694	    if (screen->curss) {					\
1695		if (sp->print_area != NULL) {				\
1696		    dotext(xw,						\
1697			   screen->gsets[(int) (screen->curss)],	\
1698			   sp->print_area,				\
1699			   (Cardinal) 1);				\
1700		    single++;						\
1701		}							\
1702		screen->curss = 0;					\
1703	    }								\
1704	    if (sp->print_used > single) {				\
1705		if (sp->print_area != NULL) {				\
1706		    dotext(xw,						\
1707			   screen->gsets[(int) (screen->curgl)],	\
1708			   sp->print_area + single,			\
1709			   (Cardinal) (sp->print_used - single));	\
1710		}							\
1711	    }								\
1712	    sp->print_used = 0;						\
1713	}								\
1714
1715typedef enum {
1716    sa_INIT
1717    ,sa_LAST
1718    ,sa_REGIS
1719    ,sa_SIXEL
1720} StringArgs;
1721
1722struct ParseState {
1723    unsigned check_recur;
1724#if OPT_VT52_MODE
1725    Bool vt52_cup;
1726#endif
1727    const PARSE_T *groundtable;
1728    const PARSE_T *parsestate;
1729    int scstype;
1730    int scssize;
1731    Bool private_function;	/* distinguish private-mode from standard */
1732    int string_mode;		/* nonzero iff we're processing a string */
1733    StringArgs string_args;	/* parse-state within string processing */
1734    Bool string_skip;		/* true if we will ignore the string */
1735    int lastchar;		/* positive iff we had a graphic character */
1736    int nextstate;
1737#if OPT_WIDE_CHARS
1738    int last_was_wide;
1739#endif
1740    /* Buffer for processing printable text */
1741    IChar *print_area;
1742    size_t print_size;
1743    size_t print_used;
1744    /* Buffer for processing strings (e.g., OSC ... ST) */
1745    Char *string_area;
1746    size_t string_size;
1747    size_t string_used;
1748    /* Buffer for deferring input */
1749    Char *defer_area;
1750    size_t defer_size;
1751    size_t defer_used;
1752};
1753
1754static struct ParseState myState;
1755
1756static void
1757init_groundtable(TScreen *screen, struct ParseState *sp)
1758{
1759    (void) screen;
1760
1761#if OPT_VT52_MODE
1762    if (!(screen->vtXX_level)) {
1763	sp->groundtable = vt52_table;
1764    } else if (screen->terminal_id >= 100)
1765#endif
1766    {
1767	sp->groundtable = ansi_table;
1768    }
1769}
1770
1771static void
1772select_charset(struct ParseState *sp, int type, int size)
1773{
1774    TRACE(("select_charset G%d size %d -> G%d size %d\n",
1775	   sp->scstype, sp->scssize,
1776	   type, size));
1777
1778    sp->scstype = type;
1779    sp->scssize = size;
1780    if (size == 94) {
1781	sp->parsestate = scstable;
1782    } else {
1783	sp->parsestate = scs96table;
1784    }
1785}
1786/* *INDENT-OFF* */
1787static const struct {
1788    DECNRCM_codes result;
1789    int prefix;
1790    int suffix;
1791    int min_level;
1792    int max_level;
1793    int need_nrc;
1794    int sized_96;
1795} scs_table[] = {
1796    { nrc_ASCII,             0,   'B', 1, 9, 0, 0 },
1797    { nrc_British,           0,   'A', 1, 9, 0, 0 },
1798    { nrc_DEC_Spec_Graphic,  0,   '0', 1, 9, 0, 0 },
1799    { nrc_DEC_Alt_Chars,     0,   '1', 1, 1, 0, 0 },
1800    { nrc_DEC_Alt_Graphics,  0,   '2', 1, 1, 0, 0 },
1801    /* VT2xx */
1802    { nrc_DEC_Supp,          0,   '<', 2, 2, 0, 0 },
1803    { nrc_Dutch,             0,   '4', 2, 9, 1, 0 },
1804    { nrc_Finnish,           0,   '5', 2, 9, 1, 0 },
1805    { nrc_Finnish2,          0,   'C', 2, 9, 1, 0 },
1806    { nrc_French,            0,   'R', 2, 9, 1, 0 },
1807    { nrc_French2,           0,   'f', 2, 9, 1, 0 },
1808    { nrc_French_Canadian,   0,   'Q', 2, 9, 1, 0 },
1809    { nrc_German,            0,   'K', 2, 9, 1, 0 },
1810    { nrc_Italian,           0,   'Y', 2, 9, 1, 0 },
1811    { nrc_Norwegian_Danish2, 0,   'E', 2, 9, 1, 0 },
1812    { nrc_Norwegian_Danish3, 0,   '6', 2, 9, 1, 0 },
1813    { nrc_Spanish,           0,   'Z', 2, 9, 1, 0 },
1814    { nrc_Swedish,           0,   '7', 2, 9, 1, 0 },
1815    { nrc_Swedish2,          0,   'H', 2, 9, 1, 0 },
1816    { nrc_Swiss,             0,   '=', 2, 9, 1, 0 },
1817    /* VT3xx */
1818    { nrc_DEC_UPSS,          0,   '<', 3, 9, 0, 1 },
1819    { nrc_British_Latin_1,   0,   'A', 3, 9, 1, 0 },
1820    { nrc_DEC_Supp_Graphic,  '%', '5', 3, 9, 0, 0 },
1821    { nrc_DEC_Technical,     0,   '>', 3, 9, 0, 0 },
1822    { nrc_French_Canadian2,  0,   '9', 3, 9, 1, 0 },
1823    { nrc_Norwegian_Danish,  0,   '`', 3, 9, 1, 0 },
1824    { nrc_Portugese,         '%', '6', 3, 9, 1, 0 },
1825    { nrc_ISO_Latin_1_Supp,  0,   'A', 3, 9, 0, 1 },
1826    { nrc_JIS_Katakana,      0,   'I', 3, 3, 0, 0 },
1827    { nrc_JIS_Roman,         0,   'J', 3, 3, 0, 0 },
1828    /* VT5xx */
1829    { nrc_Greek,             '"', '>', 5, 9, 1, 0 },
1830    { nrc_Hebrew,            '%', '=', 5, 9, 1, 0 },
1831    { nrc_Russian,	     '&', '5', 5, 9, 1, 0 },
1832    { nrc_SCS_NRCS,	     '%', '3', 5, 9, 1, 0 },
1833    { nrc_Turkish,	     '%', '2', 5, 9, 1, 0 },
1834    { nrc_DEC_Cyrillic,      '&', '4', 5, 9, 0, 0 },
1835    { nrc_DEC_Greek_Supp,    '"', '?', 5, 9, 0, 0 },
1836    { nrc_DEC_Hebrew_Supp,   '"', '4', 5, 9, 0, 0 },
1837    { nrc_DEC_Turkish_Supp,  '%', '0', 5, 9, 0, 0 },
1838    { nrc_ISO_Greek_Supp,    0,   'F', 5, 9, 0, 1 },
1839    { nrc_ISO_Hebrew_Supp,   0,   'H', 5, 9, 0, 1 },
1840    { nrc_ISO_Latin_2_Supp,  0,   'B', 5, 9, 0, 1 },
1841    { nrc_ISO_Latin_5_Supp,  0,   'M', 5, 9, 0, 1 },
1842    { nrc_ISO_Latin_Cyrillic,0,   'L', 5, 9, 0, 1 },
1843};
1844/* *INDENT-ON* */
1845
1846#if OPT_DEC_RECTOPS
1847static char *
1848encode_scs(DECNRCM_codes value, int *psize)
1849{
1850    static char buffer[3];
1851    Cardinal n;
1852    char *result = buffer;
1853
1854    for (n = 0; n < XtNumber(scs_table); ++n) {
1855	if (scs_table[n].result == value) {
1856	    if (scs_table[n].prefix)
1857		*result++ = (char) scs_table[n].prefix;
1858	    if (scs_table[n].suffix)
1859		*result++ = (char) scs_table[n].suffix;
1860	    *psize = scs_table[n].sized_96;
1861	    break;
1862	}
1863    }
1864    *result = '\0';
1865    return buffer;
1866}
1867
1868static int
1869is_96charset(DECNRCM_codes value)
1870{
1871    Cardinal n;
1872    int result = 0;
1873
1874    for (n = 0; n < XtNumber(scs_table); ++n) {
1875	if (scs_table[n].result == value) {
1876	    result = scs_table[n].sized_96 ? 1 : 0;
1877	    break;
1878	}
1879    }
1880    return result;
1881}
1882#endif
1883
1884void
1885xtermDecodeSCS(XtermWidget xw, int which, int sgroup, int prefix, int suffix)
1886{
1887    TScreen *screen = TScreenOf(xw);
1888    Cardinal n;
1889    DECNRCM_codes result = nrc_Unknown;
1890
1891    prefix = AsciiOf(prefix);
1892    suffix = AsciiOf(suffix);
1893    for (n = 0; n < XtNumber(scs_table); ++n) {
1894	if (prefix == scs_table[n].prefix
1895	    && suffix == scs_table[n].suffix
1896	    && sgroup <= scs_table[n].min_level
1897	    && screen->vtXX_level >= scs_table[n].min_level
1898	    && screen->vtXX_level <= scs_table[n].max_level
1899	    && (scs_table[n].need_nrc == 0 || (xw->flags & NATIONAL) != 0)) {
1900	    result = scs_table[n].result;
1901	    break;
1902	}
1903    }
1904    if (result != nrc_Unknown) {
1905	initCharset(screen, which, result);
1906	TRACE(("setting G%d to table #%d %s",
1907	       which, n, visibleScsCode((int) result)));
1908    } else {
1909	TRACE(("...unknown GSET"));
1910	initCharset(screen, which, nrc_ASCII);
1911    }
1912#if OPT_TRACE
1913    TRACE((" ("));
1914    if (prefix)
1915	TRACE(("prefix='%c', ", prefix));
1916    TRACE(("suffix='%c', sgroup=%d", suffix, sgroup));
1917    TRACE((")\n"));
1918#endif
1919}
1920
1921/*
1922 * Given a parameter number, and subparameter (starting in each case from zero)
1923 * return the corresponding index into the parameter array.  If the combination
1924 * is not found, return -1.
1925 */
1926static int
1927subparam_index(int p, int s)
1928{
1929    int result = -1;
1930    int j, p2, s2;
1931
1932    for (j = p2 = 0; j < nparam; ++j, ++p2) {
1933	if (parms.is_sub[j]) {
1934	    s2 = 0;
1935
1936	    do {
1937		if ((p == p2) && (s == s2)) {
1938		    result = j;
1939		    break;
1940		}
1941		++s2;
1942	    } while ((++j < nparam) && (parms.is_sub[j - 1] < parms.is_sub[j]));
1943
1944	    if (result >= 0)
1945		break;
1946
1947	    --j;		/* undo the last "while" */
1948	} else if (p == p2) {
1949	    if (s == 0) {
1950		result = j;
1951	    }
1952	    break;
1953	}
1954    }
1955    TRACE2(("...subparam_index %d.%d = %d\n", p + 1, s + 1, result));
1956    return result;
1957}
1958
1959/*
1960 * Given an index into the parameter array, return the corresponding parameter
1961 * number (starting from zero).
1962 */
1963static int
1964param_number(int item)
1965{
1966    int result = -1;
1967    int j, p;
1968
1969    for (j = p = 0; j < nparam; ++j, ++p) {
1970	if (j >= item) {
1971	    result = p;
1972	    break;
1973	}
1974	if (parms.is_sub[j]) {
1975	    while ((++j < nparam) && (parms.is_sub[j - 1] < parms.is_sub[j])) {
1976		/* EMPTY */
1977	    }
1978	    --j;
1979	}
1980    }
1981
1982    TRACE2(("...param_number(%d) = %d\n", item, result));
1983    return result;
1984}
1985
1986/*
1987 * Check if the given index in the parameter array has subparameters.
1988 * If so, return the number of subparameters to use as a loop limit, etc.
1989 */
1990static int
1991param_has_subparams(int item)
1992{
1993    int result = 0;
1994    if (parms.has_subparams) {
1995	int p = param_number(item);
1996	int n = subparam_index(p, 0);
1997	if (n >= 0 && parms.is_sub[n]) {
1998	    while (++n < nparam && parms.is_sub[n - 1] < parms.is_sub[n]) {
1999		result++;
2000	    }
2001	}
2002    }
2003    TRACE(("...param_has_subparams(%d) ->%d\n", item, result));
2004    return result;
2005}
2006
2007#if OPT_DIRECT_COLOR || OPT_256_COLORS || OPT_88_COLORS || OPT_ISO_COLORS
2008
2009static int
2010get_subparam(int p, int s)
2011{
2012    int item = subparam_index(p, s);
2013    int result = (item >= 0) ? parms.params[item] : DEFAULT;
2014    TRACE(("...get_subparam[%d] = %d\n", item, result));
2015    return result;
2016}
2017
2018/*
2019 * Some background -
2020 *
2021 * Todd Larason provided the initial changes to support 256-colors in July 1999.
2022 * I pointed out that the description of SGR 38/48 in ECMA-48 was vague, and
2023 * was unsure if there would be some standard using those codes.  His response
2024 * was that this was documented (it turns out, in equally vague terms) in ITU
2025 * T.416
2026 *
2027 * Discussing this with Todd Larason in mid-1999, my point was that given the
2028 * high cost of obtaining ITU T.416 (ISO-8613-6), the standard was not going
2029 * to be effective (more than $100 then, more than $200 in 2012)
2030 *
2031 * We overlooked the detail about ":" as a subparameter delimiter (documented
2032 * in 5.4.2 in ECMA-48).  Some discussion in KDE in mid-2006 led Lars Doelle
2033 * to discuss the issue with me.  Lars' initial concern dealt with the fact
2034 * that a sequence such as
2035 *	CSI 38 ; 5 ; 1 m
2036 * violated the principle that SGR parameters could be used in any order.
2037 * Further discussion (see KDE #107487) resolved that the standard expected
2038 * that the sequence would look like
2039 *	CSI 38 ; 5 : 1 m
2040 * which still violates that principle, since the "5:1" parameter has to
2041 * follow the "38" to be useful.
2042 *
2043 * This function accepts either format (per request by Paul Leonerd Evans).
2044 * It also accepts
2045 *	CSI 38 : 5 : 1 m
2046 * according to Lars' original assumption.  While implementing that, I added
2047 * support for Konsole's interpretation of "CSI 38 : 2" as a 24-bit RGB value.
2048 * ISO-8613-6 documents that as "direct color".
2049 *
2050 * At the time in 2012, no one noticed (or commented) regarding ISO-8613-6's
2051 * quirk in the description of direct color:  it mentions a color space
2052 * identifier parameter which should follow the "2" (as parameter 1).  In the
2053 * same section, ISO-8613-6 mentions a parameter 6 which can be ignored, as
2054 * well as parameters 7 and 8.  Like parameter 1, parameters 7 and 8 are not
2055 * defined clearly in the standard, and a close reading indicates they are
2056 * optional, saying they "may be used".  This implementation ignores parameters
2057 * 6 (and above), and provides for the color space identifier by checking the
2058 * number of parameters:
2059 *	3 after "2" (no color space identifier)
2060 *	4 or more after "2" (color space identifier)
2061 *
2062 * By the way - all of the parameters are decimal integers, and missing
2063 * parameters represent a default value.  ISO-8613-6 is clear about that.
2064 *
2065 * Aside from ISO-8613-3, there is no standard use of ":" as a delimiter.
2066 * ECMA-48 says only:
2067 *
2068 *	5.4.2 Parameter string format
2069 *
2070 *	A parameter string which does not start with a bit combination in the
2071 *	range 03/12 to 03/15 shall have the following format:
2072 *
2073 *	    a) A parameter string consists of one or more parameter
2074 *	       sub-strings, each of which represents a number in decimal
2075 *	       notation.
2076 *
2077 *	    b) Each parameter sub-string consists of one or more bit
2078 *	       combinations from 03/00 to 03/10; the bit combinations from
2079 *	       03/00 to 03/09 represent the digits ZERO to NINE; bit
2080 *	       combination 03/10 may be used as a separator in a parameter
2081 *	       sub-string, for example, to separate the fractional part of a
2082 *	       decimal number from the integer part of that number.
2083 *
2084 * That is, there is no mention in ECMA-48 of the possibility that a parameter
2085 * string might be a list of parameters, as done in ISO-8613-3 (nor does
2086 * ECMA-48 provide an example where the ":" separator might be used).  Because
2087 * of this, xterm treats other cases than those needed for ISO-8613-3 as an
2088 * error, and stops interpreting the sequence.
2089 */
2090#define extended_colors_limit(n) ((n) == 5 ? 1 : ((n) == 2 ? 3 : 0))
2091static Boolean
2092parse_extended_colors(XtermWidget xw, int *colorp, int *itemp, Boolean *extended)
2093{
2094    Boolean result = False;
2095    int item = *itemp;
2096    int next = item;
2097    int base = param_number(item);
2098    int code = -1;
2099    int values[3];		/* maximum number of subparameters */
2100    int need = 0;		/* number of subparameters needed */
2101    int have;
2102    int n;
2103
2104    /*
2105     * On entry, 'item' points to the 38/48 code in the parameter array.
2106     * If that has subparameters, we will expect all of the values to
2107     * be subparameters of that item.
2108     */
2109    if ((have = param_has_subparams(item)) != 0) {
2110	/* accept CSI 38 : 5 : 1 m */
2111	/* accept CSI 38 : 2 : 1 : 2 : 3 m */
2112	code = get_subparam(base, 1);
2113	need = extended_colors_limit(code);
2114	next = item + have;
2115	for (n = 0; n < need && n < 3; ++n) {
2116	    values[n] = get_subparam(base, 2 + n + (have > 4));
2117	}
2118    } else if (++item < nparam) {
2119	++base;
2120	if ((have = param_has_subparams(item)) != 0) {
2121	    /* accept CSI 38 ; 5 : 1 m */
2122	    /* accept CSI 38 ; 2 : 1 : 2 : 3 m */
2123	    code = get_subparam(base, 0);
2124	    need = extended_colors_limit(code);
2125	    next = base + have;
2126	    for (n = 0; n < need && n < 3; ++n) {
2127		values[n] = get_subparam(base, 1 + n + (have > 3));
2128	    }
2129	} else {
2130	    /* accept CSI 38 ; 5 ; 1 m */
2131	    /* accept CSI 38 ; 2 ; 1 ; 2 ; 3 m */
2132	    code = GetParam(item);
2133	    need = extended_colors_limit(code);
2134	    next = item + need;
2135	    for (n = 0; n < need && n < 3; ++n) {
2136		values[n] = GetParam(item + 1 + n);
2137	    }
2138	}
2139    }
2140    item = next;
2141
2142    *extended = False;
2143    switch (code) {
2144    case 2:
2145	/* direct color in rgb space */
2146	if ((values[0] >= 0 && values[0] < 256) &&
2147	    (values[1] >= 0 && values[1] < 256) &&
2148	    (values[2] >= 0 && values[2] < 256)) {
2149#if OPT_DIRECT_COLOR
2150	    if (TScreenOf(xw)->direct_color && xw->has_rgb) {
2151		*colorp = getDirectColor(xw, values[0], values[1], values[2]);
2152		result = True;
2153		*extended = True;
2154	    } else
2155#endif
2156	    {
2157		*colorp = xtermClosestColor(xw, values[0], values[1], values[2]);
2158		result = okIndexedColor(*colorp);
2159	    }
2160	} else {
2161	    *colorp = -1;
2162	}
2163	break;
2164    case 5:
2165	/* indexed color */
2166	*colorp = values[0];
2167	result = okIndexedColor(*colorp);
2168	break;
2169    default:
2170	*colorp = -1;
2171	break;
2172    }
2173
2174    TRACE(("...resulting color %d/%d %s\n",
2175	   *colorp, NUM_ANSI_COLORS,
2176	   result ? "OK" : "ERR"));
2177
2178    *itemp = item;
2179    return result;
2180}
2181#endif /* ...extended_colors */
2182
2183static int
2184optional_param(int which)
2185{
2186    return (nparam > which) ? GetParam(which) : DEFAULT;
2187}
2188
2189static int
2190only_default(void)
2191{
2192    return (nparam <= 1) && (GetParam(0) == DEFAULT);
2193}
2194
2195static int
2196use_default_value(int which, int default_value)
2197{
2198    int result = (nparam > which) ? GetParam(which) : default_value;
2199    if (result <= 0)
2200	result = default_value;
2201    return result;
2202}
2203
2204#define zero_if_default(which) use_default_value(which, 0)
2205
2206#define one_if_default(which) use_default_value(which, 1)
2207
2208#define BeginString(mode) \
2209	do { \
2210	    sp->string_mode = mode; \
2211	    sp->string_args = sa_LAST; \
2212	    sp->parsestate = sos_table; \
2213	} while (0)
2214
2215#define BeginString2(mode) \
2216	do { \
2217	    sp->string_mode = mode; \
2218	    sp->string_args = sa_INIT; \
2219	    sp->parsestate = sos_table; \
2220	} while (0)
2221
2222static void
2223begin_sixel(XtermWidget xw, struct ParseState *sp)
2224{
2225    TScreen *screen = TScreenOf(xw);
2226
2227    sp->string_args = sa_LAST;
2228    if (optSixelGraphics(screen)) {
2229#if OPT_SIXEL_GRAPHICS
2230	ANSI params;
2231	const char *cp;
2232
2233	cp = (const char *) sp->string_area;
2234	sp->string_area[sp->string_used] = '\0';
2235	parse_ansi_params(&params, &cp);
2236	parse_sixel_init(xw, &params);
2237	sp->string_args = sa_SIXEL;
2238	sp->string_used = 0;
2239#else
2240	(void) screen;
2241	TRACE(("ignoring sixel graphic (compilation flag not enabled)\n"));
2242#endif
2243    }
2244}
2245
2246/*
2247 * Color palette changes using the OSC controls require a repaint of the
2248 * screen - but not immediately.  Do the repaint as soon as we detect a
2249 * state which will not lead to another color palette change.
2250 */
2251static void
2252repaintWhenPaletteChanged(XtermWidget xw, struct ParseState *sp)
2253{
2254    Boolean ignore = False;
2255
2256    switch (sp->nextstate) {
2257    case CASE_ESC:
2258	ignore = ((sp->parsestate == ansi_table) ||
2259		  (sp->parsestate == sos_table));
2260#if USE_DOUBLE_BUFFER
2261	if (resource.buffered && TScreenOf(xw)->needSwap) {
2262	    ignore = False;
2263	}
2264#endif
2265	break;
2266    case CASE_OSC:
2267	ignore = ((sp->parsestate == ansi_table) ||
2268		  (sp->parsestate == esc_table));
2269	break;
2270    case CASE_IGNORE:
2271	ignore = (sp->parsestate == sos_table);
2272	break;
2273    case CASE_ST:
2274	ignore = ((sp->parsestate == esc_table) ||
2275		  (sp->parsestate == sos_table));
2276	break;
2277    case CASE_ESC_DIGIT:
2278	ignore = (sp->parsestate == csi_table);
2279	break;
2280    case CASE_ESC_SEMI:
2281	ignore = (sp->parsestate == csi2_table);
2282	break;
2283    }
2284
2285    if (!ignore) {
2286	TRACE(("repaintWhenPaletteChanged\n"));
2287	xw->work.palette_changed = False;
2288	xtermRepaint(xw);
2289	xtermFlushDbe(xw);
2290    }
2291}
2292
2293#if OPT_C1_PRINT || OPT_WIDE_CHARS
2294#define ParseSOS(screen) ((screen)->c1_printable == 0)
2295#else
2296#define ParseSOS(screen) 0
2297#endif
2298
2299#define ResetState(sp) InitParams(), (sp)->parsestate = (sp)->groundtable
2300
2301static void
2302illegal_parse(XtermWidget xw, unsigned c, struct ParseState *sp)
2303{
2304    ResetState(sp);
2305    sp->nextstate = sp->parsestate[c];
2306    Bell(xw, XkbBI_MinorError, 0);
2307}
2308
2309static void
2310init_parser(XtermWidget xw, struct ParseState *sp)
2311{
2312    TScreen *screen = TScreenOf(xw);
2313
2314    free(sp->defer_area);
2315    free(sp->print_area);
2316    free(sp->string_area);
2317    memset(sp, 0, sizeof(*sp));
2318    sp->scssize = 94;		/* number of printable/nonspace ASCII */
2319    sp->lastchar = -1;		/* not a legal IChar */
2320    sp->nextstate = -1;		/* not a legal state */
2321
2322    init_groundtable(screen, sp);
2323    ResetState(sp);
2324}
2325
2326static void
2327init_reply(unsigned type)
2328{
2329    memset(&reply, 0, sizeof(reply));
2330    reply.a_type = (Char) type;
2331}
2332
2333static void
2334deferparsing(unsigned c, struct ParseState *sp)
2335{
2336    SafeAlloc(Char, sp->defer_area, sp->defer_used, sp->defer_size);
2337    if (new_string == NULL) {
2338	xtermWarning("Cannot allocate %lu bytes for deferred parsing of %u\n",
2339		     (unsigned long) new_length, c);
2340	return;
2341    }
2342    SafeFree(sp->defer_area, sp->defer_size);
2343    sp->defer_area[(sp->defer_used)++] = CharOf(c);
2344}
2345
2346#if OPT_MOD_FKEYS
2347static void
2348set_mod_fkeys(XtermWidget xw, int which, int what, Bool enabled)
2349{
2350#define SET_MOD_FKEYS(field) \
2351    xw->keyboard.modify_now.field = ((what == DEFAULT) && enabled) \
2352				     ? xw->keyboard.modify_1st.field \
2353				     : what; \
2354    TRACE(("set modify_now.%s to %d\n", #field, \
2355	   xw->keyboard.modify_now.field));
2356
2357    switch (which) {
2358    case 0:
2359	SET_MOD_FKEYS(allow_keys);
2360	break;
2361    case 1:
2362	SET_MOD_FKEYS(cursor_keys);
2363	break;
2364    case 2:
2365	SET_MOD_FKEYS(function_keys);
2366	break;
2367    case 3:
2368	SET_MOD_FKEYS(keypad_keys);
2369	break;
2370    case 4:
2371	SET_MOD_FKEYS(other_keys);
2372	break;
2373    case 5:
2374	SET_MOD_FKEYS(string_keys);
2375	break;
2376    }
2377}
2378
2379static void
2380report_mod_fkeys(XtermWidget xw, int which)	/* XTQMODKEYS */
2381{
2382#define GET_MOD_FKEYS(field) \
2383    reply.a_param[1] = (ParmType) xw->keyboard.modify_now.field
2384
2385    init_reply(ANSI_CSI);
2386    reply.a_pintro = '>';	/* replies look like a set-mode */
2387    reply.a_nparam = 2;
2388    reply.a_final = 'm';
2389
2390    reply.a_param[1] = DEFAULT;
2391    switch (reply.a_param[0] = (ParmType) which) {
2392    case 0:
2393	GET_MOD_FKEYS(allow_keys);
2394	break;
2395    case 1:
2396	GET_MOD_FKEYS(cursor_keys);
2397	break;
2398    case 2:
2399	GET_MOD_FKEYS(function_keys);
2400	break;
2401    case 3:
2402	GET_MOD_FKEYS(keypad_keys);
2403	break;
2404    case 4:
2405	GET_MOD_FKEYS(other_keys);
2406	break;
2407    case 5:
2408	GET_MOD_FKEYS(string_keys);
2409	break;
2410    }
2411    unparseseq(xw, &reply);
2412}
2413#endif /* OPT_MOD_FKEYS */
2414
2415#if OPT_STATUS_LINE
2416typedef enum {
2417    SLnone = 0,			/* no status-line timer needed */
2418    SLclock = 1,		/* status-line updates once/second */
2419    SLcoords = 2,		/* status-line shows cursor-position */
2420    SLwritten = 3		/* status-line may need asynchronous repainting */
2421} SL_MODE;
2422
2423#define SL_BUFSIZ 80
2424
2425#if OPT_TRACE
2426static const char *
2427visibleStatusType(int code)
2428{
2429    const char *result = "?";
2430    switch (code) {
2431    case 0:
2432	result = "none";
2433	break;
2434    case 1:
2435	result = "indicator";
2436	break;
2437    case 2:
2438	result = "writable";
2439	break;
2440    }
2441    return result;
2442}
2443
2444static void
2445trace_status_line(XtermWidget xw, int lineno, const char *tag)
2446{
2447    TScreen *screen = TScreenOf(xw);
2448
2449    TRACE(("@%d, %s (%s, %s)%s%s @ (%d,%d) vs %d\n",
2450	   lineno,
2451	   tag,
2452	   screen->status_active ? "active" : "inactive",
2453	   visibleStatusType(screen->status_type),
2454	   ((screen->status_type != screen->status_shown)
2455	    ? " vs "
2456	    : ""),
2457	   ((screen->status_type != screen->status_shown)
2458	    ? visibleStatusType(screen->status_shown)
2459	    : ""),
2460	   screen->cur_row,
2461	   screen->cur_col,
2462	   LastRowNumber(screen)));
2463}
2464
2465#define TRACE_SL(tag) trace_status_line(xw, __LINE__, tag)
2466#else
2467#define TRACE_SL(tag)		/* nothing */
2468#endif
2469
2470static SL_MODE
2471find_SL_MODE(XtermWidget xw)
2472{
2473    TScreen *screen = TScreenOf(xw);
2474    SL_MODE result = SLnone;
2475    const char *parse;
2476
2477    for (parse = screen->status_fmt; *parse != '\0'; ++parse) {
2478	const char *found = parse;
2479	if (*parse == '%') {
2480	    if (*++parse == L_CURL) {
2481		const char *check = strchr(parse, '%');
2482		size_t length = 0;
2483
2484		if (check != NULL && check[1] == R_CURL) {
2485		    length = (size_t) (2 + check - found);
2486		} else {
2487		    length = strlen(found);
2488		}
2489
2490		if (!strncmp(found, "%{unixtime%}", length)) {
2491		    if (result == SLnone)
2492			result = SLclock;
2493		} else if (!strncmp(found, "%{position%}", length)) {
2494		    result = SLcoords;
2495		}
2496		parse = found + length - 1;
2497	    }
2498#if defined(HAVE_STRFTIME)
2499	    else if (*parse != '\0') {
2500		if (result == SLnone && strchr("cEgOrsSTX+", *parse) != NULL) {
2501		    result = SLclock;
2502		}
2503	    }
2504#endif
2505	}
2506    }
2507    return result;
2508}
2509
2510static long
2511find_SL_Timeout(XtermWidget xw)
2512{
2513    long result = 0;
2514    switch (find_SL_MODE(xw)) {
2515    case SLnone:
2516    case SLwritten:
2517	break;
2518    case SLclock:
2519	result = DEF_SL_CLOCK;
2520	break;
2521    case SLcoords:
2522	result = DEF_SL_COORDS;
2523	break;
2524    }
2525    return result;
2526}
2527
2528static void
2529StatusInit(SavedCursor * data)
2530{
2531    memset(data, 0, sizeof(*data));
2532    data->sgr_foreground = -1;
2533    data->sgr_background = -1;
2534}
2535
2536#define SL_SAVE(n) \
2537	do { \
2538	    TRACE(("@%d saving %s to %d,%d\n", __LINE__, \
2539		  (n) ? "status" : "main", \
2540		  screen->cur_row, \
2541		  screen->cur_col)); \
2542	    CursorSave2(xw, &screen->status_data[n]); \
2543	} while (0)
2544#define SL_RESTORE(n) \
2545	do { \
2546	    CursorRestore2(xw, &screen->status_data[n]); \
2547	    TRACE(("@%d restored %s to %d,%d\n", __LINE__, \
2548		  (n) ? "status" : "main", \
2549		  screen->status_data[n].row, \
2550		  screen->status_data[n].col)); \
2551	} while (0)
2552
2553/* save the status-line position, restore main display */
2554#define SL_SAVE2() \
2555	do { \
2556	    SL_SAVE(1); \
2557	    SL_RESTORE(0); \
2558	} while (0)
2559
2560/* save the main-display position, restore status-line */
2561#define SL_RESTORE2() \
2562	do { \
2563	    SL_SAVE(0); \
2564	    SL_RESTORE(1); \
2565	    screen->cur_row = FirstRowNumber(screen); \
2566	} while (0)
2567
2568static void
2569StatusPutChars(XtermWidget xw, const char *value, int length)
2570{
2571    TScreen *screen = TScreenOf(xw);
2572
2573    if (length < 0)
2574	length = (int) strlen(value);
2575
2576    while (length > 0) {
2577	IChar buffer[SL_BUFSIZ + 1];
2578	Cardinal n;
2579	for (n = 0; n < SL_BUFSIZ && length > 0 && *value != '\0'; ++n) {
2580	    buffer[n] = CharOf(*value++);
2581	    if (buffer[n] < 32 || buffer[n] > 126)
2582		buffer[n] = ' ';	/* FIXME - provide for UTF-8 */
2583	    --length;
2584	}
2585	buffer[n] = 0;
2586	dotext(xw,
2587	       screen->gsets[(int) (screen->curgl)],
2588	       buffer, n);
2589    }
2590}
2591
2592static void
2593show_indicator_status(XtPointer closure, XtIntervalId * id GCC_UNUSED)
2594{
2595    XtermWidget xw = (XtermWidget) closure;
2596    TScreen *screen = TScreenOf(xw);
2597    int right_margin;
2598
2599    time_t now;
2600    const char *parse;
2601    char buffer[SL_BUFSIZ + 1];
2602    long interval;
2603
2604    if (screen->status_type != 1) {
2605	screen->status_timeout = False;
2606	return;
2607    }
2608    if (screen->status_active && (screen->status_type == screen->status_shown)) {
2609	return;
2610    }
2611
2612    screen->status_active = True;
2613
2614    if (screen->status_shown <= 1) {
2615	SL_SAVE(0);
2616    }
2617    screen->cur_row = FirstRowNumber(screen);
2618    screen->cur_col = 0;
2619
2620    xw->flags |= INVERSE;
2621    xw->flags &= (IFlags) (~WRAPAROUND);
2622
2623    now = time((time_t *) 0);
2624
2625    for (parse = screen->status_fmt; *parse != '\0'; ++parse) {
2626	const char *found = parse;
2627	if (*parse == '%') {
2628	    if (*++parse == L_CURL) {
2629		const char *check = strchr(parse, '%');
2630		size_t length = 0;
2631
2632		if (check != NULL && check[1] == R_CURL) {
2633		    length = (size_t) (2 + check - found);
2634		} else {
2635		    length = strlen(found);
2636		}
2637
2638		if (!strncmp(found, "%{version%}", length)) {
2639		    StatusPutChars(xw, xtermVersion(), -1);
2640		} else if (!strncmp(found, "%{unixtime%}", length)) {
2641		    char *t = x_strtrim(ctime(&now));
2642		    if (t != NULL) {
2643			StatusPutChars(xw, t, -1);
2644			free(t);
2645		    }
2646		} else if (!strncmp(found, "%{position%}", length)) {
2647		    sprintf(buffer, "(%02d,%03d)",
2648			    screen->status_data[0].row + 1,
2649			    screen->status_data[0].col + 1);
2650		    StatusPutChars(xw, buffer, -1);
2651		} else {
2652		    StatusPutChars(xw, found, (int) length);
2653		}
2654		parse = found + length - 1;
2655	    }
2656#if defined(HAVE_STRFTIME)
2657	    else if (*parse != '\0') {
2658		char format[3];
2659		struct tm *tm = localtime(&now);
2660
2661		format[0] = '%';
2662		format[1] = *parse;
2663		format[2] = '\0';
2664		if (strftime(buffer, sizeof(buffer) - 1, format, tm) != 0) {
2665		    StatusPutChars(xw, buffer, -1);
2666		} else {
2667		    StatusPutChars(xw, "?", 1);
2668		    StatusPutChars(xw, parse - 1, 2);
2669		}
2670	    }
2671#endif
2672	} else {
2673	    StatusPutChars(xw, parse, 1);
2674	}
2675    }
2676    right_margin = ScrnRightMargin(xw);
2677    memset(buffer, ' ', (size_t) SL_BUFSIZ);
2678    while (screen->cur_col < right_margin) {
2679	int chunk = Min(SL_BUFSIZ, (right_margin - screen->cur_col));
2680	StatusPutChars(xw, buffer, chunk);
2681    }
2682
2683    ScrnRefresh(xw, FirstRowNumber(screen), 0, 1, right_margin, True);
2684    screen->status_active = False;
2685
2686    SL_RESTORE(0);
2687
2688    /* if we processed a position or date/time, repeat */
2689    interval = find_SL_Timeout(xw);
2690    if (interval > 0) {
2691	(void) XtAppAddTimeOut(app_con,
2692			       (unsigned long) interval,
2693			       show_indicator_status, xw);
2694    }
2695    screen->status_timeout = True;
2696}
2697
2698static void
2699clear_status_line(XtermWidget xw)
2700{
2701    TScreen *screen = TScreenOf(xw);
2702    SavedCursor save_me;
2703    SavedCursor clearit;
2704    int save_type = screen->status_type;
2705
2706    TRACE_SL("clear_status_line");
2707    StatusInit(&clearit);
2708    CursorSave2(xw, &save_me);
2709    CursorRestore2(xw, &clearit);
2710
2711    screen->status_type = 2;
2712    set_cur_row(screen, LastRowNumber(screen));
2713#if 1
2714    ClearLine(xw);
2715#else
2716    if (getLineData(screen, screen->cur_row) != NULL) {
2717	int n;
2718	char buffer[SL_BUFSIZ + 1];
2719	CLineData *ld = getLineData(screen, screen->cur_row);
2720	int right_margin = ScrnRightMargin(xw);
2721
2722	TRACE(("...text[%d:%d]:%s\n",
2723	       screen->cur_row,
2724	       LastRowNumber(screen),
2725	       visibleIChars(ld->charData, ld->lineSize)));
2726
2727	memset(buffer, '#', SL_BUFSIZ);
2728	for (n = 0; n < screen->max_col; n += SL_BUFSIZ) {
2729	    StatusPutChars(xw, buffer, right_margin - n);
2730	}
2731    }
2732#endif
2733    CursorRestore2(xw, &save_me);
2734    screen->status_type = save_type;
2735    TRACE_SL("clear_status_line (done)");
2736}
2737
2738static void
2739show_writable_status(XtermWidget xw)
2740{
2741    TScreen *screen = TScreenOf(xw);
2742
2743    TRACE(("show_writable_status (%d:%d) max=%d\n",
2744	   FirstRowNumber(screen),
2745	   LastRowNumber(screen),
2746	   MaxRows(screen)));
2747    screen->cur_row = FirstRowNumber(screen);
2748}
2749
2750/*
2751 * Depending the status-type, make the window grow or shrink by one row to
2752 * show or hide the status-line.  Keep the rest of the window from scrolling
2753 * by overriding the resize-gravity.
2754 */
2755static void
2756resize_status_line(XtermWidget xw)
2757{
2758    TScreen *screen = TScreenOf(xw);
2759    XtGravity savedGravity = xw->misc.resizeGravity;
2760
2761    TRACE_SL(screen->status_type
2762	     ? "...resize to show status-line"
2763	     : "...resize to hide status-line");
2764
2765    xw->misc.resizeGravity = NorthWestGravity;
2766
2767    RequestResize(xw, MaxRows(screen), MaxCols(screen), True);
2768
2769    xw->misc.resizeGravity = savedGravity;
2770}
2771
2772/*
2773 * DEC STD 070, chapter 14 "VSRM - Status Display Extension"
2774 */
2775static void
2776update_status_line(XtermWidget xw, int new_active, int new_type)
2777{
2778    /* *INDENT-EQLS* */
2779    TScreen *screen = TScreenOf(xw);
2780    int old_active  = screen->status_active;
2781    int old_type    = screen->status_type;
2782    int old_shown   = screen->status_shown;
2783
2784    TRACE_SL("update_status_line");
2785
2786    if (new_active >= 0 && new_active <= 1) {
2787	screen->status_active = new_active;
2788	if (old_active == new_active) {
2789	    goto finish;
2790	}
2791	if (old_type < 2) {
2792	    goto finish;
2793	}
2794	if (new_active && !old_active) {
2795	    SL_SAVE(0);
2796	}
2797    } else if (new_type >= 0 && new_type <= 2) {
2798	screen->status_type = new_type;
2799    } else {
2800	goto finish;
2801    }
2802
2803    if (screen->status_type == 1) {
2804	int next_shown = screen->status_type;
2805	if (screen->status_type != screen->status_shown) {
2806	    if (screen->status_shown == 0) {
2807		resize_status_line(xw);
2808	    } else {
2809		clear_status_line(xw);
2810	    }
2811	}
2812	show_indicator_status(xw, NULL);
2813	if (screen->status_shown != next_shown) {
2814	    screen->status_shown = next_shown;
2815	    TRACE_SL("...updating shown");
2816	}
2817	if (old_shown == 2) {
2818	    SL_RESTORE(0);
2819	}
2820    } else if (screen->status_active) {
2821	if (screen->status_type != screen->status_shown) {
2822	    Boolean do_resize = False;
2823
2824	    if (screen->status_type == 0) {
2825		if (screen->status_shown >= 2) {
2826		    SL_SAVE2();
2827		}
2828		do_resize = True;	/* shrink... */
2829		clear_status_line(xw);
2830		StatusInit(&screen->status_data[1]);
2831	    } else if (screen->status_shown == 0) {
2832		if (screen->status_type >= 2) {
2833		    SL_RESTORE2();
2834		}
2835		do_resize = True;	/* grow... */
2836	    } else {
2837		clear_status_line(xw);
2838	    }
2839	    if (do_resize) {
2840		resize_status_line(xw);
2841	    }
2842	    screen->status_shown = screen->status_type;
2843	    TRACE_SL("...updating shown");
2844	}
2845	show_writable_status(xw);
2846    } else {
2847	if (screen->status_shown) {
2848	    if (screen->status_type != 0 &&
2849		screen->status_type != screen->status_shown) {
2850		clear_status_line(xw);
2851	    }
2852	    if (screen->status_shown >= 2) {
2853		SL_SAVE2();
2854	    }
2855	    if (screen->status_type == 0) {
2856		screen->status_timeout = False;
2857		clear_status_line(xw);
2858		StatusInit(&screen->status_data[1]);
2859		resize_status_line(xw);		/* shrink... */
2860	    }
2861	    screen->status_shown = screen->status_type;
2862	    TRACE_SL("...updating shown");
2863	}
2864    }
2865  finish:
2866    TRACE_SL("update_status_line (done)");
2867    return;
2868}
2869
2870/*
2871 * If the status-type is "2", we can switch the active status display back and
2872 * forth between the main-display and the status-line without clearing the
2873 * status-line (unless the status-line was not shown before).
2874 *
2875 * This has no effect if the status-line displays an indicator (type==1),
2876 * or if no status-line type was selected (type==0).
2877 */
2878static void
2879handle_DECSASD(XtermWidget xw, int value)
2880{
2881    TRACE(("CASE_DECSASD - select active status display: %s (currently %s)\n",
2882	   BtoS(value),
2883	   BtoS(TScreenOf(xw)->status_active)));
2884
2885    update_status_line(xw, value, -1);
2886}
2887
2888/*
2889 * If the status-line is inactive (i.e., only the main-display is used),
2890 * changing the status-type between none/writable has no immediate effect.
2891 *
2892 * But if the status-line is active, setting the status-type reinitializes the
2893 * status-line.
2894 *
2895 * Setting the status-type to indicator overrides the DECSASD active-display
2896 * mode.
2897 */
2898static void
2899handle_DECSSDT(XtermWidget xw, int value)
2900{
2901    TRACE(("CASE_DECSSDT - select type of status display: %d (currently %d)\n",
2902	   value,
2903	   TScreenOf(xw)->status_type));
2904
2905    update_status_line(xw, -1, value);
2906}
2907
2908#else
2909#define clear_status_line(xw)	/* nothing */
2910#endif /* OPT_STATUS_LINE */
2911
2912#if OPT_VT52_MODE
2913static void
2914update_vt52_vt100_settings(void)
2915{
2916    update_autowrap();
2917    update_reversewrap();
2918    update_autolinefeed();
2919    update_appcursor();
2920    update_appkeypad();
2921    update_allow132();
2922}
2923#endif
2924
2925#define TRACE_GSETS(name) TRACE(("CASE_GSETS%s(%d) = '%c'\n", name, sp->scstype, AsciiOf(c)))
2926
2927static Boolean
2928doparsing(XtermWidget xw, unsigned c, struct ParseState *sp)
2929{
2930    TScreen *screen = TScreenOf(xw);
2931    int item;
2932    int count;
2933    int value;
2934    int laststate;
2935    int thischar = -1;
2936    XTermRect myRect;
2937#if OPT_DEC_RECTOPS
2938    int thispage = 1;
2939#endif
2940
2941    if (sp->check_recur) {
2942	/* Defer parsing when parser is already running as the parser is not
2943	 * safe to reenter.
2944	 */
2945	deferparsing(c, sp);
2946	return True;
2947    }
2948    sp->check_recur++;
2949
2950    do {
2951#if OPT_WIDE_CHARS
2952	int this_is_wide = 0;
2953	int is_formatter = 0;
2954
2955	/*
2956	 * Handle zero-width combining characters.  Make it faster by noting
2957	 * that according to the Unicode charts, the majority of Western
2958	 * character sets do not use this feature.  There are some unassigned
2959	 * codes at 0x242, but no zero-width characters until past 0x300.
2960	 */
2961	if (c >= 0x300
2962	    && screen->wide_chars
2963	    && CharWidth(screen, c) == 0
2964	    && !(is_formatter = (CharacterClass((int) c) == CNTRL))) {
2965	    int prev, test;
2966	    Boolean used = True;
2967	    int use_row;
2968	    int use_col;
2969
2970	    WriteNow();
2971	    use_row = (screen->char_was_written
2972		       ? screen->last_written_row
2973		       : screen->cur_row);
2974	    use_col = (screen->char_was_written
2975		       ? screen->last_written_col
2976		       : screen->cur_col);
2977
2978	    /*
2979	     * Check if the latest data can be added to the base character.
2980	     * If there is already a combining character stored for the cell,
2981	     * we cannot, since that would change the order.
2982	     */
2983	    if (screen->normalized_c
2984		&& !IsCellCombined(screen, use_row, use_col)) {
2985		prev = (int) XTERM_CELL(use_row, use_col);
2986		test = do_precomposition(prev, (int) c);
2987		TRACE(("do_precomposition (U+%04X [%d], U+%04X [%d]) -> U+%04X [%d]\n",
2988		       prev, CharWidth(screen, prev),
2989		       (int) c, CharWidth(screen, c),
2990		       test, CharWidth(screen, test)));
2991	    } else {
2992		prev = -1;
2993		test = -1;
2994	    }
2995
2996	    /* substitute combined character with precomposed character
2997	     * only if it does not change the width of the base character
2998	     */
2999	    if (test != -1
3000		&& CharWidth(screen, test) == CharWidth(screen, prev)) {
3001		putXtermCell(screen, use_row, use_col, test);
3002	    } else if (screen->char_was_written
3003		       || getXtermCell(screen, use_row, use_col) >= ' ') {
3004		addXtermCombining(screen, use_row, use_col, c);
3005	    } else {
3006		/*
3007		 * none of the above... we will add the combining character as
3008		 * a base character.
3009		 */
3010		used = False;
3011	    }
3012
3013	    if (used) {
3014		if (!screen->scroll_amt)
3015		    ScrnUpdate(xw, use_row, use_col, 1, 1, 1);
3016		break;
3017	    }
3018	}
3019#endif
3020
3021	/* Intercept characters for printer controller mode */
3022	if (PrinterOf(screen).printer_controlmode == 2) {
3023	    if ((c = (unsigned) xtermPrinterControl(xw, (int) c)) == 0)
3024		break;
3025	}
3026
3027	/*
3028	 * VT52 is a little ugly in the one place it has a parameterized
3029	 * control sequence, since the parameter falls after the character
3030	 * that denotes the type of sequence.
3031	 */
3032#if OPT_VT52_MODE
3033	if (sp->vt52_cup) {
3034	    int row, col;
3035	    if (nparam < NPARAM - 1) {
3036		SetParam(nparam++, (int) AsciiOf(c) - 32);
3037		parms.is_sub[nparam] = 0;
3038	    }
3039	    if (nparam < 2)
3040		break;
3041	    sp->vt52_cup = False;
3042	    /*
3043	     * According to EK-VT5X-OP-001 DECscope User's Guide, if the row
3044	     * is out of range, no vertical movement occurs, while if the
3045	     * column is out of range, it is set to the rightmost column.
3046	     *
3047	     * However, DEC 070 (VSRM - VT52 Emulation EL-00070-0A, page A-28)
3048	     * differs from that, updating the column only when the parameter
3049	     * is in range, i.e., not mentioning the rightmost column.
3050	     */
3051	    if ((row = GetParam(0)) > screen->max_row)
3052		row = screen->cur_row;
3053	    if ((col = GetParam(1)) > screen->max_col)
3054		col = ((screen->terminal_id < 100)
3055		       ? screen->max_col	/* real VT52 */
3056		       : screen->cur_col);	/* emulated VT52 */
3057	    CursorSet(screen, row, col, xw->flags);
3058	    sp->parsestate = vt52_table;
3059	    SetParam(0, 0);
3060	    SetParam(1, 0);
3061	    break;
3062	}
3063#endif
3064
3065	laststate = sp->nextstate;
3066	if (c == ANSI_DEL
3067	    && sp->parsestate == sp->groundtable
3068	    && sp->scssize == 96
3069	    && sp->scstype != 0) {
3070	    /*
3071	     * Handle special case of shifts for 96-character sets by checking
3072	     * if we have a DEL.  The other special case for SPACE will always
3073	     * be printable.
3074	     */
3075	    sp->nextstate = CASE_PRINT;
3076	} else
3077#if OPT_WIDE_CHARS
3078	if (c > 255) {
3079	    /*
3080	     * The parsing tables all have 256 entries.  If we're supporting
3081	     * wide characters, we handle them by treating them the same as
3082	     * printing characters.
3083	     */
3084	    if (sp->parsestate == sp->groundtable) {
3085		sp->nextstate = is_formatter ? CASE_IGNORE : CASE_PRINT;
3086	    } else if (sp->parsestate == sos_table) {
3087		if ((c & WIDEST_ICHAR) > 255) {
3088		    TRACE(("Found code > 255 while in SOS state: %04X\n", c));
3089		    c = BAD_ASCII;
3090		}
3091	    } else {
3092		sp->nextstate = CASE_GROUND_STATE;
3093	    }
3094	} else
3095#endif
3096	    sp->nextstate = sp->parsestate[c];
3097
3098#if OPT_BROKEN_OSC
3099	/*
3100	 * Linux console palette escape sequences start with an OSC, but do
3101	 * not terminate correctly.  Some scripts do not check before writing
3102	 * them, making xterm appear to hang (it's awaiting a valid string
3103	 * terminator).  Just ignore these if we see them - there's no point
3104	 * in emulating bad code.
3105	 */
3106	if (screen->brokenLinuxOSC
3107	    && sp->parsestate == sos_table) {
3108	    if (sp->string_used && sp->string_area) {
3109		switch (sp->string_area[0]) {
3110		case 'P':
3111		    if (sp->string_used <= 7)
3112			break;
3113		    /* FALLTHRU */
3114		case 'R':
3115		    illegal_parse(xw, c, sp);
3116		    TRACE(("Reset to ground state (brokenLinuxOSC)\n"));
3117		    break;
3118		}
3119	    }
3120	}
3121#endif
3122
3123#if OPT_BROKEN_ST
3124	/*
3125	 * Before patch #171, carriage control embedded within an OSC string
3126	 * would terminate it.  Some (buggy, of course) applications rely on
3127	 * this behavior.  Accommodate them by allowing one to compile xterm
3128	 * and emulate the old behavior.
3129	 */
3130	if (screen->brokenStringTerm
3131	    && sp->parsestate == sos_table
3132	    && c < 32) {
3133	    switch (c) {
3134	    case ANSI_EOT:	/* FALLTHRU */
3135	    case ANSI_BS:	/* FALLTHRU */
3136	    case ANSI_HT:	/* FALLTHRU */
3137	    case ANSI_LF:	/* FALLTHRU */
3138	    case ANSI_VT:	/* FALLTHRU */
3139	    case ANSI_FF:	/* FALLTHRU */
3140	    case ANSI_CR:	/* FALLTHRU */
3141	    case ANSI_SO:	/* FALLTHRU */
3142	    case ANSI_SI:	/* FALLTHRU */
3143	    case ANSI_XON:	/* FALLTHRU */
3144	    case ANSI_CAN:
3145		illegal_parse(xw, c, sp);
3146		TRACE(("Reset to ground state (brokenStringTerm)\n"));
3147		break;
3148	    }
3149	}
3150#endif
3151
3152#if OPT_C1_PRINT
3153	/*
3154	 * This is not completely foolproof, but will allow an application
3155	 * with values in the C1 range to use them as printable characters,
3156	 * provided that they are not intermixed with an escape sequence.
3157	 */
3158#if OPT_WIDE_CHARS
3159	if (!screen->wide_chars)
3160#endif
3161	    if (screen->c1_printable
3162		&& (c >= 128 && c < 256)) {
3163		sp->nextstate = (sp->parsestate == esc_table
3164				 ? CASE_ESC_IGNORE
3165				 : sp->parsestate[160]);
3166		TRACE(("allowC1Printable %04X %s ->%s\n",
3167		       c, which_table(sp->parsestate),
3168		       visibleVTparse(sp->nextstate)));
3169	    }
3170#endif
3171
3172#if OPT_WIDE_CHARS
3173	/*
3174	 * If we have a C1 code and the c1_printable flag is not set, simply
3175	 * ignore it when it was translated from UTF-8, unless the parse-state
3176	 * tells us that a C1 would be legal.
3177	 */
3178#if OPT_C1_PRINT
3179	if (!screen->c1_printable)
3180#endif
3181	    if (screen->wide_chars
3182		&& (c >= 128 && c < 160)) {
3183		if (sp->parsestate != ansi_table)
3184		    sp->nextstate = CASE_IGNORE;
3185	    }
3186
3187	/*
3188	 * If this character is a different width than the last one, put the
3189	 * previous text into the buffer and draw it now.
3190	 */
3191	this_is_wide = isWide((int) c);
3192	if (this_is_wide != sp->last_was_wide) {
3193	    WriteNow();
3194	}
3195#endif
3196
3197	/*
3198	 * Accumulate string for printable text.  This may be 8/16-bit
3199	 * characters.
3200	 */
3201	if (sp->nextstate == CASE_PRINT) {
3202	    SafeAlloc(IChar, sp->print_area, sp->print_used, sp->print_size);
3203	    if (new_string == NULL) {
3204		xtermWarning("Cannot allocate %lu bytes for printable text\n",
3205			     (unsigned long) new_length);
3206		break;
3207	    }
3208	    SafeFree(sp->print_area, sp->print_size);
3209#if OPT_VT52_MODE
3210	    /*
3211	     * Strip output text to 7-bits for VT52.  We should do this for
3212	     * VT100 also (which is a 7-bit device), but xterm has been
3213	     * doing this for so long we shouldn't change this behavior.
3214	     */
3215	    if (screen->vtXX_level < 1)
3216		c = AsciiOf(c);
3217#endif
3218	    sp->print_area[sp->print_used++] = (IChar) c;
3219	    sp->lastchar = thischar = (int) c;
3220#if OPT_WIDE_CHARS
3221	    sp->last_was_wide = this_is_wide;
3222#endif
3223	    if (morePtyData(screen, VTbuffer)) {
3224		break;
3225	    }
3226	}
3227
3228	if (sp->nextstate == CASE_PRINT
3229	    || (laststate == CASE_PRINT && sp->print_used)) {
3230	    WriteNow();
3231	}
3232
3233	/*
3234	 * Accumulate string for DCS, OSC controls
3235	 * The string content should always be 8-bit characters.
3236	 *
3237	 * APC, PM and SOS are ignored; xterm currently does not use those.
3238	 */
3239	if (sp->parsestate == sos_table) {
3240#if OPT_WIDE_CHARS
3241	    /*
3242	     * We cannot display codes above 255, but let's try to
3243	     * accommodate the application a little by not aborting the
3244	     * string.
3245	     */
3246	    if ((c & WIDEST_ICHAR) > 255) {
3247		sp->nextstate = CASE_PRINT;
3248		c = BAD_ASCII;
3249	    }
3250#endif
3251	    if (sp->string_mode == ANSI_APC ||
3252		sp->string_mode == ANSI_PM ||
3253		sp->string_mode == ANSI_SOS) {
3254		/* EMPTY */
3255	    }
3256#if OPT_SIXEL_GRAPHICS
3257	    else if (sp->string_args == sa_SIXEL) {
3258		/* avoid adding the string-terminator */
3259		if (sos_table[CharOf(c)] == CASE_IGNORE)
3260		    parse_sixel_char(AsciiOf(c));
3261	    }
3262#endif
3263	    else if (sp->string_skip) {
3264		sp->string_used++;
3265	    } else if (sp->string_used > screen->strings_max) {
3266		sp->string_skip = True;
3267		sp->string_used++;
3268		FreeAndNull(sp->string_area);
3269		sp->string_size = 0;
3270	    } else {
3271		Boolean utf8Title;
3272
3273		SafeAlloc(Char, sp->string_area, sp->string_used, sp->string_size);
3274		if (new_string == NULL) {
3275		    xtermWarning("Cannot allocate %lu bytes for string mode %#02x\n",
3276				 (unsigned long) new_length, sp->string_mode);
3277		    break;
3278		}
3279		SafeFree(sp->string_area, sp->string_size);
3280
3281		/*
3282		 * Provide for special case where xterm allows an OSC string to
3283		 * contain 8-bit data.  Otherwise, ECMA-48 section 9 recommends
3284		 * parsing controls with a 7-bit table, precluding the use of
3285		 * 8-bit data.
3286		 */
3287#if OPT_WIDE_CHARS
3288		utf8Title = (sp->string_mode == ANSI_OSC
3289			     && IsSetUtf8Title(xw)
3290			     && (sp->string_used >= 2)
3291			     && (sp->string_area[0] == '0'
3292				 || sp->string_area[0] == '2')
3293			     && sp->string_area[1] == ';');
3294#else
3295		utf8Title = False;
3296#endif
3297
3298		/*
3299		 * ReGIS and SIXEL data can be detected by skipping over (only)
3300		 * parameters to the first non-parameter character and
3301		 * inspecting it.  Since both are DCS, we can also ignore OSC.
3302		 */
3303		sp->string_area[(sp->string_used)++] = (utf8Title
3304							? CharOf(c)
3305							: AsciiOf(c));
3306		if (sp->string_args < sa_LAST) {
3307		    switch (c) {
3308		    case ':':
3309		    case ';':
3310		    case '0':
3311		    case '1':
3312		    case '2':
3313		    case '3':
3314		    case '4':
3315		    case '5':
3316		    case '6':
3317		    case '7':
3318		    case '8':
3319		    case '9':
3320			break;
3321		    case 'p':
3322			sp->string_args = sa_REGIS;
3323			break;
3324		    case 'q':
3325			begin_sixel(xw, sp);
3326			break;
3327		    default:
3328			sp->string_args = sa_LAST;
3329			break;
3330		    }
3331		}
3332	    }
3333	} else if (sp->parsestate != esc_table) {
3334	    /* if we were accumulating, we're not any more */
3335	    sp->string_mode = 0;
3336	    sp->string_used = 0;
3337	}
3338
3339	DumpParams();
3340	TRACE(("parse %04X -> %s %s (used=%lu)\n",
3341	       c, visibleVTparse(sp->nextstate),
3342	       which_table(sp->parsestate),
3343	       (unsigned long) sp->string_used));
3344
3345	/*
3346	 * If the parameter list has subparameters (tokens separated by ":")
3347	 * reject any controls that do not accept subparameters.
3348	 */
3349	if (parms.has_subparams) {
3350	    switch (sp->nextstate) {
3351	    case CASE_GROUND_STATE:
3352	    case CASE_CSI_IGNORE:
3353	    case CASE_SUB:
3354		/* FALLTHRU */
3355
3356	    case CASE_ESC_DIGIT:
3357	    case CASE_ESC_SEMI:
3358	    case CASE_ESC_COLON:
3359		/* these states are required to parse parameter lists */
3360		break;
3361
3362	    case CASE_SGR:
3363		TRACE(("...possible subparam usage\n"));
3364		break;
3365
3366	    case CASE_CSI_DEC_DOLLAR_STATE:
3367	    case CASE_CSI_DOLLAR_STATE:
3368	    case CASE_CSI_HASH_STATE:
3369	    case CASE_CSI_EX_STATE:
3370	    case CASE_CSI_QUOTE_STATE:
3371	    case CASE_CSI_SPACE_STATE:
3372	    case CASE_CSI_STAR_STATE:
3373	    case CASE_CSI_TICK_STATE:
3374	    case CASE_DEC2_STATE:
3375	    case CASE_DEC3_STATE:
3376	    case CASE_DEC_STATE:
3377		/* use this branch when we do not yet have the final character */
3378		TRACE(("...unexpected subparam usage\n"));
3379		InitParams();
3380		sp->nextstate = CASE_CSI_IGNORE;
3381		break;
3382
3383	    default:
3384		/* use this branch for cases where we have the final character
3385		 * in the table that processed the parameter list.
3386		 */
3387		TRACE(("...unexpected subparam usage\n"));
3388		ResetState(sp);
3389		break;
3390	    }
3391	}
3392
3393	if (xw->work.palette_changed) {
3394	    repaintWhenPaletteChanged(xw, sp);
3395	}
3396#if OPT_STATUS_LINE
3397	/*
3398	 * If we are currently writing to the status-line, ignore controls that
3399	 * apply only to the full screen, or which use features which we will
3400	 * not support in the status-line.
3401	 */
3402	if (IsStatusShown(screen) && (screen)->status_active) {
3403	    switch (sp->nextstate) {
3404	    case CASE_DECDHL:
3405	    case CASE_DECSWL:
3406	    case CASE_DECDWL:
3407	    case CASE_CUU:
3408	    case CASE_CUD:
3409	    case CASE_VPA:
3410	    case CASE_VPR:
3411	    case CASE_ED:
3412	    case CASE_TRACK_MOUSE:
3413	    case CASE_DECSTBM:
3414	    case CASE_DECALN:
3415	    case CASE_GRAPHICS_ATTRIBUTES:
3416	    case CASE_SUB:
3417	    case CASE_SPA:
3418	    case CASE_EPA:
3419	    case CASE_SU:
3420	    case CASE_IND:
3421	    case CASE_CPL:
3422	    case CASE_CNL:
3423	    case CASE_NEL:
3424	    case CASE_RI:
3425#if OPT_DEC_LOCATOR
3426	    case CASE_DECEFR:
3427	    case CASE_DECELR:
3428	    case CASE_DECSLE:
3429	    case CASE_DECRQLP:
3430#endif
3431#if OPT_DEC_RECTOPS
3432	    case CASE_DECRQCRA:
3433	    case CASE_DECCRA:
3434	    case CASE_DECERA:
3435	    case CASE_DECFRA:
3436	    case CASE_DECSERA:
3437	    case CASE_DECSACE:
3438	    case CASE_DECCARA:
3439	    case CASE_DECRARA:
3440#endif
3441		ResetState(sp);
3442		sp->nextstate = -1;	/* not a legal state */
3443		break;
3444	    }
3445	}
3446#endif
3447
3448	switch (sp->nextstate) {
3449	case CASE_PRINT:
3450	    TRACE(("CASE_PRINT - printable characters\n"));
3451	    break;
3452
3453	case CASE_GROUND_STATE:
3454	    TRACE(("CASE_GROUND_STATE - exit ignore mode\n"));
3455	    ResetState(sp);
3456	    break;
3457
3458	case CASE_IGNORE:
3459	    TRACE(("CASE_IGNORE - Ignore character %02X\n", c));
3460	    break;
3461
3462	case CASE_SUB:
3463	    TRACE(("CASE_SUB - substitute/show error\n"));
3464	    /*
3465	     * ECMA-48 5th edition (June 1991) documents SUB without describing
3466	     * its effect.  Earlier editions do not mention it.
3467	     *
3468	     * DEC's VT100 user guide documents SUB as having the same effect
3469	     * as CAN (cancel).  The VT220 reference adds a visible effect
3470	     * (display as a reverse "?"), as well as mentioning that device
3471	     * control sequences also are cancelled.  DEC 070 comments that a
3472	     * "half-tone blotch" is used with VT100, etc.
3473	     *
3474	     * None of that applies to VT52.
3475	     */
3476	    if (screen->terminal_id >= 100) {
3477		IChar effect = (
3478#if OPT_WIDE_CHARS
3479				   (screen->terminal_id > 200) ? 0x2426 : 0x2592
3480#else
3481				   2
3482#endif
3483		);
3484		dotext(xw,
3485		       screen->gsets[(int) (screen->curgl)],
3486		       &effect, 1);
3487	    }
3488	    ResetState(sp);
3489	    break;
3490
3491	case CASE_ENQ:
3492	    TRACE(("CASE_ENQ - answerback\n"));
3493	    if (((xw->keyboard.flags & MODE_SRM) == 0)
3494		? (sp->check_recur == 0)
3495		: (sp->check_recur <= 1)) {
3496		for (count = 0; screen->answer_back[count] != 0; count++)
3497		    unparseputc(xw, screen->answer_back[count]);
3498		unparse_end(xw);
3499	    }
3500	    break;
3501
3502	case CASE_BELL:
3503	    TRACE(("CASE_BELL - bell\n"));
3504	    if (sp->string_mode == ANSI_OSC) {
3505		if (sp->string_area) {
3506		    if (sp->string_used)
3507			sp->string_area[--(sp->string_used)] = '\0';
3508		    if (sp->check_recur <= 1)
3509			do_osc(xw, sp->string_area, sp->string_used, (int) c);
3510		}
3511		ResetState(sp);
3512	    } else {
3513		/* bell */
3514		Bell(xw, XkbBI_TerminalBell, 0);
3515	    }
3516	    break;
3517
3518	case CASE_BS:
3519	    TRACE(("CASE_BS - backspace\n"));
3520	    CursorBack(xw, 1);
3521	    break;
3522
3523	case CASE_CR:
3524	    TRACE(("CASE_CR\n"));
3525	    CarriageReturn(xw);
3526	    break;
3527
3528	case CASE_ESC:
3529	    if_OPT_VT52_MODE(screen, {
3530		sp->parsestate = vt52_esc_table;
3531		break;
3532	    });
3533	    sp->parsestate = esc_table;
3534	    break;
3535
3536#if OPT_VT52_MODE
3537	case CASE_VT52_CUP:
3538	    TRACE(("CASE_VT52_CUP - VT52 cursor addressing\n"));
3539	    sp->vt52_cup = True;
3540	    ResetState(sp);
3541	    break;
3542
3543	case CASE_VT52_IGNORE:
3544	    TRACE(("CASE_VT52_IGNORE - VT52 ignore-character\n"));
3545	    sp->parsestate = vt52_ignore_table;
3546	    break;
3547#endif
3548
3549	case CASE_VMOT:
3550	    TRACE(("CASE_VMOT\n"));
3551	    /*
3552	     * form feed, line feed, vertical tab
3553	     */
3554	    xtermAutoPrint(xw, c);
3555	    xtermIndex(xw, 1);
3556	    if (xw->flags & LINEFEED)
3557		CarriageReturn(xw);
3558	    else if (screen->jumpscroll && !screen->fastscroll)
3559		do_xevents(xw);
3560	    break;
3561
3562	case CASE_CBT:
3563	    TRACE(("CASE_CBT\n"));
3564	    /* cursor backward tabulation */
3565	    count = one_if_default(0);
3566	    while ((count-- > 0)
3567		   && (TabToPrevStop(xw))) ;
3568	    ResetState(sp);
3569	    break;
3570
3571	case CASE_CHT:
3572	    TRACE(("CASE_CHT\n"));
3573	    /* cursor forward tabulation */
3574	    count = one_if_default(0);
3575	    while ((count-- > 0)
3576		   && (TabToNextStop(xw))) ;
3577	    ResetState(sp);
3578	    break;
3579
3580	case CASE_TAB:
3581	    /* tab */
3582	    TabToNextStop(xw);
3583	    break;
3584
3585	case CASE_SI:
3586	    screen->curgl = 0;
3587	    if_OPT_VT52_MODE(screen, {
3588		ResetState(sp);
3589	    });
3590	    break;
3591
3592	case CASE_SO:
3593	    screen->curgl = 1;
3594	    if_OPT_VT52_MODE(screen, {
3595		ResetState(sp);
3596	    });
3597	    break;
3598
3599	case CASE_DECDHL:
3600	    TRACE(("CASE_DECDHL - double-height line: %s\n",
3601		   (AsciiOf(c) == '3') ? "top" : "bottom"));
3602	    xterm_DECDHL(xw, AsciiOf(c) == '3');
3603	    ResetState(sp);
3604	    break;
3605
3606	case CASE_DECSWL:
3607	    TRACE(("CASE_DECSWL - single-width line\n"));
3608	    xterm_DECSWL(xw);
3609	    ResetState(sp);
3610	    break;
3611
3612	case CASE_DECDWL:
3613	    TRACE(("CASE_DECDWL - double-width line\n"));
3614	    xterm_DECDWL(xw);
3615	    ResetState(sp);
3616	    break;
3617
3618	case CASE_SCR_STATE:
3619	    /* enter scr state */
3620	    sp->parsestate = scrtable;
3621	    break;
3622
3623	case CASE_SCS0_STATE:
3624	    /* enter scs state 0 */
3625	    select_charset(sp, 0, 94);
3626	    break;
3627
3628	case CASE_SCS1_STATE:
3629	    /* enter scs state 1 */
3630	    select_charset(sp, 1, 94);
3631	    break;
3632
3633	case CASE_SCS2_STATE:
3634	    /* enter scs state 2 */
3635	    select_charset(sp, 2, 94);
3636	    break;
3637
3638	case CASE_SCS3_STATE:
3639	    /* enter scs state 3 */
3640	    select_charset(sp, 3, 94);
3641	    break;
3642
3643	case CASE_SCS1A_STATE:
3644	    /* enter scs state 1 */
3645	    select_charset(sp, 1, 96);
3646	    break;
3647
3648	case CASE_SCS2A_STATE:
3649	    /* enter scs state 2 */
3650	    select_charset(sp, 2, 96);
3651	    break;
3652
3653	case CASE_SCS3A_STATE:
3654	    /* enter scs state 3 */
3655	    select_charset(sp, 3, 96);
3656	    break;
3657
3658	case CASE_ESC_IGNORE:
3659	    /* unknown escape sequence */
3660	    sp->parsestate = eigtable;
3661	    break;
3662
3663	case CASE_ESC_DIGIT:
3664	    /* digit in csi or dec mode */
3665	    if (nparam > 0) {
3666		value = zero_if_default(nparam - 1);
3667		SetParam(nparam - 1, (10 * value) + (int) (AsciiOf(c) - '0'));
3668		if (GetParam(nparam - 1) > MAX_I_PARAM)
3669		    SetParam(nparam - 1, MAX_I_PARAM);
3670		if (sp->parsestate == csi_table)
3671		    sp->parsestate = csi2_table;
3672	    }
3673	    break;
3674
3675	case CASE_ESC_SEMI:
3676	    /* semicolon in csi or dec mode */
3677	    if (nparam < NPARAM) {
3678		parms.is_sub[nparam] = 0;
3679		SetParam(nparam++, DEFAULT);
3680	    }
3681	    if (sp->parsestate == csi_table)
3682		sp->parsestate = csi2_table;
3683	    break;
3684
3685	    /*
3686	     * A _few_ commands accept colon-separated subparameters.
3687	     * Mark the parameter list so that we can exclude (most) bogus
3688	     * commands with simple/fast checks.
3689	     */
3690	case CASE_ESC_COLON:
3691	    if (nparam < NPARAM) {
3692		parms.has_subparams = 1;
3693		if (nparam == 0) {
3694		    parms.is_sub[nparam] = 1;
3695		    SetParam(nparam++, DEFAULT);
3696		} else if (parms.is_sub[nparam - 1] == 0) {
3697		    parms.is_sub[nparam - 1] = 1;
3698		    parms.is_sub[nparam] = 2;
3699		    parms.params[nparam] = 0;
3700		    ++nparam;
3701		} else {
3702		    parms.is_sub[nparam] = 1 + parms.is_sub[nparam - 1];
3703		    parms.params[nparam] = 0;
3704		    ++nparam;
3705		}
3706	    }
3707	    break;
3708
3709	case CASE_DEC_STATE:
3710	    /* enter dec mode */
3711	    sp->parsestate = dec_table;
3712	    break;
3713
3714	case CASE_DEC2_STATE:
3715	    /* enter dec2 mode */
3716	    sp->parsestate = dec2_table;
3717	    break;
3718
3719	case CASE_DEC3_STATE:
3720	    /* enter dec3 mode */
3721	    sp->parsestate = dec3_table;
3722	    break;
3723
3724	case CASE_ICH:
3725	    TRACE(("CASE_ICH - insert char\n"));
3726	    InsertChar(xw, (unsigned) one_if_default(0));
3727	    ResetState(sp);
3728	    break;
3729
3730	case CASE_CUU:
3731	    TRACE(("CASE_CUU - cursor up\n"));
3732	    CursorUp(screen, one_if_default(0));
3733	    ResetState(sp);
3734	    break;
3735
3736	case CASE_CUD:
3737	    TRACE(("CASE_CUD - cursor down\n"));
3738	    CursorDown(screen, one_if_default(0));
3739	    ResetState(sp);
3740	    break;
3741
3742	case CASE_CUF:
3743	    TRACE(("CASE_CUF - cursor forward\n"));
3744	    CursorForward(xw, one_if_default(0));
3745	    ResetState(sp);
3746	    break;
3747
3748	case CASE_CUB:
3749	    TRACE(("CASE_CUB - cursor backward\n"));
3750	    CursorBack(xw, one_if_default(0));
3751	    ResetState(sp);
3752	    break;
3753
3754	case CASE_CUP:
3755	    TRACE(("CASE_CUP - cursor position\n"));
3756	    if_OPT_XMC_GLITCH(screen, {
3757		Jump_XMC(xw);
3758	    });
3759	    CursorSet(screen, one_if_default(0) - 1, one_if_default(1) - 1, xw->flags);
3760	    ResetState(sp);
3761	    break;
3762
3763	case CASE_VPA:
3764	    TRACE(("CASE_VPA - vertical position absolute\n"));
3765	    CursorSet(screen, one_if_default(0) - 1, CursorCol(xw), xw->flags);
3766	    ResetState(sp);
3767	    break;
3768
3769	case CASE_HPA:
3770	    TRACE(("CASE_HPA - horizontal position absolute\n"));
3771	    CursorSet(screen, CursorRow(xw), one_if_default(0) - 1, xw->flags);
3772	    ResetState(sp);
3773	    break;
3774
3775	case CASE_VPR:
3776	    TRACE(("CASE_VPR - vertical position relative\n"));
3777	    CursorSet(screen,
3778		      CursorRow(xw) + one_if_default(0),
3779		      CursorCol(xw),
3780		      xw->flags);
3781	    ResetState(sp);
3782	    break;
3783
3784	case CASE_HPR:
3785	    TRACE(("CASE_HPR - horizontal position relative\n"));
3786	    CursorSet(screen,
3787		      CursorRow(xw),
3788		      CursorCol(xw) + one_if_default(0),
3789		      xw->flags);
3790	    ResetState(sp);
3791	    break;
3792
3793	case CASE_HP_BUGGY_LL:
3794	    TRACE(("CASE_HP_BUGGY_LL\n"));
3795	    /* Some HP-UX applications have the bug that they
3796	       assume ESC F goes to the lower left corner of
3797	       the screen, regardless of what terminfo says. */
3798	    if (screen->hp_ll_bc)
3799		CursorSet(screen, screen->max_row, 0, xw->flags);
3800	    ResetState(sp);
3801	    break;
3802
3803	case CASE_ED:
3804	    TRACE(("CASE_ED - erase display\n"));
3805	    do_cd_xtra_scroll(xw, zero_if_default(0));
3806	    do_erase_display(xw, zero_if_default(0), OFF_PROTECT);
3807	    ResetState(sp);
3808	    break;
3809
3810	case CASE_EL:
3811	    TRACE(("CASE_EL - erase line\n"));
3812	    do_erase_line(xw, zero_if_default(0), OFF_PROTECT);
3813	    ResetState(sp);
3814	    break;
3815
3816	case CASE_ECH:
3817	    TRACE(("CASE_ECH - erase char\n"));
3818	    /* ECH */
3819	    do_erase_char(xw, one_if_default(0), OFF_PROTECT);
3820	    ResetState(sp);
3821	    break;
3822
3823	case CASE_IL:
3824	    TRACE(("CASE_IL - insert line\n"));
3825	    InsertLine(xw, one_if_default(0));
3826	    ResetState(sp);
3827	    break;
3828
3829	case CASE_DL:
3830	    TRACE(("CASE_DL - delete line\n"));
3831	    DeleteLine(xw, one_if_default(0), True);
3832	    ResetState(sp);
3833	    break;
3834
3835	case CASE_DCH:
3836	    TRACE(("CASE_DCH - delete char\n"));
3837	    DeleteChar(xw, (unsigned) one_if_default(0));
3838	    ResetState(sp);
3839	    break;
3840
3841	case CASE_TRACK_MOUSE:
3842	    /*
3843	     * A single parameter other than zero is always scroll-down.
3844	     * A zero-parameter is used to reset the mouse mode, and is
3845	     * not useful for scrolling anyway.
3846	     */
3847	    if (nparam > 1 || GetParam(0) == 0) {
3848		CELL start;
3849
3850		TRACE(("CASE_TRACK_MOUSE\n"));
3851		/* Track mouse as long as in window and between
3852		 * specified rows
3853		 */
3854		start.row = one_if_default(2) - 1;
3855		start.col = GetParam(1) - 1;
3856		TrackMouse(xw,
3857			   GetParam(0),
3858			   &start,
3859			   GetParam(3) - 1, GetParam(4) - 2);
3860	    } else {
3861		TRACE(("CASE_SD - scroll down\n"));
3862		/* SD */
3863		RevScroll(xw, one_if_default(0));
3864		do_xevents(xw);
3865	    }
3866	    ResetState(sp);
3867	    break;
3868
3869	case CASE_SD:
3870	    /*
3871	     * Cater to ECMA-48's typographical error...
3872	     */
3873	    TRACE(("CASE_SD - scroll down\n"));
3874	    RevScroll(xw, one_if_default(0));
3875	    do_xevents(xw);
3876	    ResetState(sp);
3877	    break;
3878
3879	case CASE_DECID:
3880	    TRACE(("CASE_DECID\n"));
3881	    if_OPT_VT52_MODE(screen, {
3882		/*
3883		 * If xterm's started in VT52 mode, it's not emulating VT52
3884		 * within VT100, etc., so the terminal identifies differently.
3885		 */
3886		switch (screen->terminal_id) {
3887		case 50:
3888		    value = 'A';
3889		    break;
3890		case 52:
3891		    value = 'K';
3892		    break;
3893		case 55:
3894		    value = 'C';
3895		    break;
3896		default:
3897		    value = 'Z';
3898		    break;
3899		}
3900		unparseputc(xw, ANSI_ESC);
3901		unparseputc(xw, '/');
3902		unparseputc(xw, value);
3903		unparse_end(xw);
3904		ResetState(sp);
3905		break;
3906	    });
3907	    SetParam(0, DEFAULT);	/* Default ID parameter */
3908	    /* FALLTHRU */
3909	case CASE_DA1:
3910	    TRACE(("CASE_DA1\n"));
3911	    if (GetParam(0) <= 0) {	/* less than means DEFAULT */
3912		count = 0;
3913		init_reply(ANSI_CSI);
3914		reply.a_pintro = '?';
3915
3916		/*
3917		 * The first parameter corresponds to the highest operating
3918		 * level (i.e., service level) of the emulation.  A DEC
3919		 * terminal can be setup to respond with a different DA
3920		 * response, but there's no control sequence that modifies
3921		 * this.  We set it via a resource.
3922		 */
3923		if (screen->display_da1 < 200) {
3924		    switch (screen->display_da1) {
3925		    case 132:
3926			reply.a_param[count++] = 4;	/* VT132 */
3927#if OPT_REGIS_GRAPHICS
3928			reply.a_param[count++] = 6;	/* no STP, AVO, GPO (ReGIS) */
3929#else
3930			reply.a_param[count++] = 2;	/* no STP, AVO, no GPO (ReGIS) */
3931#endif
3932			break;
3933		    case 131:
3934			reply.a_param[count++] = 7;	/* VT131 */
3935			break;
3936		    case 125:
3937			reply.a_param[count++] = 12;	/* VT125 */
3938#if OPT_REGIS_GRAPHICS
3939			reply.a_param[count++] = 0 | 2 | 1;	/* no STP, AVO, GPO (ReGIS) */
3940#else
3941			reply.a_param[count++] = 0 | 2 | 0;	/* no STP, AVO, no GPO (ReGIS) */
3942#endif
3943			reply.a_param[count++] = 0;	/* no printer */
3944			reply.a_param[count++] = XTERM_PATCH;	/* ROM version */
3945			break;
3946		    case 102:
3947			reply.a_param[count++] = 6;	/* VT102 */
3948			break;
3949		    case 101:
3950			reply.a_param[count++] = 1;	/* VT101 */
3951			reply.a_param[count++] = 0;	/* no options */
3952			break;
3953		    default:	/* VT100 */
3954			reply.a_param[count++] = 1;	/* VT100 */
3955			reply.a_param[count++] = 2;	/* no STP, AVO, no GPO (ReGIS) */
3956			break;
3957		    }
3958		} else {
3959		    reply.a_param[count++] = (ParmType) (60
3960							 + screen->display_da1
3961							 / 100);
3962		    reply.a_param[count++] = 1;		/* 132-columns */
3963		    reply.a_param[count++] = 2;		/* printer */
3964#if OPT_REGIS_GRAPHICS
3965		    if (optRegisGraphics(screen)) {
3966			reply.a_param[count++] = 3;	/* ReGIS graphics */
3967		    }
3968#endif
3969#if OPT_SIXEL_GRAPHICS
3970		    if (optSixelGraphics(screen)) {
3971			reply.a_param[count++] = 4;	/* sixel graphics */
3972		    }
3973#endif
3974		    reply.a_param[count++] = 6;		/* selective-erase */
3975#if OPT_SUNPC_KBD
3976		    if (xw->keyboard.type == keyboardIsVT220)
3977#endif
3978			reply.a_param[count++] = 8;	/* user-defined-keys */
3979		    reply.a_param[count++] = 9;		/* national replacement charsets */
3980		    reply.a_param[count++] = 15;	/* technical characters */
3981		    reply.a_param[count++] = 16;	/* locator port */
3982		    if (screen->display_da1 >= 400) {
3983			reply.a_param[count++] = 17;	/* terminal state interrogation */
3984			reply.a_param[count++] = 18;	/* windowing extension */
3985			reply.a_param[count++] = 21;	/* horizontal scrolling */
3986		    }
3987		    if_OPT_ISO_COLORS(screen, {
3988			reply.a_param[count++] = 22;	/* ANSI color, VT525 */
3989		    });
3990		    reply.a_param[count++] = 28;	/* rectangular editing */
3991#if OPT_DEC_LOCATOR
3992		    reply.a_param[count++] = 29;	/* ANSI text locator */
3993#endif
3994		}
3995		reply.a_nparam = (ParmType) count;
3996		reply.a_final = 'c';
3997		unparseseq(xw, &reply);
3998	    }
3999	    ResetState(sp);
4000	    break;
4001
4002	case CASE_DA2:
4003	    TRACE(("CASE_DA2\n"));
4004	    if (GetParam(0) <= 0) {	/* less than means DEFAULT */
4005		count = 0;
4006		init_reply(ANSI_CSI);
4007		reply.a_pintro = '>';
4008
4009		if (screen->terminal_id >= 200) {
4010		    switch (screen->terminal_id) {
4011		    case 220:
4012		    default:
4013			reply.a_param[count++] = 1;	/* VT220 */
4014			break;
4015		    case 240:
4016		    case 241:
4017			/* http://www.decuslib.com/DECUS/vax87a/gendyn/vt200_kind.lis */
4018			reply.a_param[count++] = 2;	/* VT240 */
4019			break;
4020		    case 320:
4021			/* http://www.vt100.net/docs/vt320-uu/appendixe.html */
4022			reply.a_param[count++] = 24;	/* VT320 */
4023			break;
4024		    case 330:
4025			reply.a_param[count++] = 18;	/* VT330 */
4026			break;
4027		    case 340:
4028			reply.a_param[count++] = 19;	/* VT340 */
4029			break;
4030		    case 382:
4031			reply.a_param[count++] = 32;	/* VT382 */
4032			break;
4033		    case 420:
4034			reply.a_param[count++] = 41;	/* VT420 */
4035			break;
4036		    case 510:
4037			/* http://www.vt100.net/docs/vt510-rm/DA2 */
4038			reply.a_param[count++] = 61;	/* VT510 */
4039			break;
4040		    case 520:
4041			reply.a_param[count++] = 64;	/* VT520 */
4042			break;
4043		    case 525:
4044			reply.a_param[count++] = 65;	/* VT525 */
4045			break;
4046		    }
4047		} else {
4048		    reply.a_param[count++] = 0;		/* VT100 (nonstandard) */
4049		}
4050		reply.a_param[count++] = XTERM_PATCH;	/* Version */
4051		reply.a_param[count++] = 0;	/* options (none) */
4052		reply.a_nparam = (ParmType) count;
4053		reply.a_final = 'c';
4054		unparseseq(xw, &reply);
4055	    }
4056	    ResetState(sp);
4057	    break;
4058
4059	case CASE_DECRPTUI:
4060	    TRACE(("CASE_DECRPTUI\n"));
4061	    if ((screen->vtXX_level >= 4)
4062		&& (GetParam(0) <= 0)) {	/* less than means DEFAULT */
4063		unparseputc1(xw, ANSI_DCS);
4064		unparseputc(xw, '!');
4065		unparseputc(xw, '|');
4066		/* report the "terminal unit id" as 4 pairs of hexadecimal
4067		 * digits -- meaningless for a terminal emulator, but some
4068		 * host may care about the format.
4069		 */
4070		for (count = 0; count < 8; ++count) {
4071		    unparseputc(xw, '0');
4072		}
4073		unparseputc1(xw, ANSI_ST);
4074		unparse_end(xw);
4075	    }
4076	    ResetState(sp);
4077	    break;
4078
4079	case CASE_TBC:
4080	    TRACE(("CASE_TBC - tab clear\n"));
4081	    if ((value = GetParam(0)) <= 0)	/* less than means default */
4082		TabClear(xw->tabs, screen->cur_col);
4083	    else if (value == 3)
4084		TabZonk(xw->tabs);
4085	    ResetState(sp);
4086	    break;
4087
4088	case CASE_SET:
4089	    TRACE(("CASE_SET - set mode\n"));
4090	    ansi_modes(xw, bitset);
4091	    ResetState(sp);
4092	    break;
4093
4094	case CASE_RST:
4095	    TRACE(("CASE_RST - reset mode\n"));
4096	    ansi_modes(xw, bitclr);
4097	    ResetState(sp);
4098	    break;
4099
4100	case CASE_SGR:
4101	    for (item = 0; item < nparam; ++item) {
4102		int op = GetParam(item);
4103		int skip;
4104
4105		if_OPT_XMC_GLITCH(screen, {
4106		    Mark_XMC(xw, op);
4107		});
4108		TRACE(("CASE_SGR %d\n", op));
4109
4110		/*
4111		 * Only SGR 38/48 accept subparameters, and in those cases
4112		 * the values will not be seen at this point.
4113		 */
4114		if ((skip = param_has_subparams(item)) != 0) {
4115		    switch (op) {
4116		    case 38:
4117			/* FALLTHRU */
4118		    case 48:
4119			if_OPT_ISO_COLORS(screen, {
4120			    break;
4121			});
4122			/* FALLTHRU */
4123		    default:
4124			TRACE(("...unexpected subparameter in SGR\n"));
4125			item += skip;	/* ignore this */
4126			op = 9999;	/* will never use this, anyway */
4127			break;
4128		    }
4129		}
4130
4131		switch (op) {
4132		case DEFAULT:
4133		    /* FALLTHRU */
4134		case 0:
4135		    resetRendition(xw);
4136		    if_OPT_ISO_COLORS(screen, {
4137			reset_SGR_Colors(xw);
4138		    });
4139		    break;
4140		case 1:	/* Bold                 */
4141		    UIntSet(xw->flags, BOLD);
4142		    if_OPT_ISO_COLORS(screen, {
4143			setExtendedFG(xw);
4144		    });
4145		    break;
4146#if OPT_WIDE_ATTRS
4147		case 2:	/* faint, decreased intensity or second colour */
4148		    UIntSet(xw->flags, ATR_FAINT);
4149		    if_OPT_ISO_COLORS(screen, {
4150			setExtendedFG(xw);
4151		    });
4152		    break;
4153		case 3:	/* italicized */
4154		    setItalicFont(xw, UseItalicFont(screen));
4155		    UIntSet(xw->flags, ATR_ITALIC);
4156		    if_OPT_ISO_COLORS(screen, {
4157			setExtendedFG(xw);
4158		    });
4159		    break;
4160#endif
4161		case 4:	/* Underscore           */
4162		    UIntSet(xw->flags, UNDERLINE);
4163		    if_OPT_ISO_COLORS(screen, {
4164			setExtendedFG(xw);
4165		    });
4166		    break;
4167		case 5:	/* Blink (less than 150 per minute) */
4168		    /* FALLTHRU */
4169		case 6:	/* Blink (150 per minute, or more) */
4170		    UIntSet(xw->flags, BLINK);
4171		    StartBlinking(xw);
4172		    if_OPT_ISO_COLORS(screen, {
4173			setExtendedFG(xw);
4174		    });
4175		    break;
4176		case 7:
4177		    UIntSet(xw->flags, INVERSE);
4178		    if_OPT_ISO_COLORS(screen, {
4179			setExtendedBG(xw);
4180		    });
4181		    break;
4182		case 8:
4183		    UIntSet(xw->flags, INVISIBLE);
4184		    break;
4185#if OPT_WIDE_ATTRS
4186		case 9:	/* crossed-out characters */
4187		    UIntSet(xw->flags, ATR_STRIKEOUT);
4188		    break;
4189#endif
4190#if OPT_WIDE_ATTRS
4191		case 21:	/* doubly-underlined */
4192		    UIntSet(xw->flags, ATR_DBL_UNDER);
4193		    break;
4194#endif
4195		case 22:	/* reset 'bold' */
4196		    UIntClr(xw->flags, BOLD);
4197#if OPT_WIDE_ATTRS
4198		    UIntClr(xw->flags, ATR_FAINT);
4199#endif
4200		    if_OPT_ISO_COLORS(screen, {
4201			setExtendedFG(xw);
4202		    });
4203		    break;
4204#if OPT_WIDE_ATTRS
4205		case 23:	/* not italicized */
4206		    ResetItalics(xw);
4207		    if_OPT_ISO_COLORS(screen, {
4208			setExtendedFG(xw);
4209		    });
4210		    break;
4211#endif
4212		case 24:
4213		    UIntClr(xw->flags, UNDERLINE);
4214#if OPT_WIDE_ATTRS
4215		    UIntClr(xw->flags, ATR_DBL_UNDER);
4216#endif
4217		    if_OPT_ISO_COLORS(screen, {
4218			setExtendedFG(xw);
4219		    });
4220		    break;
4221		case 25:	/* reset 'blink' */
4222		    UIntClr(xw->flags, BLINK);
4223		    if_OPT_ISO_COLORS(screen, {
4224			setExtendedFG(xw);
4225		    });
4226		    break;
4227		case 27:
4228		    UIntClr(xw->flags, INVERSE);
4229		    if_OPT_ISO_COLORS(screen, {
4230			setExtendedBG(xw);
4231		    });
4232		    break;
4233		case 28:
4234		    UIntClr(xw->flags, INVISIBLE);
4235		    break;
4236#if OPT_WIDE_ATTRS
4237		case 29:	/* not crossed out */
4238		    UIntClr(xw->flags, ATR_STRIKEOUT);
4239		    break;
4240#endif
4241		case 30:
4242		    /* FALLTHRU */
4243		case 31:
4244		    /* FALLTHRU */
4245		case 32:
4246		    /* FALLTHRU */
4247		case 33:
4248		    /* FALLTHRU */
4249		case 34:
4250		    /* FALLTHRU */
4251		case 35:
4252		    /* FALLTHRU */
4253		case 36:
4254		    /* FALLTHRU */
4255		case 37:
4256		    if_OPT_ISO_COLORS(screen, {
4257			xw->sgr_foreground = (op - 30);
4258			xw->sgr_38_xcolors = False;
4259			clrDirectFG(xw->flags);
4260			setExtendedFG(xw);
4261		    });
4262		    break;
4263		case 38:
4264		    /* This is more complicated than I'd like, but it should
4265		     * properly eat all the parameters for unsupported modes.
4266		     */
4267		    if_OPT_ISO_COLORS(screen, {
4268			Boolean extended;
4269			if (parse_extended_colors(xw, &value, &item,
4270						  &extended)) {
4271			    xw->sgr_foreground = value;
4272			    xw->sgr_38_xcolors = True;
4273			    setDirectFG(xw->flags, extended);
4274			    setExtendedFG(xw);
4275			}
4276		    });
4277		    break;
4278		case 39:
4279		    if_OPT_ISO_COLORS(screen, {
4280			reset_SGR_Foreground(xw);
4281		    });
4282		    break;
4283		case 40:
4284		    /* FALLTHRU */
4285		case 41:
4286		    /* FALLTHRU */
4287		case 42:
4288		    /* FALLTHRU */
4289		case 43:
4290		    /* FALLTHRU */
4291		case 44:
4292		    /* FALLTHRU */
4293		case 45:
4294		    /* FALLTHRU */
4295		case 46:
4296		    /* FALLTHRU */
4297		case 47:
4298		    if_OPT_ISO_COLORS(screen, {
4299			xw->sgr_background = (op - 40);
4300			clrDirectBG(xw->flags);
4301			setExtendedBG(xw);
4302		    });
4303		    break;
4304		case 48:
4305		    if_OPT_ISO_COLORS(screen, {
4306			Boolean extended;
4307			if (parse_extended_colors(xw, &value, &item,
4308						  &extended)) {
4309			    xw->sgr_background = value;
4310			    setDirectBG(xw->flags, extended);
4311			    setExtendedBG(xw);
4312			}
4313		    });
4314		    break;
4315		case 49:
4316		    if_OPT_ISO_COLORS(screen, {
4317			reset_SGR_Background(xw);
4318		    });
4319		    break;
4320		case 90:
4321		    /* FALLTHRU */
4322		case 91:
4323		    /* FALLTHRU */
4324		case 92:
4325		    /* FALLTHRU */
4326		case 93:
4327		    /* FALLTHRU */
4328		case 94:
4329		    /* FALLTHRU */
4330		case 95:
4331		    /* FALLTHRU */
4332		case 96:
4333		    /* FALLTHRU */
4334		case 97:
4335		    if_OPT_AIX_COLORS(screen, {
4336			xw->sgr_foreground = (op - 90 + 8);
4337			clrDirectFG(xw->flags);
4338			setExtendedFG(xw);
4339		    });
4340		    break;
4341		case 100:
4342#if !OPT_AIX_COLORS
4343		    if_OPT_ISO_COLORS(screen, {
4344			reset_SGR_Foreground(xw);
4345			reset_SGR_Background(xw);
4346		    });
4347		    break;
4348#endif
4349		case 101:
4350		    /* FALLTHRU */
4351		case 102:
4352		    /* FALLTHRU */
4353		case 103:
4354		    /* FALLTHRU */
4355		case 104:
4356		    /* FALLTHRU */
4357		case 105:
4358		    /* FALLTHRU */
4359		case 106:
4360		    /* FALLTHRU */
4361		case 107:
4362		    if_OPT_AIX_COLORS(screen, {
4363			xw->sgr_background = (op - 100 + 8);
4364			clrDirectBG(xw->flags);
4365			setExtendedBG(xw);
4366		    });
4367		    break;
4368		default:
4369		    /* later: skip += NPARAM; */
4370		    break;
4371		}
4372	    }
4373	    ResetState(sp);
4374	    break;
4375
4376	    /* DSR (except for the '?') is a superset of CPR */
4377	case CASE_DSR:
4378	    sp->private_function = True;
4379
4380	    /* FALLTHRU */
4381	case CASE_CPR:
4382	    TRACE(("CASE_DSR - device status report\n"));
4383	    count = 0;
4384	    init_reply(ANSI_CSI);
4385	    reply.a_pintro = CharOf(sp->private_function ? '?' : 0);
4386	    reply.a_final = 'n';
4387
4388	    switch (GetParam(0)) {
4389	    case 5:
4390		TRACE(("...request operating status\n"));
4391		/* operating status */
4392		reply.a_param[count++] = 0;	/* (no malfunction ;-) */
4393		break;
4394	    case 6:
4395		TRACE(("...request %s\n",
4396		       (sp->private_function
4397			? "DECXCPR"
4398			: "CPR")));
4399		/* CPR */
4400		/* DECXCPR (with page=1) */
4401		value = screen->cur_row;
4402		if ((xw->flags & ORIGIN) != 0) {
4403		    value -= screen->top_marg;
4404		}
4405		if_STATUS_LINE(screen, {
4406		    if ((value -= LastRowNumber(screen)) < 0)
4407			value = 0;
4408		});
4409		reply.a_param[count++] = (ParmType) (value + 1);
4410
4411		value = (screen->cur_col + 1);
4412		if ((xw->flags & ORIGIN) != 0) {
4413		    value -= screen->lft_marg;
4414		}
4415		reply.a_param[count++] = (ParmType) value;
4416
4417		if (sp->private_function &&
4418		    (screen->vtXX_level >= 4 ||
4419		     (screen->terminal_id >= 330 &&
4420		      screen->vtXX_level >= 3))) {
4421		    /* VT330 (not VT320) and VT420 */
4422		    reply.a_param[count++] = 1;
4423		}
4424		reply.a_final = 'R';
4425		break;
4426	    case 15:
4427		TRACE(("...request printer status\n"));
4428		if (sp->private_function
4429		    && screen->vtXX_level >= 2) {	/* VT220 */
4430		    reply.a_param[count++] = 13;	/* no printer detected */
4431		}
4432		break;
4433	    case 25:
4434		TRACE(("...request UDK status\n"));
4435		if (sp->private_function
4436		    && screen->vtXX_level >= 2) {	/* VT220 */
4437		    reply.a_param[count++] = 20;	/* UDK always unlocked */
4438		}
4439		break;
4440	    case 26:
4441		TRACE(("...request keyboard status\n"));
4442		if (sp->private_function
4443		    && screen->vtXX_level >= 2) {	/* VT220 */
4444		    reply.a_param[count++] = 27;
4445		    reply.a_param[count++] = 1;		/* North American */
4446		    if (screen->vtXX_level >= 3) {	/* VT320 */
4447			reply.a_param[count++] = 0;	/* ready */
4448		    }
4449		    if (screen->vtXX_level >= 4) {	/* VT420 */
4450			reply.a_param[count++] = 0;	/* LK201 */
4451		    }
4452		}
4453		break;
4454	    case 55:		/* according to the VT330/VT340 Text Programming Manual */
4455		TRACE(("...request locator status\n"));
4456		if (sp->private_function
4457		    && screen->vtXX_level >= 3) {	/* VT330 */
4458#if OPT_DEC_LOCATOR
4459		    reply.a_param[count++] = 50;	/* locator ready */
4460#else
4461		    reply.a_param[count++] = 53;	/* no locator */
4462#endif
4463		}
4464		break;
4465	    case 56:
4466		TRACE(("...request locator type\n"));
4467		if (sp->private_function
4468		    && screen->vtXX_level >= 3) {	/* VT330 */
4469		    reply.a_param[count++] = 57;
4470#if OPT_DEC_LOCATOR
4471		    reply.a_param[count++] = 1;		/* mouse */
4472#else
4473		    reply.a_param[count++] = 0;		/* unknown */
4474#endif
4475		}
4476		break;
4477	    case 62:
4478		TRACE(("...request DECMSR - macro space\n"));
4479		if (sp->private_function
4480		    && screen->vtXX_level >= 4) {	/* VT420 */
4481		    reply.a_pintro = 0;
4482		    reply.a_radix[count] = 16;	/* no data */
4483		    reply.a_param[count++] = 0;		/* no space for macros */
4484		    reply.a_inters = '*';
4485		    reply.a_final = L_CURL;
4486		}
4487		break;
4488	    case 63:
4489		TRACE(("...request DECCKSR - memory checksum\n"));
4490		/* DECCKSR - Memory checksum */
4491		if (sp->private_function
4492		    && screen->vtXX_level >= 4) {	/* VT420 */
4493		    init_reply(ANSI_DCS);
4494		    reply.a_param[count++] = (ParmType) GetParam(1);	/* PID */
4495		    reply.a_delim = "!~";	/* delimiter */
4496		    reply.a_radix[count] = 16;	/* use hex */
4497		    reply.a_param[count++] = 0;		/* no data */
4498		}
4499		break;
4500	    case 75:
4501		TRACE(("...request data integrity\n"));
4502		if (sp->private_function
4503		    && screen->vtXX_level >= 4) {	/* VT420 */
4504		    reply.a_param[count++] = 70;	/* no errors */
4505		}
4506		break;
4507	    case 85:
4508		TRACE(("...request multi-session configuration\n"));
4509		if (sp->private_function
4510		    && screen->vtXX_level >= 4) {	/* VT420 */
4511		    reply.a_param[count++] = 83;	/* not configured */
4512		}
4513		break;
4514	    default:
4515		break;
4516	    }
4517
4518	    if ((reply.a_nparam = (ParmType) count) != 0)
4519		unparseseq(xw, &reply);
4520
4521	    ResetState(sp);
4522	    sp->private_function = False;
4523	    break;
4524
4525	case CASE_MC:
4526	    TRACE(("CASE_MC - media control\n"));
4527	    xtermMediaControl(xw, GetParam(0), False);
4528	    ResetState(sp);
4529	    break;
4530
4531	case CASE_DEC_MC:
4532	    TRACE(("CASE_DEC_MC - DEC media control\n"));
4533	    xtermMediaControl(xw, GetParam(0), True);
4534	    ResetState(sp);
4535	    break;
4536
4537	case CASE_HP_MEM_LOCK:
4538	    /* FALLTHRU */
4539	case CASE_HP_MEM_UNLOCK:
4540	    TRACE(("%s\n", ((sp->parsestate[c] == CASE_HP_MEM_LOCK)
4541			    ? "CASE_HP_MEM_LOCK"
4542			    : "CASE_HP_MEM_UNLOCK")));
4543	    if (screen->scroll_amt)
4544		FlushScroll(xw);
4545	    if (sp->parsestate[c] == CASE_HP_MEM_LOCK)
4546		set_tb_margins(screen, screen->cur_row, screen->bot_marg);
4547	    else
4548		set_tb_margins(screen, 0, screen->bot_marg);
4549	    ResetState(sp);
4550	    break;
4551
4552	case CASE_DECSTBM:
4553	    TRACE(("CASE_DECSTBM - set scrolling region\n"));
4554	    {
4555		int top;
4556		int bot;
4557		top = one_if_default(0);
4558		if (nparam < 2 || (bot = GetParam(1)) == DEFAULT
4559		    || bot > MaxRows(screen)
4560		    || bot == 0)
4561		    bot = MaxRows(screen);
4562		if (bot > top) {
4563		    if (screen->scroll_amt)
4564			FlushScroll(xw);
4565		    set_tb_margins(screen, top - 1, bot - 1);
4566		    CursorSet(screen, 0, 0, xw->flags);
4567		}
4568		ResetState(sp);
4569	    }
4570	    break;
4571
4572	case CASE_DECREQTPARM:
4573	    TRACE(("CASE_DECREQTPARM\n"));
4574	    if (screen->terminal_id < 200) {	/* VT102 */
4575		value = zero_if_default(0);
4576		if (value == 0 || value == 1) {
4577		    init_reply(ANSI_CSI);
4578		    reply.a_nparam = 7;
4579		    reply.a_param[0] = (ParmType) (value + 2);
4580		    reply.a_param[1] = 1;	/* no parity */
4581		    reply.a_param[2] = 1;	/* eight bits */
4582		    reply.a_param[3] = 128;	/* transmit 38.4k baud */
4583		    reply.a_param[4] = 128;	/* receive 38.4k baud */
4584		    reply.a_param[5] = 1;	/* clock multiplier ? */
4585		    reply.a_param[6] = 0;	/* STP flags ? */
4586		    reply.a_final = 'x';
4587		    unparseseq(xw, &reply);
4588		}
4589	    }
4590	    ResetState(sp);
4591	    break;
4592
4593	case CASE_DECSET:
4594	    /* DECSET */
4595#if OPT_VT52_MODE
4596	    if (screen->vtXX_level != 0)
4597#endif
4598		dpmodes(xw, bitset);
4599	    ResetState(sp);
4600#if OPT_TEK4014
4601	    if (TEK4014_ACTIVE(xw)) {
4602		TRACE(("Tek4014 is now active...\n"));
4603		if (sp->check_recur)
4604		    sp->check_recur--;
4605		return False;
4606	    }
4607#endif
4608	    break;
4609
4610	case CASE_DECRST:
4611	    /* DECRST */
4612	    dpmodes(xw, bitclr);
4613	    init_groundtable(screen, sp);
4614	    ResetState(sp);
4615	    break;
4616
4617	case CASE_DECALN:
4618	    TRACE(("CASE_DECALN - alignment test\n"));
4619	    if (screen->cursor_state)
4620		HideCursor(xw);
4621	    /*
4622	     * DEC STD 070 (see pages D-19 to D-20) does not mention left/right
4623	     * margins.  The section is dated March 1985, not updated for the
4624	     * VT420 (introduced in 1990).
4625	     */
4626	    UIntClr(xw->flags, ORIGIN);
4627	    screen->do_wrap = False;
4628	    resetRendition(xw);
4629	    resetMargins(xw);
4630	    xterm_ResetDouble(xw);
4631	    CursorSet(screen, 0, 0, xw->flags);
4632	    xtermParseRect(xw, 0, NULL, &myRect);
4633	    ScrnFillRectangle(xw, &myRect, 'E', 0, False);
4634	    ResetState(sp);
4635	    break;
4636
4637	case CASE_GSETS5:
4638	    if (screen->vtXX_level >= 5) {
4639		TRACE_GSETS("5");
4640		xtermDecodeSCS(xw, sp->scstype, 5, 0, (int) c);
4641	    }
4642	    ResetState(sp);
4643	    break;
4644
4645	case CASE_GSETS3:
4646	    if (screen->vtXX_level >= 3) {
4647		TRACE_GSETS("3");
4648		xtermDecodeSCS(xw, sp->scstype, 3, 0, (int) c);
4649	    }
4650	    ResetState(sp);
4651	    break;
4652
4653	case CASE_GSETS:
4654	    if (strchr("012AB", AsciiOf(c)) != NULL) {
4655		TRACE_GSETS("");
4656		xtermDecodeSCS(xw, sp->scstype, 1, 0, (int) c);
4657	    } else if (screen->vtXX_level >= 2) {
4658		TRACE_GSETS("");
4659		xtermDecodeSCS(xw, sp->scstype, 2, 0, (int) c);
4660	    }
4661	    ResetState(sp);
4662	    break;
4663
4664	case CASE_ANSI_SC:
4665	    if (IsLeftRightMode(xw)) {
4666		int left;
4667		int right;
4668
4669		TRACE(("CASE_DECSLRM - set left and right margin\n"));
4670		left = one_if_default(0);
4671		if (nparam < 2 || (right = GetParam(1)) == DEFAULT
4672		    || right > MaxCols(screen)
4673		    || right == 0)
4674		    right = MaxCols(screen);
4675		if (right > left) {
4676		    set_lr_margins(screen, left - 1, right - 1);
4677		    CursorSet(screen, 0, 0, xw->flags);
4678		}
4679	    } else if (only_default()) {
4680		TRACE(("CASE_ANSI_SC - save cursor\n"));
4681		CursorSave(xw);
4682	    }
4683	    ResetState(sp);
4684	    break;
4685
4686	case CASE_DECSC:
4687	    TRACE(("CASE_DECSC - save cursor\n"));
4688	    CursorSave(xw);
4689	    ResetState(sp);
4690	    break;
4691
4692	case CASE_ANSI_RC:
4693	    if (!only_default())
4694		break;
4695	    /* FALLTHRU */
4696	case CASE_DECRC:
4697	    TRACE(("CASE_%sRC - restore cursor\n",
4698		   (sp->nextstate == CASE_DECRC) ? "DEC" : "ANSI_"));
4699	    CursorRestore(xw);
4700	    if_OPT_ISO_COLORS(screen, {
4701		setExtendedFG(xw);
4702	    });
4703	    ResetState(sp);
4704	    break;
4705
4706	case CASE_DECKPAM:
4707	    TRACE(("CASE_DECKPAM\n"));
4708	    xw->keyboard.flags |= MODE_DECKPAM;
4709	    update_appkeypad();
4710	    ResetState(sp);
4711	    break;
4712
4713	case CASE_DECKPNM:
4714	    TRACE(("CASE_DECKPNM\n"));
4715	    UIntClr(xw->keyboard.flags, MODE_DECKPAM);
4716	    update_appkeypad();
4717	    ResetState(sp);
4718	    break;
4719
4720	case CASE_CSI_QUOTE_STATE:
4721	    sp->parsestate = csi_quo_table;
4722	    break;
4723
4724#if OPT_BLINK_CURS
4725	case CASE_CSI_SPACE_STATE:
4726	    sp->parsestate = csi_sp_table;
4727	    break;
4728
4729	case CASE_DECSCUSR:
4730	    TRACE(("CASE_DECSCUSR\n"));
4731	    {
4732		Boolean change;
4733		int blinks = screen->cursor_blink_esc;
4734		XtCursorShape shapes = screen->cursor_shape;
4735
4736		HideCursor(xw);
4737
4738		switch (GetParam(0)) {
4739		case DEFAULT:
4740		    /* FALLTHRU */
4741		case DEFAULT_STYLE:
4742		    /* FALLTHRU */
4743		case BLINK_BLOCK:
4744		    blinks = True;
4745		    screen->cursor_shape = CURSOR_BLOCK;
4746		    break;
4747		case STEADY_BLOCK:
4748		    blinks = False;
4749		    screen->cursor_shape = CURSOR_BLOCK;
4750		    break;
4751		case BLINK_UNDERLINE:
4752		    blinks = True;
4753		    screen->cursor_shape = CURSOR_UNDERLINE;
4754		    break;
4755		case STEADY_UNDERLINE:
4756		    blinks = False;
4757		    screen->cursor_shape = CURSOR_UNDERLINE;
4758		    break;
4759		case BLINK_BAR:
4760		    blinks = True;
4761		    screen->cursor_shape = CURSOR_BAR;
4762		    break;
4763		case STEADY_BAR:
4764		    blinks = False;
4765		    screen->cursor_shape = CURSOR_BAR;
4766		    break;
4767		}
4768		change = (blinks != screen->cursor_blink_esc ||
4769			  shapes != screen->cursor_shape);
4770		TRACE(("cursor_shape:%d blinks:%d%s\n",
4771		       screen->cursor_shape, blinks,
4772		       change ? " (changed)" : ""));
4773		if (change) {
4774		    xtermSetCursorBox(screen);
4775		    if (SettableCursorBlink(screen)) {
4776			screen->cursor_blink_esc = blinks;
4777			UpdateCursorBlink(xw);
4778		    }
4779		}
4780	    }
4781	    ResetState(sp);
4782	    break;
4783#endif
4784
4785#if OPT_SCROLL_LOCK
4786	case CASE_DECLL:
4787	    TRACE(("CASE_DECLL\n"));
4788	    if (nparam > 0) {
4789		for (count = 0; count < nparam; ++count) {
4790		    int op = zero_if_default(count);
4791		    switch (op) {
4792		    case 0:
4793		    case DEFAULT:
4794			xtermClearLEDs(screen);
4795			break;
4796		    case 1:
4797			/* FALLTHRU */
4798		    case 2:
4799			/* FALLTHRU */
4800		    case 3:
4801			xtermShowLED(screen,
4802				     (Cardinal) op,
4803				     True);
4804			break;
4805		    case 21:
4806			/* FALLTHRU */
4807		    case 22:
4808			/* FALLTHRU */
4809		    case 23:
4810			xtermShowLED(screen,
4811				     (Cardinal) (op - 20),
4812				     True);
4813			break;
4814		    }
4815		}
4816	    } else {
4817		xtermClearLEDs(screen);
4818	    }
4819	    ResetState(sp);
4820	    break;
4821#endif
4822
4823#if OPT_VT52_MODE
4824	case CASE_VT52_FINISH:
4825	    TRACE(("CASE_VT52_FINISH terminal_id %d, vtXX_level %d\n",
4826		   screen->terminal_id,
4827		   screen->vtXX_level));
4828	    if (screen->terminal_id >= 100
4829		&& screen->vtXX_level == 0) {
4830		sp->groundtable =
4831		    sp->parsestate = ansi_table;
4832		/*
4833		 * On restore, the terminal does not recognize DECRQSS for
4834		 * DECSCL (per vttest).
4835		 */
4836		set_vtXX_level(screen, 1);
4837		xw->flags = screen->vt52_save_flags;
4838		screen->curgl = screen->vt52_save_curgl;
4839		screen->curgr = screen->vt52_save_curgr;
4840		screen->curss = screen->vt52_save_curss;
4841		restoreCharsets(screen, screen->vt52_save_gsets);
4842		update_vt52_vt100_settings();
4843	    }
4844	    break;
4845#endif
4846
4847	case CASE_ANSI_LEVEL_1:
4848	    TRACE(("CASE_ANSI_LEVEL_1\n"));
4849	    set_ansi_conformance(screen, 1);
4850	    ResetState(sp);
4851	    break;
4852
4853	case CASE_ANSI_LEVEL_2:
4854	    TRACE(("CASE_ANSI_LEVEL_2\n"));
4855	    set_ansi_conformance(screen, 2);
4856	    ResetState(sp);
4857	    break;
4858
4859	case CASE_ANSI_LEVEL_3:
4860	    TRACE(("CASE_ANSI_LEVEL_3\n"));
4861	    set_ansi_conformance(screen, 3);
4862	    ResetState(sp);
4863	    break;
4864
4865	case CASE_DECSCL:
4866	    TRACE(("CASE_DECSCL(%d,%d)\n", GetParam(0), GetParam(1)));
4867	    /*
4868	     * This changes the emulation level, and is not recognized by
4869	     * VT100s.  However, a VT220 or above can be set to conformance
4870	     * level 1 to act like a VT100.
4871	     */
4872	    if (screen->terminal_id >= 200) {
4873		/*
4874		 * Disallow unrecognized parameters, as well as attempts to set
4875		 * the operating level higher than the given terminal-id.
4876		 */
4877		if (GetParam(0) >= 61
4878		    && GetParam(0) <= 60 + (screen->terminal_id / 100)) {
4879		    int new_vtXX_level = GetParam(0) - 60;
4880		    int case_value = zero_if_default(1);
4881		    /*
4882		     * Note:
4883		     *
4884		     * The VT300, VT420, VT520 manuals claim that DECSCL does a
4885		     * hard reset (RIS).
4886		     *
4887		     * Both the VT220 manual and DEC STD 070 (which documents
4888		     * levels 1-4 in detail) state that it is a soft reset.
4889		     *
4890		     * Perhaps both sets of manuals are right (unlikely).
4891		     * Kermit says it's soft.
4892		     */
4893		    ReallyReset(xw, False, False);
4894		    init_parser(xw, sp);
4895		    set_vtXX_level(screen, new_vtXX_level);
4896		    if (new_vtXX_level > 1) {
4897			switch (case_value) {
4898			case 1:
4899			    show_8bit_control(False);
4900			    break;
4901			case 0:
4902			case 2:
4903			    show_8bit_control(True);
4904			    break;
4905			}
4906		    }
4907		}
4908	    }
4909	    ResetState(sp);
4910	    break;
4911
4912	case CASE_DECSCA:
4913	    TRACE(("CASE_DECSCA\n"));
4914	    screen->protected_mode = DEC_PROTECT;
4915	    if (GetParam(0) <= 0 || GetParam(0) == 2) {
4916		UIntClr(xw->flags, PROTECTED);
4917		TRACE(("...clear PROTECTED\n"));
4918	    } else if (GetParam(0) == 1) {
4919		xw->flags |= PROTECTED;
4920		TRACE(("...set PROTECTED\n"));
4921	    }
4922	    ResetState(sp);
4923	    break;
4924
4925	case CASE_DECSED:
4926	    TRACE(("CASE_DECSED\n"));
4927	    do_erase_display(xw, zero_if_default(0), DEC_PROTECT);
4928	    ResetState(sp);
4929	    break;
4930
4931	case CASE_DECSEL:
4932	    TRACE(("CASE_DECSEL\n"));
4933	    do_erase_line(xw, zero_if_default(0), DEC_PROTECT);
4934	    ResetState(sp);
4935	    break;
4936
4937	case CASE_GRAPHICS_ATTRIBUTES:
4938#if OPT_GRAPHICS
4939	    TRACE(("CASE_GRAPHICS_ATTRIBUTES\n"));
4940	    {
4941		/* request: item, action, value */
4942		/* reply: item, status, value */
4943		if (nparam != 3) {
4944		    TRACE(("DATA_ERROR: malformed CASE_GRAPHICS_ATTRIBUTES request with %d parameters\n", nparam));
4945		} else {
4946		    int status = 3;	/* assume failure */
4947		    int result = 0;
4948		    int result2 = 0;
4949
4950		    TRACE(("CASE_GRAPHICS_ATTRIBUTES request: %d, %d, %d\n",
4951			   GetParam(0), GetParam(1), GetParam(2)));
4952		    switch (GetParam(0)) {
4953		    case 1:	/* color register count */
4954			switch (GetParam(1)) {
4955			case 1:	/* read */
4956			    status = 0;		/* success */
4957			    result = (int) get_color_register_count(screen);
4958			    break;
4959			case 2:	/* reset */
4960			    screen->numcolorregisters = 0;
4961			    status = 0;		/* success */
4962			    result = (int) get_color_register_count(screen);
4963			    break;
4964			case 3:	/* set */
4965			    if (GetParam(2) > 1 &&
4966				(unsigned) GetParam(2) <= MAX_COLOR_REGISTERS) {
4967				screen->numcolorregisters = GetParam(2);
4968				status = 0;	/* success */
4969				result = (int) get_color_register_count(screen);
4970			    }
4971			    break;
4972			case 4:	/* read maximum */
4973			    status = 0;		/* success */
4974			    result = MAX_COLOR_REGISTERS;
4975			    break;
4976			default:
4977			    TRACE(("DATA_ERROR: CASE_GRAPHICS_ATTRIBUTES color register count request with unknown action parameter: %d\n",
4978				   GetParam(1)));
4979			    status = 2;		/* error in Pa */
4980			    break;
4981			}
4982			if (status == 0 && !(optSixelGraphics(screen)
4983					     || optRegisGraphics(screen)))
4984			    status = 3;
4985			break;
4986# if OPT_SIXEL_GRAPHICS
4987		    case 2:	/* graphics geometry */
4988			switch (GetParam(1)) {
4989			case 1:	/* read */
4990			    TRACE(("Get sixel graphics geometry\n"));
4991			    status = 0;		/* success */
4992			    result = Min(Width(screen), (int) screen->graphics_max_wide);
4993			    result2 = Min(Height(screen), (int) screen->graphics_max_high);
4994			    break;
4995			case 2:	/* reset */
4996			    /* FALLTHRU */
4997			case 3:	/* set */
4998			    break;
4999			case 4:	/* read maximum */
5000			    status = 0;		/* success */
5001			    result = screen->graphics_max_wide;
5002			    result2 = screen->graphics_max_high;
5003			    break;
5004			default:
5005			    TRACE(("DATA_ERROR: CASE_GRAPHICS_ATTRIBUTES graphics geometry request with unknown action parameter: %d\n",
5006				   GetParam(1)));
5007			    status = 2;		/* error in Pa */
5008			    break;
5009			}
5010			if (status == 0 && !optSixelGraphics(screen))
5011			    status = 3;
5012			break;
5013#endif
5014# if OPT_REGIS_GRAPHICS
5015		    case 3:	/* ReGIS geometry */
5016			switch (GetParam(1)) {
5017			case 1:	/* read */
5018			    status = 0;		/* success */
5019			    result = screen->graphics_regis_def_wide;
5020			    result2 = screen->graphics_regis_def_high;
5021			    break;
5022			case 2:	/* reset */
5023			    /* FALLTHRU */
5024			case 3:	/* set */
5025			    /* FALLTHRU */
5026			case 4:	/* read maximum */
5027			    /* not implemented */
5028			    break;
5029			default:
5030			    TRACE(("DATA_ERROR: CASE_GRAPHICS_ATTRIBUTES ReGIS geometry request with unknown action parameter: %d\n",
5031				   GetParam(1)));
5032			    status = 2;		/* error in Pa */
5033			    break;
5034			}
5035			if (status == 0 && !optRegisGraphics(screen))
5036			    status = 3;
5037			break;
5038#endif
5039		    default:
5040			TRACE(("DATA_ERROR: CASE_GRAPHICS_ATTRIBUTES request with unknown item parameter: %d\n",
5041			       GetParam(0)));
5042			status = 1;
5043			break;
5044		    }
5045
5046		    init_reply(ANSI_CSI);
5047		    reply.a_pintro = '?';
5048		    count = 0;
5049		    reply.a_param[count++] = (ParmType) GetParam(0);
5050		    reply.a_param[count++] = (ParmType) status;
5051		    if (status == 0) {
5052			reply.a_param[count++] = (ParmType) result;
5053			if (GetParam(0) >= 2)
5054			    reply.a_param[count++] = (ParmType) result2;
5055		    }
5056		    reply.a_nparam = (ParmType) count;
5057		    reply.a_final = 'S';
5058		    unparseseq(xw, &reply);
5059		}
5060	    }
5061#endif
5062	    ResetState(sp);
5063	    break;
5064
5065	case CASE_ST:
5066	    TRACE(("CASE_ST: End of String (%lu bytes) (mode=%d)\n",
5067		   (unsigned long) sp->string_used,
5068		   sp->string_mode));
5069	    ResetState(sp);
5070	    if (!sp->string_used && !sp->string_args)
5071		break;
5072	    if (sp->string_skip) {
5073		xtermWarning("Ignoring too-long string (%lu) for mode %#02x\n",
5074			     (unsigned long) sp->string_used,
5075			     sp->string_mode);
5076		sp->string_skip = False;
5077		sp->string_used = 0;
5078	    } else {
5079		if (sp->string_used)
5080		    sp->string_area[--(sp->string_used)] = '\0';
5081		if (sp->check_recur <= 1) {
5082		    switch (sp->string_mode) {
5083		    case ANSI_APC:
5084			/* ignored */
5085			break;
5086		    case ANSI_DCS:
5087#if OPT_SIXEL_GRAPHICS
5088			if (sp->string_args == sa_SIXEL) {
5089			    parse_sixel_finished();
5090			    TRACE(("DONE parsed sixel data\n"));
5091			} else
5092#endif
5093			    do_dcs(xw, sp->string_area, sp->string_used);
5094			break;
5095		    case ANSI_OSC:
5096			do_osc(xw, sp->string_area, sp->string_used, ANSI_ST);
5097			break;
5098		    case ANSI_PM:
5099			/* ignored */
5100			break;
5101		    case ANSI_SOS:
5102			/* ignored */
5103			break;
5104		    default:
5105			TRACE(("unknown mode\n"));
5106			break;
5107		    }
5108		}
5109	    }
5110	    break;
5111
5112	case CASE_SOS:
5113	    TRACE(("CASE_SOS: Start of String\n"));
5114	    if (ParseSOS(screen)) {
5115		BeginString(ANSI_SOS);
5116	    } else {
5117		illegal_parse(xw, c, sp);
5118	    }
5119	    break;
5120
5121	case CASE_PM:
5122	    TRACE(("CASE_PM: Privacy Message\n"));
5123	    if (ParseSOS(screen)) {
5124		BeginString(ANSI_PM);
5125	    } else {
5126		illegal_parse(xw, c, sp);
5127	    }
5128	    break;
5129
5130	case CASE_DCS:
5131	    TRACE(("CASE_DCS: Device Control String\n"));
5132	    BeginString2(ANSI_DCS);
5133	    break;
5134
5135	case CASE_APC:
5136	    TRACE(("CASE_APC: Application Program Command\n"));
5137	    if (ParseSOS(screen)) {
5138		BeginString(ANSI_APC);
5139	    } else {
5140		illegal_parse(xw, c, sp);
5141	    }
5142	    break;
5143
5144	case CASE_SPA:
5145	    TRACE(("CASE_SPA - start protected area\n"));
5146	    screen->protected_mode = ISO_PROTECT;
5147	    xw->flags |= PROTECTED;
5148	    ResetState(sp);
5149	    break;
5150
5151	case CASE_EPA:
5152	    TRACE(("CASE_EPA - end protected area\n"));
5153	    UIntClr(xw->flags, PROTECTED);
5154	    ResetState(sp);
5155	    break;
5156
5157	case CASE_SU:
5158	    TRACE(("CASE_SU - scroll up\n"));
5159	    xtermScroll(xw, one_if_default(0));
5160	    ResetState(sp);
5161	    break;
5162
5163	case CASE_SL:		/* ISO 6429, non-DEC */
5164	    TRACE(("CASE_SL - scroll left\n"));
5165	    xtermScrollLR(xw, one_if_default(0), True);
5166	    ResetState(sp);
5167	    break;
5168
5169	case CASE_SR:		/* ISO 6429, non-DEC */
5170	    TRACE(("CASE_SR - scroll right\n"));
5171	    xtermScrollLR(xw, one_if_default(0), False);
5172	    ResetState(sp);
5173	    break;
5174
5175	case CASE_DECDC:
5176	    TRACE(("CASE_DC - delete column\n"));
5177	    if (screen->vtXX_level >= 4) {
5178		xtermColScroll(xw, one_if_default(0), True, screen->cur_col);
5179	    }
5180	    ResetState(sp);
5181	    break;
5182
5183	case CASE_DECIC:
5184	    TRACE(("CASE_IC - insert column\n"));
5185	    if (screen->vtXX_level >= 4) {
5186		xtermColScroll(xw, one_if_default(0), False, screen->cur_col);
5187	    }
5188	    ResetState(sp);
5189	    break;
5190
5191	case CASE_DECBI:
5192	    TRACE(("CASE_BI - back index\n"));
5193	    if (screen->vtXX_level >= 4) {
5194		xtermColIndex(xw, True);
5195	    }
5196	    ResetState(sp);
5197	    break;
5198
5199	case CASE_DECFI:
5200	    TRACE(("CASE_FI - forward index\n"));
5201	    if (screen->vtXX_level >= 4) {
5202		xtermColIndex(xw, False);
5203	    }
5204	    ResetState(sp);
5205	    break;
5206
5207	case CASE_IND:
5208	    TRACE(("CASE_IND - index\n"));
5209	    xtermIndex(xw, 1);
5210	    do_xevents(xw);
5211	    ResetState(sp);
5212	    break;
5213
5214	case CASE_CPL:
5215	    TRACE(("CASE_CPL - cursor prev line\n"));
5216	    CursorPrevLine(xw, one_if_default(0));
5217	    ResetState(sp);
5218	    break;
5219
5220	case CASE_CNL:
5221	    TRACE(("CASE_CNL - cursor next line\n"));
5222	    CursorNextLine(xw, one_if_default(0));
5223	    ResetState(sp);
5224	    break;
5225
5226	case CASE_NEL:
5227	    TRACE(("CASE_NEL\n"));
5228	    xtermIndex(xw, 1);
5229	    CarriageReturn(xw);
5230	    ResetState(sp);
5231	    break;
5232
5233	case CASE_HTS:
5234	    TRACE(("CASE_HTS - horizontal tab set\n"));
5235	    TabSet(xw->tabs, screen->cur_col);
5236	    ResetState(sp);
5237	    break;
5238
5239	case CASE_REPORT_VERSION:
5240	    TRACE(("CASE_REPORT_VERSION - report terminal version\n"));
5241	    if (GetParam(0) <= 0) {
5242		unparseputc1(xw, ANSI_DCS);
5243		unparseputc(xw, '>');
5244		unparseputc(xw, '|');
5245		unparseputs(xw, xtermVersion());
5246		unparseputc1(xw, ANSI_ST);
5247		unparse_end(xw);
5248	    }
5249	    ResetState(sp);
5250	    break;
5251
5252	case CASE_RI:
5253	    TRACE(("CASE_RI - reverse index\n"));
5254	    RevIndex(xw, 1);
5255	    ResetState(sp);
5256	    break;
5257
5258	case CASE_SS2:
5259	    TRACE(("CASE_SS2\n"));
5260	    if (screen->vtXX_level > 1)
5261		screen->curss = 2;
5262	    ResetState(sp);
5263	    break;
5264
5265	case CASE_SS3:
5266	    TRACE(("CASE_SS3\n"));
5267	    if (screen->vtXX_level > 1)
5268		screen->curss = 3;
5269	    ResetState(sp);
5270	    break;
5271
5272	case CASE_CSI_STATE:
5273	    /* enter csi state */
5274	    InitParams();
5275	    SetParam(nparam++, DEFAULT);
5276	    sp->parsestate = csi_table;
5277	    break;
5278
5279	case CASE_ESC_SP_STATE:
5280	    /* esc space */
5281	    sp->parsestate = esc_sp_table;
5282	    break;
5283
5284	case CASE_CSI_EX_STATE:
5285	    /* csi exclamation */
5286	    sp->parsestate = csi_ex_table;
5287	    break;
5288
5289	case CASE_CSI_TICK_STATE:
5290	    /* csi tick (') */
5291	    sp->parsestate = csi_tick_table;
5292	    break;
5293
5294#if OPT_DEC_LOCATOR
5295	case CASE_DECEFR:
5296	    TRACE(("CASE_DECEFR - Enable Filter Rectangle\n"));
5297	    if (okSendMousePos(xw) == DEC_LOCATOR) {
5298		MotionOff(screen, xw);
5299		if ((screen->loc_filter_top = GetParam(0)) < 1)
5300		    screen->loc_filter_top = LOC_FILTER_POS;
5301		if (nparam < 2
5302		    || (screen->loc_filter_left = GetParam(1)) < 1)
5303		    screen->loc_filter_left = LOC_FILTER_POS;
5304		if (nparam < 3
5305		    || (screen->loc_filter_bottom = GetParam(2)) < 1)
5306		    screen->loc_filter_bottom = LOC_FILTER_POS;
5307		if (nparam < 4
5308		    || (screen->loc_filter_right = GetParam(3)) < 1)
5309		    screen->loc_filter_right = LOC_FILTER_POS;
5310		InitLocatorFilter(xw);
5311	    }
5312	    ResetState(sp);
5313	    break;
5314
5315	case CASE_DECELR:
5316	    MotionOff(screen, xw);
5317	    if (GetParam(0) <= 0 || GetParam(0) > 2) {
5318		screen->send_mouse_pos = MOUSE_OFF;
5319		TRACE(("DECELR - Disable Locator Reports\n"));
5320	    } else {
5321		TRACE(("DECELR - Enable Locator Reports\n"));
5322		screen->send_mouse_pos = DEC_LOCATOR;
5323		xtermShowPointer(xw, True);
5324		if (GetParam(0) == 2) {
5325		    screen->locator_reset = True;
5326		} else {
5327		    screen->locator_reset = False;
5328		}
5329		if (nparam < 2 || GetParam(1) != 1) {
5330		    screen->locator_pixels = False;
5331		} else {
5332		    screen->locator_pixels = True;
5333		}
5334		screen->loc_filter = False;
5335	    }
5336	    ResetState(sp);
5337	    break;
5338
5339	case CASE_DECSLE:
5340	    TRACE(("DECSLE - Select Locator Events\n"));
5341	    for (count = 0; count < nparam; ++count) {
5342		switch (zero_if_default(count)) {
5343		case 0:
5344		    MotionOff(screen, xw);
5345		    screen->loc_filter = False;
5346		    screen->locator_events = 0;
5347		    break;
5348		case 1:
5349		    screen->locator_events |= LOC_BTNS_DN;
5350		    break;
5351		case 2:
5352		    UIntClr(screen->locator_events, LOC_BTNS_DN);
5353		    break;
5354		case 3:
5355		    screen->locator_events |= LOC_BTNS_UP;
5356		    break;
5357		case 4:
5358		    UIntClr(screen->locator_events, LOC_BTNS_UP);
5359		    break;
5360		}
5361	    }
5362	    ResetState(sp);
5363	    break;
5364
5365	case CASE_DECRQLP:
5366	    TRACE(("DECRQLP - Request Locator Position\n"));
5367	    if (GetParam(0) < 2) {
5368		/* Issue DECLRP Locator Position Report */
5369		GetLocatorPosition(xw);
5370	    }
5371	    ResetState(sp);
5372	    break;
5373#endif /* OPT_DEC_LOCATOR */
5374
5375	case CASE_CSI_AMP_STATE:
5376	    TRACE(("CASE_CSI_AMP_STATE\n"));
5377	    /* csi ampersand (&) */
5378	    if (screen->vtXX_level >= 3)
5379		sp->parsestate = csi_amp_table;
5380	    else
5381		sp->parsestate = eigtable;
5382	    break;
5383
5384#if OPT_DEC_RECTOPS
5385	case CASE_CSI_DOLLAR_STATE:
5386	    TRACE(("CASE_CSI_DOLLAR_STATE\n"));
5387	    /* csi dollar ($) */
5388	    if (screen->vtXX_level >= 3)
5389		sp->parsestate = csi_dollar_table;
5390	    else
5391		sp->parsestate = eigtable;
5392	    break;
5393
5394	case CASE_CSI_STAR_STATE:
5395	    TRACE(("CASE_CSI_STAR_STATE\n"));
5396	    /* csi star (*) */
5397	    if (screen->vtXX_level >= 4)
5398		sp->parsestate = csi_star_table;
5399	    else
5400		sp->parsestate = eigtable;
5401	    break;
5402
5403	case CASE_DECRQCRA:
5404	    if (screen->vtXX_level >= 4 && AllowWindowOps(xw, ewGetChecksum)) {
5405		int checksum;
5406		int pid;
5407
5408		TRACE(("CASE_DECRQCRA - Request checksum of rectangular area\n"));
5409		xtermCheckRect(xw, ParamPair(0), &checksum);
5410		init_reply(ANSI_DCS);
5411		count = 0;
5412		checksum &= 0xffff;
5413		pid = GetParam(0);
5414		reply.a_param[count++] = (ParmType) pid;
5415		reply.a_delim = "!~";	/* delimiter */
5416		reply.a_radix[count] = 16;
5417		reply.a_param[count++] = (ParmType) checksum;
5418		reply.a_nparam = (ParmType) count;
5419		TRACE(("...checksum(%d) = %04X\n", pid, checksum));
5420		unparseseq(xw, &reply);
5421	    }
5422	    ResetState(sp);
5423	    break;
5424
5425	case CASE_DECCRA:
5426	    if (screen->vtXX_level >= 4) {
5427		TRACE(("CASE_DECCRA - Copy rectangular area\n"));
5428		xtermParseRect(xw, ParamPair(0), &myRect);
5429		ScrnCopyRectangle(xw, &myRect, ParamPair(5));
5430	    }
5431	    ResetState(sp);
5432	    break;
5433
5434	case CASE_DECERA:
5435	    if (screen->vtXX_level >= 4) {
5436		TRACE(("CASE_DECERA - Erase rectangular area\n"));
5437		xtermParseRect(xw, ParamPair(0), &myRect);
5438		ScrnFillRectangle(xw, &myRect, ' ', xw->flags, True);
5439	    }
5440	    ResetState(sp);
5441	    break;
5442
5443	case CASE_DECFRA:
5444	    if (screen->vtXX_level >= 4) {
5445		value = use_default_value(0, ' ');
5446
5447		TRACE(("CASE_DECFRA - Fill rectangular area\n"));
5448		/* DEC 070, page 5-170 says the fill-character is either
5449		 * ASCII or Latin1; xterm allows printable Unicode values.
5450		 */
5451		if (nparam > 0
5452		    && ((value >= 256 && CharWidth(screen, value) > 0)
5453			|| IsLatin1(value))) {
5454		    xtermParseRect(xw, ParamPair(1), &myRect);
5455		    ScrnFillRectangle(xw, &myRect, value, xw->flags, True);
5456		}
5457	    }
5458	    ResetState(sp);
5459	    break;
5460
5461	case CASE_DECSERA:
5462	    if (screen->vtXX_level >= 4) {
5463		TRACE(("CASE_DECSERA - Selective erase rectangular area\n"));
5464		xtermParseRect(xw, ParamPair(0), &myRect);
5465		ScrnWipeRectangle(xw, &myRect);
5466	    }
5467	    ResetState(sp);
5468	    break;
5469
5470	case CASE_DECSACE:
5471	    TRACE(("CASE_DECSACE - Select attribute change extent\n"));
5472	    screen->cur_decsace = zero_if_default(0);
5473	    ResetState(sp);
5474	    break;
5475
5476	case CASE_DECCARA:
5477	    if (screen->vtXX_level >= 4) {
5478		TRACE(("CASE_DECCARA - Change attributes in rectangular area\n"));
5479		xtermParseRect(xw, ParamPair(0), &myRect);
5480		ScrnMarkRectangle(xw, &myRect, False, ParamPair(4));
5481	    }
5482	    ResetState(sp);
5483	    break;
5484
5485	case CASE_DECRARA:
5486	    if (screen->vtXX_level >= 4) {
5487		TRACE(("CASE_DECRARA - Reverse attributes in rectangular area\n"));
5488		xtermParseRect(xw, ParamPair(0), &myRect);
5489		ScrnMarkRectangle(xw, &myRect, True, ParamPair(4));
5490	    }
5491	    ResetState(sp);
5492	    break;
5493
5494	case CASE_DECSCPP:
5495	    if (screen->vtXX_level >= 3) {
5496		TRACE(("CASE_DECSCPP\n"));
5497		/* default and 0 are "80", with "132" as the other legal choice */
5498		switch (zero_if_default(0)) {
5499		case 0:
5500		case 80:
5501		    value = 80;
5502		    break;
5503		case 132:
5504		    value = 132;
5505		    break;
5506		default:
5507		    value = -1;
5508		    break;
5509		}
5510		if (value > 0) {
5511		    if (screen->cur_col + 1 > value)
5512			CursorSet(screen, screen->cur_row, value - 1, xw->flags);
5513		    UIntClr(xw->flags, IN132COLUMNS);
5514		    if (value == 132)
5515			UIntSet(xw->flags, IN132COLUMNS);
5516		    RequestResize(xw, -1, value, True);
5517		}
5518	    }
5519	    ResetState(sp);
5520	    break;
5521
5522	case CASE_DECSNLS:
5523	    if (screen->vtXX_level >= 4 && AllowWindowOps(xw, ewSetWinLines)) {
5524		TRACE(("CASE_DECSNLS\n"));
5525		value = zero_if_default(0);
5526		if (value >= 1 && value <= 255) {
5527		    RequestResize(xw, value, -1, True);
5528		}
5529	    }
5530	    ResetState(sp);
5531	    break;
5532
5533	case CASE_DECRQDE:
5534	    if (screen->vtXX_level >= 3) {
5535		init_reply(ANSI_CSI);
5536		count = 0;
5537		reply.a_param[count++] = (ParmType) MaxRows(screen);	/* number of lines */
5538		reply.a_param[count++] = (ParmType) MaxCols(screen);	/* number of columns */
5539		reply.a_param[count++] = 1;	/* current page column */
5540		reply.a_param[count++] = 1;	/* current page line */
5541		reply.a_param[count++] = 1;	/* current page */
5542		reply.a_inters = '"';
5543		reply.a_final = 'w';
5544		reply.a_nparam = (ParmType) count;
5545		unparseseq(xw, &reply);
5546	    }
5547	    ResetState(sp);
5548	    break;
5549
5550	case CASE_DECRQPSR:
5551#define reply_char(n,c) do { reply.a_radix[(n)] = 1; reply.a_param[(n)++] = (ParmType)(c); } while (0)
5552#define reply_bit(n,c) ((n) ? (c) : 0)
5553	    if (screen->vtXX_level >= 3) {
5554		TRACE(("CASE_DECRQPSR\n"));
5555		switch (GetParam(0)) {
5556		case 1:
5557		    TRACE(("...DECCIR\n"));
5558		    init_reply(ANSI_DCS);
5559		    count = 0;
5560		    reply_char(count, '1');
5561		    reply_char(count, '$');
5562		    reply_char(count, 'u');
5563		    reply.a_param[count++] = (ParmType) (screen->cur_row + 1);
5564		    reply.a_param[count++] = (ParmType) (screen->cur_col + 1);
5565		    reply.a_param[count++] = (ParmType) thispage;
5566		    reply_char(count, ';');
5567		    reply_char(count, (0x40
5568				       | reply_bit(xw->flags & INVERSE, 8)
5569				       | reply_bit(xw->flags & BLINK, 4)
5570				       | reply_bit(xw->flags & UNDERLINE, 2)
5571				       | reply_bit(xw->flags & BOLD, 1)
5572			       ));
5573		    reply_char(count, ';');
5574		    reply_char(count, 0x40 |
5575			       reply_bit(screen->protected_mode &
5576					 DEC_PROTECT, 1)
5577			);
5578		    reply_char(count, ';');
5579		    reply_char(count, (0x40
5580				       | reply_bit(screen->do_wrap, 8)
5581				       | reply_bit((screen->curss == 3), 4)
5582				       | reply_bit((screen->curss == 2), 2)
5583				       | reply_bit(xw->flags & ORIGIN, 1)
5584			       ));
5585		    reply_char(count, ';');
5586		    reply.a_param[count++] = screen->curgl;
5587		    reply.a_param[count++] = screen->curgr;
5588		    reply_char(count, ';');
5589		    value = 0x40;
5590		    for (item = 0; item < NUM_GSETS; ++item) {
5591			value |= (is_96charset(screen->gsets[item]) << item);
5592		    }
5593		    reply_char(count, value);	/* encoded charset sizes */
5594		    reply_char(count, ';');
5595		    for (item = 0; item < NUM_GSETS; ++item) {
5596			int ps;
5597			char *temp = encode_scs(screen->gsets[item], &ps);
5598			while (*temp != '\0') {
5599			    reply_char(count, *temp++);
5600			}
5601		    }
5602		    reply.a_nparam = (ParmType) count;
5603		    unparseseq(xw, &reply);
5604		    break;
5605		case 2:
5606		    TRACE(("...DECTABSR\n"));
5607		    init_reply(ANSI_DCS);
5608		    reply.a_delim = "/";
5609		    count = 0;
5610		    reply_char(count, '2');
5611		    reply_char(count, '$');
5612		    reply_char(count, 'u');
5613		    for (item = 0; item < MAX_TABS; ++item) {
5614			if (count + 1 >= NPARAM)
5615			    break;
5616			if (item > screen->max_col)
5617			    break;
5618			if (TabIsSet(xw->tabs, item))
5619			    reply.a_param[count++] = (ParmType) (item + 1);
5620		    }
5621		    reply.a_nparam = (ParmType) count;
5622		    unparseseq(xw, &reply);
5623		    break;
5624		}
5625	    }
5626	    ResetState(sp);
5627	    break;
5628
5629	case CASE_DECRQUPSS:
5630	    TRACE(("CASE_DECRQUPSS\n"));
5631	    if (screen->vtXX_level >= 3) {
5632		int psize = 0;
5633		char *encoded = encode_scs(screen->gsets_upss, &psize);
5634		init_reply(ANSI_DCS);
5635		count = 0;
5636		reply_char(count, psize ? '1' : '0');
5637		reply_char(count, '!');
5638		reply_char(count, 'u');
5639		reply_char(count, *encoded++);
5640		if (*encoded)
5641		    reply_char(count, *encoded);
5642		reply.a_nparam = (ParmType) count;
5643		unparseseq(xw, &reply);
5644	    }
5645	    break;
5646
5647	case CASE_RQM:
5648	    TRACE(("CASE_RQM\n"));
5649	    do_ansi_rqm(xw, ParamPair(0));
5650	    ResetState(sp);
5651	    break;
5652
5653	case CASE_DECRQM:
5654	    TRACE(("CASE_DECRQM\n"));
5655	    do_dec_rqm(xw, ParamPair(0));
5656	    ResetState(sp);
5657	    break;
5658
5659	case CASE_CSI_DEC_DOLLAR_STATE:
5660	    TRACE(("CASE_CSI_DEC_DOLLAR_STATE\n"));
5661	    /* csi ? dollar ($) */
5662	    sp->parsestate = csi_dec_dollar_table;
5663	    break;
5664
5665	case CASE_DECST8C:
5666	    TRACE(("CASE_DECST8C\n"));
5667	    if (screen->vtXX_level >= 5
5668		&& (GetParam(0) == 5 || GetParam(0) <= 0)) {
5669		TabZonk(xw->tabs);
5670		for (count = 0; count < MAX_TABS; ++count) {
5671		    item = (count + 1) * 8;
5672		    if (item > screen->max_col)
5673			break;
5674		    TabSet(xw->tabs, item);
5675		}
5676	    }
5677	    ResetState(sp);
5678	    break;
5679#else
5680	case CASE_CSI_DOLLAR_STATE:
5681	    /* csi dollar ($) */
5682	    sp->parsestate = eigtable;
5683	    break;
5684
5685	case CASE_CSI_STAR_STATE:
5686	    /* csi dollar (*) */
5687	    sp->parsestate = eigtable;
5688	    break;
5689
5690	case CASE_CSI_DEC_DOLLAR_STATE:
5691	    /* csi ? dollar ($) */
5692	    sp->parsestate = eigtable;
5693	    break;
5694
5695	case CASE_DECST8C:
5696	    /* csi ? 5 W */
5697	    ResetState(sp);
5698	    break;
5699#endif /* OPT_DEC_RECTOPS */
5700
5701#if OPT_VT525_COLORS
5702	case CASE_CSI_COMMA_STATE:
5703	    TRACE(("CASE_CSI_COMMA_STATE\n"));
5704	    /* csi comma (,) */
5705	    if (screen->vtXX_level >= 5)
5706		sp->parsestate = csi_comma_table;
5707	    else
5708		sp->parsestate = eigtable;
5709	    break;
5710
5711	case CASE_DECAC:
5712	    TRACE(("CASE_DECAC\n"));
5713#if OPT_ISO_COLORS
5714	    if (screen->terminal_id >= 525) {
5715		int fg, bg;
5716
5717		switch (GetParam(0)) {
5718		case 1:
5719		    fg = GetParam(1);
5720		    bg = GetParam(2);
5721		    if (fg >= 0 && fg < 16 && bg >= 0 && bg < 16) {
5722			Boolean repaint = False;
5723
5724			if (AssignFgColor(xw,
5725					  GET_COLOR_RES(xw, screen->Acolors[fg])))
5726			    repaint = True;
5727			if (AssignBgColor(xw,
5728					  GET_COLOR_RES(xw, screen->Acolors[bg])))
5729			    repaint = True;
5730			if (repaint)
5731			    xtermRepaint(xw);
5732			screen->assigned_fg = fg;
5733			screen->assigned_bg = bg;
5734		    }
5735		    break;
5736		case 2:
5737		    /* window frames: not implemented */
5738		    break;
5739		}
5740	    }
5741#endif
5742	    ResetState(sp);
5743	    break;
5744
5745	case CASE_DECATC:
5746#if OPT_ISO_COLORS
5747	    TRACE(("CASE_DECATC\n"));
5748	    if (screen->terminal_id >= 525) {
5749		int ps = GetParam(0);
5750		int fg = GetParam(1);
5751		int bg = GetParam(2);
5752		if (ps >= 0 && ps < 16
5753		    && fg >= 0 && fg < 16
5754		    && bg >= 0 && bg < 16) {
5755		    screen->alt_colors[ps].fg = fg;
5756		    screen->alt_colors[ps].bg = bg;
5757		}
5758	    }
5759#endif
5760	    ResetState(sp);
5761	    break;
5762
5763	case CASE_DECTID:
5764	    TRACE(("CASE_DECTID\n"));
5765	    switch (GetParam(0)) {
5766	    case 0:
5767		screen->display_da1 = 100;
5768		break;
5769	    case 1:
5770		screen->display_da1 = 101;
5771		break;
5772	    case 2:
5773		screen->display_da1 = 102;
5774		break;
5775	    case 5:
5776		screen->display_da1 = 220;
5777		break;
5778	    case 7:
5779		screen->display_da1 = 320;
5780		break;
5781	    case 9:
5782		screen->display_da1 = 420;
5783		break;
5784	    case 10:
5785		screen->display_da1 = 520;
5786		break;
5787	    }
5788	    ResetState(sp);
5789	    break;
5790#else
5791	case CASE_CSI_COMMA_STATE:
5792	    sp->parsestate = eigtable;
5793	    break;
5794#endif
5795
5796	case CASE_DECSASD:
5797#if OPT_STATUS_LINE
5798	    if (screen->vtXX_level >= 2) {
5799		handle_DECSASD(xw, zero_if_default(0));
5800	    }
5801#endif
5802	    ResetState(sp);
5803	    break;
5804
5805	case CASE_DECSSDT:
5806#if OPT_STATUS_LINE
5807	    if (screen->vtXX_level >= 2) {
5808		handle_DECSSDT(xw, zero_if_default(0));
5809	    }
5810#endif
5811	    ResetState(sp);
5812	    break;
5813
5814#if OPT_XTERM_SGR		/* most are related, all use csi_hash_table[] */
5815	case CASE_CSI_HASH_STATE:
5816	    TRACE(("CASE_CSI_HASH_STATE\n"));
5817	    /* csi hash (#) */
5818	    sp->parsestate = csi_hash_table;
5819	    break;
5820
5821	case CASE_XTERM_CHECKSUM:
5822#if OPT_DEC_RECTOPS
5823	    if (screen->vtXX_level >= 4 && AllowWindowOps(xw, ewSetChecksum)) {
5824		TRACE(("CASE_XTERM_CHECKSUM\n"));
5825		screen->checksum_ext = zero_if_default(0);
5826	    }
5827#endif
5828	    ResetState(sp);
5829	    break;
5830
5831	case CASE_XTERM_PUSH_SGR:
5832	    TRACE(("CASE_XTERM_PUSH_SGR\n"));
5833	    value = 0;
5834	    if (nparam == 0 || (nparam == 1 && GetParam(0) == DEFAULT)) {
5835		value = DEFAULT;
5836	    } else if (nparam > 0) {
5837		for (count = 0; count < nparam; ++count) {
5838		    item = zero_if_default(count);
5839		    /* deprecated - for compatibility */
5840#if OPT_ISO_COLORS
5841		    if (item == psFG_COLOR_obs) {
5842			item = psFG_COLOR;
5843		    } else if (item == psBG_COLOR_obs) {
5844			item = psBG_COLOR;
5845		    }
5846#endif
5847		    if (item > 0 && item < MAX_PUSH_SGR) {
5848			value |= (1 << (item - 1));
5849		    }
5850		}
5851	    }
5852	    xtermPushSGR(xw, value);
5853	    ResetState(sp);
5854	    break;
5855
5856	case CASE_XTERM_REPORT_SGR:
5857	    TRACE(("CASE_XTERM_REPORT_SGR\n"));
5858	    xtermParseRect(xw, ParamPair(0), &myRect);
5859	    xtermReportSGR(xw, &myRect);
5860	    ResetState(sp);
5861	    break;
5862
5863	case CASE_XTERM_POP_SGR:
5864	    TRACE(("CASE_XTERM_POP_SGR\n"));
5865	    xtermPopSGR(xw);
5866	    ResetState(sp);
5867	    break;
5868
5869	case CASE_XTERM_PUSH_COLORS:
5870	    TRACE(("CASE_XTERM_PUSH_COLORS\n"));
5871	    if (nparam == 0) {
5872		xtermPushColors(xw, DEFAULT);
5873	    } else {
5874		for (count = 0; count < nparam; ++count) {
5875		    xtermPushColors(xw, GetParam(count));
5876		}
5877	    }
5878	    ResetState(sp);
5879	    break;
5880
5881	case CASE_XTERM_POP_COLORS:
5882	    TRACE(("CASE_XTERM_POP_COLORS\n"));
5883	    if (nparam == 0) {
5884		xtermPopColors(xw, DEFAULT);
5885	    } else {
5886		for (count = 0; count < nparam; ++count) {
5887		    xtermPopColors(xw, GetParam(count));
5888		}
5889	    }
5890	    ResetState(sp);
5891	    break;
5892
5893	case CASE_XTERM_REPORT_COLORS:
5894	    TRACE(("CASE_XTERM_REPORT_COLORS\n"));
5895	    xtermReportColors(xw);
5896	    ResetState(sp);
5897	    break;
5898
5899	case CASE_XTERM_TITLE_STACK:
5900	    xtermReportTitleStack(xw);
5901	    ResetState(sp);
5902	    break;
5903#endif
5904
5905	case CASE_S7C1T:
5906	    TRACE(("CASE_S7C1T\n"));
5907	    if (screen->vtXX_level >= 2) {
5908		show_8bit_control(False);
5909		ResetState(sp);
5910	    }
5911	    break;
5912
5913	case CASE_S8C1T:
5914	    TRACE(("CASE_S8C1T\n"));
5915	    if (screen->vtXX_level >= 2) {
5916		show_8bit_control(True);
5917		ResetState(sp);
5918	    }
5919	    break;
5920
5921	case CASE_OSC:
5922	    TRACE(("CASE_OSC: Operating System Command\n"));
5923	    BeginString(ANSI_OSC);
5924	    break;
5925
5926	case CASE_RIS:
5927	    TRACE(("CASE_RIS\n"));
5928	    VTReset(xw, True, True);
5929	    /* NOTREACHED */
5930
5931	case CASE_DECSTR:
5932	    TRACE(("CASE_DECSTR\n"));
5933	    VTReset(xw, False, False);
5934	    /* NOTREACHED */
5935
5936	case CASE_REP:
5937	    TRACE(("CASE_REP\n"));
5938	    if (CharWidth(screen, sp->lastchar) > 0) {
5939		IChar repeated[2];
5940		count = one_if_default(0);
5941		repeated[0] = (IChar) sp->lastchar;
5942		while (count-- > 0) {
5943		    dotext(xw,
5944			   screen->gsets[(int) (screen->curgl)],
5945			   repeated, 1);
5946		}
5947	    }
5948	    ResetState(sp);
5949	    break;
5950
5951	case CASE_LS2:
5952	    TRACE(("CASE_LS2\n"));
5953	    if (screen->ansi_level > 2)
5954		screen->curgl = 2;
5955	    ResetState(sp);
5956	    break;
5957
5958	case CASE_LS3:
5959	    TRACE(("CASE_LS3\n"));
5960	    if (screen->ansi_level > 2)
5961		screen->curgl = 3;
5962	    ResetState(sp);
5963	    break;
5964
5965	case CASE_LS3R:
5966	    TRACE(("CASE_LS3R\n"));
5967	    if (screen->ansi_level > 2)
5968		screen->curgr = 3;
5969	    ResetState(sp);
5970	    break;
5971
5972	case CASE_LS2R:
5973	    TRACE(("CASE_LS2R\n"));
5974	    if (screen->ansi_level > 2)
5975		screen->curgr = 2;
5976	    ResetState(sp);
5977	    break;
5978
5979	case CASE_LS1R:
5980	    TRACE(("CASE_LS1R\n"));
5981	    if (screen->ansi_level > 2)
5982		screen->curgr = 1;
5983	    ResetState(sp);
5984	    break;
5985
5986	case CASE_XTERM_SAVE:
5987	    savemodes(xw);
5988	    ResetState(sp);
5989	    break;
5990
5991	case CASE_XTERM_RESTORE:
5992	    restoremodes(xw);
5993	    ResetState(sp);
5994	    break;
5995
5996	case CASE_XTERM_WINOPS:
5997	    TRACE(("CASE_XTERM_WINOPS\n"));
5998	    window_ops(xw);
5999	    ResetState(sp);
6000	    break;
6001#if OPT_WIDE_CHARS
6002	case CASE_ESC_PERCENT:
6003	    TRACE(("CASE_ESC_PERCENT\n"));
6004	    sp->parsestate = esc_pct_table;
6005	    break;
6006
6007	case CASE_UTF8:
6008	    /* If we did not set UTF-8 mode from resource or the
6009	     * command-line, allow it to be enabled/disabled by
6010	     * control sequence.
6011	     */
6012	    TRACE(("CASE_UTF8 wide:%d, utf8:%d, req:%s\n",
6013		   screen->wide_chars,
6014		   screen->utf8_mode,
6015		   BtoS(AsciiOf(c) == 'G')));
6016	    if ((!screen->wide_chars) && (AsciiOf(c) == 'G')) {
6017		WriteNow();
6018		ChangeToWide(xw);
6019	    }
6020	    if (screen->wide_chars
6021		&& !screen->utf8_always) {
6022		switchPtyData(screen, AsciiOf(c) == 'G');
6023		TRACE(("UTF8 mode %s\n",
6024		       BtoS(screen->utf8_mode)));
6025	    } else {
6026		TRACE(("UTF8 mode NOT turned %s (%s)\n",
6027		       BtoS(AsciiOf(c) == 'G'),
6028		       (screen->utf8_mode == uAlways)
6029		       ? "UTF-8 mode set from command-line"
6030		       : "wideChars resource was not set"));
6031	    }
6032	    ResetState(sp);
6033	    break;
6034
6035	case CASE_SCS_DQUOTE:
6036	    TRACE(("CASE_SCS_DQUOTE\n"));
6037	    sp->parsestate = scs_2qt_table;
6038	    break;
6039
6040	case CASE_GSETS_DQUOTE:
6041	    if (screen->vtXX_level >= 5) {
6042		TRACE_GSETS("_DQUOTE");
6043		xtermDecodeSCS(xw, sp->scstype, 5, '"', (int) c);
6044	    }
6045	    ResetState(sp);
6046	    break;
6047
6048	case CASE_SCS_AMPRSND:
6049	    TRACE(("CASE_SCS_AMPRSND\n"));
6050	    sp->parsestate = scs_amp_table;
6051	    break;
6052
6053	case CASE_GSETS_AMPRSND:
6054	    if (screen->vtXX_level >= 5) {
6055		TRACE_GSETS("_AMPRSND");
6056		xtermDecodeSCS(xw, sp->scstype, 5, '&', (int) c);
6057	    }
6058	    ResetState(sp);
6059	    break;
6060
6061	case CASE_SCS_PERCENT:
6062	    TRACE(("CASE_SCS_PERCENT\n"));
6063	    sp->parsestate = scs_pct_table;
6064	    break;
6065
6066	case CASE_GSETS_PERCENT:
6067	    if (screen->vtXX_level >= 3) {
6068		TRACE_GSETS("_PERCENT");
6069		switch (AsciiOf(c)) {
6070		case '0':	/* DEC Turkish */
6071		case '2':	/* Turkish */
6072		case '=':	/* Hebrew */
6073		    value = 5;
6074		    break;
6075		case '5':	/* DEC Supplemental Graphics */
6076		case '6':	/* Portuguese */
6077		default:
6078		    value = 3;
6079		    break;
6080		}
6081		xtermDecodeSCS(xw, sp->scstype, value, '%', (int) c);
6082	    }
6083	    ResetState(sp);
6084	    break;
6085#endif
6086	case CASE_XTERM_SHIFT_ESCAPE:
6087	    TRACE(("CASE_XTERM_SHIFT_ESCAPE\n"));
6088	    value = ((nparam == 0)
6089		     ? 0
6090		     : one_if_default(0));
6091	    if (value >= 0 && value <= 1)
6092		xw->keyboard.shift_escape = value;
6093	    ResetState(sp);
6094	    break;
6095
6096#if OPT_MOD_FKEYS
6097	case CASE_SET_MOD_FKEYS:
6098	    TRACE(("CASE_SET_MOD_FKEYS\n"));
6099	    if (nparam >= 1) {
6100		set_mod_fkeys(xw,
6101			      GetParam(0),
6102			      ((nparam > 1)
6103			       ? GetParam(1)
6104			       : DEFAULT),
6105			      True);
6106	    } else {
6107		for (value = 1; value <= 5; ++value)
6108		    set_mod_fkeys(xw, value, DEFAULT, True);
6109	    }
6110	    ResetState(sp);
6111	    break;
6112
6113	case CASE_SET_MOD_FKEYS0:
6114	    TRACE(("CASE_SET_MOD_FKEYS0\n"));
6115	    if (nparam >= 1 && GetParam(0) != DEFAULT) {
6116		set_mod_fkeys(xw, GetParam(0), -1, False);
6117	    } else {
6118		xw->keyboard.modify_now.function_keys = -1;
6119	    }
6120	    ResetState(sp);
6121	    break;
6122
6123	case CASE_XTERM_REPORT_MOD_FKEYS:
6124	    TRACE(("CASE_XTERM_REPORT_MOD_FKEYS\n"));
6125	    for (value = 0; value < nparam; ++value) {
6126		report_mod_fkeys(xw, GetParam(value));
6127	    }
6128	    ResetState(sp);
6129	    break;
6130#endif
6131	case CASE_HIDE_POINTER:
6132	    TRACE(("CASE_HIDE_POINTER\n"));
6133	    if (nparam >= 1 && GetParam(0) != DEFAULT) {
6134		screen->pointer_mode = GetParam(0);
6135	    } else {
6136		screen->pointer_mode = DEF_POINTER_MODE;
6137	    }
6138	    ResetState(sp);
6139	    break;
6140
6141	case CASE_XTERM_SM_TITLE:
6142	    TRACE(("CASE_XTERM_SM_TITLE\n"));
6143	    if (nparam >= 1) {
6144		for (count = 0; count < nparam; ++count) {
6145		    value = GetParam(count);
6146		    if (ValidTitleMode(value))
6147			screen->title_modes |= xBIT(value);
6148		}
6149	    } else {
6150		screen->title_modes = DEF_TITLE_MODES;
6151	    }
6152	    TRACE(("...title_modes %#x\n", screen->title_modes));
6153	    ResetState(sp);
6154	    break;
6155
6156	case CASE_XTERM_RM_TITLE:
6157	    TRACE(("CASE_XTERM_RM_TITLE\n"));
6158	    if (nparam >= 1) {
6159		for (count = 0; count < nparam; ++count) {
6160		    value = GetParam(count);
6161		    if (ValidTitleMode(value))
6162			screen->title_modes &= ~xBIT(value);
6163		}
6164	    } else {
6165		screen->title_modes = DEF_TITLE_MODES;
6166	    }
6167	    TRACE(("...title_modes %#x\n", screen->title_modes));
6168	    ResetState(sp);
6169	    break;
6170
6171	case CASE_CSI_IGNORE:
6172	    sp->parsestate = cigtable;
6173	    break;
6174
6175	case CASE_DECSWBV:
6176	    TRACE(("CASE_DECSWBV\n"));
6177	    switch (zero_if_default(0)) {
6178	    case 2:
6179		/* FALLTHRU */
6180	    case 3:
6181		/* FALLTHRU */
6182	    case 4:
6183		screen->warningVolume = bvLow;
6184		break;
6185	    case 5:
6186		/* FALLTHRU */
6187	    case 6:
6188		/* FALLTHRU */
6189	    case 7:
6190		/* FALLTHRU */
6191	    case 8:
6192		screen->warningVolume = bvHigh;
6193		break;
6194	    default:
6195		screen->warningVolume = bvOff;
6196		break;
6197	    }
6198	    TRACE(("...warningVolume %d\n", screen->warningVolume));
6199	    ResetState(sp);
6200	    break;
6201
6202	case CASE_DECSMBV:
6203	    TRACE(("CASE_DECSMBV\n"));
6204	    switch (zero_if_default(0)) {
6205	    case 2:
6206		/* FALLTHRU */
6207	    case 3:
6208		/* FALLTHRU */
6209	    case 4:
6210		screen->marginVolume = bvLow;
6211		break;
6212	    case 0:
6213		/* FALLTHRU */
6214	    case 5:
6215		/* FALLTHRU */
6216	    case 6:
6217		/* FALLTHRU */
6218	    case 7:
6219		/* FALLTHRU */
6220	    case 8:
6221		screen->marginVolume = bvHigh;
6222		break;
6223	    default:
6224		screen->marginVolume = bvOff;
6225		break;
6226	    }
6227	    TRACE(("...marginVolume %d\n", screen->marginVolume));
6228	    ResetState(sp);
6229	    break;
6230	}
6231	if (sp->parsestate == sp->groundtable)
6232	    sp->lastchar = thischar;
6233    } while (0);
6234
6235#if OPT_WIDE_CHARS
6236    screen->utf8_inparse = (Boolean) ((screen->utf8_mode != uFalse)
6237				      && (sp->parsestate != sos_table));
6238#endif
6239
6240    if (sp->check_recur)
6241	sp->check_recur--;
6242    return True;
6243}
6244
6245static void
6246VTparse(XtermWidget xw)
6247{
6248    Boolean keep_running;
6249
6250    /* We longjmp back to this point in VTReset() */
6251    (void) setjmp(vtjmpbuf);
6252    init_parser(xw, &myState);
6253
6254    do {
6255	keep_running = doparsing(xw, doinput(xw), &myState);
6256	if (myState.check_recur == 0 && myState.defer_used != 0) {
6257	    while (myState.defer_used) {
6258		Char *deferred = myState.defer_area;
6259		size_t len = myState.defer_used;
6260		size_t i;
6261		myState.defer_area = NULL;
6262		myState.defer_size = 0;
6263		myState.defer_used = 0;
6264		for (i = 0; i < len; i++) {
6265		    (void) doparsing(xw, deferred[i], &myState);
6266		}
6267		free(deferred);
6268	    }
6269	} else {
6270	    free(myState.defer_area);
6271	}
6272	myState.defer_area = NULL;
6273	myState.defer_size = 0;
6274	myState.defer_used = 0;
6275    } while (keep_running);
6276}
6277
6278static Char *v_buffer;		/* pointer to physical buffer */
6279static Char *v_bufstr = NULL;	/* beginning of area to write */
6280static Char *v_bufptr;		/* end of area to write */
6281static Char *v_bufend;		/* end of physical buffer */
6282
6283/* Write data to the pty as typed by the user, pasted with the mouse,
6284   or generated by us in response to a query ESC sequence. */
6285
6286void
6287v_write(int f, const Char *data, size_t len)
6288{
6289    TRACE2(("v_write(%d:%s)\n", len, visibleChars(data, len)));
6290    if (v_bufstr == NULL) {
6291	if (len > 0) {
6292	    v_buffer = (Char *) XtMalloc((Cardinal) len);
6293	    v_bufstr = v_buffer;
6294	    v_bufptr = v_buffer;
6295	    v_bufend = v_buffer + len;
6296	}
6297	if (v_bufstr == NULL) {
6298	    return;
6299	}
6300    }
6301    if_DEBUG({
6302	fprintf(stderr, "v_write called with %lu bytes (%lu left over)",
6303		(unsigned long) len,
6304		(unsigned long) (v_bufptr - v_bufstr));
6305	if (len > 1 && len < 10)
6306	    fprintf(stderr, " \"%.*s\"", (int) len, (const char *) data);
6307	fprintf(stderr, "\n");
6308    });
6309
6310    if (!FD_ISSET(f, &pty_mask)) {
6311	IGNORE_RC(write(f, (const char *) data, (size_t) len));
6312	return;
6313    }
6314
6315    /*
6316     * Append to the block we already have.
6317     * Always doing this simplifies the code, and
6318     * isn't too bad, either.  If this is a short
6319     * block, it isn't too expensive, and if this is
6320     * a long block, we won't be able to write it all
6321     * anyway.
6322     */
6323
6324    if (len > 0) {
6325#if OPT_DABBREV
6326	TScreenOf(term)->dabbrev_working = False;	/* break dabbrev sequence */
6327#endif
6328	if (v_bufend < v_bufptr + len) {	/* we've run out of room */
6329	    if (v_bufstr != v_buffer) {
6330		/* there is unused space, move everything down */
6331		/* possibly overlapping memmove here */
6332		if_DEBUG({
6333		    fprintf(stderr, "moving data down %ld\n",
6334			    (long) (v_bufstr - v_buffer));
6335		});
6336		memmove(v_buffer, v_bufstr, (size_t) (v_bufptr - v_bufstr));
6337		v_bufptr -= v_bufstr - v_buffer;
6338		v_bufstr = v_buffer;
6339	    }
6340	    if (v_bufend < v_bufptr + len) {
6341		/* still won't fit: get more space */
6342		/* Don't use XtRealloc because an error is not fatal. */
6343		size_t size = (size_t) (v_bufptr - v_buffer);
6344		v_buffer = TypeRealloc(Char, size + len, v_buffer);
6345		if (v_buffer) {
6346		    if_DEBUG({
6347			fprintf(stderr, "expanded buffer to %lu\n",
6348				(unsigned long) (size + len));
6349		    });
6350		    v_bufstr = v_buffer;
6351		    v_bufptr = v_buffer + size;
6352		    v_bufend = v_bufptr + len;
6353		} else {
6354		    /* no memory: ignore entire write request */
6355		    xtermWarning("cannot allocate buffer space\n");
6356		    v_buffer = v_bufstr;	/* restore clobbered pointer */
6357		}
6358	    }
6359	}
6360	if (v_bufend >= v_bufptr + len) {
6361	    /* new stuff will fit */
6362	    memmove(v_bufptr, data, (size_t) len);
6363	    v_bufptr += len;
6364	}
6365    }
6366
6367    /*
6368     * Write out as much of the buffer as we can.
6369     * Be careful not to overflow the pty's input silo.
6370     * We are conservative here and only write
6371     * a small amount at a time.
6372     *
6373     * If we can't push all the data into the pty yet, we expect write
6374     * to return a non-negative number less than the length requested
6375     * (if some data written) or -1 and set errno to EAGAIN,
6376     * EWOULDBLOCK, or EINTR (if no data written).
6377     *
6378     * (Not all systems do this, sigh, so the code is actually
6379     * a little more forgiving.)
6380     */
6381
6382#define MAX_PTY_WRITE 128	/* 1/2 POSIX minimum MAX_INPUT */
6383
6384    if (v_bufptr > v_bufstr) {
6385	int riten;
6386
6387	riten = (int) write(f, v_bufstr,
6388			    (size_t) ((v_bufptr - v_bufstr <= MAX_PTY_WRITE)
6389				      ? v_bufptr - v_bufstr
6390				      : MAX_PTY_WRITE));
6391	if (riten < 0) {
6392	    if_DEBUG({
6393		perror("write");
6394	    });
6395	    riten = 0;
6396	}
6397	if_DEBUG({
6398	    fprintf(stderr, "write called with %ld, wrote %d\n",
6399		    ((long) ((v_bufptr - v_bufstr) <= MAX_PTY_WRITE)
6400		     ? (long) (v_bufptr - v_bufstr)
6401		     : MAX_PTY_WRITE),
6402		    riten);
6403	});
6404	v_bufstr += riten;
6405	if (v_bufstr >= v_bufptr)	/* we wrote it all */
6406	    v_bufstr = v_bufptr = v_buffer;
6407    }
6408
6409    /*
6410     * If we have lots of unused memory allocated, return it
6411     */
6412    if (v_bufend - v_bufptr > 1024) {	/* arbitrary hysteresis */
6413	/* save pointers across realloc */
6414	size_t start = (size_t) (v_bufstr - v_buffer);
6415	size_t size = (size_t) (v_bufptr - v_buffer);
6416	size_t allocsize = (size ? size : 1);
6417
6418	v_buffer = TypeRealloc(Char, allocsize, v_buffer);
6419	if (v_buffer) {
6420	    v_bufstr = v_buffer + start;
6421	    v_bufptr = v_buffer + size;
6422	    v_bufend = v_buffer + allocsize;
6423	    if_DEBUG({
6424		fprintf(stderr, "shrunk buffer to %lu\n", (unsigned long) allocsize);
6425	    });
6426	} else {
6427	    /* should we print a warning if couldn't return memory? */
6428	    v_buffer = v_bufstr - start;	/* restore clobbered pointer */
6429	}
6430    }
6431}
6432
6433static void
6434updateCursor(XtermWidget xw)
6435{
6436    TScreen *screen = TScreenOf(xw);
6437
6438    if (screen->cursor_set != screen->cursor_state) {
6439	if (screen->cursor_set)
6440	    ShowCursor(xw);
6441	else
6442	    HideCursor(xw);
6443    }
6444}
6445
6446#if OPT_BLINK_CURS || OPT_BLINK_TEXT
6447static void
6448reallyStopBlinking(XtermWidget xw)
6449{
6450    TScreen *screen = TScreenOf(xw);
6451
6452    if (screen->cursor_state == BLINKED_OFF) {
6453	/* force cursor to display if it is enabled */
6454	screen->cursor_state = !screen->cursor_set;
6455	updateCursor(xw);
6456	xevents(xw);
6457    }
6458}
6459#endif
6460
6461static void
6462update_the_screen(XtermWidget xw)
6463{
6464    TScreen *screen = TScreenOf(xw);
6465    Boolean moved;
6466
6467    if (screen->scroll_amt)
6468	FlushScroll(xw);
6469    moved = CursorMoved(screen);
6470    if (screen->cursor_set && moved) {
6471	if (screen->cursor_state)
6472	    HideCursor(xw);
6473	ShowCursor(xw);
6474#if OPT_INPUT_METHOD
6475	PreeditPosition(xw);
6476#endif
6477    } else {
6478#if OPT_INPUT_METHOD
6479	if (moved)
6480	    PreeditPosition(xw);
6481#endif
6482	updateCursor(xw);
6483    }
6484}
6485
6486static void
6487init_timeval(struct timeval *target, long usecs)
6488{
6489    target->tv_sec = 0;
6490    target->tv_usec = usecs;
6491    while (target->tv_usec > 1000000) {
6492	target->tv_usec -= 1000000;
6493	target->tv_sec++;
6494    }
6495}
6496
6497static Boolean
6498better_timeout(struct timeval *check, struct timeval *against)
6499{
6500    Boolean result = False;
6501    if (against->tv_sec == 0 && against->tv_usec == 0) {
6502	result = True;
6503    } else if (check->tv_sec == against->tv_sec) {
6504	if (check->tv_usec < against->tv_usec) {
6505	    result = True;
6506	}
6507    } else if (check->tv_sec < against->tv_sec) {
6508	result = True;
6509    }
6510    return result;
6511}
6512
6513#if OPT_BLINK_CURS
6514static long
6515smaller_timeout(long value)
6516{
6517    /* 1000 for msec/usec, 8 for "much" smaller */
6518    value *= (1000 / 8);
6519    if (value < 1)
6520	value = 1;
6521    return value;
6522}
6523#endif
6524
6525static void
6526in_put(XtermWidget xw)
6527{
6528    static PtySelect select_mask;
6529    static PtySelect write_mask;
6530
6531    TScreen *screen = TScreenOf(xw);
6532    int i;
6533    int update = VTbuffer->update;
6534#if USE_DOUBLE_BUFFER
6535    int should_wait = 1;
6536#endif
6537    struct timeval my_timeout;
6538
6539    for (;;) {
6540	int size;
6541	int time_select;
6542
6543	if (screen->eventMode == NORMAL
6544	    && (size = readPtyData(xw, &select_mask, VTbuffer)) != 0) {
6545	    if (screen->scrollWidget
6546		&& screen->scrollttyoutput
6547		&& screen->topline < 0)
6548		WindowScroll(xw, 0, False);	/* Scroll to bottom */
6549	    /* stop speed reading at some point to look for X stuff */
6550	    TRACE(("VTbuffer uses %ld/%d\n",
6551		   (long) (VTbuffer->last - VTbuffer->buffer),
6552		   BUF_SIZE));
6553	    if ((VTbuffer->last - VTbuffer->buffer) > BUF_SIZE) {
6554		FD_CLR(screen->respond, &select_mask);
6555		break;
6556	    }
6557#if USE_DOUBLE_BUFFER
6558	    if (resource.buffered && should_wait) {
6559		/* wait for potential extra data (avoids some flickering) */
6560		usleep((unsigned) DbeMsecs(xw));
6561		should_wait = 0;
6562	    }
6563#endif
6564#if defined(HAVE_SCHED_YIELD)
6565	    /*
6566	     * If we've read a full (small/fragment) buffer, let the operating
6567	     * system have a turn, and we'll resume reading until we've either
6568	     * read only a fragment of the buffer, or we've filled the large
6569	     * buffer (see above).  Doing this helps keep up with large bursts
6570	     * of output.
6571	     */
6572	    if (size == FRG_SIZE) {
6573		init_timeval(&my_timeout, 0L);
6574		i = Select(max_plus1, &select_mask, &write_mask, 0, &my_timeout);
6575		if (i > 0 && FD_ISSET(screen->respond, &select_mask)) {
6576		    sched_yield();
6577		} else
6578		    break;
6579	    } else {
6580		break;
6581	    }
6582#else
6583	    (void) size;	/* unused in this branch */
6584	    break;
6585#endif
6586	}
6587	update_the_screen(xw);
6588
6589	XFlush(screen->display);	/* always flush writes before waiting */
6590
6591	/* Update the masks and, unless X events are already in the queue,
6592	   wait for I/O to be possible. */
6593	XFD_COPYSET(&Select_mask, &select_mask);
6594	/* in selection mode xterm does not read pty */
6595	if (screen->eventMode != NORMAL)
6596	    FD_CLR(screen->respond, &select_mask);
6597
6598	if (v_bufptr > v_bufstr) {
6599	    XFD_COPYSET(&pty_mask, &write_mask);
6600	} else
6601	    FD_ZERO(&write_mask);
6602	init_timeval(&my_timeout, 0L);
6603	time_select = 0;
6604
6605	/*
6606	 * if there's either an XEvent or an XtTimeout pending, just take
6607	 * a quick peek, i.e. timeout from the select() immediately.  If
6608	 * there's nothing pending, let select() block a little while, but
6609	 * for a shorter interval than the arrow-style scrollbar timeout.
6610	 * The blocking is optional, because it tends to increase the load
6611	 * on the host.
6612	 */
6613	if (xtermAppPending()) {
6614	    time_select = 1;
6615	} else {
6616#define ImproveTimeout(usecs) \
6617		struct timeval try_timeout; \
6618		init_timeval(&try_timeout, usecs); \
6619		if (better_timeout(&try_timeout, &my_timeout)) { \
6620		    my_timeout = try_timeout; \
6621		}
6622#if OPT_STATUS_LINE
6623	    if ((screen->status_type == 1) && screen->status_timeout) {
6624		ImproveTimeout(find_SL_Timeout(xw) * 1000L);
6625		time_select = 1;
6626	    }
6627#endif
6628	    if (screen->awaitInput) {
6629		ImproveTimeout(50000L);
6630		time_select = 1;
6631	    }
6632#if OPT_BLINK_CURS
6633	    if ((screen->blink_timer != 0 &&
6634		 ((screen->select & FOCUS) || screen->always_highlight)) ||
6635		(screen->cursor_state == BLINKED_OFF)) {
6636		/*
6637		 * Compute the timeout for the blinking cursor to be much
6638		 * smaller than the "on" or "off" interval.
6639		 */
6640		long tick = smaller_timeout((long) ((screen->blink_on < screen->blink_off)
6641						    ? screen->blink_on
6642						    : screen->blink_off));
6643		ImproveTimeout(tick);
6644		time_select = 1;
6645	    }
6646#endif
6647	}
6648#if OPT_SESSION_MGT
6649	if (resource.sessionMgt && (ice_fd >= 0)) {
6650	    FD_SET(ice_fd, &select_mask);
6651	}
6652#endif
6653	if (need_cleanup)
6654	    NormalExit();
6655	xtermFlushDbe(xw);
6656	i = Select(max_plus1, &select_mask, &write_mask, 0,
6657		   (time_select ? &my_timeout : NULL));
6658	if (i < 0) {
6659	    if (errno != EINTR)
6660		SysError(ERROR_SELECT);
6661	    continue;
6662	}
6663
6664	/* if there is room to write more data to the pty, go write more */
6665	if (FD_ISSET(screen->respond, &write_mask)) {
6666	    v_write(screen->respond, (Char *) 0, (size_t) 0);	/* flush buffer */
6667	}
6668
6669	/* if there are X events already in our queue, it
6670	   counts as being readable */
6671	if (xtermAppPending() ||
6672	    FD_ISSET(ConnectionNumber(screen->display), &select_mask)) {
6673	    xevents(xw);
6674	    if (VTbuffer->update != update)	/* HandleInterpret */
6675		break;
6676	}
6677
6678    }
6679}
6680
6681static IChar
6682doinput(XtermWidget xw)
6683{
6684    TScreen *screen = TScreenOf(xw);
6685
6686    while (!morePtyData(screen, VTbuffer))
6687	in_put(xw);
6688    return nextPtyData(screen, VTbuffer);
6689}
6690
6691#if OPT_INPUT_METHOD
6692/*
6693 *  For OverTheSpot, client has to inform the position for XIM preedit.
6694 */
6695static void
6696PreeditPosition(XtermWidget xw)
6697{
6698    TInput *input = lookupTInput(xw, (Widget) xw);
6699    TScreen *screen = TScreenOf(xw);
6700    CLineData *ld;
6701    XPoint spot;
6702    XVaNestedList list;
6703
6704    if (input && input->xic
6705	&& (ld = getLineData(screen, screen->cur_row)) != NULL) {
6706	spot.x = (short) LineCursorX(screen, ld, screen->cur_col);
6707	spot.y = (short) (CursorY(screen, screen->cur_row) + xw->work.xim_fs_ascent);
6708	list = XVaCreateNestedList(0,
6709				   XNSpotLocation, &spot,
6710				   XNForeground, T_COLOR(screen, TEXT_FG),
6711				   XNBackground, T_COLOR(screen, TEXT_BG),
6712				   (void *) 0);
6713	XSetICValues(input->xic, XNPreeditAttributes, list, (void *) 0);
6714	XFree(list);
6715    }
6716}
6717#endif
6718
6719static void
6720WrapLine(XtermWidget xw)
6721{
6722    TScreen *screen = TScreenOf(xw);
6723    LineData *ld = getLineData(screen, screen->cur_row);
6724
6725    if (ld != NULL) {
6726	/* mark that we had to wrap this line */
6727	LineSetFlag(ld, LINEWRAPPED);
6728	ShowWrapMarks(xw, screen->cur_row, ld);
6729	xtermAutoPrint(xw, '\n');
6730	xtermIndex(xw, 1);
6731	set_cur_col(screen, ScrnLeftMargin(xw));
6732    }
6733}
6734
6735/*
6736 * Process a string of characters according to the character set indicated by
6737 * charset.  Worry about end of line conditions (wraparound if selected).
6738 *
6739 * It is possible to use CUP, etc., to move outside margins.  In that case, the
6740 * right-margin is ineffective until the text (may) wrap and get within the
6741 * margins.
6742 */
6743void
6744dotext(XtermWidget xw,
6745       DECNRCM_codes charset,
6746       IChar *buf,		/* start of characters to process */
6747       Cardinal len)		/* end */
6748{
6749    TScreen *screen = TScreenOf(xw);
6750#if OPT_WIDE_CHARS
6751    Cardinal chars_chomped = 1;
6752    int next_col = screen->cur_col;
6753#else
6754    int next_col, this_col;	/* must be signed */
6755#endif
6756    Cardinal offset;
6757    int rmargin = ScrnRightMargin(xw);
6758
6759    xw->work.write_text = buf;
6760#if OPT_DEC_RECTOPS
6761    xw->work.write_sums = NULL;
6762#endif
6763#if OPT_WIDE_CHARS
6764    if (screen->vt100_graphics)
6765#endif
6766    {
6767	DECNRCM_codes rightset = screen->gsets[(int) (screen->curgr)];
6768	if (charset != nrc_ASCII || rightset != nrc_ASCII) {
6769	    len = xtermCharSetOut(xw, len, charset);
6770	    if (len == 0)
6771		return;
6772	}
6773    }
6774
6775    if_OPT_XMC_GLITCH(screen, {
6776	Cardinal n;
6777	if (charset != '?') {
6778	    for (n = 0; n < len; n++) {
6779		if (buf[n] == XMC_GLITCH)
6780		    buf[n] = XMC_GLITCH + 1;
6781	    }
6782	}
6783    });
6784
6785#if OPT_WIDE_CHARS
6786    for (offset = 0;
6787	 offset < len && (chars_chomped > 0 || screen->do_wrap);
6788	 offset += chars_chomped) {
6789#if OPT_DEC_CHRSET
6790	CLineData *ld = getLineData(screen, screen->cur_row);
6791	int real_rmargin = (CSET_DOUBLE(GetLineDblCS(ld))
6792			    ? (rmargin / 2)
6793			    : rmargin);
6794#else
6795	int real_rmargin = rmargin;
6796#endif
6797	int last_col = LineMaxCol(screen, ld);
6798	int width_here = 0;
6799	int last_chomp = 0;
6800	Boolean force_wrap;
6801
6802	chars_chomped = 0;
6803	do {
6804	    int right = ((screen->cur_col > real_rmargin)
6805			 ? last_col
6806			 : real_rmargin);
6807	    int width_available = right + 1 - screen->cur_col;
6808	    Boolean need_wrap = False;
6809	    Boolean did_wrap = False;
6810
6811	    force_wrap = False;
6812
6813	    if (screen->do_wrap) {
6814		screen->do_wrap = False;
6815		if ((xw->flags & WRAPAROUND)) {
6816		    WrapLine(xw);
6817		    right = ((screen->cur_col > real_rmargin)
6818			     ? last_col
6819			     : real_rmargin);
6820		    width_available = right + 1 - screen->cur_col;
6821		    next_col = screen->cur_col;
6822		    did_wrap = True;
6823		}
6824	    }
6825
6826	    /*
6827	     * This can happen with left/right margins...
6828	     */
6829	    if (width_available <= 0) {
6830		break;
6831	    }
6832
6833	    /*
6834	     * Regarding the soft-hyphen aberration, see
6835	     * http://archives.miloush.net/michkap/archive/2006/09/02/736881.html
6836	     */
6837	    while (width_here <= width_available
6838		   && chars_chomped < (len - offset)) {
6839		Cardinal n = chars_chomped + offset;
6840		if (!screen->utf8_mode
6841		    || (screen->vt100_graphics && charset == '0')) {
6842		    last_chomp = 1;
6843		} else if (screen->c1_printable &&
6844			   buf[n] >= 0x80 &&
6845			   buf[n] <= 0xa0) {
6846		    last_chomp = 1;
6847		} else {
6848		    last_chomp = CharWidth(screen, buf[n]);
6849		    if (last_chomp <= 0) {
6850			IChar ch = buf[n];
6851			Bool eat_it = !screen->utf8_mode && (ch > 127);
6852			if (ch == 0xad) {
6853			    /*
6854			     * Only display soft-hyphen if it happens to be at
6855			     * the right-margin.  While that means that only
6856			     * the displayed character could be selected for
6857			     * pasting, a well-behaved application would never
6858			     * send this, anyway...
6859			     */
6860			    if (width_here < width_available - 1) {
6861				eat_it = True;
6862			    } else {
6863				last_chomp = 1;
6864				eat_it = False;
6865			    }
6866			    TRACE(("...will%s display soft-hyphen\n",
6867				   eat_it ? " not" : ""));
6868			}
6869			/*
6870			 * Supposedly we dealt with combining characters and
6871			 * control characters in doparse().  Anything left over
6872			 * is junk that we will not attempt to display.
6873			 */
6874			if (eat_it) {
6875			    TRACE(("...will not display U+%04X\n", ch));
6876			    --len;
6877			    while (n < len) {
6878				buf[n] = buf[n + 1];
6879				++n;
6880			    }
6881			    last_chomp = 0;
6882			    chars_chomped--;
6883			}
6884		    }
6885		}
6886		width_here += last_chomp;
6887		chars_chomped++;
6888	    }
6889
6890	    if (width_here > width_available) {
6891		if (last_chomp > right + 1) {
6892		    break;	/* give up - it is too big */
6893		} else if (chars_chomped-- == 0) {
6894		    /* This can happen with left/right margins... */
6895		    break;
6896		}
6897		width_here -= last_chomp;
6898		if (chars_chomped > 0) {
6899		    if (!(xw->flags & WRAPAROUND)) {
6900			buf[chars_chomped + offset - 1] = buf[len - 1];
6901		    } else {
6902			need_wrap = True;
6903		    }
6904		}
6905	    } else if (width_here == width_available) {
6906		need_wrap = True;
6907	    } else if (chars_chomped != (len - offset)) {
6908		need_wrap = True;
6909	    }
6910
6911	    if (chars_chomped != 0 && next_col <= last_col) {
6912		WriteText(xw, offset, chars_chomped);
6913	    } else if (!did_wrap
6914		       && len > 0
6915		       && (xw->flags & WRAPAROUND)
6916		       && screen->cur_col > ScrnLeftMargin(xw)) {
6917		force_wrap = True;
6918		need_wrap = True;
6919	    }
6920	    next_col += width_here;
6921	    screen->do_wrap = need_wrap;
6922	} while (force_wrap);
6923    }
6924
6925    /*
6926     * Remember that we wrote something to the screen, for use as a base of
6927     * combining characters.  The logic above may have called cursor-forward
6928     * or carriage-return operations which resets this flag, so we set it at
6929     * the very end.
6930     */
6931    screen->char_was_written = True;
6932#else /* ! OPT_WIDE_CHARS */
6933
6934    for (offset = 0; offset < len; offset += (Cardinal) this_col) {
6935#if OPT_DEC_CHRSET
6936	CLineData *ld = getLineData(screen, screen->cur_row);
6937#endif
6938	int right = ((screen->cur_col > rmargin)
6939		     ? screen->max_col
6940		     : rmargin);
6941
6942	int last_col = LineMaxCol(screen, ld);
6943	if (last_col > right)
6944	    last_col = right;
6945	this_col = last_col - screen->cur_col + 1;
6946	if (screen->do_wrap) {
6947	    screen->do_wrap = False;
6948	    if ((xw->flags & WRAPAROUND)) {
6949		WrapLine(xw);
6950	    }
6951	    this_col = 1;
6952	}
6953	if (offset + (Cardinal) this_col > len) {
6954	    this_col = (int) (len - offset);
6955	}
6956	next_col = screen->cur_col + this_col;
6957
6958	WriteText(xw, offset, (unsigned) this_col);
6959
6960	/*
6961	 * The call to WriteText updates screen->cur_col.
6962	 * If screen->cur_col is less than next_col, we must have
6963	 * hit the right margin - so set the do_wrap flag.
6964	 */
6965	screen->do_wrap = (Boolean) (screen->cur_col < next_col);
6966    }
6967
6968#endif /* OPT_WIDE_CHARS */
6969}
6970
6971#if OPT_WIDE_CHARS
6972unsigned
6973visual_width(const IChar *str, Cardinal len)
6974{
6975    /* returns the visual width of a string (doublewide characters count
6976       as 2, normalwide characters count as 1) */
6977    unsigned my_len = 0;
6978    while (len) {
6979	int ch = (int) *str++;
6980	if (isWide(ch))
6981	    my_len += 2;
6982	else
6983	    my_len++;
6984	len--;
6985    }
6986    return my_len;
6987}
6988#endif
6989
6990#if HANDLE_STRUCT_NOTIFY
6991/* Flag icon name with "***" on window output when iconified.
6992 */
6993static void
6994HandleStructNotify(Widget w GCC_UNUSED,
6995		   XtPointer closure GCC_UNUSED,
6996		   XEvent *event,
6997		   Boolean *cont GCC_UNUSED)
6998{
6999    XtermWidget xw = term;
7000    TScreen *screen = TScreenOf(xw);
7001
7002    (void) screen;
7003    TRACE_EVENT("HandleStructNotify", event, NULL, NULL);
7004    switch (event->type) {
7005    case MapNotify:
7006	resetZIconBeep(xw);
7007	mapstate = !IsUnmapped;
7008	break;
7009    case UnmapNotify:
7010	mapstate = IsUnmapped;
7011	break;
7012    case MappingNotify:
7013	XRefreshKeyboardMapping(&(event->xmapping));
7014	VTInitModifiers(xw);
7015	break;
7016    case ConfigureNotify:
7017	if (event->xconfigure.window == XtWindow(toplevel)) {
7018#if !OPT_TOOLBAR
7019	    int height = event->xconfigure.height;
7020	    int width = event->xconfigure.width;
7021#endif
7022
7023#if USE_DOUBLE_BUFFER
7024	    discardRenderDraw(screen);
7025#endif /* USE_DOUBLE_BUFFER */
7026#if OPT_TOOLBAR
7027	    /*
7028	     * The notification is for the top-level widget, but we care about
7029	     * vt100 (ignore the tek4014 window).
7030	     */
7031	    if (screen->Vshow) {
7032		VTwin *Vwin = WhichVWin(screen);
7033		TbInfo *info = &(Vwin->tb_info);
7034		TbInfo save = *info;
7035
7036		if (info->menu_bar) {
7037		    XtVaGetValues(info->menu_bar,
7038				  XtNheight, &info->menu_height,
7039				  XtNborderWidth, &info->menu_border,
7040				  (XtPointer) 0);
7041
7042		    if (save.menu_height != info->menu_height
7043			|| save.menu_border != info->menu_border) {
7044
7045			TRACE(("...menu_height %d\n", info->menu_height));
7046			TRACE(("...menu_border %d\n", info->menu_border));
7047			TRACE(("...had height  %d, border %d\n",
7048			       save.menu_height,
7049			       save.menu_border));
7050
7051			/*
7052			 * Window manager still may be using the old values.
7053			 * Try to fool it.
7054			 */
7055			REQ_RESIZE((Widget) xw,
7056				   screen->fullVwin.fullwidth,
7057				   (Dimension) (info->menu_height
7058						- save.menu_height
7059						+ screen->fullVwin.fullheight),
7060				   NULL, NULL);
7061			repairSizeHints();
7062		    }
7063		}
7064	    }
7065#else
7066	    if (!xw->work.doing_resize
7067#if OPT_RENDERFONT && USE_DOUBLE_BUFFER
7068		&& !(resource.buffered && UsingRenderFont(xw))	/* buggyXft */
7069#endif
7070		&& (height != xw->hints.height
7071		    || width != xw->hints.width)) {
7072		/*
7073		 * This is a special case: other calls to RequestResize that
7074		 * could set the screensize arbitrarily are via escape
7075		 * sequences, and we've limited resizing.  But a configure
7076		 * notify is from the window manager, presumably under control
7077		 * of the interactive user (ignoring abuse of wmctrl).  Ignore
7078		 * the limit for this case.
7079		 */
7080		int saved_limit = xw->misc.limit_resize;
7081		xw->misc.limit_resize = 0;
7082		RequestResize(xw, height, width, False);
7083		xw->misc.limit_resize = saved_limit;
7084	    }
7085#endif /* OPT_TOOLBAR */
7086	}
7087	break;
7088    }
7089}
7090#endif /* HANDLE_STRUCT_NOTIFY */
7091
7092#if OPT_BLINK_CURS
7093static int
7094DoStartBlinking(TScreen *screen)
7095{
7096    int actual = ((screen->cursor_blink == cbTrue ||
7097		   screen->cursor_blink == cbAlways)
7098		  ? 1
7099		  : 0);
7100    int wanted = screen->cursor_blink_esc ? 1 : 0;
7101    int result;
7102    if (screen->cursor_blink_xor) {
7103	result = actual ^ wanted;
7104    } else {
7105	result = actual | wanted;
7106    }
7107    return result;
7108}
7109
7110static void
7111SetCursorBlink(XtermWidget xw, BlinkOps enable)
7112{
7113    TScreen *screen = TScreenOf(xw);
7114
7115    if (SettableCursorBlink(screen)) {
7116	screen->cursor_blink = enable;
7117    }
7118    if (DoStartBlinking(screen)) {
7119	StartBlinking(xw);
7120    } else {
7121	/* EMPTY */
7122#if OPT_BLINK_TEXT
7123	reallyStopBlinking(xw);
7124#else
7125	StopBlinking(xw);
7126#endif
7127    }
7128    update_cursorblink();
7129}
7130
7131void
7132ToggleCursorBlink(XtermWidget xw)
7133{
7134    TScreen *screen = TScreenOf(xw);
7135
7136    if (screen->cursor_blink == cbTrue) {
7137	SetCursorBlink(xw, cbFalse);
7138    } else if (screen->cursor_blink == cbFalse) {
7139	SetCursorBlink(xw, cbTrue);
7140    }
7141}
7142#endif
7143
7144/*
7145 * process ANSI modes set, reset
7146 */
7147static void
7148ansi_modes(XtermWidget xw, BitFunc func)
7149{
7150    int i;
7151
7152    for (i = 0; i < nparam; ++i) {
7153	switch (GetParam(i)) {
7154	case 2:		/* KAM (if set, keyboard locked */
7155	    (*func) (&xw->keyboard.flags, MODE_KAM);
7156	    break;
7157
7158	case 4:		/* IRM                          */
7159	    (*func) (&xw->flags, INSERT);
7160	    break;
7161
7162	case 12:		/* SRM (if set, local echo      */
7163	    (*func) (&xw->keyboard.flags, MODE_SRM);
7164	    break;
7165
7166	case 20:		/* LNM                          */
7167	    (*func) (&xw->flags, LINEFEED);
7168	    update_autolinefeed();
7169	    break;
7170	}
7171    }
7172}
7173
7174#define IsSM() (func == bitset)
7175
7176#define set_bool_mode(flag) \
7177	flag = (Boolean) IsSM()
7178
7179static void
7180really_set_mousemode(XtermWidget xw,
7181		     Bool enabled,
7182		     XtermMouseModes mode)
7183{
7184    TScreenOf(xw)->send_mouse_pos = enabled ? mode : MOUSE_OFF;
7185    if (okSendMousePos(xw) != MOUSE_OFF)
7186	xtermShowPointer(xw, True);
7187}
7188
7189#define set_mousemode(mode) really_set_mousemode(xw, IsSM(), mode)
7190
7191#if OPT_PASTE64 || OPT_READLINE
7192#define set_mouseflag(f)		\
7193	(IsSM()				\
7194	 ? SCREEN_FLAG_set(screen, f)	\
7195	 : SCREEN_FLAG_unset(screen, f))
7196#endif
7197
7198/*
7199 * DEC 070, pp 5-29 to 5-30 (DECLRMM).
7200 * DEC 070, pp 5-71 to 5-72 (DECCOLM).
7201 *
7202 * The descriptions for DECLRMM and DECCOLM agree that setting DECLRMM resets
7203 * double-sized mode to single-size, and that if DECLRMM is being set, then
7204 * double-sized mode is disabled.  Resetting DECLRMM has no effect on the
7205 * double-sized mode.  The description of DECCOLM has an apparent error in its
7206 * pseudo-code (because it is inconsistent with the description of DECLRMM),
7207 * indicating that left_right_margins_mode is changed to SETABLE no matter
7208 * which way DECCOLM is set.
7209 */
7210static void
7211set_column_mode(XtermWidget xw)
7212{
7213    TScreen *screen = TScreenOf(xw);
7214
7215    /* switch 80/132 columns clears the screen and sets to single-width */
7216    xterm_ResetDouble(xw);
7217    resetMargins(xw);
7218    CursorSet(screen, 0, 0, xw->flags);
7219}
7220
7221/*
7222 * DEC 070, pp 5-29 to 5-30.
7223 */
7224static void
7225set_left_right_margin_mode(XtermWidget xw)
7226{
7227    TScreen *screen = TScreenOf(xw);
7228
7229    if (screen->vtXX_level >= 4) {
7230	if (IsLeftRightMode(xw)) {
7231	    xterm_ResetDouble(xw);
7232	} else {
7233	    reset_lr_margins(screen);
7234	}
7235    }
7236}
7237
7238/*
7239 * process DEC private modes set, reset
7240 */
7241static void
7242dpmodes(XtermWidget xw, BitFunc func)
7243{
7244    TScreen *screen = TScreenOf(xw);
7245    int i, j;
7246    unsigned myflags;
7247
7248    TRACE(("changing %d DEC private modes\n", nparam));
7249    if_STATUS_LINE(screen, {
7250	return;
7251    });
7252    for (i = 0; i < nparam; ++i) {
7253	int code = GetParam(i);
7254
7255	TRACE(("%s %d\n", IsSM()? "DECSET" : "DECRST", code));
7256	switch ((DECSET_codes) code) {
7257	case srm_DECCKM:
7258	    (*func) (&xw->keyboard.flags, MODE_DECCKM);
7259	    update_appcursor();
7260	    break;
7261	case srm_DECANM:	/* ANSI/VT52 mode      */
7262#if OPT_STATUS_LINE
7263	    if (screen->status_type == 2 && screen->status_active) {
7264		/* DEC 070, section 14.2.3 item 4 */
7265		/* EMPTY */ ;
7266	    } else
7267#endif
7268	    if (IsSM()) {	/* ANSI (VT100) */
7269		/*
7270		 * Setting DECANM should have no effect, since this function
7271		 * cannot be reached from vt52 mode.
7272		 */
7273		/* EMPTY */ ;
7274	    }
7275#if OPT_VT52_MODE
7276	    else if (screen->terminal_id >= 100) {	/* VT52 */
7277		TRACE(("DECANM terminal_id %d, vtXX_level %d\n",
7278		       screen->terminal_id,
7279		       screen->vtXX_level));
7280		/*
7281		 * According to DEC STD 070 section A.5.5, the various VT100
7282		 * modes have undefined behavior when entering/exiting VT52
7283		 * mode.  xterm saves/restores/initializes the most commonly
7284		 * used settings, but a real VT100 or VT520 may differ.
7285		 *
7286		 * For instance, DEC's documentation goes on to comment that
7287		 * while the VT52 uses hardware tabs (8 columns), the emulation
7288		 * (e.g., a VT420) does not alter those tab settings when
7289		 * switching modes.
7290		 */
7291		set_vtXX_level(screen, 0);
7292		screen->vt52_save_flags = xw->flags;
7293		xw->flags = 0;
7294		screen->vt52_save_curgl = screen->curgl;
7295		screen->vt52_save_curgr = screen->curgr;
7296		screen->vt52_save_curss = screen->curss;
7297		saveCharsets(screen, screen->vt52_save_gsets);
7298		resetCharsets(screen);
7299		InitParams();	/* ignore the remaining params, if any */
7300		update_vt52_vt100_settings();
7301		RequestResize(xw, -1, 80, True);
7302	    }
7303#endif
7304	    break;
7305	case srm_DECCOLM:
7306	    if (screen->c132) {
7307		Boolean willResize = ((j = IsSM()
7308				       ? 132
7309				       : 80)
7310				      != ((xw->flags & IN132COLUMNS)
7311					  ? 132
7312					  : 80)
7313				      || j != MaxCols(screen));
7314		if (!(xw->flags & NOCLEAR_COLM)) {
7315#if OPT_STATUS_LINE
7316		    if (IsStatusShown(screen))
7317			clear_status_line(xw);
7318#endif
7319		    ClearScreen(xw);
7320		}
7321		if (willResize)
7322		    RequestResize(xw, -1, j, True);
7323		(*func) (&xw->flags, IN132COLUMNS);
7324		set_column_mode(xw);
7325	    }
7326	    break;
7327	case srm_DECSCLM:	/* (slow scroll)        */
7328	    if (IsSM()) {
7329		screen->jumpscroll = 0;
7330		if (screen->scroll_amt)
7331		    FlushScroll(xw);
7332	    } else
7333		screen->jumpscroll = 1;
7334	    (*func) (&xw->flags, SMOOTHSCROLL);
7335	    update_jumpscroll();
7336	    break;
7337	case srm_DECSCNM:
7338	    myflags = xw->flags;
7339	    (*func) (&xw->flags, REVERSE_VIDEO);
7340	    if ((xw->flags ^ myflags) & REVERSE_VIDEO)
7341		ReverseVideo(xw);
7342	    /* update_reversevideo done in RevVid */
7343	    break;
7344
7345	case srm_DECOM:
7346	    (*func) (&xw->flags, ORIGIN);
7347	    CursorSet(screen, 0, 0, xw->flags);
7348	    break;
7349
7350	case srm_DECAWM:
7351	    (*func) (&xw->flags, WRAPAROUND);
7352	    update_autowrap();
7353	    break;
7354	case srm_DECARM:
7355	    /* ignore autorepeat
7356	     * XAutoRepeatOn() and XAutoRepeatOff() can do this, but only
7357	     * for the whole display - not limited to a given window.
7358	     */
7359	    break;
7360	case srm_X10_MOUSE:	/* MIT bogus sequence           */
7361	    MotionOff(screen, xw);
7362	    set_mousemode(X10_MOUSE);
7363	    break;
7364#if OPT_TOOLBAR
7365	case srm_RXVT_TOOLBAR:
7366	    ShowToolbar(IsSM());
7367	    break;
7368#else
7369	case srm_DECEDM:	/* vt330:edit */
7370	    break;
7371#endif
7372#if OPT_BLINK_CURS
7373	case srm_ATT610_BLINK:	/* AT&T 610: Start/stop blinking cursor */
7374	    if (SettableCursorBlink(screen)) {
7375		set_bool_mode(screen->cursor_blink_esc);
7376		UpdateCursorBlink(xw);
7377	    }
7378	    break;
7379	case srm_CURSOR_BLINK_OPS:
7380	    /* intentionally ignored (this is user-preference) */
7381	    break;
7382	case srm_XOR_CURSOR_BLINKS:
7383	    /* intentionally ignored (this is user-preference) */
7384	    break;
7385#else
7386	case srm_DECKANAM:	/* vt382:Katakana shift */
7387	case srm_DECSCFDM:	/* vt330:space compression field delimiter */
7388	case srm_DECTEM:	/* vt330:transmission execution */
7389	    break;
7390#endif
7391	case srm_DECPFF:	/* print form feed */
7392	    set_bool_mode(PrinterOf(screen).printer_formfeed);
7393	    break;
7394	case srm_DECPEX:	/* print extent */
7395	    set_bool_mode(PrinterOf(screen).printer_extent);
7396	    break;
7397	case srm_DECTCEM:	/* Show/hide cursor (VT200) */
7398	    set_bool_mode(screen->cursor_set);
7399	    break;
7400	case srm_RXVT_SCROLLBAR:
7401	    if (screen->fullVwin.sb_info.width != (IsSM()? ON : OFF))
7402		ToggleScrollBar(xw);
7403	    break;
7404#if OPT_SHIFT_FONTS
7405	case srm_RXVT_FONTSIZE:
7406	    set_bool_mode(xw->misc.shift_fonts);
7407	    break;
7408#endif
7409#if OPT_TEK4014
7410	case srm_DECTEK:
7411	    if (IsSM() && !(screen->inhibit & I_TEK)) {
7412		FlushLog(xw);
7413		TEK4014_ACTIVE(xw) = True;
7414		TRACE(("Tek4014 is now active...\n"));
7415		update_vttekmode();
7416	    }
7417	    break;
7418#endif
7419	case srm_132COLS:	/* 132 column mode              */
7420	    set_bool_mode(screen->c132);
7421	    update_allow132();
7422	    break;
7423	case srm_CURSES_HACK:
7424	    set_bool_mode(screen->curses);
7425	    update_cursesemul();
7426	    break;
7427	case srm_DECNRCM:	/* national charset (VT220) */
7428	    if (screen->vtXX_level >= 2) {
7429		if ((*func) (&xw->flags, NATIONAL)) {
7430		    modified_DECNRCM(xw);
7431		}
7432	    }
7433	    break;
7434#if OPT_PRINT_GRAPHICS
7435	case srm_DECGEPM:	/* Graphics Expanded Print Mode */
7436	    set_bool_mode(screen->graphics_expanded_print_mode);
7437	    break;
7438#endif
7439	case srm_MARGIN_BELL:	/* margin bell (xterm) also DECGPCM (Graphics Print Color Mode) */
7440	    if_PRINT_GRAPHICS2(set_bool_mode(screen->graphics_print_color_mode)) {
7441		set_bool_mode(screen->marginbell);
7442		if (!screen->marginbell)
7443		    screen->bellArmed = -1;
7444		update_marginbell();
7445	    }
7446	    break;
7447	case srm_REVERSEWRAP:	/* reverse wraparound (xterm) also DECGPCS (Graphics Print Color Syntax) */
7448	    if_PRINT_GRAPHICS2(set_bool_mode(screen->graphics_print_color_syntax)) {
7449		(*func) (&xw->flags, REVERSEWRAP);
7450		update_reversewrap();
7451	    }
7452	    break;
7453	case srm_REVERSEWRAP2:	/* extended reverse wraparound (xterm) */
7454	    (*func) (&xw->flags, REVERSEWRAP2);
7455	    break;
7456#ifdef ALLOWLOGGING
7457	case srm_ALLOWLOGGING:	/* logging (xterm) also DECGPBM (Graphics Print Background Mode) */
7458	    if_PRINT_GRAPHICS2(set_bool_mode(screen->graphics_print_background_mode)) {
7459#ifdef ALLOWLOGFILEONOFF
7460		/*
7461		 * if this feature is enabled, logging may be
7462		 * enabled and disabled via escape sequences.
7463		 */
7464		if (IsSM())
7465		    StartLog(xw);
7466		else
7467		    CloseLog(xw);
7468#else
7469		Bell(xw, XkbBI_Info, 0);
7470		Bell(xw, XkbBI_Info, 0);
7471#endif /* ALLOWLOGFILEONOFF */
7472	    }
7473	    break;
7474#elif OPT_PRINT_GRAPHICS
7475	case srm_DECGPBM:	/* Graphics Print Background Mode */
7476	    set_bool_mode(screen->graphics_print_background_mode);
7477	    break;
7478#endif /* ALLOWLOGGING */
7479	case srm_OPT_ALTBUF_CURSOR:	/* optional alternate buffer and clear (xterm) */
7480	    if (!xw->misc.titeInhibit) {
7481		if (IsSM()) {
7482		    CursorSave(xw);
7483		    ToAlternate(xw, True);
7484		    ClearScreen(xw);
7485		} else {
7486		    FromAlternate(xw, False);
7487		    CursorRestore(xw);
7488		}
7489	    } else if (IsSM()) {
7490		do_ti_xtra_scroll(xw);
7491	    }
7492	    break;
7493	case srm_OPT_ALTBUF:	/* optional alternate buffer and clear (xterm) */
7494	    if (!xw->misc.titeInhibit) {
7495		if (IsSM()) {
7496		    ToAlternate(xw, False);
7497		} else {
7498		    if (screen->whichBuf)
7499			ClearScreen(xw);
7500		    FromAlternate(xw, False);
7501		}
7502	    } else if (IsSM()) {
7503		do_ti_xtra_scroll(xw);
7504	    }
7505	    break;
7506	case srm_ALTBUF:	/* alternate buffer (xterm) also DECGRPM (Graphics Rotated Print Mode) */
7507	    if_PRINT_GRAPHICS2(set_bool_mode(screen->graphics_rotated_print_mode)) {
7508		if (!xw->misc.titeInhibit) {
7509		    if (IsSM()) {
7510			ToAlternate(xw, False);
7511		    } else {
7512			FromAlternate(xw, False);
7513		    }
7514		} else if (IsSM()) {
7515		    do_ti_xtra_scroll(xw);
7516		}
7517	    }
7518	    break;
7519	case srm_DECNKM:
7520	    (*func) (&xw->keyboard.flags, MODE_DECKPAM);
7521	    update_appkeypad();
7522	    break;
7523	case srm_DECBKM:
7524	    /* back-arrow mapped to backspace or delete(D) */
7525	    (*func) (&xw->keyboard.flags, MODE_DECBKM);
7526	    TRACE(("DECSET DECBKM %s\n",
7527		   BtoS(xw->keyboard.flags & MODE_DECBKM)));
7528	    update_decbkm();
7529	    break;
7530	case srm_DECLRMM:
7531	    if (screen->vtXX_level >= 4) {	/* VT420 */
7532		(*func) (&xw->flags, LEFT_RIGHT);
7533		set_left_right_margin_mode(xw);
7534	    }
7535	    break;
7536#if OPT_SIXEL_GRAPHICS
7537	case srm_DECSDM:	/* sixel display mode (no scrolling) */
7538	    if (optSixelGraphics(screen)) {	/* FIXME: VT24x did not scroll sixel graphics */
7539		(*func) (&xw->keyboard.flags, MODE_DECSDM);
7540		TRACE(("DECSET/DECRST DECSDM %s (resource default is %s)\n",
7541		       BtoS(xw->keyboard.flags & MODE_DECSDM),
7542		       BtoS(!screen->sixel_scrolling)));
7543		update_decsdm();
7544	    }
7545	    break;
7546#endif
7547	case srm_DECNCSM:
7548	    if (screen->vtXX_level >= 5) {	/* VT510 */
7549		(*func) (&xw->flags, NOCLEAR_COLM);
7550	    }
7551	    break;
7552	case srm_VT200_MOUSE:	/* xterm bogus sequence         */
7553	    MotionOff(screen, xw);
7554	    set_mousemode(VT200_MOUSE);
7555	    break;
7556	case srm_VT200_HIGHLIGHT_MOUSE:	/* xterm sequence w/hilite tracking */
7557	    MotionOff(screen, xw);
7558	    set_mousemode(VT200_HIGHLIGHT_MOUSE);
7559	    break;
7560	case srm_BTN_EVENT_MOUSE:
7561	    MotionOff(screen, xw);
7562	    set_mousemode(BTN_EVENT_MOUSE);
7563	    break;
7564	case srm_ANY_EVENT_MOUSE:
7565	    set_mousemode(ANY_EVENT_MOUSE);
7566	    if (screen->send_mouse_pos == MOUSE_OFF) {
7567		MotionOff(screen, xw);
7568	    } else {
7569		MotionOn(screen, xw);
7570	    }
7571	    break;
7572#if OPT_FOCUS_EVENT
7573	case srm_FOCUS_EVENT_MOUSE:
7574	    set_bool_mode(screen->send_focus_pos);
7575	    break;
7576#endif
7577	case srm_EXT_MODE_MOUSE:
7578	    /* FALLTHRU */
7579	case srm_SGR_EXT_MODE_MOUSE:
7580	    /* FALLTHRU */
7581	case srm_URXVT_EXT_MODE_MOUSE:
7582	    /* FALLTHRU */
7583	case srm_PIXEL_POSITION_MOUSE:
7584	    /*
7585	     * Rather than choose an arbitrary precedence among the coordinate
7586	     * modes, they are mutually exclusive.  For consistency, a reset is
7587	     * only effective against the matching mode.
7588	     */
7589	    if (IsSM()) {
7590		screen->extend_coords = code;
7591	    } else if (screen->extend_coords == code) {
7592		screen->extend_coords = 0;
7593	    }
7594	    break;
7595	case srm_ALTERNATE_SCROLL:
7596	    set_bool_mode(screen->alternateScroll);
7597	    break;
7598	case srm_RXVT_SCROLL_TTY_OUTPUT:
7599	    set_bool_mode(screen->scrollttyoutput);
7600	    update_scrollttyoutput();
7601	    break;
7602	case srm_RXVT_SCROLL_TTY_KEYPRESS:
7603	    set_bool_mode(screen->scrollkey);
7604	    update_scrollkey();
7605	    break;
7606	case srm_EIGHT_BIT_META:
7607	    if (screen->eight_bit_meta != ebNever) {
7608		set_bool_mode(screen->eight_bit_meta);
7609	    }
7610	    break;
7611#if OPT_NUM_LOCK
7612	case srm_REAL_NUMLOCK:
7613	    set_bool_mode(xw->misc.real_NumLock);
7614	    update_num_lock();
7615	    break;
7616	case srm_META_SENDS_ESC:
7617	    set_bool_mode(screen->meta_sends_esc);
7618	    update_meta_esc();
7619	    break;
7620#endif
7621	case srm_DELETE_IS_DEL:
7622	    set_bool_mode(screen->delete_is_del);
7623	    update_delete_del();
7624	    break;
7625#if OPT_NUM_LOCK
7626	case srm_ALT_SENDS_ESC:
7627	    set_bool_mode(screen->alt_sends_esc);
7628	    update_alt_esc();
7629	    break;
7630#endif
7631	case srm_KEEP_SELECTION:
7632	    set_bool_mode(screen->keepSelection);
7633	    update_keepSelection();
7634	    break;
7635	case srm_SELECT_TO_CLIPBOARD:
7636	    set_bool_mode(screen->selectToClipboard);
7637	    update_selectToClipboard();
7638	    break;
7639	case srm_BELL_IS_URGENT:
7640	    set_bool_mode(screen->bellIsUrgent);
7641	    update_bellIsUrgent();
7642	    break;
7643	case srm_POP_ON_BELL:
7644	    set_bool_mode(screen->poponbell);
7645	    update_poponbell();
7646	    break;
7647	case srm_KEEP_CLIPBOARD:
7648	    set_bool_mode(screen->keepClipboard);
7649	    update_keepClipboard();
7650	    break;
7651	case srm_ALLOW_ALTBUF:
7652	    if (IsSM()) {
7653		xw->misc.titeInhibit = False;
7654	    } else if (!xw->misc.titeInhibit) {
7655		xw->misc.titeInhibit = True;
7656		FromAlternate(xw, False);
7657	    }
7658	    update_titeInhibit();
7659	    break;
7660	case srm_SAVE_CURSOR:
7661	    if (!xw->misc.titeInhibit) {
7662		if (IsSM())
7663		    CursorSave(xw);
7664		else
7665		    CursorRestore(xw);
7666	    }
7667	    break;
7668	case srm_FAST_SCROLL:
7669	    set_bool_mode(screen->fastscroll);
7670	    break;
7671#if OPT_TCAP_FKEYS
7672	case srm_TCAP_FKEYS:
7673	    set_keyboard_type(xw, keyboardIsTermcap, IsSM());
7674	    break;
7675#endif
7676#if OPT_SUN_FUNC_KEYS
7677	case srm_SUN_FKEYS:
7678	    set_keyboard_type(xw, keyboardIsSun, IsSM());
7679	    break;
7680#endif
7681#if OPT_HP_FUNC_KEYS
7682	case srm_HP_FKEYS:
7683	    set_keyboard_type(xw, keyboardIsHP, IsSM());
7684	    break;
7685#endif
7686#if OPT_SCO_FUNC_KEYS
7687	case srm_SCO_FKEYS:
7688	    set_keyboard_type(xw, keyboardIsSCO, IsSM());
7689	    break;
7690#endif
7691	case srm_LEGACY_FKEYS:
7692	    set_keyboard_type(xw, keyboardIsLegacy, IsSM());
7693	    break;
7694#if OPT_SUNPC_KBD
7695	case srm_VT220_FKEYS:
7696	    set_keyboard_type(xw, keyboardIsVT220, IsSM());
7697	    break;
7698#endif
7699#if OPT_PASTE64 || OPT_READLINE
7700	case srm_PASTE_IN_BRACKET:
7701	    set_mouseflag(paste_brackets);
7702	    break;
7703#endif
7704#if OPT_READLINE
7705	case srm_BUTTON1_MOVE_POINT:
7706	    set_mouseflag(click1_moves);
7707	    break;
7708	case srm_BUTTON2_MOVE_POINT:
7709	    set_mouseflag(paste_moves);
7710	    break;
7711	case srm_DBUTTON3_DELETE:
7712	    set_mouseflag(dclick3_deletes);
7713	    break;
7714	case srm_PASTE_QUOTE:
7715	    set_mouseflag(paste_quotes);
7716	    break;
7717	case srm_PASTE_LITERAL_NL:
7718	    set_mouseflag(paste_literal_nl);
7719	    break;
7720#endif /* OPT_READLINE */
7721#if OPT_GRAPHICS
7722	case srm_PRIVATE_COLOR_REGISTERS:	/* private color registers for each graphic */
7723	    TRACE(("DECSET/DECRST PRIVATE_COLOR_REGISTERS to %s (resource default is %s)\n",
7724		   BtoS(screen->privatecolorregisters),
7725		   BtoS(screen->privatecolorregisters0)));
7726	    set_bool_mode(screen->privatecolorregisters);
7727	    update_privatecolorregisters();
7728	    break;
7729#endif
7730#if OPT_SIXEL_GRAPHICS
7731	case srm_SIXEL_SCROLLS_RIGHT:	/* sixel scrolling moves cursor to right */
7732	    if (optSixelGraphics(screen)) {	/* FIXME: VT24x did not scroll sixel graphics */
7733		set_bool_mode(screen->sixel_scrolls_right);
7734		TRACE(("DECSET/DECRST SIXEL_SCROLLS_RIGHT to %s (resource default is %s)\n",
7735		       BtoS(screen->sixel_scrolls_right),
7736		       BtoS(TScreenOf(xw)->sixel_scrolls_right)));
7737	    }
7738	    break;
7739#endif
7740	case srm_DEC131TM:	/* ignore */
7741	case srm_DECAAM:	/* ignore */
7742	case srm_DECARSM:	/* ignore */
7743	case srm_DECATCBM:	/* ignore */
7744	case srm_DECATCUM:	/* ignore */
7745	case srm_DECBBSM:	/* ignore */
7746	case srm_DECCANSM:	/* ignore */
7747	case srm_DECCAPSLK:	/* ignore */
7748	case srm_DECCRTSM:	/* ignore */
7749	case srm_DECECM:	/* ignore */
7750	case srm_DECEKEM:	/* ignore */
7751	case srm_DECESKM:	/* ignore */
7752	case srm_DECFWM:	/* ignore */
7753	case srm_DECHCCM:	/* ignore */
7754	case srm_DECHDPXM:	/* ignore */
7755	case srm_DECHEM:	/* ignore */
7756	case srm_DECHWUM:	/* ignore */
7757	case srm_DECIPEM:	/* ignore */
7758	case srm_DECKBUM:	/* ignore */
7759	case srm_DECKLHIM:	/* ignore */
7760	case srm_DECKKDM:	/* ignore */
7761	case srm_DECKPM:	/* ignore */
7762	case srm_DECLTM:	/* ignore */
7763	case srm_DECMCM:	/* ignore */
7764	case srm_DECNAKB:	/* ignore */
7765	case srm_DECNULM:	/* ignore */
7766	case srm_DECNUMLK:	/* ignore */
7767	case srm_DECOSCNM:	/* ignore */
7768	case srm_DECPCCM:	/* ignore */
7769	case srm_DECRLCM:	/* ignore */
7770	case srm_DECRLM:	/* ignore */
7771	case srm_DECRPL:	/* ignore */
7772	case srm_DECVCCM:	/* ignore */
7773	case srm_DECXRLM:	/* ignore */
7774	default:
7775	    TRACE(("DATA_ERROR: unknown private code %d\n", code));
7776	    break;
7777	}
7778    }
7779}
7780
7781/*
7782 * process xterm private modes save
7783 */
7784static void
7785savemodes(XtermWidget xw)
7786{
7787    TScreen *screen = TScreenOf(xw);
7788    int i;
7789
7790    if_STATUS_LINE(screen, {
7791	return;
7792    });
7793    for (i = 0; i < nparam; i++) {
7794	int code = GetParam(i);
7795
7796	TRACE(("savemodes %d\n", code));
7797	switch ((DECSET_codes) code) {
7798	case srm_DECCKM:
7799	    DoSM(DP_DECCKM, xw->keyboard.flags & MODE_DECCKM);
7800	    break;
7801	case srm_DECANM:	/* ANSI/VT52 mode      */
7802	    /* no effect */
7803	    break;
7804	case srm_DECCOLM:
7805	    if (screen->c132)
7806		DoSM(DP_DECCOLM, xw->flags & IN132COLUMNS);
7807	    break;
7808	case srm_DECSCLM:	/* (slow scroll)        */
7809	    DoSM(DP_DECSCLM, xw->flags & SMOOTHSCROLL);
7810	    break;
7811	case srm_DECSCNM:
7812	    DoSM(DP_DECSCNM, xw->flags & REVERSE_VIDEO);
7813	    break;
7814	case srm_DECOM:
7815	    DoSM(DP_DECOM, xw->flags & ORIGIN);
7816	    break;
7817	case srm_DECAWM:
7818	    DoSM(DP_DECAWM, xw->flags & WRAPAROUND);
7819	    break;
7820	case srm_DECARM:
7821	    /* ignore autorepeat */
7822	    break;
7823	case srm_X10_MOUSE:	/* mouse bogus sequence */
7824	    DoSM(DP_X_X10MSE, screen->send_mouse_pos);
7825	    break;
7826#if OPT_TOOLBAR
7827	case srm_RXVT_TOOLBAR:
7828	    DoSM(DP_TOOLBAR, resource.toolBar);
7829	    break;
7830#else
7831	case srm_DECEDM:	/* vt330:edit */
7832	    break;
7833#endif
7834#if OPT_BLINK_CURS
7835	case srm_ATT610_BLINK:	/* AT&T 610: Start/stop blinking cursor */
7836	    if (SettableCursorBlink(screen)) {
7837		DoSM(DP_CRS_BLINK, screen->cursor_blink_esc);
7838	    }
7839	    break;
7840	case srm_CURSOR_BLINK_OPS:
7841	    /* intentionally ignored (this is user-preference) */
7842	    break;
7843	case srm_XOR_CURSOR_BLINKS:
7844	    /* intentionally ignored (this is user-preference) */
7845	    break;
7846#else
7847	case srm_DECKANAM:	/* vt382:Katakana shift */
7848	case srm_DECSCFDM:	/* vt330:space compression field delimiter */
7849	case srm_DECTEM:	/* vt330:transmission execution */
7850	    break;
7851#endif
7852	case srm_DECPFF:	/* print form feed */
7853	    DoSM(DP_PRN_FORMFEED, PrinterOf(screen).printer_formfeed);
7854	    break;
7855	case srm_DECPEX:	/* print extent */
7856	    DoSM(DP_PRN_EXTENT, PrinterOf(screen).printer_extent);
7857	    break;
7858	case srm_DECTCEM:	/* Show/hide cursor (VT200) */
7859	    DoSM(DP_CRS_VISIBLE, screen->cursor_set);
7860	    break;
7861	case srm_RXVT_SCROLLBAR:
7862	    DoSM(DP_RXVT_SCROLLBAR, (screen->fullVwin.sb_info.width != 0));
7863	    break;
7864#if OPT_SHIFT_FONTS
7865	case srm_RXVT_FONTSIZE:
7866	    DoSM(DP_RXVT_FONTSIZE, xw->misc.shift_fonts);
7867	    break;
7868#endif
7869#if OPT_TEK4014
7870	case srm_DECTEK:
7871	    DoSM(DP_DECTEK, TEK4014_ACTIVE(xw));
7872	    break;
7873#endif
7874	case srm_132COLS:	/* 132 column mode              */
7875	    DoSM(DP_X_DECCOLM, screen->c132);
7876	    break;
7877	case srm_CURSES_HACK:	/* curses hack                  */
7878	    DoSM(DP_X_MORE, screen->curses);
7879	    break;
7880	case srm_DECNRCM:	/* national charset (VT220) */
7881	    if (screen->vtXX_level >= 2) {
7882		DoSM(DP_DECNRCM, xw->flags & NATIONAL);
7883	    }
7884	    break;
7885#if OPT_PRINT_GRAPHICS
7886	case srm_DECGEPM:	/* Graphics Expanded Print Mode */
7887	    DoSM(DP_DECGEPM, screen->graphics_expanded_print_mode);
7888	    break;
7889#endif
7890	case srm_MARGIN_BELL:	/* margin bell (xterm) also DECGPCM (Graphics Print Color Mode) */
7891	    if_PRINT_GRAPHICS2(DoSM(DP_DECGPCM, screen->graphics_print_color_mode)) {
7892		DoSM(DP_X_MARGIN, screen->marginbell);
7893	    }
7894	    break;
7895	case srm_REVERSEWRAP:	/* reverse wraparound (xterm) also DECGPCS (Graphics Print Color Syntax) */
7896	    if_PRINT_GRAPHICS2(DoSM(DP_DECGPCS, screen->graphics_print_color_syntax)) {
7897		DoSM(DP_X_REVWRAP, xw->flags & REVERSEWRAP);
7898	    }
7899	    break;
7900	case srm_REVERSEWRAP2:	/* extended reverse wraparound (xterm) */
7901	    DoSM(DP_X_REVWRAP2, xw->flags & REVERSEWRAP2);
7902	    break;
7903#ifdef ALLOWLOGGING
7904	case srm_ALLOWLOGGING:	/* logging (xterm) also DECGPBM (Graphics Print Background Mode) */
7905	    if_PRINT_GRAPHICS2(DoSM(DP_DECGPBM, screen->graphics_print_background_mode)) {
7906#ifdef ALLOWLOGFILEONOFF
7907		DoSM(DP_X_LOGGING, screen->logging);
7908#endif /* ALLOWLOGFILEONOFF */
7909	    }
7910	    break;
7911#elif OPT_PRINT_GRAPHICS
7912	case srm_DECGPBM:	/* Graphics Print Background Mode */
7913	    DoSM(DP_DECGPBM, screen->graphics_print_background_mode);
7914	    break;
7915#endif /* ALLOWLOGGING */
7916	case srm_OPT_ALTBUF_CURSOR:	/* optional alternate buffer and clear (xterm) */
7917	    /* FALLTHRU */
7918	case srm_OPT_ALTBUF:	/* optional alternate buffer and clear (xterm) */
7919	    DoSM(DP_X_ALTBUF, screen->whichBuf);
7920	    break;
7921	case srm_ALTBUF:	/* alternate buffer (xterm) also DECGRPM (Graphics Rotated Print Mode) */
7922	    if_PRINT_GRAPHICS2(DoSM(DP_DECGRPM, screen->graphics_rotated_print_mode)) {
7923		DoSM(DP_X_ALTBUF, screen->whichBuf);
7924	    }
7925	    break;
7926	case srm_DECNKM:
7927	    DoSM(DP_DECKPAM, xw->keyboard.flags & MODE_DECKPAM);
7928	    break;
7929	case srm_DECBKM:	/* backarrow mapping */
7930	    DoSM(DP_DECBKM, xw->keyboard.flags & MODE_DECBKM);
7931	    break;
7932	case srm_DECLRMM:	/* left-right */
7933	    DoSM(DP_X_LRMM, LEFT_RIGHT);
7934	    break;
7935#if OPT_SIXEL_GRAPHICS
7936	case srm_DECSDM:	/* sixel display mode (no scroll) */
7937	    DoSM(DP_DECSDM, xw->keyboard.flags & MODE_DECSDM);
7938	    update_decsdm();
7939	    break;
7940#endif
7941	case srm_DECNCSM:	/* noclear */
7942	    DoSM(DP_X_NCSM, NOCLEAR_COLM);
7943	    break;
7944	case srm_VT200_MOUSE:	/* mouse bogus sequence         */
7945	    /* FALLTHRU */
7946	case srm_VT200_HIGHLIGHT_MOUSE:
7947	    /* FALLTHRU */
7948	case srm_BTN_EVENT_MOUSE:
7949	    /* FALLTHRU */
7950	case srm_ANY_EVENT_MOUSE:
7951	    DoSM(DP_X_MOUSE, screen->send_mouse_pos);
7952	    break;
7953#if OPT_FOCUS_EVENT
7954	case srm_FOCUS_EVENT_MOUSE:
7955	    DoSM(DP_X_FOCUS, screen->send_focus_pos);
7956	    break;
7957#endif
7958	case srm_EXT_MODE_MOUSE:
7959	    /* FALLTHRU */
7960	case srm_SGR_EXT_MODE_MOUSE:
7961	    /* FALLTHRU */
7962	case srm_URXVT_EXT_MODE_MOUSE:
7963	    /* FALLTHRU */
7964	case srm_PIXEL_POSITION_MOUSE:
7965	    DoSM(DP_X_EXT_MOUSE, screen->extend_coords);
7966	    break;
7967	case srm_ALTERNATE_SCROLL:
7968	    DoSM(DP_ALTERNATE_SCROLL, screen->alternateScroll);
7969	    break;
7970	case srm_RXVT_SCROLL_TTY_OUTPUT:
7971	    DoSM(DP_RXVT_SCROLL_TTY_OUTPUT, screen->scrollttyoutput);
7972	    break;
7973	case srm_RXVT_SCROLL_TTY_KEYPRESS:
7974	    DoSM(DP_RXVT_SCROLL_TTY_KEYPRESS, screen->scrollkey);
7975	    break;
7976	case srm_EIGHT_BIT_META:
7977	    DoSM(DP_EIGHT_BIT_META, screen->eight_bit_meta);
7978	    break;
7979#if OPT_NUM_LOCK
7980	case srm_REAL_NUMLOCK:
7981	    DoSM(DP_REAL_NUMLOCK, xw->misc.real_NumLock);
7982	    break;
7983	case srm_META_SENDS_ESC:
7984	    DoSM(DP_META_SENDS_ESC, screen->meta_sends_esc);
7985	    break;
7986#endif
7987	case srm_DELETE_IS_DEL:
7988	    DoSM(DP_DELETE_IS_DEL, screen->delete_is_del);
7989	    break;
7990#if OPT_NUM_LOCK
7991	case srm_ALT_SENDS_ESC:
7992	    DoSM(DP_ALT_SENDS_ESC, screen->alt_sends_esc);
7993	    break;
7994#endif
7995	case srm_KEEP_SELECTION:
7996	    DoSM(DP_KEEP_SELECTION, screen->keepSelection);
7997	    break;
7998	case srm_SELECT_TO_CLIPBOARD:
7999	    DoSM(DP_SELECT_TO_CLIPBOARD, screen->selectToClipboard);
8000	    break;
8001	case srm_BELL_IS_URGENT:
8002	    DoSM(DP_BELL_IS_URGENT, screen->bellIsUrgent);
8003	    break;
8004	case srm_POP_ON_BELL:
8005	    DoSM(DP_POP_ON_BELL, screen->poponbell);
8006	    break;
8007	case srm_KEEP_CLIPBOARD:
8008	    DoSM(DP_KEEP_CLIPBOARD, screen->keepClipboard);
8009	    break;
8010#if OPT_TCAP_FKEYS
8011	case srm_TCAP_FKEYS:
8012	    /* FALLTHRU */
8013#endif
8014#if OPT_SUN_FUNC_KEYS
8015	case srm_SUN_FKEYS:
8016	    /* FALLTHRU */
8017#endif
8018#if OPT_HP_FUNC_KEYS
8019	case srm_HP_FKEYS:
8020	    /* FALLTHRU */
8021#endif
8022#if OPT_SCO_FUNC_KEYS
8023	case srm_SCO_FKEYS:
8024	    /* FALLTHRU */
8025#endif
8026#if OPT_SUNPC_KBD
8027	case srm_VT220_FKEYS:
8028	    /* FALLTHRU */
8029#endif
8030	case srm_LEGACY_FKEYS:
8031	    DoSM(DP_KEYBOARD_TYPE, xw->keyboard.type);
8032	    break;
8033	case srm_ALLOW_ALTBUF:
8034	    DoSM(DP_ALLOW_ALTBUF, xw->misc.titeInhibit);
8035	    break;
8036	case srm_SAVE_CURSOR:
8037	    if (!xw->misc.titeInhibit) {
8038		CursorSave(xw);
8039	    }
8040	    break;
8041	case srm_FAST_SCROLL:
8042	    DoSM(DP_FAST_SCROLL, screen->fastscroll);
8043	    break;
8044#if OPT_PASTE64 || OPT_READLINE
8045	case srm_PASTE_IN_BRACKET:
8046	    SCREEN_FLAG_save(screen, paste_brackets);
8047	    break;
8048#endif
8049#if OPT_READLINE
8050	case srm_BUTTON1_MOVE_POINT:
8051	    SCREEN_FLAG_save(screen, click1_moves);
8052	    break;
8053	case srm_BUTTON2_MOVE_POINT:
8054	    SCREEN_FLAG_save(screen, paste_moves);
8055	    break;
8056	case srm_DBUTTON3_DELETE:
8057	    SCREEN_FLAG_save(screen, dclick3_deletes);
8058	    break;
8059	case srm_PASTE_QUOTE:
8060	    SCREEN_FLAG_save(screen, paste_quotes);
8061	    break;
8062	case srm_PASTE_LITERAL_NL:
8063	    SCREEN_FLAG_save(screen, paste_literal_nl);
8064	    break;
8065#endif /* OPT_READLINE */
8066#if OPT_GRAPHICS
8067	case srm_PRIVATE_COLOR_REGISTERS:	/* private color registers for each graphic */
8068	    TRACE(("save PRIVATE_COLOR_REGISTERS %s\n",
8069		   BtoS(screen->privatecolorregisters)));
8070	    DoSM(DP_X_PRIVATE_COLOR_REGISTERS, screen->privatecolorregisters);
8071	    update_privatecolorregisters();
8072	    break;
8073#endif
8074#if OPT_SIXEL_GRAPHICS
8075	case srm_SIXEL_SCROLLS_RIGHT:
8076	    TRACE(("save SIXEL_SCROLLS_RIGHT %s\n",
8077		   BtoS(screen->sixel_scrolls_right)));
8078	    DoSM(DP_SIXEL_SCROLLS_RIGHT, screen->sixel_scrolls_right);
8079	    break;
8080#endif
8081	case srm_DEC131TM:	/* ignore */
8082	case srm_DECAAM:	/* ignore */
8083	case srm_DECARSM:	/* ignore */
8084	case srm_DECATCBM:	/* ignore */
8085	case srm_DECATCUM:	/* ignore */
8086	case srm_DECBBSM:	/* ignore */
8087	case srm_DECCANSM:	/* ignore */
8088	case srm_DECCAPSLK:	/* ignore */
8089	case srm_DECCRTSM:	/* ignore */
8090	case srm_DECECM:	/* ignore */
8091	case srm_DECEKEM:	/* ignore */
8092	case srm_DECESKM:	/* ignore */
8093	case srm_DECFWM:	/* ignore */
8094	case srm_DECHCCM:	/* ignore */
8095	case srm_DECHDPXM:	/* ignore */
8096	case srm_DECHEM:	/* ignore */
8097	case srm_DECHWUM:	/* ignore */
8098	case srm_DECIPEM:	/* ignore */
8099	case srm_DECKBUM:	/* ignore */
8100	case srm_DECKKDM:	/* ignore */
8101	case srm_DECKLHIM:	/* ignore */
8102	case srm_DECKPM:	/* ignore */
8103	case srm_DECLTM:	/* ignore */
8104	case srm_DECMCM:	/* ignore */
8105	case srm_DECNAKB:	/* ignore */
8106	case srm_DECNULM:	/* ignore */
8107	case srm_DECNUMLK:	/* ignore */
8108	case srm_DECOSCNM:	/* ignore */
8109	case srm_DECPCCM:	/* ignore */
8110	case srm_DECRLCM:	/* ignore */
8111	case srm_DECRLM:	/* ignore */
8112	case srm_DECRPL:	/* ignore */
8113	case srm_DECVCCM:	/* ignore */
8114	case srm_DECXRLM:	/* ignore */
8115	default:
8116	    break;
8117	}
8118    }
8119}
8120
8121/*
8122 * process xterm private modes restore
8123 */
8124static void
8125restoremodes(XtermWidget xw)
8126{
8127    TScreen *screen = TScreenOf(xw);
8128    int i, j;
8129
8130    if_STATUS_LINE(screen, {
8131	return;
8132    });
8133    for (i = 0; i < nparam; i++) {
8134	int code = GetParam(i);
8135
8136	TRACE(("restoremodes %d\n", code));
8137	switch ((DECSET_codes) code) {
8138	case srm_DECCKM:
8139	    bitcpy(&xw->keyboard.flags,
8140		   screen->save_modes[DP_DECCKM], MODE_DECCKM);
8141	    update_appcursor();
8142	    break;
8143	case srm_DECANM:	/* ANSI/VT52 mode      */
8144	    /* no effect */
8145	    break;
8146	case srm_DECCOLM:
8147	    if (screen->c132) {
8148		if (!(xw->flags & NOCLEAR_COLM))
8149		    ClearScreen(xw);
8150		CursorSet(screen, 0, 0, xw->flags);
8151		if ((j = (screen->save_modes[DP_DECCOLM] & IN132COLUMNS)
8152		     ? 132 : 80) != ((xw->flags & IN132COLUMNS)
8153				     ? 132 : 80) || j != MaxCols(screen))
8154		    RequestResize(xw, -1, j, True);
8155		bitcpy(&xw->flags,
8156		       screen->save_modes[DP_DECCOLM],
8157		       IN132COLUMNS);
8158	    }
8159	    break;
8160	case srm_DECSCLM:	/* (slow scroll)        */
8161	    if (screen->save_modes[DP_DECSCLM] & SMOOTHSCROLL) {
8162		screen->jumpscroll = 0;
8163		if (screen->scroll_amt)
8164		    FlushScroll(xw);
8165	    } else
8166		screen->jumpscroll = 1;
8167	    bitcpy(&xw->flags, screen->save_modes[DP_DECSCLM], SMOOTHSCROLL);
8168	    update_jumpscroll();
8169	    break;
8170	case srm_DECSCNM:
8171	    if ((screen->save_modes[DP_DECSCNM] ^ xw->flags) & REVERSE_VIDEO) {
8172		bitcpy(&xw->flags, screen->save_modes[DP_DECSCNM], REVERSE_VIDEO);
8173		ReverseVideo(xw);
8174		/* update_reversevideo done in RevVid */
8175	    }
8176	    break;
8177	case srm_DECOM:
8178	    bitcpy(&xw->flags, screen->save_modes[DP_DECOM], ORIGIN);
8179	    CursorSet(screen, 0, 0, xw->flags);
8180	    break;
8181
8182	case srm_DECAWM:
8183	    bitcpy(&xw->flags, screen->save_modes[DP_DECAWM], WRAPAROUND);
8184	    update_autowrap();
8185	    break;
8186	case srm_DECARM:
8187	    /* ignore autorepeat */
8188	    break;
8189	case srm_X10_MOUSE:	/* MIT bogus sequence           */
8190	    DoRM0(DP_X_X10MSE, screen->send_mouse_pos);
8191	    really_set_mousemode(xw,
8192				 screen->send_mouse_pos != MOUSE_OFF,
8193				 (XtermMouseModes) screen->send_mouse_pos);
8194	    break;
8195#if OPT_TOOLBAR
8196	case srm_RXVT_TOOLBAR:
8197	    DoRM(DP_TOOLBAR, resource.toolBar);
8198	    ShowToolbar(resource.toolBar);
8199	    break;
8200#else
8201	case srm_DECEDM:	/* vt330:edit */
8202	    break;
8203#endif
8204#if OPT_BLINK_CURS
8205	case srm_ATT610_BLINK:	/* Start/stop blinking cursor */
8206	    if (SettableCursorBlink(screen)) {
8207		DoRM(DP_CRS_BLINK, screen->cursor_blink_esc);
8208		UpdateCursorBlink(xw);
8209	    }
8210	    break;
8211	case srm_CURSOR_BLINK_OPS:
8212	    /* intentionally ignored (this is user-preference) */
8213	    break;
8214	case srm_XOR_CURSOR_BLINKS:
8215	    /* intentionally ignored (this is user-preference) */
8216	    break;
8217#else
8218	case srm_DECKANAM:	/* vt382:Katakana shift */
8219	case srm_DECSCFDM:	/* vt330:space compression field delimiter */
8220	case srm_DECTEM:	/* vt330:transmission execution */
8221	    break;
8222#endif
8223	case srm_DECPFF:	/* print form feed */
8224	    DoRM(DP_PRN_FORMFEED, PrinterOf(screen).printer_formfeed);
8225	    break;
8226	case srm_DECPEX:	/* print extent */
8227	    DoRM(DP_PRN_EXTENT, PrinterOf(screen).printer_extent);
8228	    break;
8229	case srm_DECTCEM:	/* Show/hide cursor (VT200) */
8230	    DoRM(DP_CRS_VISIBLE, screen->cursor_set);
8231	    updateCursor(xw);
8232	    break;
8233	case srm_RXVT_SCROLLBAR:
8234	    if ((screen->fullVwin.sb_info.width != 0) !=
8235		screen->save_modes[DP_RXVT_SCROLLBAR]) {
8236		ToggleScrollBar(xw);
8237	    }
8238	    break;
8239#if OPT_SHIFT_FONTS
8240	case srm_RXVT_FONTSIZE:
8241	    DoRM(DP_RXVT_FONTSIZE, xw->misc.shift_fonts);
8242	    break;
8243#endif
8244#if OPT_TEK4014
8245	case srm_DECTEK:
8246	    if (!(screen->inhibit & I_TEK) &&
8247		(TEK4014_ACTIVE(xw) != (Boolean) screen->save_modes[DP_DECTEK])) {
8248		FlushLog(xw);
8249		TEK4014_ACTIVE(xw) = (Boolean) screen->save_modes[DP_DECTEK];
8250		update_vttekmode();
8251	    }
8252	    break;
8253#endif
8254	case srm_132COLS:	/* 132 column mode              */
8255	    DoRM(DP_X_DECCOLM, screen->c132);
8256	    update_allow132();
8257	    break;
8258	case srm_CURSES_HACK:	/* curses hack                  */
8259	    DoRM(DP_X_MORE, screen->curses);
8260	    update_cursesemul();
8261	    break;
8262	case srm_DECNRCM:	/* national charset (VT220) */
8263	    if (screen->vtXX_level >= 2) {
8264		if (bitcpy(&xw->flags, screen->save_modes[DP_DECNRCM], NATIONAL))
8265		    modified_DECNRCM(xw);
8266	    }
8267	    break;
8268#if OPT_PRINT_GRAPHICS
8269	case srm_DECGEPM:	/* Graphics Expanded Print Mode */
8270	    DoRM(DP_DECGEPM, screen->graphics_expanded_print_mode);
8271	    break;
8272#endif
8273	case srm_MARGIN_BELL:	/* margin bell (xterm) also DECGPCM (Graphics Print Color Mode) */
8274	    if_PRINT_GRAPHICS2(DoRM(DP_DECGPCM, screen->graphics_print_color_mode)) {
8275		if ((DoRM(DP_X_MARGIN, screen->marginbell)) == 0)
8276		    screen->bellArmed = -1;
8277		update_marginbell();
8278	    }
8279	    break;
8280	case srm_REVERSEWRAP:	/* reverse wraparound (xterm) also DECGPCS (Graphics Print Color Syntax) */
8281	    if_PRINT_GRAPHICS2(DoRM(DP_DECGPCS, screen->graphics_print_color_syntax)) {
8282		bitcpy(&xw->flags, screen->save_modes[DP_X_REVWRAP], REVERSEWRAP);
8283		update_reversewrap();
8284	    }
8285	    break;
8286	case srm_REVERSEWRAP2:	/* extended reverse wraparound (xterm) */
8287	    bitcpy(&xw->flags, screen->save_modes[DP_X_REVWRAP2], REVERSEWRAP2);
8288	    break;
8289#ifdef ALLOWLOGGING
8290	case srm_ALLOWLOGGING:	/* logging (xterm) also DECGPBM (Graphics Print Background Mode) */
8291	    if_PRINT_GRAPHICS2(DoRM(DP_DECGPBM, screen->graphics_print_background_mode)) {
8292#ifdef ALLOWLOGFILEONOFF
8293		if (screen->save_modes[DP_X_LOGGING])
8294		    StartLog(xw);
8295		else
8296		    CloseLog(xw);
8297#endif /* ALLOWLOGFILEONOFF */
8298		/* update_logging done by StartLog and CloseLog */
8299	    }
8300	    break;
8301#elif OPT_PRINT_GRAPHICS
8302	case srm_DECGPBM:	/* Graphics Print Background Mode */
8303	    DoRM(DP_DECGPBM, screen->graphics_print_background_mode);
8304	    break;
8305#endif /* ALLOWLOGGING */
8306	case srm_OPT_ALTBUF_CURSOR:	/* optional alternate buffer and clear (xterm) */
8307	    /* FALLTHRU */
8308	case srm_OPT_ALTBUF:	/* optional alternate buffer and clear (xterm) */
8309	    if (!xw->misc.titeInhibit) {
8310		if (screen->save_modes[DP_X_ALTBUF])
8311		    ToAlternate(xw, False);
8312		else
8313		    FromAlternate(xw, False);
8314		/* update_altscreen done by ToAlt and FromAlt */
8315	    } else if (screen->save_modes[DP_X_ALTBUF]) {
8316		do_ti_xtra_scroll(xw);
8317	    }
8318	    break;
8319	case srm_ALTBUF:	/* alternate buffer (xterm) also DECGRPM (Graphics Rotated Print Mode) */
8320	    if_PRINT_GRAPHICS2(DoRM(DP_DECGRPM, screen->graphics_rotated_print_mode)) {
8321		if (!xw->misc.titeInhibit) {
8322		    if (screen->save_modes[DP_X_ALTBUF])
8323			ToAlternate(xw, False);
8324		    else
8325			FromAlternate(xw, False);
8326		    /* update_altscreen done by ToAlt and FromAlt */
8327		} else if (screen->save_modes[DP_X_ALTBUF]) {
8328		    do_ti_xtra_scroll(xw);
8329		}
8330	    }
8331	    break;
8332	case srm_DECNKM:
8333	    bitcpy(&xw->flags, screen->save_modes[DP_DECKPAM], MODE_DECKPAM);
8334	    update_appkeypad();
8335	    break;
8336	case srm_DECBKM:	/* backarrow mapping */
8337	    bitcpy(&xw->flags, screen->save_modes[DP_DECBKM], MODE_DECBKM);
8338	    update_decbkm();
8339	    break;
8340	case srm_DECLRMM:	/* left-right */
8341	    bitcpy(&xw->flags, screen->save_modes[DP_X_LRMM], LEFT_RIGHT);
8342	    if (IsLeftRightMode(xw)) {
8343		xterm_ResetDouble(xw);
8344	    } else {
8345		reset_lr_margins(screen);
8346	    }
8347	    break;
8348#if OPT_SIXEL_GRAPHICS
8349	case srm_DECSDM:	/* sixel display mode (no scroll) */
8350	    bitcpy(&xw->keyboard.flags, screen->save_modes[DP_DECSDM], MODE_DECSDM);
8351	    update_decsdm();
8352	    break;
8353#endif
8354	case srm_DECNCSM:	/* noclear */
8355	    bitcpy(&xw->flags, screen->save_modes[DP_X_NCSM], NOCLEAR_COLM);
8356	    break;
8357	case srm_VT200_MOUSE:	/* mouse bogus sequence         */
8358	    /* FALLTHRU */
8359	case srm_VT200_HIGHLIGHT_MOUSE:
8360	    /* FALLTHRU */
8361	case srm_BTN_EVENT_MOUSE:
8362	    /* FALLTHRU */
8363	case srm_ANY_EVENT_MOUSE:
8364	    DoRM0(DP_X_MOUSE, screen->send_mouse_pos);
8365	    really_set_mousemode(xw,
8366				 screen->send_mouse_pos != MOUSE_OFF,
8367				 (XtermMouseModes) screen->send_mouse_pos);
8368	    break;
8369#if OPT_FOCUS_EVENT
8370	case srm_FOCUS_EVENT_MOUSE:
8371	    DoRM(DP_X_FOCUS, screen->send_focus_pos);
8372	    break;
8373#endif
8374	case srm_EXT_MODE_MOUSE:
8375	    /* FALLTHRU */
8376	case srm_SGR_EXT_MODE_MOUSE:
8377	    /* FALLTHRU */
8378	case srm_URXVT_EXT_MODE_MOUSE:
8379	    /* FALLTHRU */
8380	case srm_PIXEL_POSITION_MOUSE:
8381	    DoRM(DP_X_EXT_MOUSE, screen->extend_coords);
8382	    break;
8383	case srm_ALLOW_ALTBUF:
8384	    DoRM(DP_ALLOW_ALTBUF, xw->misc.titeInhibit);
8385	    if (xw->misc.titeInhibit)
8386		FromAlternate(xw, False);
8387	    update_titeInhibit();
8388	    break;
8389	case srm_SAVE_CURSOR:
8390	    if (!xw->misc.titeInhibit) {
8391		CursorRestore(xw);
8392	    }
8393	    break;
8394	case srm_FAST_SCROLL:
8395	    DoRM(DP_FAST_SCROLL, screen->fastscroll);
8396	    break;
8397	case srm_ALTERNATE_SCROLL:
8398	    DoRM(DP_ALTERNATE_SCROLL, screen->alternateScroll);
8399	    break;
8400	case srm_RXVT_SCROLL_TTY_OUTPUT:
8401	    DoRM(DP_RXVT_SCROLL_TTY_OUTPUT, screen->scrollttyoutput);
8402	    update_scrollttyoutput();
8403	    break;
8404	case srm_RXVT_SCROLL_TTY_KEYPRESS:
8405	    DoRM(DP_RXVT_SCROLL_TTY_KEYPRESS, screen->scrollkey);
8406	    update_scrollkey();
8407	    break;
8408	case srm_EIGHT_BIT_META:
8409	    DoRM(DP_EIGHT_BIT_META, screen->eight_bit_meta);
8410	    break;
8411#if OPT_NUM_LOCK
8412	case srm_REAL_NUMLOCK:
8413	    DoRM(DP_REAL_NUMLOCK, xw->misc.real_NumLock);
8414	    update_num_lock();
8415	    break;
8416	case srm_META_SENDS_ESC:
8417	    DoRM(DP_META_SENDS_ESC, screen->meta_sends_esc);
8418	    update_meta_esc();
8419	    break;
8420#endif
8421	case srm_DELETE_IS_DEL:
8422	    DoRM(DP_DELETE_IS_DEL, screen->delete_is_del);
8423	    update_delete_del();
8424	    break;
8425#if OPT_NUM_LOCK
8426	case srm_ALT_SENDS_ESC:
8427	    DoRM(DP_ALT_SENDS_ESC, screen->alt_sends_esc);
8428	    update_alt_esc();
8429	    break;
8430#endif
8431	case srm_KEEP_SELECTION:
8432	    DoRM(DP_KEEP_SELECTION, screen->keepSelection);
8433	    update_keepSelection();
8434	    break;
8435	case srm_SELECT_TO_CLIPBOARD:
8436	    DoRM(DP_SELECT_TO_CLIPBOARD, screen->selectToClipboard);
8437	    update_selectToClipboard();
8438	    break;
8439	case srm_BELL_IS_URGENT:
8440	    DoRM(DP_BELL_IS_URGENT, screen->bellIsUrgent);
8441	    update_bellIsUrgent();
8442	    break;
8443	case srm_POP_ON_BELL:
8444	    DoRM(DP_POP_ON_BELL, screen->poponbell);
8445	    update_poponbell();
8446	    break;
8447	case srm_KEEP_CLIPBOARD:
8448	    DoRM(DP_KEEP_CLIPBOARD, screen->keepClipboard);
8449	    update_keepClipboard();
8450	    break;
8451#if OPT_TCAP_FKEYS
8452	case srm_TCAP_FKEYS:
8453	    /* FALLTHRU */
8454#endif
8455#if OPT_SUN_FUNC_KEYS
8456	case srm_SUN_FKEYS:
8457	    /* FALLTHRU */
8458#endif
8459#if OPT_HP_FUNC_KEYS
8460	case srm_HP_FKEYS:
8461	    /* FALLTHRU */
8462#endif
8463#if OPT_SCO_FUNC_KEYS
8464	case srm_SCO_FKEYS:
8465	    /* FALLTHRU */
8466#endif
8467#if OPT_SUNPC_KBD
8468	case srm_VT220_FKEYS:
8469	    /* FALLTHRU */
8470#endif
8471	case srm_LEGACY_FKEYS:
8472	    xw->keyboard.type = (xtermKeyboardType) screen->save_modes[DP_KEYBOARD_TYPE];
8473	    break;
8474#if OPT_PASTE64 || OPT_READLINE
8475	case srm_PASTE_IN_BRACKET:
8476	    SCREEN_FLAG_restore(screen, paste_brackets);
8477	    break;
8478#endif
8479#if OPT_READLINE
8480	case srm_BUTTON1_MOVE_POINT:
8481	    SCREEN_FLAG_restore(screen, click1_moves);
8482	    break;
8483	case srm_BUTTON2_MOVE_POINT:
8484	    SCREEN_FLAG_restore(screen, paste_moves);
8485	    break;
8486	case srm_DBUTTON3_DELETE:
8487	    SCREEN_FLAG_restore(screen, dclick3_deletes);
8488	    break;
8489	case srm_PASTE_QUOTE:
8490	    SCREEN_FLAG_restore(screen, paste_quotes);
8491	    break;
8492	case srm_PASTE_LITERAL_NL:
8493	    SCREEN_FLAG_restore(screen, paste_literal_nl);
8494	    break;
8495#endif /* OPT_READLINE */
8496#if OPT_GRAPHICS
8497	case srm_PRIVATE_COLOR_REGISTERS:	/* private color registers for each graphic */
8498	    TRACE(("restore PRIVATE_COLOR_REGISTERS before: %s\n",
8499		   BtoS(screen->privatecolorregisters)));
8500	    DoRM(DP_X_PRIVATE_COLOR_REGISTERS, screen->privatecolorregisters);
8501	    TRACE(("restore PRIVATE_COLOR_REGISTERS after: %s\n",
8502		   BtoS(screen->privatecolorregisters)));
8503	    update_privatecolorregisters();
8504	    break;
8505#endif
8506#if OPT_SIXEL_GRAPHICS
8507	case srm_SIXEL_SCROLLS_RIGHT:
8508	    TRACE(("restore SIXEL_SCROLLS_RIGHT before: %s\n",
8509		   BtoS(screen->sixel_scrolls_right)));
8510	    DoRM(DP_SIXEL_SCROLLS_RIGHT, screen->sixel_scrolls_right);
8511	    TRACE(("restore SIXEL_SCROLLS_RIGHT after: %s\n",
8512		   BtoS(screen->sixel_scrolls_right)));
8513	    break;
8514#endif
8515	case srm_DEC131TM:	/* ignore */
8516	case srm_DECAAM:	/* ignore */
8517	case srm_DECARSM:	/* ignore */
8518	case srm_DECATCBM:	/* ignore */
8519	case srm_DECATCUM:	/* ignore */
8520	case srm_DECBBSM:	/* ignore */
8521	case srm_DECCANSM:	/* ignore */
8522	case srm_DECCAPSLK:	/* ignore */
8523	case srm_DECCRTSM:	/* ignore */
8524	case srm_DECECM:	/* ignore */
8525	case srm_DECEKEM:	/* ignore */
8526	case srm_DECESKM:	/* ignore */
8527	case srm_DECFWM:	/* ignore */
8528	case srm_DECHCCM:	/* ignore */
8529	case srm_DECHDPXM:	/* ignore */
8530	case srm_DECHEM:	/* ignore */
8531	case srm_DECHWUM:	/* ignore */
8532	case srm_DECIPEM:	/* ignore */
8533	case srm_DECKBUM:	/* ignore */
8534	case srm_DECKKDM:	/* ignore */
8535	case srm_DECKLHIM:	/* ignore */
8536	case srm_DECKPM:	/* ignore */
8537	case srm_DECLTM:	/* ignore */
8538	case srm_DECMCM:	/* ignore */
8539	case srm_DECNAKB:	/* ignore */
8540	case srm_DECNULM:	/* ignore */
8541	case srm_DECNUMLK:	/* ignore */
8542	case srm_DECOSCNM:	/* ignore */
8543	case srm_DECPCCM:	/* ignore */
8544	case srm_DECRLCM:	/* ignore */
8545	case srm_DECRLM:	/* ignore */
8546	case srm_DECRPL:	/* ignore */
8547	case srm_DECVCCM:	/* ignore */
8548	case srm_DECXRLM:	/* ignore */
8549	default:
8550	    break;
8551	}
8552    }
8553}
8554
8555/*
8556 * Convert an XTextProperty to a string.
8557 *
8558 * This frees the data owned by the XTextProperty, and returns in its place the
8559 * string, which must be freed by the caller.
8560 */
8561static char *
8562property_to_string(XtermWidget xw, XTextProperty * text)
8563{
8564    TScreen *screen = TScreenOf(xw);
8565    Display *dpy = screen->display;
8566    char *result = NULL;
8567    char **list = NULL;
8568    int length = 0;
8569    int rc;
8570
8571    TRACE(("property_to_string value %p, encoding %s, format %d, nitems %ld\n",
8572	   text->value,
8573	   TraceAtomName(dpy, text->encoding),
8574	   text->format,
8575	   text->nitems));
8576
8577#if OPT_WIDE_CHARS
8578    /*
8579     * We will use the XmbTextPropertyToTextList call to extract UTF-8 data.
8580     * The xtermUtf8ToTextList() call is used to convert UTF-8 explicitly to
8581     * ISO-8859-1.
8582     */
8583    rc = -1;
8584    if ((text->format != 8)
8585	|| IsTitleMode(xw, tmGetUtf8)
8586	|| (text->encoding == XA_UTF8_STRING(dpy) &&
8587	    !(screen->wide_chars || screen->c1_printable) &&
8588	    (rc = xtermUtf8ToTextList(xw, text, &list, &length)) < 0)
8589	|| (rc < 0))
8590#endif
8591	if ((rc = XmbTextPropertyToTextList(dpy, text, &list, &length)) < 0)
8592	    rc = XTextPropertyToStringList(text, &list, &length);
8593
8594    if (rc >= 0) {
8595	int n, c, pass;
8596	size_t need;
8597
8598	for (pass = 0; pass < 2; ++pass) {
8599	    for (n = 0, need = 0; n < length; n++) {
8600		char *s = list[n];
8601		while ((c = *s++) != '\0') {
8602		    if (pass)
8603			result[need] = (char) c;
8604		    ++need;
8605		}
8606	    }
8607	    if (pass)
8608		result[need] = '\0';
8609	    else
8610		result = malloc(need + 1);
8611	    if (result == NULL)
8612		break;
8613	}
8614	XFreeStringList(list);
8615    }
8616    if (text->value != NULL)
8617	XFree(text->value);
8618
8619    return result;
8620}
8621
8622static char *
8623get_icon_label(XtermWidget xw)
8624{
8625    XTextProperty text;
8626    char *result = NULL;
8627
8628    if (XGetWMIconName(TScreenOf(xw)->display, VShellWindow(xw), &text)) {
8629	result = property_to_string(xw, &text);
8630    }
8631    return result;
8632}
8633
8634static char *
8635get_window_label(XtermWidget xw)
8636{
8637    XTextProperty text;
8638    char *result = NULL;
8639
8640    if (XGetWMName(TScreenOf(xw)->display, VShellWindow(xw), &text)) {
8641	result = property_to_string(xw, &text);
8642    }
8643    return result;
8644}
8645
8646/*
8647 * Report window label (icon or title) in dtterm protocol
8648 * ESC ] code label ESC backslash
8649 */
8650static void
8651report_win_label(XtermWidget xw,
8652		 int code,
8653		 char *text)
8654{
8655    unparseputc(xw, ANSI_ESC);
8656    unparseputc(xw, ']');
8657    unparseputc(xw, code);
8658
8659    if (text != NULL) {
8660	int copy = IsTitleMode(xw, tmGetBase16);
8661	if (copy) {
8662	    TRACE(("Encoding hex:%s\n", text));
8663	    text = x_encode_hex(text);
8664	}
8665	unparseputs(xw, text);
8666	if (copy)
8667	    free(text);
8668    }
8669
8670    unparseputc(xw, ANSI_ESC);
8671    unparseputc(xw, '\\');	/* should be ST */
8672    unparse_end(xw);
8673}
8674
8675/*
8676 * Window operations (from CDE dtterm description, as well as extensions).
8677 * See also "allowWindowOps" resource.
8678 */
8679static void
8680window_ops(XtermWidget xw)
8681{
8682    TScreen *screen = TScreenOf(xw);
8683    XWindowChanges values;
8684    XWindowAttributes win_attrs;
8685#if OPT_MAXIMIZE
8686    unsigned root_width;
8687    unsigned root_height;
8688#endif
8689    int code = zero_if_default(0);
8690    char *label;
8691
8692    TRACE(("window_ops %d\n", code));
8693    switch (code) {
8694    case ewRestoreWin:		/* Restore (de-iconify) window */
8695	if (AllowWindowOps(xw, ewRestoreWin)) {
8696	    xtermDeiconify(xw);
8697	}
8698	break;
8699
8700    case ewMinimizeWin:	/* Minimize (iconify) window */
8701	if (AllowWindowOps(xw, ewMinimizeWin)) {
8702	    xtermIconify(xw);
8703	}
8704	break;
8705
8706    case ewSetWinPosition:	/* Move the window to the given position */
8707	if (AllowWindowOps(xw, ewSetWinPosition)) {
8708	    unsigned value_mask;
8709
8710	    values.x = (Position) zero_if_default(1);
8711	    values.y = (Position) zero_if_default(2);
8712	    TRACE(("...move window to %d,%d\n", values.x, values.y));
8713	    value_mask = (CWX | CWY);
8714	    XReconfigureWMWindow(screen->display,
8715				 VShellWindow(xw),
8716				 DefaultScreen(screen->display),
8717				 value_mask,
8718				 &values);
8719	}
8720	break;
8721
8722    case ewSetWinSizePixels:	/* Resize the window to given size in pixels */
8723	if (AllowWindowOps(xw, ewSetWinSizePixels)) {
8724	    RequestResize(xw, optional_param(1), optional_param(2), False);
8725	}
8726	break;
8727
8728    case ewRaiseWin:		/* Raise the window to the front of the stack */
8729	if (AllowWindowOps(xw, ewRaiseWin)) {
8730	    TRACE(("...raise window\n"));
8731	    XRaiseWindow(screen->display, VShellWindow(xw));
8732	}
8733	break;
8734
8735    case ewLowerWin:		/* Lower the window to the bottom of the stack */
8736	if (AllowWindowOps(xw, ewLowerWin)) {
8737	    TRACE(("...lower window\n"));
8738	    XLowerWindow(screen->display, VShellWindow(xw));
8739	}
8740	break;
8741
8742    case ewRefreshWin:		/* Refresh the window */
8743	if (AllowWindowOps(xw, ewRefreshWin)) {
8744	    TRACE(("...redraw window\n"));
8745	    Redraw();
8746	}
8747	break;
8748
8749    case ewSetWinSizeChars:	/* Resize the text-area, in characters */
8750	if (AllowWindowOps(xw, ewSetWinSizeChars)) {
8751	    RequestResize(xw, optional_param(1), optional_param(2), True);
8752	}
8753	break;
8754
8755#if OPT_MAXIMIZE
8756    case ewMaximizeWin:	/* Maximize or restore */
8757	if (AllowWindowOps(xw, ewMaximizeWin)) {
8758	    RequestMaximize(xw, zero_if_default(1));
8759	}
8760	break;
8761    case ewFullscreenWin:	/* Fullscreen or restore */
8762	if (AllowWindowOps(xw, ewFullscreenWin)) {
8763	    switch (zero_if_default(1)) {
8764	    default:
8765		RequestMaximize(xw, 0);
8766		break;
8767	    case 1:
8768		RequestMaximize(xw, 1);
8769		break;
8770	    case 2:
8771		RequestMaximize(xw, !(screen->restore_data));
8772		break;
8773	    }
8774	}
8775	break;
8776#endif
8777
8778    case ewGetWinState:	/* Report the window's state */
8779	if (AllowWindowOps(xw, ewGetWinState)) {
8780	    TRACE(("...get window attributes\n"));
8781	    init_reply(ANSI_CSI);
8782	    reply.a_nparam = 1;
8783	    reply.a_param[0] = (ParmType) (xtermIsIconified(xw) ? 2 : 1);
8784	    reply.a_final = 't';
8785	    unparseseq(xw, &reply);
8786	}
8787	break;
8788
8789    case ewGetWinPosition:	/* Report the window's position */
8790	if (AllowWindowOps(xw, ewGetWinPosition)) {
8791	    Window win;
8792	    Window result_win;
8793	    int result_y, result_x;
8794
8795	    TRACE(("...get window position\n"));
8796	    init_reply(ANSI_CSI);
8797	    reply.a_nparam = 3;
8798	    reply.a_param[0] = 3;
8799	    switch (zero_if_default(1)) {
8800	    case 2:		/* report the text-window's position */
8801		result_y = 0;
8802		result_x = 0;
8803		{
8804		    Widget mw;
8805		    for (mw = (Widget) xw; mw != NULL; mw = XtParent(mw)) {
8806			result_x += mw->core.x;
8807			result_y += mw->core.y;
8808			if (mw == SHELL_OF(xw))
8809			    break;
8810		    }
8811		}
8812		result_x += OriginX(screen);
8813		result_y += OriginY(screen);
8814		break;
8815	    default:
8816		win = WMFrameWindow(xw);
8817		xtermGetWinAttrs(screen->display,
8818				 win,
8819				 &win_attrs);
8820		XTranslateCoordinates(screen->display,
8821				      VShellWindow(xw),
8822				      win_attrs.root,
8823				      -win_attrs.border_width,
8824				      -win_attrs.border_width,
8825				      &result_x, &result_y, &result_win);
8826		TRACE(("translated position %d,%d vs %d,%d\n",
8827		       result_y, result_x,
8828		       win_attrs.y, win_attrs.x));
8829		if (!discount_frame_extents(xw, &result_y, &result_x)) {
8830		    TRACE(("...cancelled translation\n"));
8831		    result_y = win_attrs.y;
8832		    result_x = win_attrs.x;
8833		}
8834		break;
8835	    }
8836	    reply.a_param[1] = (ParmType) result_x;
8837	    reply.a_param[2] = (ParmType) result_y;
8838	    reply.a_final = 't';
8839	    unparseseq(xw, &reply);
8840	}
8841	break;
8842
8843    case ewGetWinSizePixels:	/* Report the window's size in pixels */
8844	if (AllowWindowOps(xw, ewGetWinSizePixels)) {
8845	    ParmType high = (ParmType) Height(screen);
8846	    ParmType wide = (ParmType) Width(screen);
8847
8848	    TRACE(("...get window size in pixels\n"));
8849	    init_reply(ANSI_CSI);
8850	    reply.a_nparam = 3;
8851	    reply.a_param[0] = 4;
8852	    switch (zero_if_default(1)) {
8853	    case 2:		/* report the shell-window's size */
8854		xtermGetWinAttrs(screen->display,
8855				 WMFrameWindow(xw),
8856				 &win_attrs);
8857		high = (ParmType) win_attrs.height;
8858		wide = (ParmType) win_attrs.width;
8859		/* FALLTHRU */
8860	    default:
8861		reply.a_param[1] = high;
8862		reply.a_param[2] = wide;
8863		break;
8864	    }
8865	    reply.a_final = 't';
8866	    unparseseq(xw, &reply);
8867	}
8868	break;
8869
8870#if OPT_MAXIMIZE
8871    case ewGetScreenSizePixels:	/* Report the screen's size, in Pixels */
8872	if (AllowWindowOps(xw, ewGetScreenSizePixels)) {
8873	    TRACE(("...get screen size in pixels\n"));
8874	    (void) QueryMaximize(xw, &root_width, &root_height);
8875	    init_reply(ANSI_CSI);
8876	    reply.a_nparam = 3;
8877	    reply.a_param[0] = 5;
8878	    reply.a_param[1] = (ParmType) root_height;
8879	    reply.a_param[2] = (ParmType) root_width;
8880	    reply.a_final = 't';
8881	    unparseseq(xw, &reply);
8882	}
8883	break;
8884    case ewGetCharSizePixels:	/* Report the font's size, in pixel */
8885	if (AllowWindowOps(xw, ewGetScreenSizeChars)) {
8886	    TRACE(("...get font size in pixels\n"));
8887	    TRACE(("...using font size %dx%d\n",
8888		   FontHeight(screen),
8889		   FontWidth(screen)));
8890	    init_reply(ANSI_CSI);
8891	    reply.a_nparam = 3;
8892	    reply.a_param[0] = 6;
8893	    reply.a_param[1] = (ParmType) FontHeight(screen);
8894	    reply.a_param[2] = (ParmType) FontWidth(screen);
8895	    reply.a_final = 't';
8896	    unparseseq(xw, &reply);
8897	}
8898	break;
8899#endif
8900
8901    case ewGetWinSizeChars:	/* Report the text's size in characters */
8902	if (AllowWindowOps(xw, ewGetWinSizeChars)) {
8903	    TRACE(("...get window size in characters\n"));
8904	    init_reply(ANSI_CSI);
8905	    reply.a_nparam = 3;
8906	    reply.a_param[0] = 8;
8907	    reply.a_param[1] = (ParmType) MaxRows(screen);
8908	    reply.a_param[2] = (ParmType) MaxCols(screen);
8909	    reply.a_final = 't';
8910	    unparseseq(xw, &reply);
8911	}
8912	break;
8913
8914#if OPT_MAXIMIZE
8915    case ewGetScreenSizeChars:	/* Report the screen's size, in characters */
8916	if (AllowWindowOps(xw, ewGetScreenSizeChars)) {
8917	    TRACE(("...get screen size in characters\n"));
8918	    TRACE(("...using font size %dx%d\n",
8919		   FontHeight(screen),
8920		   FontWidth(screen)));
8921	    (void) QueryMaximize(xw, &root_width, &root_height);
8922	    init_reply(ANSI_CSI);
8923	    reply.a_nparam = 3;
8924	    reply.a_param[0] = 9;
8925	    reply.a_param[1] = (ParmType) (root_height
8926					   / (unsigned) FontHeight(screen));
8927	    reply.a_param[2] = (ParmType) (root_width
8928					   / (unsigned) FontWidth(screen));
8929	    reply.a_final = 't';
8930	    unparseseq(xw, &reply);
8931	}
8932	break;
8933#endif
8934
8935    case ewGetIconTitle:	/* Report the icon's label */
8936	if (AllowWindowOps(xw, ewGetIconTitle)) {
8937	    TRACE(("...get icon's label\n"));
8938	    report_win_label(xw, 'L', label = get_icon_label(xw));
8939	    free(label);
8940	}
8941	break;
8942
8943    case ewGetWinTitle:	/* Report the window's title */
8944	if (AllowWindowOps(xw, ewGetWinTitle)) {
8945	    TRACE(("...get window's label\n"));
8946	    report_win_label(xw, 'l', label = get_window_label(xw));
8947	    free(label);
8948	}
8949	break;
8950
8951#define WhichTitle(n) \
8952	((n) == 0 \
8953	 ? "window/icon titles" \
8954	 : ((n) == 1 \
8955	    ? "icon title" \
8956	    : ((n) == 2 \
8957	       ? "window title" \
8958	       : "no titles")))
8959
8960    case ewPushTitle:		/* save the window's title(s) on stack */
8961	if (AllowWindowOps(xw, ewPushTitle)) {
8962	    SaveTitle item;
8963
8964	    TRACE(("...push %s onto stack\n", WhichTitle(zero_if_default(1))));
8965	    memset(&item, 0, sizeof(item));
8966	    switch (zero_if_default(1)) {
8967	    case 0:
8968		item.iconName = get_icon_label(xw);
8969		item.windowName = get_window_label(xw);
8970		break;
8971	    case 1:
8972		item.iconName = get_icon_label(xw);
8973		break;
8974	    case 2:
8975		item.windowName = get_window_label(xw);
8976		break;
8977	    }
8978	    xtermPushTitle(screen, zero_if_default(2), &item);
8979	}
8980	break;
8981
8982    case ewPopTitle:		/* restore the window's title(s) from stack */
8983	if (AllowWindowOps(xw, ewPopTitle)) {
8984	    SaveTitle item;
8985
8986	    TRACE(("...%s %s off stack\n",
8987		   (zero_if_default(2)
8988		    ? "get"
8989		    : "pop"),
8990		   WhichTitle(zero_if_default(1))));
8991
8992	    if (xtermPopTitle(screen, zero_if_default(2), &item)) {
8993		switch (zero_if_default(1)) {
8994		case 0:
8995		    ChangeIconName(xw, item.iconName);
8996		    ChangeTitle(xw, item.windowName);
8997		    break;
8998		case 1:
8999		    ChangeIconName(xw, item.iconName);
9000		    break;
9001		case 2:
9002		    ChangeTitle(xw, item.windowName);
9003		    break;
9004		}
9005		if (!zero_if_default(2))
9006		    xtermFreeTitle(&item);
9007	    }
9008	}
9009	break;
9010
9011    default:			/* DECSLPP (24, 25, 36, 48, 72, 144) */
9012	if (AllowWindowOps(xw, ewSetWinLines)) {
9013	    if (code >= 24)
9014		RequestResize(xw, code, -1, True);
9015	}
9016	break;
9017    }
9018}
9019
9020/*
9021 * set a bit in a word given a pointer to the word and a mask.
9022 */
9023static int
9024bitset(unsigned *p, unsigned mask)
9025{
9026    unsigned before = *p;
9027    *p |= mask;
9028    return (before != *p);
9029}
9030
9031/*
9032 * clear a bit in a word given a pointer to the word and a mask.
9033 */
9034static int
9035bitclr(unsigned *p, unsigned mask)
9036{
9037    unsigned before = *p;
9038    *p &= ~mask;
9039    return (before != *p);
9040}
9041
9042/*
9043 * Copy bits from one word to another, given a mask
9044 */
9045static int
9046bitcpy(unsigned *p, unsigned q, unsigned mask)
9047{
9048    unsigned before = *p;
9049    bitclr(p, mask);
9050    bitset(p, q & mask);
9051    return (before != *p);
9052}
9053
9054void
9055unparseputc1(XtermWidget xw, int c)
9056{
9057    if (c >= 0x80 && c <= 0x9F) {
9058	if (!TScreenOf(xw)->control_eight_bits) {
9059	    unparseputc(xw, ANSI_ESC);
9060	    c = c - 0x40;
9061	}
9062    }
9063    unparseputc(xw, c);
9064}
9065
9066void
9067unparseseq(XtermWidget xw, ANSI *ap)
9068{
9069    int c;
9070
9071    assert(ap->a_nparam < NPARAM);
9072    unparseputc1(xw, c = ap->a_type);
9073    if (c == ANSI_ESC
9074	|| c == ANSI_DCS
9075	|| c == ANSI_CSI
9076	|| c == ANSI_OSC
9077	|| c == ANSI_PM
9078	|| c == ANSI_APC
9079	|| c == ANSI_SS3) {
9080	int i;
9081	int inters;
9082	char temp[8];
9083
9084	if (ap->a_pintro != 0)
9085	    unparseputc(xw, ap->a_pintro);
9086	for (i = 0; i < ap->a_nparam; ++i) {
9087	    if (i != 0) {
9088		if (ap->a_radix[i] == 1 || ap->a_radix[i - 1] == 1) {
9089		    ;
9090		} else if (ap->a_delim) {
9091		    unparseputs(xw, ap->a_delim);
9092		} else {
9093		    unparseputc(xw, ';');
9094		}
9095	    }
9096	    switch (ap->a_radix[i]) {
9097	    case 16:
9098		sprintf(temp, "%04X", UParmOf(ap->a_param[i]));
9099		unparseputs(xw, temp);
9100		break;
9101	    case 1:
9102		unparseputc(xw, ap->a_param[i]);
9103		break;
9104	    default:
9105		unparseputn(xw, UParmOf(ap->a_param[i]));
9106		break;
9107	    }
9108	}
9109	if ((inters = ap->a_inters) != 0) {
9110	    for (i = 3; i >= 0; --i) {
9111		c = CharOf(inters >> (8 * i));
9112		if (c != 0)
9113		    unparseputc(xw, c);
9114	    }
9115	}
9116	switch (ap->a_type) {
9117	case ANSI_DCS:
9118	    /* FALLTHRU */
9119	case ANSI_OSC:
9120	    /* FALLTHRU */
9121	case ANSI_PM:
9122	    /* FALLTHRU */
9123	case ANSI_APC:
9124	    unparseputc1(xw, ANSI_ST);
9125	    break;
9126	default:
9127	    unparseputc(xw, (char) ap->a_final);
9128	    break;
9129	}
9130    }
9131    unparse_end(xw);
9132}
9133
9134void
9135unparseputn(XtermWidget xw, unsigned n)
9136{
9137    unsigned q;
9138
9139    q = n / 10;
9140    if (q != 0)
9141	unparseputn(xw, q);
9142    unparseputc(xw, (char) ('0' + (n % 10)));
9143}
9144
9145void
9146unparseputs(XtermWidget xw, const char *s)
9147{
9148    if (s != NULL) {
9149	while (*s)
9150	    unparseputc(xw, *s++);
9151    }
9152}
9153
9154void
9155unparseputc(XtermWidget xw, int c)
9156{
9157    TScreen *screen = TScreenOf(xw);
9158    IChar *buf = screen->unparse_bfr;
9159    unsigned len;
9160
9161    if ((screen->unparse_len + 2) >= screen->unparse_max)
9162	unparse_end(xw);
9163
9164    len = screen->unparse_len;
9165
9166#if OPT_TCAP_QUERY
9167    /*
9168     * If we're returning a termcap string, it has to be translated since
9169     * a DCS must not contain any characters except for the normal 7-bit
9170     * printable ASCII (counting tab, carriage return, etc).  For now,
9171     * just use hexadecimal for the whole thing.
9172     */
9173    if (screen->tc_query_code >= 0) {
9174	char tmp[3];
9175	sprintf(tmp, "%02X", (unsigned) (c & 0xFF));
9176	buf[len++] = CharOf(tmp[0]);
9177	buf[len++] = CharOf(tmp[1]);
9178    } else
9179#endif
9180    if ((buf[len++] = (IChar) c) == '\r' && (xw->flags & LINEFEED)) {
9181	buf[len++] = '\n';
9182    }
9183
9184    screen->unparse_len = len;
9185
9186    /* If send/receive mode is reset, we echo characters locally */
9187    if ((xw->keyboard.flags & MODE_SRM) == 0) {
9188	doparsing(xw, (unsigned) c, &myState);
9189    }
9190}
9191
9192void
9193unparse_end(XtermWidget xw)
9194{
9195    TScreen *screen = TScreenOf(xw);
9196
9197#if OPT_TCAP_QUERY
9198    /*
9199     * tcap-query works by simulating key-presses, which ordinarily would be
9200     * flushed out at the end of each key.  For better efficiency, do not do
9201     * the flush unless we are about to fill the buffer used to capture the
9202     * response.
9203     */
9204    if ((screen->tc_query_code >= 0)
9205	&& (screen->unparse_len + 2 < screen->unparse_max)) {
9206	return;
9207    }
9208#endif
9209    if (screen->unparse_len) {
9210	TRACE(("unparse_end %u:%s\n",
9211	       screen->unparse_len,
9212	       visibleIChars(screen->unparse_bfr, (size_t) screen->unparse_len)));
9213	writePtyData(screen->respond, screen->unparse_bfr, (size_t) screen->unparse_len);
9214	screen->unparse_len = 0;
9215    }
9216}
9217
9218void
9219ToggleAlternate(XtermWidget xw)
9220{
9221    if (TScreenOf(xw)->whichBuf)
9222	FromAlternate(xw, False);
9223    else
9224	ToAlternate(xw, False);
9225}
9226
9227static void
9228ToAlternate(XtermWidget xw, Bool clearFirst)
9229{
9230    TScreen *screen = TScreenOf(xw);
9231
9232    if (screen->whichBuf == 0) {
9233	TRACE(("ToAlternate\n"));
9234	if (!screen->editBuf_index[1]) {
9235	    screen->editBuf_index[1] = allocScrnBuf(xw,
9236						    (unsigned) MaxRows(screen),
9237						    (unsigned) MaxCols(screen),
9238						    &screen->editBuf_data[1]);
9239	}
9240	SwitchBufs(xw, 1, clearFirst);
9241	screen->visbuf = screen->editBuf_index[screen->whichBuf];
9242	update_altscreen();
9243    }
9244}
9245
9246static void
9247FromAlternate(XtermWidget xw, Bool clearFirst)
9248{
9249    TScreen *screen = TScreenOf(xw);
9250
9251    if (screen->whichBuf != 0) {
9252	TRACE(("FromAlternate\n"));
9253	if (screen->scroll_amt) {
9254	    FlushScroll(xw);
9255	}
9256	if (clearFirst)
9257	    ClearScreen(xw);
9258	SwitchBufs(xw, 0, False);
9259	screen->visbuf = screen->editBuf_index[screen->whichBuf];
9260	update_altscreen();
9261    }
9262}
9263
9264static void
9265SwitchBufs(XtermWidget xw, int toBuf, Bool clearFirst)
9266{
9267    TScreen *screen = TScreenOf(xw);
9268    int rows, top;
9269
9270    screen->whichBuf = toBuf;
9271    if (screen->cursor_state)
9272	HideCursor(xw);
9273
9274    rows = MaxRows(screen);
9275#if OPT_STATUS_LINE
9276    if (IsStatusShown(screen) && (rows > 0)) {
9277	/* avoid clearing the status-line in this function */
9278	--rows;
9279    }
9280#endif
9281    SwitchBufPtrs(xw, toBuf);
9282
9283    if ((top = INX2ROW(screen, 0)) < rows) {
9284	if (screen->scroll_amt) {
9285	    FlushScroll(xw);
9286	}
9287	xtermClear2(xw,
9288		    (int) OriginX(screen),
9289		    (int) top * FontHeight(screen) + screen->border,
9290		    (unsigned) Width(screen),
9291		    (unsigned) ((rows - top) * FontHeight(screen)));
9292	if (clearFirst) {
9293	    ClearBufRows(xw, top, rows);
9294	}
9295    }
9296    ScrnUpdate(xw, 0, 0, rows, MaxCols(screen), False);
9297}
9298
9299Bool
9300CheckBufPtrs(TScreen *screen)
9301{
9302    return (screen->visbuf != NULL
9303	    && screen->editBuf_index[0] != NULL
9304	    && screen->editBuf_index[1] != NULL);
9305}
9306
9307/*
9308 * Swap buffer line pointers between alternate and regular screens.
9309 */
9310void
9311SwitchBufPtrs(XtermWidget xw, int toBuf)
9312{
9313    TScreen *screen = TScreenOf(xw);
9314
9315    if (CheckBufPtrs(screen)) {
9316#if OPT_STATUS_LINE
9317	if (IsStatusShown(screen)
9318	    && (screen->visbuf != screen->editBuf_index[toBuf])) {
9319	    LineData *oldLD;
9320	    LineData *newLD;
9321	    int row = MaxRows(screen);
9322
9323	    oldLD = getLineData(screen, row);
9324	    screen->visbuf = screen->editBuf_index[toBuf];
9325	    newLD = getLineData(screen, row);
9326
9327	    copyLineData(newLD, oldLD);
9328	} else
9329#endif
9330	    screen->visbuf = screen->editBuf_index[toBuf];
9331    }
9332}
9333
9334void
9335VTRun(XtermWidget xw)
9336{
9337    TScreen *screen = TScreenOf(xw);
9338
9339    TRACE(("VTRun ...\n"));
9340
9341    if (!screen->Vshow && !resource.notMapped) {
9342	set_vt_visibility(True);
9343    }
9344    update_vttekmode();
9345    update_vtshow();
9346    update_tekshow();
9347    set_vthide_sensitivity();
9348
9349    ScrnAllocBuf(xw);
9350
9351    screen->cursor_state = OFF;
9352    screen->cursor_set = ON;
9353#if OPT_BLINK_CURS
9354    if (DoStartBlinking(screen))
9355	StartBlinking(xw);
9356#endif
9357
9358#if OPT_TEK4014
9359    if (Tpushb > Tpushback) {
9360	fillPtyData(xw, VTbuffer, (char *) Tpushback, (size_t) (Tpushb - Tpushback));
9361	Tpushb = Tpushback;
9362    }
9363#endif
9364    screen->is_running = True;
9365    if (screen->embed_high && screen->embed_wide) {
9366	ScreenResize(xw, screen->embed_wide, screen->embed_high, &(xw->flags));
9367    }
9368#if OPT_MAXIMIZE
9369    else if (resource.fullscreen == esTrue || resource.fullscreen == esAlways)
9370	FullScreen(xw, True);
9371#endif
9372    if (!setjmp(VTend))
9373	VTparse(xw);
9374    StopBlinking(xw);
9375    HideCursor(xw);
9376    screen->cursor_set = OFF;
9377    TRACE(("... VTRun\n"));
9378}
9379
9380/*ARGSUSED*/
9381static void
9382VTExpose(Widget w GCC_UNUSED,
9383	 XEvent *event,
9384	 Region region GCC_UNUSED)
9385{
9386    DEBUG_MSG("Expose\n");
9387    if (event->type == Expose)
9388	HandleExposure(term, event);
9389}
9390
9391static void
9392VTGraphicsOrNoExpose(XEvent *event)
9393{
9394    XtermWidget xw = term;
9395    TScreen *screen = TScreenOf(xw);
9396    if (screen->incopy <= 0) {
9397	screen->incopy = 1;
9398	if (screen->scrolls > 0)
9399	    screen->scrolls--;
9400    }
9401    if (event->type == GraphicsExpose)
9402	if (HandleExposure(xw, event))
9403	    screen->cursor_state = OFF;
9404    if ((event->type == NoExpose)
9405	|| ((XGraphicsExposeEvent *) event)->count == 0) {
9406	if (screen->incopy <= 0 && screen->scrolls > 0)
9407	    screen->scrolls--;
9408	if (screen->scrolls)
9409	    screen->incopy = -1;
9410	else
9411	    screen->incopy = 0;
9412    }
9413}
9414
9415/*ARGSUSED*/
9416static void
9417VTNonMaskableEvent(Widget w GCC_UNUSED,
9418		   XtPointer closure GCC_UNUSED,
9419		   XEvent *event,
9420		   Boolean *cont GCC_UNUSED)
9421{
9422    switch (event->type) {
9423    case GraphicsExpose:
9424	/* FALLTHRU */
9425    case NoExpose:
9426	VTGraphicsOrNoExpose(event);
9427	break;
9428    }
9429}
9430
9431static void
9432VTResize(Widget w)
9433{
9434    if (XtIsRealized(w)) {
9435	XtermWidget xw = (XtermWidget) w;
9436	ScreenResize(xw, xw->core.width, xw->core.height, &xw->flags);
9437    }
9438}
9439
9440#define okDimension(src,dst) ((src <= MAX_U_COORD) \
9441			  && ((dst = (Dimension) src) == src))
9442
9443static void
9444RequestResize(XtermWidget xw, int rows, int cols, Bool text)
9445{
9446    TScreen *screen = TScreenOf(xw);
9447    Dimension replyWidth, replyHeight;
9448    Dimension askedWidth, askedHeight;
9449    XtGeometryResult status;
9450    XWindowAttributes attrs;
9451#if OPT_RENDERFONT && USE_DOUBLE_BUFFER
9452    Boolean buggyXft = False;
9453    Cardinal ignore = 0;
9454#endif
9455
9456    TRACE(("RequestResize(rows=%d, cols=%d, text=%d)\n", rows, cols, text));
9457#if OPT_STATUS_LINE
9458    if (IsStatusShown(screen)) {
9459	if (rows == -1) {
9460	    /* prevent shrinking on DECCOLM, XTRESTORE, DECSCPP, DECANM */
9461	    rows = MaxRows(screen);
9462	}
9463	if (rows > 0) {
9464	    TRACE(("...reserve a row for status-line\n"));
9465	    ++rows;
9466	}
9467    }
9468#endif
9469
9470    /* check first if the row/column values fit into a Dimension */
9471    if (cols > 0) {
9472	if ((int) (askedWidth = (Dimension) cols) < cols) {
9473	    TRACE(("... cols too large for Dimension\n"));
9474	    return;
9475	}
9476    } else {
9477	askedWidth = 0;
9478    }
9479    if (rows > 0) {
9480	if ((int) (askedHeight = (Dimension) rows) < rows) {
9481	    TRACE(("... rows too large for Dimension\n"));
9482	    return;
9483	}
9484    } else {
9485	askedHeight = 0;
9486    }
9487
9488    xw->work.doing_resize = True;
9489
9490#if OPT_RENDERFONT && USE_DOUBLE_BUFFER
9491    /*
9492     * Work around a bug seen when vttest switches from 132 columns back to 80
9493     * columns, while double-buffering is active.  If Xft is active during the
9494     * resize, the screen will be blank thereafter.  This workaround causes
9495     * some extra flickering, but that is preferable to a blank screen.
9496     *
9497     * Since the bitmap- and TrueType-fonts do not always have identical sizes,
9498     * do this switching early, to use the updated font-sizes in the request
9499     * for resizing the window.
9500     */
9501#define ToggleXft() HandleRenderFont((Widget)xw, (XEvent *)0, (String *)0, &ignore)
9502    if (resource.buffered
9503	&& UsingRenderFont(xw)) {
9504	ToggleXft();
9505	buggyXft = True;
9506    }
9507#endif
9508
9509    /*
9510     * If the requested values will fit into a Dimension, and one or both are
9511     * zero, get the current corresponding screen dimension to use as a limit.
9512     */
9513    if (askedHeight == 0
9514	|| askedWidth == 0
9515	|| xw->misc.limit_resize > 0) {
9516	xtermGetWinAttrs(XtDisplay(xw),
9517			 RootWindowOfScreen(XtScreen(xw)), &attrs);
9518    }
9519
9520    /*
9521     * Using the current font metrics, translate the requested character
9522     * rows/columns into pixels.
9523     */
9524    if (text) {
9525	unsigned long value;
9526
9527	if ((value = (unsigned long) rows) != 0) {
9528	    if (rows < 0)
9529		value = (unsigned long) MaxRows(screen);
9530	    value *= (unsigned long) FontHeight(screen);
9531	    value += (unsigned long) (2 * screen->border);
9532	    if (!okDimension(value, askedHeight))
9533		goto give_up;
9534	}
9535
9536	if ((value = (unsigned long) cols) != 0) {
9537	    if (cols < 0)
9538		value = (unsigned long) MaxCols(screen);
9539	    value *= (unsigned long) FontWidth(screen);
9540	    value += (unsigned long) ((2 * screen->border)
9541				      + ScrollbarWidth(screen));
9542	    if (!okDimension(value, askedWidth))
9543		goto give_up;
9544	}
9545
9546    } else {
9547	if (rows < 0)
9548	    askedHeight = FullHeight(screen);
9549	if (cols < 0)
9550	    askedWidth = FullWidth(screen);
9551    }
9552
9553    if (rows == 0) {
9554	askedHeight = (Dimension) attrs.height;
9555    }
9556    if (cols == 0) {
9557	askedWidth = (Dimension) attrs.width;
9558    }
9559
9560    if (xw->misc.limit_resize > 0) {
9561	Dimension high = (Dimension) (xw->misc.limit_resize * attrs.height);
9562	Dimension wide = (Dimension) (xw->misc.limit_resize * attrs.width);
9563	if ((int) high < attrs.height)
9564	    high = (Dimension) attrs.height;
9565	if (askedHeight > high)
9566	    askedHeight = high;
9567	if ((int) wide < attrs.width)
9568	    wide = (Dimension) attrs.width;
9569	if (askedWidth > wide)
9570	    askedWidth = wide;
9571    }
9572#ifndef nothack
9573    getXtermSizeHints(xw);
9574#endif
9575
9576    TRACE(("...requesting resize %dx%d (%dx%d)\n",
9577	   askedHeight, askedWidth,
9578	   askedHeight / FontHeight(screen),
9579	   askedWidth / FontWidth(screen)));
9580    status = REQ_RESIZE((Widget) xw,
9581			askedWidth, askedHeight,
9582			&replyWidth, &replyHeight);
9583
9584    if (status == XtGeometryYes ||
9585	status == XtGeometryDone) {
9586	ScreenResize(xw, replyWidth, replyHeight, &xw->flags);
9587    }
9588#ifndef nothack
9589    /*
9590     * XtMakeResizeRequest() has the undesirable side-effect of clearing
9591     * the window manager's hints, even on a failed request.  This would
9592     * presumably be fixed if the shell did its own work.
9593     */
9594    if (xw->hints.flags
9595	&& replyHeight
9596	&& replyWidth) {
9597	xw->hints.height = replyHeight;
9598	xw->hints.width = replyWidth;
9599
9600	TRACE(("%s@%d -- ", __FILE__, __LINE__));
9601	TRACE_HINTS(&xw->hints);
9602	XSetWMNormalHints(screen->display, VShellWindow(xw), &xw->hints);
9603	TRACE(("%s@%d -- ", __FILE__, __LINE__));
9604	TRACE_WM_HINTS(xw);
9605    }
9606#endif
9607
9608    XSync(screen->display, False);	/* synchronize */
9609    if (xtermAppPending()) {
9610	xevents(xw);
9611    }
9612
9613  give_up:
9614#if OPT_RENDERFONT && USE_DOUBLE_BUFFER
9615    if (buggyXft) {
9616	ToggleXft();
9617	if (xtermAppPending()) {
9618	    xevents(xw);
9619	}
9620    }
9621#endif
9622
9623    xw->work.doing_resize = False;
9624
9625    TRACE(("...RequestResize done\n"));
9626    return;
9627}
9628
9629static String xterm_trans =
9630"<ClientMessage>WM_PROTOCOLS: DeleteWindow()\n\
9631     <MappingNotify>: KeyboardMapping()\n";
9632
9633int
9634VTInit(XtermWidget xw)
9635{
9636    Widget vtparent = SHELL_OF(xw);
9637
9638    TRACE(("VTInit " TRACE_L "\n"));
9639
9640    XtRealizeWidget(vtparent);
9641    XtOverrideTranslations(vtparent, XtParseTranslationTable(xterm_trans));
9642    (void) XSetWMProtocols(XtDisplay(vtparent), XtWindow(vtparent),
9643			   &wm_delete_window, 1);
9644
9645    if (IsEmpty(xw->keyboard.print_translations)) {
9646	TRACE_TRANS("shell", vtparent);
9647	TRACE_TRANS("vt100", (Widget) (xw));
9648	xtermButtonInit(xw);
9649    }
9650
9651    ScrnAllocBuf(xw);
9652
9653    TRACE(("..." TRACE_R " VTInit\n"));
9654    return (1);
9655}
9656
9657static void
9658VTClassInit(void)
9659{
9660    XtAddConverter(XtRString, XtRGravity, XmuCvtStringToGravity,
9661		   (XtConvertArgList) NULL, (Cardinal) 0);
9662}
9663
9664/*
9665 * Override the use of XtDefaultForeground/XtDefaultBackground to make some
9666 * colors, such as cursor color, use the actual foreground/background value
9667 * if there is no explicit resource value used.
9668 */
9669static Pixel
9670fill_Tres(XtermWidget target, XtermWidget source, int offset)
9671{
9672    char *name;
9673    ScrnColors temp;
9674    TScreen *src = TScreenOf(source);
9675    TScreen *dst = TScreenOf(target);
9676
9677    dst->Tcolors[offset] = src->Tcolors[offset];
9678    dst->Tcolors[offset].mode = False;
9679
9680    if ((name = x_strtrim(dst->Tcolors[offset].resource)) != NULL)
9681	dst->Tcolors[offset].resource = name;
9682
9683    if (name == NULL) {
9684	dst->Tcolors[offset].value = target->dft_foreground;
9685    } else if (isDefaultForeground(name)) {
9686	dst->Tcolors[offset].value = ((offset == TEXT_FG || offset == TEXT_BG)
9687				      ? target->dft_foreground
9688				      : dst->Tcolors[TEXT_FG].value);
9689    } else if (isDefaultBackground(name)) {
9690	dst->Tcolors[offset].value = ((offset == TEXT_FG || offset == TEXT_BG)
9691				      ? target->dft_background
9692				      : dst->Tcolors[TEXT_BG].value);
9693    } else {
9694	memset(&temp, 0, sizeof(temp));
9695	if (AllocateTermColor(target, &temp, offset, name, True)) {
9696	    if (COLOR_DEFINED(&(temp), offset))
9697		free(temp.names[offset]);
9698	    dst->Tcolors[offset].value = temp.colors[offset];
9699	} else if (offset == TEXT_FG || offset == TEXT_BG) {
9700	    free(name);
9701	    dst->Tcolors[offset].resource = NULL;
9702	}
9703    }
9704    return dst->Tcolors[offset].value;
9705}
9706
9707/*
9708 * If one or both of the foreground/background colors cannot be allocated,
9709 * e.g., due to gross misconfiguration, recover by setting both to the
9710 * display's default values.
9711 */
9712static void
9713repairColors(XtermWidget target)
9714{
9715    TScreen *screen = TScreenOf(target);
9716
9717    if (screen->Tcolors[TEXT_FG].resource == NULL ||
9718	screen->Tcolors[TEXT_BG].resource == NULL) {
9719	xtermWarning("unable to allocate fg/bg colors\n");
9720	screen->Tcolors[TEXT_FG].resource = x_strdup(XtDefaultForeground);
9721	screen->Tcolors[TEXT_BG].resource = x_strdup(XtDefaultBackground);
9722	if (screen->Tcolors[TEXT_FG].resource == NULL ||
9723	    screen->Tcolors[TEXT_BG].resource == NULL) {
9724	    Exit(ERROR_MISC);
9725	}
9726	screen->Tcolors[TEXT_FG].value = target->dft_foreground;
9727	screen->Tcolors[TEXT_BG].value = target->dft_background;
9728    }
9729}
9730
9731#if OPT_WIDE_CHARS
9732static void
9733set_utf8_feature(TScreen *screen, int *feature)
9734{
9735    if (*feature == uDefault) {
9736	switch (screen->utf8_mode) {
9737	case uFalse:
9738	    /* FALLTHRU */
9739	case uTrue:
9740	    *feature = screen->utf8_mode;
9741	    break;
9742	case uDefault:
9743	    /* should not happen */
9744	    *feature = uTrue;
9745	    break;
9746	case uAlways:
9747	    /* use this to disable menu entry */
9748	    break;
9749	}
9750    }
9751}
9752
9753static void
9754VTInitialize_locale(XtermWidget xw)
9755{
9756    TScreen *screen = TScreenOf(xw);
9757    Bool is_utf8 = xtermEnvUTF8();
9758
9759    TRACE(("VTInitialize_locale\n"));
9760    TRACE(("... request screen.utf8_mode = %d\n", screen->utf8_mode));
9761    TRACE(("... request screen.utf8_fonts = %d\n", screen->utf8_fonts));
9762    TRACE(("... request screen.utf8_title = %d\n", screen->utf8_title));
9763
9764    screen->utf8_always = (screen->utf8_mode == uAlways);
9765    if (screen->utf8_mode < 0)
9766	screen->utf8_mode = uFalse;
9767
9768    if (screen->utf8_mode > 3)
9769	screen->utf8_mode = uDefault;
9770
9771    screen->latin9_mode = 0;
9772    screen->unicode_font = 0;
9773#if OPT_LUIT_PROG
9774    xw->misc.callfilter = 0;
9775    xw->misc.use_encoding = 0;
9776
9777    TRACE(("... setup for luit:\n"));
9778    TRACE(("... request misc.locale_str = \"%s\"\n", xw->misc.locale_str));
9779
9780    if (screen->utf8_mode == uFalse) {
9781	TRACE(("... command-line +u8 overrides\n"));
9782    } else
9783#if OPT_MINI_LUIT
9784    if (x_strcasecmp(xw->misc.locale_str, "CHECKFONT") == 0) {
9785	int fl = (int) strlen(DefaultFontN(xw));
9786	if (fl > 11
9787	    && x_strcasecmp(DefaultFontN(xw) + fl - 11, "-ISO10646-1") == 0) {
9788	    screen->unicode_font = 1;
9789	    /* unicode font, use True */
9790#ifdef HAVE_LANGINFO_CODESET
9791	    if (!strcmp(xtermEnvEncoding(), "ANSI_X3.4-1968")
9792		|| !strcmp(xtermEnvEncoding(), "ISO-8859-1")) {
9793		if (screen->utf8_mode == uDefault)
9794		    screen->utf8_mode = uFalse;
9795	    } else if (!strcmp(xtermEnvEncoding(), "ISO-8859-15")) {
9796		if (screen->utf8_mode == uDefault)
9797		    screen->utf8_mode = uFalse;
9798		screen->latin9_mode = 1;
9799	    } else {
9800		xw->misc.callfilter = (Boolean) (is_utf8 ? 0 : 1);
9801		screen->utf8_mode = uAlways;
9802	    }
9803#else
9804	    xw->misc.callfilter = is_utf8 ? 0 : 1;
9805	    screen->utf8_mode = uAlways;
9806#endif
9807	} else {
9808	    /* other encoding, use False */
9809	    if (screen->utf8_mode == uDefault) {
9810		screen->utf8_mode = is_utf8 ? uAlways : uFalse;
9811	    }
9812	}
9813    } else
9814#endif /* OPT_MINI_LUIT */
9815	if (x_strcasecmp(xw->misc.locale_str, "TRUE") == 0 ||
9816	    x_strcasecmp(xw->misc.locale_str, "ON") == 0 ||
9817	    x_strcasecmp(xw->misc.locale_str, "YES") == 0 ||
9818	    x_strcasecmp(xw->misc.locale_str, "AUTO") == 0 ||
9819	    strcmp(xw->misc.locale_str, "1") == 0) {
9820	/* when true ... fully obeying LC_CTYPE locale */
9821	xw->misc.callfilter = (Boolean) (is_utf8 ? 0 : 1);
9822	screen->utf8_mode = uAlways;
9823    } else if (x_strcasecmp(xw->misc.locale_str, "FALSE") == 0 ||
9824	       x_strcasecmp(xw->misc.locale_str, "OFF") == 0 ||
9825	       x_strcasecmp(xw->misc.locale_str, "NO") == 0 ||
9826	       strcmp(xw->misc.locale_str, "0") == 0) {
9827	/* when false ... original value of utf8_mode is effective */
9828	if (screen->utf8_mode == uDefault) {
9829	    screen->utf8_mode = is_utf8 ? uAlways : uFalse;
9830	}
9831    } else if (x_strcasecmp(xw->misc.locale_str, "MEDIUM") == 0 ||
9832	       x_strcasecmp(xw->misc.locale_str, "SEMIAUTO") == 0) {
9833	/* when medium ... obeying locale only for UTF-8 and Asian */
9834	if (is_utf8) {
9835	    screen->utf8_mode = uAlways;
9836	} else if (
9837#ifdef MB_CUR_MAX
9838		      MB_CUR_MAX > 1 ||
9839#else
9840		      !strncmp(xtermEnvLocale(), "ja", (size_t) 2) ||
9841		      !strncmp(xtermEnvLocale(), "ko", (size_t) 2) ||
9842		      !strncmp(xtermEnvLocale(), "zh", (size_t) 2) ||
9843#endif
9844		      !strncmp(xtermEnvLocale(), "th", (size_t) 2) ||
9845		      !strncmp(xtermEnvLocale(), "vi", (size_t) 2)) {
9846	    xw->misc.callfilter = 1;
9847	    screen->utf8_mode = uAlways;
9848	} else {
9849	    screen->utf8_mode = uFalse;
9850	}
9851    } else if (x_strcasecmp(xw->misc.locale_str, "UTF-8") == 0 ||
9852	       x_strcasecmp(xw->misc.locale_str, "UTF8") == 0) {
9853	/* when UTF-8 ... UTF-8 mode */
9854	screen->utf8_mode = uAlways;
9855    } else {
9856	/* other words are regarded as encoding name passed to luit */
9857	xw->misc.callfilter = 1;
9858	screen->utf8_mode = uAlways;
9859	xw->misc.use_encoding = 1;
9860    }
9861    TRACE(("... updated misc.callfilter = %s\n", BtoS(xw->misc.callfilter)));
9862    TRACE(("... updated misc.use_encoding = %s\n", BtoS(xw->misc.use_encoding)));
9863#else
9864    if (screen->utf8_mode == uDefault) {
9865	screen->utf8_mode = is_utf8 ? uAlways : uFalse;
9866    }
9867#endif /* OPT_LUIT_PROG */
9868
9869    set_utf8_feature(screen, &screen->utf8_fonts);
9870    set_utf8_feature(screen, &screen->utf8_title);
9871
9872    screen->utf8_inparse = (Boolean) (screen->utf8_mode != uFalse);
9873
9874    TRACE(("... updated screen.utf8_mode = %d\n", screen->utf8_mode));
9875    TRACE(("... updated screen.utf8_fonts = %d\n", screen->utf8_fonts));
9876    TRACE(("... updated screen.utf8_title = %d\n", screen->utf8_title));
9877    TRACE(("...VTInitialize_locale done\n"));
9878}
9879#endif
9880
9881void
9882lookupSelectUnit(XtermWidget xw, Cardinal item, String value)
9883{
9884    /* *INDENT-OFF* */
9885    static const struct {
9886	const char *	name;
9887	SelectUnit	code;
9888    } table[] = {
9889    	{ "char",	Select_CHAR },
9890    	{ "word",	Select_WORD },
9891    	{ "line",	Select_LINE },
9892    	{ "group",	Select_GROUP },
9893    	{ "page",	Select_PAGE },
9894    	{ "all",	Select_ALL },
9895#if OPT_SELECT_REGEX
9896    	{ "regex",	Select_REGEX },
9897#endif
9898    };
9899    /* *INDENT-ON* */
9900
9901    TScreen *screen = TScreenOf(xw);
9902    String next = x_skip_nonblanks(value);
9903    Cardinal n;
9904
9905    screen->selectMap[item] = NSELECTUNITS;
9906    for (n = 0; n < XtNumber(table); ++n) {
9907	if (!x_strncasecmp(table[n].name, value, (unsigned) (next - value))) {
9908	    screen->selectMap[item] = table[n].code;
9909#if OPT_SELECT_REGEX
9910	    if (table[n].code == Select_REGEX) {
9911		screen->selectExpr[item] = x_strtrim(next);
9912		TRACE(("Parsed regex \"%s\"\n", screen->selectExpr[item]));
9913	    }
9914#endif
9915	    break;
9916	}
9917    }
9918}
9919
9920static void
9921ParseOnClicks(XtermWidget wnew, XtermWidget wreq, Cardinal item)
9922{
9923    lookupSelectUnit(wnew, item, TScreenOf(wreq)->onClick[item]);
9924}
9925
9926/*
9927 * Parse a comma-separated list, returning a string which the caller must
9928 * free, and updating the source pointer.
9929 */
9930static char *
9931ParseList(const char **source)
9932{
9933    const char *base = *source;
9934    const char *next;
9935    char *value = NULL;
9936    char *result;
9937
9938    /* ignore empty values */
9939    while (*base == ',')
9940	++base;
9941
9942    if (*base != '\0') {
9943	size_t size;
9944
9945	next = base;
9946	while (*next != '\0' && *next != ',')
9947	    ++next;
9948	size = (size_t) (1 + next - base);
9949	value = malloc(size);
9950	if (value != NULL) {
9951	    memcpy(value, base, size);
9952	    value[size - 1] = '\0';
9953	}
9954	*source = next;
9955    } else {
9956	*source = base;
9957    }
9958    result = x_strtrim(value);
9959    free(value);
9960    return result;
9961}
9962
9963static void
9964set_flags_from_list(char *target,
9965		    const char *source,
9966		    const FlagList * list)
9967{
9968    Cardinal n;
9969
9970    while (!IsEmpty(source)) {
9971	char *next = ParseList(&source);
9972	Boolean found = False;
9973	char flag = 1;
9974
9975	if (next == NULL)
9976	    break;
9977	if (*next == '~') {
9978	    flag = 0;
9979	    next++;
9980	}
9981	if (isdigit(CharOf(*next))) {
9982	    char *temp;
9983	    int value = (int) strtol(next, &temp, 0);
9984	    if (!FullS2L(next, temp)) {
9985		xtermWarning("Expected a number: %s\n", next);
9986	    } else {
9987		for (n = 0; list[n].name != NULL; ++n) {
9988		    if (list[n].code == value) {
9989			target[value] = flag;
9990			found = True;
9991			TRACE(("...found %s (%d)\n", list[n].name, value));
9992			break;
9993		    }
9994		}
9995	    }
9996	} else {
9997	    for (n = 0; list[n].name != NULL; ++n) {
9998		if (!x_wildstrcmp(next, list[n].name)) {
9999		    int value = list[n].code;
10000		    target[value] = flag;
10001		    found = True;
10002		    TRACE(("...found %s (%d)\n", list[n].name, value));
10003		}
10004	    }
10005	}
10006	if (!found) {
10007	    xtermWarning("Unrecognized keyword: %s\n", next);
10008	}
10009	free(next);
10010    }
10011}
10012
10013#define InitCursorShape(target, source) \
10014    target->cursor_shape = source->cursor_underline ? CURSOR_UNDERLINE : \
10015                           source->cursor_bar ? CURSOR_BAR : CURSOR_BLOCK
10016
10017#if OPT_XRES_QUERY
10018static XtResource *
10019findVT100Resource(const char *name)
10020{
10021    Cardinal n;
10022    XtResource *result = NULL;
10023
10024    if (!IsEmpty(name)) {
10025	XrmQuark quarkName = XrmPermStringToQuark(name);
10026	for (n = 0; n < XtNumber(xterm_resources); ++n) {
10027	    if ((int) xterm_resources[n].resource_offset >= 0
10028		&& !strcmp(xterm_resources[n].resource_name, name)) {
10029		result = &xterm_resources[n];
10030		break;
10031	    } else if (xterm_resources[n].resource_name
10032		       == (String) (intptr_t) quarkName) {
10033		result = &xterm_resources[n];
10034		break;
10035	    }
10036	}
10037    }
10038    return result;
10039}
10040
10041static int
10042cmp_resources(const void *a, const void *b)
10043{
10044    return strcmp((*(const String *) a),
10045		  (*(const String *) b));
10046}
10047
10048static void
10049reportResources(XtermWidget xw)
10050{
10051    String *list = TypeMallocN(String, XtNumber(xterm_resources));
10052    Cardinal n;
10053    int widest = 0;
10054
10055    if (list == NULL)
10056	return;
10057
10058    for (n = 0; n < XtNumber(xterm_resources); ++n) {
10059	int width;
10060	list[n] = (((int) xterm_resources[n].resource_offset < 0)
10061		   ? XrmQuarkToString((XrmQuark) (intptr_t)
10062				      xterm_resources[n].resource_name)
10063		   : xterm_resources[n].resource_name);
10064	width = (int) strlen(list[n]);
10065	if (widest < width)
10066	    widest = width;
10067    }
10068    qsort(list, (size_t) XtNumber(xterm_resources), sizeof(String), cmp_resources);
10069    for (n = 0; n < XtNumber(xterm_resources); ++n) {
10070	char *value = vt100ResourceToString(xw, list[n]);
10071	printf("%-*s : %s\n", widest, list[n], value ? value : "(skip)");
10072	free(value);
10073    }
10074    free(list);
10075}
10076
10077char *
10078vt100ResourceToString(XtermWidget xw, const char *name)
10079{
10080    XtResource *data;
10081    char *result = NULL;
10082
10083    if ((data = findVT100Resource(name)) != NULL) {
10084	int fake_offset = (int) data->resource_offset;
10085	void *res_addr;
10086	int real_offset;
10087	String res_type;
10088
10089	/*
10090	 * X Toolkit "compiles" the resource-list into quarks and changes the
10091	 * resource-offset at the same time to a negative value.
10092	 */
10093	if (fake_offset < 0) {
10094	    real_offset = -(fake_offset + 1);
10095	    res_type = XrmQuarkToString((XrmQuark) (intptr_t) data->resource_type);
10096	} else {
10097	    real_offset = fake_offset;
10098	    res_type = data->resource_type;
10099	}
10100	res_addr = (void *) ((char *) xw + real_offset);
10101
10102	if (!strcmp(res_type, XtRString)) {
10103	    char *value = *(char **) res_addr;
10104	    if (value != NULL) {
10105		size_t need = strlen(value);
10106		if ((result = malloc(1 + need)) != NULL)
10107		    strcpy(result, value);
10108	    }
10109	} else if (!strcmp(res_type, XtRInt)) {
10110	    if ((result = malloc(1 + (size_t) (3 * data->resource_size))) != NULL)
10111		sprintf(result, "%d", *(int *) res_addr);
10112	} else if (!strcmp(res_type, XtRFloat)) {
10113	    if ((result = malloc(1 + (size_t) (3 * data->resource_size))) != NULL)
10114		sprintf(result, "%f", (double) (*(float *) res_addr));
10115	} else if (!strcmp(res_type, XtRBoolean)) {
10116	    if ((result = malloc((size_t) 6)) != NULL)
10117		strcpy(result, *(Boolean *) res_addr ? "true" : "false");
10118	}
10119    }
10120    TRACE(("vt100ResourceToString(%s) %s\n", name, NonNull(result)));
10121    return result;
10122}
10123#endif /* OPT_XRES_QUERY */
10124
10125/*
10126 * Decode a terminal-ID or graphics-terminal-ID, using the default terminal-ID
10127 * if the value is outside a (looser) range than limitedTerminalID.  This uses
10128 * a wider range, to avoid being a nuisance when using X resources with
10129 * different configurations of xterm.
10130 */
10131static int
10132decodeTerminalID(const char *value)
10133{
10134    const char *s;
10135    char *t;
10136    long result;
10137
10138    for (s = value; *s; s++) {
10139	if (!isalpha(CharOf(*s)))
10140	    break;
10141    }
10142    result = strtol(s, &t, 10);
10143    if (t == s || *t != '\0' || result <= 0L || result > 1000L) {
10144	xtermWarning("unexpected value for terminalID: \"%s\"\n", value);
10145	result = atoi(DFT_DECID);
10146    }
10147    TRACE(("decodeTerminalID \"%s\" ->%d\n", value, (int) result));
10148    return (int) result;
10149}
10150
10151/*
10152 * Ensures that the value returned by decodeTerminalID is either in the range
10153 * of IDs matching a known terminal, or (failing that), set to the built-in
10154 * default.  The DA response relies on having the ID being set to a known
10155 * value.
10156 */
10157static int
10158limitedTerminalID(int terminal_id)
10159{
10160    if (terminal_id < MIN_DECID)
10161	terminal_id = MIN_DECID;
10162    else if (terminal_id > MAX_DECID)
10163	terminal_id = MAX_DECID;
10164    else
10165	terminal_id = atoi(DFT_DECID);
10166    return terminal_id;
10167}
10168
10169#define DATA_END   { NULL,  -1       }
10170
10171#define DATA(name) { #name, ec##name }
10172static const FlagList tblColorOps[] =
10173{
10174    DATA(SetColor)
10175    ,DATA(GetColor)
10176    ,DATA(GetAnsiColor)
10177    ,DATA_END
10178};
10179#undef DATA
10180
10181#define DATA(name) { #name, ef##name }
10182static const FlagList tblFontOps[] =
10183{
10184    DATA(SetFont)
10185    ,DATA(GetFont)
10186    ,DATA_END
10187};
10188#undef DATA
10189
10190#define DATA(name) { #name, em##name }
10191static const FlagList tblMouseOps[] =
10192{
10193    DATA(X10)
10194    ,DATA(Locator)
10195    ,DATA(VT200Click)
10196    ,DATA(VT200Hilite)
10197    ,DATA(AnyButton)
10198    ,DATA(AnyEvent)
10199    ,DATA(FocusEvent)
10200    ,DATA(Extended)
10201    ,DATA(SGR)
10202    ,DATA(URXVT)
10203    ,DATA(AlternateScroll)
10204    ,DATA_END
10205};
10206#undef DATA
10207
10208#define DATA(name) { #name, ep##name }
10209#define DATA2(alias,name) { #alias, ep##name }
10210static const FlagList tblPasteOps[] =
10211{
10212    DATA(NUL)
10213    ,DATA(SOH)
10214    ,DATA(STX)
10215    ,DATA(ETX)
10216    ,DATA(EOT)
10217    ,DATA(ENQ)
10218    ,DATA(ACK)
10219    ,DATA(BEL)
10220    ,DATA(BS)
10221    ,DATA(HT)
10222    ,DATA(LF)
10223    ,DATA(VT)
10224    ,DATA(FF)
10225    ,DATA(CR)
10226    ,DATA(SO)
10227    ,DATA(SI)
10228    ,DATA(DLE)
10229    ,DATA(DC1)
10230    ,DATA(DC2)
10231    ,DATA(DC3)
10232    ,DATA(DC4)
10233    ,DATA(NAK)
10234    ,DATA(SYN)
10235    ,DATA(ETB)
10236    ,DATA(CAN)
10237    ,DATA(EM)
10238    ,DATA(SUB)
10239    ,DATA(ESC)
10240    ,DATA(FS)
10241    ,DATA(GS)
10242    ,DATA(RS)
10243    ,DATA(US)
10244/* aliases */
10245    ,DATA2(NL, LF)
10246    ,DATA(C0)
10247    ,DATA(DEL)
10248    ,DATA(STTY)
10249    ,DATA_END
10250};
10251#undef DATA
10252#undef DATA2
10253
10254#define DATA(name) { #name, et##name }
10255static const FlagList tblTcapOps[] =
10256{
10257    DATA(SetTcap)
10258    ,DATA(GetTcap)
10259    ,DATA_END
10260};
10261#undef DATA
10262
10263#define DATA(name) { #name, ew##name }
10264static const FlagList tblWindowOps[] =
10265{
10266    DATA(RestoreWin)
10267    ,DATA(MinimizeWin)
10268    ,DATA(SetWinPosition)
10269    ,DATA(SetWinSizePixels)
10270    ,DATA(RaiseWin)
10271    ,DATA(LowerWin)
10272    ,DATA(RefreshWin)
10273    ,DATA(SetWinSizeChars)
10274#if OPT_MAXIMIZE
10275    ,DATA(MaximizeWin)
10276    ,DATA(FullscreenWin)
10277#endif
10278    ,DATA(GetWinState)
10279    ,DATA(GetWinPosition)
10280    ,DATA(GetWinSizePixels)
10281    ,DATA(GetWinSizeChars)
10282#if OPT_MAXIMIZE
10283    ,DATA(GetScreenSizeChars)
10284#endif
10285    ,DATA(GetIconTitle)
10286    ,DATA(GetWinTitle)
10287    ,DATA(PushTitle)
10288    ,DATA(PopTitle)
10289/* this item uses all remaining numbers in the sequence */
10290    ,DATA(SetWinLines)
10291/* starting at this point, numbers do not apply */
10292    ,DATA(SetXprop)
10293    ,DATA(GetSelection)
10294    ,DATA(SetSelection)
10295    ,DATA(GetChecksum)
10296    ,DATA(SetChecksum)
10297    ,DATA_END
10298};
10299#undef DATA
10300
10301void
10302unparse_disallowed_ops(XtermWidget xw, char *value)
10303{
10304    TScreen *screen = TScreenOf(xw);
10305#define DATA(mixed, plain, flags) { #mixed, offsetof(TScreen, plain), sizeof(screen->plain), flags }
10306    /* *INDENT-OFF* */
10307    static const struct {
10308	const char *	name;
10309	size_t		offset;
10310	size_t		length;
10311	const FlagList *codes;
10312    } table[] = {
10313	DATA(allowColorOps,	 disallow_color_ops, tblColorOps),
10314	DATA(allowFontOps,	 disallow_font_ops,  tblFontOps),
10315	DATA(allowMouseOps,	 disallow_mouse_ops, tblMouseOps),
10316	DATA(allowPasteControls, disallow_paste_ops, tblPasteOps),
10317	DATA(allowTcapOps,	 disallow_tcap_ops,  tblTcapOps),
10318	DATA(allowWinOps,	 disallow_win_ops,   tblWindowOps),
10319    };
10320    /* *INDENT-ON* */
10321#undef DATA
10322    Cardinal j, k, jk;
10323    char delim = ';';
10324
10325    for (j = 0; j < XtNumber(table); ++j) {
10326	if (!x_strcasecmp(value, table[j].name)) {
10327	    const char *flags = (char *) screen + table[j].offset;
10328
10329	    for (k = 0; k < table[j].length; ++k) {
10330		if (flags[k]) {
10331		    const FlagList *codes = table[j].codes;
10332		    Boolean found = False;
10333
10334		    unparseputc(xw, delim);
10335		    for (jk = 0; codes[jk].name; ++jk) {
10336			if (codes[jk].code == (int) k) {
10337			    unparseputs(xw, codes[jk].name);
10338			    found = True;
10339			    break;
10340			}
10341		    }
10342		    if (!found)
10343			unparseputn(xw, k);
10344		    delim = ',';
10345		}
10346	    }
10347	    break;
10348	}
10349    }
10350}
10351
10352/* ARGSUSED */
10353static void
10354VTInitialize(Widget wrequest,
10355	     Widget new_arg,
10356	     ArgList args GCC_UNUSED,
10357	     Cardinal *num_args GCC_UNUSED)
10358{
10359#define Kolor(name) TScreenOf(wnew)->name.resource
10360#define TxtFg(name) !x_strcasecmp(Kolor(Tcolors[TEXT_FG]), Kolor(name))
10361#define TxtBg(name) !x_strcasecmp(Kolor(Tcolors[TEXT_BG]), Kolor(name))
10362#define DftFg(name) isDefaultForeground(Kolor(name))
10363#define DftBg(name) isDefaultBackground(Kolor(name))
10364
10365#if OPT_BLINK_CURS
10366#define DATA(name) { #name, cb##name }
10367    static const FlagList tblBlinkOps[] =
10368    {
10369	DATA(Always)
10370	,DATA(Never)
10371	,DATA_END
10372    };
10373#undef DATA
10374#endif
10375
10376#if OPT_RENDERFONT
10377#define DATA(name) { #name, er##name }
10378    static const FlagList tblRenderFont[] =
10379    {
10380	DATA(Default)
10381	,DATA(DefaultOff)
10382	,DATA_END
10383    };
10384#undef DATA
10385#endif
10386
10387#define DATA(name) { #name, ss##name }
10388    static const FlagList tblShift2S[] =
10389    {
10390	DATA(Always)
10391	,DATA(Never)
10392	,DATA_END
10393    };
10394#undef DATA
10395
10396#if OPT_WIDE_CHARS
10397#define DATA(name) { #name, u##name }
10398    static const FlagList tblUtf8Mode[] =
10399    {
10400	DATA(Always)
10401	,DATA(Default)
10402	,DATA_END
10403    };
10404#undef DATA
10405#endif
10406
10407#ifndef NO_ACTIVE_ICON
10408#define DATA(name) { #name, ei##name }
10409    static const FlagList tblAIconOps[] =
10410    {
10411	DATA(Default)
10412	,DATA_END
10413    };
10414#undef DATA
10415#endif
10416
10417#define DATA(name) { #name, eb##name }
10418    static const FlagList tbl8BitMeta[] =
10419    {
10420	DATA(Never)
10421	,DATA(Locale)
10422	,DATA_END
10423    };
10424#undef DATA
10425
10426#define DATA(name) { #name, ed##name }
10427    static const FlagList tblCdXtraScroll[] =
10428    {
10429	DATA(Trim)
10430	,DATA_END
10431    };
10432#undef DATA
10433
10434    XtermWidget request = (XtermWidget) wrequest;
10435    XtermWidget wnew = (XtermWidget) new_arg;
10436    Widget my_parent = SHELL_OF(wnew);
10437    int i;
10438
10439#if OPT_ISO_COLORS
10440    Bool color_ok;
10441#endif
10442
10443#if OPT_ISO_COLORS
10444    static XtResource fake_resources[] =
10445    {
10446#if OPT_256_COLORS
10447# include <256colres.h>
10448#elif OPT_88_COLORS
10449# include <88colres.h>
10450#endif
10451    };
10452#endif
10453
10454    TScreen *screen = TScreenOf(wnew);
10455    char *saveLocale = xtermSetLocale(LC_NUMERIC, "C");
10456#if OPT_BLINK_CURS
10457    int ebValue;
10458#endif
10459
10460#if OPT_TRACE
10461    check_bitmasks();
10462    check_tables();
10463#endif
10464
10465    TRACE(("VTInitialize wnew %p, %d / %d resources " TRACE_L "\n",
10466	   (void *) wnew, XtNumber(xterm_resources), MAXRESOURCES));
10467    assert(XtNumber(xterm_resources) < MAXRESOURCES);
10468
10469    /* Zero out the entire "screen" component of "wnew" widget, then do
10470     * field-by-field assignment of "screen" fields that are named in the
10471     * resource list.
10472     */
10473    memset(screen, 0, sizeof(wnew->screen));
10474
10475    /* DESCO Sys#67660
10476     * Zero out the entire "keyboard" component of "wnew" widget.
10477     */
10478    memset(&wnew->keyboard, 0, sizeof(wnew->keyboard));
10479
10480    /*
10481     * The workspace has no resources - clear it.
10482     */
10483    memset(&wnew->work, 0, sizeof(wnew->work));
10484
10485    /* dummy values so that we don't try to Realize the parent shell with height
10486     * or width of 0, which is illegal in X.  The real size is computed in the
10487     * xtermWidget's Realize proc, but the shell's Realize proc is called first,
10488     * and must see a valid size.
10489     */
10490    wnew->core.height = wnew->core.width = 1;
10491
10492    /*
10493     * The definition of -rv now is that it changes the definition of
10494     * XtDefaultForeground and XtDefaultBackground.  So, we no longer
10495     * need to do anything special.
10496     */
10497    screen->display = wnew->core.screen->display;
10498
10499    /* prep getVisualInfo() */
10500    wnew->visInfo = NULL;
10501    wnew->numVisuals = 0;
10502    (void) getVisualInfo(wnew);
10503
10504#if OPT_STATUS_LINE
10505    StatusInit(&screen->status_data[0]);
10506    StatusInit(&screen->status_data[1]);
10507#endif
10508
10509    /*
10510     * We use the default foreground/background colors to compare/check if a
10511     * color-resource has been set.
10512     */
10513#define MyBlackPixel(dpy) BlackPixel(dpy,DefaultScreen(dpy))
10514#define MyWhitePixel(dpy) WhitePixel(dpy,DefaultScreen(dpy))
10515
10516    if (request->misc.re_verse) {
10517	wnew->dft_foreground = MyWhitePixel(screen->display);
10518	wnew->dft_background = MyBlackPixel(screen->display);
10519    } else {
10520	wnew->dft_foreground = MyBlackPixel(screen->display);
10521	wnew->dft_background = MyWhitePixel(screen->display);
10522    }
10523
10524    init_Tres(TEXT_FG);
10525    init_Tres(TEXT_BG);
10526    repairColors(wnew);
10527
10528    wnew->old_foreground = T_COLOR(screen, TEXT_FG);
10529    wnew->old_background = T_COLOR(screen, TEXT_BG);
10530
10531    TRACE(("Color resource initialization:\n"));
10532    TRACE(("   Default foreground 0x%06lx\n", wnew->dft_foreground));
10533    TRACE(("   Default background 0x%06lx\n", wnew->dft_background));
10534    TRACE(("   Screen foreground  0x%06lx\n", T_COLOR(screen, TEXT_FG)));
10535    TRACE(("   Screen background  0x%06lx\n", T_COLOR(screen, TEXT_BG)));
10536    TRACE(("   Actual  foreground 0x%06lx\n", wnew->old_foreground));
10537    TRACE(("   Actual  background 0x%06lx\n", wnew->old_background));
10538
10539    screen->mouse_button = 0;
10540    screen->mouse_row = -1;
10541    screen->mouse_col = -1;
10542
10543#if OPT_BOX_CHARS
10544    init_Bres(screen.force_box_chars);
10545    init_Bres(screen.force_packed);
10546    init_Bres(screen.assume_all_chars);
10547#endif
10548#if OPT_BOX_CHARS || OPT_WIDE_CHARS
10549    init_Bres(screen.force_all_chars);
10550#endif
10551    init_Bres(screen.free_bold_box);
10552    init_Bres(screen.allowBoldFonts);
10553
10554    init_Bres(screen.c132);
10555    init_Bres(screen.curses);
10556    init_Bres(screen.hp_ll_bc);
10557#if OPT_XMC_GLITCH
10558    init_Ires(screen.xmc_glitch);
10559    init_Ires(screen.xmc_attributes);
10560    init_Bres(screen.xmc_inline);
10561    init_Bres(screen.move_sgr_ok);
10562#endif
10563#if OPT_BLINK_CURS
10564    init_Sres(screen.cursor_blink_s);
10565    ebValue = extendedBoolean(wnew->screen.cursor_blink_s, tblBlinkOps, cbLAST);
10566    wnew->screen.cursor_blink = (BlinkOps) ebValue;
10567    init_Bres(screen.cursor_blink_xor);
10568    init_Ires(screen.blink_on);
10569    init_Ires(screen.blink_off);
10570    screen->cursor_blink_i = screen->cursor_blink;
10571#endif
10572    init_Bres(screen.cursor_underline);
10573    init_Bres(screen.cursor_bar);
10574    /* resources allow for underline or block, not (yet) bar */
10575    InitCursorShape(screen, TScreenOf(request));
10576#if OPT_BLINK_CURS
10577    TRACE(("cursor_shape:%d blinks:%d\n",
10578	   screen->cursor_shape,
10579	   screen->cursor_blink));
10580#endif
10581#if OPT_BLINK_TEXT
10582    init_Ires(screen.blink_as_bold);
10583#endif
10584    init_Ires(screen.border);
10585    init_Bres(screen.jumpscroll);
10586    init_Bres(screen.fastscroll);
10587
10588    init_Bres(screen.old_fkeys);
10589    wnew->screen.old_fkeys0 = wnew->screen.old_fkeys;
10590    wnew->keyboard.type = screen->old_fkeys
10591	? keyboardIsLegacy
10592	: keyboardIsDefault;
10593
10594    init_Mres(screen.delete_is_del);
10595#ifdef ALLOWLOGGING
10596    init_Bres(misc.logInhibit);
10597    init_Bres(misc.log_on);
10598    init_Sres(screen.logfile);
10599#endif
10600    init_Bres(screen.bellIsUrgent);
10601    init_Bres(screen.bellOnReset);
10602    init_Bres(screen.marginbell);
10603    init_Bres(screen.multiscroll);
10604    init_Ires(screen.nmarginbell);
10605    init_Ires(screen.savelines);
10606    init_Ires(screen.scrollBarBorder);
10607    init_Ires(screen.scrolllines);
10608    init_Bres(screen.alternateScroll);
10609    init_Bres(screen.scrollttyoutput);
10610    init_Bres(screen.scrollkey);
10611
10612    init_Dres(screen.scale_height);
10613    if (screen->scale_height < MIN_SCALE_HEIGHT)
10614	screen->scale_height = MIN_SCALE_HEIGHT;
10615    if (screen->scale_height > MAX_SCALE_HEIGHT)
10616	screen->scale_height = MAX_SCALE_HEIGHT;
10617
10618    init_Bres(misc.autoWrap);
10619    init_Bres(misc.login_shell);
10620    init_Bres(misc.reverseWrap);
10621    init_Bres(misc.scrollbar);
10622    init_Sres(misc.geo_metry);
10623    init_Sres(misc.T_geometry);
10624
10625    init_Sres(screen.term_id);
10626    screen->terminal_id = decodeTerminalID(TScreenOf(request)->term_id);
10627    screen->display_da1 = screen->terminal_id;
10628    /*
10629     * (1) If a known terminal model, and not a graphical terminal, preserve
10630     *     the terminal id.
10631     * (2) Otherwise, if ReGIS or sixel graphics are enabled, preserve the ID,
10632     *     even if it is not a known terminal.
10633     * (3) Otherwise force the terminal ID to the min, max, or VT420 depending
10634     *     on the input.
10635     */
10636    switch (screen->terminal_id) {
10637    case 52:			/* MIN_DECID */
10638    case 100:
10639    case 101:
10640    case 102:
10641    case 131:
10642    case 132:
10643    case 220:
10644    case 320:
10645    case 420:			/* DFT_DECID, unless overridden in configure */
10646    case 510:
10647    case 520:
10648    case 525:			/* MAX_DECID */
10649	break;
10650    default:
10651#if OPT_REGIS_GRAPHICS
10652	if (optRegisGraphics(screen))
10653	    break;
10654#endif
10655#if OPT_SIXEL_GRAPHICS
10656	if (optSixelGraphics(screen))
10657	    break;
10658#endif
10659	screen->terminal_id = limitedTerminalID(screen->terminal_id);
10660	screen->display_da1 = screen->terminal_id;
10661	break;
10662    }
10663    TRACE(("term_id '%s' -> terminal_id %d\n",
10664	   screen->term_id,
10665	   screen->terminal_id));
10666
10667    set_vtXX_level(screen, (screen->terminal_id / 100));
10668
10669    init_Ires(screen.title_modes);
10670    screen->title_modes0 = screen->title_modes;
10671
10672    init_Ires(screen.nextEventDelay);
10673    if (screen->nextEventDelay <= 0)
10674	screen->nextEventDelay = 1;
10675
10676    init_Bres(screen.visualbell);
10677    init_Bres(screen.flash_line);
10678    init_Ires(screen.visualBellDelay);
10679    init_Bres(screen.poponbell);
10680
10681    init_Bres(screen.eraseSavedLines0);
10682    screen->eraseSavedLines = screen->eraseSavedLines0;
10683
10684    init_Ires(misc.limit_resize);
10685
10686#if OPT_NUM_LOCK
10687    init_Bres(misc.real_NumLock);
10688    init_Bres(misc.alwaysUseMods);
10689#endif
10690
10691#if OPT_INPUT_METHOD
10692    init_Bres(misc.open_im);
10693    init_Ires(misc.retry_im);
10694    init_Sres(misc.f_x);
10695    init_Sres(misc.input_method);
10696    init_Sres(misc.preedit_type);
10697#endif
10698
10699#if OPT_SHIFT_FONTS
10700    init_Bres(misc.shift_fonts);
10701#endif
10702#if OPT_SUNPC_KBD
10703    init_Ires(misc.ctrl_fkeys);
10704#endif
10705#if OPT_TEK4014
10706    TEK4014_SHOWN(wnew) = False;	/* not a resource... */
10707    init_Bres(misc.tekInhibit);
10708    init_Bres(misc.tekSmall);
10709    init_Bres(misc.TekEmu);
10710#endif
10711#if OPT_TCAP_QUERY
10712    screen->tc_query_code = -1;
10713#endif
10714    wnew->misc.re_verse0 = request->misc.re_verse;
10715    init_Bres(misc.re_verse);
10716    init_Ires(screen.multiClickTime);
10717    init_Ires(screen.bellSuppressTime);
10718    init_Sres(screen.charClass);
10719
10720    init_Bres(screen.always_highlight);
10721    init_Bres(screen.brokenSelections);
10722    init_Bres(screen.cutNewline);
10723    init_Bres(screen.cutToBeginningOfLine);
10724    init_Bres(screen.highlight_selection);
10725    init_Bres(screen.show_wrap_marks);
10726    init_Bres(screen.i18nSelections);
10727    init_Bres(screen.keepClipboard);
10728    init_Bres(screen.keepSelection);
10729    init_Bres(screen.selectToClipboard);
10730    init_Bres(screen.trim_selection);
10731
10732    screen->pointer_cursor = TScreenOf(request)->pointer_cursor;
10733    init_Ires(screen.pointer_mode);
10734    wnew->screen.pointer_mode0 = wnew->screen.pointer_mode;
10735
10736    init_Sres(screen.answer_back);
10737    init_Bres(screen.prefer_latin1);
10738
10739    wnew->SPS.printer_checked = False;
10740    init_Sres(SPS.printer_command);
10741    init_Bres(SPS.printer_autoclose);
10742    init_Bres(SPS.printer_extent);
10743    init_Bres(SPS.printer_formfeed);
10744    init_Bres(SPS.printer_newline);
10745    init_Ires(SPS.printer_controlmode);
10746#if OPT_PRINT_COLORS
10747    init_Ires(SPS.print_attributes);
10748#endif
10749    init_Bres(screen.print_rawchars);
10750
10751    init_Sres(screen.keyboard_dialect);
10752
10753    init_Sres(screen.cursor_font_name);
10754    init_Sres(screen.pointer_shape);
10755
10756    init_Bres(screen.input_eight_bits);
10757    init_Bres(screen.output_eight_bits);
10758    init_Bres(screen.control_eight_bits);
10759    init_Bres(screen.backarrow_key);
10760    init_Bres(screen.alt_is_not_meta);
10761    init_Bres(screen.alt_sends_esc);
10762    init_Bres(screen.meta_sends_esc);
10763
10764    init_Bres(screen.allowPasteControl0);
10765    init_Bres(screen.allowSendEvent0);
10766    init_Bres(screen.allowColorOp0);
10767    init_Bres(screen.allowFontOp0);
10768    init_Bres(screen.allowMouseOp0);
10769    init_Bres(screen.allowTcapOp0);
10770    init_Bres(screen.allowTitleOp0);
10771    init_Bres(screen.allowWindowOp0);
10772
10773#if OPT_SCROLL_LOCK
10774    init_Bres(screen.allowScrollLock0);
10775    init_Bres(screen.autoScrollLock);
10776#endif
10777
10778    init_Sres(screen.disallowedColorOps);
10779
10780    set_flags_from_list(screen->disallow_color_ops,
10781			screen->disallowedColorOps,
10782			tblColorOps);
10783
10784    init_Sres(screen.disallowedFontOps);
10785
10786    set_flags_from_list(screen->disallow_font_ops,
10787			screen->disallowedFontOps,
10788			tblFontOps);
10789
10790    init_Sres(screen.disallowedMouseOps);
10791
10792    set_flags_from_list(screen->disallow_mouse_ops,
10793			screen->disallowedMouseOps,
10794			tblMouseOps);
10795
10796    init_Sres(screen.disallowedPasteOps);
10797
10798    set_flags_from_list(screen->disallow_paste_ops,
10799			screen->disallowedPasteOps,
10800			tblPasteOps);
10801
10802    init_Sres(screen.disallowedTcapOps);
10803
10804    set_flags_from_list(screen->disallow_tcap_ops,
10805			screen->disallowedTcapOps,
10806			tblTcapOps);
10807
10808    init_Sres(screen.disallowedWinOps);
10809
10810    set_flags_from_list(screen->disallow_win_ops,
10811			screen->disallowedWinOps,
10812			tblWindowOps);
10813
10814    init_Sres(screen.default_string);
10815    init_Sres(screen.eightbit_select_types);
10816#if OPT_WIDE_CHARS
10817    init_Sres(screen.utf8_select_types);
10818#endif
10819
10820    /* make a copy so that editres cannot change the resource after startup */
10821    screen->allowPasteControls = screen->allowPasteControl0;
10822    screen->allowSendEvents = screen->allowSendEvent0;
10823    screen->allowColorOps = screen->allowColorOp0;
10824    screen->allowFontOps = screen->allowFontOp0;
10825    screen->allowMouseOps = screen->allowMouseOp0;
10826    screen->allowTcapOps = screen->allowTcapOp0;
10827    screen->allowTitleOps = screen->allowTitleOp0;
10828    screen->allowWindowOps = screen->allowWindowOp0;
10829
10830#if OPT_SCROLL_LOCK
10831    screen->allowScrollLock = screen->allowScrollLock0;
10832#endif
10833
10834    init_Bres(screen.quiet_grab);
10835
10836#ifndef NO_ACTIVE_ICON
10837    init_Sres(screen.icon_fontname);
10838    getIconicFont(screen)->fs = xtermLoadQueryFont(wnew,
10839						   screen->icon_fontname);
10840    TRACE(("iconFont '%s' %sloaded successfully\n",
10841	   screen->icon_fontname,
10842	   getIconicFont(screen)->fs ? "" : "NOT "));
10843    init_Sres(misc.active_icon_s);
10844    wnew->work.active_icon =
10845	(Boolean) extendedBoolean(wnew->misc.active_icon_s,
10846				  tblAIconOps, eiLAST);
10847    init_Ires(misc.icon_border_width);
10848    wnew->misc.icon_border_pixel = request->misc.icon_border_pixel;
10849#endif /* NO_ACTIVE_ICON */
10850
10851    init_Bres(misc.signalInhibit);
10852    init_Bres(misc.titeInhibit);
10853    init_Bres(misc.color_inner_border);
10854    init_Bres(misc.dynamicColors);
10855    init_Bres(misc.resizeByPixel);
10856
10857    init_Sres(misc.cdXtraScroll_s);
10858    wnew->misc.cdXtraScroll =
10859	extendedBoolean(request->misc.cdXtraScroll_s, tblCdXtraScroll, edLast);
10860
10861    init_Sres(misc.tiXtraScroll_s);
10862    wnew->misc.tiXtraScroll =
10863	extendedBoolean(request->misc.tiXtraScroll_s, tblCdXtraScroll, edLast);
10864
10865#if OPT_DEC_CHRSET
10866    for (i = 0; i < NUM_CHRSET; i++) {
10867	screen->double_fonts[i].warn = fwResource;
10868    }
10869#endif
10870    for (i = fontMenu_font1; i <= fontMenu_lastBuiltin; i++) {
10871	init_Sres2(screen.MenuFontName, i);
10872    }
10873    for (i = 0; i < fMAX; i++) {
10874	screen->fnts[i].warn = fwResource;
10875#if OPT_WIDE_ATTRS
10876	screen->ifnts[i].warn = fwResource;
10877#endif
10878    }
10879#ifndef NO_ACTIVE_ICON
10880    screen->fnt_icon.warn = fwResource;
10881#endif
10882
10883    init_Ires(misc.fontWarnings);
10884
10885    initFontLists(wnew);
10886
10887#define DefaultFontNames screen->menu_font_names[fontMenu_default]
10888
10889    /*
10890     * Process Xft font resources first, since faceName may contain X11 fonts
10891     * that should override the "font" resource.
10892     */
10893#if OPT_RENDERFONT
10894    init_Bres(screen.force_xft_height);
10895    for (i = 0; i <= fontMenu_lastBuiltin; ++i) {
10896	init_Dres2(misc.face_size, i);
10897    }
10898    init_Ires(screen.xft_max_glyph_memory);
10899    init_Ires(screen.xft_max_unref_fonts);
10900    init_Bres(screen.xft_track_mem_usage);
10901
10902#define ALLOC_FONTLIST(name,which,field) \
10903    init_Sres(misc.default_xft.field);\
10904    allocFontList(wnew,\
10905		  name,\
10906		  &(wnew->work.fonts),\
10907		  which,\
10908		  wnew->misc.default_xft.field,\
10909		  True)
10910
10911    ALLOC_FONTLIST(XtNfaceName, fNorm, f_n);
10912
10913#if OPT_WIDE_CHARS
10914    ALLOC_FONTLIST(XtNfaceNameDoublesize, fWide, f_w);
10915#endif
10916
10917#undef ALLOC_FONTLIST
10918
10919#endif
10920
10921    /*
10922     * Process X11 (XLFD) font specifications.
10923     */
10924#define ALLOC_FONTLIST(name,which,field) \
10925    init_Sres(misc.default_font.field);\
10926    allocFontList(wnew,\
10927		  name,\
10928		  &(wnew->work.fonts),\
10929		  which,\
10930		  wnew->misc.default_font.field,\
10931		  False)
10932
10933    ALLOC_FONTLIST(XtNfont, fNorm, f_n);
10934    ALLOC_FONTLIST(XtNboldFont, fBold, f_b);
10935
10936    DefaultFontNames[fNorm] = x_strdup(DefaultFontN(wnew));
10937    DefaultFontNames[fBold] = x_strdup(DefaultFontB(wnew));
10938
10939#if OPT_WIDE_CHARS
10940    ALLOC_FONTLIST(XtNwideFont, fWide, f_w);
10941    ALLOC_FONTLIST(XtNwideBoldFont, fWBold, f_wb);
10942
10943    DefaultFontNames[fWide] = x_strdup(DefaultFontW(wnew));
10944    DefaultFontNames[fWBold] = x_strdup(DefaultFontWB(wnew));
10945#endif
10946
10947#undef ALLOC_FONTLIST
10948
10949    screen->EscapeFontName() = NULL;
10950    screen->SelectFontName() = NULL;
10951
10952    screen->menu_font_number = fontMenu_default;
10953    init_Sres(screen.initial_font);
10954    if (screen->initial_font != NULL) {
10955	int result = xtermGetFont(screen->initial_font);
10956	if (result >= 0)
10957	    screen->menu_font_number = result;
10958    }
10959#if OPT_BROKEN_OSC
10960    init_Bres(screen.brokenLinuxOSC);
10961#endif
10962
10963#if OPT_BROKEN_ST
10964    init_Bres(screen.brokenStringTerm);
10965#endif
10966
10967#if OPT_C1_PRINT
10968    init_Bres(screen.c1_printable);
10969#endif
10970
10971#if OPT_CLIP_BOLD
10972    init_Bres(screen.use_border_clipping);
10973    init_Bres(screen.use_clipping);
10974#endif
10975
10976#if OPT_DEC_CHRSET
10977    init_Bres(screen.font_doublesize);
10978    init_Ires(screen.cache_doublesize);
10979    if (screen->cache_doublesize > NUM_CHRSET)
10980	screen->cache_doublesize = NUM_CHRSET;
10981    if (screen->cache_doublesize == 0)
10982	screen->font_doublesize = False;
10983    TRACE(("Doublesize%s enabled, up to %d fonts\n",
10984	   screen->font_doublesize ? "" : " not",
10985	   screen->cache_doublesize));
10986#endif
10987#if OPT_DEC_RECTOPS
10988    init_Ires(screen.checksum_ext0);
10989    screen->checksum_ext = screen->checksum_ext0;
10990#endif
10991
10992#if OPT_ISO_COLORS
10993    init_Ires(screen.veryBoldColors);
10994    init_Bres(screen.boldColors);
10995    init_Bres(screen.colorAttrMode);
10996    init_Bres(screen.colorBDMode);
10997    init_Bres(screen.colorBLMode);
10998    init_Bres(screen.colorMode);
10999    init_Bres(screen.colorULMode);
11000    init_Bres(screen.italicULMode);
11001    init_Bres(screen.colorRVMode);
11002
11003#if OPT_WIDE_ATTRS
11004    init_Bres(screen.colorITMode);
11005#endif
11006#if OPT_DIRECT_COLOR
11007    init_Bres(screen.direct_color);
11008#endif
11009#if OPT_WIDE_ATTRS && OPT_SGR2_HASH
11010    init_Bres(screen.faint_relative);
11011#endif
11012
11013#if OPT_VT525_COLORS
11014    screen->assigned_fg = 7;
11015    screen->assigned_bg = 0;
11016#if MIN_ANSI_COLORS >= 16
11017    /*
11018     * VT520-RM does not define the initial palette, but this is preferable
11019     * to black-on-black.
11020     */
11021    for (i = 0; i < 16; i++) {
11022	screen->alt_colors[i].fg = screen->assigned_fg;
11023	screen->alt_colors[i].bg = screen->assigned_bg;
11024    }
11025#endif
11026#endif
11027
11028    TRACE(("...will fake resources for color%d to color%d\n",
11029	   MIN_ANSI_COLORS,
11030	   NUM_ANSI_COLORS - 1));
11031
11032    for (i = 0, color_ok = False; i < MAXCOLORS; i++) {
11033	/*
11034	 * Xt has a hardcoded limit on the maximum number of resources that can
11035	 * be used in a widget.  If we configured both luit (which implies
11036	 * wide-characters) and 256-colors, it goes over that limit.  Most
11037	 * people would not need a resource-file with 256-colors; the default
11038	 * values in our table are sufficient.  Fake the resource setting by
11039	 * copying the default value from the table.  The #define's can be
11040	 * overridden to make these true resources.
11041	 */
11042	if (i >= MIN_ANSI_COLORS && i < NUM_ANSI_COLORS) {
11043	    screen->Acolors[i].resource =
11044		x_strtrim(fake_resources[i - MIN_ANSI_COLORS].default_addr);
11045	    if (screen->Acolors[i].resource == NULL)
11046		screen->Acolors[i].resource = XtDefaultForeground;
11047	} else {
11048	    screen->Acolors[i] = TScreenOf(request)->Acolors[i];
11049	    screen->Acolors[i].resource =
11050		x_strtrim(screen->Acolors[i].resource);
11051	}
11052
11053	TRACE(("Acolors[%d] = %s\n", i, screen->Acolors[i].resource));
11054	screen->Acolors[i].mode = False;
11055	if (DftFg(Acolors[i])) {
11056	    screen->Acolors[i].value = T_COLOR(screen, TEXT_FG);
11057	    screen->Acolors[i].mode = True;
11058	} else if (DftBg(Acolors[i])) {
11059	    screen->Acolors[i].value = T_COLOR(screen, TEXT_BG);
11060	    screen->Acolors[i].mode = True;
11061	} else {
11062	    color_ok = True;
11063	}
11064    }
11065
11066    /*
11067     * Check if we're trying to use color in a monochrome screen.  Disable
11068     * color in that case, since that would make ANSI colors unusable.  A 4-bit
11069     * or 8-bit display is usable, so we do not have to check for anything more
11070     * specific.
11071     */
11072    if (color_ok) {
11073	if (getVisualDepth(wnew) <= 1) {
11074	    TRACE(("disabling color since screen is monochrome\n"));
11075	    color_ok = False;
11076	}
11077    }
11078
11079    /* If none of the colors are anything other than the foreground or
11080     * background, we'll assume this isn't color, no matter what the colorMode
11081     * resource says.  (There doesn't seem to be any good way to determine if
11082     * the resource lookup failed versus the user having misconfigured this).
11083     */
11084    if (!color_ok) {
11085	screen->colorMode = False;
11086	TRACE(("All colors are foreground or background: disable colorMode\n"));
11087    }
11088    wnew->sgr_foreground = -1;
11089    wnew->sgr_background = -1;
11090    wnew->sgr_38_xcolors = False;
11091    clrDirectFG(wnew->flags);
11092    clrDirectFG(wnew->flags);
11093#endif /* OPT_ISO_COLORS */
11094
11095    /*
11096     * Decode the resources that control the behavior on multiple mouse clicks.
11097     * A single click is always bound to normal character selection, but the
11098     * other flavors can be changed.
11099     */
11100    for (i = 0; i < NSELECTUNITS; ++i) {
11101	int ck = (i + 1);
11102	screen->maxClicks = ck;
11103	if (i == Select_CHAR)
11104	    screen->selectMap[i] = Select_CHAR;
11105	else if (TScreenOf(request)->onClick[i] != NULL)
11106	    ParseOnClicks(wnew, request, (unsigned) i);
11107	else if (i <= Select_LINE)
11108	    screen->selectMap[i] = (SelectUnit) i;
11109	else
11110	    break;
11111#if OPT_XRES_QUERY
11112	init_Sres(screen.onClick[i]);
11113#endif
11114	TRACE(("on%dClicks %s=%d\n", ck,
11115	       NonNull(TScreenOf(request)->onClick[i]),
11116	       screen->selectMap[i]));
11117	if (screen->selectMap[i] == NSELECTUNITS)
11118	    break;
11119    }
11120    TRACE(("maxClicks %d\n", screen->maxClicks));
11121
11122    init_Tres(MOUSE_FG);
11123    init_Tres(MOUSE_BG);
11124    init_Tres(TEXT_CURSOR);
11125#if OPT_HIGHLIGHT_COLOR
11126    init_Tres(HIGHLIGHT_BG);
11127    init_Tres(HIGHLIGHT_FG);
11128    init_Bres(screen.hilite_reverse);
11129    init_Mres(screen.hilite_color);
11130    if (screen->hilite_color == Maybe) {
11131	screen->hilite_color = False;
11132	/*
11133	 * If the highlight text/background are both set, and if they are
11134	 * not equal to either the text/background or background/text, then
11135	 * set the highlightColorMode automatically.
11136	 */
11137	if (!DftFg(Tcolors[HIGHLIGHT_BG])
11138	    && !DftBg(Tcolors[HIGHLIGHT_FG])
11139	    && !TxtFg(Tcolors[HIGHLIGHT_BG])
11140	    && !TxtBg(Tcolors[HIGHLIGHT_FG])
11141	    && !TxtBg(Tcolors[HIGHLIGHT_BG])
11142	    && !TxtFg(Tcolors[HIGHLIGHT_FG])) {
11143	    TRACE(("...setting hilite_color automatically\n"));
11144	    screen->hilite_color = True;
11145	}
11146    }
11147#endif
11148
11149#if OPT_TEK4014
11150    /*
11151     * The Tek4014 window has no separate resources for foreground, background
11152     * and cursor color.  Since xterm always creates the vt100 widget first, we
11153     * can set the Tektronix colors here.  That lets us use escape sequences to
11154     * set its dynamic colors and get consistent behavior whether or not the
11155     * window is displayed.
11156     */
11157    screen->Tcolors[TEK_BG] = screen->Tcolors[TEXT_BG];
11158    screen->Tcolors[TEK_FG] = screen->Tcolors[TEXT_FG];
11159    screen->Tcolors[TEK_CURSOR] = screen->Tcolors[TEXT_CURSOR];
11160#endif
11161
11162#ifdef SCROLLBAR_RIGHT
11163    init_Bres(misc.useRight);
11164#endif
11165
11166#if OPT_RENDERFONT
11167    init_Ires(misc.limit_fontsets);
11168    init_Ires(misc.limit_fontheight);
11169    if (wnew->misc.limit_fontheight > 50) {
11170	xtermWarning("limiting extra fontheight percent to 50 (was %d)\n",
11171		     wnew->misc.limit_fontheight);
11172	wnew->misc.limit_fontheight = 50;
11173    }
11174    init_Ires(misc.limit_fontwidth);
11175    if (wnew->misc.limit_fontwidth > 50) {
11176	xtermWarning("limiting extra fontwidth percent to 50 (was %d)\n",
11177		     wnew->misc.limit_fontwidth);
11178	wnew->misc.limit_fontwidth = 50;
11179    }
11180    wnew->work.max_fontsets = (unsigned) wnew->misc.limit_fontsets;
11181    if (wnew->work.max_fontsets > 255) {
11182	xtermWarning("limiting number of fontsets to 255 (was %u)\n",
11183		     wnew->work.max_fontsets);
11184	wnew->work.max_fontsets = 255;
11185    }
11186
11187    init_Sres(misc.render_font_s);
11188    wnew->work.render_font =
11189	(Boolean) extendedBoolean(wnew->misc.render_font_s,
11190				  tblRenderFont, erLast);
11191    if (wnew->work.render_font == erDefault) {
11192	if (IsEmpty(CurrentXftFont(wnew))) {
11193	    free((void *) CurrentXftFont(wnew));
11194	    CurrentXftFont(wnew) = x_strdup(DEFFACENAME_AUTO);
11195	    TRACE(("will allow runtime switch to render_font using \"%s\"\n",
11196		   CurrentXftFont(wnew)));
11197	} else {
11198	    wnew->work.render_font = erTrue;
11199	    TRACE(("initially using TrueType font\n"));
11200	}
11201    } else if (wnew->work.render_font == erDefaultOff) {
11202	wnew->work.render_font = erFalse;
11203    }
11204    /* minor tweak to make debug traces consistent: */
11205    if (wnew->work.render_font) {
11206	if (IsEmpty(CurrentXftFont(wnew))) {
11207	    wnew->work.render_font = False;
11208	    TRACE(("reset render_font since there is no face_name\n"));
11209	}
11210    }
11211#endif
11212
11213#if OPT_WIDE_CHARS
11214    /* setup data for next call */
11215    init_Sres(screen.utf8_mode_s);
11216    request->screen.utf8_mode =
11217	extendedBoolean(request->screen.utf8_mode_s, tblUtf8Mode, uLast);
11218
11219    init_Sres(screen.utf8_fonts_s);
11220    request->screen.utf8_fonts =
11221	extendedBoolean(request->screen.utf8_fonts_s, tblUtf8Mode, uLast);
11222
11223    init_Sres(screen.utf8_title_s);
11224    request->screen.utf8_title =
11225	extendedBoolean(request->screen.utf8_title_s, tblUtf8Mode, uLast);
11226
11227    /*
11228     * Make a copy in the input/request so that DefaultFontN() works for
11229     * the "CHECKFONT" option.
11230     */
11231    copyFontList(&(request->work.fonts.x11.list_n),
11232		 wnew->work.fonts.x11.list_n);
11233
11234    VTInitialize_locale(request);
11235    init_Bres(screen.normalized_c);
11236    init_Bres(screen.utf8_latin1);
11237    init_Bres(screen.utf8_weblike);
11238
11239#if OPT_LUIT_PROG
11240    init_Bres(misc.callfilter);
11241    init_Bres(misc.use_encoding);
11242    init_Sres(misc.locale_str);
11243    init_Sres(misc.localefilter);
11244#endif
11245
11246    init_Ires(screen.utf8_inparse);
11247    init_Ires(screen.utf8_mode);
11248    init_Ires(screen.utf8_fonts);
11249    init_Ires(screen.utf8_title);
11250    init_Ires(screen.max_combining);
11251
11252    init_Ires(screen.utf8_always);	/* from utf8_mode, used in doparse */
11253
11254    if (screen->max_combining < 0) {
11255	screen->max_combining = 0;
11256    }
11257    if (screen->max_combining > 5) {
11258	screen->max_combining = 5;
11259    }
11260
11261    init_Bres(screen.vt100_graphics);
11262    init_Bres(screen.wide_chars);
11263    init_Bres(misc.mk_width);
11264    init_Bres(misc.cjk_width);
11265
11266    init_Ires(misc.mk_samplesize);
11267    init_Ires(misc.mk_samplepass);
11268
11269    if (wnew->misc.mk_samplesize > 0xffff)
11270	wnew->misc.mk_samplesize = 0xffff;
11271    if (wnew->misc.mk_samplesize < 0)
11272	wnew->misc.mk_samplesize = 0;
11273
11274    if (wnew->misc.mk_samplepass > wnew->misc.mk_samplesize)
11275	wnew->misc.mk_samplepass = wnew->misc.mk_samplesize;
11276    if (wnew->misc.mk_samplepass < 0)
11277	wnew->misc.mk_samplepass = 0;
11278
11279    if (TScreenOf(request)->utf8_mode) {
11280	TRACE(("setting wide_chars on\n"));
11281	screen->wide_chars = True;
11282    } else {
11283	TRACE(("setting utf8_mode to 0\n"));
11284	screen->utf8_mode = uFalse;
11285    }
11286    mk_wcwidth_init(screen->utf8_mode);
11287    TRACE(("initialized UTF-8 mode to %d\n", screen->utf8_mode));
11288
11289#if OPT_MINI_LUIT
11290    if (TScreenOf(request)->latin9_mode) {
11291	screen->latin9_mode = True;
11292    }
11293    if (TScreenOf(request)->unicode_font) {
11294	screen->unicode_font = True;
11295    }
11296    TRACE(("initialized Latin9 mode to %d\n", screen->latin9_mode));
11297    TRACE(("initialized unicode_font to %d\n", screen->unicode_font));
11298#endif
11299
11300    decode_wcwidth(wnew);
11301    xtermSaveVTFonts(wnew);
11302#endif /* OPT_WIDE_CHARS */
11303
11304    init_Sres(screen.eight_bit_meta_s);
11305    wnew->screen.eight_bit_meta =
11306	extendedBoolean(request->screen.eight_bit_meta_s, tbl8BitMeta, ebLast);
11307    if (wnew->screen.eight_bit_meta == ebLocale) {
11308#if OPT_WIDE_CHARS
11309	if (xtermEnvUTF8()) {
11310	    wnew->screen.eight_bit_meta = ebFalse;
11311	    TRACE(("...eightBitMeta is false due to locale\n"));
11312	} else
11313#endif /* OPT_WIDE_CHARS */
11314	{
11315	    wnew->screen.eight_bit_meta = ebTrue;
11316	    TRACE(("...eightBitMeta is true due to locale\n"));
11317	}
11318    }
11319
11320    init_Bres(screen.always_bold_mode);
11321    init_Bres(screen.bold_mode);
11322    init_Bres(screen.underline);
11323
11324    wnew->cur_foreground = 0;
11325    wnew->cur_background = 0;
11326
11327    wnew->keyboard.flags = MODE_SRM;
11328
11329    if (screen->backarrow_key)
11330	wnew->keyboard.flags |= MODE_DECBKM;
11331    TRACE(("initialized DECBKM %s\n",
11332	   BtoS(wnew->keyboard.flags & MODE_DECBKM)));
11333
11334#if OPT_SIXEL_GRAPHICS
11335    /* Sixel scrolling is opposite of Sixel Display Mode */
11336    init_Bres(screen.sixel_scrolling);
11337    if (screen->sixel_scrolling)
11338	UIntClr(wnew->keyboard.flags, MODE_DECSDM);
11339    else
11340	UIntSet(wnew->keyboard.flags, MODE_DECSDM);
11341    TRACE(("initialized DECSDM %s\n",
11342	   BtoS(wnew->keyboard.flags & MODE_DECSDM)));
11343#endif
11344
11345#if OPT_GRAPHICS
11346    init_Sres(screen.graph_termid);
11347    screen->graphics_termid = decodeTerminalID(TScreenOf(request)->graph_termid);
11348    switch (screen->graphics_termid) {
11349    case 125:
11350    case 240:
11351    case 241:
11352    case 330:
11353    case 340:
11354    case 382:
11355	break;
11356    default:
11357	screen->graphics_termid = 0;
11358	break;
11359    }
11360    TRACE(("graph_termid '%s' -> graphics_termid %d\n",
11361	   screen->graph_termid,
11362	   screen->graphics_termid));
11363
11364    init_Ires(screen.numcolorregisters);
11365    TRACE(("initialized NUM_COLOR_REGISTERS to resource default: %d\n",
11366	   screen->numcolorregisters));
11367
11368    init_Bres(screen.privatecolorregisters);	/* FIXME: should this be off unconditionally here? */
11369    TRACE(("initialized PRIVATE_COLOR_REGISTERS to resource default: %s\n",
11370	   BtoS(screen->privatecolorregisters)));
11371    screen->privatecolorregisters0 = screen->privatecolorregisters;
11372
11373    init_Bres(screen.incremental_graphics);
11374    TRACE(("initialized INCREMENTAL_GRAPHICS to resource default: %s\n",
11375	   BtoS(screen->incremental_graphics)));
11376#endif
11377
11378#if OPT_GRAPHICS
11379    {
11380	int native_w, native_h;
11381
11382	switch (GraphicsTermId(screen)) {
11383	case 125:
11384	    native_w = 768;
11385	    native_h = 460;
11386	    break;
11387	case 240:
11388	    /* FALLTHRU */
11389	case 241:
11390	    native_w = 800;
11391	    native_h = 460;
11392	    break;
11393	case 330:
11394	    /* FALLTHRU */
11395	case 340:
11396	    native_w = 800;
11397	    native_h = 480;
11398	    break;
11399	default:
11400	    native_w = 800;
11401	    native_h = 480;
11402	    break;
11403	case 382:
11404	    native_w = 960;
11405	    native_h = 720;
11406	    break;
11407	}
11408
11409# if OPT_REGIS_GRAPHICS
11410	init_Sres(screen.graphics_regis_default_font);
11411	TRACE(("default ReGIS font: %s\n",
11412	       screen->graphics_regis_default_font));
11413
11414	init_Sres(screen.graphics_regis_screensize);
11415	screen->graphics_regis_def_high = 1000;
11416	screen->graphics_regis_def_wide = 1000;
11417	if (!x_strcasecmp(screen->graphics_regis_screensize, "auto")) {
11418	    TRACE(("setting default ReGIS screensize based on graphics_id %d\n",
11419		   GraphicsTermId(screen)));
11420	    screen->graphics_regis_def_high = (Dimension) native_h;
11421	    screen->graphics_regis_def_wide = (Dimension) native_w;
11422	} else {
11423	    int conf_high;
11424	    int conf_wide;
11425	    char ignore;
11426
11427	    if (sscanf(screen->graphics_regis_screensize,
11428		       "%dx%d%c",
11429		       &conf_wide,
11430		       &conf_high,
11431		       &ignore) == 2) {
11432		if (conf_high > 0 && conf_wide > 0) {
11433		    screen->graphics_regis_def_high =
11434			(Dimension) conf_high;
11435		    screen->graphics_regis_def_wide =
11436			(Dimension) conf_wide;
11437		} else {
11438		    TRACE(("ignoring invalid regisScreenSize %s\n",
11439			   screen->graphics_regis_screensize));
11440		}
11441	    } else {
11442		TRACE(("ignoring invalid regisScreenSize %s\n",
11443		       screen->graphics_regis_screensize));
11444	    }
11445	}
11446	TRACE(("default ReGIS graphics screensize %dx%d\n",
11447	       (int) screen->graphics_regis_def_wide,
11448	       (int) screen->graphics_regis_def_high));
11449# endif
11450
11451	init_Sres(screen.graphics_max_size);
11452	screen->graphics_max_high = 1000;
11453	screen->graphics_max_wide = 1000;
11454	if (!x_strcasecmp(screen->graphics_max_size, "auto")) {
11455	    TRACE(("setting max graphics screensize based on graphics_id %d\n",
11456		   GraphicsTermId(screen)));
11457	    screen->graphics_max_high = (Dimension) native_h;
11458	    screen->graphics_max_wide = (Dimension) native_w;
11459	} else {
11460	    int conf_high;
11461	    int conf_wide;
11462	    char ignore;
11463
11464	    if (sscanf(screen->graphics_max_size,
11465		       "%dx%d%c",
11466		       &conf_wide,
11467		       &conf_high,
11468		       &ignore) == 2) {
11469		if (conf_high > 0 && conf_wide > 0) {
11470		    screen->graphics_max_high = (Dimension) conf_high;
11471		    screen->graphics_max_wide = (Dimension) conf_wide;
11472		} else {
11473		    TRACE(("ignoring invalid maxGraphicSize %s\n",
11474			   screen->graphics_max_size));
11475		}
11476	    } else {
11477		TRACE(("ignoring invalid maxGraphicSize %s\n",
11478		       screen->graphics_max_size));
11479	    }
11480	}
11481# if OPT_REGIS_GRAPHICS
11482	/* Make sure the max is large enough for the default ReGIS size. */
11483	if (screen->graphics_regis_def_high >
11484	    screen->graphics_max_high) {
11485	    screen->graphics_max_high =
11486		screen->graphics_regis_def_high;
11487	}
11488	if (screen->graphics_regis_def_wide >
11489	    screen->graphics_max_wide) {
11490	    screen->graphics_max_wide =
11491		screen->graphics_regis_def_wide;
11492	}
11493# endif
11494	TRACE(("max graphics screensize %dx%d\n",
11495	       (int) screen->graphics_max_wide,
11496	       (int) screen->graphics_max_high));
11497    }
11498#endif
11499
11500#if OPT_SIXEL_GRAPHICS
11501    init_Bres(screen.sixel_scrolls_right);
11502    screen->sixel_scrolls_right0 = screen->sixel_scrolls_right;
11503#endif
11504#if OPT_PRINT_GRAPHICS
11505    init_Bres(screen.graphics_print_to_host);
11506    init_Bres(screen.graphics_expanded_print_mode);
11507    init_Bres(screen.graphics_print_color_mode);
11508    init_Bres(screen.graphics_print_color_syntax);
11509    init_Bres(screen.graphics_print_background_mode);
11510    init_Bres(screen.graphics_rotated_print_mode);
11511#endif
11512
11513#if OPT_STATUS_LINE
11514    init_Sres(screen.status_fmt);
11515#endif
11516
11517    /* look for focus related events on the shell, because we need
11518     * to care about the shell's border being part of our focus.
11519     */
11520    TRACE(("adding event handlers for my_parent %p\n", (void *) my_parent));
11521    XtAddEventHandler(my_parent, EnterWindowMask, False,
11522		      HandleEnterWindow, (Opaque) NULL);
11523    XtAddEventHandler(my_parent, LeaveWindowMask, False,
11524		      HandleLeaveWindow, (Opaque) NULL);
11525    XtAddEventHandler(my_parent, FocusChangeMask, False,
11526		      HandleFocusChange, (Opaque) NULL);
11527    XtAddEventHandler((Widget) wnew, 0L, True,
11528		      VTNonMaskableEvent, (Opaque) NULL);
11529    XtAddEventHandler((Widget) wnew, PropertyChangeMask, False,
11530		      HandleBellPropertyChange, (Opaque) NULL);
11531
11532#if HANDLE_STRUCT_NOTIFY
11533#if OPT_TOOLBAR
11534    wnew->VT100_TB_INFO(menu_bar) = request->VT100_TB_INFO(menu_bar);
11535    init_Ires(VT100_TB_INFO(menu_height));
11536#endif
11537    XtAddEventHandler(my_parent, MappingNotify | StructureNotifyMask, False,
11538		      HandleStructNotify, (Opaque) 0);
11539#endif /* HANDLE_STRUCT_NOTIFY */
11540
11541    screen->bellInProgress = False;
11542
11543    set_character_class(screen->charClass);
11544#if OPT_REPORT_CCLASS
11545    if (resource.reportCClass)
11546	report_char_class(wnew);
11547#endif
11548
11549    /* create it, but don't realize it */
11550    ScrollBarOn(wnew, True);
11551
11552    /* make sure that the resize gravity acceptable */
11553    if (!GravityIsNorthWest(wnew) &&
11554	!GravityIsSouthWest(wnew)) {
11555	char value[80];
11556	String temp[2];
11557	Cardinal nparams = 1;
11558
11559	sprintf(value, "%d", wnew->misc.resizeGravity);
11560	temp[0] = value;
11561	temp[1] = NULL;
11562	XtAppWarningMsg(app_con, "rangeError", "resizeGravity", "XTermError",
11563			"unsupported resizeGravity resource value (%s)",
11564			temp, &nparams);
11565	wnew->misc.resizeGravity = SouthWestGravity;
11566    }
11567#ifndef NO_ACTIVE_ICON
11568    screen->whichVwin = &screen->fullVwin;
11569#endif /* NO_ACTIVE_ICON */
11570
11571    init_Ires(screen.unparse_max);
11572    if ((int) screen->unparse_max < 256)
11573	screen->unparse_max = 256;
11574    screen->unparse_bfr = (IChar *) (void *) XtCalloc(screen->unparse_max,
11575						      (Cardinal) sizeof(IChar));
11576
11577    init_Ires(screen.strings_max);
11578
11579    if (screen->savelines < 0)
11580	screen->savelines = 0;
11581
11582    init_Bres(screen.awaitInput);
11583
11584    wnew->flags = 0;
11585    if (!screen->jumpscroll)
11586	wnew->flags |= SMOOTHSCROLL;
11587    if (wnew->misc.reverseWrap)
11588	wnew->flags |= REVERSEWRAP;
11589    if (wnew->misc.autoWrap)
11590	wnew->flags |= WRAPAROUND;
11591    if (wnew->misc.re_verse != wnew->misc.re_verse0)
11592	wnew->flags |= REVERSE_VIDEO;
11593    if (screen->c132)
11594	wnew->flags |= IN132COLUMNS;
11595
11596    wnew->initflags = wnew->flags;
11597
11598    init_Sres(keyboard.shift_escape_s);
11599    wnew->keyboard.shift_escape =
11600	extendedBoolean(wnew->keyboard.shift_escape_s, tblShift2S, ssLAST);
11601
11602#if OPT_MOD_FKEYS
11603    init_Ires(keyboard.modify_1st.allow_keys);
11604    init_Ires(keyboard.modify_1st.cursor_keys);
11605    init_Ires(keyboard.modify_1st.function_keys);
11606    init_Ires(keyboard.modify_1st.keypad_keys);
11607    init_Ires(keyboard.modify_1st.other_keys);
11608    init_Ires(keyboard.modify_1st.string_keys);
11609    init_Ires(keyboard.format_keys);
11610    wnew->keyboard.modify_now = wnew->keyboard.modify_1st;
11611#endif
11612
11613    init_Ires(misc.appcursorDefault);
11614    if (wnew->misc.appcursorDefault)
11615	wnew->keyboard.flags |= MODE_DECCKM;
11616
11617    init_Ires(misc.appkeypadDefault);
11618    if (wnew->misc.appkeypadDefault)
11619	wnew->keyboard.flags |= MODE_DECKPAM;
11620
11621    initLineData(wnew);
11622#if OPT_WIDE_CHARS
11623    freeFontList(&(request->work.fonts.x11.list_n));
11624#endif
11625#if OPT_XRES_QUERY
11626    if (resource.reportXRes)
11627	reportResources(wnew);
11628#endif
11629    xtermResetLocale(LC_NUMERIC, saveLocale);
11630    TRACE(("" TRACE_R " VTInitialize\n"));
11631    return;
11632}
11633
11634void
11635releaseCursorGCs(XtermWidget xw)
11636{
11637    TScreen *screen = TScreenOf(xw);
11638    VTwin *win = WhichVWin(screen);
11639    int n;
11640
11641    for_each_curs_gc(n) {
11642	freeCgs(xw, win, (CgsEnum) n);
11643    }
11644}
11645
11646void
11647releaseWindowGCs(XtermWidget xw, VTwin *win)
11648{
11649    int n;
11650
11651    for_each_text_gc(n) {
11652	switch (n) {
11653	case gcBorder:
11654	case gcFiller:
11655	    break;
11656	default:
11657	    freeCgs(xw, win, (CgsEnum) n);
11658	    break;
11659	}
11660    }
11661}
11662
11663#define TRACE_FREE_LEAK(name) \
11664	if (name) { \
11665	    TRACE(("freed " #name ": %p\n", (const void *) name)); \
11666	    FreeAndNull(name); \
11667	}
11668
11669#define TRACE_FREE_GC(name,part) \
11670	if (part) { \
11671	    TRACE(("freed %s " #part ": %p\n", name, (const void *) part)); \
11672	    XFreeGC(dpy, part); \
11673	    part = NULL; \
11674	}
11675
11676#if OPT_INPUT_METHOD
11677static void
11678cleanupInputMethod(XtermWidget xw)
11679{
11680    TInput *input = lookupTInput(xw, (Widget) xw);
11681
11682    if (input && input->xim) {
11683	XCloseIM(input->xim);
11684	input->xim = NULL;
11685	TRACE(("freed screen->xim\n"));
11686    }
11687}
11688#else
11689#define cleanupInputMethod(xw)	/* nothing */
11690#endif
11691
11692#ifdef NO_LEAKS
11693#define FREE_VT_WIN(name) freeVTwin(dpy, #name, &(screen->name))
11694static void
11695freeVTwin(Display *dpy, const char *whichWin, VTwin *win)
11696{
11697    (void) whichWin;
11698    TRACE_FREE_GC(whichWin, win->filler_gc);
11699    TRACE_FREE_GC(whichWin, win->border_gc);
11700    TRACE_FREE_GC(whichWin, win->marker_gc[0]);
11701    TRACE_FREE_GC(whichWin, win->marker_gc[1]);
11702}
11703#endif
11704
11705static void
11706VTDestroy(Widget w GCC_UNUSED)
11707{
11708#ifdef NO_LEAKS
11709    XtermWidget xw = (XtermWidget) w;
11710    TScreen *screen = TScreenOf(xw);
11711    Display *dpy = screen->display;
11712    Cardinal n, k;
11713
11714    StopBlinking(xw);
11715
11716    if (screen->scrollWidget) {
11717	XtUninstallTranslations(screen->scrollWidget);
11718	XtDestroyWidget(screen->scrollWidget);
11719    }
11720
11721    while (screen->saved_fifo > 0) {
11722	deleteScrollback(screen);
11723    }
11724
11725    for (n = 0; n < MAX_SAVED_TITLES; ++n)
11726	xtermFreeTitle(&screen->saved_titles.data[n]);
11727
11728#if OPT_STATUS_LINE
11729    free(screen->status_fmt);
11730#endif
11731#ifndef NO_ACTIVE_ICON
11732    TRACE_FREE_LEAK(xw->misc.active_icon_s);
11733#endif
11734#if OPT_ISO_COLORS
11735    TRACE_FREE_LEAK(screen->cmap_data);
11736    for (n = 0; n < MAXCOLORS; n++) {
11737	TRACE_FREE_LEAK(screen->Acolors[n].resource);
11738    }
11739    for (n = 0; n < MAX_SAVED_SGR; n++) {
11740	TRACE_FREE_LEAK(xw->saved_colors.palettes[n]);
11741    }
11742#endif
11743    for (n = 0; n < NCOLORS; n++) {
11744	switch (n) {
11745#if OPT_TEK4014
11746	case TEK_BG:
11747	    /* FALLTHRU */
11748	case TEK_FG:
11749	    /* FALLTHRU */
11750	case TEK_CURSOR:
11751	    break;
11752#endif
11753	default:
11754	    TRACE_FREE_LEAK(screen->Tcolors[n].resource);
11755	    break;
11756	}
11757    }
11758    FreeMarkGCs(xw);
11759    TRACE_FREE_LEAK(screen->unparse_bfr);
11760    TRACE_FREE_LEAK(screen->save_ptr);
11761    TRACE_FREE_LEAK(screen->saveBuf_data);
11762    TRACE_FREE_LEAK(screen->saveBuf_index);
11763    for (n = 0; n < 2; ++n) {
11764	TRACE_FREE_LEAK(screen->editBuf_data[n]);
11765	TRACE_FREE_LEAK(screen->editBuf_index[n]);
11766    }
11767    TRACE_FREE_LEAK(screen->keyboard_dialect);
11768    TRACE_FREE_LEAK(screen->cursor_font_name);
11769    TRACE_FREE_LEAK(screen->pointer_shape);
11770    TRACE_FREE_LEAK(screen->term_id);
11771#if OPT_WIDE_CHARS
11772    TRACE_FREE_LEAK(screen->utf8_mode_s);
11773    TRACE_FREE_LEAK(screen->utf8_fonts_s);
11774    TRACE_FREE_LEAK(screen->utf8_title_s);
11775#if OPT_LUIT_PROG
11776    TRACE_FREE_LEAK(xw->misc.locale_str);
11777    TRACE_FREE_LEAK(xw->misc.localefilter);
11778#endif
11779#endif
11780    TRACE_FREE_LEAK(xw->misc.T_geometry);
11781    TRACE_FREE_LEAK(xw->misc.geo_metry);
11782#if OPT_INPUT_METHOD
11783    cleanupInputMethod(xw);
11784    TRACE_FREE_LEAK(xw->misc.f_x);
11785    TRACE_FREE_LEAK(xw->misc.input_method);
11786    TRACE_FREE_LEAK(xw->misc.preedit_type);
11787#endif
11788    releaseCursorGCs(xw);
11789    releaseWindowGCs(xw, &(screen->fullVwin));
11790#ifndef NO_ACTIVE_ICON
11791    XFreeFont(screen->display, getIconicFont(screen)->fs);
11792    releaseWindowGCs(xw, &(screen->iconVwin));
11793#endif
11794    XtUninstallTranslations((Widget) xw);
11795#if OPT_TOOLBAR
11796    XtUninstallTranslations((Widget) XtParent(xw));
11797#endif
11798    XtUninstallTranslations((Widget) SHELL_OF(xw));
11799
11800    if (screen->hidden_cursor)
11801	XFreeCursor(screen->display, screen->hidden_cursor);
11802
11803    xtermCloseFonts(xw, screen->fnts);
11804#if OPT_WIDE_ATTRS
11805    xtermCloseFonts(xw, screen->ifnts);
11806#endif
11807    noleaks_cachedCgs(xw);
11808    free_termcap(xw);
11809
11810    FREE_VT_WIN(fullVwin);
11811#ifndef NO_ACTIVE_ICON
11812    FREE_VT_WIN(iconVwin);
11813#endif /* NO_ACTIVE_ICON */
11814
11815    TRACE_FREE_LEAK(screen->selection_targets_8bit);
11816#if OPT_SELECT_REGEX
11817    for (n = 0; n < NSELECTUNITS; ++n) {
11818	if (screen->selectMap[n] == Select_REGEX) {
11819	    TRACE_FREE_LEAK(screen->selectExpr[n]);
11820	}
11821    }
11822#endif
11823
11824#if OPT_RENDERFONT
11825    for (n = 0; n < NMENUFONTS; ++n) {
11826	int e;
11827	for (e = 0; e < fMAX; ++e) {
11828	    xtermCloseXft(screen, getMyXftFont(xw, e, (int) n));
11829	}
11830    }
11831    discardRenderDraw(screen);
11832    {
11833	ListXftFonts *p;
11834	while ((p = screen->list_xft_fonts) != NULL) {
11835	    screen->list_xft_fonts = p->next;
11836	    free(p);
11837	}
11838    }
11839#endif
11840
11841    /* free things allocated via init_Sres or Init_Sres2 */
11842#ifndef NO_ACTIVE_ICON
11843    TRACE_FREE_LEAK(screen->icon_fontname);
11844#endif
11845#ifdef ALLOWLOGGING
11846    TRACE_FREE_LEAK(screen->logfile);
11847#endif
11848    TRACE_FREE_LEAK(screen->eight_bit_meta_s);
11849    TRACE_FREE_LEAK(screen->charClass);
11850    TRACE_FREE_LEAK(screen->answer_back);
11851    TRACE_FREE_LEAK(screen->printer_state.printer_command);
11852    TRACE_FREE_LEAK(screen->disallowedColorOps);
11853    TRACE_FREE_LEAK(screen->disallowedFontOps);
11854    TRACE_FREE_LEAK(screen->disallowedMouseOps);
11855    TRACE_FREE_LEAK(screen->disallowedPasteOps);
11856    TRACE_FREE_LEAK(screen->disallowedTcapOps);
11857    TRACE_FREE_LEAK(screen->disallowedWinOps);
11858    TRACE_FREE_LEAK(screen->default_string);
11859    TRACE_FREE_LEAK(screen->eightbit_select_types);
11860
11861#if OPT_WIDE_CHARS
11862    TRACE_FREE_LEAK(screen->utf8_select_types);
11863#endif
11864
11865#if 0
11866    for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; n++) {
11867	TRACE_FREE_LEAK(screen->MenuFontName(n));
11868    }
11869#endif
11870
11871    TRACE_FREE_LEAK(screen->initial_font);
11872
11873#if OPT_LUIT_PROG
11874    TRACE_FREE_LEAK(xw->misc.locale_str);
11875    TRACE_FREE_LEAK(xw->misc.localefilter);
11876#endif
11877
11878    TRACE_FREE_LEAK(xw->misc.cdXtraScroll_s);
11879    TRACE_FREE_LEAK(xw->misc.tiXtraScroll_s);
11880
11881#if OPT_RENDERFONT
11882    TRACE_FREE_LEAK(xw->misc.default_xft.f_n);
11883#if OPT_WIDE_CHARS
11884    TRACE_FREE_LEAK(xw->misc.default_xft.f_w);
11885#endif
11886    TRACE_FREE_LEAK(xw->misc.render_font_s);
11887#endif
11888
11889    TRACE_FREE_LEAK(xw->misc.default_font.f_n);
11890    TRACE_FREE_LEAK(xw->misc.default_font.f_b);
11891
11892#if OPT_WIDE_CHARS
11893    TRACE_FREE_LEAK(xw->misc.default_font.f_w);
11894    TRACE_FREE_LEAK(xw->misc.default_font.f_wb);
11895#endif
11896
11897    TRACE_FREE_LEAK(xw->work.wm_name);
11898    freeFontLists(&(xw->work.fonts.x11));
11899#if OPT_RENDERFONT
11900    freeFontLists(&(xw->work.fonts.xft));
11901#endif
11902
11903    xtermFontName(NULL);
11904#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS
11905    TRACE_FREE_LEAK(screen->cacheVTFonts.default_font.f_n);
11906    TRACE_FREE_LEAK(screen->cacheVTFonts.default_font.f_b);
11907#if OPT_WIDE_CHARS
11908    TRACE_FREE_LEAK(screen->cacheVTFonts.default_font.f_w);
11909    TRACE_FREE_LEAK(screen->cacheVTFonts.default_font.f_wb);
11910#endif
11911    freeFontLists(&(screen->cacheVTFonts.fonts.x11));
11912    for (n = 0; n < NMENUFONTS; ++n) {
11913	for (k = 0; k < fMAX; ++k) {
11914	    if (screen->menu_font_names[n][k] !=
11915		screen->cacheVTFonts.menu_font_names[n][k]) {
11916		if (screen->menu_font_names[n][k] != _Font_Selected_) {
11917		    TRACE_FREE_LEAK(screen->menu_font_names[n][k]);
11918		}
11919		TRACE_FREE_LEAK(screen->cacheVTFonts.menu_font_names[n][k]);
11920	    } else {
11921		TRACE_FREE_LEAK(screen->menu_font_names[n][k]);
11922	    }
11923	}
11924    }
11925#endif
11926
11927#if OPT_BLINK_CURS
11928    TRACE_FREE_LEAK(screen->cursor_blink_s);
11929#endif
11930
11931#if OPT_REGIS_GRAPHICS
11932    TRACE_FREE_LEAK(screen->graphics_regis_default_font);
11933    TRACE_FREE_LEAK(screen->graphics_regis_screensize);
11934#endif
11935#if OPT_GRAPHICS
11936    TRACE_FREE_LEAK(screen->graph_termid);
11937    TRACE_FREE_LEAK(screen->graphics_max_size);
11938#endif
11939
11940    for (n = 0; n < NSELECTUNITS; ++n) {
11941#if OPT_SELECT_REGEX
11942	TRACE_FREE_LEAK(screen->selectExpr[n]);
11943#endif
11944#if OPT_XRES_QUERY
11945	TRACE_FREE_LEAK(screen->onClick[n]);
11946#endif
11947    }
11948
11949    XtFree((void *) (screen->selection_atoms));
11950
11951    for (n = 0; n < MAX_SELECTIONS; ++n) {
11952	free(screen->selected_cells[n].data_buffer);
11953    }
11954
11955    if (defaultTranslations != xtermClassRec.core_class.tm_table) {
11956	TRACE_FREE_LEAK(defaultTranslations);
11957    }
11958    TRACE_FREE_LEAK(xtermClassRec.core_class.tm_table);
11959    TRACE_FREE_LEAK(xw->keyboard.shift_escape_s);
11960    TRACE_FREE_LEAK(xw->keyboard.extra_translations);
11961    TRACE_FREE_LEAK(xw->keyboard.shell_translations);
11962    TRACE_FREE_LEAK(xw->keyboard.xterm_translations);
11963    TRACE_FREE_LEAK(xw->keyboard.print_translations);
11964    UnmapSelections(xw);
11965
11966    XtFree((void *) (xw->visInfo));
11967
11968#if OPT_WIDE_CHARS
11969    FreeTypedBuffer(IChar);
11970    FreeTypedBuffer(XChar2b);
11971    FreeTypedBuffer(Char);
11972#endif
11973#if OPT_RENDERFONT
11974#if OPT_RENDERWIDE
11975    FreeTypedBuffer(XftCharSpec);
11976#else
11977    FreeTypedBuffer(XftChar8);
11978#endif
11979#endif
11980
11981    TRACE_FREE_LEAK(myState.print_area);
11982    TRACE_FREE_LEAK(myState.string_area);
11983    memset(&myState, 0, sizeof(myState));
11984
11985#endif /* defined(NO_LEAKS) */
11986}
11987
11988#ifndef NO_ACTIVE_ICON
11989static void *
11990getProperty(Display *dpy,
11991	    Window w,
11992	    Atom req_type,
11993	    const char *prop_name)
11994{
11995    Atom property;
11996    Atom actual_return_type;
11997    int actual_format_return = 0;
11998    unsigned long nitems_return = 0;
11999    unsigned long bytes_after_return = 0;
12000    unsigned char *prop_return = NULL;
12001    long long_length = 1024;
12002    size_t limit;
12003    char *result = NULL;
12004
12005    TRACE(("getProperty %s(%s)\n", prop_name,
12006	   req_type ? TraceAtomName(dpy, req_type) : "?"));
12007    property = CachedInternAtom(dpy, prop_name);
12008
12009    if (!xtermGetWinProp(dpy,
12010			 w,
12011			 property,
12012			 0L,
12013			 long_length,
12014			 req_type,
12015			 &actual_return_type,
12016			 &actual_format_return,
12017			 &nitems_return,
12018			 &bytes_after_return,
12019			 &prop_return)) {
12020	TRACE((".. Cannot get %s property.\n", prop_name));
12021    } else if (prop_return != NULL) {
12022
12023	if (nitems_return != 0 &&
12024	    actual_format_return != 0 &&
12025	    actual_return_type == req_type) {
12026	    /*
12027	     * Null-terminate the result to make string handling easier.
12028	     * The format==8 corresponds to strings, and the number of items
12029	     * is the number of characters.
12030	     */
12031	    if (actual_format_return == 8) {
12032		limit = nitems_return;
12033	    } else {
12034		/* manpage is misleading - X really uses 'long', not 32-bits */
12035		limit = sizeof(long) * nitems_return;
12036	    }
12037	    if ((result = malloc(limit + 1)) != NULL) {
12038		memcpy(result, prop_return, limit);
12039		result[limit] = '\0';
12040	    }
12041	    TRACE(("... result %s\n", result ? ("ok") : "null"));
12042	}
12043	XFree(prop_return);
12044    } else {
12045	TRACE((".. no property returned\n"));
12046    }
12047    return (void *) result;
12048}
12049
12050/*
12051 * Active icons are supported by fvwm.  This feature is not supported by
12052 * metacity (gnome) or kwin (kde).  Both metacity and kwin support (in
12053 * incompatible ways, e.g., one uses the icon theme as a fallback for window
12054 * decorations but the other does not, etc, ...) an icon as part of the window
12055 * decoration (usually on the upper-left of the window).
12056 *
12057 * In either case, xterm's icon will only be shown in the window decorations if
12058 * xterm does not use the active icon feature.
12059 *
12060 * This function (tries to) determine the window manager's name, so that we can
12061 * provide a useful automatic default for active icons.  It is based on reading
12062 * wmctrl, which covers most of EWMH and ICCM.
12063 */
12064static char *
12065getWindowManagerName(XtermWidget xw)
12066{
12067    TScreen *screen = TScreenOf(xw);
12068    Display *dpy = screen->display;
12069    Window *sup_window = NULL;
12070    char *result = NULL;
12071
12072    TRACE(("getWindowManagerName\n"));
12073#define getWinProp(type, name) \
12074    (Window *)getProperty(dpy, DefaultRootWindow(dpy), type, name)
12075    if ((sup_window = getWinProp(XA_WINDOW, "_NET_SUPPORTING_WM_CHECK")) == NULL) {
12076	sup_window = getWinProp(XA_CARDINAL, "_WIN_SUPPORTING_WM_CHECK");
12077    }
12078
12079    /*
12080     * If we found the supporting window, get the property containing the
12081     * window manager's name.  EWMH defines _NET_WM_NAME, while ICCM defines
12082     * WM_CLASS.  There is no standard for the names stored there;
12083     * conventionally it is mixed case.  In practice, the former is more often
12084     * set; the latter is not given (or is a lowercased version of the former).
12085     */
12086    if (sup_window != NULL) {
12087#define getStringProp(type,name) \
12088	(char *)getProperty(dpy, *sup_window, type, name)
12089	if ((result = getStringProp(XA_UTF8_STRING(dpy), "_NET_WM_NAME")) == NULL
12090	    && (result = getStringProp(XA_STRING, "_NET_WM_NAME")) == NULL
12091	    && (result = getStringProp(XA_STRING, "WM_CLASS")) == NULL) {
12092	    TRACE(("... window manager does not tell its name\n"));
12093	}
12094	free(sup_window);
12095    } else {
12096	TRACE(("... Cannot get window manager info properties\n"));
12097    }
12098    if (result == NULL)
12099	result = x_strdup("unknown");
12100    TRACE(("... window manager name is %s\n", result));
12101    return result;
12102}
12103
12104static Boolean
12105discount_frame_extents(XtermWidget xw, int *high, int *wide)
12106{
12107    TScreen *screen = TScreenOf(xw);
12108    Display *dpy = screen->display;
12109
12110    Atom atom_supported = CachedInternAtom(dpy, "_NET_FRAME_EXTENTS");
12111    Atom actual_type;
12112    int actual_format;
12113    long long_offset = 0;
12114    long long_length = 128;	/* number of items to ask for at a time */
12115    unsigned long nitems;
12116    unsigned long bytes_after;
12117    unsigned char *args;
12118    Boolean rc;
12119
12120    rc = xtermGetWinProp(dpy,
12121			 VShellWindow(xw),
12122			 atom_supported,
12123			 long_offset,
12124			 long_length,
12125			 XA_CARDINAL,	/* req_type */
12126			 &actual_type,	/* actual_type_return */
12127			 &actual_format,	/* actual_format_return */
12128			 &nitems,	/* nitems_return */
12129			 &bytes_after,	/* bytes_after_return */
12130			 &args	/* prop_return */
12131	);
12132
12133    if (rc && args && (nitems == 4) && (actual_format == 32)) {
12134	long *extents = (long *) (void *) args;
12135
12136	TRACE(("_NET_FRAME_EXTENTS:\n"));
12137	TRACE(("   left:   %ld\n", extents[0]));
12138	TRACE(("   right:  %ld\n", extents[1]));
12139	TRACE(("   top:    %ld\n", extents[2]));
12140	TRACE(("   bottom: %ld\n", extents[3]));
12141
12142	if (!x_strncasecmp(xw->work.wm_name, "gnome shell", 11)) {
12143	    *wide -= (int) (extents[0] + extents[1]);	/* -= (left+right) */
12144	    *high -= (int) (extents[2] + extents[3]);	/* -= (top+bottom) */
12145	    TRACE(("...applied extents %d,%d\n", *high, *wide));
12146	} else if (!x_strncasecmp(xw->work.wm_name, "compiz", 6)) {
12147	    /* Ubuntu 16.04 is really off-by-one */
12148	    *wide -= (int) (extents[0] + extents[1] - 1);
12149	    *high -= (int) (extents[2] + extents[3] - 1);
12150	    TRACE(("...applied extents %d,%d\n", *high, *wide));
12151	} else if (!x_strncasecmp(xw->work.wm_name, "fvwm", 4)) {
12152	    TRACE(("...skipping extents\n"));
12153	} else {
12154	    TRACE(("...ignoring extents\n"));
12155	    rc = False;
12156	}
12157	XFree(args);
12158    } else {
12159	rc = False;
12160    }
12161    return rc;
12162}
12163#endif /* !NO_ACTIVE_ICON */
12164
12165void
12166initBorderGC(XtermWidget xw, VTwin *win)
12167{
12168    TScreen *screen = TScreenOf(xw);
12169    Pixel filler;
12170
12171    TRACE(("initBorderGC(%s) core bg %#lx, bd %#lx text fg %#lx, bg %#lx %s\n",
12172	   (win == &(screen->fullVwin)) ? "full" : "icon",
12173	   xw->core.background_pixel,
12174	   xw->core.border_pixel,
12175	   T_COLOR(screen, TEXT_FG),
12176	   T_COLOR(screen, TEXT_BG),
12177	   xw->misc.re_verse ? "reverse" : "normal"));
12178    if (xw->misc.color_inner_border
12179	&& (xw->core.background_pixel != xw->core.border_pixel)) {
12180	/*
12181	 * By default, try to match the inner window's background.
12182	 */
12183	if ((xw->core.background_pixel == T_COLOR(screen, TEXT_BG)) &&
12184	    (xw->core.border_pixel == T_COLOR(screen, TEXT_FG))) {
12185	    filler = T_COLOR(screen, TEXT_BG);
12186	} else {
12187	    filler = xw->core.border_pixel;
12188	}
12189	TRACE((" border %#lx\n", filler));
12190	setCgsFore(xw, win, gcBorder, filler);
12191	setCgsBack(xw, win, gcBorder, filler);
12192	win->border_gc = getCgsGC(xw, win, gcBorder);
12193    }
12194#if USE_DOUBLE_BUFFER
12195    else if (resource.buffered) {
12196	filler = T_COLOR(screen, TEXT_BG);
12197	TRACE((" border %#lx (buffered)\n", filler));
12198	setCgsFore(xw, win, gcBorder, filler);
12199	setCgsBack(xw, win, gcBorder, filler);
12200	win->border_gc = getCgsGC(xw, win, gcBorder);
12201    }
12202#endif
12203    else {
12204	TRACE((" border unused\n"));
12205	win->border_gc = NULL;
12206    }
12207
12208    /*
12209     * Initialize a GC for double-buffering, needed for XFillRectangle call
12210     * in xtermClear2().  When not double-buffering, the XClearArea call works,
12211     * without requiring a separate GC.
12212     */
12213#if USE_DOUBLE_BUFFER
12214    if (resource.buffered) {
12215	filler = (((xw->flags & BG_COLOR) && (xw->cur_background >= 0))
12216		  ? getXtermBG(xw, xw->flags, xw->cur_background)
12217		  : T_COLOR(screen, TEXT_BG));
12218
12219	TRACE((" filler %#lx %s\n",
12220	       filler,
12221	       xw->misc.re_verse ? "reverse" : "normal"));
12222
12223	setCgsFore(xw, win, gcFiller, filler);
12224	setCgsBack(xw, win, gcFiller, filler);
12225
12226	win->filler_gc = getCgsGC(xw, win, gcFiller);
12227    }
12228#endif
12229}
12230#if USE_DOUBLE_BUFFER
12231static Boolean
12232allocateDbe(XtermWidget xw, VTwin *target)
12233{
12234    TScreen *screen = TScreenOf(xw);
12235    Boolean result = False;
12236
12237    target->drawable = target->window;
12238
12239    if (resource.buffered) {
12240	Window win = target->window;
12241	Drawable d;
12242	int major, minor;
12243	if (XdbeQueryExtension(XtDisplay(xw), &major, &minor)) {
12244	    d = XdbeAllocateBackBufferName(XtDisplay(xw), win,
12245					   (XdbeSwapAction) XdbeCopied);
12246	    if (d == None) {
12247		fprintf(stderr, "Couldn't allocate a back buffer!\n");
12248		exit(3);
12249	    }
12250	    target->drawable = d;
12251	    screen->needSwap = 1;
12252	    TRACE(("initialized double-buffering\n"));
12253	    result = True;
12254	} else {
12255	    resource.buffered = False;
12256	}
12257    }
12258    return result;
12259}
12260#endif /* USE_DOUBLE_BUFFER */
12261
12262/*ARGSUSED*/
12263static void
12264VTRealize(Widget w,
12265	  XtValueMask * valuemask,
12266	  XSetWindowAttributes * values)
12267{
12268    XtermWidget xw = (XtermWidget) w;
12269    TScreen *screen = TScreenOf(xw);
12270
12271    const VTFontNames *myfont;
12272    struct Xinerama_geometry pos;
12273    int pr;
12274    Atom pid_atom;
12275    int i;
12276
12277    TRACE(("VTRealize " TRACE_L "\n"));
12278
12279    TabReset(xw->tabs);
12280
12281    if (screen->menu_font_number == fontMenu_default) {
12282	myfont = defaultVTFontNames(xw);
12283    } else {
12284	myfont = xtermFontName(screen->MenuFontName(screen->menu_font_number));
12285    }
12286    memset(screen->fnts, 0, sizeof(screen->fnts));
12287
12288    if (!xtermLoadFont(xw,
12289		       myfont,
12290		       False,
12291		       screen->menu_font_number)) {
12292	if (XmuCompareISOLatin1(myfont->f_n, DEFFONT) != 0) {
12293	    char *use_font = x_strdup(DEFFONT);
12294	    xtermWarning("unable to open font \"%s\", trying \"%s\"....\n",
12295			 myfont->f_n, use_font);
12296	    (void) xtermLoadFont(xw,
12297				 xtermFontName(use_font),
12298				 False,
12299				 screen->menu_font_number);
12300	    screen->MenuFontName(screen->menu_font_number) = use_font;
12301	}
12302    }
12303
12304    /* really screwed if we couldn't open default font */
12305    if (!GetNormalFont(screen, fNorm)->fs) {
12306	xtermWarning("unable to locate a suitable font\n");
12307	Exit(ERROR_MISC);
12308    }
12309#if OPT_WIDE_CHARS
12310    if (screen->utf8_mode) {
12311	TRACE(("check if this is a wide font, if not try again\n"));
12312	if (xtermLoadWideFonts(xw, False)) {
12313	    SetVTFont(xw, screen->menu_font_number, True, NULL);
12314	    /* we will not be able to switch to ISO-8859-1 */
12315	    if (!screen->mergedVTFonts) {
12316		screen->utf8_fonts = uAlways;
12317		update_font_utf8_fonts();
12318	    }
12319	}
12320    }
12321#endif
12322
12323    xtermSetupPointer(xw, screen->pointer_shape);
12324
12325    /* set defaults */
12326    pos.x = 1;
12327    pos.y = 1;
12328    pos.w = 80;
12329    pos.h = 24;
12330
12331    TRACE(("parsing geo_metry %s\n", NonNull(xw->misc.geo_metry)));
12332    pr = XParseXineramaGeometry(screen->display, xw->misc.geo_metry, &pos);
12333    TRACE(("... position %d,%d size %dx%d\n", pos.y, pos.x, pos.h, pos.w));
12334
12335    set_max_col(screen, (int) (pos.w - 1));	/* units in character cells */
12336    set_max_row(screen, (int) (pos.h - 1));	/* units in character cells */
12337    xtermUpdateFontInfo(xw, False);
12338
12339    pos.w = screen->fullVwin.fullwidth;
12340    pos.h = screen->fullVwin.fullheight;
12341
12342    TRACE(("... BorderWidth: widget %d parent %d shell %d\n",
12343	   BorderWidth(xw),
12344	   BorderWidth(XtParent(xw)),
12345	   BorderWidth(SHELL_OF(xw))));
12346
12347    if ((pr & XValue) && (XNegative & pr)) {
12348	pos.x = (Position) (pos.x + (pos.scr_w
12349				     - (int) pos.w
12350				     - (BorderWidth(XtParent(xw)) * 2)));
12351    }
12352    if ((pr & YValue) && (YNegative & pr)) {
12353	pos.y = (Position) (pos.y + (pos.scr_h
12354				     - (int) pos.h
12355				     - (BorderWidth(XtParent(xw)) * 2)));
12356    }
12357    pos.x = (Position) (pos.x + pos.scr_x);
12358    pos.y = (Position) (pos.y + pos.scr_y);
12359
12360    /* set up size hints for window manager; min 1 char by 1 char */
12361    getXtermSizeHints(xw);
12362    xtermSizeHints(xw, (xw->misc.scrollbar
12363			? (screen->scrollWidget->core.width
12364			   + BorderWidth(screen->scrollWidget))
12365			: 0));
12366
12367    xw->hints.x = pos.x;
12368    xw->hints.y = pos.y;
12369#if OPT_MAXIMIZE
12370    /* assure single-increment resize for fullscreen */
12371    if (xw->work.ewmh[0].mode) {
12372	xw->hints.width_inc = 1;
12373	xw->hints.height_inc = 1;
12374    }
12375#endif
12376    if ((XValue & pr) || (YValue & pr)) {
12377	xw->hints.flags |= USSize | USPosition;
12378	xw->hints.flags |= PWinGravity;
12379	switch (pr & (XNegative | YNegative)) {
12380	case 0:
12381	    xw->hints.win_gravity = NorthWestGravity;
12382	    break;
12383	case XNegative:
12384	    xw->hints.win_gravity = NorthEastGravity;
12385	    break;
12386	case YNegative:
12387	    xw->hints.win_gravity = SouthWestGravity;
12388	    break;
12389	default:
12390	    xw->hints.win_gravity = SouthEastGravity;
12391	    break;
12392	}
12393    } else {
12394	/* set a default size, but do *not* set position */
12395	xw->hints.flags |= PSize;
12396    }
12397    xw->hints.height = xw->hints.base_height
12398	+ xw->hints.height_inc * MaxRows(screen);
12399    xw->hints.width = xw->hints.base_width
12400	+ xw->hints.width_inc * MaxCols(screen);
12401
12402    if ((WidthValue & pr) || (HeightValue & pr))
12403	xw->hints.flags |= USSize;
12404    else
12405	xw->hints.flags |= PSize;
12406
12407    /*
12408     * Note that the size-hints are for the shell, while the resize-request
12409     * is for the vt100 widget.  They are not the same size.
12410     */
12411    (void) REQ_RESIZE((Widget) xw,
12412		      (Dimension) pos.w, (Dimension) pos.h,
12413		      &xw->core.width, &xw->core.height);
12414
12415    /* XXX This is bogus.  We are parsing geometries too late.  This
12416     * is information that the shell widget ought to have before we get
12417     * realized, so that it can do the right thing.
12418     */
12419    if (xw->hints.flags & USPosition)
12420	XMoveWindow(XtDisplay(xw), VShellWindow(xw),
12421		    xw->hints.x, xw->hints.y);
12422
12423    TRACE(("%s@%d -- ", __FILE__, __LINE__));
12424    TRACE_HINTS(&xw->hints);
12425    XSetWMNormalHints(XtDisplay(xw), VShellWindow(xw), &xw->hints);
12426    TRACE(("%s@%d -- ", __FILE__, __LINE__));
12427    TRACE_WM_HINTS(xw);
12428
12429    if ((pid_atom = CachedInternAtom(XtDisplay(xw), "_NET_WM_PID")) != None) {
12430	/* XChangeProperty format 32 really is "long" */
12431	unsigned long pid_l = (unsigned long) getpid();
12432	TRACE(("Setting _NET_WM_PID property to %lu\n", pid_l));
12433	XChangeProperty(XtDisplay(xw), VShellWindow(xw),
12434			pid_atom, XA_CARDINAL, 32, PropModeReplace,
12435			(unsigned char *) &pid_l, 1);
12436    }
12437
12438    XFlush(XtDisplay(xw));	/* get it out to window manager */
12439
12440    /* use ForgetGravity instead of SouthWestGravity because translating
12441       the Expose events for ConfigureNotifys is too hard */
12442    values->bit_gravity = (GravityIsNorthWest(xw)
12443			   ? NorthWestGravity
12444			   : ForgetGravity);
12445    screen->fullVwin.window = XtWindow(xw) =
12446	XCreateWindow(XtDisplay(xw), XtWindow(XtParent(xw)),
12447		      xw->core.x, xw->core.y,
12448		      xw->core.width, xw->core.height, BorderWidth(xw),
12449		      (int) xw->core.depth,
12450		      InputOutput, CopyFromParent,
12451		      *valuemask | CWBitGravity, values);
12452#if USE_DOUBLE_BUFFER
12453    if (allocateDbe(xw, &(screen->fullVwin))) {
12454	screen->needSwap = 1;
12455	TRACE(("initialized full double-buffering\n"));
12456    } else {
12457	resource.buffered = False;
12458	screen->fullVwin.drawable = screen->fullVwin.window;
12459    }
12460#endif /* USE_DOUBLE_BUFFER */
12461    screen->event_mask = values->event_mask;
12462
12463#ifndef NO_ACTIVE_ICON
12464    /*
12465     * Normally, the font-number for icon fonts does not correspond with any of
12466     * the menu-selectable fonts.  If we cannot load the font given for the
12467     * iconFont resource, try with font1 aka "Unreadable".
12468     */
12469    screen->icon_fontnum = -1;
12470    if (getIconicFont(screen)->fs == NULL) {
12471	getIconicFont(screen)->fs =
12472	    xtermLoadQueryFont(xw, screen->MenuFontName(fontMenu_font1));
12473	ReportIcons(("%susing font1 '%s' as iconFont\n",
12474		     (getIconicFont(screen)->fs
12475		      ? ""
12476		      : "NOT "),
12477		     screen->MenuFontName(fontMenu_font1)));
12478    }
12479#if OPT_RENDERFONT
12480    /*
12481     * If we still have no result from iconFont resource (perhaps because fonts
12482     * are missing) but are using Xft, try to use that instead.  We prefer
12483     * bitmap fonts in any case, since scaled fonts are usually less readable,
12484     * particularly at small sizes.
12485     */
12486    if (UsingRenderFont(xw)
12487	&& getIconicFont(screen)->fs == NULL) {
12488	screen->icon_fontnum = fontMenu_default;
12489	getIconicFont(screen)->fs = GetNormalFont(screen, fNorm)->fs;	/* need for next-if */
12490	ReportIcons(("using TrueType font as iconFont\n"));
12491    }
12492#endif
12493    xw->work.wm_name = getWindowManagerName(xw);
12494    if ((xw->work.active_icon == eiDefault) && getIconicFont(screen)->fs) {
12495	ReportIcons(("window manager name is %s\n", xw->work.wm_name));
12496	if (x_strncasecmp(xw->work.wm_name, "fvwm", 4) &&
12497	    x_strncasecmp(xw->work.wm_name, "window maker", 12)) {
12498	    xw->work.active_icon = eiFalse;
12499	    TRACE(("... disable active_icon\n"));
12500	}
12501    }
12502    TRACE((".. if active_icon (%d), get its font\n", xw->work.active_icon));
12503    if (xw->work.active_icon && getIconicFont(screen)->fs) {
12504	int iconX = 0, iconY = 0;
12505	Widget shell = SHELL_OF(xw);
12506	VTwin *win = &(screen->iconVwin);
12507	int save_fontnum = screen->menu_font_number;
12508
12509	ReportIcons(("initializing active-icon %d\n", screen->icon_fontnum));
12510	screen->menu_font_number = screen->icon_fontnum;
12511	XtVaGetValues(shell,
12512		      XtNiconX, &iconX,
12513		      XtNiconY, &iconY,
12514		      (XtPointer) 0);
12515	xtermComputeFontInfo(xw, &(screen->iconVwin),
12516			     getIconicFont(screen)->fs, 0);
12517	screen->menu_font_number = save_fontnum;
12518
12519	/* since only one client is permitted to select for Button
12520	 * events, we have to let the window manager get 'em...
12521	 */
12522	values->event_mask &= ~(ButtonPressMask | ButtonReleaseMask);
12523	values->border_pixel = xw->misc.icon_border_pixel;
12524
12525	screen->iconVwin.window =
12526	    XCreateWindow(XtDisplay(xw),
12527			  RootWindowOfScreen(XtScreen(shell)),
12528			  iconX, iconY,
12529			  screen->iconVwin.fullwidth,
12530			  screen->iconVwin.fullheight,
12531			  xw->misc.icon_border_width,
12532			  (int) xw->core.depth,
12533			  InputOutput, CopyFromParent,
12534			  *valuemask | CWBitGravity | CWBorderPixel,
12535			  values);
12536#if USE_DOUBLE_BUFFER
12537	if (allocateDbe(xw, &(screen->iconVwin))) {
12538	    TRACE(("initialized icon double-buffering\n"));
12539	} else {
12540	    resource.buffered = False;
12541	    screen->iconVwin.drawable = screen->iconVwin.window;
12542	    screen->fullVwin.drawable = screen->fullVwin.window;
12543	}
12544#endif /* USE_DOUBLE_BUFFER */
12545	XtVaSetValues(shell,
12546		      XtNiconWindow, screen->iconVwin.window,
12547		      (XtPointer) 0);
12548	XtRegisterDrawable(XtDisplay(xw), screen->iconVwin.window, w);
12549
12550	setCgsFont(xw, win, gcNorm, getIconicFont(screen));
12551	setCgsFore(xw, win, gcNorm, T_COLOR(screen, TEXT_FG));
12552	setCgsBack(xw, win, gcNorm, T_COLOR(screen, TEXT_BG));
12553
12554	copyCgs(xw, win, gcBold, gcNorm);
12555
12556	setCgsFont(xw, win, gcNormReverse, getIconicFont(screen));
12557	setCgsFore(xw, win, gcNormReverse, T_COLOR(screen, TEXT_BG));
12558	setCgsBack(xw, win, gcNormReverse, T_COLOR(screen, TEXT_FG));
12559
12560	copyCgs(xw, win, gcBoldReverse, gcNormReverse);
12561
12562	initBorderGC(xw, win);
12563    } else {
12564	ReportIcons(("disabled active-icon\n"));
12565	xw->work.active_icon = eiFalse;
12566    }
12567#if OPT_TOOLBAR
12568    update_activeicon();
12569#endif
12570#endif /* NO_ACTIVE_ICON */
12571
12572#if OPT_INPUT_METHOD
12573    VTInitI18N(xw);
12574#endif
12575#if OPT_NUM_LOCK
12576    VTInitModifiers(xw);
12577#if OPT_EXTRA_PASTE
12578    if (xw->keyboard.extra_translations) {
12579	XtOverrideTranslations((Widget) xw,
12580			       XtParseTranslationTable(xw->keyboard.extra_translations));
12581    }
12582#endif
12583#endif
12584
12585    set_cursor_gcs(xw);
12586    initBorderGC(xw, &(screen->fullVwin));
12587
12588    /* Reset variables used by ANSI emulation. */
12589
12590    resetCharsets(screen);
12591
12592    XDefineCursor(screen->display, VShellWindow(xw), screen->pointer_cursor);
12593
12594    set_cur_col(screen, 0);
12595    set_cur_row(screen, 0);
12596    set_max_col(screen, Width(screen) / screen->fullVwin.f_width - 1);
12597    set_max_row(screen, Height(screen) / screen->fullVwin.f_height - 1);
12598    resetMarginMode(xw);
12599
12600    memset(screen->sc, 0, sizeof(screen->sc));
12601
12602    /* Mark screen buffer as unallocated.  We wait until the run loop so
12603       that the child process does not fork and exec with all the dynamic
12604       memory it will never use.  If we were to do it here, the
12605       swap space for new process would be huge for huge savelines. */
12606#if OPT_TEK4014
12607    if (!tekWidget)		/* if not called after fork */
12608#endif
12609    {
12610	screen->visbuf = NULL;
12611	screen->saveBuf_index = NULL;
12612    }
12613
12614    ResetWrap(screen);
12615    screen->scrolls = screen->incopy = 0;
12616    xtermSetCursorBox(screen);
12617
12618    screen->savedlines = 0;
12619
12620    for (i = 0; i < 2; ++i) {
12621	screen->whichBuf = !screen->whichBuf;
12622	CursorSave(xw);
12623    }
12624
12625#ifndef NO_ACTIVE_ICON
12626    if (!xw->work.active_icon)
12627#endif
12628	xtermLoadIcon(xw, resource.icon_hint);
12629
12630    /*
12631     * Do this last, since it may change the layout via a resize.
12632     */
12633    if (xw->misc.scrollbar) {
12634	screen->fullVwin.sb_info.width = 0;
12635	ScrollBarOn(xw, False);
12636    }
12637
12638    xtermSetWinSize(xw);
12639    TRACE(("" TRACE_R " VTRealize\n"));
12640}
12641
12642#if OPT_INPUT_METHOD
12643
12644/* limit this feature to recent XFree86 since X11R6.x core dumps */
12645#if defined(XtSpecificationRelease) && XtSpecificationRelease >= 6 && defined(X_HAVE_UTF8_STRING)
12646#define USE_XIM_INSTANTIATE_CB
12647
12648static void
12649xim_instantiate_cb(Display *display,
12650		   XPointer client_data GCC_UNUSED,
12651		   XPointer call_data GCC_UNUSED)
12652{
12653    XtermWidget xw = term;
12654
12655    TRACE(("xim_instantiate_cb client=%p, call=%p\n", client_data, call_data));
12656
12657    if (display == XtDisplay(xw)) {
12658	VTInitI18N(xw);
12659    }
12660}
12661
12662static void
12663xim_destroy_cb(XIM im GCC_UNUSED,
12664	       XPointer client_data GCC_UNUSED,
12665	       XPointer call_data GCC_UNUSED)
12666{
12667    XtermWidget xw = term;
12668    TInput *input = lookupTInput(xw, (Widget) xw);
12669
12670    TRACE(("xim_destroy_cb im=%lx, client=%p, call=%p\n",
12671	   (long) im, client_data, call_data));
12672    if (input)
12673	input->xic = NULL;
12674    XRegisterIMInstantiateCallback(XtDisplay(xw), NULL, NULL, NULL,
12675				   xim_instantiate_cb, NULL);
12676}
12677#endif /* X11R6+ */
12678
12679static Boolean
12680xim_create_fs(XtermWidget xw)
12681{
12682    XFontStruct **fonts;
12683    char **font_name_list;
12684    char **missing_charset_list;
12685    char *def_string;
12686    int missing_charset_count;
12687    unsigned i, j;
12688
12689    if (xw->work.xim_fs == NULL) {
12690	xw->work.xim_fs = XCreateFontSet(XtDisplay(xw),
12691					 xw->misc.f_x,
12692					 &missing_charset_list,
12693					 &missing_charset_count,
12694					 &def_string);
12695	if (xw->work.xim_fs == NULL) {
12696	    xtermWarning("Preparation of font set "
12697			 "\"%s\" for XIM failed.\n", xw->misc.f_x);
12698	    xw->work.xim_fs = XCreateFontSet(XtDisplay(xw),
12699					     DEFXIMFONT,
12700					     &missing_charset_list,
12701					     &missing_charset_count,
12702					     &def_string);
12703	}
12704    }
12705    if (xw->work.xim_fs == NULL) {
12706	xtermWarning("Preparation of default font set "
12707		     "\"%s\" for XIM failed.\n", DEFXIMFONT);
12708	cleanupInputMethod(xw);
12709	xw->work.cannot_im = True;
12710    } else {
12711	(void) XExtentsOfFontSet(xw->work.xim_fs);
12712	j = (unsigned) XFontsOfFontSet(xw->work.xim_fs, &fonts, &font_name_list);
12713	for (i = 0, xw->work.xim_fs_ascent = 0; i < j; i++) {
12714	    if (xw->work.xim_fs_ascent < (*fonts)->ascent)
12715		xw->work.xim_fs_ascent = (*fonts)->ascent;
12716	}
12717    }
12718    return (Boolean) !(xw->work.cannot_im);
12719}
12720
12721static void
12722xim_create_xic(XtermWidget xw, Widget theInput)
12723{
12724    Display *myDisplay = XtDisplay(theInput);
12725    Window myWindow = XtWindow(theInput);
12726    unsigned i, j;
12727    char *p = NULL, *s, *t, *ns, *end, buf[32];
12728    XIMStyles *xim_styles;
12729    XIMStyle input_style = 0;
12730    Bool found;
12731    static struct {
12732	const char *name;
12733	unsigned long code;
12734    } known_style[] = {
12735	{
12736	    "OverTheSpot", (XIMPreeditPosition | XIMStatusNothing)
12737	},
12738	{
12739	    "OffTheSpot", (XIMPreeditArea | XIMStatusArea)
12740	},
12741	{
12742	    "Root", (XIMPreeditNothing | XIMStatusNothing)
12743	},
12744    };
12745    TInput *input = lookupTInput(xw, theInput);
12746
12747    if (xw->work.cannot_im) {
12748	return;
12749    }
12750
12751    if (input == NULL) {
12752	for (i = 0; i < NINPUTWIDGETS; ++i) {
12753	    if (xw->work.inputs[i].w == NULL) {
12754		input = xw->work.inputs + i;
12755		input->w = theInput;
12756		break;
12757	    }
12758	}
12759    }
12760
12761    if (input == NULL) {
12762	xtermWarning("attempted to add too many input widgets\n");
12763	return;
12764    }
12765
12766    TRACE(("xim_real_init\n"));
12767
12768    if (IsEmpty(xw->misc.input_method)) {
12769	if ((p = XSetLocaleModifiers("")) != NULL && *p) {
12770	    input->xim = XOpenIM(myDisplay, NULL, NULL, NULL);
12771	}
12772    } else {
12773	s = xw->misc.input_method;
12774	i = 5 + (unsigned) strlen(s);
12775
12776	t = (char *) MyStackAlloc(i, buf);
12777	if (t == NULL) {
12778	    SysError(ERROR_VINIT);
12779	} else {
12780
12781	    for (ns = s; ns && *s;) {
12782		while (*s && isspace(CharOf(*s)))
12783		    s++;
12784		if (!*s)
12785		    break;
12786		if ((ns = end = strchr(s, ',')) == NULL)
12787		    end = s + strlen(s);
12788		while ((end != s) && isspace(CharOf(end[-1])))
12789		    end--;
12790
12791		if (end != s) {
12792		    strcpy(t, "@im=");
12793		    strncat(t, s, (size_t) (end - s));
12794
12795		    if ((p = XSetLocaleModifiers(t)) != NULL && *p
12796			&& (input->xim = XOpenIM(myDisplay,
12797						 NULL,
12798						 NULL,
12799						 NULL)) != NULL) {
12800			break;
12801		    }
12802
12803		}
12804		s = ns + 1;
12805	    }
12806	    MyStackFree(t, buf);
12807	}
12808    }
12809
12810    if (input->xim == NULL
12811	&& (p = XSetLocaleModifiers("@im=none")) != NULL
12812	&& *p) {
12813	input->xim = XOpenIM(myDisplay, NULL, NULL, NULL);
12814    }
12815
12816    if (!input->xim) {
12817	xtermWarning("Failed to open input method\n");
12818	return;
12819    }
12820    TRACE(("VTInitI18N opened input method:%s\n", NonNull(p)));
12821
12822    if (XGetIMValues(input->xim, XNQueryInputStyle, &xim_styles, (void *) 0)
12823	|| !xim_styles
12824	|| !xim_styles->count_styles) {
12825	xtermWarning("input method doesn't support any style\n");
12826	cleanupInputMethod(xw);
12827	xw->work.cannot_im = True;
12828	return;
12829    }
12830
12831    found = False;
12832    for (s = xw->misc.preedit_type; s && !found;) {
12833	while (*s && isspace(CharOf(*s)))
12834	    s++;
12835	if (!*s)
12836	    break;
12837	if ((ns = end = strchr(s, ',')) != NULL)
12838	    ns++;
12839	else
12840	    end = s + strlen(s);
12841	while ((end != s) && isspace(CharOf(end[-1])))
12842	    end--;
12843
12844	if (end != s) {		/* just in case we have a spurious comma */
12845	    TRACE(("looking for style '%.*s'\n", (int) (end - s), s));
12846	    for (i = 0; i < XtNumber(known_style); i++) {
12847		if ((int) strlen(known_style[i].name) == (end - s)
12848		    && !strncmp(s, known_style[i].name, (size_t) (end - s))) {
12849		    input_style = known_style[i].code;
12850		    for (j = 0; j < xim_styles->count_styles; j++) {
12851			if (input_style == xim_styles->supported_styles[j]) {
12852			    found = True;
12853			    break;
12854			}
12855		    }
12856		    if (found)
12857			break;
12858		}
12859	    }
12860	}
12861
12862	s = ns;
12863    }
12864    XFree(xim_styles);
12865
12866    if (!found) {
12867	xtermWarning("input method doesn't support my preedit type (%s)\n",
12868		     xw->misc.preedit_type);
12869	cleanupInputMethod(xw);
12870	xw->work.cannot_im = True;
12871	return;
12872    }
12873
12874    /*
12875     * Check for styles we do not yet support.
12876     */
12877    TRACE(("input_style %#lx\n", input_style));
12878    if (input_style == (XIMPreeditArea | XIMStatusArea)) {
12879	xtermWarning("This program doesn't support the 'OffTheSpot' preedit type\n");
12880	cleanupInputMethod(xw);
12881	xw->work.cannot_im = True;
12882	return;
12883    }
12884
12885    /*
12886     * For XIMPreeditPosition (or OverTheSpot), XIM client has to
12887     * prepare a font.
12888     * The font has to be locale-dependent XFontSet, whereas
12889     * XTerm use Unicode font.  This leads a problem that the
12890     * same font cannot be used for XIM preedit.
12891     */
12892    if (input_style != (XIMPreeditNothing | XIMStatusNothing)) {
12893	XVaNestedList p_list;
12894	XPoint spot =
12895	{0, 0};
12896
12897	if (xim_create_fs(xw)) {
12898	    p_list = XVaCreateNestedList(0,
12899					 XNSpotLocation, &spot,
12900					 XNFontSet, xw->work.xim_fs,
12901					 (void *) 0);
12902	    input->xic = XCreateIC(input->xim,
12903				   XNInputStyle, input_style,
12904				   XNClientWindow, myWindow,
12905				   XNFocusWindow, myWindow,
12906				   XNPreeditAttributes, p_list,
12907				   (void *) 0);
12908	}
12909    } else {
12910	input->xic = XCreateIC(input->xim, XNInputStyle, input_style,
12911			       XNClientWindow, myWindow,
12912			       XNFocusWindow, myWindow,
12913			       (void *) 0);
12914    }
12915
12916    if (!input->xic) {
12917	xtermWarning("Failed to create input context\n");
12918	cleanupInputMethod(xw);
12919    }
12920#if defined(USE_XIM_INSTANTIATE_CB)
12921    else {
12922	XIMCallback destroy_cb;
12923
12924	destroy_cb.callback = xim_destroy_cb;
12925	destroy_cb.client_data = NULL;
12926	if (XSetIMValues(input->xim,
12927			 XNDestroyCallback,
12928			 &destroy_cb,
12929			 (void *) 0)) {
12930	    xtermWarning("Could not set destroy callback to IM\n");
12931	}
12932    }
12933#endif
12934
12935    return;
12936}
12937
12938static void
12939xim_real_init(XtermWidget xw)
12940{
12941    xim_create_xic(xw, (Widget) xw);
12942}
12943
12944static void
12945VTInitI18N(XtermWidget xw)
12946{
12947    if (xw->misc.open_im) {
12948	xim_real_init(xw);
12949
12950#if defined(USE_XIM_INSTANTIATE_CB)
12951	if (lookupTInput(xw, (Widget) xw) == NULL
12952	    && !xw->work.cannot_im
12953	    && xw->misc.retry_im-- > 0) {
12954	    sleep(3);
12955	    XRegisterIMInstantiateCallback(XtDisplay(xw), NULL, NULL, NULL,
12956					   xim_instantiate_cb, NULL);
12957	}
12958#endif
12959    }
12960}
12961
12962TInput *
12963lookupTInput(XtermWidget xw, Widget w)
12964{
12965    TInput *result = NULL;
12966    unsigned n;
12967
12968    for (n = 0; n < NINPUTWIDGETS; ++n) {
12969	if (xw->work.inputs[n].w == w) {
12970	    result = xw->work.inputs + n;
12971	    break;
12972	}
12973    }
12974
12975    return result;
12976}
12977#endif /* OPT_INPUT_METHOD */
12978
12979static void
12980set_cursor_outline_gc(XtermWidget xw,
12981		      Bool filled,
12982		      Pixel fg,
12983		      Pixel bg,
12984		      Pixel cc)
12985{
12986    TScreen *screen = TScreenOf(xw);
12987    VTwin *win = WhichVWin(screen);
12988    CgsEnum cgsId = gcVTcursOutline;
12989
12990    if (cc == bg)
12991	cc = fg;
12992
12993    if (filled) {
12994	setCgsFore(xw, win, cgsId, bg);
12995	setCgsBack(xw, win, cgsId, cc);
12996    } else {
12997	setCgsFore(xw, win, cgsId, cc);
12998	setCgsBack(xw, win, cgsId, bg);
12999    }
13000}
13001
13002static Boolean
13003VTSetValues(Widget cur,
13004	    Widget request GCC_UNUSED,
13005	    Widget wnew,
13006	    ArgList args GCC_UNUSED,
13007	    Cardinal *num_args GCC_UNUSED)
13008{
13009    XtermWidget curvt = (XtermWidget) cur;
13010    XtermWidget newvt = (XtermWidget) wnew;
13011    Boolean refresh_needed = False;
13012    Boolean fonts_redone = False;
13013
13014    if ((T_COLOR(TScreenOf(curvt), TEXT_BG) !=
13015	 T_COLOR(TScreenOf(newvt), TEXT_BG)) ||
13016	(T_COLOR(TScreenOf(curvt), TEXT_FG) !=
13017	 T_COLOR(TScreenOf(newvt), TEXT_FG)) ||
13018	(TScreenOf(curvt)->MenuFontName(TScreenOf(curvt)->menu_font_number) !=
13019	 TScreenOf(newvt)->MenuFontName(TScreenOf(newvt)->menu_font_number)) ||
13020	strcmp(NonNull(DefaultFontN(curvt)), NonNull(DefaultFontN(newvt)))) {
13021	if (strcmp(NonNull(DefaultFontN(curvt)), NonNull(DefaultFontN(newvt)))) {
13022	    TScreenOf(newvt)->MenuFontName(fontMenu_default) = DefaultFontN(newvt);
13023	}
13024	if (xtermLoadFont(newvt,
13025			  xtermFontName(TScreenOf(newvt)->MenuFontName(TScreenOf(curvt)->menu_font_number)),
13026			  True, TScreenOf(newvt)->menu_font_number)) {
13027	    /* resizing does the redisplay, so don't ask for it here */
13028	    refresh_needed = True;
13029	    fonts_redone = True;
13030	} else if (strcmp(NonNull(DefaultFontN(curvt)), NonNull(DefaultFontN(newvt)))) {
13031	    TScreenOf(newvt)->MenuFontName(fontMenu_default) = DefaultFontN(curvt);
13032	}
13033    }
13034    if (!fonts_redone
13035	&& (T_COLOR(TScreenOf(curvt), TEXT_CURSOR) !=
13036	    T_COLOR(TScreenOf(newvt), TEXT_CURSOR))) {
13037	if (set_cursor_gcs(newvt))
13038	    refresh_needed = True;
13039    }
13040    if (curvt->misc.re_verse != newvt->misc.re_verse) {
13041	newvt->flags ^= REVERSE_VIDEO;
13042	ReverseVideo(newvt);
13043	/* ReverseVideo toggles */
13044	newvt->misc.re_verse = (Boolean) (!newvt->misc.re_verse);
13045	refresh_needed = True;
13046    }
13047    if ((T_COLOR(TScreenOf(curvt), MOUSE_FG) !=
13048	 T_COLOR(TScreenOf(newvt), MOUSE_FG)) ||
13049	(T_COLOR(TScreenOf(curvt), MOUSE_BG) !=
13050	 T_COLOR(TScreenOf(newvt), MOUSE_BG))) {
13051	recolor_cursor(TScreenOf(newvt),
13052		       TScreenOf(newvt)->pointer_cursor,
13053		       T_COLOR(TScreenOf(newvt), MOUSE_FG),
13054		       T_COLOR(TScreenOf(newvt), MOUSE_BG));
13055	refresh_needed = True;
13056    }
13057    if (curvt->misc.scrollbar != newvt->misc.scrollbar) {
13058	ToggleScrollBar(newvt);
13059    }
13060
13061    return refresh_needed;
13062}
13063
13064/*
13065 * Given a font-slot and information about selection/reverse, find the
13066 * corresponding cached-GC slot.
13067 */
13068#if OPT_WIDE_ATTRS
13069static int
13070reverseCgs(XtermWidget xw, unsigned attr_flags, Bool hilite, int font)
13071{
13072    TScreen *screen = TScreenOf(xw);
13073    CgsEnum result = gcMAX;
13074
13075    (void) screen;
13076    if (ReverseOrHilite(screen, attr_flags, hilite)) {
13077	switch (font) {
13078	case fNorm:
13079	    result = gcNormReverse;
13080	    break;
13081	case fBold:
13082	    result = gcBoldReverse;
13083	    break;
13084#if OPT_WIDE_ATTRS || OPT_RENDERWIDE
13085	case fItal:
13086	    result = gcNormReverse;	/* FIXME */
13087	    break;
13088#endif
13089#if OPT_WIDE_CHARS
13090	case fWide:
13091	    result = gcWideReverse;
13092	    break;
13093	case fWBold:
13094	    result = gcWBoldReverse;
13095	    break;
13096	case fWItal:
13097	    result = gcWideReverse;	/* FIXME */
13098	    break;
13099#endif
13100	}
13101    } else {
13102	switch (font) {
13103	case fNorm:
13104	    result = gcNorm;
13105	    break;
13106	case fBold:
13107	    result = gcBold;
13108	    break;
13109#if OPT_WIDE_ATTRS || OPT_RENDERWIDE
13110	case fItal:
13111	    result = gcNorm;	/* FIXME */
13112	    break;
13113#endif
13114#if OPT_WIDE_CHARS
13115	case fWide:
13116	    result = gcWide;
13117	    break;
13118	case fWBold:
13119	    result = gcWBold;
13120	    break;
13121	case fWItal:
13122	    result = gcWide;	/* FIXME */
13123	    break;
13124#endif
13125	}
13126    }
13127    return (int) result;
13128}
13129#endif
13130
13131#define setGC(code) set_at = __LINE__, currentCgs = code
13132
13133#define OutsideSelection(screen,srow,scol)  \
13134	 ((srow) > (screen)->endH.row || \
13135	  ((srow) == (screen)->endH.row && \
13136	   (scol) >= (screen)->endH.col) || \
13137	  (srow) < (screen)->startH.row || \
13138	  ((srow) == (screen)->startH.row && \
13139	   (scol) < (screen)->startH.col))
13140
13141/*
13142 * Shows cursor at new cursor position in screen.
13143 */
13144void
13145ShowCursor(XtermWidget xw)
13146{
13147    TScreen *screen = TScreenOf(xw);
13148    XTermDraw params;
13149    IChar base;
13150    unsigned flags;
13151    CellColor fg_bg = initCColor;
13152    GC currentGC;
13153    GC outlineGC;
13154    CgsEnum currentCgs = gcMAX;
13155    VTwin *currentWin = WhichVWin(screen);
13156    int set_at;
13157    Bool in_selection;
13158    Bool reversed;
13159    Bool filled;
13160    Pixel fg_pix;
13161    Pixel bg_pix;
13162    Pixel tmp;
13163#if OPT_HIGHLIGHT_COLOR
13164    Pixel selbg_pix = T_COLOR(screen, HIGHLIGHT_BG);
13165    Pixel selfg_pix = T_COLOR(screen, HIGHLIGHT_FG);
13166    Boolean use_selbg;
13167    Boolean use_selfg;
13168#endif
13169#if OPT_WIDE_CHARS
13170    int my_col = 0;
13171#endif
13172    int cursor_col;
13173    CLineData *ld = NULL;
13174
13175    if (screen->cursor_state == BLINKED_OFF)
13176	return;
13177
13178    if (screen->eventMode != NORMAL)
13179	return;
13180
13181    if (INX2ROW(screen, screen->cur_row) > screen->max_row)
13182	return;
13183
13184    screen->cursorp.row = screen->cur_row;
13185    cursor_col = screen->cursorp.col = screen->cur_col;
13186    screen->cursor_moved = False;
13187
13188#ifndef NO_ACTIVE_ICON
13189    if (IsIcon(screen)) {
13190	screen->cursor_state = ON;
13191	return;
13192    }
13193#endif /* NO_ACTIVE_ICON */
13194
13195    ld = getLineData(screen, screen->cur_row);
13196
13197    base = ld->charData[cursor_col];
13198    flags = ld->attribs[cursor_col];
13199
13200    if_OPT_WIDE_CHARS(screen, {
13201	if (base == HIDDEN_CHAR && cursor_col > 0) {
13202	    /* if cursor points to non-initial part of wide character,
13203	     * back it up
13204	     */
13205	    --cursor_col;
13206	    base = ld->charData[cursor_col];
13207	}
13208	my_col = cursor_col;
13209	if (base == 0)
13210	    base = ' ';
13211	if (isWide((int) base))
13212	    my_col += 1;
13213    });
13214
13215    if (base == 0) {
13216	base = ' ';
13217    }
13218#if OPT_ISO_COLORS
13219#ifdef EXP_BOGUS_FG
13220    /*
13221     * If the cursor happens to be on blanks, and we have not set both
13222     * foreground and background color, do not treat it as a colored cell.
13223     */
13224    if (base == ' ') {
13225	if ((flags & (FG_COLOR | BG_COLOR)) == BG_COLOR) {
13226	    TRACE(("ShowCursor - do not treat as a colored cell\n"));
13227	    flags &= ~(FG_COLOR | BG_COLOR);
13228	} else if ((flags & (FG_COLOR | BG_COLOR)) == FG_COLOR) {
13229	    TRACE(("ShowCursor - should we treat as a colored cell?\n"));
13230	    if (!(xw->flags & FG_COLOR)) {
13231		if (CheckBogusForeground(screen, "ShowCursor")) {
13232		    flags &= ~(FG_COLOR | BG_COLOR);
13233		}
13234	    }
13235	}
13236    }
13237#else /* !EXP_BOGUS_FG */
13238    /*
13239     * If the cursor happens to be on blanks, and the foreground color is set
13240     * but not the background, do not treat it as a colored cell.
13241     */
13242    if ((flags & TERM_COLOR_FLAGS(xw)) == FG_COLOR
13243	&& base == ' ') {
13244	flags &= ~TERM_COLOR_FLAGS(xw);
13245    }
13246#endif
13247#endif
13248
13249    /*
13250     * Compare the current cell to the last set of colors used for the
13251     * cursor and update the GC's if needed.
13252     */
13253    (void) fg_bg;
13254    if_OPT_ISO_COLORS(screen, {
13255	fg_bg = ld->color[cursor_col];
13256    });
13257
13258    fg_pix = getXtermFG(xw, flags, (int) extract_fg(xw, fg_bg, flags));
13259    bg_pix = getXtermBG(xw, flags, (int) extract_bg(xw, fg_bg, flags));
13260
13261    /*
13262     * If we happen to have the same foreground/background colors, choose
13263     * a workable foreground color from which we can obtain a visible cursor.
13264     */
13265    if (fg_pix == bg_pix) {
13266	long bg_diff = (long) (bg_pix - T_COLOR(TScreenOf(xw), TEXT_BG));
13267	long fg_diff = (long) (bg_pix - T_COLOR(TScreenOf(xw), TEXT_FG));
13268	if (bg_diff < 0)
13269	    bg_diff = -bg_diff;
13270	if (fg_diff < 0)
13271	    fg_diff = -fg_diff;
13272	if (bg_diff < fg_diff) {
13273	    fg_pix = T_COLOR(TScreenOf(xw), TEXT_FG);
13274	} else {
13275	    fg_pix = T_COLOR(TScreenOf(xw), TEXT_BG);
13276	}
13277    }
13278
13279    if (OutsideSelection(screen, screen->cur_row, screen->cur_col))
13280	in_selection = False;
13281    else
13282	in_selection = True;
13283
13284    reversed = ReverseOrHilite(screen, flags, in_selection);
13285
13286    /* This is like updatedXtermGC(), except that we have to worry about
13287     * whether the window has focus, since in that case we want just an
13288     * outline for the cursor.
13289     */
13290    filled = (screen->select || screen->always_highlight) && isCursorBlock(screen);
13291#if OPT_HIGHLIGHT_COLOR
13292    use_selbg = isNotForeground(xw, fg_pix, bg_pix, selbg_pix);
13293    use_selfg = isNotBackground(xw, fg_pix, bg_pix, selfg_pix);
13294#endif
13295    if (filled) {
13296	if (reversed) {		/* text is reverse video */
13297	    if (getCgsGC(xw, currentWin, gcVTcursNormal)) {
13298		setGC(gcVTcursNormal);
13299	    } else {
13300		if (flags & BOLDATTR(screen)) {
13301		    setGC(gcBold);
13302		} else {
13303		    setGC(gcNorm);
13304		}
13305	    }
13306	    EXCHANGE(fg_pix, bg_pix, tmp);
13307#if OPT_HIGHLIGHT_COLOR
13308	    if (screen->hilite_reverse) {
13309		if (use_selbg && !use_selfg)
13310		    fg_pix = bg_pix;
13311		if (use_selfg && !use_selbg)
13312		    bg_pix = fg_pix;
13313		if (use_selbg)
13314		    bg_pix = selbg_pix;
13315		if (use_selfg)
13316		    fg_pix = selfg_pix;
13317	    }
13318#endif
13319	} else {		/* normal video */
13320	    if (getCgsGC(xw, currentWin, gcVTcursReverse)) {
13321		setGC(gcVTcursReverse);
13322	    } else {
13323		if (flags & BOLDATTR(screen)) {
13324		    setGC(gcBoldReverse);
13325		} else {
13326		    setGC(gcNormReverse);
13327		}
13328	    }
13329	}
13330
13331#define CUR_XX T_COLOR(screen, TEXT_CURSOR)
13332#define CGS_FG getCgsFore(xw, currentWin, getCgsGC(xw, currentWin, currentCgs))
13333#define CGS_BG getCgsBack(xw, currentWin, getCgsGC(xw, currentWin, currentCgs))
13334
13335#define FIX_311 (CUR_XX == (reversed ? xw->dft_background : xw->dft_foreground))
13336#define FIX_328 (CUR_XX == bg_pix)
13337#define FIX_330 (FIX_328 && reversed && in_selection)
13338
13339	if (FIX_330 || FIX_311) {
13340	    setCgsBack(xw, currentWin, currentCgs, fg_pix);
13341	}
13342	setCgsFore(xw, currentWin, currentCgs, bg_pix);
13343    } else {			/* not selected */
13344	if (reversed) {		/* text is reverse video */
13345	    EXCHANGE(fg_pix, bg_pix, tmp);
13346	    setGC(gcNormReverse);
13347	} else {		/* normal video */
13348	    setGC(gcNorm);
13349	}
13350#if OPT_HIGHLIGHT_COLOR
13351	if (screen->hilite_reverse) {
13352	    if (in_selection && !reversed) {
13353		/* EMPTY */
13354		/* really INVERSE ... */
13355		;
13356	    } else if (in_selection || reversed) {
13357		if (use_selbg) {
13358		    if (use_selfg) {
13359			bg_pix = fg_pix;
13360		    } else {
13361			fg_pix = bg_pix;
13362			bg_pix = selbg_pix;
13363		    }
13364		}
13365		if (use_selfg) {
13366		    fg_pix = selfg_pix;
13367		}
13368	    }
13369	} else {
13370	    if (in_selection) {
13371		if (use_selbg) {
13372		    bg_pix = selbg_pix;
13373		}
13374		if (use_selfg) {
13375		    fg_pix = selfg_pix;
13376		}
13377	    }
13378	}
13379#endif
13380	setCgsFore(xw, currentWin, currentCgs, fg_pix);
13381	setCgsBack(xw, currentWin, currentCgs, bg_pix);
13382    }
13383
13384    if (screen->cursor_busy == 0
13385	&& (screen->cursor_state != ON || screen->cursor_GC != set_at)) {
13386	int x, y;
13387
13388	screen->cursor_GC = set_at;
13389	TRACE(("ShowCursor calling drawXtermText cur(%d,%d) %s-%s, set_at %d\n",
13390	       screen->cur_row, screen->cur_col,
13391	       (filled ? "filled" : "outline"),
13392	       (isCursorBlock(screen) ? "box" :
13393		isCursorUnderline(screen) ? "underline" : "bar"),
13394	       set_at));
13395
13396	currentGC = getCgsGC(xw, currentWin, currentCgs);
13397	x = LineCursorX(screen, ld, cursor_col);
13398	y = CursorY(screen, screen->cur_row);
13399
13400	if (!isCursorBlock(screen)) {
13401	    /*
13402	     * Overriding the combination of filled, reversed, in_selection is
13403	     * too complicated since the underline or bar and the text-cell use
13404	     * different rules.  Just redraw the text-cell, and draw the
13405	     * underline or bar on top of it.
13406	     */
13407	    HideCursor(xw);
13408
13409	    /*
13410	     * Our current-GC is likely to have been modified in HideCursor().
13411	     * Set up a new request.
13412	     */
13413	    if (filled) {
13414		if (FIX_330 || FIX_311) {
13415		    setCgsBack(xw, currentWin, currentCgs, fg_pix);
13416		}
13417		setCgsFore(xw, currentWin, currentCgs, bg_pix);
13418	    } else {
13419		setCgsFore(xw, currentWin, currentCgs, fg_pix);
13420		setCgsBack(xw, currentWin, currentCgs, bg_pix);
13421	    }
13422	}
13423
13424	/*
13425	 * Update the outline-gc, to keep the cursor color distinct from the
13426	 * background color.
13427	 */
13428	set_cursor_outline_gc(xw,
13429			      filled,
13430			      fg_pix,
13431			      bg_pix,
13432			      T_COLOR(screen, TEXT_CURSOR));
13433
13434	outlineGC = getCgsGC(xw, currentWin, gcVTcursOutline);
13435	if (outlineGC == NULL)
13436	    outlineGC = currentGC;
13437
13438	if (isCursorUnderline(screen)) {
13439
13440	    /*
13441	     * Finally, draw the underline.
13442	     */
13443	    screen->box->x = (short) x;
13444	    screen->box->y = (short) (y
13445				      + FontHeight(screen)
13446				      - screen->box[2].y);
13447	    XFillRectangle(screen->display, VDrawable(screen), outlineGC,
13448			   screen->box->x,
13449			   screen->box->y,
13450			   (unsigned) screen->box[1].x,
13451			   (unsigned) screen->box[2].y);
13452	} else if (isCursorBar(screen)) {
13453
13454	    /*
13455	     * Or draw the bar.
13456	     */
13457	    screen->box->x = (short) x;
13458	    screen->box->y = (short) y;
13459	    XFillRectangle(screen->display, VDrawable(screen), outlineGC,
13460			   screen->box->x,
13461			   screen->box->y,
13462			   (unsigned) screen->box[1].x,
13463			   (unsigned) screen->box[2].y);
13464	} else {
13465#if OPT_WIDE_ATTRS
13466	    int italics_on = ((ld->attribs[cursor_col] & ATR_ITALIC) != 0);
13467	    int italics_off = ((xw->flags & ATR_ITALIC) != 0);
13468	    int fix_italics = (italics_on != italics_off);
13469	    int which_font = ((xw->flags & BOLD) ? fBold : fNorm);
13470	    MyGetFont getter = italics_on ? getItalicFont : getNormalFont;
13471
13472	    if_OPT_WIDE_CHARS(screen, {
13473		if (isWide((int) base)) {
13474		    which_font = ((xw->flags & BOLD) ? fWBold : fWide);
13475		}
13476	    });
13477
13478	    if (fix_italics && UseItalicFont(screen)) {
13479		xtermLoadItalics(xw);
13480		setCgsFont(xw, currentWin, currentCgs,
13481			   getter(screen, which_font));
13482		getter = (((xw->flags & ATR_ITALIC) && UseItalicFont(screen))
13483			  ? getItalicFont
13484			  : getNormalFont);
13485	    }
13486	    currentGC = getCgsGC(xw, currentWin, currentCgs);
13487#endif /* OPT_WIDE_ATTRS */
13488
13489	    /* *INDENT-EQLS* */
13490	    params.xw          = xw;
13491	    params.attr_flags  = (flags & DRAWX_MASK);
13492	    params.draw_flags  = 0;
13493	    params.this_chrset = LineCharSet(screen, ld);
13494	    params.real_chrset = CSET_SWL;
13495	    params.on_wide     = 0;
13496
13497	    drawXtermText(&params,
13498			  currentGC, x, y,
13499			  &base, 1);
13500
13501#if OPT_WIDE_CHARS
13502	    if_OPT_WIDE_CHARS(screen, {
13503		size_t off;
13504
13505		/* *INDENT-EQLS* */
13506		params.draw_flags = NOBACKGROUND;
13507		params.on_wide    = isWide((int) base);
13508
13509		for_each_combData(off, ld) {
13510		    if (!(ld->combData[off][my_col]))
13511			break;
13512		    drawXtermText(&params,
13513				  currentGC, x, y,
13514				  ld->combData[off] + my_col, 1);
13515		}
13516	    });
13517#endif
13518
13519	    if (!filled) {
13520		screen->box->x = (short) x;
13521		screen->box->y = (short) y;
13522		XDrawLines(screen->display, VDrawable(screen), outlineGC,
13523			   screen->box, NBOX, CoordModePrevious);
13524	    }
13525#if OPT_WIDE_ATTRS
13526	    if (fix_italics && UseItalicFont(screen)) {
13527		setCgsFont(xw, currentWin, currentCgs,
13528			   getter(screen, which_font));
13529	    }
13530#endif
13531	}
13532    }
13533    screen->cursor_state = ON;
13534
13535    return;
13536}
13537
13538/*
13539 * hide cursor at previous cursor position in screen.
13540 */
13541void
13542HideCursor(XtermWidget xw)
13543{
13544    TScreen *screen = TScreenOf(xw);
13545    XTermDraw params;
13546    GC currentGC;
13547    int x, y;
13548    IChar base;
13549    unsigned flags;
13550    CellColor fg_bg = initCColor;
13551    Bool in_selection;
13552#if OPT_WIDE_CHARS
13553    int my_col = 0;
13554#endif
13555    int cursor_col;
13556    CLineData *ld = NULL;
13557#if OPT_WIDE_ATTRS
13558    int which_Cgs = gcMAX;
13559    unsigned attr_flags;
13560    int which_font = fNorm;
13561    MyGetFont getter = getNormalFont;
13562#endif
13563
13564    if (screen->cursor_state == OFF)
13565	return;
13566    if (INX2ROW(screen, screen->cursorp.row) > screen->max_row)
13567	return;
13568
13569    cursor_col = screen->cursorp.col;
13570
13571#ifndef NO_ACTIVE_ICON
13572    if (IsIcon(screen)) {
13573	screen->cursor_state = OFF;
13574	return;
13575    }
13576#endif /* NO_ACTIVE_ICON */
13577
13578    ld = getLineData(screen, screen->cursorp.row);
13579
13580    base = ld->charData[cursor_col];
13581    flags = ld->attribs[cursor_col];
13582
13583    if_OPT_WIDE_CHARS(screen, {
13584	if (base == HIDDEN_CHAR && cursor_col > 0) {
13585	    /* if cursor points to non-initial part of wide character,
13586	     * back it up
13587	     */
13588	    --cursor_col;
13589	    base = ld->charData[cursor_col];
13590	}
13591	my_col = cursor_col;
13592	if (base == 0)
13593	    base = ' ';
13594	if (isWide((int) base))
13595	    my_col += 1;
13596    });
13597
13598    if (base == 0) {
13599	base = ' ';
13600    }
13601#ifdef EXP_BOGUS_FG
13602    /*
13603     * If the cursor happens to be on blanks, and we have not set both
13604     * foreground and background color, do not treat it as a colored cell.
13605     */
13606#if OPT_ISO_COLORS
13607    if (base == ' ') {
13608	if ((flags & (FG_COLOR | BG_COLOR)) == BG_COLOR) {
13609	    TRACE(("HideCursor - do not treat as a colored cell\n"));
13610	    flags &= ~(FG_COLOR | BG_COLOR);
13611	} else if ((flags & (FG_COLOR | BG_COLOR)) == FG_COLOR) {
13612	    TRACE(("HideCursor - should we treat as a colored cell?\n"));
13613	    if (!(xw->flags & FG_COLOR))
13614		if (CheckBogusForeground(screen, "HideCursor"))
13615		    flags &= ~(FG_COLOR | BG_COLOR);
13616	}
13617    }
13618#endif
13619#endif
13620
13621    /*
13622     * Compare the current cell to the last set of colors used for the
13623     * cursor and update the GC's if needed.
13624     */
13625    if_OPT_ISO_COLORS(screen, {
13626	fg_bg = ld->color[cursor_col];
13627    });
13628
13629    if (OutsideSelection(screen, screen->cursorp.row, screen->cursorp.col))
13630	in_selection = False;
13631    else
13632	in_selection = True;
13633
13634#if OPT_WIDE_ATTRS
13635    attr_flags = ld->attribs[cursor_col];
13636    if ((attr_flags & ATR_ITALIC) ^ (xw->flags & ATR_ITALIC)) {
13637	which_font = ((attr_flags & BOLD) ? fBold : fNorm);
13638	if ((attr_flags & ATR_ITALIC) && UseItalicFont(screen))
13639	    getter = getItalicFont;
13640
13641	if_OPT_WIDE_CHARS(screen, {
13642	    if (isWide((int) base)) {
13643		which_font = ((attr_flags & BOLD) ? fWBold : fWide);
13644	    }
13645	});
13646
13647	which_Cgs = reverseCgs(xw, attr_flags, in_selection, which_font);
13648	if (which_Cgs != gcMAX) {
13649	    setCgsFont(xw, WhichVWin(screen),
13650		       (CgsEnum) which_Cgs,
13651		       getter(screen, which_font));
13652	    getter = (((xw->flags & ATR_ITALIC) && UseItalicFont(screen))
13653		      ? getItalicFont
13654		      : getNormalFont);
13655	}
13656    }
13657#endif
13658
13659    currentGC = updatedXtermGC(xw, flags, fg_bg, in_selection);
13660
13661    TRACE(("HideCursor calling drawXtermText cur(%d,%d)\n",
13662	   screen->cursorp.row, screen->cursorp.col));
13663
13664    x = LineCursorX(screen, ld, cursor_col);
13665    y = CursorY(screen, screen->cursorp.row);
13666
13667    /* *INDENT-EQLS* */
13668    params.xw          = xw;
13669    params.attr_flags  = (flags & DRAWX_MASK);
13670    params.draw_flags  = 0;
13671    params.this_chrset = LineCharSet(screen, ld);
13672    params.real_chrset = CSET_SWL;
13673    params.on_wide     = 0;
13674
13675    drawXtermText(&params,
13676		  currentGC, x, y,
13677		  &base, 1);
13678
13679#if OPT_WIDE_CHARS
13680    if_OPT_WIDE_CHARS(screen, {
13681	size_t off;
13682
13683	/* *INDENT-EQLS* */
13684	params.draw_flags  = NOBACKGROUND;
13685	params.on_wide     = isWide((int) base);
13686
13687	for_each_combData(off, ld) {
13688	    if (!(ld->combData[off][my_col]))
13689		break;
13690	    drawXtermText(&params,
13691			  currentGC, x, y,
13692			  ld->combData[off] + my_col, 1);
13693	}
13694    });
13695#endif
13696    screen->cursor_state = OFF;
13697
13698#if OPT_WIDE_ATTRS
13699    if (which_Cgs != gcMAX) {
13700	setCgsFont(xw, WhichVWin(screen),
13701		   (CgsEnum) which_Cgs,
13702		   getter(screen, which_font));
13703    }
13704#endif
13705    resetXtermGC(xw, flags, in_selection);
13706
13707    refresh_displayed_graphics(xw,
13708			       screen->cursorp.col,
13709			       screen->cursorp.row,
13710			       1, 1);
13711
13712    return;
13713}
13714
13715#if OPT_BLINK_CURS || OPT_BLINK_TEXT
13716static void
13717StartBlinking(XtermWidget xw)
13718{
13719    TScreen *screen = TScreenOf(xw);
13720
13721    if (screen->blink_timer == 0) {
13722	unsigned long interval = (unsigned long) ((screen->cursor_state == ON)
13723						  ? screen->blink_on
13724						  : screen->blink_off);
13725	if (interval == 0)	/* wow! */
13726	    interval = 1;	/* let's humor him anyway */
13727	screen->blink_timer = XtAppAddTimeOut(app_con,
13728					      interval,
13729					      HandleBlinking,
13730					      xw);
13731    }
13732}
13733
13734static void
13735StopBlinking(XtermWidget xw)
13736{
13737    TScreen *screen = TScreenOf(xw);
13738
13739    if (screen->blink_timer) {
13740	XtRemoveTimeOut(screen->blink_timer);
13741	screen->blink_timer = 0;
13742	reallyStopBlinking(xw);
13743    } else {
13744	screen->blink_timer = 0;
13745    }
13746}
13747
13748#if OPT_BLINK_TEXT
13749Bool
13750LineHasBlinking(TScreen *screen, CLineData *ld)
13751{
13752    Bool result = False;
13753    if (ld != NULL) {
13754	int col;
13755
13756	for (col = 0; col < MaxCols(screen); ++col) {
13757	    if (ld->attribs[col] & BLINK) {
13758		result = True;
13759		break;
13760	    }
13761	}
13762    }
13763    return result;
13764}
13765#endif
13766
13767/*
13768 * Blink the cursor by alternately showing/hiding cursor.  We leave the timer
13769 * running all the time (even though that's a little inefficient) to make the
13770 * logic simple.
13771 */
13772static void
13773HandleBlinking(XtPointer closure, XtIntervalId * id GCC_UNUSED)
13774{
13775    XtermWidget xw = (XtermWidget) closure;
13776    TScreen *screen = TScreenOf(xw);
13777    Bool resume = False;
13778
13779    screen->blink_timer = 0;
13780    screen->blink_state = !screen->blink_state;
13781
13782#if OPT_BLINK_CURS
13783    if (DoStartBlinking(screen)) {
13784	if (screen->cursor_state == ON) {
13785	    if (screen->select || screen->always_highlight) {
13786		HideCursor(xw);
13787		if (screen->cursor_state == OFF)
13788		    screen->cursor_state = BLINKED_OFF;
13789	    }
13790	} else if (screen->cursor_state == BLINKED_OFF) {
13791	    screen->cursor_state = OFF;
13792	    ShowCursor(xw);
13793	    if (screen->cursor_state == OFF)
13794		screen->cursor_state = BLINKED_OFF;
13795	}
13796	resume = True;
13797    }
13798#endif
13799
13800#if OPT_BLINK_TEXT
13801    /*
13802     * Inspect the lines on the current screen to see if any have the BLINK flag
13803     * associated with them.  Prune off any that have had the corresponding
13804     * cells reset.  If any are left, repaint those lines with ScrnRefresh().
13805     */
13806    if (!(screen->blink_as_bold)) {
13807	int row;
13808	int start_row = LastRowNumber(screen);
13809	int first_row = start_row;
13810	int last_row = -1;
13811
13812	for (row = start_row; row >= 0; row--) {
13813	    LineData *ld = getLineData(screen, ROW2INX(screen, row));
13814
13815	    if (ld != NULL && LineTstBlinked(ld)) {
13816		if (LineHasBlinking(screen, ld)) {
13817		    resume = True;
13818		    if (row > last_row)
13819			last_row = row;
13820		    if (row < first_row)
13821			first_row = row;
13822		} else {
13823		    LineClrBlinked(ld);
13824		}
13825	    }
13826	}
13827	/*
13828	 * FIXME: this could be a little more efficient, e.g,. by limiting the
13829	 * columns which are updated.
13830	 */
13831	if (first_row <= last_row) {
13832	    ScrnRefresh(xw,
13833			first_row,
13834			0,
13835			last_row + 1 - first_row,
13836			MaxCols(screen),
13837			True);
13838	}
13839    }
13840#endif
13841
13842    /*
13843     * If either the cursor or text is blinking, restart the timer.
13844     */
13845    if (resume)
13846	StartBlinking(xw);
13847}
13848#endif /* OPT_BLINK_CURS || OPT_BLINK_TEXT */
13849
13850void
13851RestartBlinking(XtermWidget xw)
13852{
13853#if OPT_BLINK_CURS || OPT_BLINK_TEXT
13854    TScreen *screen = TScreenOf(xw);
13855
13856    if (screen->blink_timer == 0) {
13857	Bool resume = False;
13858
13859#if OPT_BLINK_CURS
13860	if (DoStartBlinking(screen)) {
13861	    resume = True;
13862	}
13863#endif
13864#if OPT_BLINK_TEXT
13865	if (!resume) {
13866	    int row;
13867
13868	    for (row = screen->max_row; row >= 0; row--) {
13869		CLineData *ld = getLineData(screen, ROW2INX(screen, row));
13870
13871		if (ld != NULL && LineTstBlinked(ld)) {
13872		    if (LineHasBlinking(screen, ld)) {
13873			resume = True;
13874			break;
13875		    }
13876		}
13877	    }
13878	}
13879#endif
13880	if (resume)
13881	    StartBlinking(xw);
13882    }
13883#else
13884    (void) xw;
13885#endif
13886}
13887
13888/*
13889 * Implement soft or hard (full) reset of the VTxxx emulation.  There are a
13890 * couple of differences from real DEC VTxxx terminals (to avoid breaking
13891 * applications which have come to rely on xterm doing this):
13892 *
13893 *	+ autowrap mode should be reset (instead it's reset to the resource
13894 *	  default).
13895 *	+ the popup menu offers a choice of resetting the savedLines, or not.
13896 *	  (but the control sequence does this anyway).
13897 */
13898static void
13899ReallyReset(XtermWidget xw, Bool full, Bool saved)
13900{
13901    TScreen *screen = TScreenOf(xw);
13902    IFlags saveflags = xw->flags;
13903
13904    TRACE(("ReallyReset %s, %s\n",
13905	   full ? "hard" : "soft",
13906	   saved ? "clear savedLines" : "keep savedLines"));
13907
13908    if (!XtIsRealized((Widget) xw) || (CURRENT_EMU() != (Widget) xw)) {
13909	Bell(xw, XkbBI_MinorError, 0);
13910	return;
13911    }
13912
13913    if (saved) {
13914	screen->savedlines = 0;
13915	ScrollBarDrawThumb(xw, 0);
13916    }
13917
13918    /* make cursor visible */
13919    screen->cursor_set = ON;
13920    InitCursorShape(screen, screen);
13921    xtermSetCursorBox(screen);
13922#if OPT_BLINK_CURS
13923    screen->cursor_blink_esc = 0;
13924    SetCursorBlink(xw, screen->cursor_blink_i);
13925    TRACE(("cursor_shape:%d blinks:%d\n",
13926	   screen->cursor_shape,
13927	   screen->cursor_blink));
13928#endif
13929#if OPT_STATUS_LINE
13930    if (screen->vtXX_level >= 2) {
13931	if (full)
13932	    handle_DECSSDT(xw, 0);	/* DEC STD 070, page 14-10, RIS */
13933	else
13934	    handle_DECSASD(xw, 0);	/* DEC STD 070, page 14-9, DECSTR */
13935    }
13936#endif
13937
13938    /* reset scrolling region */
13939    resetMarginMode(xw);
13940
13941    bitclr(&xw->flags, ORIGIN);
13942
13943    if_OPT_ISO_COLORS(screen, {
13944	static char empty[1];
13945	reset_SGR_Colors(xw);
13946	if (ResetAnsiColorRequest(xw, empty, 0))
13947	    xtermRepaint(xw);
13948    });
13949
13950    /* Reset character-sets to initial state */
13951    resetCharsets(screen);
13952
13953    UIntClr(xw->keyboard.flags, (MODE_DECCKM | MODE_KAM | MODE_DECKPAM));
13954    if (xw->misc.appcursorDefault)
13955	xw->keyboard.flags |= MODE_DECCKM;
13956    if (xw->misc.appkeypadDefault)
13957	xw->keyboard.flags |= MODE_DECKPAM;
13958
13959#if OPT_MOD_FKEYS
13960    /* Reset modifier-resources to initial state */
13961    xw->keyboard.modify_now = xw->keyboard.modify_1st;
13962#endif
13963#if OPT_DEC_RECTOPS
13964    screen->checksum_ext = screen->checksum_ext0;
13965#endif
13966
13967    /* Reset DECSCA */
13968    bitclr(&xw->flags, PROTECTED);
13969    screen->protected_mode = OFF_PROTECT;
13970
13971    if (full) {			/* RIS */
13972	if (screen->bellOnReset)
13973	    Bell(xw, XkbBI_TerminalBell, 0);
13974
13975	reset_displayed_graphics(screen);
13976
13977	/* reset the mouse mode */
13978	screen->send_mouse_pos = MOUSE_OFF;
13979	screen->send_focus_pos = OFF;
13980	screen->extend_coords = 0;
13981	screen->waitingForTrackInfo = False;
13982	screen->eventMode = NORMAL;
13983
13984	xtermShowPointer(xw, True);
13985
13986	TabReset(xw->tabs);
13987	xw->keyboard.flags |= MODE_SRM;
13988
13989	guard_keyboard_type = False;
13990	screen->old_fkeys = screen->old_fkeys0;
13991	decode_keyboard_type(xw, &resource);
13992	update_keyboard_type();
13993
13994	UIntClr(xw->keyboard.flags, MODE_DECBKM);
13995#if OPT_INITIAL_ERASE
13996	if (xw->keyboard.reset_DECBKM == 1)
13997	    xw->keyboard.flags |= MODE_DECBKM;
13998	else if (xw->keyboard.reset_DECBKM == 2)
13999#endif
14000	    if (screen->backarrow_key)
14001		xw->keyboard.flags |= MODE_DECBKM;
14002	TRACE(("full reset DECBKM %s\n",
14003	       BtoS(xw->keyboard.flags & MODE_DECBKM)));
14004
14005#if OPT_SCROLL_LOCK
14006	xtermClearLEDs(screen);
14007#endif
14008	screen->title_modes = screen->title_modes0;
14009	screen->pointer_mode = screen->pointer_mode0;
14010#if OPT_SIXEL_GRAPHICS
14011	if (screen->sixel_scrolling)
14012	    UIntClr(xw->keyboard.flags, MODE_DECSDM);
14013	else
14014	    UIntSet(xw->keyboard.flags, MODE_DECSDM);
14015	TRACE(("full reset DECSDM to %s (resource default is %s)\n",
14016	       BtoS(xw->keyboard.flags & MODE_DECSDM),
14017	       BtoS(!screen->sixel_scrolling)));
14018#endif
14019
14020#if OPT_GRAPHICS
14021	screen->privatecolorregisters = screen->privatecolorregisters0;
14022	TRACE(("full reset PRIVATE_COLOR_REGISTERS to %s\n",
14023	       BtoS(screen->privatecolorregisters)));
14024	update_privatecolorregisters();
14025#endif
14026
14027#if OPT_SIXEL_GRAPHICS
14028	screen->sixel_scrolls_right = screen->sixel_scrolls_right0;
14029	TRACE(("full reset SIXEL_SCROLLS_RIGHT to %s\n",
14030	       BtoS(screen->sixel_scrolls_right)));
14031#endif
14032
14033	update_appcursor();
14034	update_appkeypad();
14035	update_decbkm();
14036	update_decsdm();
14037	show_8bit_control(False);
14038	reset_decudk(xw);
14039
14040	FromAlternate(xw, True);
14041	ClearScreen(xw);
14042	screen->cursor_state = OFF;
14043
14044	if (xw->flags & REVERSE_VIDEO)
14045	    ReverseVideo(xw);
14046	ResetItalics(xw);
14047	xw->flags = xw->initflags;
14048
14049	update_reversevideo();
14050	update_autowrap();
14051	update_reversewrap();
14052	update_autolinefeed();
14053
14054	screen->jumpscroll = (Boolean) (!(xw->flags & SMOOTHSCROLL));
14055	update_jumpscroll();
14056
14057#if OPT_DEC_RECTOPS
14058	screen->cur_decsace = 0;
14059#endif
14060#if OPT_PASTE64 || OPT_READLINE
14061	screen->paste_brackets = OFF;
14062#endif
14063#if OPT_READLINE
14064	screen->click1_moves = OFF;
14065	screen->paste_moves = OFF;
14066	screen->dclick3_deletes = OFF;
14067	screen->paste_quotes = OFF;
14068	screen->paste_literal_nl = OFF;
14069#endif /* OPT_READLINE */
14070
14071	if (screen->c132 && (saveflags & IN132COLUMNS)) {
14072	    TRACE(("Making resize-request to restore 80-columns %dx%d\n",
14073		   MaxRows(screen), MaxCols(screen)));
14074	    RequestResize(xw, MaxRows(screen), 80, True);
14075	    repairSizeHints();
14076	    XSync(screen->display, False);	/* synchronize */
14077	    if (xtermAppPending())
14078		xevents(xw);
14079	}
14080
14081	CursorSet(screen, 0, 0, xw->flags);
14082	CursorSave(xw);
14083    } else {			/* DECSTR */
14084	bitcpy(&xw->flags, xw->initflags, WRAPAROUND | REVERSEWRAP | REVERSEWRAP2);
14085	bitclr(&xw->flags, INSERT | INVERSE | BOLD | BLINK | UNDERLINE | INVISIBLE);
14086	ResetItalics(xw);
14087	if_OPT_ISO_COLORS(screen, {
14088	    reset_SGR_Colors(xw);
14089	});
14090	update_appcursor();
14091	update_autowrap();
14092	update_reversewrap();
14093
14094	CursorSave(xw);
14095	screen->sc[screen->whichBuf].row =
14096	    screen->sc[screen->whichBuf].col = 0;
14097    }
14098}
14099
14100void
14101VTReset(XtermWidget xw, Bool full, Bool saved)
14102{
14103    ReallyReset(xw, full, saved);
14104
14105    FreeAndNull(myState.string_area);
14106    FreeAndNull(myState.print_area);
14107
14108    longjmp(vtjmpbuf, 1);	/* force ground state in parser */
14109}
14110
14111typedef enum {
14112    ccLO,
14113    ccDASH,
14114    ccHI,
14115    ccCOLON,
14116    ccID,
14117    ccCOMMA
14118} CCLASS;
14119
14120/*
14121 * set_character_class - takes a string of the form
14122 *
14123 *   low[-high][:id][,low[-high][:id][...]]
14124 *
14125 * and sets the indicated ranges to the indicated values.
14126 */
14127static int
14128set_character_class(char *s)
14129{
14130#define FMT "%s in range string \"%s\" (position %d)\n"
14131
14132    TRACE(("set_character_class(%s) " TRACE_L "\n", NonNull(s)));
14133    if (IsEmpty(s)) {
14134	TRACE((TRACE_R " ERR set_character_class\n"));
14135	return -1;
14136    } else {
14137	CCLASS state = ccLO;
14138	int arg[3];
14139	int i;
14140	int len = (int) strlen(s);
14141
14142	arg[0] =
14143	    arg[1] =
14144	    arg[2] = -1;
14145
14146	for (i = 0; i < len; ++i) {
14147	    int ch = CharOf(s[i]);
14148	    char *t = NULL;
14149	    long value = 0;
14150
14151	    if (isspace(ch))
14152		continue;
14153
14154	    switch (state) {
14155	    case ccLO:
14156	    case ccHI:
14157	    case ccID:
14158		if (!isdigit(ch)) {
14159		    xtermWarning(FMT, "missing number", s, i);
14160		    TRACE((TRACE_R " ERR set_character_class\n"));
14161		    return (-1);
14162		}
14163		value = strtol(s + i, &t, 0);
14164		i = (int) (t - s - 1);
14165		break;
14166	    case ccDASH:
14167	    case ccCOLON:
14168	    case ccCOMMA:
14169		break;
14170	    }
14171
14172	    switch (state) {
14173	    case ccLO:
14174		arg[0] =
14175		    arg[1] = (int) value;
14176		arg[2] = -1;
14177		state = ccDASH;
14178		break;
14179
14180	    case ccDASH:
14181		if (ch == '-') {
14182		    state = ccHI;
14183		} else {
14184		    goto parse_class;
14185		}
14186		break;
14187
14188	    case ccHI:
14189		arg[1] = (int) value;
14190		state = ccCOLON;
14191		break;
14192
14193	      parse_class:
14194		/* FALLTHRU */
14195	    case ccCOLON:
14196		if (ch == ':') {
14197		    state = ccID;
14198		} else if (ch == ',') {
14199		    goto apply_class;
14200		} else {
14201		    xtermWarning(FMT, "unexpected character", s, i);
14202		    TRACE((TRACE_R " ERR set_character_class\n"));
14203		    return (-1);
14204		}
14205		break;
14206
14207	    case ccID:
14208		arg[2] = (int) value;
14209		state = ccCOMMA;
14210		break;
14211
14212	      apply_class:
14213		/* FALLTHRU */
14214	    case ccCOMMA:
14215		if (SetCharacterClassRange(arg[0], arg[1], arg[2]) != 0) {
14216		    xtermWarning(FMT, "bad range", s, i);
14217		    TRACE((TRACE_R " ERR set_character_class\n"));
14218		    return -1;
14219		}
14220		state = ccLO;
14221		break;
14222	    }
14223	}
14224	if (state >= ccDASH) {
14225	    if (SetCharacterClassRange(arg[0], arg[1], arg[2]) != 0) {
14226		xtermWarning(FMT, "bad range", s, i);
14227		TRACE((TRACE_R " ERR set_character_class\n"));
14228		return -1;
14229	    }
14230	}
14231    }
14232
14233    TRACE((TRACE_R " OK set_character_class\n"));
14234    return (0);
14235#undef FMT
14236}
14237
14238void
14239getKeymapResources(Widget w,
14240		   const char *mapName,
14241		   const char *mapClass,
14242		   const char *type,
14243		   void *result,
14244		   size_t size)
14245{
14246    XtResource key_resources[1];
14247    key_resources[0].resource_name = XtNtranslations;
14248    key_resources[0].resource_class = XtCTranslations;
14249    key_resources[0].resource_type = (char *) type;
14250    key_resources[0].resource_size = (Cardinal) size;
14251    key_resources[0].resource_offset = 0;
14252    key_resources[0].default_type = key_resources[0].resource_type;
14253    key_resources[0].default_addr = NULL;
14254    XtGetSubresources(w, (XtPointer) result, mapName, mapClass,
14255		      key_resources, (Cardinal) 1, NULL, (Cardinal) 0);
14256}
14257
14258/* ARGSUSED */
14259static void
14260HandleKeymapChange(Widget w,
14261		   XEvent *event GCC_UNUSED,
14262		   String *params,
14263		   Cardinal *param_count)
14264{
14265    static XtTranslations keymap, original;
14266
14267    TRACE(("HandleKeymapChange(%#lx, %s)\n",
14268	   (unsigned long) w,
14269	   (*param_count
14270	    ? params[0]
14271	    : "missing")));
14272
14273    if (*param_count != 1)
14274	return;
14275
14276    if (original == NULL) {
14277	TRACE(("...saving original keymap-translations\n"));
14278	original = w->core.tm.translations;
14279    }
14280
14281    if (strcmp(params[0], "None") == 0) {
14282	TRACE(("...restoring original keymap-translations\n"));
14283	XtOverrideTranslations(w, original);
14284    } else {
14285	char mapName[1000];
14286	char mapClass[1000];
14287	char *pmapName;
14288	char *pmapClass;
14289	size_t len;
14290
14291	len = strlen(params[0]) + 7;
14292
14293	pmapName = (char *) MyStackAlloc(len, mapName);
14294	pmapClass = (char *) MyStackAlloc(len, mapClass);
14295	if (pmapName == NULL
14296	    || pmapClass == NULL) {
14297	    SysError(ERROR_KMMALLOC1);
14298	} else {
14299
14300	    (void) sprintf(pmapName, "%sKeymap", params[0]);
14301	    (void) strcpy(pmapClass, pmapName);
14302	    if (islower(CharOf(pmapClass[0])))
14303		pmapClass[0] = x_toupper(pmapClass[0]);
14304	    getKeymapResources(w, pmapName, pmapClass, XtRTranslationTable,
14305			       &keymap, sizeof(keymap));
14306	    if (keymap != NULL) {
14307		TRACE(("...applying keymap \"%s\"\n", pmapName));
14308		XtOverrideTranslations(w, keymap);
14309	    } else {
14310		TRACE(("...found no match for keymap \"%s\"\n", pmapName));
14311	    }
14312
14313	    MyStackFree(pmapName, mapName);
14314	    MyStackFree(pmapClass, mapClass);
14315	}
14316    }
14317}
14318
14319/* ARGSUSED */
14320static void
14321HandleBell(Widget w GCC_UNUSED,
14322	   XEvent *event GCC_UNUSED,
14323	   String *params,	/* [0] = volume */
14324	   Cardinal *param_count)	/* 0 or 1 */
14325{
14326    int percent = (*param_count) ? atoi(params[0]) : 0;
14327
14328    Bell(term, XkbBI_TerminalBell, percent);
14329}
14330
14331/* ARGSUSED */
14332static void
14333HandleVisualBell(Widget w GCC_UNUSED,
14334		 XEvent *event GCC_UNUSED,
14335		 String *params GCC_UNUSED,
14336		 Cardinal *param_count GCC_UNUSED)
14337{
14338    VisualBell();
14339}
14340
14341/* ARGSUSED */
14342static void
14343HandleIgnore(Widget w,
14344	     XEvent *event,
14345	     String *params GCC_UNUSED,
14346	     Cardinal *param_count GCC_UNUSED)
14347{
14348    XtermWidget xw;
14349
14350    TRACE(("Handle ignore for %p %s\n",
14351	   (void *) w, visibleEventType(event->type)));
14352    if ((xw = getXtermWidget(w)) != NULL) {
14353	/* do nothing, but check for funny escape sequences */
14354	switch (event->type) {
14355	case ButtonPress:
14356	case ButtonRelease:
14357	case MotionNotify:
14358	    (void) SendMousePosition(xw, event);
14359	    break;
14360	}
14361    }
14362}
14363
14364/* ARGSUSED */
14365static void
14366DoSetSelectedFont(Widget w,
14367		  XtPointer client_data GCC_UNUSED,
14368		  Atom *selection GCC_UNUSED,
14369		  Atom *type,
14370		  XtPointer value,
14371		  unsigned long *length,
14372		  int *format)
14373{
14374    XtermWidget xw = getXtermWidget(w);
14375
14376    if (xw == NULL) {
14377	xtermWarning("unexpected widget in DoSetSelectedFont\n");
14378    } else if (*type != XA_STRING || *format != 8) {
14379	Bell(xw, XkbBI_MinorError, 0);
14380    } else {
14381	Boolean failed = False;
14382	char *save = TScreenOf(xw)->SelectFontName();
14383	char *val;
14384	char *test;
14385	unsigned len = (unsigned) *length;
14386	unsigned tst;
14387
14388	/*
14389	 * Some versions of X deliver null-terminated selections, some do not.
14390	 */
14391	for (tst = 0; tst < len; ++tst) {
14392	    if (((char *) value)[tst] == '\0') {
14393		len = tst;
14394		break;
14395	    }
14396	}
14397
14398	if (len > 0 && (val = TypeMallocN(char, len + 1)) != NULL) {
14399	    char *used;
14400
14401	    memcpy(val, value, (size_t) len);
14402	    val[len] = '\0';
14403	    used = x_strtrim(val);
14404	    TRACE(("DoSetSelectedFont(%s)\n", used));
14405	    /* Do some sanity checking to avoid sending a long selection
14406	       back to the server in an OpenFont that is unlikely to succeed.
14407	       XLFD allows up to 255 characters and no control characters;
14408	       we are a little more liberal here. */
14409	    if (len < 1000
14410		&& used != NULL
14411		&& !strchr(used, '\n')
14412		&& (test = x_strdup(used)) != NULL) {
14413		TScreenOf(xw)->SelectFontName() = test;
14414		if (!xtermLoadFont(xw,
14415				   xtermFontName(used),
14416				   True,
14417				   fontMenu_fontsel)) {
14418		    failed = True;
14419		    free(test);
14420		    TScreenOf(xw)->SelectFontName() = save;
14421		}
14422	    } else {
14423		failed = True;
14424	    }
14425	    if (failed) {
14426		Bell(xw, XkbBI_MinorError, 0);
14427	    }
14428	    free(used);
14429	    free(val);
14430	}
14431    }
14432}
14433
14434Bool
14435FindFontSelection(XtermWidget xw, const char *atom_name, Bool justprobe)
14436{
14437    TScreen *screen = TScreenOf(xw);
14438    static AtomPtr *atoms;
14439    static unsigned int atomCount = 0;
14440    AtomPtr *pAtom;
14441    unsigned a;
14442    Atom target;
14443
14444    if (!atom_name)
14445	atom_name = ((screen->mappedSelect && atomCount)
14446		     ? screen->mappedSelect[0]
14447		     : "PRIMARY");
14448    TRACE(("FindFontSelection(%s)\n", atom_name));
14449
14450    for (pAtom = atoms, a = atomCount; a; a--, pAtom++) {
14451	if (strcmp(atom_name, XmuNameOfAtom(*pAtom)) == 0) {
14452	    TRACE(("...found atom %d:%s\n", a + 1, atom_name));
14453	    break;
14454	}
14455    }
14456    if (!a) {
14457	atoms = TypeXtReallocN(AtomPtr, atoms, atomCount + 1);
14458	*(pAtom = &atoms[atomCount]) = XmuMakeAtom(atom_name);
14459	++atomCount;
14460	TRACE(("...added atom %d:%s\n", atomCount, atom_name));
14461    }
14462
14463    target = XmuInternAtom(XtDisplay(xw), *pAtom);
14464    if (justprobe) {
14465	screen->SelectFontName() =
14466	    XGetSelectionOwner(XtDisplay(xw), target) ? _Font_Selected_ : NULL;
14467	TRACE(("...selected fontname '%s'\n",
14468	       NonNull(screen->SelectFontName())));
14469    } else {
14470	XtGetSelectionValue((Widget) xw, target, XA_STRING,
14471			    DoSetSelectedFont, NULL,
14472			    XtLastTimestampProcessed(XtDisplay(xw)));
14473    }
14474    return (screen->SelectFontName() != NULL) ? True : False;
14475}
14476
14477Bool
14478set_cursor_gcs(XtermWidget xw)
14479{
14480    TScreen *screen = TScreenOf(xw);
14481    VTwin *win = WhichVWin(screen);
14482
14483    Pixel cc = T_COLOR(screen, TEXT_CURSOR);
14484    Pixel fg = T_COLOR(screen, TEXT_FG);
14485    Pixel bg = T_COLOR(screen, TEXT_BG);
14486    Bool changed = False;
14487
14488    /*
14489     * Let's see, there are three things that have "color":
14490     *
14491     *     background
14492     *     text
14493     *     cursorblock
14494     *
14495     * And, there are four situations when drawing a cursor, if we decide
14496     * that we like have a solid block of cursor color with the letter
14497     * that it is highlighting shown in the background color to make it
14498     * stand out:
14499     *
14500     *     selected window, normal video - background on cursor
14501     *     selected window, reverse video - foreground on cursor
14502     *     unselected window, normal video - foreground on background
14503     *     unselected window, reverse video - background on foreground
14504     *
14505     * Since the last two are really just normalGC and reverseGC, we only
14506     * need two new GC's.  Under monochrome, we get the same effect as
14507     * above by setting cursor color to foreground.
14508     */
14509
14510    TRACE(("set_cursor_gcs cc=%#lx, fg=%#lx, bg=%#lx\n", cc, fg, bg));
14511    if (win != NULL && (cc != bg)) {
14512	Pixel xx = ((fg == cc) ? bg : cc);
14513
14514	/* set the fonts to the current one */
14515	setCgsFont(xw, win, gcVTcursNormal, NULL);
14516	setCgsFont(xw, win, gcVTcursFilled, NULL);
14517	setCgsFont(xw, win, gcVTcursReverse, NULL);
14518	setCgsFont(xw, win, gcVTcursOutline, NULL);
14519
14520	/* we have a colored cursor */
14521	setCgsFore(xw, win, gcVTcursNormal, fg);
14522	setCgsBack(xw, win, gcVTcursNormal, xx);
14523
14524	setCgsFore(xw, win, gcVTcursFilled, xx);
14525	setCgsBack(xw, win, gcVTcursFilled, fg);
14526
14527	if (screen->always_highlight) {
14528	    /* both GC's use the same color */
14529	    setCgsFore(xw, win, gcVTcursReverse, bg);
14530	    setCgsBack(xw, win, gcVTcursReverse, cc);
14531	} else {
14532	    setCgsFore(xw, win, gcVTcursReverse, bg);
14533	    setCgsBack(xw, win, gcVTcursReverse, cc);
14534	}
14535	set_cursor_outline_gc(xw, screen->always_highlight, fg, bg, cc);
14536	changed = True;
14537	FreeMarkGCs(xw);
14538    }
14539
14540    if (changed) {
14541	TRACE(("...set_cursor_gcs - done\n"));
14542    }
14543    return changed;
14544}
14545
14546/*
14547 * Build up the default translations string, allowing the user to suppress
14548 * some of the features.
14549 */
14550void
14551VTInitTranslations(void)
14552{
14553    /* *INDENT-OFF* */
14554    static struct {
14555	Boolean wanted;
14556	const char *name;
14557	const char *value;
14558    } table[] = {
14559#define DATA(name,value) { False, name, value }
14560	DATA("select",
14561"\
14562         Shift <KeyPress> Select:select-cursor-start() select-cursor-end(SELECT, CUT_BUFFER0) \n\
14563         Shift <KeyPress> Insert:insert-selection(SELECT, CUT_BUFFER0) \n\
14564"
14565	),
14566#if OPT_MAXIMIZE
14567	DATA("fullscreen",
14568"\
14569                 Alt <Key>Return:fullscreen() \n\
14570"
14571	),
14572#endif
14573#if OPT_SCROLL_LOCK
14574	DATA("scroll-lock",
14575"\
14576        <KeyRelease> Scroll_Lock:scroll-lock() \n\
14577"
14578	),
14579#endif
14580#if OPT_SHIFT_FONTS
14581	DATA("shift-fonts",
14582"\
14583    Shift~Ctrl <KeyPress> KP_Add:larger-vt-font() \n\
14584    Shift Ctrl <KeyPress> KP_Add:smaller-vt-font() \n\
14585    Shift <KeyPress> KP_Subtract:smaller-vt-font() \n\
14586"
14587	),
14588#endif
14589	DATA("paging",
14590"\
14591          Shift <KeyPress> Prior:scroll-back(1,halfpage) \n\
14592           Shift <KeyPress> Next:scroll-forw(1,halfpage) \n\
14593"
14594	),
14595	/* This must be the last set mentioning "KeyPress" */
14596	DATA("keypress",
14597"\
14598                ~Meta <KeyPress>:insert-seven-bit() \n\
14599                 Meta <KeyPress>:insert-eight-bit() \n\
14600"
14601	),
14602	DATA("popup-menu",
14603"\
14604                !Ctrl <Btn1Down>:popup-menu(mainMenu) \n\
14605           !Lock Ctrl <Btn1Down>:popup-menu(mainMenu) \n\
14606 !Lock Ctrl @Num_Lock <Btn1Down>:popup-menu(mainMenu) \n\
14607     ! @Num_Lock Ctrl <Btn1Down>:popup-menu(mainMenu) \n\
14608                !Ctrl <Btn2Down>:popup-menu(vtMenu) \n\
14609           !Lock Ctrl <Btn2Down>:popup-menu(vtMenu) \n\
14610 !Lock Ctrl @Num_Lock <Btn2Down>:popup-menu(vtMenu) \n\
14611     ! @Num_Lock Ctrl <Btn2Down>:popup-menu(vtMenu) \n\
14612                !Ctrl <Btn3Down>:popup-menu(fontMenu) \n\
14613           !Lock Ctrl <Btn3Down>:popup-menu(fontMenu) \n\
14614 !Lock Ctrl @Num_Lock <Btn3Down>:popup-menu(fontMenu) \n\
14615     ! @Num_Lock Ctrl <Btn3Down>:popup-menu(fontMenu) \n\
14616"
14617	),
14618	/* PROCURA added "Meta <Btn2Down>:clear-saved-lines()" */
14619	DATA("reset",
14620"\
14621                 Meta <Btn2Down>:clear-saved-lines() \n\
14622"
14623	),
14624	DATA("select",
14625"\
14626                ~Meta <Btn1Down>:select-start() \n\
14627              ~Meta <Btn1Motion>:select-extend() \n\
14628          ~Ctrl ~Meta <Btn2Down>:ignore() \n\
14629            ~Ctrl ~Meta <Btn2Up>:insert-selection(SELECT, CUT_BUFFER0) \n\
14630          ~Ctrl ~Meta <Btn3Down>:start-extend() \n\
14631              ~Meta <Btn3Motion>:select-extend() \n\
14632                         <BtnUp>:select-end(SELECT, CUT_BUFFER0) \n\
14633"
14634	),
14635#if OPT_BLOCK_SELECT
14636	DATA("block-select",
14637"\
14638                 Meta <Btn1Down>:select-start(block) \n\
14639"
14640	),
14641#endif
14642	DATA("wheel-mouse",
14643"\
14644                 Ctrl <Btn4Down>:scroll-back(1,halfpage,m) \n\
14645            Lock Ctrl <Btn4Down>:scroll-back(1,halfpage,m) \n\
14646  Lock @Num_Lock Ctrl <Btn4Down>:scroll-back(1,halfpage,m) \n\
14647       @Num_Lock Ctrl <Btn4Down>:scroll-back(1,halfpage,m) \n\
14648                      <Btn4Down>:scroll-back(5,line,m)     \n\
14649                 Ctrl <Btn5Down>:scroll-forw(1,halfpage,m) \n\
14650            Lock Ctrl <Btn5Down>:scroll-forw(1,halfpage,m) \n\
14651  Lock @Num_Lock Ctrl <Btn5Down>:scroll-forw(1,halfpage,m) \n\
14652       @Num_Lock Ctrl <Btn5Down>:scroll-forw(1,halfpage,m) \n\
14653                      <Btn5Down>:scroll-forw(5,line,m)     \n\
14654"
14655	),
14656	DATA("pointer",
14657"\
14658                     <BtnMotion>:pointer-motion() \n\
14659                       <BtnDown>:pointer-button() \n\
14660                         <BtnUp>:pointer-button() \n\
14661"
14662	),
14663	DATA("default",
14664"\
14665                         <BtnUp>:ignore() \n\
14666"
14667	)
14668    };
14669#undef DATA
14670    /* *INDENT-ON* */
14671
14672    char *result = NULL;
14673
14674    int pass;
14675    Cardinal item;
14676
14677    TRACE(("VTInitTranslations\n"));
14678    for (item = 0; item < XtNumber(table); ++item) {
14679	table[item].wanted = True;
14680    }
14681#if OPT_MAXIMIZE
14682    /*
14683     * As a special case, allow for disabling the alt-enter translation if
14684     * the resource settings prevent fullscreen from being used.  We would
14685     * do the same for scroll-lock and shift-fonts if they were application
14686     * resources too, rather than in the widget.
14687     */
14688    if (resource.fullscreen == esNever) {
14689	for (item = 0; item < XtNumber(table); ++item) {
14690	    if (!strcmp(table[item].name, "fullscreen")) {
14691		table[item].wanted = False;
14692		TRACE(("omit(%s):\n%s\n", table[item].name, table[item].value));
14693	    }
14694	}
14695    }
14696#endif
14697    if (!IsEmpty(resource.omitTranslation)) {
14698	char *value;
14699	const char *source = resource.omitTranslation;
14700
14701	while (*source != '\0' && (value = ParseList(&source)) != NULL) {
14702	    size_t len = strlen(value);
14703
14704	    TRACE(("parsed:%s\n", value));
14705	    for (item = 0; item < XtNumber(table); ++item) {
14706		if (strlen(table[item].name) >= len
14707		    && x_strncasecmp(table[item].name,
14708				     value,
14709				     (unsigned) len) == 0) {
14710		    table[item].wanted = False;
14711		    TRACE(("omit(%s):\n%s\n", table[item].name, table[item].value));
14712		    /* continue: "select", for instance is two chunks */
14713		}
14714	    }
14715	    free(value);
14716	}
14717    }
14718
14719    for (pass = 0; pass < 2; ++pass) {
14720	size_t needed = 0;
14721	for (item = 0; item < XtNumber(table); ++item) {
14722	    if (table[item].wanted) {
14723		if (pass) {
14724		    strcat(result, table[item].value);
14725		} else {
14726		    needed += strlen(table[item].value) + 1;
14727		}
14728	    }
14729	}
14730	if (!pass) {
14731	    result = XtMalloc((Cardinal) needed);
14732	    *result = '\0';
14733	}
14734    }
14735
14736    TRACE(("result:\n%s\n", result));
14737
14738    defaultTranslations = result;
14739    free((void *) xtermClassRec.core_class.tm_table);
14740    xtermClassRec.core_class.tm_table = result;
14741}
14742
14743#ifdef NO_LEAKS
14744void
14745noleaks_charproc(void)
14746{
14747    free(v_buffer);
14748}
14749#endif
14750