charproc.c revision 4419d26b
1/* $XTermId: charproc.c,v 1.1888 2022/02/22 09:00:26 Vladimir.A.Pavlov Exp $ */
2
3/*
4 * Copyright 1999-2021,2022 by Thomas E. Dickey
5 *
6 *                         All Rights Reserved
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the
10 * "Software"), to deal in the Software without restriction, including
11 * without limitation the rights to use, copy, modify, merge, publish,
12 * distribute, sublicense, and/or sell copies of the Software, and to
13 * permit persons to whom the Software is furnished to do so, subject to
14 * the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
23 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 *
27 * Except as contained in this notice, the name(s) of the above copyright
28 * holders shall not be used in advertising or otherwise to promote the
29 * sale, use or other dealings in this Software without prior written
30 * authorization.
31 *
32 *
33 * Copyright 1988  X Consortium
34 *
35 * Permission to use, copy, modify, distribute, and sell this software and its
36 * documentation for any purpose is hereby granted without fee, provided that
37 * the above copyright notice appear in all copies and that both that
38 * copyright notice and this permission notice appear in supporting
39 * documentation.
40 *
41 * The above copyright notice and this permission notice shall be included in
42 * all copies or substantial portions of the Software.
43 *
44 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
45 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
46 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
47 * OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
48 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
49 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
50 *
51 * Except as contained in this notice, the name of the X Consortium shall not be
52 * used in advertising or otherwise to promote the sale, use or other dealings
53 * in this Software without prior written authorization from the X Consortium.
54 *
55 */
56/*
57 * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
58 *
59 *                         All Rights Reserved
60 *
61 * Permission to use, copy, modify, and distribute this software and its
62 * documentation for any purpose and without fee is hereby granted,
63 * provided that the above copyright notice appear in all copies and that
64 * both that copyright notice and this permission notice appear in
65 * supporting documentation, and that the name of Digital Equipment
66 * Corporation not be used in advertising or publicity pertaining to
67 * distribution of the software without specific, written prior permission.
68 *
69 *
70 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
71 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
72 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
73 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
74 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
75 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
76 * SOFTWARE.
77 */
78
79/* charproc.c */
80
81#include <version.h>
82#include <xterm.h>
83
84#include <X11/Xatom.h>
85#include <X11/Xutil.h>
86#include <X11/Xmu/Atoms.h>
87#include <X11/Xmu/CharSet.h>
88#include <X11/Xmu/Converters.h>
89
90#if OPT_INPUT_METHOD
91
92#if defined(HAVE_LIB_XAW)
93#include <X11/Xaw/XawImP.h>
94#elif defined(HAVE_LIB_XAW3D)
95#include <X11/Xaw3d/XawImP.h>
96#elif defined(HAVE_LIB_XAW3DXFT)
97#include <X11/Xaw3dxft/XawImP.h>
98#elif defined(HAVE_LIB_NEXTAW)
99#include <X11/neXtaw/XawImP.h>
100#elif defined(HAVE_LIB_XAWPLUS)
101#include <X11/XawPlus/XawImP.h>
102#endif
103
104#endif
105
106#if OPT_WIDE_CHARS
107#include <xutf8.h>
108#include <wcwidth.h>
109#include <precompose.h>
110#ifdef HAVE_LANGINFO_CODESET
111#include <langinfo.h>
112#endif
113#endif
114
115#if USE_DOUBLE_BUFFER
116#include <X11/extensions/Xdbe.h>
117#endif
118
119#include <stdio.h>
120#include <ctype.h>
121#include <assert.h>
122
123#if defined(HAVE_SCHED_YIELD)
124#include <sched.h>
125#endif
126
127#include <VTparse.h>
128#include <data.h>
129#include <error.h>
130#include <menu.h>
131#include <main.h>
132#include <fontutils.h>
133#include <charclass.h>
134#include <xstrings.h>
135#include <graphics.h>
136
137#ifdef NO_LEAKS
138#include <xtermcap.h>
139#endif
140
141typedef int (*BitFunc) (unsigned * /* p */ ,
142			unsigned /* mask */ );
143
144static IChar doinput(XtermWidget /* xw */ );
145static int set_character_class(char * /*s */ );
146static void FromAlternate(XtermWidget /* xw */ );
147static void ReallyReset(XtermWidget /* xw */ ,
148			Bool /* full */ ,
149			Bool /* saved */ );
150static void RequestResize(XtermWidget /* xw */ ,
151			  int /* rows */ ,
152			  int /* cols */ ,
153			  Bool /* text */ );
154static void SwitchBufs(XtermWidget /* xw */ ,
155		       int /* toBuf */ ,
156		       Bool /* clearFirst */ );
157static void ToAlternate(XtermWidget /* xw */ ,
158			Bool /* clearFirst */ );
159static void ansi_modes(XtermWidget /* xw */ ,
160		       BitFunc /* func */ );
161static int bitclr(unsigned *p, unsigned mask);
162static int bitcpy(unsigned *p, unsigned q, unsigned mask);
163static int bitset(unsigned *p, unsigned mask);
164static void dpmodes(XtermWidget /* xw */ ,
165		    BitFunc /* func */ );
166static void restoremodes(XtermWidget /* xw */ );
167static void savemodes(XtermWidget /* xw */ );
168static void window_ops(XtermWidget /* xw */ );
169
170#if OPT_BLINK_CURS || OPT_BLINK_TEXT
171#define SettableCursorBlink(screen) \
172	(((screen)->cursor_blink != cbAlways) && \
173	 ((screen)->cursor_blink != cbNever))
174#define UpdateCursorBlink(xw) \
175	 SetCursorBlink(xw, TScreenOf(xw)->cursor_blink)
176static void SetCursorBlink(XtermWidget /* xw */ ,
177			   BlinkOps /* enable */ );
178static void HandleBlinking(XtPointer /* closure */ ,
179			   XtIntervalId * /* id */ );
180static void StartBlinking(XtermWidget /* xw */ );
181static void StopBlinking(XtermWidget /* xw */ );
182#else
183#define StartBlinking(xw)	/* nothing */
184#define StopBlinking(xw)	/* nothing */
185#endif
186
187#ifndef NO_ACTIVE_ICON
188static Boolean discount_frame_extents(XtermWidget /* xw */ ,
189				      int * /* height */ ,
190				      int * /* width */ );
191#else
192#define discount_frame_extents(xw, height, width)	False
193#endif
194
195#if OPT_INPUT_METHOD
196static void PreeditPosition(XtermWidget /* xw */ );
197#endif
198
199#define	DEFAULT		-1
200#define BELLSUPPRESSMSEC 200
201
202static ANSI reply;
203static PARAMS parms;
204
205#define nparam parms.count
206
207#define InitParams()  init_params()
208#define GetParam(n)   parms.params[(n)]
209#define SetParam(n,v) parms.params[(n)] = v
210#define ParamPair(n)  nparam - (n), parms.params + (n)
211
212static jmp_buf vtjmpbuf;
213
214/* event handlers */
215static void HandleBell PROTO_XT_ACTIONS_ARGS;
216static void HandleIgnore PROTO_XT_ACTIONS_ARGS;
217static void HandleKeymapChange PROTO_XT_ACTIONS_ARGS;
218static void HandleVisualBell PROTO_XT_ACTIONS_ARGS;
219#if HANDLE_STRUCT_NOTIFY
220static void HandleStructNotify PROTO_XT_EV_HANDLER_ARGS;
221#endif
222
223/*
224 * NOTE: VTInitialize zeros out the entire ".screen" component of the
225 * XtermWidget, so make sure to add an assignment statement in VTInitialize()
226 * for each new ".screen" field added to this resource list.
227 */
228
229/* Defaults */
230#if OPT_ISO_COLORS
231
232/*
233 * If we default to colorMode enabled, compile-in defaults for the ANSI colors.
234 */
235#if DFT_COLORMODE
236#define DFT_COLOR(name) name
237#else
238#define DFT_COLOR(name) XtDefaultForeground
239#endif
240#endif
241
242static char _Font_Selected_[] = "yes";	/* string is arbitrary */
243
244static const char *defaultTranslations;
245/* *INDENT-OFF* */
246static XtActionsRec actionsList[] = {
247    { "allow-bold-fonts",	HandleAllowBoldFonts },
248    { "allow-send-events",	HandleAllowSends },
249    { "bell",			HandleBell },
250    { "clear-saved-lines",	HandleClearSavedLines },
251    { "copy-selection",		HandleCopySelection },
252    { "create-menu",		HandleCreateMenu },
253    { "delete-is-del",		HandleDeleteIsDEL },
254    { "dired-button",		DiredButton },
255    { "hard-reset",		HandleHardReset },
256    { "ignore",			HandleIgnore },
257    { "insert",			HandleKeyPressed },  /* alias for insert-seven-bit */
258    { "insert-eight-bit",	HandleEightBitKeyPressed },
259    { "insert-selection",	HandleInsertSelection },
260    { "insert-seven-bit",	HandleKeyPressed },
261    { "interpret",		HandleInterpret },
262    { "keymap",			HandleKeymapChange },
263    { "pointer-motion",		HandlePointerMotion },
264    { "pointer-button",		HandlePointerButton },
265    { "popup-menu",		HandlePopupMenu },
266    { "print",			HandlePrintScreen },
267    { "print-everything",	HandlePrintEverything },
268    { "print-redir",		HandlePrintControlMode },
269    { "quit",			HandleQuit },
270    { "redraw",			HandleRedraw },
271    { "scroll-back",		HandleScrollBack },
272    { "scroll-forw",		HandleScrollForward },
273    { "scroll-to",		HandleScrollTo },
274    { "secure",			HandleSecure },
275    { "select-cursor-end",	HandleKeyboardSelectEnd },
276    { "select-cursor-extend",   HandleKeyboardSelectExtend },
277    { "select-cursor-start",	HandleKeyboardSelectStart },
278    { "select-end",		HandleSelectEnd },
279    { "select-extend",		HandleSelectExtend },
280    { "select-set",		HandleSelectSet },
281    { "select-start",		HandleSelectStart },
282    { "send-signal",		HandleSendSignal },
283    { "set-8-bit-control",	Handle8BitControl },
284    { "set-allow132",		HandleAllow132 },
285    { "set-altscreen",		HandleAltScreen },
286    { "set-appcursor",		HandleAppCursor },
287    { "set-appkeypad",		HandleAppKeypad },
288    { "set-autolinefeed",	HandleAutoLineFeed },
289    { "set-autowrap",		HandleAutoWrap },
290    { "set-backarrow",		HandleBackarrow },
291    { "set-bellIsUrgent",	HandleBellIsUrgent },
292    { "set-cursesemul",		HandleCursesEmul },
293    { "set-jumpscroll",		HandleJumpscroll },
294    { "set-keep-clipboard",	HandleKeepClipboard },
295    { "set-keep-selection",	HandleKeepSelection },
296    { "set-marginbell",		HandleMarginBell },
297    { "set-old-function-keys",	HandleOldFunctionKeys },
298    { "set-pop-on-bell",	HandleSetPopOnBell },
299    { "set-reverse-video",	HandleReverseVideo },
300    { "set-reversewrap",	HandleReverseWrap },
301    { "set-scroll-on-key",	HandleScrollKey },
302    { "set-scroll-on-tty-output", HandleScrollTtyOutput },
303    { "set-scrollbar",		HandleScrollbar },
304    { "set-select",		HandleSetSelect },
305    { "set-sun-keyboard",	HandleSunKeyboard },
306    { "set-titeInhibit",	HandleTiteInhibit },
307    { "set-visual-bell",	HandleSetVisualBell },
308    { "set-vt-font",		HandleSetFont },
309    { "soft-reset",		HandleSoftReset },
310    { "start-cursor-extend",	HandleKeyboardStartExtend },
311    { "start-extend",		HandleStartExtend },
312    { "string",			HandleStringEvent },
313    { "vi-button",		ViButton },
314    { "visual-bell",		HandleVisualBell },
315#ifdef ALLOWLOGGING
316    { "set-logging",		HandleLogging },
317#endif
318#if OPT_ALLOW_XXX_OPS
319    { "allow-color-ops",	HandleAllowColorOps },
320    { "allow-font-ops",		HandleAllowFontOps },
321    { "allow-mouse-ops",	HandleAllowMouseOps },
322    { "allow-tcap-ops",		HandleAllowTcapOps },
323    { "allow-title-ops",	HandleAllowTitleOps },
324    { "allow-window-ops",	HandleAllowWindowOps },
325#endif
326#if OPT_BLINK_CURS
327    { "set-cursorblink",	HandleCursorBlink },
328#endif
329#if OPT_BOX_CHARS
330    { "set-font-linedrawing",	HandleFontBoxChars },
331    { "set-font-packed",	HandleFontPacked },
332#endif
333#if OPT_DABBREV
334    { "dabbrev-expand",		HandleDabbrevExpand },
335#endif
336#if OPT_DEC_CHRSET
337    { "set-font-doublesize",	HandleFontDoublesize },
338#endif
339#if OPT_DEC_SOFTFONT
340    { "set-font-loading",	HandleFontLoading },
341#endif
342#if OPT_EXEC_XTERM
343    { "spawn-new-terminal",	HandleSpawnTerminal },
344#endif
345#if OPT_GRAPHICS
346    { "set-private-colors",	HandleSetPrivateColorRegisters },
347#endif
348#if OPT_HP_FUNC_KEYS
349    { "set-hp-function-keys",	HandleHpFunctionKeys },
350#endif
351#if OPT_LOAD_VTFONTS
352    { "load-vt-fonts",		HandleLoadVTFonts },
353#endif
354#if OPT_MAXIMIZE
355    { "deiconify",		HandleDeIconify },
356    { "fullscreen",		HandleFullscreen },
357    { "iconify",		HandleIconify },
358    { "maximize",		HandleMaximize },
359    { "restore",		HandleRestoreSize },
360#endif
361#if OPT_NUM_LOCK
362    { "alt-sends-escape",	HandleAltEsc },
363    { "meta-sends-escape",	HandleMetaEsc },
364    { "set-num-lock",		HandleNumLock },
365#endif
366#ifdef OPT_PRINT_ON_EXIT
367    { "print-immediate",	HandlePrintImmediate },
368    { "print-on-error",		HandlePrintOnError },
369#endif
370#if OPT_READLINE
371    { "readline-button",	ReadLineButton },
372#endif
373#if OPT_RENDERFONT
374    { "set-render-font",	HandleRenderFont },
375#endif
376#if OPT_SCO_FUNC_KEYS
377    { "set-sco-function-keys",	HandleScoFunctionKeys },
378#endif
379#if OPT_SCREEN_DUMPS
380    { "dump-html",	        HandleDumpHtml },
381    { "dump-svg",	        HandleDumpSvg },
382#endif
383#if OPT_SCROLL_LOCK
384    { "scroll-lock",		HandleScrollLock },
385#endif
386#if OPT_SELECTION_OPS
387    { "exec-formatted",		HandleExecFormatted },
388    { "exec-selectable",	HandleExecSelectable },
389    { "insert-formatted",	HandleInsertFormatted },
390    { "insert-selectable",	HandleInsertSelectable },
391#endif
392#if OPT_SHIFT_FONTS
393    { "larger-vt-font",		HandleLargerFont },
394    { "smaller-vt-font",	HandleSmallerFont },
395#endif
396#if OPT_SIXEL_GRAPHICS
397    { "set-sixel-scrolling",	HandleSixelScrolling },
398#endif
399#if OPT_SUN_FUNC_KEYS
400    { "set-sun-function-keys",	HandleSunFunctionKeys },
401#endif
402#if OPT_TEK4014
403    { "set-terminal-type",	HandleSetTerminalType },
404    { "set-visibility",		HandleVisibility },
405    { "set-tek-text",		HandleSetTekText },
406    { "tek-page",		HandleTekPage },
407    { "tek-reset",		HandleTekReset },
408    { "tek-copy",		HandleTekCopy },
409#endif
410#if OPT_TOOLBAR
411    { "set-toolbar",		HandleToolbar },
412#endif
413#if OPT_WIDE_CHARS
414    { "set-utf8-mode",		HandleUTF8Mode },
415    { "set-utf8-fonts",		HandleUTF8Fonts },
416    { "set-utf8-title",		HandleUTF8Title },
417#endif
418};
419/* *INDENT-ON* */
420
421#define SPS screen.printer_state
422
423static XtResource xterm_resources[] =
424{
425    Bres(XtNallowPasteControls, XtCAllowPasteControls,
426	 screen.allowPasteControl0, False),
427    Bres(XtNallowSendEvents, XtCAllowSendEvents, screen.allowSendEvent0, False),
428    Bres(XtNallowColorOps, XtCAllowColorOps, screen.allowColorOp0, DEF_ALLOW_COLOR),
429    Bres(XtNallowFontOps, XtCAllowFontOps, screen.allowFontOp0, DEF_ALLOW_FONT),
430    Bres(XtNallowMouseOps, XtCAllowMouseOps, screen.allowMouseOp0, DEF_ALLOW_MOUSE),
431    Bres(XtNallowTcapOps, XtCAllowTcapOps, screen.allowTcapOp0, DEF_ALLOW_TCAP),
432    Bres(XtNallowTitleOps, XtCAllowTitleOps, screen.allowTitleOp0, DEF_ALLOW_TITLE),
433    Bres(XtNallowWindowOps, XtCAllowWindowOps, screen.allowWindowOp0, DEF_ALLOW_WINDOW),
434    Bres(XtNaltIsNotMeta, XtCAltIsNotMeta, screen.alt_is_not_meta, False),
435    Bres(XtNaltSendsEscape, XtCAltSendsEscape, screen.alt_sends_esc, DEF_ALT_SENDS_ESC),
436    Bres(XtNallowBoldFonts, XtCAllowBoldFonts, screen.allowBoldFonts, True),
437    Bres(XtNalwaysBoldMode, XtCAlwaysBoldMode, screen.always_bold_mode, False),
438    Bres(XtNalwaysHighlight, XtCAlwaysHighlight, screen.always_highlight, False),
439    Bres(XtNappcursorDefault, XtCAppcursorDefault, misc.appcursorDefault, False),
440    Bres(XtNappkeypadDefault, XtCAppkeypadDefault, misc.appkeypadDefault, False),
441    Bres(XtNalternateScroll, XtCScrollCond, screen.alternateScroll, False),
442    Bres(XtNautoWrap, XtCAutoWrap, misc.autoWrap, True),
443    Bres(XtNawaitInput, XtCAwaitInput, screen.awaitInput, False),
444    Bres(XtNfreeBoldBox, XtCFreeBoldBox, screen.free_bold_box, False),
445    Bres(XtNbackarrowKey, XtCBackarrowKey, screen.backarrow_key, DEF_BACKARO_BS),
446    Bres(XtNbellIsUrgent, XtCBellIsUrgent, screen.bellIsUrgent, False),
447    Bres(XtNbellOnReset, XtCBellOnReset, screen.bellOnReset, True),
448    Bres(XtNboldMode, XtCBoldMode, screen.bold_mode, True),
449    Bres(XtNbrokenSelections, XtCBrokenSelections, screen.brokenSelections, False),
450    Bres(XtNc132, XtCC132, screen.c132, False),
451    Sres(XtNcdXtraScroll, XtCCdXtraScroll, misc.cdXtraScroll_s, DEF_CD_XTRA_SCROLL),
452    Bres(XtNcolorInnerBorder, XtCColorInnerBorder, misc.color_inner_border, False),
453    Bres(XtNcurses, XtCCurses, screen.curses, False),
454    Bres(XtNcutNewline, XtCCutNewline, screen.cutNewline, True),
455    Bres(XtNcutToBeginningOfLine, XtCCutToBeginningOfLine,
456	 screen.cutToBeginningOfLine, True),
457    Bres(XtNdeleteIsDEL, XtCDeleteIsDEL, screen.delete_is_del, DEFDELETE_DEL),
458    Bres(XtNdynamicColors, XtCDynamicColors, misc.dynamicColors, True),
459    Bres(XtNeightBitControl, XtCEightBitControl, screen.control_eight_bits, False),
460    Bres(XtNeightBitInput, XtCEightBitInput, screen.input_eight_bits, True),
461    Bres(XtNeightBitOutput, XtCEightBitOutput, screen.output_eight_bits, True),
462    Bres(XtNeraseSavedLines, XtCEraseSavedLines, screen.eraseSavedLines0, True),
463    Bres(XtNhighlightSelection, XtCHighlightSelection,
464	 screen.highlight_selection, False),
465    Bres(XtNshowWrapMarks, XtCShowWrapMarks, screen.show_wrap_marks, False),
466    Bres(XtNhpLowerleftBugCompat, XtCHpLowerleftBugCompat, screen.hp_ll_bc, False),
467    Bres(XtNi18nSelections, XtCI18nSelections, screen.i18nSelections, True),
468    Bres(XtNfastScroll, XtCFastScroll, screen.fastscroll, False),
469    Bres(XtNjumpScroll, XtCJumpScroll, screen.jumpscroll, True),
470    Bres(XtNkeepClipboard, XtCKeepClipboard, screen.keepClipboard, False),
471    Bres(XtNkeepSelection, XtCKeepSelection, screen.keepSelection, True),
472    Bres(XtNloginShell, XtCLoginShell, misc.login_shell, False),
473    Bres(XtNmarginBell, XtCMarginBell, screen.marginbell, False),
474    Bres(XtNmetaSendsEscape, XtCMetaSendsEscape, screen.meta_sends_esc, DEF_META_SENDS_ESC),
475    Bres(XtNmultiScroll, XtCMultiScroll, screen.multiscroll, False),
476    Bres(XtNoldXtermFKeys, XtCOldXtermFKeys, screen.old_fkeys, False),
477    Bres(XtNpopOnBell, XtCPopOnBell, screen.poponbell, False),
478    Bres(XtNprinterAutoClose, XtCPrinterAutoClose, SPS.printer_autoclose, False),
479    Bres(XtNprinterExtent, XtCPrinterExtent, SPS.printer_extent, False),
480    Bres(XtNprinterFormFeed, XtCPrinterFormFeed, SPS.printer_formfeed, False),
481    Bres(XtNprinterNewLine, XtCPrinterNewLine, SPS.printer_newline, True),
482    Bres(XtNquietGrab, XtCQuietGrab, screen.quiet_grab, False),
483    Bres(XtNresizeByPixel, XtCResizeByPixel, misc.resizeByPixel, False),
484    Bres(XtNreverseVideo, XtCReverseVideo, misc.re_verse, False),
485    Bres(XtNreverseWrap, XtCReverseWrap, misc.reverseWrap, False),
486    Bres(XtNscrollBar, XtCScrollBar, misc.scrollbar, False),
487    Bres(XtNscrollKey, XtCScrollCond, screen.scrollkey, False),
488    Bres(XtNscrollTtyOutput, XtCScrollCond, screen.scrollttyoutput, True),
489    Bres(XtNselectToClipboard, XtCSelectToClipboard,
490	 screen.selectToClipboard, False),
491    Bres(XtNsignalInhibit, XtCSignalInhibit, misc.signalInhibit, False),
492    Bres(XtNtiteInhibit, XtCTiteInhibit, misc.titeInhibit, False),
493    Sres(XtNtiXtraScroll, XtCTiXtraScroll, misc.tiXtraScroll_s, DEF_TI_XTRA_SCROLL),
494    Bres(XtNtrimSelection, XtCTrimSelection, screen.trim_selection, False),
495    Bres(XtNunderLine, XtCUnderLine, screen.underline, True),
496    Bres(XtNvisualBell, XtCVisualBell, screen.visualbell, False),
497    Bres(XtNvisualBellLine, XtCVisualBellLine, screen.flash_line, False),
498
499    Dres(XtNscaleHeight, XtCScaleHeight, screen.scale_height, "1.0"),
500
501    Ires(XtNbellSuppressTime, XtCBellSuppressTime, screen.bellSuppressTime, BELLSUPPRESSMSEC),
502    Ires(XtNfontWarnings, XtCFontWarnings, misc.fontWarnings, fwResource),
503    Ires(XtNinternalBorder, XtCBorderWidth, screen.border, DEFBORDER),
504    Ires(XtNlimitResize, XtCLimitResize, misc.limit_resize, 1),
505    Ires(XtNlimitResponse, XtCLimitResponse, screen.unparse_max, DEF_LIMIT_RESPONSE),
506    Ires(XtNmultiClickTime, XtCMultiClickTime, screen.multiClickTime, MULTICLICKTIME),
507    Ires(XtNnMarginBell, XtCColumn, screen.nmarginbell, N_MARGINBELL),
508    Ires(XtNpointerMode, XtCPointerMode, screen.pointer_mode, DEF_POINTER_MODE),
509    Ires(XtNprinterControlMode, XtCPrinterControlMode,
510	 SPS.printer_controlmode, 0),
511    Ires(XtNtitleModes, XtCTitleModes, screen.title_modes, DEF_TITLE_MODES),
512    Ires(XtNnextEventDelay, XtCNextEventDelay, screen.nextEventDelay, 1),
513    Ires(XtNvisualBellDelay, XtCVisualBellDelay, screen.visualBellDelay, 100),
514    Ires(XtNsaveLines, XtCSaveLines, screen.savelines, DEF_SAVE_LINES),
515    Ires(XtNscrollBarBorder, XtCScrollBarBorder, screen.scrollBarBorder, 1),
516    Ires(XtNscrollLines, XtCScrollLines, screen.scrolllines, DEF_SCROLL_LINES),
517
518    Sres(XtNinitialFont, XtCInitialFont, screen.initial_font, NULL),
519    Sres(XtNfont1, XtCFont1, screen.MenuFontName(fontMenu_font1), NULL),
520    Sres(XtNfont2, XtCFont2, screen.MenuFontName(fontMenu_font2), NULL),
521    Sres(XtNfont3, XtCFont3, screen.MenuFontName(fontMenu_font3), NULL),
522    Sres(XtNfont4, XtCFont4, screen.MenuFontName(fontMenu_font4), NULL),
523    Sres(XtNfont5, XtCFont5, screen.MenuFontName(fontMenu_font5), NULL),
524    Sres(XtNfont6, XtCFont6, screen.MenuFontName(fontMenu_font6), NULL),
525    Sres(XtNfont7, XtCFont7, screen.MenuFontName(fontMenu_font7), NULL),
526
527    Sres(XtNanswerbackString, XtCAnswerbackString, screen.answer_back, ""),
528    Sres(XtNboldFont, XtCBoldFont, misc.default_font.f_b, DEFBOLDFONT),
529    Sres(XtNcharClass, XtCCharClass, screen.charClass, NULL),
530    Sres(XtNdecTerminalID, XtCDecTerminalID, screen.term_id, DFT_DECID),
531    Sres(XtNdefaultString, XtCDefaultString, screen.default_string, "#"),
532    Sres(XtNdisallowedColorOps, XtCDisallowedColorOps,
533	 screen.disallowedColorOps, DEF_DISALLOWED_COLOR),
534    Sres(XtNdisallowedFontOps, XtCDisallowedFontOps,
535	 screen.disallowedFontOps, DEF_DISALLOWED_FONT),
536    Sres(XtNdisallowedMouseOps, XtCDisallowedMouseOps,
537	 screen.disallowedMouseOps, DEF_DISALLOWED_MOUSE),
538    Sres(XtNdisallowedPasteControls, XtCDisallowedPasteControls,
539	 screen.disallowedPasteControls, DEF_DISALLOWED_PASTE_CONTROLS),
540    Sres(XtNdisallowedTcapOps, XtCDisallowedTcapOps,
541	 screen.disallowedTcapOps, DEF_DISALLOWED_TCAP),
542    Sres(XtNdisallowedWindowOps, XtCDisallowedWindowOps,
543	 screen.disallowedWinOps, DEF_DISALLOWED_WINDOW),
544    Sres(XtNeightBitMeta, XtCEightBitMeta, screen.eight_bit_meta_s, DEF_8BIT_META),
545    Sres(XtNeightBitSelectTypes, XtCEightBitSelectTypes,
546	 screen.eightbit_select_types, NULL),
547    Sres(XtNfont, XtCFont, misc.default_font.f_n, DEFFONT),
548    Sres(XtNgeometry, XtCGeometry, misc.geo_metry, NULL),
549    Sres(XtNkeyboardDialect, XtCKeyboardDialect, screen.keyboard_dialect, DFT_KBD_DIALECT),
550    Sres(XtNprinterCommand, XtCPrinterCommand, SPS.printer_command, ""),
551    Sres(XtNtekGeometry, XtCGeometry, misc.T_geometry, NULL),
552    Sres(XtNpointerFont, XtCPointerFont, screen.cursor_font_name, NULL),
553
554    Tres(XtNcursorColor, XtCCursorColor, TEXT_CURSOR, XtDefaultForeground),
555    Tres(XtNforeground, XtCForeground, TEXT_FG, XtDefaultForeground),
556    Tres(XtNpointerColor, XtCPointerColor, MOUSE_FG, XtDefaultForeground),
557    Tres(XtNbackground, XtCBackground, TEXT_BG, XtDefaultBackground),
558    Tres(XtNpointerColorBackground, XtCBackground, MOUSE_BG, XtDefaultBackground),
559
560    {XtNresizeGravity, XtCResizeGravity, XtRGravity, sizeof(XtGravity),
561     XtOffsetOf(XtermWidgetRec, misc.resizeGravity),
562     XtRImmediate, (XtPointer) SouthWestGravity},
563
564    Sres(XtNpointerShape, XtCCursor, screen.pointer_shape, "xterm"),
565
566#ifdef ALLOWLOGGING
567    Bres(XtNlogInhibit, XtCLogInhibit, misc.logInhibit, False),
568    Bres(XtNlogging, XtCLogging, misc.log_on, False),
569    Sres(XtNlogFile, XtCLogfile, screen.logfile, NULL),
570#endif
571
572#ifndef NO_ACTIVE_ICON
573    Sres("activeIcon", "ActiveIcon", misc.active_icon_s, "default"),
574    Ires("iconBorderWidth", XtCBorderWidth, misc.icon_border_width, 2),
575    Sres("iconFont", "IconFont", screen.icon_fontname, "nil2"),
576    Cres("iconBorderColor", XtCBorderColor, misc.icon_border_pixel, XtDefaultBackground),
577#endif				/* NO_ACTIVE_ICON */
578
579#if OPT_BLINK_CURS
580    Bres(XtNcursorBlinkXOR, XtCCursorBlinkXOR, screen.cursor_blink_xor, True),
581    Sres(XtNcursorBlink, XtCCursorBlink, screen.cursor_blink_s, "false"),
582#endif
583    Bres(XtNcursorUnderLine, XtCCursorUnderLine, screen.cursor_underline, False),
584
585#if OPT_BLINK_TEXT
586    Bres(XtNshowBlinkAsBold, XtCCursorBlink, screen.blink_as_bold, DEFBLINKASBOLD),
587#endif
588
589#if OPT_BLINK_CURS || OPT_BLINK_TEXT
590    Ires(XtNcursorOnTime, XtCCursorOnTime, screen.blink_on, 600),
591    Ires(XtNcursorOffTime, XtCCursorOffTime, screen.blink_off, 300),
592#endif
593
594#if OPT_BOX_CHARS
595    Bres(XtNforceBoxChars, XtCForceBoxChars, screen.force_box_chars, False),
596    Bres(XtNforcePackedFont, XtCForcePackedFont, screen.force_packed, True),
597    Bres(XtNshowMissingGlyphs, XtCShowMissingGlyphs, screen.force_all_chars, False),
598    Bres(XtNassumeAllChars, XtCAssumeAllChars, screen.assume_all_chars, True),
599#endif
600
601#if OPT_BROKEN_OSC
602    Bres(XtNbrokenLinuxOSC, XtCBrokenLinuxOSC, screen.brokenLinuxOSC, True),
603#endif
604
605#if OPT_BROKEN_ST
606    Bres(XtNbrokenStringTerm, XtCBrokenStringTerm, screen.brokenStringTerm, False),
607#endif
608
609#if OPT_C1_PRINT
610    Bres(XtNallowC1Printable, XtCAllowC1Printable, screen.c1_printable, False),
611#endif
612
613#if OPT_CLIP_BOLD
614    Bres(XtNuseClipping, XtCUseClipping, screen.use_clipping, True),
615    Bres(XtNuseBorderClipping, XtCUseBorderClipping,
616	 screen.use_border_clipping, False),
617#endif
618
619#if OPT_DEC_CHRSET
620    Bres(XtNfontDoublesize, XtCFontDoublesize, screen.font_doublesize, True),
621    Ires(XtNcacheDoublesize, XtCCacheDoublesize, screen.cache_doublesize, NUM_CHRSET),
622#endif
623
624#if OPT_DEC_RECTOPS
625    Ires(XtNchecksumExtension, XtCChecksumExtension, screen.checksum_ext0, csDEC),
626#endif
627
628#if OPT_HIGHLIGHT_COLOR
629    Tres(XtNhighlightColor, XtCHighlightColor, HIGHLIGHT_BG, XtDefaultForeground),
630    Tres(XtNhighlightTextColor, XtCHighlightTextColor, HIGHLIGHT_FG, XtDefaultBackground),
631    Bres(XtNhighlightReverse, XtCHighlightReverse, screen.hilite_reverse, True),
632    Bres(XtNhighlightColorMode, XtCHighlightColorMode, screen.hilite_color, Maybe),
633#endif				/* OPT_HIGHLIGHT_COLOR */
634
635#if OPT_INPUT_METHOD
636    Bres(XtNopenIm, XtCOpenIm, misc.open_im, True),
637    Sres(XtNinputMethod, XtCInputMethod, misc.input_method, NULL),
638    Sres(XtNpreeditType, XtCPreeditType, misc.preedit_type,
639	 "OverTheSpot,Root"),
640    Ires(XtNretryInputMethod, XtCRetryInputMethod, misc.retry_im, 3),
641#endif
642
643#if OPT_ISO_COLORS
644    Bres(XtNboldColors, XtCColorMode, screen.boldColors, True),
645    Ires(XtNveryBoldColors, XtCVeryBoldColors, screen.veryBoldColors, 0),
646    Bres(XtNcolorMode, XtCColorMode, screen.colorMode, DFT_COLORMODE),
647
648    Bres(XtNcolorAttrMode, XtCColorAttrMode, screen.colorAttrMode, False),
649    Bres(XtNcolorBDMode, XtCColorAttrMode, screen.colorBDMode, False),
650    Bres(XtNcolorBLMode, XtCColorAttrMode, screen.colorBLMode, False),
651    Bres(XtNcolorRVMode, XtCColorAttrMode, screen.colorRVMode, False),
652    Bres(XtNcolorULMode, XtCColorAttrMode, screen.colorULMode, False),
653    Bres(XtNitalicULMode, XtCColorAttrMode, screen.italicULMode, False),
654#if OPT_WIDE_ATTRS
655    Bres(XtNcolorITMode, XtCColorAttrMode, screen.colorITMode, False),
656#endif
657#if OPT_DIRECT_COLOR
658    Bres(XtNdirectColor, XtCDirectColor, screen.direct_color, True),
659#endif
660
661    COLOR_RES("0", screen.Acolors[COLOR_0], DFT_COLOR("black")),
662    COLOR_RES("1", screen.Acolors[COLOR_1], DFT_COLOR("red3")),
663    COLOR_RES("2", screen.Acolors[COLOR_2], DFT_COLOR("green3")),
664    COLOR_RES("3", screen.Acolors[COLOR_3], DFT_COLOR("yellow3")),
665    COLOR_RES("4", screen.Acolors[COLOR_4], DFT_COLOR(DEF_COLOR4)),
666    COLOR_RES("5", screen.Acolors[COLOR_5], DFT_COLOR("magenta3")),
667    COLOR_RES("6", screen.Acolors[COLOR_6], DFT_COLOR("cyan3")),
668    COLOR_RES("7", screen.Acolors[COLOR_7], DFT_COLOR("gray90")),
669    COLOR_RES("8", screen.Acolors[COLOR_8], DFT_COLOR("gray50")),
670    COLOR_RES("9", screen.Acolors[COLOR_9], DFT_COLOR("red")),
671    COLOR_RES("10", screen.Acolors[COLOR_10], DFT_COLOR("green")),
672    COLOR_RES("11", screen.Acolors[COLOR_11], DFT_COLOR("yellow")),
673    COLOR_RES("12", screen.Acolors[COLOR_12], DFT_COLOR(DEF_COLOR12)),
674    COLOR_RES("13", screen.Acolors[COLOR_13], DFT_COLOR("magenta")),
675    COLOR_RES("14", screen.Acolors[COLOR_14], DFT_COLOR("cyan")),
676    COLOR_RES("15", screen.Acolors[COLOR_15], DFT_COLOR("white")),
677    COLOR_RES("BD", screen.Acolors[COLOR_BD], DFT_COLOR(XtDefaultForeground)),
678    COLOR_RES("BL", screen.Acolors[COLOR_BL], DFT_COLOR(XtDefaultForeground)),
679    COLOR_RES("UL", screen.Acolors[COLOR_UL], DFT_COLOR(XtDefaultForeground)),
680    COLOR_RES("RV", screen.Acolors[COLOR_RV], DFT_COLOR(XtDefaultForeground)),
681
682#if OPT_WIDE_ATTRS
683    COLOR_RES("IT", screen.Acolors[COLOR_IT], DFT_COLOR(XtDefaultForeground)),
684#endif
685
686#endif				/* OPT_ISO_COLORS */
687
688    CLICK_RES("2", screen.onClick[1], "word"),
689    CLICK_RES("3", screen.onClick[2], "line"),
690    CLICK_RES("4", screen.onClick[3], 0),
691    CLICK_RES("5", screen.onClick[4], 0),
692
693    Sres(XtNshiftEscape, XtCShiftEscape, keyboard.shift_escape_s, "false"),
694
695#if OPT_MOD_FKEYS
696    Ires(XtNmodifyKeyboard, XtCModifyKeyboard,
697	 keyboard.modify_1st.allow_keys, 0),
698    Ires(XtNmodifyCursorKeys, XtCModifyCursorKeys,
699	 keyboard.modify_1st.cursor_keys, 2),
700    Ires(XtNmodifyFunctionKeys, XtCModifyFunctionKeys,
701	 keyboard.modify_1st.function_keys, 2),
702    Ires(XtNmodifyKeypadKeys, XtCModifyKeypadKeys,
703	 keyboard.modify_1st.keypad_keys, 0),
704    Ires(XtNmodifyOtherKeys, XtCModifyOtherKeys,
705	 keyboard.modify_1st.other_keys, 0),
706    Ires(XtNmodifyStringKeys, XtCModifyStringKeys,
707	 keyboard.modify_1st.string_keys, 0),
708    Ires(XtNformatOtherKeys, XtCFormatOtherKeys,
709	 keyboard.format_keys, 0),
710#endif
711
712#if OPT_NUM_LOCK
713    Bres(XtNalwaysUseMods, XtCAlwaysUseMods, misc.alwaysUseMods, False),
714    Bres(XtNnumLock, XtCNumLock, misc.real_NumLock, True),
715#endif
716
717#if OPT_PRINT_COLORS
718    Ires(XtNprintAttributes, XtCPrintAttributes, SPS.print_attributes, 1),
719#endif
720
721#if OPT_REGIS_GRAPHICS
722    Sres(XtNregisDefaultFont, XtCRegisDefaultFont,
723	 screen.graphics_regis_default_font, ""),
724    Sres(XtNregisScreenSize, XtCRegisScreenSize,
725	 screen.graphics_regis_screensize, "auto"),
726#endif
727
728#if OPT_GRAPHICS
729    Sres(XtNdecGraphicsID, XtCDecGraphicsID, screen.graph_termid, DFT_DECID),
730    Sres(XtNmaxGraphicSize, XtCMaxGraphicSize, screen.graphics_max_size,
731	 "1000x1000"),
732#endif
733
734#if OPT_SHIFT_FONTS
735    Bres(XtNshiftFonts, XtCShiftFonts, misc.shift_fonts, True),
736#endif
737
738#if OPT_SIXEL_GRAPHICS
739    Bres(XtNsixelScrolling, XtCSixelScrolling, screen.sixel_scrolling, False),
740    Bres(XtNsixelScrollsRight, XtCSixelScrollsRight,
741	 screen.sixel_scrolls_right, False),
742#endif
743
744#if OPT_GRAPHICS
745    Ires(XtNnumColorRegisters, XtCNumColorRegisters,
746	 screen.numcolorregisters, 0),
747    Bres(XtNprivateColorRegisters, XtCPrivateColorRegisters,
748	 screen.privatecolorregisters, True),
749#endif
750
751#if OPT_STATUS_LINE
752    Sres(XtNindicatorFormat, XtCIndicatorFormat, screen.status_fmt, DEF_SL_FORMAT),
753#endif
754
755#if OPT_SUNPC_KBD
756    Ires(XtNctrlFKeys, XtCCtrlFKeys, misc.ctrl_fkeys, 10),
757#endif
758
759#if OPT_TEK4014
760    Bres(XtNtekInhibit, XtCTekInhibit, misc.tekInhibit, False),
761    Bres(XtNtekSmall, XtCTekSmall, misc.tekSmall, False),
762    Bres(XtNtekStartup, XtCTekStartup, misc.TekEmu, False),
763#endif
764
765#if OPT_TOOLBAR
766    Wres(XtNmenuBar, XtCMenuBar, VT100_TB_INFO(menu_bar), 0),
767    Ires(XtNmenuHeight, XtCMenuHeight, VT100_TB_INFO(menu_height), 25),
768#endif
769
770#if OPT_WIDE_CHARS
771    Bres(XtNcjkWidth, XtCCjkWidth, misc.cjk_width, False),
772    Bres(XtNmkWidth, XtCMkWidth, misc.mk_width, False),
773    Bres(XtNprecompose, XtCPrecompose, screen.normalized_c, True),
774    Bres(XtNutf8Latin1, XtCUtf8Latin1, screen.utf8_latin1, False),
775    Bres(XtNutf8Weblike, XtCUtf8Weblike, screen.utf8_weblike, False),
776    Bres(XtNvt100Graphics, XtCVT100Graphics, screen.vt100_graphics, True),
777    Bres(XtNwideChars, XtCWideChars, screen.wide_chars, False),
778    Ires(XtNcombiningChars, XtCCombiningChars, screen.max_combining, 2),
779    Ires(XtNmkSamplePass, XtCMkSamplePass, misc.mk_samplepass, 655),
780    Ires(XtNmkSampleSize, XtCMkSampleSize, misc.mk_samplesize, 65536),
781    Sres(XtNutf8, XtCUtf8, screen.utf8_mode_s, "default"),
782    Sres(XtNutf8Fonts, XtCUtf8Fonts, screen.utf8_fonts_s, "default"),
783    Sres(XtNutf8Title, XtCUtf8Title, screen.utf8_title_s, "default"),
784    Sres(XtNwideBoldFont, XtCWideBoldFont, misc.default_font.f_wb, DEFWIDEBOLDFONT),
785    Sres(XtNwideFont, XtCWideFont, misc.default_font.f_w, DEFWIDEFONT),
786    Sres(XtNutf8SelectTypes, XtCUtf8SelectTypes, screen.utf8_select_types, NULL),
787#endif
788
789#if OPT_LUIT_PROG
790    Sres(XtNlocale, XtCLocale, misc.locale_str, "medium"),
791    Sres(XtNlocaleFilter, XtCLocaleFilter, misc.localefilter, DEFLOCALEFILTER),
792#endif
793
794#if OPT_INPUT_METHOD
795    Sres(XtNximFont, XtCXimFont, misc.f_x, DEFXIMFONT),
796#endif
797
798#if OPT_SCROLL_LOCK
799    Bres(XtNallowScrollLock, XtCAllowScrollLock, screen.allowScrollLock0, False),
800    Bres(XtNautoScrollLock, XtCAutoScrollLock, screen.autoScrollLock, False),
801#endif
802
803    /* these are used only for testing ncurses, not in the manual page */
804#if OPT_XMC_GLITCH
805    Bres(XtNxmcInline, XtCXmcInline, screen.xmc_inline, False),
806    Bres(XtNxmcMoveSGR, XtCXmcMoveSGR, screen.move_sgr_ok, True),
807    Ires(XtNxmcAttributes, XtCXmcAttributes, screen.xmc_attributes, 1),
808    Ires(XtNxmcGlitch, XtCXmcGlitch, screen.xmc_glitch, 0),
809#endif
810
811#ifdef SCROLLBAR_RIGHT
812    Bres(XtNrightScrollBar, XtCRightScrollBar, misc.useRight, False),
813#endif
814
815#if OPT_RENDERFONT
816    Bres(XtNforceXftHeight, XtCForceXftHeight, screen.force_xft_height, False),
817#define RES_FACESIZE(n) Dres(XtNfaceSize #n, XtCFaceSize #n, misc.face_size[n], "0.0")
818    RES_FACESIZE(1),
819    RES_FACESIZE(2),
820    RES_FACESIZE(3),
821    RES_FACESIZE(4),
822    RES_FACESIZE(5),
823    RES_FACESIZE(6),
824    RES_FACESIZE(7),
825    Dres(XtNfaceSize, XtCFaceSize, misc.face_size[0], DEFFACESIZE),
826    Sres(XtNfaceName, XtCFaceName, misc.default_xft.f_n, DEFFACENAME),
827    Sres(XtNrenderFont, XtCRenderFont, misc.render_font_s, "default"),
828    Ires(XtNlimitFontsets, XtCLimitFontsets, misc.limit_fontsets, DEF_XFT_CACHE),
829#if OPT_RENDERWIDE
830    Sres(XtNfaceNameDoublesize, XtCFaceNameDoublesize, misc.default_xft.f_w, DEFFACENAME),
831#endif
832#endif
833};
834
835static Boolean VTSetValues(Widget cur, Widget request, Widget new_arg,
836			   ArgList args, Cardinal *num_args);
837static void VTClassInit(void);
838static void VTDestroy(Widget w);
839static void VTExpose(Widget w, XEvent *event, Region region);
840static void VTInitialize(Widget wrequest, Widget new_arg, ArgList args,
841			 Cardinal *num_args);
842static void VTRealize(Widget w, XtValueMask * valuemask,
843		      XSetWindowAttributes * values);
844static void VTResize(Widget w);
845
846#if OPT_INPUT_METHOD
847static void VTInitI18N(XtermWidget);
848#endif
849
850#ifdef VMS
851globaldef {
852    "xtermclassrec"
853} noshare
854
855#else
856static
857#endif				/* VMS */
858WidgetClassRec xtermClassRec =
859{
860    {
861	/* core_class fields */
862	(WidgetClass) & widgetClassRec,		/* superclass   */
863	"VT100",		/* class_name                   */
864	sizeof(XtermWidgetRec),	/* widget_size                  */
865	VTClassInit,		/* class_initialize             */
866	NULL,			/* class_part_initialize        */
867	False,			/* class_inited                 */
868	VTInitialize,		/* initialize                   */
869	NULL,			/* initialize_hook              */
870	VTRealize,		/* realize                      */
871	actionsList,		/* actions                      */
872	XtNumber(actionsList),	/* num_actions                  */
873	xterm_resources,	/* resources                    */
874	XtNumber(xterm_resources),	/* num_resources        */
875	NULLQUARK,		/* xrm_class                    */
876	True,			/* compress_motion              */
877	False,			/* compress_exposure            */
878	True,			/* compress_enterleave          */
879	False,			/* visible_interest             */
880	VTDestroy,		/* destroy                      */
881	VTResize,		/* resize                       */
882	VTExpose,		/* expose                       */
883	VTSetValues,		/* set_values                   */
884	NULL,			/* set_values_hook              */
885	XtInheritSetValuesAlmost,	/* set_values_almost    */
886	NULL,			/* get_values_hook              */
887	NULL,			/* accept_focus                 */
888	XtVersion,		/* version                      */
889	NULL,			/* callback_offsets             */
890	0,			/* tm_table                     */
891	XtInheritQueryGeometry,	/* query_geometry               */
892	XtInheritDisplayAccelerator,	/* display_accelerator  */
893	NULL			/* extension                    */
894    }
895};
896
897#ifdef VMS
898globaldef {
899    "xtermwidgetclass"
900}
901noshare
902#endif /* VMS */
903WidgetClass xtermWidgetClass = (WidgetClass) & xtermClassRec;
904
905/*
906 * Add input-actions for widgets that are overlooked (scrollbar and toolbar):
907 *
908 *	a) Sometimes the scrollbar passes through translations, sometimes it
909 *	   doesn't.  We add the KeyPress translations here, just to be sure.
910 *	b) In the normal (non-toolbar) configuration, the xterm widget covers
911 *	   almost all of the window.  With a toolbar, there's a relatively
912 *	   large area that the user would expect to enter keystrokes since the
913 *	   program can get the focus.
914 */
915void
916xtermAddInput(Widget w)
917{
918    /* *INDENT-OFF* */
919    XtActionsRec input_actions[] = {
920	{ "insert",		    HandleKeyPressed }, /* alias */
921	{ "insert-eight-bit",	    HandleEightBitKeyPressed },
922	{ "insert-seven-bit",	    HandleKeyPressed },
923	{ "pointer-motion",	    HandlePointerMotion },
924	{ "pointer-button",	    HandlePointerButton },
925	{ "secure",		    HandleSecure },
926	{ "string",		    HandleStringEvent },
927	{ "scroll-back",	    HandleScrollBack },
928	{ "scroll-forw",	    HandleScrollForward },
929	{ "scroll-to",		    HandleScrollTo },
930	{ "select-cursor-end",	    HandleKeyboardSelectEnd },
931	{ "select-cursor-extend",   HandleKeyboardSelectExtend },
932	{ "select-cursor-start",    HandleKeyboardSelectStart },
933	{ "insert-selection",	    HandleInsertSelection },
934	{ "select-start",	    HandleSelectStart },
935	{ "select-extend",	    HandleSelectExtend },
936	{ "start-extend",	    HandleStartExtend },
937	{ "select-end",		    HandleSelectEnd },
938	{ "clear-saved-lines",	    HandleClearSavedLines },
939	{ "popup-menu",		    HandlePopupMenu },
940	{ "bell",		    HandleBell },
941	{ "ignore",		    HandleIgnore },
942#if OPT_DABBREV
943	{ "dabbrev-expand",	    HandleDabbrevExpand },
944#endif
945#if OPT_MAXIMIZE
946	{ "fullscreen",		    HandleFullscreen },
947#endif
948#if OPT_SCROLL_LOCK
949	{ "scroll-lock",	    HandleScrollLock },
950#endif
951#if OPT_SHIFT_FONTS
952	{ "larger-vt-font",	    HandleLargerFont },
953	{ "smaller-vt-font",	    HandleSmallerFont },
954#endif
955    };
956    /* *INDENT-ON* */
957
958    TRACE_TRANS("BEFORE", w);
959    XtAppAddActions(app_con, input_actions, XtNumber(input_actions));
960    XtAugmentTranslations(w, XtParseTranslationTable(defaultTranslations));
961    TRACE_TRANS("AFTER:", w);
962
963#if OPT_EXTRA_PASTE
964    if (term && term->keyboard.extra_translations)
965	XtOverrideTranslations((Widget) term, XtParseTranslationTable(term->keyboard.extra_translations));
966#endif
967}
968
969#if OPT_ISO_COLORS
970#ifdef EXP_BOGUS_FG
971static Bool
972CheckBogusForeground(TScreen *screen, const char *tag)
973{
974    int row = -1, col = -1, pass;
975    Bool isClear = True;
976
977    (void) tag;
978    for (pass = 0; pass < 2; ++pass) {
979	row = screen->cur_row;
980	for (; isClear && (row <= screen->max_row); ++row) {
981	    CLineData *ld = getLineData(screen, row);
982
983	    if (ld != 0) {
984		IAttr *attribs = ld->attribs;
985
986		col = (row == screen->cur_row) ? screen->cur_col : 0;
987		for (; isClear && (col <= screen->max_col); ++col) {
988		    unsigned flags = attribs[col];
989		    if (pass) {
990			flags &= ~FG_COLOR;
991			attribs[col] = (IAttr) flags;
992		    } else if ((flags & BG_COLOR)) {
993			isClear = False;
994		    } else if ((flags & FG_COLOR)) {
995			unsigned ch = ld->charData[col];
996			isClear = ((ch == ' ') || (ch == 0));
997		    } else {
998			isClear = False;
999		    }
1000		}
1001	    }
1002	}
1003    }
1004    TRACE(("%s checked %d,%d to %d,%d %s pass %d\n",
1005	   tag, screen->cur_row, screen->cur_col,
1006	   row, col,
1007	   isClear && pass ? "cleared" : "unchanged",
1008	   pass));
1009
1010    return isClear;
1011}
1012#endif
1013
1014/*
1015 * The terminal's foreground and background colors are set via two mechanisms:
1016 *	text (cur_foreground, cur_background values that are passed down to
1017 *		XDrawImageString and XDrawString)
1018 *	area (X11 graphics context used in XClearArea and XFillRectangle)
1019 */
1020void
1021SGR_Foreground(XtermWidget xw, int color)
1022{
1023    TScreen *screen = TScreenOf(xw);
1024    Pixel fg;
1025
1026    if (color >= 0) {
1027	UIntSet(xw->flags, FG_COLOR);
1028    } else {
1029	UIntClr(xw->flags, FG_COLOR);
1030    }
1031    fg = getXtermFG(xw, xw->flags, color);
1032    xw->cur_foreground = color;
1033
1034    setCgsFore(xw, WhichVWin(screen), gcNorm, fg);
1035    setCgsBack(xw, WhichVWin(screen), gcNormReverse, fg);
1036
1037    setCgsFore(xw, WhichVWin(screen), gcBold, fg);
1038    setCgsBack(xw, WhichVWin(screen), gcBoldReverse, fg);
1039
1040#ifdef EXP_BOGUS_FG
1041    /*
1042     * If we've just turned off the foreground color, check for blank cells
1043     * which have no background color, but do have foreground color.  This
1044     * could happen due to setting the foreground color just before scrolling.
1045     *
1046     * Those cells look uncolored, but will confuse ShowCursor(), which looks
1047     * for the colors in the current cell, and will see the foreground color.
1048     * In that case, remove the foreground color from the blank cells.
1049     */
1050    if (color < 0) {
1051	CheckBogusForeground(screen, "SGR_Foreground");
1052    }
1053#endif
1054}
1055
1056void
1057SGR_Background(XtermWidget xw, int color)
1058{
1059    TScreen *screen = TScreenOf(xw);
1060    Pixel bg;
1061
1062    /*
1063     * An indexing operation may have set screen->scroll_amt, which would
1064     * normally result in calling FlushScroll() in WriteText().  However,
1065     * if we're changing the background color now, then the new value
1066     * should not apply to the pending blank lines.
1067     */
1068    if (screen->scroll_amt && (color != xw->cur_background))
1069	FlushScroll(xw);
1070
1071    if (color >= 0) {
1072	UIntSet(xw->flags, BG_COLOR);
1073    } else {
1074	UIntClr(xw->flags, BG_COLOR);
1075    }
1076    bg = getXtermBG(xw, xw->flags, color);
1077    xw->cur_background = color;
1078
1079    setCgsBack(xw, WhichVWin(screen), gcNorm, bg);
1080    setCgsFore(xw, WhichVWin(screen), gcNormReverse, bg);
1081
1082    setCgsBack(xw, WhichVWin(screen), gcBold, bg);
1083    setCgsFore(xw, WhichVWin(screen), gcBoldReverse, bg);
1084}
1085
1086/* Invoked after updating bold/underline flags, computes the extended color
1087 * index to use for foreground.  (See also 'extract_fg()').
1088 */
1089static void
1090setExtendedFG(XtermWidget xw)
1091{
1092    int fg = xw->sgr_foreground;
1093
1094    if (TScreenOf(xw)->colorAttrMode
1095	|| (fg < 0)) {
1096	fg = MapToColorMode(fg, TScreenOf(xw), xw->flags);
1097    }
1098
1099    /* This implements the IBM PC-style convention of 8-colors, with one
1100     * bit for bold, thus mapping the 0-7 codes to 8-15.  It won't make
1101     * much sense for 16-color applications, but we keep it to retain
1102     * compatibility with ANSI-color applications.
1103     */
1104#if OPT_PC_COLORS		/* XXXJTL should be settable at runtime (resource or OSC?) */
1105    if (TScreenOf(xw)->boldColors
1106	&& (!xw->sgr_38_xcolors)
1107	&& (fg >= 0)
1108	&& (fg < 8)
1109	&& (xw->flags & BOLD))
1110	fg |= 8;
1111#endif
1112
1113    SGR_Foreground(xw, fg);
1114}
1115
1116/* Invoked after updating inverse flag, computes the extended color
1117 * index to use for background.  (See also 'extract_bg()').
1118 */
1119static void
1120setExtendedBG(XtermWidget xw)
1121{
1122    int bg = xw->sgr_background;
1123
1124    if (TScreenOf(xw)->colorAttrMode
1125	|| (bg < 0)) {
1126	if (TScreenOf(xw)->colorRVMode && (xw->flags & INVERSE))
1127	    bg = COLOR_RV;
1128    }
1129
1130    SGR_Background(xw, bg);
1131}
1132
1133void
1134setExtendedColors(XtermWidget xw)
1135{
1136    setExtendedFG(xw);
1137    setExtendedBG(xw);
1138}
1139
1140static void
1141reset_SGR_Foreground(XtermWidget xw)
1142{
1143    xw->sgr_foreground = -1;
1144    xw->sgr_38_xcolors = False;
1145    clrDirectFG(xw->flags);
1146    setExtendedFG(xw);
1147}
1148
1149static void
1150reset_SGR_Background(XtermWidget xw)
1151{
1152    xw->sgr_background = -1;
1153    clrDirectBG(xw->flags);
1154    setExtendedBG(xw);
1155}
1156
1157static void
1158reset_SGR_Colors(XtermWidget xw)
1159{
1160    reset_SGR_Foreground(xw);
1161    reset_SGR_Background(xw);
1162}
1163#endif /* OPT_ISO_COLORS */
1164
1165#if OPT_WIDE_ATTRS
1166/*
1167 * Call this before changing the state of ATR_ITALIC, to update the GC fonts.
1168 */
1169static void
1170setItalicFont(XtermWidget xw, Bool enable)
1171{
1172    if (enable) {
1173	if ((xw->flags & ATR_ITALIC) == 0) {
1174	    xtermLoadItalics(xw);
1175	    TRACE(("setItalicFont: enabling Italics\n"));
1176	    xtermUpdateFontGCs(xw, getItalicFont);
1177	}
1178    } else if ((xw->flags & ATR_ITALIC) != 0) {
1179	TRACE(("setItalicFont: disabling Italics\n"));
1180	xtermUpdateFontGCs(xw, getNormalFont);
1181    }
1182}
1183
1184static void
1185ResetItalics(XtermWidget xw)
1186{
1187    setItalicFont(xw, False);
1188    UIntClr(xw->flags, ATR_ITALIC);
1189}
1190
1191#else
1192#define ResetItalics(xw)	/* nothing */
1193#endif
1194
1195static void
1196initCharset(TScreen *screen, int which, DECNRCM_codes code)
1197{
1198    screen->gsets[which] = code;
1199}
1200
1201void
1202saveCharsets(TScreen *screen, DECNRCM_codes * target)
1203{
1204    int g;
1205    for (g = 0; g < NUM_GSETS; ++g) {
1206	target[g] = screen->gsets[g];
1207    }
1208}
1209
1210void
1211restoreCharsets(TScreen *screen, DECNRCM_codes * source)
1212{
1213    int g;
1214    for (g = 0; g < NUM_GSETS; ++g) {
1215	screen->gsets[g] = source[g];
1216    }
1217}
1218
1219void
1220resetCharsets(TScreen *screen)
1221{
1222    TRACE(("resetCharsets\n"));
1223
1224    initCharset(screen, 0, nrc_ASCII);
1225    initCharset(screen, 1, nrc_ASCII);
1226    initCharset(screen, 2, nrc_ASCII);
1227    initCharset(screen, 3, nrc_ASCII);
1228
1229    screen->curgl = 0;		/* G0 => GL.            */
1230    screen->curgr = 2;		/* G2 => GR.            */
1231    screen->curss = 0;		/* No single shift.     */
1232
1233#if OPT_VT52_MODE
1234    if (screen->vtXX_level == 0)
1235	initCharset(screen, 1, nrc_DEC_Spec_Graphic);	/* Graphics */
1236#endif
1237}
1238
1239static void
1240modified_DECNRCM(XtermWidget xw)
1241{
1242#if OPT_WIDE_CHARS
1243    TScreen *screen = TScreenOf(xw);
1244    if (screen->wide_chars && (screen->utf8_mode || screen->utf8_nrc_mode)) {
1245	int enabled = ((xw->flags & NATIONAL) != 0);
1246	int modefix;
1247	EXCHANGE(screen->utf8_nrc_mode, screen->utf8_mode, modefix);
1248	switchPtyData(screen, !enabled);
1249	TRACE(("UTF8 mode temporarily %s\n", enabled ? "ON" : "OFF"));
1250    }
1251#else
1252    (void) xw;
1253#endif
1254}
1255
1256/*
1257 * VT300 and up support three ANSI conformance levels, defined according to
1258 * the dpANSI X3.134.1 standard.  DEC's manuals equate levels 1 and 2, and
1259 * are unclear.  This code is written based on the manuals.
1260 */
1261static void
1262set_ansi_conformance(TScreen *screen, int level)
1263{
1264    TRACE(("set_ansi_conformance(%d) dec_level %d:%d, ansi_level %d\n",
1265	   level,
1266	   screen->vtXX_level * 100,
1267	   screen->terminal_id,
1268	   screen->ansi_level));
1269    if (screen->vtXX_level >= 3) {
1270	switch (screen->ansi_level = level) {
1271	case 1:
1272	    /* FALLTHRU */
1273	case 2:
1274	    initCharset(screen, 0, nrc_ASCII);	/* G0 is ASCII */
1275	    initCharset(screen, 1, nrc_ASCII);	/* G1 is ISO Latin-1 */
1276	    screen->curgl = 0;
1277	    screen->curgr = 1;
1278	    break;
1279	case 3:
1280	    initCharset(screen, 0, nrc_ASCII);	/* G0 is ASCII */
1281	    screen->curgl = 0;
1282	    break;
1283	}
1284    }
1285}
1286
1287/*
1288 * Set scrolling margins.  VTxxx terminals require that the top/bottom are
1289 * different, so we have at least two lines in the scrolling region.
1290 */
1291static void
1292set_tb_margins(TScreen *screen, int top, int bottom)
1293{
1294    TRACE(("set_tb_margins %d..%d, prior %d..%d\n",
1295	   top, bottom,
1296	   screen->top_marg,
1297	   screen->bot_marg));
1298    if (bottom > top) {
1299	screen->top_marg = top;
1300	screen->bot_marg = bottom;
1301    }
1302    if (screen->top_marg > screen->max_row)
1303	screen->top_marg = screen->max_row;
1304    if (screen->bot_marg > screen->max_row)
1305	screen->bot_marg = screen->max_row;
1306}
1307
1308static void
1309set_lr_margins(TScreen *screen, int left, int right)
1310{
1311    TRACE(("set_lr_margins %d..%d, prior %d..%d\n",
1312	   left, right,
1313	   screen->lft_marg,
1314	   screen->rgt_marg));
1315    if (right > left) {
1316	screen->lft_marg = left;
1317	screen->rgt_marg = right;
1318    }
1319    if (screen->lft_marg > screen->max_col)
1320	screen->lft_marg = screen->max_col;
1321    if (screen->rgt_marg > screen->max_col)
1322	screen->rgt_marg = screen->max_col;
1323}
1324
1325#define reset_tb_margins(screen) set_tb_margins(screen, 0, screen->max_row)
1326#define reset_lr_margins(screen) set_lr_margins(screen, 0, screen->max_col)
1327
1328void
1329resetMargins(XtermWidget xw)
1330{
1331    TScreen *screen = TScreenOf(xw);
1332
1333    reset_tb_margins(screen);
1334    reset_lr_margins(screen);
1335}
1336
1337static void
1338resetMarginMode(XtermWidget xw)
1339{
1340    UIntClr(xw->flags, LEFT_RIGHT);
1341    resetMargins(xw);
1342}
1343
1344static void
1345resetRendition(XtermWidget xw)
1346{
1347    TScreen *screen = TScreenOf(xw);
1348    (void) screen;
1349    ResetItalics(xw);
1350    UIntClr(xw->flags,
1351	    (SGR_MASK | SGR_MASK2 | INVISIBLE));
1352}
1353
1354void
1355set_max_col(TScreen *screen, int cols)
1356{
1357    TRACE(("set_max_col %d, prior %d\n", cols, screen->max_col));
1358    if (cols < 0)
1359	cols = 0;
1360    screen->max_col = cols;
1361}
1362
1363void
1364set_max_row(TScreen *screen, int rows)
1365{
1366    TRACE(("set_max_row %d, prior %d\n", rows, screen->max_row));
1367    if (rows < 0)
1368	rows = 0;
1369    screen->max_row = rows;
1370}
1371
1372#if OPT_MOD_FKEYS
1373static void
1374set_mod_fkeys(XtermWidget xw, int which, int what, Bool enabled)
1375{
1376#define SET_MOD_FKEYS(field) \
1377    xw->keyboard.modify_now.field = ((what == DEFAULT) && enabled) \
1378				     ? xw->keyboard.modify_1st.field \
1379				     : what; \
1380    TRACE(("set modify_now.%s to %d\n", #field, \
1381	   xw->keyboard.modify_now.field));
1382
1383    switch (which) {
1384    case 0:
1385	SET_MOD_FKEYS(allow_keys);
1386	break;
1387    case 1:
1388	SET_MOD_FKEYS(cursor_keys);
1389	break;
1390    case 2:
1391	SET_MOD_FKEYS(function_keys);
1392	break;
1393    case 3:
1394	SET_MOD_FKEYS(keypad_keys);
1395	break;
1396    case 4:
1397	SET_MOD_FKEYS(other_keys);
1398	break;
1399    case 5:
1400	SET_MOD_FKEYS(string_keys);
1401	break;
1402    }
1403}
1404#endif /* OPT_MOD_FKEYS */
1405
1406#if OPT_TRACE
1407#define DATA(name) { name, #name }
1408static const struct {
1409    Const PARSE_T *table;
1410    const char *name;
1411} all_tables[] = {
1412
1413    DATA(ansi_table)
1414	,DATA(cigtable)
1415	,DATA(csi2_table)
1416	,DATA(csi_ex_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_WIDE_CHARS
1441	,DATA(esc_pct_table)
1442	,DATA(scs_amp_table)
1443	,DATA(scs_pct_table)
1444	,DATA(scs_2qt_table)
1445#endif
1446#if OPT_VT52_MODE
1447	,DATA(vt52_table)
1448	,DATA(vt52_esc_table)
1449	,DATA(vt52_ignore_table)
1450#endif
1451#if OPT_XTERM_SGR
1452	,DATA(csi_hash_table)
1453#endif
1454#undef DATA
1455};
1456
1457#define WHICH_TABLE(name) if (table == name) result = #name
1458static const char *
1459which_table(Const PARSE_T * table)
1460{
1461    const char *result = "?";
1462    Cardinal n;
1463    for (n = 0; n < XtNumber(all_tables); ++n) {
1464	if (table == all_tables[n].table) {
1465	    result = all_tables[n].name;
1466	    break;
1467	}
1468    }
1469
1470    return result;
1471}
1472
1473static void
1474check_tables(void)
1475{
1476    Cardinal n;
1477    int ch;
1478    int total_codes = 0;
1479    int total_ground = 0;
1480    int total_ignored = 0;
1481
1482    TRACE(("** check_tables\n"));
1483    for (n = 0; n < XtNumber(all_tables); ++n) {
1484	Const PARSE_T *table = all_tables[n].table;
1485	TRACE(("*** %s\n", all_tables[n].name));
1486	/*
1487	 * Most of the tables should use the same codes in 0..31, 128..159
1488	 * as the "ansi" table.
1489	 */
1490	if (strncmp(all_tables[n].name, "ansi", 4) &&
1491	    strncmp(all_tables[n].name, "sos_", 4) &&
1492	    strncmp(all_tables[n].name, "vt52", 4)) {
1493	    for (ch = 0; ch < 32; ++ch) {
1494		int c1 = ch + 128;
1495		PARSE_T st_l = table[ch];
1496		PARSE_T st_r = table[c1];
1497		if (st_l != ansi_table[ch]) {
1498		    TRACE(("  %3d: %d vs %d\n", ch, st_l, ansi_table[ch]));
1499		}
1500		if (st_r != ansi_table[c1]) {
1501		    TRACE(("  %3d: %d vs %d\n", c1, st_r, ansi_table[c1]));
1502		}
1503	    }
1504	}
1505	/*
1506	 * All of the tables should have their GL/GR parts encoded the same.
1507	 */
1508	for (ch = 32; ch < 127; ++ch) {
1509	    PARSE_T st_l = table[ch];
1510	    PARSE_T st_r = table[ch + 128];
1511	    if (st_l != st_r) {
1512		if (st_r == CASE_IGNORE &&
1513		    !strncmp(all_tables[n].name, "vt52", 4)) {
1514		    ;
1515		} else {
1516		    TRACE(("  %3d: %d vs %d\n", ch, st_l, st_r));
1517		}
1518	    }
1519	}
1520	/*
1521	 * Just for amusement, show how sparse the encoding tables are.
1522	 */
1523	for (ch = 0; ch < 256; ++ch) {
1524	    ++total_codes;
1525	    switch (table[ch]) {
1526	    case CASE_GROUND_STATE:
1527		total_ground++;
1528		break;
1529	    case CASE_ESC_IGNORE:
1530		/* FALLTHRU */
1531	    case CASE_IGNORE:
1532		/* FALLTHRU */
1533	    case CASE_VT52_IGNORE:
1534		total_ignored++;
1535		break;
1536	    }
1537	}
1538    }
1539    TRACE(("VTPrsTbl:\n"));
1540    TRACE(("%d total codes\n", total_codes));
1541    TRACE(("%d total ignored\n", total_ignored));
1542    TRACE(("%d total reset/ground\n", total_ground));
1543}
1544
1545static void
1546check_bitmasks(void)
1547{
1548#define dMSK 0x100
1549#define DATA(mode,name) { mode, name, #name }
1550#define DMSK(what) (dMSK | (what))
1551#define DGRP(offs) (1 << ((offs) - 1))
1552    static struct {
1553	int mode;
1554	int code;
1555	Const char *name;
1556    } table[] = {
1557	DATA(DGRP(1), INVERSE),
1558	    DATA(DGRP(1), UNDERLINE),
1559	    DATA(DGRP(1), BOLD),
1560	    DATA(DGRP(1), BLINK),
1561	    DATA(DMSK(DGRP(1)), SGR_MASK),
1562	    DATA(DGRP(2), BG_COLOR),
1563	    DATA(DGRP(2), FG_COLOR),
1564	    DATA(DGRP(2), PROTECTED),
1565	    DATA(DGRP(4), CHARDRAWN),
1566#if OPT_WIDE_ATTRS
1567	    DATA(DGRP(2), ATR_FAINT),
1568	    DATA(DGRP(2), ATR_ITALIC),
1569	    DATA(DGRP(2), ATR_STRIKEOUT),
1570	    DATA(DGRP(2), ATR_DBL_UNDER),
1571	    DATA(DGRP(2), ATR_DIRECT_FG),
1572	    DATA(DGRP(2), ATR_DIRECT_BG),
1573#endif
1574	    DATA(DMSK(DGRP(2)), SGR_MASK2),
1575	    DATA(DGRP(3), WRAPAROUND),
1576	    DATA(DGRP(3), REVERSEWRAP),
1577	    DATA(DGRP(3), REVERSE_VIDEO),
1578	    DATA(DGRP(3), LINEFEED),
1579	    DATA(DGRP(3), ORIGIN),
1580	    DATA(DGRP(3), INSERT),
1581	    DATA(DGRP(3), SMOOTHSCROLL),
1582	    DATA(DGRP(3), IN132COLUMNS),
1583	    DATA(DGRP(3), INVISIBLE),
1584	    DATA(DMSK(DGRP(3)), ATTRIBUTES),
1585	    DATA(DGRP(5), NATIONAL),
1586	    DATA(DGRP(5), LEFT_RIGHT),
1587	    DATA(DGRP(5), NOCLEAR_COLM),
1588	    DATA(DGRP(4), NOBACKGROUND),
1589	    DATA(DGRP(4), NOTRANSLATION),
1590	    DATA(DGRP(4), DOUBLEWFONT),
1591	    DATA(DGRP(4), DOUBLEHFONT),
1592	    DATA(DGRP(4), CHARBYCHAR),
1593	    DATA(DGRP(4), NORESOLUTION),
1594	    DATA(DMSK(DGRP(1) | DGRP(2) | DGRP(4)), DRAWX_MASK),
1595	    DATA(-1, EOF)
1596    };
1597#undef DATA
1598    int j, k;
1599    TRACE(("** check_bitmasks:\n"));
1600    for (j = 0; table[j].mode >= 0; ++j) {
1601	TRACE(("%4X %8X %s\n", table[j].mode, table[j].code, table[j].name));
1602	if (table[j].mode & dMSK) {
1603	    int mask = dMSK;
1604	    for (k = 0; table[k].mode >= 0; ++k) {
1605		if (j == k)
1606		    continue;
1607		if (table[k].mode & dMSK)
1608		    continue;
1609		if ((table[j].mode & table[k].mode) != 0)
1610		    mask |= table[k].mode;
1611	    }
1612	    if (mask != table[j].mode) {
1613		TRACE(("...expected %08X\n", mask));
1614	    }
1615	} else {
1616	    for (k = 0; table[k].mode >= 0; ++k) {
1617		if (j == k)
1618		    continue;
1619		if (table[k].mode & dMSK)
1620		    continue;
1621		if ((table[j].code & table[k].code) != 0) {
1622		    TRACE(("...same bits %s\n", table[k].name));
1623		}
1624	    }
1625	}
1626    }
1627}
1628#endif
1629
1630static int
1631init_params(void)
1632{
1633    while (parms.count-- > 0) {
1634	parms.is_sub[parms.count] = 0;
1635	parms.params[parms.count] = 0;
1636    }
1637    parms.count = 0;
1638    parms.has_subparams = 0;
1639    return 0;
1640}
1641
1642#if OPT_TRACE > 0
1643static void
1644dump_params(void)
1645{
1646    int n;
1647    int arg;
1648    TRACE(("params %d (%d)\n", nparam, parms.has_subparams));
1649    for (arg = 1, n = 0; n < nparam; ++n) {
1650	TRACE(("%3d.%d %d\n", arg, parms.is_sub[n], parms.params[n]));
1651	if (!parms.is_sub[n])
1652	    ++arg;
1653    }
1654}
1655#define DumpParams() dump_params()
1656#else
1657#define DumpParams()		/* nothing */
1658#endif
1659
1660	/* allocate larger buffer if needed/possible */
1661#define SafeAlloc(type, area, used, size) \
1662		type *new_string = area; \
1663		size_t new_length = size; \
1664		if (new_length == 0) { \
1665		    new_length = 1024; \
1666		    new_string = TypeMallocN(type, new_length); \
1667		} else if (used+1 >= new_length) { \
1668		    new_length = size * 2; \
1669		    new_string = TypeMallocN(type, new_length); \
1670		    if (new_string != 0 \
1671		     && area != 0 \
1672		     && used != 0) { \
1673			memcpy(new_string, area, used * sizeof(type)); \
1674		     } \
1675		}
1676#define SafeFree(area, size) \
1677		if (area != new_string) { \
1678		    free(area); \
1679		    area = new_string; \
1680		} \
1681		size = new_length
1682
1683#define WriteNow() {						\
1684	    unsigned single = 0;				\
1685								\
1686	    if (screen->curss) {				\
1687		dotext(xw,					\
1688		       screen->gsets[(int) (screen->curss)],	\
1689		       sp->print_area,				\
1690		       (Cardinal) 1);				\
1691		screen->curss = 0;				\
1692		single++;					\
1693	    }							\
1694	    if (sp->print_used > single) {			\
1695		dotext(xw,					\
1696		       screen->gsets[(int) (screen->curgl)],	\
1697		       sp->print_area + single,			\
1698		       (Cardinal) (sp->print_used - single));	\
1699	    }							\
1700	    sp->print_used = 0;					\
1701	}							\
1702
1703#define PARSE_SRM 1
1704
1705struct ParseState {
1706    unsigned check_recur;
1707#if OPT_VT52_MODE
1708    Bool vt52_cup;
1709#endif
1710    Const PARSE_T *groundtable;
1711    Const PARSE_T *parsestate;
1712    int scstype;
1713    int scssize;
1714    Bool private_function;	/* distinguish private-mode from standard */
1715    int string_mode;		/* nonzero iff we're processing a string */
1716    int lastchar;		/* positive iff we had a graphic character */
1717    int nextstate;
1718#if OPT_WIDE_CHARS
1719    int last_was_wide;
1720#endif
1721    /* Buffer for processing printable text */
1722    IChar *print_area;
1723    size_t print_size;
1724    size_t print_used;
1725    /* Buffer for processing strings (e.g., OSC ... ST) */
1726    Char *string_area;
1727    size_t string_size;
1728    size_t string_used;
1729    /* Buffer for deferring input */
1730    Char *defer_area;
1731    size_t defer_size;
1732    size_t defer_used;
1733};
1734
1735static struct ParseState myState;
1736
1737static void
1738init_groundtable(TScreen *screen, struct ParseState *sp)
1739{
1740    (void) screen;
1741
1742#if OPT_VT52_MODE
1743    if (!(screen->vtXX_level)) {
1744	sp->groundtable = vt52_table;
1745    } else if (screen->terminal_id >= 100)
1746#endif
1747    {
1748	sp->groundtable = ansi_table;
1749    }
1750}
1751
1752static void
1753select_charset(struct ParseState *sp, int type, int size)
1754{
1755    TRACE(("select_charset G%d size %d -> G%d size %d\n",
1756	   sp->scstype, sp->scssize,
1757	   type, size));
1758
1759    sp->scstype = type;
1760    sp->scssize = size;
1761    if (size == 94) {
1762	sp->parsestate = scstable;
1763    } else {
1764	sp->parsestate = scs96table;
1765    }
1766}
1767/* *INDENT-OFF* */
1768static const struct {
1769    DECNRCM_codes result;
1770    int prefix;
1771    int suffix;
1772    int min_level;
1773    int max_level;
1774    int need_nrc;
1775} scs_table[] = {
1776    { nrc_ASCII,             0,   'B', 1, 9, 0 },
1777    { nrc_British,           0,   'A', 1, 9, 0 },
1778    { nrc_DEC_Spec_Graphic,  0,   '0', 1, 9, 0 },
1779    { nrc_DEC_Alt_Chars,     0,   '1', 1, 1, 0 },
1780    { nrc_DEC_Alt_Graphics,  0,   '2', 1, 1, 0 },
1781    /* VT2xx */
1782    { nrc_DEC_Supp,          0,   '<', 2, 9, 0 },
1783    { nrc_Dutch,             0,   '4', 2, 9, 1 },
1784    { nrc_Finnish,           0,   '5', 2, 9, 1 },
1785    { nrc_Finnish2,          0,   'C', 2, 9, 1 },
1786    { nrc_French,            0,   'R', 2, 9, 1 },
1787    { nrc_French2,           0,   'f', 2, 9, 1 },
1788    { nrc_French_Canadian,   0,   'Q', 2, 9, 1 },
1789    { nrc_German,            0,   'K', 2, 9, 1 },
1790    { nrc_Italian,           0,   'Y', 2, 9, 1 },
1791    { nrc_Norwegian_Danish2, 0,   'E', 2, 9, 1 },
1792    { nrc_Norwegian_Danish3, 0,   '6', 2, 9, 1 },
1793    { nrc_Spanish,           0,   'Z', 2, 9, 1 },
1794    { nrc_Swedish,           0,   '7', 2, 9, 1 },
1795    { nrc_Swedish2,          0,   'H', 2, 9, 1 },
1796    { nrc_Swiss,             0,   '=', 2, 9, 1 },
1797    /* VT3xx */
1798    { nrc_British_Latin_1,   0,   'A', 3, 9, 1 },
1799    { nrc_DEC_Supp_Graphic,  '%', '5', 3, 9, 0 },
1800    { nrc_DEC_Technical,     0,   '>', 3, 9, 0 },
1801    { nrc_French_Canadian2,  0,   '9', 3, 9, 1 },
1802    { nrc_Norwegian_Danish,  0,   '`', 3, 9, 1 },
1803    { nrc_Portugese,         '%', '6', 3, 9, 1 },
1804    { nrc_ISO_Latin_1_Supp,  0,   'A', 3, 9, 0 },
1805    /* VT5xx */
1806    { nrc_Greek,             '"', '>', 5, 9, 1 },
1807    { nrc_Hebrew,            '%', '=', 5, 9, 1 },
1808    { nrc_Turkish,	     '%', '2', 5, 9, 1 },
1809    { nrc_DEC_Cyrillic,      '&', '4', 5, 9, 0 },
1810    { nrc_DEC_Greek_Supp,    '"', '?', 5, 9, 0 },
1811    { nrc_DEC_Hebrew_Supp,   '"', '4', 5, 9, 0 },
1812    { nrc_DEC_Turkish_Supp,  '%', '0', 5, 9, 0 },
1813    { nrc_ISO_Greek_Supp,    0,   'F', 5, 9, 0 },
1814    { nrc_ISO_Hebrew_Supp,   0,   'H', 5, 9, 0 },
1815    { nrc_ISO_Latin_2_Supp,  0,   'B', 5, 9, 0 },
1816    { nrc_ISO_Latin_5_Supp,  0,   'M', 5, 9, 0 },
1817    { nrc_ISO_Latin_Cyrillic,0,   'L', 5, 9, 0 },
1818    /* VT5xx (not implemented) */
1819#if 0
1820    { nrc_Russian,           '&', '5', 5, 9, 1 },
1821    { nrc_SCS_NRCS,          '%', '3', 5, 9, 0 },
1822#endif
1823};
1824/* *INDENT-ON* */
1825
1826#if OPT_DEC_RECTOPS
1827static char *
1828encode_scs(DECNRCM_codes value)
1829{
1830    static char buffer[3];
1831    Cardinal n;
1832    char *result = buffer;
1833    for (n = 0; n < XtNumber(scs_table); ++n) {
1834	if (scs_table[n].result == value) {
1835	    if (scs_table[n].prefix)
1836		*result++ = (char) scs_table[n].prefix;
1837	    if (scs_table[n].suffix)
1838		*result++ = (char) scs_table[n].suffix;
1839	    break;
1840	}
1841    }
1842    *result = '\0';
1843    return buffer;
1844}
1845#endif
1846
1847void
1848xtermDecodeSCS(XtermWidget xw, int which, int sgroup, int prefix, int suffix)
1849{
1850    TScreen *screen = TScreenOf(xw);
1851    Cardinal n;
1852    DECNRCM_codes result = nrc_Unknown;
1853
1854    suffix &= 0x7f;
1855    for (n = 0; n < XtNumber(scs_table); ++n) {
1856	if (prefix == scs_table[n].prefix
1857	    && suffix == scs_table[n].suffix
1858	    && sgroup == scs_table[n].min_level
1859	    && screen->vtXX_level >= scs_table[n].min_level
1860	    && screen->vtXX_level <= scs_table[n].max_level
1861	    && (scs_table[n].need_nrc == 0 || (xw->flags & NATIONAL) != 0)) {
1862	    result = scs_table[n].result;
1863	    break;
1864	}
1865    }
1866    if (result != nrc_Unknown) {
1867	initCharset(screen, which, result);
1868	TRACE(("setting G%d to table #%d %s",
1869	       which, n, visibleScsCode((int) result)));
1870    } else {
1871	TRACE(("...unknown GSET"));
1872	initCharset(screen, which, nrc_ASCII);
1873    }
1874#if OPT_TRACE
1875    TRACE((" ("));
1876    if (prefix)
1877	TRACE(("prefix='%c', ", prefix));
1878    TRACE(("suffix='%c', sgroup=%d", suffix, sgroup));
1879    TRACE((")\n"));
1880#endif
1881}
1882
1883/*
1884 * Given a parameter number, and subparameter (starting in each case from zero)
1885 * return the corresponding index into the parameter array.  If the combination
1886 * is not found, return -1.
1887 */
1888static int
1889subparam_index(int p, int s)
1890{
1891    int result = -1;
1892    int j, p2, s2;
1893
1894    for (j = p2 = 0; j < nparam; ++j, ++p2) {
1895	if (parms.is_sub[j]) {
1896	    s2 = 0;
1897
1898	    do {
1899		if ((p == p2) && (s == s2)) {
1900		    result = j;
1901		    break;
1902		}
1903		++s2;
1904	    } while ((++j < nparam) && (parms.is_sub[j - 1] < parms.is_sub[j]));
1905
1906	    if (result >= 0)
1907		break;
1908
1909	    --j;		/* undo the last "while" */
1910	} else if (p == p2) {
1911	    if (s == 0) {
1912		result = j;
1913	    }
1914	    break;
1915	}
1916    }
1917    TRACE2(("...subparam_index %d.%d = %d\n", p + 1, s + 1, result));
1918    return result;
1919}
1920
1921/*
1922 * Check if the given item in the parameter array has subparameters.
1923 * If so, return the number of subparameters to use as a loop limit, etc.
1924 */
1925static int
1926param_has_subparams(int item)
1927{
1928    int result = 0;
1929    if (parms.has_subparams) {
1930	int n = subparam_index(item, 0);
1931	if (n >= 0 && parms.is_sub[n]) {
1932	    while (++n < nparam && parms.is_sub[n - 1] < parms.is_sub[n]) {
1933		result++;
1934	    }
1935	}
1936    }
1937    TRACE(("...param_has_subparams(%d) ->%d\n", item, result));
1938    return result;
1939}
1940
1941#if OPT_DIRECT_COLOR || OPT_256_COLORS || OPT_88_COLORS || OPT_ISO_COLORS
1942/*
1943 * Given an index into the parameter array, return the corresponding parameter
1944 * number (starting from zero).
1945 */
1946static int
1947param_number(int item)
1948{
1949    int result = -1;
1950    int j, p;
1951
1952    for (j = p = 0; j < nparam; ++j, ++p) {
1953	if (p >= item) {
1954	    result = j;
1955	    break;
1956	}
1957	if (parms.is_sub[j]) {
1958	    while ((++j < nparam) && (parms.is_sub[j - 1] < parms.is_sub[j])) {
1959		/* EMPTY */
1960	    }
1961	    --j;
1962	}
1963    }
1964
1965    TRACE2(("...param_number(%d) = %d\n", item, result));
1966    return result;
1967}
1968
1969static int
1970get_subparam(int p, int s)
1971{
1972    int item = subparam_index(p, s);
1973    int result = (item >= 0) ? parms.params[item] : DEFAULT;
1974    TRACE(("...get_subparam[%d] = %d\n", item, result));
1975    return result;
1976}
1977
1978/*
1979 * Some background -
1980 *
1981 * Todd Larason provided the initial changes to support 256-colors in July 1999.
1982 * I pointed out that the description of SGR 38/48 in ECMA-48 was vague, and
1983 * was unsure if there would be some standard using those codes.  His response
1984 * was that this was documented (it turns out, in equally vague terms) in ITU
1985 * T.416
1986 *
1987 * Discussing this with Todd Larason in mid-1999, my point was that given the
1988 * high cost of obtaining ITU T.416 (ISO-8613-6), the standard was not going
1989 * to be effective (more than $100 then, more than $200 in 2012)
1990 *
1991 * We overlooked the detail about ":" as a subparameter delimiter (documented
1992 * in 5.4.2 in ECMA-48).  Some discussion in KDE in mid-2006 led Lars Doelle
1993 * to discuss the issue with me.  Lars' initial concern dealt with the fact
1994 * that a sequence such as
1995 *	CSI 38 ; 5 ; 1 m
1996 * violated the principle that SGR parameters could be used in any order.
1997 * Further discussion (see KDE #107487) resolved that the standard expected
1998 * that the sequence would look like
1999 *	CSI 38 ; 5 : 1 m
2000 * which still violates that principle, since the "5:1" parameter has to
2001 * follow the "38" to be useful.
2002 *
2003 * This function accepts either format (per request by Paul Leonerd Evans).
2004 * It also accepts
2005 *	CSI 38 : 5 : 1 m
2006 * according to Lars' original assumption.  While implementing that, I added
2007 * support for Konsole's interpretation of "CSI 38 : 2" as a 24-bit RGB value.
2008 * ISO-8613-6 documents that as "direct color".
2009 *
2010 * At the time in 2012, no one noticed (or commented) regarding ISO-8613-6's
2011 * quirk in the description of direct color:  it mentions a color space
2012 * identifier parameter which should follow the "2" (as parameter 1).  In the
2013 * same section, ISO-8613-6 mentions a parameter 6 which can be ignored, as
2014 * well as parameters 7 and 8.  Like parameter 1, parameters 7 and 8 are not
2015 * defined clearly in the standard, and a close reading indicates they are
2016 * optional, saying they "may be used".  This implementation ignores parameters
2017 * 6 (and above), and provides for the color space identifier by checking the
2018 * number of parameters:
2019 *	3 after "2" (no color space identifier)
2020 *	4 or more after "2" (color space identifier)
2021 *
2022 * By the way - all of the parameters are decimal integers, and missing
2023 * parameters represent a default value.  ISO-8613-6 is clear about that.
2024 *
2025 * Aside from ISO-8613-3, there is no standard use of ":" as a delimiter.
2026 * ECMA-48 says only:
2027 *
2028 *	5.4.2 Parameter string format
2029 *
2030 *	A parameter string which does not start with a bit combination in the
2031 *	range 03/12 to 03/15 shall have the following format:
2032 *
2033 *	    a) A parameter string consists of one or more parameter
2034 *	       sub-strings, each of which represents a number in decimal
2035 *	       notation.
2036 *
2037 *	    b) Each parameter sub-string consists of one or more bit
2038 *	       combinations from 03/00 to 03/10; the bit combinations from
2039 *	       03/00 to 03/09 represent the digits ZERO to NINE; bit
2040 *	       combination 03/10 may be used as a separator in a parameter
2041 *	       sub-string, for example, to separate the fractional part of a
2042 *	       decimal number from the integer part of that number.
2043 *
2044 * That is, there is no mention in ECMA-48 of the possibility that a parameter
2045 * string might be a list of parameters, as done in ISO-8613-3 (nor does
2046 * ECMA-48 provide an example where the ":" separator might be used).  Because
2047 * of this, xterm treats other cases than those needed for ISO-8613-3 as an
2048 * error, and stops interpreting the sequence.
2049 */
2050#define extended_colors_limit(n) ((n) == 5 ? 1 : ((n) == 2 ? 3 : 0))
2051static Boolean
2052parse_extended_colors(XtermWidget xw, int *colorp, int *itemp, Boolean *extended)
2053{
2054    Boolean result = False;
2055    int item = *itemp;
2056    int next = item;
2057    int base = param_number(item);
2058    int code = -1;
2059    int values[3];		/* maximum number of subparameters */
2060    int need = 0;		/* number of subparameters needed */
2061    int have;
2062    int n;
2063
2064    /*
2065     * On entry, 'item' points to the 38/48 code in the parameter array.
2066     * If that has subparameters, we will expect all of the values to
2067     * be subparameters of that item.
2068     */
2069    if ((have = param_has_subparams(item)) != 0) {
2070	/* accept CSI 38 : 5 : 1 m */
2071	/* accept CSI 38 : 2 : 1 : 2 : 3 m */
2072	code = get_subparam(base, 1);
2073	need = extended_colors_limit(code);
2074	next = item + have;
2075	for (n = 0; n < need && n < 3; ++n) {
2076	    values[n] = get_subparam(base, 2 + n + (have > 4));
2077	}
2078    } else if (++item < nparam) {
2079	++base;
2080	if ((have = param_has_subparams(item)) != 0) {
2081	    /* accept CSI 38 ; 5 : 1 m */
2082	    /* accept CSI 38 ; 2 : 1 : 2 : 3 m */
2083	    code = get_subparam(base, 0);
2084	    need = extended_colors_limit(code);
2085	    next = base + have;
2086	    for (n = 0; n < need && n < 3; ++n) {
2087		values[n] = get_subparam(base, 1 + n + (have > 3));
2088	    }
2089	} else {
2090	    /* accept CSI 38 ; 5 ; 1 m */
2091	    /* accept CSI 38 ; 2 ; 1 ; 2 ; 3 m */
2092	    code = GetParam(item);
2093	    need = extended_colors_limit(code);
2094	    next = item + need;
2095	    for (n = 0; n < need && n < 3; ++n) {
2096		values[n] = GetParam(item + 1 + n);
2097	    }
2098	}
2099    }
2100    item = next;
2101
2102    *extended = False;
2103    switch (code) {
2104    case 2:
2105	/* direct color in rgb space */
2106	if ((values[0] >= 0 && values[0] < 256) &&
2107	    (values[1] >= 0 && values[1] < 256) &&
2108	    (values[2] >= 0 && values[2] < 256)) {
2109#if OPT_DIRECT_COLOR
2110	    if (TScreenOf(xw)->direct_color && xw->has_rgb) {
2111		*colorp = getDirectColor(xw, values[0], values[1], values[2]);
2112		result = True;
2113		*extended = True;
2114	    } else
2115#endif
2116	    {
2117		*colorp = xtermClosestColor(xw, values[0], values[1], values[2]);
2118		result = okIndexedColor(*colorp);
2119	    }
2120	} else {
2121	    *colorp = -1;
2122	}
2123	break;
2124    case 5:
2125	/* indexed color */
2126	*colorp = values[0];
2127	result = okIndexedColor(*colorp);
2128	break;
2129    default:
2130	*colorp = -1;
2131	break;
2132    }
2133
2134    TRACE(("...resulting color %d/%d %s\n",
2135	   *colorp, NUM_ANSI_COLORS,
2136	   result ? "OK" : "ERR"));
2137
2138    *itemp = item;
2139    return result;
2140}
2141#endif /* ...extended_colors */
2142
2143static int
2144optional_param(int which)
2145{
2146    return (nparam > which) ? GetParam(which) : DEFAULT;
2147}
2148
2149static int
2150zero_if_default(int which)
2151{
2152    int result = (nparam > which) ? GetParam(which) : 0;
2153    if (result <= 0)
2154	result = 0;
2155    return result;
2156}
2157
2158static int
2159one_if_default(int which)
2160{
2161    int result = (nparam > which) ? GetParam(which) : 0;
2162    if (result <= 0)
2163	result = 1;
2164    return result;
2165}
2166
2167/*
2168 * Color palette changes using the OSC controls require a repaint of the
2169 * screen - but not immediately.  Do the repaint as soon as we detect a
2170 * state which will not lead to another color palette change.
2171 */
2172static void
2173repaintWhenPaletteChanged(XtermWidget xw, struct ParseState *sp)
2174{
2175    Boolean ignore = False;
2176
2177    switch (sp->nextstate) {
2178    case CASE_ESC:
2179	ignore = ((sp->parsestate == ansi_table) ||
2180		  (sp->parsestate == sos_table));
2181#if USE_DOUBLE_BUFFER
2182	if (resource.buffered && TScreenOf(xw)->needSwap) {
2183	    ignore = False;
2184	}
2185#endif
2186	break;
2187    case CASE_OSC:
2188	ignore = ((sp->parsestate == ansi_table) ||
2189		  (sp->parsestate == esc_table));
2190	break;
2191    case CASE_IGNORE:
2192	ignore = (sp->parsestate == sos_table);
2193	break;
2194    case CASE_ST:
2195	ignore = ((sp->parsestate == esc_table) ||
2196		  (sp->parsestate == sos_table));
2197	break;
2198    case CASE_ESC_DIGIT:
2199	ignore = (sp->parsestate == csi_table);
2200	break;
2201    case CASE_ESC_SEMI:
2202	ignore = (sp->parsestate == csi2_table);
2203	break;
2204    }
2205
2206    if (!ignore) {
2207	TRACE(("repaintWhenPaletteChanged\n"));
2208	xw->work.palette_changed = False;
2209	xtermRepaint(xw);
2210	xtermFlushDbe(xw);
2211    }
2212}
2213
2214#if OPT_C1_PRINT || OPT_WIDE_CHARS
2215#define ParseSOS(screen) ((screen)->c1_printable == 0)
2216#else
2217#define ParseSOS(screen) 0
2218#endif
2219
2220#define ResetState(sp) InitParams(), (sp)->parsestate = (sp)->groundtable
2221
2222static void
2223illegal_parse(XtermWidget xw, unsigned c, struct ParseState *sp)
2224{
2225    ResetState(sp);
2226    sp->nextstate = sp->parsestate[E2A(c)];
2227    Bell(xw, XkbBI_MinorError, 0);
2228}
2229
2230static void
2231init_parser(XtermWidget xw, struct ParseState *sp)
2232{
2233    TScreen *screen = TScreenOf(xw);
2234
2235    free(sp->defer_area);
2236    free(sp->print_area);
2237    free(sp->string_area);
2238    memset(sp, 0, sizeof(*sp));
2239    sp->scssize = 94;		/* number of printable/nonspace ASCII */
2240    sp->lastchar = -1;		/* not a legal IChar */
2241    sp->nextstate = -1;		/* not a legal state */
2242
2243    init_groundtable(screen, sp);
2244    ResetState(sp);
2245}
2246
2247static void
2248init_reply(unsigned type)
2249{
2250    memset(&reply, 0, sizeof(reply));
2251    reply.a_type = (Char) type;
2252}
2253
2254static void
2255deferparsing(unsigned c, struct ParseState *sp)
2256{
2257    SafeAlloc(Char, sp->defer_area, sp->defer_used, sp->defer_size);
2258    if (new_string == 0) {
2259	xtermWarning("Cannot allocate %lu bytes for deferred parsing of %u\n",
2260		     (unsigned long) new_length, c);
2261	return;
2262    }
2263    SafeFree(sp->defer_area, sp->defer_size);
2264    sp->defer_area[(sp->defer_used)++] = CharOf(c);
2265}
2266
2267#if OPT_STATUS_LINE
2268typedef enum {
2269    SLnone = 0,			/* no status-line timer needed */
2270    SLclock = 1,		/* status-line updates once/second */
2271    SLcoords = 2,		/* status-line shows cursor-position */
2272    SLwritten = 3		/* status-line may need asynchonous repainting */
2273} SL_MODE;
2274
2275#define SL_BUFSIZ 80
2276
2277#if OPT_TRACE
2278static const char *
2279visibleStatusType(int code)
2280{
2281    const char *result = "?";
2282    switch (code) {
2283    case 0:
2284	result = "none";
2285	break;
2286    case 1:
2287	result = "indicator";
2288	break;
2289    case 2:
2290	result = "writable";
2291	break;
2292    }
2293    return result;
2294}
2295
2296static void
2297trace_status_line(XtermWidget xw, int lineno, const char *tag)
2298{
2299    TScreen *screen = TScreenOf(xw);
2300
2301    TRACE(("@%d, %s (%s, %s)%s%s @ (%d,%d) vs %d\n",
2302	   lineno,
2303	   tag,
2304	   screen->status_active ? "active" : "inactive",
2305	   visibleStatusType(screen->status_type),
2306	   ((screen->status_type != screen->status_shown)
2307	    ? " vs "
2308	    : ""),
2309	   ((screen->status_type != screen->status_shown)
2310	    ? visibleStatusType(screen->status_shown)
2311	    : ""),
2312	   screen->cur_row,
2313	   screen->cur_col,
2314	   LastRowNumber(screen)));
2315}
2316
2317#define TRACE_SL(tag) trace_status_line(xw, __LINE__, tag)
2318#else
2319#define TRACE_SL(tag)		/* nothing */
2320#endif
2321
2322static SL_MODE
2323find_SL_MODE(XtermWidget xw)
2324{
2325    TScreen *screen = TScreenOf(xw);
2326    SL_MODE result = SLnone;
2327    const char *parse;
2328
2329    for (parse = screen->status_fmt; *parse != '\0'; ++parse) {
2330	const char *found = parse;
2331	if (*parse == '%') {
2332	    if (*++parse == L_CURL) {
2333		const char *check = strchr(parse, '%');
2334		size_t length = 0;
2335
2336		if (check != NULL && check[1] == R_CURL) {
2337		    length = (size_t) (2 + check - found);
2338		} else {
2339		    length = strlen(found);
2340		}
2341
2342		if (!strncmp(found, "%{unixtime%}", length)) {
2343		    if (result == SLnone)
2344			result = SLclock;
2345		} else if (!strncmp(found, "%{position%}", length)) {
2346		    result = SLcoords;
2347		}
2348		parse = found + length - 1;
2349	    }
2350#if defined(HAVE_STRFTIME)
2351	    else if (*parse != '\0') {
2352		if (result == SLnone && strchr("cEgOrsSTX+", *parse) != NULL) {
2353		    result = SLclock;
2354		}
2355	    }
2356#endif
2357	}
2358    }
2359    return result;
2360}
2361
2362static long
2363find_SL_Timeout(XtermWidget xw)
2364{
2365    long result = 0;
2366    switch (find_SL_MODE(xw)) {
2367    case SLnone:
2368    case SLwritten:
2369	break;
2370    case SLclock:
2371	result = 1000;
2372	break;
2373    case SLcoords:
2374	result = 80;
2375	break;
2376    }
2377    return result;
2378}
2379
2380static void
2381StatusInit(SavedCursor * data)
2382{
2383    memset(data, 0, sizeof(*data));
2384    data->sgr_foreground = -1;
2385    data->sgr_background = -1;
2386}
2387
2388/* save the status-line position, restore main display */
2389static void
2390StatusSave(XtermWidget xw)
2391{
2392    TScreen *screen = TScreenOf(xw);
2393
2394    CursorSave2(xw, &screen->status_data[1]);
2395    CursorRestore2(xw, &screen->status_data[0]);
2396
2397    TRACE(("...StatusSave %d,%d -> %d,%d (main)\n",
2398	   screen->status_data[1].row,
2399	   screen->status_data[1].col,
2400	   screen->cur_row,
2401	   screen->cur_col));
2402}
2403
2404/* save the main-display position, restore status-line */
2405static void
2406StatusRestore(XtermWidget xw)
2407{
2408    TScreen *screen = TScreenOf(xw);
2409
2410    CursorSave2(xw, &screen->status_data[0]);
2411    CursorRestore2(xw, &screen->status_data[1]);
2412    screen->cur_row = FirstRowNumber(screen);
2413
2414    TRACE(("...StatusRestore %d,%d -> %d,%d (status)\n",
2415	   screen->status_data[0].row,
2416	   screen->status_data[0].col,
2417	   screen->cur_row,
2418	   screen->cur_col));
2419}
2420
2421static void
2422StatusPutChars(XtermWidget xw, const char *value, int length)
2423{
2424    TScreen *screen = TScreenOf(xw);
2425
2426    if (length < 0)
2427	length = (int) strlen(value);
2428
2429    while (length > 0) {
2430	IChar buffer[SL_BUFSIZ + 1];
2431	Cardinal n;
2432	for (n = 0; n < SL_BUFSIZ && length > 0 && *value != '\0'; ++n) {
2433	    buffer[n] = CharOf(*value++);
2434	    --length;
2435	}
2436	buffer[n] = 0;
2437	dotext(xw,
2438	       screen->gsets[(int) (screen->curgl)],
2439	       buffer, n);
2440    }
2441}
2442
2443static void
2444show_indicator_status(XtPointer closure, XtIntervalId * id GCC_UNUSED)
2445{
2446    XtermWidget xw = (XtermWidget) closure;
2447    TScreen *screen = TScreenOf(xw);
2448
2449    time_t now;
2450    const char *parse;
2451    char buffer[SL_BUFSIZ + 1];
2452    long interval;
2453
2454    if (screen->status_type != 1) {
2455	screen->status_timeout = False;
2456	return;
2457    }
2458    if (screen->status_active) {
2459	return;
2460    }
2461
2462    screen->status_active = True;
2463
2464    CursorSave2(xw, &screen->status_data[0]);
2465    screen->cur_row = FirstRowNumber(screen);
2466    screen->cur_col = 0;
2467
2468    xw->flags |= INVERSE;
2469    xw->flags &= (IFlags) (~WRAPAROUND);
2470
2471    now = time((time_t *) 0);
2472
2473    for (parse = screen->status_fmt; *parse != '\0'; ++parse) {
2474	const char *found = parse;
2475	if (*parse == '%') {
2476	    if (*++parse == L_CURL) {
2477		const char *check = strchr(parse, '%');
2478		size_t length = 0;
2479
2480		if (check != NULL && check[1] == R_CURL) {
2481		    length = (size_t) (2 + check - found);
2482		} else {
2483		    length = strlen(found);
2484		}
2485
2486		if (!strncmp(found, "%{version%}", length)) {
2487		    StatusPutChars(xw, xtermVersion(), -1);
2488		} else if (!strncmp(found, "%{unixtime%}", length)) {
2489		    char *t = x_strtrim(ctime(&now));
2490		    if (t != 0) {
2491			StatusPutChars(xw, t, -1);
2492			free(t);
2493		    }
2494		} else if (!strncmp(found, "%{position%}", length)) {
2495		    sprintf(buffer, "(%02d,%03d)",
2496			    screen->status_data[0].row + 1,
2497			    screen->status_data[0].col + 1);
2498		    StatusPutChars(xw, buffer, -1);
2499		} else {
2500		    StatusPutChars(xw, found, (int) length);
2501		}
2502		parse = found + length - 1;
2503	    }
2504#if defined(HAVE_STRFTIME)
2505	    else if (*parse != '\0') {
2506		char format[3];
2507		struct tm *tm = localtime(&now);
2508
2509		format[0] = '%';
2510		format[1] = *parse;
2511		format[2] = '\0';
2512		if (strftime(buffer, sizeof(buffer) - 1, format, tm) != 0) {
2513		    StatusPutChars(xw, buffer, -1);
2514		} else {
2515		    StatusPutChars(xw, "?", 1);
2516		    StatusPutChars(xw, parse - 1, 2);
2517		}
2518	    }
2519#endif
2520	} else {
2521	    StatusPutChars(xw, parse, 1);
2522	}
2523    }
2524    while (screen->cur_col < screen->max_col)
2525	StatusPutChars(xw, " ", 1);
2526
2527    ScrnRefresh(xw, FirstRowNumber(screen), 0, 1, screen->max_col, True);
2528    screen->status_active = False;
2529
2530    CursorRestore2(xw, &screen->status_data[0]);
2531
2532    /* if we processed a position or date/time, repeat */
2533    interval = find_SL_Timeout(xw);
2534    if (interval > 0) {
2535	(void) XtAppAddTimeOut(app_con,
2536			       (unsigned long) interval,
2537			       show_indicator_status, xw);
2538    }
2539    screen->status_timeout = True;
2540}
2541
2542static void
2543clear_status_line(XtermWidget xw)
2544{
2545    TScreen *screen = TScreenOf(xw);
2546    SavedCursor save_me;
2547    SavedCursor clearit;
2548    int save_type = screen->status_type;
2549
2550    TRACE_SL("clear_status_line");
2551    StatusInit(&clearit);
2552    CursorSave2(xw, &save_me);
2553    CursorRestore2(xw, &clearit);
2554
2555    screen->status_type = 2;
2556    set_cur_row(screen, LastRowNumber(screen));
2557#if 1
2558    ClearLine(xw);
2559#else
2560    if (getLineData(screen, screen->cur_row) != NULL) {
2561	int n;
2562	char buffer[SL_BUFSIZ + 1];
2563	CLineData *ld = getLineData(screen, screen->cur_row);
2564
2565	TRACE(("...text[%d:%d]:%s\n",
2566	       screen->cur_row,
2567	       LastRowNumber(screen),
2568	       visibleIChars(ld->charData, ld->lineSize)));
2569
2570	memset(buffer, '#', SL_BUFSIZ);
2571	for (n = 0; n < screen->max_col; n += SL_BUFSIZ) {
2572	    StatusPutChars(xw, buffer, screen->max_col - n);
2573	}
2574    }
2575#endif
2576    CursorRestore2(xw, &save_me);
2577    screen->status_type = save_type;
2578    TRACE_SL("clear_status_line (done)");
2579}
2580
2581static void
2582show_writable_status(XtermWidget xw)
2583{
2584    TScreen *screen = TScreenOf(xw);
2585
2586    TRACE(("show_writable_status (%d:%d) max=%d\n",
2587	   FirstRowNumber(screen),
2588	   LastRowNumber(screen),
2589	   MaxRows(screen)));
2590    screen->cur_row = FirstRowNumber(screen);
2591}
2592
2593/*
2594 * Depending the status-type, make the window grow or shrink by one row to
2595 * show or hide the status-line.  Keep the rest of the window from scrolling
2596 * by overriding the resize-gravity.
2597 */
2598static void
2599resize_status_line(XtermWidget xw)
2600{
2601    TScreen *screen = TScreenOf(xw);
2602    XtGravity savedGravity = xw->misc.resizeGravity;
2603
2604    TRACE_SL(screen->status_type
2605	     ? "...resize to show status-line"
2606	     : "...resize to hide status-line");
2607
2608    xw->misc.resizeGravity = NorthWestGravity;
2609
2610    RequestResize(xw, MaxRows(screen), MaxCols(screen), True);
2611
2612    xw->misc.resizeGravity = savedGravity;
2613}
2614
2615/*
2616 * DEC STD 070, chapter 14 "VSRM - Status Display Extension"
2617 */
2618static void
2619update_status_line(XtermWidget xw)
2620{
2621    TScreen *screen = TScreenOf(xw);
2622
2623    TRACE_SL("update_status_line");
2624
2625    if (screen->status_type == 1) {
2626	if (screen->status_type != screen->status_shown) {
2627	    if (screen->status_shown == 0) {
2628		resize_status_line(xw);
2629	    } else {
2630		clear_status_line(xw);
2631	    }
2632	    screen->status_shown = screen->status_type;
2633	    TRACE_SL("...updating shown");
2634	}
2635	show_indicator_status(xw, NULL);
2636    } else if (screen->status_active) {
2637	if (screen->status_type != screen->status_shown) {
2638	    Boolean do_resize = False;
2639
2640	    if (screen->status_type == 0) {
2641		if (screen->status_shown >= 2) {
2642		    StatusSave(xw);
2643		}
2644		do_resize = True;	/* shrink... */
2645		clear_status_line(xw);
2646		StatusInit(&screen->status_data[1]);
2647	    } else if (screen->status_shown == 0) {
2648		if (screen->status_type >= 2) {
2649		    StatusRestore(xw);
2650		}
2651		do_resize = True;	/* grow... */
2652	    } else {
2653		clear_status_line(xw);
2654	    }
2655	    if (do_resize) {
2656		resize_status_line(xw);
2657	    }
2658	    screen->status_shown = screen->status_type;
2659	    TRACE_SL("...updating shown");
2660	}
2661	show_writable_status(xw);
2662    } else {
2663	if (screen->status_shown) {
2664	    if (screen->status_type != 0 &&
2665		screen->status_type != screen->status_shown) {
2666		clear_status_line(xw);
2667	    }
2668	    if (screen->status_shown >= 2) {
2669		StatusSave(xw);
2670	    }
2671	    if (screen->status_type == 0) {
2672		screen->status_timeout = False;
2673		clear_status_line(xw);
2674		StatusInit(&screen->status_data[1]);
2675		resize_status_line(xw);		/* shrink... */
2676	    }
2677	    screen->status_shown = screen->status_type;
2678	    TRACE_SL("...updating shown");
2679	}
2680    }
2681    TRACE_SL("update_status_line (done)");
2682}
2683
2684/*
2685 * If the status-type is "2", we can switch the active status display back and
2686 * forth between the main-display and the status-line without clearing the
2687 * status-line (unless the status-line was not shown before).
2688 *
2689 * This has no effect if the status-line displays an indicator (type==1).
2690 */
2691static void
2692handle_DECSASD(XtermWidget xw, int value)
2693{
2694    TScreen *screen = TScreenOf(xw);
2695    Boolean updates = value ? True : False;
2696
2697    TRACE(("CASE_DECSASD - select active status display: %s (currently %s)\n",
2698	   BtoS(value),
2699	   BtoS(screen->status_active)));
2700
2701    if (screen->status_active != updates) {
2702	screen->status_active = updates;
2703	if (screen->status_type != 1) {
2704	    if (updates) {
2705		TRACE(("...@%d, saving main position %d,%d\n",
2706		       __LINE__, screen->cur_row, screen->cur_col));
2707		CursorSave2(xw, &screen->status_data[0]);
2708	    }
2709	    update_status_line(xw);
2710	}
2711    }
2712}
2713
2714/*
2715 * If the status-line is inactive (i.e., only the main-display is used),
2716 * changing the status-type between none/writable has no immediate effect.
2717 *
2718 * But if the status-line is active, setting the status-type reinitializes the
2719 * status-line.
2720 *
2721 * Setting the status-type to indicator overrides the DECSASD active-display
2722 * mode.
2723 */
2724static void
2725handle_DECSSDT(XtermWidget xw, int value)
2726{
2727    TScreen *screen = TScreenOf(xw);
2728
2729    TRACE(("CASE_DECSSDT - select type of status display: %d (currently %d)\n",
2730	   value,
2731	   screen->status_type));
2732    if (value <= 2) {
2733	screen->status_type = value;
2734	if (!screen->status_active) {
2735	    TRACE(("...@%d, saving main position %d,%d\n",
2736		   __LINE__, screen->cur_row, screen->cur_col));
2737	    CursorSave2(xw, &screen->status_data[0]);
2738	}
2739	update_status_line(xw);
2740    }
2741}
2742#endif
2743
2744#if OPT_VT52_MODE
2745static void
2746update_vt52_vt100_settings(void)
2747{
2748    update_autowrap();
2749    update_reversewrap();
2750    update_autolinefeed();
2751    update_appcursor();
2752    update_appkeypad();
2753    update_allow132();
2754}
2755#endif
2756
2757static Boolean
2758doparsing(XtermWidget xw, unsigned c, struct ParseState *sp)
2759{
2760    TScreen *screen = TScreenOf(xw);
2761    int item;
2762    int count;
2763    int value;
2764    int laststate;
2765    int thischar = -1;
2766    XTermRect myRect;
2767#if OPT_DEC_RECTOPS
2768    int thispage = 1;
2769#endif
2770
2771    if (sp->check_recur) {
2772	/* Defer parsing when parser is already running as the parser is not
2773	 * safe to reenter.
2774	 */
2775	deferparsing(c, sp);
2776	return True;
2777    }
2778    sp->check_recur++;
2779
2780    do {
2781#if OPT_WIDE_CHARS
2782	int this_is_wide = 0;
2783
2784	/*
2785	 * Handle zero-width combining characters.  Make it faster by noting
2786	 * that according to the Unicode charts, the majority of Western
2787	 * character sets do not use this feature.  There are some unassigned
2788	 * codes at 0x242, but no zero-width characters until past 0x300.
2789	 */
2790	if (c >= 0x300
2791	    && screen->wide_chars
2792	    && CharWidth(screen, c) == 0
2793	    && !isWideControl(c)) {
2794	    int prev, test;
2795	    Boolean used = True;
2796	    int use_row;
2797	    int use_col;
2798
2799	    WriteNow();
2800	    use_row = (screen->char_was_written
2801		       ? screen->last_written_row
2802		       : screen->cur_row);
2803	    use_col = (screen->char_was_written
2804		       ? screen->last_written_col
2805		       : screen->cur_col);
2806
2807	    /*
2808	     * Check if the latest data can be added to the base character.
2809	     * If there is already a combining character stored for the cell,
2810	     * we cannot, since that would change the order.
2811	     */
2812	    if (screen->normalized_c
2813		&& !IsCellCombined(screen, use_row, use_col)) {
2814		prev = (int) XTERM_CELL(use_row, use_col);
2815		test = do_precomposition(prev, (int) c);
2816		TRACE(("do_precomposition (U+%04X [%d], U+%04X [%d]) -> U+%04X [%d]\n",
2817		       prev, CharWidth(screen, prev),
2818		       (int) c, CharWidth(screen, c),
2819		       test, CharWidth(screen, test)));
2820	    } else {
2821		prev = -1;
2822		test = -1;
2823	    }
2824
2825	    /* substitute combined character with precomposed character
2826	     * only if it does not change the width of the base character
2827	     */
2828	    if (test != -1
2829		&& CharWidth(screen, test) == CharWidth(screen, prev)) {
2830		putXtermCell(screen, use_row, use_col, test);
2831	    } else if (screen->char_was_written
2832		       || getXtermCell(screen, use_row, use_col) >= ' ') {
2833		addXtermCombining(screen, use_row, use_col, c);
2834	    } else {
2835		/*
2836		 * none of the above... we will add the combining character as
2837		 * a base character.
2838		 */
2839		used = False;
2840	    }
2841
2842	    if (used) {
2843		if (!screen->scroll_amt)
2844		    ScrnUpdate(xw, use_row, use_col, 1, 1, 1);
2845		continue;
2846	    }
2847	}
2848#endif
2849
2850	/* Intercept characters for printer controller mode */
2851	if (PrinterOf(screen).printer_controlmode == 2) {
2852	    if ((c = (unsigned) xtermPrinterControl(xw, (int) c)) == 0)
2853		continue;
2854	}
2855
2856	/*
2857	 * VT52 is a little ugly in the one place it has a parameterized
2858	 * control sequence, since the parameter falls after the character
2859	 * that denotes the type of sequence.
2860	 */
2861#if OPT_VT52_MODE
2862	if (sp->vt52_cup) {
2863	    if (nparam < NPARAM - 1) {
2864		SetParam(nparam++, (int) (c & 0x7f) - 32);
2865		parms.is_sub[nparam] = 0;
2866	    }
2867	    if (nparam < 2)
2868		continue;
2869	    sp->vt52_cup = False;
2870	    CursorSet(screen, zero_if_default(0), zero_if_default(1), xw->flags);
2871	    sp->parsestate = vt52_table;
2872	    SetParam(0, 0);
2873	    SetParam(1, 0);
2874	    continue;
2875	}
2876#endif
2877
2878	laststate = sp->nextstate;
2879	if (c == ANSI_DEL
2880	    && sp->parsestate == sp->groundtable
2881	    && sp->scssize == 96
2882	    && sp->scstype != 0) {
2883	    /*
2884	     * Handle special case of shifts for 96-character sets by checking
2885	     * if we have a DEL.  The other special case for SPACE will always
2886	     * be printable.
2887	     */
2888	    sp->nextstate = CASE_PRINT;
2889	} else
2890#if OPT_WIDE_CHARS
2891	if (c > 255) {
2892	    /*
2893	     * The parsing tables all have 256 entries.  If we're supporting
2894	     * wide characters, we handle them by treating them the same as
2895	     * printing characters.
2896	     */
2897	    if (sp->parsestate == sp->groundtable) {
2898		sp->nextstate = CASE_PRINT;
2899	    } else if (sp->parsestate == sos_table) {
2900		c &= WIDEST_ICHAR;
2901		if (c > 255) {
2902		    TRACE(("Found code > 255 while in SOS state: %04X\n", c));
2903		    c = BAD_ASCII;
2904		}
2905	    } else {
2906		sp->nextstate = CASE_GROUND_STATE;
2907	    }
2908	} else
2909#endif
2910	    sp->nextstate = sp->parsestate[E2A(c)];
2911
2912#if OPT_BROKEN_OSC
2913	/*
2914	 * Linux console palette escape sequences start with an OSC, but do
2915	 * not terminate correctly.  Some scripts do not check before writing
2916	 * them, making xterm appear to hang (it's awaiting a valid string
2917	 * terminator).  Just ignore these if we see them - there's no point
2918	 * in emulating bad code.
2919	 */
2920	if (screen->brokenLinuxOSC
2921	    && sp->parsestate == sos_table) {
2922	    if (sp->string_used) {
2923		switch (sp->string_area[0]) {
2924		case 'P':
2925		    if (sp->string_used <= 7)
2926			break;
2927		    /* FALLTHRU */
2928		case 'R':
2929		    illegal_parse(xw, c, sp);
2930		    TRACE(("Reset to ground state (brokenLinuxOSC)\n"));
2931		    break;
2932		}
2933	    }
2934	}
2935#endif
2936
2937#if OPT_BROKEN_ST
2938	/*
2939	 * Before patch #171, carriage control embedded within an OSC string
2940	 * would terminate it.  Some (buggy, of course) applications rely on
2941	 * this behavior.  Accommodate them by allowing one to compile xterm
2942	 * and emulate the old behavior.
2943	 */
2944	if (screen->brokenStringTerm
2945	    && sp->parsestate == sos_table
2946	    && c < 32) {
2947	    switch (c) {
2948	    case ANSI_EOT:	/* FALLTHRU */
2949	    case ANSI_BS:	/* FALLTHRU */
2950	    case ANSI_HT:	/* FALLTHRU */
2951	    case ANSI_LF:	/* FALLTHRU */
2952	    case ANSI_VT:	/* FALLTHRU */
2953	    case ANSI_FF:	/* FALLTHRU */
2954	    case ANSI_CR:	/* FALLTHRU */
2955	    case ANSI_SO:	/* FALLTHRU */
2956	    case ANSI_SI:	/* FALLTHRU */
2957	    case ANSI_XON:	/* FALLTHRU */
2958	    case ANSI_CAN:
2959		illegal_parse(xw, c, sp);
2960		TRACE(("Reset to ground state (brokenStringTerm)\n"));
2961		break;
2962	    }
2963	}
2964#endif
2965
2966#if OPT_C1_PRINT
2967	/*
2968	 * This is not completely foolproof, but will allow an application
2969	 * with values in the C1 range to use them as printable characters,
2970	 * provided that they are not intermixed with an escape sequence.
2971	 */
2972	if (screen->c1_printable
2973	    && (c >= 128 && c < 256)) {
2974	    sp->nextstate = (sp->parsestate == esc_table
2975			     ? CASE_ESC_IGNORE
2976			     : sp->parsestate[E2A(160)]);
2977	    TRACE(("allowC1Printable %04X %s ->%s\n",
2978		   c, which_table(sp->parsestate),
2979		   visibleVTparse(sp->nextstate)));
2980	}
2981#endif
2982
2983#if OPT_WIDE_CHARS
2984	/*
2985	 * If we have a C1 code and the c1_printable flag is not set, simply
2986	 * ignore it when it was translated from UTF-8.  That is because the
2987	 * value could not have been present as-is in the UTF-8.
2988	 *
2989	 * To see that CASE_IGNORE is a consistent value, note that it is
2990	 * always used for NUL and other uninteresting C0 controls.
2991	 */
2992#if OPT_C1_PRINT
2993	if (!screen->c1_printable)
2994#endif
2995	    if (screen->wide_chars
2996		&& (c >= 128 && c < 160)) {
2997		sp->nextstate = CASE_IGNORE;
2998	    }
2999
3000	/*
3001	 * If this character is a different width than the last one, put the
3002	 * previous text into the buffer and draw it now.
3003	 */
3004	this_is_wide = isWide((int) c);
3005	if (this_is_wide != sp->last_was_wide) {
3006	    WriteNow();
3007	}
3008#endif
3009
3010	/*
3011	 * Accumulate string for printable text.  This may be 8/16-bit
3012	 * characters.
3013	 */
3014	if (sp->nextstate == CASE_PRINT) {
3015	    SafeAlloc(IChar, sp->print_area, sp->print_used, sp->print_size);
3016	    if (new_string == 0) {
3017		xtermWarning("Cannot allocate %lu bytes for printable text\n",
3018			     (unsigned long) new_length);
3019		continue;
3020	    }
3021	    SafeFree(sp->print_area, sp->print_size);
3022#if OPT_VT52_MODE
3023	    /*
3024	     * Strip output text to 7-bits for VT52.  We should do this for
3025	     * VT100 also (which is a 7-bit device), but xterm has been
3026	     * doing this for so long we shouldn't change this behavior.
3027	     */
3028	    if (screen->vtXX_level < 1)
3029		c &= 0x7f;
3030#endif
3031	    sp->print_area[sp->print_used++] = (IChar) c;
3032	    sp->lastchar = thischar = (int) c;
3033#if OPT_WIDE_CHARS
3034	    sp->last_was_wide = this_is_wide;
3035#endif
3036	    if (morePtyData(screen, VTbuffer)) {
3037		continue;
3038	    }
3039	}
3040
3041	if (sp->nextstate == CASE_PRINT
3042	    || (laststate == CASE_PRINT && sp->print_used)) {
3043	    WriteNow();
3044	}
3045
3046	/*
3047	 * Accumulate string for APC, DCS, PM, OSC, SOS controls
3048	 * This should always be 8-bit characters.
3049	 */
3050	if (sp->parsestate == sos_table) {
3051	    SafeAlloc(Char, sp->string_area, sp->string_used, sp->string_size);
3052	    if (new_string == 0) {
3053		xtermWarning("Cannot allocate %lu bytes for string mode %d\n",
3054			     (unsigned long) new_length, sp->string_mode);
3055		continue;
3056	    }
3057	    SafeFree(sp->string_area, sp->string_size);
3058#if OPT_WIDE_CHARS
3059	    /*
3060	     * We cannot display codes above 255, but let's try to
3061	     * accommodate the application a little by not aborting the
3062	     * string.
3063	     */
3064	    if ((c & WIDEST_ICHAR) > 255) {
3065		sp->nextstate = CASE_PRINT;
3066		c = BAD_ASCII;
3067	    }
3068#endif
3069	    sp->string_area[(sp->string_used)++] = CharOf(c);
3070	} else if (sp->parsestate != esc_table) {
3071	    /* if we were accumulating, we're not any more */
3072	    sp->string_mode = 0;
3073	    sp->string_used = 0;
3074	}
3075
3076	DumpParams();
3077	TRACE(("parse %04X -> %s %s (used=%lu)\n",
3078	       c, visibleVTparse(sp->nextstate),
3079	       which_table(sp->parsestate),
3080	       (unsigned long) sp->string_used));
3081
3082	/*
3083	 * If the parameter list has subparameters (tokens separated by ":")
3084	 * reject any controls that do not accept subparameters.
3085	 */
3086	if (parms.has_subparams) {
3087	    switch (sp->nextstate) {
3088	    case CASE_GROUND_STATE:
3089	    case CASE_CSI_IGNORE:
3090		/* FALLTHRU */
3091
3092	    case CASE_ESC_DIGIT:
3093	    case CASE_ESC_SEMI:
3094	    case CASE_ESC_COLON:
3095		/* these states are required to parse parameter lists */
3096		break;
3097
3098	    case CASE_SGR:
3099		TRACE(("...possible subparam usage\n"));
3100		break;
3101
3102	    case CASE_CSI_DEC_DOLLAR_STATE:
3103	    case CASE_CSI_DOLLAR_STATE:
3104	    case CASE_CSI_HASH_STATE:
3105	    case CASE_CSI_EX_STATE:
3106	    case CASE_CSI_QUOTE_STATE:
3107	    case CASE_CSI_SPACE_STATE:
3108	    case CASE_CSI_STAR_STATE:
3109	    case CASE_CSI_TICK_STATE:
3110	    case CASE_DEC2_STATE:
3111	    case CASE_DEC3_STATE:
3112	    case CASE_DEC_STATE:
3113		/* use this branch when we do not yet have the final character */
3114		TRACE(("...unexpected subparam usage\n"));
3115		InitParams();
3116		sp->nextstate = CASE_CSI_IGNORE;
3117		break;
3118
3119	    default:
3120		/* use this branch for cases where we have the final character
3121		 * in the table that processed the parameter list.
3122		 */
3123		TRACE(("...unexpected subparam usage\n"));
3124		ResetState(sp);
3125		continue;
3126	    }
3127	}
3128
3129	if (xw->work.palette_changed) {
3130	    repaintWhenPaletteChanged(xw, sp);
3131	}
3132
3133	switch (sp->nextstate) {
3134	case CASE_PRINT:
3135	    TRACE(("CASE_PRINT - printable characters\n"));
3136	    break;
3137
3138	case CASE_GROUND_STATE:
3139	    TRACE(("CASE_GROUND_STATE - exit ignore mode\n"));
3140	    ResetState(sp);
3141	    break;
3142
3143	case CASE_IGNORE:
3144	    TRACE(("CASE_IGNORE - Ignore character %02X\n", c));
3145	    break;
3146
3147	case CASE_ENQ:
3148	    TRACE(("CASE_ENQ - answerback\n"));
3149	    if (((xw->keyboard.flags & MODE_SRM) == 0)
3150		? (sp->check_recur == 0)
3151		: (sp->check_recur <= 1)) {
3152		for (count = 0; screen->answer_back[count] != 0; count++)
3153		    unparseputc(xw, screen->answer_back[count]);
3154		unparse_end(xw);
3155	    }
3156	    break;
3157
3158	case CASE_BELL:
3159	    TRACE(("CASE_BELL - bell\n"));
3160	    if (sp->string_mode == ANSI_OSC) {
3161		if (sp->string_used)
3162		    sp->string_area[--(sp->string_used)] = '\0';
3163		if (sp->check_recur <= 1)
3164		    do_osc(xw, sp->string_area, sp->string_used, (int) c);
3165		ResetState(sp);
3166	    } else {
3167		/* bell */
3168		Bell(xw, XkbBI_TerminalBell, 0);
3169	    }
3170	    break;
3171
3172	case CASE_BS:
3173	    TRACE(("CASE_BS - backspace\n"));
3174	    CursorBack(xw, 1);
3175	    break;
3176
3177	case CASE_CR:
3178	    TRACE(("CASE_CR\n"));
3179	    CarriageReturn(xw);
3180	    break;
3181
3182	case CASE_ESC:
3183	    if_OPT_VT52_MODE(screen, {
3184		sp->parsestate = vt52_esc_table;
3185		break;
3186	    });
3187	    sp->parsestate = esc_table;
3188	    break;
3189
3190#if OPT_VT52_MODE
3191	case CASE_VT52_CUP:
3192	    TRACE(("CASE_VT52_CUP - VT52 cursor addressing\n"));
3193	    sp->vt52_cup = True;
3194	    ResetState(sp);
3195	    break;
3196
3197	case CASE_VT52_IGNORE:
3198	    TRACE(("CASE_VT52_IGNORE - VT52 ignore-character\n"));
3199	    sp->parsestate = vt52_ignore_table;
3200	    break;
3201#endif
3202
3203	case CASE_VMOT:
3204	    TRACE(("CASE_VMOT\n"));
3205	    /*
3206	     * form feed, line feed, vertical tab
3207	     */
3208	    xtermAutoPrint(xw, c);
3209	    xtermIndex(xw, 1);
3210	    if (xw->flags & LINEFEED)
3211		CarriageReturn(xw);
3212	    else
3213		do_xevents(xw);
3214	    break;
3215
3216	case CASE_CBT:
3217	    TRACE(("CASE_CBT\n"));
3218	    /* cursor backward tabulation */
3219	    count = one_if_default(0);
3220	    while ((count-- > 0)
3221		   && (TabToPrevStop(xw))) ;
3222	    ResetState(sp);
3223	    break;
3224
3225	case CASE_CHT:
3226	    TRACE(("CASE_CHT\n"));
3227	    /* cursor forward tabulation */
3228	    count = one_if_default(0);
3229	    while ((count-- > 0)
3230		   && (TabToNextStop(xw))) ;
3231	    ResetState(sp);
3232	    break;
3233
3234	case CASE_TAB:
3235	    /* tab */
3236	    TabToNextStop(xw);
3237	    break;
3238
3239	case CASE_SI:
3240	    screen->curgl = 0;
3241	    if_OPT_VT52_MODE(screen, {
3242		ResetState(sp);
3243	    });
3244	    break;
3245
3246	case CASE_SO:
3247	    screen->curgl = 1;
3248	    if_OPT_VT52_MODE(screen, {
3249		ResetState(sp);
3250	    });
3251	    break;
3252
3253	case CASE_DECDHL:
3254	    xterm_DECDHL(xw, c == '3');
3255	    ResetState(sp);
3256	    break;
3257
3258	case CASE_DECSWL:
3259	    xterm_DECSWL(xw);
3260	    ResetState(sp);
3261	    break;
3262
3263	case CASE_DECDWL:
3264	    xterm_DECDWL(xw);
3265	    ResetState(sp);
3266	    break;
3267
3268	case CASE_SCR_STATE:
3269	    /* enter scr state */
3270	    sp->parsestate = scrtable;
3271	    break;
3272
3273	case CASE_SCS0_STATE:
3274	    /* enter scs state 0 */
3275	    select_charset(sp, 0, 94);
3276	    break;
3277
3278	case CASE_SCS1_STATE:
3279	    /* enter scs state 1 */
3280	    select_charset(sp, 1, 94);
3281	    break;
3282
3283	case CASE_SCS2_STATE:
3284	    /* enter scs state 2 */
3285	    select_charset(sp, 2, 94);
3286	    break;
3287
3288	case CASE_SCS3_STATE:
3289	    /* enter scs state 3 */
3290	    select_charset(sp, 3, 94);
3291	    break;
3292
3293	case CASE_SCS1A_STATE:
3294	    /* enter scs state 1 */
3295	    select_charset(sp, 1, 96);
3296	    break;
3297
3298	case CASE_SCS2A_STATE:
3299	    /* enter scs state 2 */
3300	    select_charset(sp, 2, 96);
3301	    break;
3302
3303	case CASE_SCS3A_STATE:
3304	    /* enter scs state 3 */
3305	    select_charset(sp, 3, 96);
3306	    break;
3307
3308	case CASE_ESC_IGNORE:
3309	    /* unknown escape sequence */
3310	    sp->parsestate = eigtable;
3311	    break;
3312
3313	case CASE_ESC_DIGIT:
3314	    /* digit in csi or dec mode */
3315	    if (nparam > 0) {
3316		value = zero_if_default(nparam - 1);
3317		SetParam(nparam - 1, (10 * value) + ((int) c - '0'));
3318		if (GetParam(nparam - 1) > MAX_I_PARAM)
3319		    SetParam(nparam - 1, MAX_I_PARAM);
3320		if (sp->parsestate == csi_table)
3321		    sp->parsestate = csi2_table;
3322	    }
3323	    break;
3324
3325	case CASE_ESC_SEMI:
3326	    /* semicolon in csi or dec mode */
3327	    if (nparam < NPARAM) {
3328		parms.is_sub[nparam] = 0;
3329		SetParam(nparam++, DEFAULT);
3330	    }
3331	    if (sp->parsestate == csi_table)
3332		sp->parsestate = csi2_table;
3333	    break;
3334
3335	    /*
3336	     * A _few_ commands accept colon-separated subparameters.
3337	     * Mark the parameter list so that we can exclude (most) bogus
3338	     * commands with simple/fast checks.
3339	     */
3340	case CASE_ESC_COLON:
3341	    if (nparam < NPARAM) {
3342		parms.has_subparams = 1;
3343		if (nparam == 0) {
3344		    parms.is_sub[nparam] = 1;
3345		    SetParam(nparam++, DEFAULT);
3346		} else if (parms.is_sub[nparam - 1] == 0) {
3347		    parms.is_sub[nparam - 1] = 1;
3348		    parms.is_sub[nparam] = 2;
3349		    parms.params[nparam] = 0;
3350		    ++nparam;
3351		} else {
3352		    parms.is_sub[nparam] = 1 + parms.is_sub[nparam - 1];
3353		    parms.params[nparam] = 0;
3354		    ++nparam;
3355		}
3356	    }
3357	    break;
3358
3359	case CASE_DEC_STATE:
3360	    /* enter dec mode */
3361	    sp->parsestate = dec_table;
3362	    break;
3363
3364	case CASE_DEC2_STATE:
3365	    /* enter dec2 mode */
3366	    sp->parsestate = dec2_table;
3367	    break;
3368
3369	case CASE_DEC3_STATE:
3370	    /* enter dec3 mode */
3371	    sp->parsestate = dec3_table;
3372	    break;
3373
3374	case CASE_ICH:
3375	    TRACE(("CASE_ICH - insert char\n"));
3376	    InsertChar(xw, (unsigned) one_if_default(0));
3377	    ResetState(sp);
3378	    break;
3379
3380	case CASE_CUU:
3381	    TRACE(("CASE_CUU - cursor up\n"));
3382	    CursorUp(screen, one_if_default(0));
3383	    ResetState(sp);
3384	    break;
3385
3386	case CASE_CUD:
3387	    TRACE(("CASE_CUD - cursor down\n"));
3388	    CursorDown(screen, one_if_default(0));
3389	    ResetState(sp);
3390	    break;
3391
3392	case CASE_CUF:
3393	    TRACE(("CASE_CUF - cursor forward\n"));
3394	    CursorForward(xw, one_if_default(0));
3395	    ResetState(sp);
3396	    break;
3397
3398	case CASE_CUB:
3399	    TRACE(("CASE_CUB - cursor backward\n"));
3400	    CursorBack(xw, one_if_default(0));
3401	    ResetState(sp);
3402	    break;
3403
3404	case CASE_CUP:
3405	    TRACE(("CASE_CUP - cursor position\n"));
3406	    if_OPT_XMC_GLITCH(screen, {
3407		Jump_XMC(xw);
3408	    });
3409	    CursorSet(screen, one_if_default(0) - 1, one_if_default(1) - 1, xw->flags);
3410	    ResetState(sp);
3411	    break;
3412
3413	case CASE_VPA:
3414	    TRACE(("CASE_VPA - vertical position absolute\n"));
3415	    CursorSet(screen, one_if_default(0) - 1, CursorCol(xw), xw->flags);
3416	    ResetState(sp);
3417	    break;
3418
3419	case CASE_HPA:
3420	    TRACE(("CASE_HPA - horizontal position absolute\n"));
3421	    CursorSet(screen, CursorRow(xw), one_if_default(0) - 1, xw->flags);
3422	    ResetState(sp);
3423	    break;
3424
3425	case CASE_VPR:
3426	    TRACE(("CASE_VPR - vertical position relative\n"));
3427	    CursorSet(screen,
3428		      CursorRow(xw) + one_if_default(0),
3429		      CursorCol(xw),
3430		      xw->flags);
3431	    ResetState(sp);
3432	    break;
3433
3434	case CASE_HPR:
3435	    TRACE(("CASE_HPR - horizontal position relative\n"));
3436	    CursorSet(screen,
3437		      CursorRow(xw),
3438		      CursorCol(xw) + one_if_default(0),
3439		      xw->flags);
3440	    ResetState(sp);
3441	    break;
3442
3443	case CASE_HP_BUGGY_LL:
3444	    TRACE(("CASE_HP_BUGGY_LL\n"));
3445	    /* Some HP-UX applications have the bug that they
3446	       assume ESC F goes to the lower left corner of
3447	       the screen, regardless of what terminfo says. */
3448	    if (screen->hp_ll_bc)
3449		CursorSet(screen, screen->max_row, 0, xw->flags);
3450	    ResetState(sp);
3451	    break;
3452
3453	case CASE_ED:
3454	    TRACE(("CASE_ED - erase display\n"));
3455	    do_cd_xtra_scroll(xw, zero_if_default(0));
3456	    do_erase_display(xw, zero_if_default(0), OFF_PROTECT);
3457	    ResetState(sp);
3458	    break;
3459
3460	case CASE_EL:
3461	    TRACE(("CASE_EL - erase line\n"));
3462	    do_erase_line(xw, zero_if_default(0), OFF_PROTECT);
3463	    ResetState(sp);
3464	    break;
3465
3466	case CASE_ECH:
3467	    TRACE(("CASE_ECH - erase char\n"));
3468	    /* ECH */
3469	    do_erase_char(xw, one_if_default(0), OFF_PROTECT);
3470	    ResetState(sp);
3471	    break;
3472
3473	case CASE_IL:
3474	    TRACE(("CASE_IL - insert line\n"));
3475	    InsertLine(xw, one_if_default(0));
3476	    ResetState(sp);
3477	    break;
3478
3479	case CASE_DL:
3480	    TRACE(("CASE_DL - delete line\n"));
3481	    DeleteLine(xw, one_if_default(0), True);
3482	    ResetState(sp);
3483	    break;
3484
3485	case CASE_DCH:
3486	    TRACE(("CASE_DCH - delete char\n"));
3487	    DeleteChar(xw, (unsigned) one_if_default(0));
3488	    ResetState(sp);
3489	    break;
3490
3491	case CASE_TRACK_MOUSE:
3492	    /*
3493	     * A single parameter other than zero is always scroll-down.
3494	     * A zero-parameter is used to reset the mouse mode, and is
3495	     * not useful for scrolling anyway.
3496	     */
3497	    if (nparam > 1 || GetParam(0) == 0) {
3498		CELL start;
3499
3500		TRACE(("CASE_TRACK_MOUSE\n"));
3501		/* Track mouse as long as in window and between
3502		 * specified rows
3503		 */
3504		start.row = one_if_default(2) - 1;
3505		start.col = GetParam(1) - 1;
3506		TrackMouse(xw,
3507			   GetParam(0),
3508			   &start,
3509			   GetParam(3) - 1, GetParam(4) - 2);
3510	    } else {
3511		TRACE(("CASE_SD - scroll down\n"));
3512		/* SD */
3513		RevScroll(xw, one_if_default(0));
3514		do_xevents(xw);
3515	    }
3516	    ResetState(sp);
3517	    break;
3518
3519	case CASE_SD:
3520	    /*
3521	     * Cater to ECMA-48's typographical error...
3522	     */
3523	    TRACE(("CASE_SD - scroll down\n"));
3524	    RevScroll(xw, one_if_default(0));
3525	    do_xevents(xw);
3526	    ResetState(sp);
3527	    break;
3528
3529	case CASE_DECID:
3530	    TRACE(("CASE_DECID\n"));
3531	    if_OPT_VT52_MODE(screen, {
3532		unparseputc(xw, ANSI_ESC);
3533		unparseputc(xw, '/');
3534		unparseputc(xw, 'Z');
3535		unparse_end(xw);
3536		ResetState(sp);
3537		break;
3538	    });
3539	    SetParam(0, DEFAULT);	/* Default ID parameter */
3540	    /* FALLTHRU */
3541	case CASE_DA1:
3542	    TRACE(("CASE_DA1\n"));
3543	    if (GetParam(0) <= 0) {	/* less than means DEFAULT */
3544		count = 0;
3545		init_reply(ANSI_CSI);
3546		reply.a_pintro = '?';
3547
3548		/*
3549		 * The first parameter corresponds to the highest operating
3550		 * level (i.e., service level) of the emulation.  A DEC
3551		 * terminal can be setup to respond with a different DA
3552		 * response, but there's no control sequence that modifies
3553		 * this.  We set it via a resource.
3554		 */
3555		if (screen->terminal_id < 200) {
3556		    switch (screen->terminal_id) {
3557		    case 132:
3558			reply.a_param[count++] = 4;	/* VT132 */
3559#if OPT_REGIS_GRAPHICS
3560			reply.a_param[count++] = 6;	/* no STP, AVO, GPO (ReGIS) */
3561#else
3562			reply.a_param[count++] = 2;	/* no STP, AVO, no GPO (ReGIS) */
3563#endif
3564			break;
3565		    case 131:
3566			reply.a_param[count++] = 7;	/* VT131 */
3567			break;
3568		    case 125:
3569			reply.a_param[count++] = 12;	/* VT125 */
3570#if OPT_REGIS_GRAPHICS
3571			reply.a_param[count++] = 0 | 2 | 1;	/* no STP, AVO, GPO (ReGIS) */
3572#else
3573			reply.a_param[count++] = 0 | 2 | 0;	/* no STP, AVO, no GPO (ReGIS) */
3574#endif
3575			reply.a_param[count++] = 0;	/* no printer */
3576			reply.a_param[count++] = XTERM_PATCH;	/* ROM version */
3577			break;
3578		    case 102:
3579			reply.a_param[count++] = 6;	/* VT102 */
3580			break;
3581		    case 101:
3582			reply.a_param[count++] = 1;	/* VT101 */
3583			reply.a_param[count++] = 0;	/* no options */
3584			break;
3585		    default:	/* VT100 */
3586			reply.a_param[count++] = 1;	/* VT100 */
3587			reply.a_param[count++] = 2;	/* no STP, AVO, no GPO (ReGIS) */
3588			break;
3589		    }
3590		} else {
3591		    reply.a_param[count++] = (ParmType) (60
3592							 + screen->terminal_id
3593							 / 100);
3594		    reply.a_param[count++] = 1;		/* 132-columns */
3595		    reply.a_param[count++] = 2;		/* printer */
3596#if OPT_REGIS_GRAPHICS
3597		    if (optRegisGraphics(screen)) {
3598			reply.a_param[count++] = 3;	/* ReGIS graphics */
3599		    }
3600#endif
3601#if OPT_SIXEL_GRAPHICS
3602		    if (optSixelGraphics(screen)) {
3603			reply.a_param[count++] = 4;	/* sixel graphics */
3604		    }
3605#endif
3606		    reply.a_param[count++] = 6;		/* selective-erase */
3607#if OPT_SUNPC_KBD
3608		    if (xw->keyboard.type == keyboardIsVT220)
3609#endif
3610			reply.a_param[count++] = 8;	/* user-defined-keys */
3611		    reply.a_param[count++] = 9;		/* national replacement charsets */
3612		    reply.a_param[count++] = 15;	/* technical characters */
3613		    reply.a_param[count++] = 16;	/* locator port */
3614		    if (screen->terminal_id >= 400) {
3615			reply.a_param[count++] = 17;	/* terminal state interrogation */
3616			reply.a_param[count++] = 18;	/* windowing extension */
3617			reply.a_param[count++] = 21;	/* horizontal scrolling */
3618		    }
3619		    if_OPT_ISO_COLORS(screen, {
3620			reply.a_param[count++] = 22;	/* ANSI color, VT525 */
3621		    });
3622		    reply.a_param[count++] = 28;	/* rectangular editing */
3623#if OPT_DEC_LOCATOR
3624		    reply.a_param[count++] = 29;	/* ANSI text locator */
3625#endif
3626		}
3627		reply.a_nparam = (ParmType) count;
3628		reply.a_inters = 0;
3629		reply.a_final = 'c';
3630		unparseseq(xw, &reply);
3631	    }
3632	    ResetState(sp);
3633	    break;
3634
3635	case CASE_DA2:
3636	    TRACE(("CASE_DA2\n"));
3637	    if (GetParam(0) <= 0) {	/* less than means DEFAULT */
3638		count = 0;
3639		init_reply(ANSI_CSI);
3640		reply.a_pintro = '>';
3641
3642		if (screen->terminal_id >= 200) {
3643		    switch (screen->terminal_id) {
3644		    case 220:
3645		    default:
3646			reply.a_param[count++] = 1;	/* VT220 */
3647			break;
3648		    case 240:
3649		    case 241:
3650			/* http://www.decuslib.com/DECUS/vax87a/gendyn/vt200_kind.lis */
3651			reply.a_param[count++] = 2;	/* VT240 */
3652			break;
3653		    case 320:
3654			/* http://www.vt100.net/docs/vt320-uu/appendixe.html */
3655			reply.a_param[count++] = 24;	/* VT320 */
3656			break;
3657		    case 330:
3658			reply.a_param[count++] = 18;	/* VT330 */
3659			break;
3660		    case 340:
3661			reply.a_param[count++] = 19;	/* VT340 */
3662			break;
3663		    case 382:
3664			reply.a_param[count++] = 32;	/* VT382 */
3665			break;
3666		    case 420:
3667			reply.a_param[count++] = 41;	/* VT420 */
3668			break;
3669		    case 510:
3670			/* http://www.vt100.net/docs/vt510-rm/DA2 */
3671			reply.a_param[count++] = 61;	/* VT510 */
3672			break;
3673		    case 520:
3674			reply.a_param[count++] = 64;	/* VT520 */
3675			break;
3676		    case 525:
3677			reply.a_param[count++] = 65;	/* VT525 */
3678			break;
3679		    }
3680		} else {
3681		    reply.a_param[count++] = 0;		/* VT100 (nonstandard) */
3682		}
3683		reply.a_param[count++] = XTERM_PATCH;	/* Version */
3684		reply.a_param[count++] = 0;	/* options (none) */
3685		reply.a_nparam = (ParmType) count;
3686		reply.a_inters = 0;
3687		reply.a_final = 'c';
3688		unparseseq(xw, &reply);
3689	    }
3690	    ResetState(sp);
3691	    break;
3692
3693	case CASE_DECRPTUI:
3694	    TRACE(("CASE_DECRPTUI\n"));
3695	    if ((screen->vtXX_level >= 4)
3696		&& (GetParam(0) <= 0)) {	/* less than means DEFAULT */
3697		unparseputc1(xw, ANSI_DCS);
3698		unparseputc(xw, '!');
3699		unparseputc(xw, '|');
3700		/* report the "terminal unit id" as 4 pairs of hexadecimal
3701		 * digits -- meaningless for a terminal emulator, but some
3702		 * host may care about the format.
3703		 */
3704		for (count = 0; count < 8; ++count) {
3705		    unparseputc(xw, '0');
3706		}
3707		unparseputc1(xw, ANSI_ST);
3708		unparse_end(xw);
3709	    }
3710	    ResetState(sp);
3711	    break;
3712
3713	case CASE_TBC:
3714	    TRACE(("CASE_TBC - tab clear\n"));
3715	    if ((value = GetParam(0)) <= 0)	/* less than means default */
3716		TabClear(xw->tabs, screen->cur_col);
3717	    else if (value == 3)
3718		TabZonk(xw->tabs);
3719	    ResetState(sp);
3720	    break;
3721
3722	case CASE_SET:
3723	    TRACE(("CASE_SET - set mode\n"));
3724	    ansi_modes(xw, bitset);
3725	    ResetState(sp);
3726	    break;
3727
3728	case CASE_RST:
3729	    TRACE(("CASE_RST - reset mode\n"));
3730	    ansi_modes(xw, bitclr);
3731	    ResetState(sp);
3732	    break;
3733
3734	case CASE_SGR:
3735	    for (item = 0; item < nparam; ++item) {
3736		int op = GetParam(item);
3737		int skip;
3738
3739		if_OPT_XMC_GLITCH(screen, {
3740		    Mark_XMC(xw, op);
3741		});
3742		TRACE(("CASE_SGR %d\n", op));
3743
3744		/*
3745		 * Only SGR 38/48 accept subparameters, and in those cases
3746		 * the values will not be seen at this point.
3747		 */
3748		if ((skip = param_has_subparams(item))) {
3749		    switch (op) {
3750		    case 38:
3751			/* FALLTHRU */
3752		    case 48:
3753			if_OPT_ISO_COLORS(screen, {
3754			    break;
3755			});
3756			/* FALLTHRU */
3757		    default:
3758			TRACE(("...unexpected subparameter in SGR\n"));
3759			item += skip;	/* ignore this */
3760			op = NPARAM;	/* will never use this, anyway */
3761			break;
3762		    }
3763		}
3764
3765		switch (op) {
3766		case DEFAULT:
3767		    /* FALLTHRU */
3768		case 0:
3769		    resetRendition(xw);
3770		    if_OPT_ISO_COLORS(screen, {
3771			reset_SGR_Colors(xw);
3772		    });
3773		    break;
3774		case 1:	/* Bold                 */
3775		    UIntSet(xw->flags, BOLD);
3776		    if_OPT_ISO_COLORS(screen, {
3777			setExtendedFG(xw);
3778		    });
3779		    break;
3780#if OPT_WIDE_ATTRS
3781		case 2:	/* faint, decreased intensity or second colour */
3782		    UIntSet(xw->flags, ATR_FAINT);
3783		    if_OPT_ISO_COLORS(screen, {
3784			setExtendedFG(xw);
3785		    });
3786		    break;
3787		case 3:	/* italicized */
3788		    setItalicFont(xw, UseItalicFont(screen));
3789		    UIntSet(xw->flags, ATR_ITALIC);
3790		    if_OPT_ISO_COLORS(screen, {
3791			setExtendedFG(xw);
3792		    });
3793		    break;
3794#endif
3795		case 4:	/* Underscore           */
3796		    UIntSet(xw->flags, UNDERLINE);
3797		    if_OPT_ISO_COLORS(screen, {
3798			setExtendedFG(xw);
3799		    });
3800		    break;
3801		case 5:	/* Blink (less than 150 per minute) */
3802		    /* FALLTHRU */
3803		case 6:	/* Blink (150 per minute, or more) */
3804		    UIntSet(xw->flags, BLINK);
3805		    StartBlinking(xw);
3806		    if_OPT_ISO_COLORS(screen, {
3807			setExtendedFG(xw);
3808		    });
3809		    break;
3810		case 7:
3811		    UIntSet(xw->flags, INVERSE);
3812		    if_OPT_ISO_COLORS(screen, {
3813			setExtendedBG(xw);
3814		    });
3815		    break;
3816		case 8:
3817		    UIntSet(xw->flags, INVISIBLE);
3818		    break;
3819#if OPT_WIDE_ATTRS
3820		case 9:	/* crossed-out characters */
3821		    UIntSet(xw->flags, ATR_STRIKEOUT);
3822		    break;
3823#endif
3824#if OPT_WIDE_ATTRS
3825		case 21:	/* doubly-underlined */
3826		    UIntSet(xw->flags, ATR_DBL_UNDER);
3827		    break;
3828#endif
3829		case 22:	/* reset 'bold' */
3830		    UIntClr(xw->flags, BOLD);
3831#if OPT_WIDE_ATTRS
3832		    UIntClr(xw->flags, ATR_FAINT);
3833#endif
3834		    if_OPT_ISO_COLORS(screen, {
3835			setExtendedFG(xw);
3836		    });
3837		    break;
3838#if OPT_WIDE_ATTRS
3839		case 23:	/* not italicized */
3840		    ResetItalics(xw);
3841		    if_OPT_ISO_COLORS(screen, {
3842			setExtendedFG(xw);
3843		    });
3844		    break;
3845#endif
3846		case 24:
3847		    UIntClr(xw->flags, UNDERLINE);
3848#if OPT_WIDE_ATTRS
3849		    UIntClr(xw->flags, ATR_DBL_UNDER);
3850#endif
3851		    if_OPT_ISO_COLORS(screen, {
3852			setExtendedFG(xw);
3853		    });
3854		    break;
3855		case 25:	/* reset 'blink' */
3856		    UIntClr(xw->flags, BLINK);
3857		    if_OPT_ISO_COLORS(screen, {
3858			setExtendedFG(xw);
3859		    });
3860		    break;
3861		case 27:
3862		    UIntClr(xw->flags, INVERSE);
3863		    if_OPT_ISO_COLORS(screen, {
3864			setExtendedBG(xw);
3865		    });
3866		    break;
3867		case 28:
3868		    UIntClr(xw->flags, INVISIBLE);
3869		    break;
3870#if OPT_WIDE_ATTRS
3871		case 29:	/* not crossed out */
3872		    UIntClr(xw->flags, ATR_STRIKEOUT);
3873		    break;
3874#endif
3875		case 30:
3876		    /* FALLTHRU */
3877		case 31:
3878		    /* FALLTHRU */
3879		case 32:
3880		    /* FALLTHRU */
3881		case 33:
3882		    /* FALLTHRU */
3883		case 34:
3884		    /* FALLTHRU */
3885		case 35:
3886		    /* FALLTHRU */
3887		case 36:
3888		    /* FALLTHRU */
3889		case 37:
3890		    if_OPT_ISO_COLORS(screen, {
3891			xw->sgr_foreground = (op - 30);
3892			xw->sgr_38_xcolors = False;
3893			clrDirectFG(xw->flags);
3894			setExtendedFG(xw);
3895		    });
3896		    break;
3897		case 38:
3898		    /* This is more complicated than I'd like, but it should
3899		     * properly eat all the parameters for unsupported modes.
3900		     */
3901		    if_OPT_ISO_COLORS(screen, {
3902			Boolean extended;
3903			if (parse_extended_colors(xw, &value, &item,
3904						  &extended)) {
3905			    xw->sgr_foreground = value;
3906			    xw->sgr_38_xcolors = True;
3907			    setDirectFG(xw->flags, extended);
3908			    setExtendedFG(xw);
3909			}
3910		    });
3911		    break;
3912		case 39:
3913		    if_OPT_ISO_COLORS(screen, {
3914			reset_SGR_Foreground(xw);
3915		    });
3916		    break;
3917		case 40:
3918		    /* FALLTHRU */
3919		case 41:
3920		    /* FALLTHRU */
3921		case 42:
3922		    /* FALLTHRU */
3923		case 43:
3924		    /* FALLTHRU */
3925		case 44:
3926		    /* FALLTHRU */
3927		case 45:
3928		    /* FALLTHRU */
3929		case 46:
3930		    /* FALLTHRU */
3931		case 47:
3932		    if_OPT_ISO_COLORS(screen, {
3933			xw->sgr_background = (op - 40);
3934			clrDirectBG(xw->flags);
3935			setExtendedBG(xw);
3936		    });
3937		    break;
3938		case 48:
3939		    if_OPT_ISO_COLORS(screen, {
3940			Boolean extended;
3941			if (parse_extended_colors(xw, &value, &item,
3942						  &extended)) {
3943			    xw->sgr_background = value;
3944			    setDirectBG(xw->flags, extended);
3945			    setExtendedBG(xw);
3946			}
3947		    });
3948		    break;
3949		case 49:
3950		    if_OPT_ISO_COLORS(screen, {
3951			reset_SGR_Background(xw);
3952		    });
3953		    break;
3954		case 90:
3955		    /* FALLTHRU */
3956		case 91:
3957		    /* FALLTHRU */
3958		case 92:
3959		    /* FALLTHRU */
3960		case 93:
3961		    /* FALLTHRU */
3962		case 94:
3963		    /* FALLTHRU */
3964		case 95:
3965		    /* FALLTHRU */
3966		case 96:
3967		    /* FALLTHRU */
3968		case 97:
3969		    if_OPT_AIX_COLORS(screen, {
3970			xw->sgr_foreground = (op - 90 + 8);
3971			clrDirectFG(xw->flags);
3972			setExtendedFG(xw);
3973		    });
3974		    break;
3975		case 100:
3976#if !OPT_AIX_COLORS
3977		    if_OPT_ISO_COLORS(screen, {
3978			reset_SGR_Foreground(xw);
3979			reset_SGR_Background(xw);
3980		    });
3981		    break;
3982#endif
3983		case 101:
3984		    /* FALLTHRU */
3985		case 102:
3986		    /* FALLTHRU */
3987		case 103:
3988		    /* FALLTHRU */
3989		case 104:
3990		    /* FALLTHRU */
3991		case 105:
3992		    /* FALLTHRU */
3993		case 106:
3994		    /* FALLTHRU */
3995		case 107:
3996		    if_OPT_AIX_COLORS(screen, {
3997			xw->sgr_background = (op - 100 + 8);
3998			clrDirectBG(xw->flags);
3999			setExtendedBG(xw);
4000		    });
4001		    break;
4002		default:
4003		    /* later: skip += NPARAM; */
4004		    break;
4005		}
4006	    }
4007	    ResetState(sp);
4008	    break;
4009
4010	    /* DSR (except for the '?') is a superset of CPR */
4011	case CASE_DSR:
4012	    sp->private_function = True;
4013
4014	    /* FALLTHRU */
4015	case CASE_CPR:
4016	    TRACE(("CASE_DSR - device status report\n"));
4017	    count = 0;
4018	    init_reply(ANSI_CSI);
4019	    reply.a_pintro = CharOf(sp->private_function ? '?' : 0);
4020	    reply.a_inters = 0;
4021	    reply.a_final = 'n';
4022
4023	    switch (GetParam(0)) {
4024	    case 5:
4025		TRACE(("...request operating status\n"));
4026		/* operating status */
4027		reply.a_param[count++] = 0;	/* (no malfunction ;-) */
4028		break;
4029	    case 6:
4030		TRACE(("...request %s\n",
4031		       (sp->private_function
4032			? "DECXCPR"
4033			: "CPR")));
4034		/* CPR */
4035		/* DECXCPR (with page=1) */
4036		value = screen->cur_row;
4037		if ((xw->flags & ORIGIN) != 0) {
4038		    value -= screen->top_marg;
4039		}
4040		if_STATUS_LINE(screen, {
4041		    if ((value -= LastRowNumber(screen)) < 0)
4042			value = 0;
4043		});
4044		reply.a_param[count++] = (ParmType) (value + 1);
4045
4046		value = (screen->cur_col + 1);
4047		if ((xw->flags & ORIGIN) != 0) {
4048		    value -= screen->lft_marg;
4049		}
4050		reply.a_param[count++] = (ParmType) value;
4051
4052		if (sp->private_function
4053		    && screen->vtXX_level >= 4) {	/* VT420 */
4054		    reply.a_param[count++] = 1;
4055		}
4056		reply.a_final = 'R';
4057		break;
4058	    case 15:
4059		TRACE(("...request printer status\n"));
4060		if (sp->private_function
4061		    && screen->vtXX_level >= 2) {	/* VT220 */
4062		    reply.a_param[count++] = 13;	/* no printer detected */
4063		}
4064		break;
4065	    case 25:
4066		TRACE(("...request UDK status\n"));
4067		if (sp->private_function
4068		    && screen->vtXX_level >= 2) {	/* VT220 */
4069		    reply.a_param[count++] = 20;	/* UDK always unlocked */
4070		}
4071		break;
4072	    case 26:
4073		TRACE(("...request keyboard status\n"));
4074		if (sp->private_function
4075		    && screen->vtXX_level >= 2) {	/* VT220 */
4076		    reply.a_param[count++] = 27;
4077		    reply.a_param[count++] = 1;		/* North American */
4078		    if (screen->vtXX_level >= 3) {	/* VT320 */
4079			reply.a_param[count++] = 0;	/* ready */
4080		    }
4081		    if (screen->vtXX_level >= 4) {	/* VT420 */
4082			reply.a_param[count++] = 0;	/* LK201 */
4083		    }
4084		}
4085		break;
4086	    case 53:		/* according to existing xterm handling */
4087		/* FALLTHRU */
4088	    case 55:		/* according to the VT330/VT340 Text Programming Manual */
4089		TRACE(("...request locator status\n"));
4090		if (sp->private_function
4091		    && screen->vtXX_level >= 3) {	/* VT330 */
4092#if OPT_DEC_LOCATOR
4093		    reply.a_param[count++] = 50;	/* locator ready */
4094#else
4095		    reply.a_param[count++] = 53;	/* no locator */
4096#endif
4097		}
4098		break;
4099	    case 56:
4100		TRACE(("...request locator type\n"));
4101		if (sp->private_function
4102		    && screen->vtXX_level >= 3) {	/* VT330 */
4103		    reply.a_param[count++] = 57;
4104#if OPT_DEC_LOCATOR
4105		    reply.a_param[count++] = 1;		/* mouse */
4106#else
4107		    reply.a_param[count++] = 0;		/* unknown */
4108#endif
4109		}
4110		break;
4111	    case 62:
4112		TRACE(("...request DECMSR - macro space\n"));
4113		if (sp->private_function
4114		    && screen->vtXX_level >= 4) {	/* VT420 */
4115		    reply.a_pintro = 0;
4116		    reply.a_radix[count] = 16;	/* no data */
4117		    reply.a_param[count++] = 0;		/* no space for macros */
4118		    reply.a_inters = '*';
4119		    reply.a_final = L_CURL;
4120		}
4121		break;
4122	    case 63:
4123		TRACE(("...request DECCKSR - memory checksum\n"));
4124		/* DECCKSR - Memory checksum */
4125		if (sp->private_function
4126		    && screen->vtXX_level >= 4) {	/* VT420 */
4127		    init_reply(ANSI_DCS);
4128		    reply.a_param[count++] = (ParmType) GetParam(1);	/* PID */
4129		    reply.a_delim = "!~";	/* delimiter */
4130		    reply.a_radix[count] = 16;	/* use hex */
4131		    reply.a_param[count++] = 0;		/* no data */
4132		}
4133		break;
4134	    case 75:
4135		TRACE(("...request data integrity\n"));
4136		if (sp->private_function
4137		    && screen->vtXX_level >= 4) {	/* VT420 */
4138		    reply.a_param[count++] = 70;	/* no errors */
4139		}
4140		break;
4141	    case 85:
4142		TRACE(("...request multi-session configuration\n"));
4143		if (sp->private_function
4144		    && screen->vtXX_level >= 4) {	/* VT420 */
4145		    reply.a_param[count++] = 83;	/* not configured */
4146		}
4147		break;
4148	    default:
4149		break;
4150	    }
4151
4152	    if ((reply.a_nparam = (ParmType) count) != 0)
4153		unparseseq(xw, &reply);
4154
4155	    ResetState(sp);
4156	    sp->private_function = False;
4157	    break;
4158
4159	case CASE_MC:
4160	    TRACE(("CASE_MC - media control\n"));
4161	    xtermMediaControl(xw, GetParam(0), False);
4162	    ResetState(sp);
4163	    break;
4164
4165	case CASE_DEC_MC:
4166	    TRACE(("CASE_DEC_MC - DEC media control\n"));
4167	    xtermMediaControl(xw, GetParam(0), True);
4168	    ResetState(sp);
4169	    break;
4170
4171	case CASE_HP_MEM_LOCK:
4172	    /* FALLTHRU */
4173	case CASE_HP_MEM_UNLOCK:
4174	    TRACE(("%s\n", ((sp->parsestate[c] == CASE_HP_MEM_LOCK)
4175			    ? "CASE_HP_MEM_LOCK"
4176			    : "CASE_HP_MEM_UNLOCK")));
4177	    if (screen->scroll_amt)
4178		FlushScroll(xw);
4179	    if (sp->parsestate[c] == CASE_HP_MEM_LOCK)
4180		set_tb_margins(screen, screen->cur_row, screen->bot_marg);
4181	    else
4182		set_tb_margins(screen, 0, screen->bot_marg);
4183	    ResetState(sp);
4184	    break;
4185
4186	case CASE_DECSTBM:
4187	    TRACE(("CASE_DECSTBM - set scrolling region\n"));
4188	    {
4189		int top;
4190		int bot;
4191		top = one_if_default(0);
4192		if (nparam < 2 || (bot = GetParam(1)) == DEFAULT
4193		    || bot > MaxRows(screen)
4194		    || bot == 0)
4195		    bot = MaxRows(screen);
4196		if (bot > top) {
4197		    if (screen->scroll_amt)
4198			FlushScroll(xw);
4199		    set_tb_margins(screen, top - 1, bot - 1);
4200		    CursorSet(screen, 0, 0, xw->flags);
4201		}
4202		ResetState(sp);
4203	    }
4204	    break;
4205
4206	case CASE_DECREQTPARM:
4207	    TRACE(("CASE_DECREQTPARM\n"));
4208	    if (screen->terminal_id < 200) {	/* VT102 */
4209		value = zero_if_default(0);
4210		if (value == 0 || value == 1) {
4211		    init_reply(ANSI_CSI);
4212		    reply.a_pintro = 0;
4213		    reply.a_nparam = 7;
4214		    reply.a_param[0] = (ParmType) (value + 2);
4215		    reply.a_param[1] = 1;	/* no parity */
4216		    reply.a_param[2] = 1;	/* eight bits */
4217		    reply.a_param[3] = 128;	/* transmit 38.4k baud */
4218		    reply.a_param[4] = 128;	/* receive 38.4k baud */
4219		    reply.a_param[5] = 1;	/* clock multiplier ? */
4220		    reply.a_param[6] = 0;	/* STP flags ? */
4221		    reply.a_inters = 0;
4222		    reply.a_final = 'x';
4223		    unparseseq(xw, &reply);
4224		}
4225	    }
4226	    ResetState(sp);
4227	    break;
4228
4229	case CASE_DECSET:
4230	    /* DECSET */
4231#if OPT_VT52_MODE
4232	    if (screen->vtXX_level != 0)
4233#endif
4234		dpmodes(xw, bitset);
4235	    ResetState(sp);
4236#if OPT_TEK4014
4237	    if (TEK4014_ACTIVE(xw)) {
4238		TRACE(("Tek4014 is now active...\n"));
4239		if (sp->check_recur)
4240		    sp->check_recur--;
4241		return False;
4242	    }
4243#endif
4244	    break;
4245
4246	case CASE_DECRST:
4247	    /* DECRST */
4248	    dpmodes(xw, bitclr);
4249	    init_groundtable(screen, sp);
4250	    ResetState(sp);
4251	    break;
4252
4253	case CASE_DECALN:
4254	    TRACE(("CASE_DECALN - alignment test\n"));
4255	    if (screen->cursor_state)
4256		HideCursor(xw);
4257	    /*
4258	     * DEC STD 070 (see pages D-19 to D-20) does not mention left/right
4259	     * margins.  The section is dated March 1985, not updated for the
4260	     * VT420 (introduced in 1990).
4261	     */
4262	    UIntClr(xw->flags, ORIGIN);
4263	    screen->do_wrap = False;
4264	    resetRendition(xw);
4265	    resetMargins(xw);
4266	    xterm_ResetDouble(xw);
4267	    CursorSet(screen, 0, 0, xw->flags);
4268	    xtermParseRect(xw, 0, 0, &myRect);
4269	    ScrnFillRectangle(xw, &myRect, 'E', 0, False);
4270	    ResetState(sp);
4271	    break;
4272
4273	case CASE_GSETS5:
4274	    if (screen->vtXX_level >= 5) {
4275		TRACE(("CASE_GSETS5(%d) = '%c'\n", sp->scstype, c));
4276		xtermDecodeSCS(xw, sp->scstype, 5, 0, (int) c);
4277	    }
4278	    ResetState(sp);
4279	    break;
4280
4281	case CASE_GSETS3:
4282	    if (screen->vtXX_level >= 3) {
4283		TRACE(("CASE_GSETS3(%d) = '%c'\n", sp->scstype, c));
4284		xtermDecodeSCS(xw, sp->scstype, 3, 0, (int) c);
4285	    }
4286	    ResetState(sp);
4287	    break;
4288
4289	case CASE_GSETS:
4290	    if (strchr("012AB", (int) c) != 0) {
4291		TRACE(("CASE_GSETS(%d) = '%c'\n", sp->scstype, c));
4292		xtermDecodeSCS(xw, sp->scstype, 1, 0, (int) c);
4293	    } else if (screen->vtXX_level >= 2) {
4294		TRACE(("CASE_GSETS(%d) = '%c'\n", sp->scstype, c));
4295		xtermDecodeSCS(xw, sp->scstype, 2, 0, (int) c);
4296	    }
4297	    ResetState(sp);
4298	    break;
4299
4300	case CASE_ANSI_SC:
4301	    if (IsLeftRightMode(xw)) {
4302		int left;
4303		int right;
4304
4305		TRACE(("CASE_DECSLRM - set left and right margin\n"));
4306		left = one_if_default(0);
4307		if (nparam < 2 || (right = GetParam(1)) == DEFAULT
4308		    || right > MaxCols(screen)
4309		    || right == 0)
4310		    right = MaxCols(screen);
4311		if (right > left) {
4312		    set_lr_margins(screen, left - 1, right - 1);
4313		    CursorSet(screen, 0, 0, xw->flags);
4314		}
4315	    } else {
4316		TRACE(("CASE_ANSI_SC - save cursor\n"));
4317		CursorSave(xw);
4318	    }
4319	    ResetState(sp);
4320	    break;
4321
4322	case CASE_DECSC:
4323	    TRACE(("CASE_DECSC - save cursor\n"));
4324	    CursorSave(xw);
4325	    ResetState(sp);
4326	    break;
4327
4328	case CASE_ANSI_RC:
4329	    /* FALLTHRU */
4330	case CASE_DECRC:
4331	    TRACE(("CASE_%sRC - restore cursor\n",
4332		   (sp->nextstate == CASE_DECRC) ? "DEC" : "ANSI_"));
4333	    CursorRestore(xw);
4334	    if_OPT_ISO_COLORS(screen, {
4335		setExtendedFG(xw);
4336	    });
4337	    ResetState(sp);
4338	    break;
4339
4340	case CASE_DECKPAM:
4341	    TRACE(("CASE_DECKPAM\n"));
4342	    xw->keyboard.flags |= MODE_DECKPAM;
4343	    update_appkeypad();
4344	    ResetState(sp);
4345	    break;
4346
4347	case CASE_DECKPNM:
4348	    TRACE(("CASE_DECKPNM\n"));
4349	    UIntClr(xw->keyboard.flags, MODE_DECKPAM);
4350	    update_appkeypad();
4351	    ResetState(sp);
4352	    break;
4353
4354	case CASE_CSI_QUOTE_STATE:
4355	    sp->parsestate = csi_quo_table;
4356	    break;
4357
4358#if OPT_BLINK_CURS
4359	case CASE_CSI_SPACE_STATE:
4360	    sp->parsestate = csi_sp_table;
4361	    break;
4362
4363	case CASE_DECSCUSR:
4364	    TRACE(("CASE_DECSCUSR\n"));
4365	    {
4366		Boolean change = True;
4367		int blinks = screen->cursor_blink_esc;
4368
4369		HideCursor(xw);
4370
4371		switch (GetParam(0)) {
4372		case DEFAULT:
4373		    /* FALLTHRU */
4374		case DEFAULT_STYLE:
4375		    /* FALLTHRU */
4376		case BLINK_BLOCK:
4377		    blinks = True;
4378		    screen->cursor_shape = CURSOR_BLOCK;
4379		    break;
4380		case STEADY_BLOCK:
4381		    blinks = False;
4382		    screen->cursor_shape = CURSOR_BLOCK;
4383		    break;
4384		case BLINK_UNDERLINE:
4385		    blinks = True;
4386		    screen->cursor_shape = CURSOR_UNDERLINE;
4387		    break;
4388		case STEADY_UNDERLINE:
4389		    blinks = False;
4390		    screen->cursor_shape = CURSOR_UNDERLINE;
4391		    break;
4392		case BLINK_BAR:
4393		    blinks = True;
4394		    screen->cursor_shape = CURSOR_BAR;
4395		    break;
4396		case STEADY_BAR:
4397		    blinks = False;
4398		    screen->cursor_shape = CURSOR_BAR;
4399		    break;
4400		default:
4401		    change = False;
4402		    break;
4403		}
4404		TRACE(("cursor_shape:%d blinks:%s\n",
4405		       screen->cursor_shape, BtoS(blinks)));
4406		if (change) {
4407		    xtermSetCursorBox(screen);
4408		    if (SettableCursorBlink(screen)) {
4409			screen->cursor_blink_esc = blinks;
4410			UpdateCursorBlink(xw);
4411		    }
4412		}
4413	    }
4414	    ResetState(sp);
4415	    break;
4416#endif
4417
4418#if OPT_SCROLL_LOCK
4419	case CASE_DECLL:
4420	    TRACE(("CASE_DECLL\n"));
4421	    if (nparam > 0) {
4422		for (count = 0; count < nparam; ++count) {
4423		    int op = zero_if_default(count);
4424		    switch (op) {
4425		    case 0:
4426		    case DEFAULT:
4427			xtermClearLEDs(screen);
4428			break;
4429		    case 1:
4430			/* FALLTHRU */
4431		    case 2:
4432			/* FALLTHRU */
4433		    case 3:
4434			xtermShowLED(screen,
4435				     (Cardinal) op,
4436				     True);
4437			break;
4438		    case 21:
4439			/* FALLTHRU */
4440		    case 22:
4441			/* FALLTHRU */
4442		    case 23:
4443			xtermShowLED(screen,
4444				     (Cardinal) (op - 20),
4445				     True);
4446			break;
4447		    }
4448		}
4449	    } else {
4450		xtermClearLEDs(screen);
4451	    }
4452	    ResetState(sp);
4453	    break;
4454#endif
4455
4456#if OPT_VT52_MODE
4457	case CASE_VT52_FINISH:
4458	    TRACE(("CASE_VT52_FINISH terminal_id %d, vtXX_level %d\n",
4459		   screen->terminal_id,
4460		   screen->vtXX_level));
4461	    if (screen->terminal_id >= 100
4462		&& screen->vtXX_level == 0) {
4463		sp->groundtable =
4464		    sp->parsestate = ansi_table;
4465		/*
4466		 * On restore, the terminal does not recognize DECRQSS for
4467		 * DECSCL (per vttest).
4468		 */
4469		screen->vtXX_level = 1;
4470		xw->flags = screen->vt52_save_flags;
4471		screen->curgl = screen->vt52_save_curgl;
4472		screen->curgr = screen->vt52_save_curgr;
4473		screen->curss = screen->vt52_save_curss;
4474		restoreCharsets(screen, screen->vt52_save_gsets);
4475		update_vt52_vt100_settings();
4476	    }
4477	    break;
4478#endif
4479
4480	case CASE_ANSI_LEVEL_1:
4481	    TRACE(("CASE_ANSI_LEVEL_1\n"));
4482	    set_ansi_conformance(screen, 1);
4483	    ResetState(sp);
4484	    break;
4485
4486	case CASE_ANSI_LEVEL_2:
4487	    TRACE(("CASE_ANSI_LEVEL_2\n"));
4488	    set_ansi_conformance(screen, 2);
4489	    ResetState(sp);
4490	    break;
4491
4492	case CASE_ANSI_LEVEL_3:
4493	    TRACE(("CASE_ANSI_LEVEL_3\n"));
4494	    set_ansi_conformance(screen, 3);
4495	    ResetState(sp);
4496	    break;
4497
4498	case CASE_DECSCL:
4499	    TRACE(("CASE_DECSCL(%d,%d)\n", GetParam(0), GetParam(1)));
4500	    /*
4501	     * This changes the emulation level, and is not recognized by
4502	     * VT100s.  However, a VT220 or above can be set to conformance
4503	     * level 1 to act like a VT100.
4504	     */
4505	    if (screen->terminal_id >= 200) {
4506		/*
4507		 * Disallow unrecognized parameters, as well as attempts to set
4508		 * the operating level higher than the given terminal-id.
4509		 */
4510		if (GetParam(0) >= 61
4511		    && GetParam(0) <= 60 + (screen->terminal_id / 100)) {
4512		    int new_vtXX_level = GetParam(0) - 60;
4513		    int case_value = zero_if_default(1);
4514		    /*
4515		     * Note:
4516		     *
4517		     * The VT300, VT420, VT520 manuals claim that DECSCL does a
4518		     * hard reset (RIS).
4519		     *
4520		     * Both the VT220 manual and DEC STD 070 (which documents
4521		     * levels 1-4 in detail) state that it is a soft reset.
4522		     *
4523		     * Perhaps both sets of manuals are right (unlikely).
4524		     * Kermit says it's soft.
4525		     */
4526		    ReallyReset(xw, False, False);
4527		    init_parser(xw, sp);
4528		    screen->vtXX_level = new_vtXX_level;
4529		    if (new_vtXX_level > 1) {
4530			switch (case_value) {
4531			case 1:
4532			    show_8bit_control(False);
4533			    break;
4534			case 0:
4535			case 2:
4536			    show_8bit_control(True);
4537			    break;
4538			}
4539		    }
4540		}
4541	    }
4542	    ResetState(sp);
4543	    break;
4544
4545	case CASE_DECSCA:
4546	    TRACE(("CASE_DECSCA\n"));
4547	    screen->protected_mode = DEC_PROTECT;
4548	    if (GetParam(0) <= 0 || GetParam(0) == 2) {
4549		UIntClr(xw->flags, PROTECTED);
4550		TRACE(("...clear PROTECTED\n"));
4551	    } else if (GetParam(0) == 1) {
4552		xw->flags |= PROTECTED;
4553		TRACE(("...set PROTECTED\n"));
4554	    }
4555	    ResetState(sp);
4556	    break;
4557
4558	case CASE_DECSED:
4559	    TRACE(("CASE_DECSED\n"));
4560	    do_erase_display(xw, zero_if_default(0), DEC_PROTECT);
4561	    ResetState(sp);
4562	    break;
4563
4564	case CASE_DECSEL:
4565	    TRACE(("CASE_DECSEL\n"));
4566	    do_erase_line(xw, zero_if_default(0), DEC_PROTECT);
4567	    ResetState(sp);
4568	    break;
4569
4570	case CASE_GRAPHICS_ATTRIBUTES:
4571#if OPT_GRAPHICS
4572	    TRACE(("CASE_GRAPHICS_ATTRIBUTES\n"));
4573	    {
4574		/* request: item, action, value */
4575		/* reply: item, status, value */
4576		if (nparam != 3) {
4577		    TRACE(("DATA_ERROR: malformed CASE_GRAPHICS_ATTRIBUTES request with %d parameters\n", nparam));
4578		} else {
4579		    int status = 3;	/* assume failure */
4580		    int result = 0;
4581		    int result2 = 0;
4582
4583		    TRACE(("CASE_GRAPHICS_ATTRIBUTES request: %d, %d, %d\n",
4584			   GetParam(0), GetParam(1), GetParam(2)));
4585		    switch (GetParam(0)) {
4586		    case 1:	/* color register count */
4587			switch (GetParam(1)) {
4588			case 1:	/* read */
4589			    status = 0;		/* success */
4590			    result = (int) get_color_register_count(screen);
4591			    break;
4592			case 2:	/* reset */
4593			    screen->numcolorregisters = 0;
4594			    status = 0;		/* success */
4595			    result = (int) get_color_register_count(screen);
4596			    break;
4597			case 3:	/* set */
4598			    if (GetParam(2) > 1 &&
4599				(unsigned) GetParam(2) <= MAX_COLOR_REGISTERS) {
4600				screen->numcolorregisters = GetParam(2);
4601				status = 0;	/* success */
4602				result = (int) get_color_register_count(screen);
4603			    }
4604			    break;
4605			case 4:	/* read maximum */
4606			    status = 0;		/* success */
4607			    result = MAX_COLOR_REGISTERS;
4608			    break;
4609			default:
4610			    TRACE(("DATA_ERROR: CASE_GRAPHICS_ATTRIBUTES color register count request with unknown action parameter: %d\n",
4611				   GetParam(1)));
4612			    status = 2;		/* error in Pa */
4613			    break;
4614			}
4615			if (status == 0 && !(optSixelGraphics(screen)
4616					     || optRegisGraphics(screen)))
4617			    status = 3;
4618			break;
4619# if OPT_SIXEL_GRAPHICS
4620		    case 2:	/* graphics geometry */
4621			switch (GetParam(1)) {
4622			case 1:	/* read */
4623			    TRACE(("Get sixel graphics geometry\n"));
4624			    status = 0;		/* success */
4625			    result = Min(Width(screen), (int) screen->graphics_max_wide);
4626			    result2 = Min(Height(screen), (int) screen->graphics_max_high);
4627			    break;
4628			case 2:	/* reset */
4629			    /* FALLTHRU */
4630			case 3:	/* set */
4631			    break;
4632			case 4:	/* read maximum */
4633			    status = 0;		/* success */
4634			    result = screen->graphics_max_wide;
4635			    result2 = screen->graphics_max_high;
4636			    break;
4637			default:
4638			    TRACE(("DATA_ERROR: CASE_GRAPHICS_ATTRIBUTES graphics geometry request with unknown action parameter: %d\n",
4639				   GetParam(1)));
4640			    status = 2;		/* error in Pa */
4641			    break;
4642			}
4643			if (status == 0 && !optSixelGraphics(screen))
4644			    status = 3;
4645			break;
4646#endif
4647# if OPT_REGIS_GRAPHICS
4648		    case 3:	/* ReGIS geometry */
4649			switch (GetParam(1)) {
4650			case 1:	/* read */
4651			    status = 0;		/* success */
4652			    result = screen->graphics_regis_def_wide;
4653			    result2 = screen->graphics_regis_def_high;
4654			    break;
4655			case 2:	/* reset */
4656			    /* FALLTHRU */
4657			case 3:	/* set */
4658			    /* FALLTHRU */
4659			case 4:	/* read maximum */
4660			    /* not implemented */
4661			    break;
4662			default:
4663			    TRACE(("DATA_ERROR: CASE_GRAPHICS_ATTRIBUTES ReGIS geometry request with unknown action parameter: %d\n",
4664				   GetParam(1)));
4665			    status = 2;		/* error in Pa */
4666			    break;
4667			}
4668			if (status == 0 && !optRegisGraphics(screen))
4669			    status = 3;
4670			break;
4671#endif
4672		    default:
4673			TRACE(("DATA_ERROR: CASE_GRAPHICS_ATTRIBUTES request with unknown item parameter: %d\n",
4674			       GetParam(0)));
4675			status = 1;
4676			break;
4677		    }
4678
4679		    init_reply(ANSI_CSI);
4680		    reply.a_pintro = '?';
4681		    count = 0;
4682		    reply.a_param[count++] = (ParmType) GetParam(0);
4683		    reply.a_param[count++] = (ParmType) status;
4684		    if (status == 0) {
4685			reply.a_param[count++] = (ParmType) result;
4686			if (GetParam(0) >= 2)
4687			    reply.a_param[count++] = (ParmType) result2;
4688		    }
4689		    reply.a_nparam = (ParmType) count;
4690		    reply.a_inters = 0;
4691		    reply.a_final = 'S';
4692		    unparseseq(xw, &reply);
4693		}
4694	    }
4695#endif
4696	    ResetState(sp);
4697	    break;
4698
4699	case CASE_ST:
4700	    TRACE(("CASE_ST: End of String (%lu bytes) (mode=%d)\n",
4701		   (unsigned long) sp->string_used,
4702		   sp->string_mode));
4703	    ResetState(sp);
4704	    if (!sp->string_used)
4705		break;
4706	    sp->string_area[--(sp->string_used)] = '\0';
4707	    if (sp->check_recur <= 1)
4708		switch (sp->string_mode) {
4709		case ANSI_APC:
4710		    /* ignored */
4711		    break;
4712		case ANSI_DCS:
4713		    do_dcs(xw, sp->string_area, sp->string_used);
4714		    break;
4715		case ANSI_OSC:
4716		    do_osc(xw, sp->string_area, sp->string_used, ANSI_ST);
4717		    break;
4718		case ANSI_PM:
4719		    /* ignored */
4720		    break;
4721		case ANSI_SOS:
4722		    /* ignored */
4723		    break;
4724		default:
4725		    TRACE(("unknown mode\n"));
4726		    break;
4727		}
4728	    break;
4729
4730	case CASE_SOS:
4731	    TRACE(("CASE_SOS: Start of String\n"));
4732	    if (ParseSOS(screen)) {
4733		sp->string_mode = ANSI_SOS;
4734		sp->parsestate = sos_table;
4735	    } else {
4736		illegal_parse(xw, c, sp);
4737	    }
4738	    break;
4739
4740	case CASE_PM:
4741	    TRACE(("CASE_PM: Privacy Message\n"));
4742	    if (ParseSOS(screen)) {
4743		sp->string_mode = ANSI_PM;
4744		sp->parsestate = sos_table;
4745	    } else {
4746		illegal_parse(xw, c, sp);
4747	    }
4748	    break;
4749
4750	case CASE_DCS:
4751	    TRACE(("CASE_DCS: Device Control String\n"));
4752	    sp->string_mode = ANSI_DCS;
4753	    sp->parsestate = sos_table;
4754	    break;
4755
4756	case CASE_APC:
4757	    TRACE(("CASE_APC: Application Program Command\n"));
4758	    if (ParseSOS(screen)) {
4759		sp->string_mode = ANSI_APC;
4760		sp->parsestate = sos_table;
4761	    } else {
4762		illegal_parse(xw, c, sp);
4763	    }
4764	    break;
4765
4766	case CASE_SPA:
4767	    TRACE(("CASE_SPA - start protected area\n"));
4768	    screen->protected_mode = ISO_PROTECT;
4769	    xw->flags |= PROTECTED;
4770	    ResetState(sp);
4771	    break;
4772
4773	case CASE_EPA:
4774	    TRACE(("CASE_EPA - end protected area\n"));
4775	    UIntClr(xw->flags, PROTECTED);
4776	    ResetState(sp);
4777	    break;
4778
4779	case CASE_SU:
4780	    TRACE(("CASE_SU - scroll up\n"));
4781	    xtermScroll(xw, one_if_default(0));
4782	    ResetState(sp);
4783	    break;
4784
4785	case CASE_SL:		/* ISO 6429, non-DEC */
4786	    TRACE(("CASE_SL - scroll left\n"));
4787	    xtermScrollLR(xw, one_if_default(0), True);
4788	    ResetState(sp);
4789	    break;
4790
4791	case CASE_SR:		/* ISO 6429, non-DEC */
4792	    TRACE(("CASE_SR - scroll right\n"));
4793	    xtermScrollLR(xw, one_if_default(0), False);
4794	    ResetState(sp);
4795	    break;
4796
4797	case CASE_DECDC:
4798	    TRACE(("CASE_DC - delete column\n"));
4799	    if (screen->vtXX_level >= 4) {
4800		xtermColScroll(xw, one_if_default(0), True, screen->cur_col);
4801	    }
4802	    ResetState(sp);
4803	    break;
4804
4805	case CASE_DECIC:
4806	    TRACE(("CASE_IC - insert column\n"));
4807	    if (screen->vtXX_level >= 4) {
4808		xtermColScroll(xw, one_if_default(0), False, screen->cur_col);
4809	    }
4810	    ResetState(sp);
4811	    break;
4812
4813	case CASE_DECBI:
4814	    TRACE(("CASE_BI - back index\n"));
4815	    if (screen->vtXX_level >= 4) {
4816		xtermColIndex(xw, True);
4817	    }
4818	    ResetState(sp);
4819	    break;
4820
4821	case CASE_DECFI:
4822	    TRACE(("CASE_FI - forward index\n"));
4823	    if (screen->vtXX_level >= 4) {
4824		xtermColIndex(xw, False);
4825	    }
4826	    ResetState(sp);
4827	    break;
4828
4829	case CASE_IND:
4830	    TRACE(("CASE_IND - index\n"));
4831	    xtermIndex(xw, 1);
4832	    do_xevents(xw);
4833	    ResetState(sp);
4834	    break;
4835
4836	case CASE_CPL:
4837	    TRACE(("CASE_CPL - cursor prev line\n"));
4838	    CursorPrevLine(xw, one_if_default(0));
4839	    ResetState(sp);
4840	    break;
4841
4842	case CASE_CNL:
4843	    TRACE(("CASE_CNL - cursor next line\n"));
4844	    CursorNextLine(xw, one_if_default(0));
4845	    ResetState(sp);
4846	    break;
4847
4848	case CASE_NEL:
4849	    TRACE(("CASE_NEL\n"));
4850	    xtermIndex(xw, 1);
4851	    CarriageReturn(xw);
4852	    ResetState(sp);
4853	    break;
4854
4855	case CASE_HTS:
4856	    TRACE(("CASE_HTS - horizontal tab set\n"));
4857	    TabSet(xw->tabs, screen->cur_col);
4858	    ResetState(sp);
4859	    break;
4860
4861	case CASE_REPORT_VERSION:
4862	    TRACE(("CASE_REPORT_VERSION - report terminal version\n"));
4863	    if (GetParam(0) <= 0) {
4864		unparseputc1(xw, ANSI_DCS);
4865		unparseputc(xw, '>');
4866		unparseputc(xw, '|');
4867		unparseputs(xw, xtermVersion());
4868		unparseputc1(xw, ANSI_ST);
4869		unparse_end(xw);
4870	    }
4871	    ResetState(sp);
4872	    break;
4873
4874	case CASE_RI:
4875	    TRACE(("CASE_RI - reverse index\n"));
4876	    RevIndex(xw, 1);
4877	    ResetState(sp);
4878	    break;
4879
4880	case CASE_SS2:
4881	    TRACE(("CASE_SS2\n"));
4882	    screen->curss = 2;
4883	    ResetState(sp);
4884	    break;
4885
4886	case CASE_SS3:
4887	    TRACE(("CASE_SS3\n"));
4888	    screen->curss = 3;
4889	    ResetState(sp);
4890	    break;
4891
4892	case CASE_CSI_STATE:
4893	    /* enter csi state */
4894	    InitParams();
4895	    SetParam(nparam++, DEFAULT);
4896	    sp->parsestate = csi_table;
4897	    break;
4898
4899	case CASE_ESC_SP_STATE:
4900	    /* esc space */
4901	    sp->parsestate = esc_sp_table;
4902	    break;
4903
4904	case CASE_CSI_EX_STATE:
4905	    /* csi exclamation */
4906	    sp->parsestate = csi_ex_table;
4907	    break;
4908
4909	case CASE_CSI_TICK_STATE:
4910	    /* csi tick (') */
4911	    sp->parsestate = csi_tick_table;
4912	    break;
4913
4914#if OPT_DEC_LOCATOR
4915	case CASE_DECEFR:
4916	    TRACE(("CASE_DECEFR - Enable Filter Rectangle\n"));
4917	    if (okSendMousePos(xw) == DEC_LOCATOR) {
4918		MotionOff(screen, xw);
4919		if ((screen->loc_filter_top = GetParam(0)) < 1)
4920		    screen->loc_filter_top = LOC_FILTER_POS;
4921		if (nparam < 2
4922		    || (screen->loc_filter_left = GetParam(1)) < 1)
4923		    screen->loc_filter_left = LOC_FILTER_POS;
4924		if (nparam < 3
4925		    || (screen->loc_filter_bottom = GetParam(2)) < 1)
4926		    screen->loc_filter_bottom = LOC_FILTER_POS;
4927		if (nparam < 4
4928		    || (screen->loc_filter_right = GetParam(3)) < 1)
4929		    screen->loc_filter_right = LOC_FILTER_POS;
4930		InitLocatorFilter(xw);
4931	    }
4932	    ResetState(sp);
4933	    break;
4934
4935	case CASE_DECELR:
4936	    MotionOff(screen, xw);
4937	    if (GetParam(0) <= 0 || GetParam(0) > 2) {
4938		screen->send_mouse_pos = MOUSE_OFF;
4939		TRACE(("DECELR - Disable Locator Reports\n"));
4940	    } else {
4941		TRACE(("DECELR - Enable Locator Reports\n"));
4942		screen->send_mouse_pos = DEC_LOCATOR;
4943		xtermShowPointer(xw, True);
4944		if (GetParam(0) == 2) {
4945		    screen->locator_reset = True;
4946		} else {
4947		    screen->locator_reset = False;
4948		}
4949		if (nparam < 2 || GetParam(1) != 1) {
4950		    screen->locator_pixels = False;
4951		} else {
4952		    screen->locator_pixels = True;
4953		}
4954		screen->loc_filter = False;
4955	    }
4956	    ResetState(sp);
4957	    break;
4958
4959	case CASE_DECSLE:
4960	    TRACE(("DECSLE - Select Locator Events\n"));
4961	    for (count = 0; count < nparam; ++count) {
4962		switch (zero_if_default(count)) {
4963		case 0:
4964		    MotionOff(screen, xw);
4965		    screen->loc_filter = False;
4966		    screen->locator_events = 0;
4967		    break;
4968		case 1:
4969		    screen->locator_events |= LOC_BTNS_DN;
4970		    break;
4971		case 2:
4972		    UIntClr(screen->locator_events, LOC_BTNS_DN);
4973		    break;
4974		case 3:
4975		    screen->locator_events |= LOC_BTNS_UP;
4976		    break;
4977		case 4:
4978		    UIntClr(screen->locator_events, LOC_BTNS_UP);
4979		    break;
4980		}
4981	    }
4982	    ResetState(sp);
4983	    break;
4984
4985	case CASE_DECRQLP:
4986	    TRACE(("DECRQLP - Request Locator Position\n"));
4987	    if (GetParam(0) < 2) {
4988		/* Issue DECLRP Locator Position Report */
4989		GetLocatorPosition(xw);
4990	    }
4991	    ResetState(sp);
4992	    break;
4993#endif /* OPT_DEC_LOCATOR */
4994
4995#if OPT_DEC_RECTOPS
4996	case CASE_CSI_DOLLAR_STATE:
4997	    TRACE(("CASE_CSI_DOLLAR_STATE\n"));
4998	    /* csi dollar ($) */
4999	    if (screen->vtXX_level >= 3)
5000		sp->parsestate = csi_dollar_table;
5001	    else
5002		sp->parsestate = eigtable;
5003	    break;
5004
5005	case CASE_CSI_STAR_STATE:
5006	    TRACE(("CASE_CSI_STAR_STATE\n"));
5007	    /* csi star (*) */
5008	    if (screen->vtXX_level >= 4)
5009		sp->parsestate = csi_star_table;
5010	    else
5011		sp->parsestate = eigtable;
5012	    break;
5013
5014	case CASE_DECRQCRA:
5015	    if (screen->vtXX_level >= 4 && AllowWindowOps(xw, ewGetChecksum)) {
5016		int checksum;
5017		int pid;
5018
5019		TRACE(("CASE_DECRQCRA - Request checksum of rectangular area\n"));
5020		xtermCheckRect(xw, ParamPair(0), &checksum);
5021		init_reply(ANSI_DCS);
5022		count = 0;
5023		checksum &= 0xffff;
5024		pid = GetParam(0);
5025		reply.a_param[count++] = (ParmType) pid;
5026		reply.a_delim = "!~";	/* delimiter */
5027		reply.a_radix[count] = 16;
5028		reply.a_param[count++] = (ParmType) checksum;
5029		reply.a_nparam = (ParmType) count;
5030		TRACE(("...checksum(%d) = %04X\n", pid, checksum));
5031		unparseseq(xw, &reply);
5032	    }
5033	    ResetState(sp);
5034	    break;
5035
5036	case CASE_DECCRA:
5037	    if (screen->vtXX_level >= 4) {
5038		TRACE(("CASE_DECCRA - Copy rectangular area\n"));
5039		xtermParseRect(xw, ParamPair(0), &myRect);
5040		ScrnCopyRectangle(xw, &myRect, ParamPair(5));
5041	    }
5042	    ResetState(sp);
5043	    break;
5044
5045	case CASE_DECERA:
5046	    if (screen->vtXX_level >= 4) {
5047		TRACE(("CASE_DECERA - Erase rectangular area\n"));
5048		xtermParseRect(xw, ParamPair(0), &myRect);
5049		ScrnFillRectangle(xw, &myRect, ' ', xw->flags, True);
5050	    }
5051	    ResetState(sp);
5052	    break;
5053
5054	case CASE_DECFRA:
5055	    if (screen->vtXX_level >= 4) {
5056		value = zero_if_default(0);
5057
5058		TRACE(("CASE_DECFRA - Fill rectangular area\n"));
5059		if (nparam > 0 && CharWidth(screen, value) > 0) {
5060		    xtermParseRect(xw, ParamPair(1), &myRect);
5061		    ScrnFillRectangle(xw, &myRect, value, xw->flags, True);
5062		}
5063	    }
5064	    ResetState(sp);
5065	    break;
5066
5067	case CASE_DECSERA:
5068	    if (screen->vtXX_level >= 4) {
5069		TRACE(("CASE_DECSERA - Selective erase rectangular area\n"));
5070		xtermParseRect(xw, ParamPair(0), &myRect);
5071		ScrnWipeRectangle(xw, &myRect);
5072	    }
5073	    ResetState(sp);
5074	    break;
5075
5076	case CASE_DECSACE:
5077	    TRACE(("CASE_DECSACE - Select attribute change extent\n"));
5078	    screen->cur_decsace = zero_if_default(0);
5079	    ResetState(sp);
5080	    break;
5081
5082	case CASE_DECCARA:
5083	    if (screen->vtXX_level >= 4) {
5084		TRACE(("CASE_DECCARA - Change attributes in rectangular area\n"));
5085		xtermParseRect(xw, ParamPair(0), &myRect);
5086		ScrnMarkRectangle(xw, &myRect, False, ParamPair(4));
5087	    }
5088	    ResetState(sp);
5089	    break;
5090
5091	case CASE_DECRARA:
5092	    if (screen->vtXX_level >= 4) {
5093		TRACE(("CASE_DECRARA - Reverse attributes in rectangular area\n"));
5094		xtermParseRect(xw, ParamPair(0), &myRect);
5095		ScrnMarkRectangle(xw, &myRect, True, ParamPair(4));
5096	    }
5097	    ResetState(sp);
5098	    break;
5099
5100	case CASE_DECSCPP:
5101	    if (screen->vtXX_level >= 3) {
5102		TRACE(("CASE_DECSCPP\n"));
5103		/* default and 0 are "80", with "132" as the other legal choice */
5104		switch (zero_if_default(0)) {
5105		case 0:
5106		case 80:
5107		    value = 80;
5108		    break;
5109		case 132:
5110		    value = 132;
5111		    break;
5112		default:
5113		    value = -1;
5114		    break;
5115		}
5116		if (value > 0) {
5117		    if (screen->cur_col + 1 > value)
5118			CursorSet(screen, screen->cur_row, value - 1, xw->flags);
5119		    UIntClr(xw->flags, IN132COLUMNS);
5120		    if (value == 132)
5121			UIntSet(xw->flags, IN132COLUMNS);
5122		    RequestResize(xw, -1, value, True);
5123		}
5124	    }
5125	    ResetState(sp);
5126	    break;
5127
5128	case CASE_DECSNLS:
5129	    if (screen->vtXX_level >= 4 && AllowWindowOps(xw, ewSetWinLines)) {
5130		TRACE(("CASE_DECSNLS\n"));
5131		value = zero_if_default(0);
5132		if (value >= 1 && value <= 255) {
5133		    RequestResize(xw, value, -1, True);
5134		}
5135	    }
5136	    ResetState(sp);
5137	    break;
5138
5139	case CASE_DECRQPSR:
5140#define reply_char(n,c) do { reply.a_radix[(n)] = 1; reply.a_param[(n)++] = (ParmType)(c); } while (0)
5141#define reply_bit(n,c) ((n) ? (c) : 0)
5142	    if (screen->vtXX_level >= 3) {
5143		TRACE(("CASE_DECRQPSR\n"));
5144		switch (GetParam(0)) {
5145		case 1:
5146		    TRACE(("...DECCIR\n"));
5147		    init_reply(ANSI_DCS);
5148		    count = 0;
5149		    reply_char(count, '1');
5150		    reply_char(count, '$');
5151		    reply_char(count, 'u');
5152		    reply.a_param[count++] = (ParmType) (screen->cur_row + 1);
5153		    reply.a_param[count++] = (ParmType) (screen->cur_col + 1);
5154		    reply.a_param[count++] = (ParmType) thispage;
5155		    reply_char(count, ';');
5156		    reply_char(count, (0x40
5157				       | reply_bit(xw->flags & INVERSE, 8)
5158				       | reply_bit(xw->flags & BLINK, 4)
5159				       | reply_bit(xw->flags & UNDERLINE, 2)
5160				       | reply_bit(xw->flags & BOLD, 1)
5161			       ));
5162		    reply_char(count, ';');
5163		    reply_char(count, 0x40 |
5164			       reply_bit(screen->protected_mode &
5165					 DEC_PROTECT, 1)
5166			);
5167		    reply_char(count, ';');
5168		    reply_char(count, (0x40
5169				       | reply_bit(screen->do_wrap, 8)
5170				       | reply_bit((screen->curss == 3), 4)
5171				       | reply_bit((screen->curss == 2), 2)
5172				       | reply_bit(xw->flags & ORIGIN, 1)
5173			       ));
5174		    reply_char(count, ';');
5175		    reply.a_param[count++] = screen->curgl;
5176		    reply.a_param[count++] = screen->curgr;
5177		    reply_char(count, ';');
5178		    reply_char(count, 0x4f);	/* assert all 96's */
5179		    reply_char(count, ';');
5180		    for (item = 0; item < NUM_GSETS; ++item) {
5181			char *temp = encode_scs(screen->gsets[item]);
5182			while (*temp != '\0') {
5183			    reply_char(count, *temp++);
5184			}
5185		    }
5186		    reply.a_nparam = (ParmType) count;
5187		    unparseseq(xw, &reply);
5188		    break;
5189		case 2:
5190		    TRACE(("...DECTABSR\n"));
5191		    init_reply(ANSI_DCS);
5192		    reply.a_delim = "/";
5193		    count = 0;
5194		    reply_char(count, '2');
5195		    reply_char(count, '$');
5196		    reply_char(count, 'u');
5197		    for (item = 0; item < MAX_TABS; ++item) {
5198			if (count + 1 >= NPARAM)
5199			    break;
5200			if (TabIsSet(xw->tabs, item)) {
5201			    reply.a_param[count++] = (ParmType) (item + 1);
5202			}
5203			if (item > screen->max_col)
5204			    break;
5205		    }
5206		    reply.a_nparam = (ParmType) count;
5207		    unparseseq(xw, &reply);
5208		    break;
5209		}
5210	    }
5211	    ResetState(sp);
5212	    break;
5213
5214	case CASE_RQM:
5215	    TRACE(("CASE_RQM\n"));
5216	    do_ansi_rqm(xw, ParamPair(0));
5217	    ResetState(sp);
5218	    break;
5219
5220	case CASE_DECRQM:
5221	    TRACE(("CASE_DECRQM\n"));
5222	    do_dec_rqm(xw, ParamPair(0));
5223	    ResetState(sp);
5224	    break;
5225
5226	case CASE_CSI_DEC_DOLLAR_STATE:
5227	    TRACE(("CASE_CSI_DEC_DOLLAR_STATE\n"));
5228	    /* csi ? dollar ($) */
5229	    sp->parsestate = csi_dec_dollar_table;
5230	    break;
5231#else
5232	case CASE_CSI_DOLLAR_STATE:
5233	    /* csi dollar ($) */
5234	    sp->parsestate = eigtable;
5235	    break;
5236
5237	case CASE_CSI_STAR_STATE:
5238	    /* csi dollar (*) */
5239	    sp->parsestate = eigtable;
5240	    break;
5241
5242	case CASE_CSI_DEC_DOLLAR_STATE:
5243	    /* csi ? dollar ($) */
5244	    sp->parsestate = eigtable;
5245	    break;
5246#endif /* OPT_DEC_RECTOPS */
5247
5248	case CASE_DECSASD:
5249#if OPT_STATUS_LINE
5250	    if (screen->vtXX_level >= 2) {
5251		handle_DECSASD(xw, zero_if_default(0));
5252	    }
5253#endif
5254	    ResetState(sp);
5255	    break;
5256
5257	case CASE_DECSSDT:
5258#if OPT_STATUS_LINE
5259	    if (screen->vtXX_level >= 2) {
5260		handle_DECSSDT(xw, zero_if_default(0));
5261	    }
5262#endif
5263	    ResetState(sp);
5264	    break;
5265
5266#if OPT_XTERM_SGR
5267	case CASE_CSI_HASH_STATE:
5268	    TRACE(("CASE_CSI_HASH_STATE\n"));
5269	    /* csi hash (#) */
5270	    sp->parsestate = csi_hash_table;
5271	    break;
5272
5273	case CASE_XTERM_CHECKSUM:
5274#if OPT_DEC_RECTOPS
5275	    if (screen->vtXX_level >= 4 && AllowWindowOps(xw, ewSetChecksum)) {
5276		TRACE(("CASE_XTERM_CHECKSUM\n"));
5277		screen->checksum_ext = zero_if_default(0);
5278	    }
5279#endif
5280	    ResetState(sp);
5281	    break;
5282
5283	case CASE_XTERM_PUSH_SGR:
5284	    TRACE(("CASE_XTERM_PUSH_SGR\n"));
5285	    value = 0;
5286	    if (nparam == 0 || (nparam == 1 && GetParam(0) == DEFAULT)) {
5287		value = DEFAULT;
5288	    } else if (nparam > 0) {
5289		for (count = 0; count < nparam; ++count) {
5290		    item = zero_if_default(count);
5291		    /* deprecated - for compatibility */
5292#if OPT_ISO_COLORS
5293		    if (item == psFG_COLOR_obs) {
5294			item = psFG_COLOR;
5295		    } else if (item == psBG_COLOR_obs) {
5296			item = psBG_COLOR;
5297		    }
5298#endif
5299		    if (item > 0 && item < MAX_PUSH_SGR) {
5300			value |= (1 << (item - 1));
5301		    }
5302		}
5303	    }
5304	    xtermPushSGR(xw, value);
5305	    ResetState(sp);
5306	    break;
5307
5308	case CASE_XTERM_REPORT_SGR:
5309	    TRACE(("CASE_XTERM_REPORT_SGR\n"));
5310	    xtermParseRect(xw, ParamPair(0), &myRect);
5311	    xtermReportSGR(xw, &myRect);
5312	    ResetState(sp);
5313	    break;
5314
5315	case CASE_XTERM_POP_SGR:
5316	    TRACE(("CASE_XTERM_POP_SGR\n"));
5317	    xtermPopSGR(xw);
5318	    ResetState(sp);
5319	    break;
5320
5321	case CASE_XTERM_PUSH_COLORS:
5322	    TRACE(("CASE_XTERM_PUSH_COLORS\n"));
5323	    if (nparam == 0) {
5324		xtermPushColors(xw, DEFAULT);
5325	    } else {
5326		for (count = 0; count < nparam; ++count) {
5327		    xtermPushColors(xw, GetParam(count));
5328		}
5329	    }
5330	    ResetState(sp);
5331	    break;
5332
5333	case CASE_XTERM_POP_COLORS:
5334	    TRACE(("CASE_XTERM_POP_COLORS\n"));
5335	    if (nparam == 0) {
5336		xtermPopColors(xw, DEFAULT);
5337	    } else {
5338		for (count = 0; count < nparam; ++count) {
5339		    xtermPopColors(xw, GetParam(count));
5340		}
5341	    }
5342	    ResetState(sp);
5343	    break;
5344
5345	case CASE_XTERM_REPORT_COLORS:
5346	    TRACE(("CASE_XTERM_REPORT_COLORS\n"));
5347	    xtermReportColors(xw);
5348	    ResetState(sp);
5349	    break;
5350#endif
5351
5352	case CASE_S7C1T:
5353	    TRACE(("CASE_S7C1T\n"));
5354	    if (screen->vtXX_level >= 2) {
5355		show_8bit_control(False);
5356		ResetState(sp);
5357	    }
5358	    break;
5359
5360	case CASE_S8C1T:
5361	    TRACE(("CASE_S8C1T\n"));
5362	    if (screen->vtXX_level >= 2) {
5363		show_8bit_control(True);
5364		ResetState(sp);
5365	    }
5366	    break;
5367
5368	case CASE_OSC:
5369	    TRACE(("CASE_OSC: Operating System Command\n"));
5370	    sp->parsestate = sos_table;
5371	    sp->string_mode = ANSI_OSC;
5372	    break;
5373
5374	case CASE_RIS:
5375	    TRACE(("CASE_RIS\n"));
5376	    VTReset(xw, True, True);
5377	    /* NOTREACHED */
5378
5379	case CASE_DECSTR:
5380	    TRACE(("CASE_DECSTR\n"));
5381	    VTReset(xw, False, False);
5382	    /* NOTREACHED */
5383
5384	case CASE_REP:
5385	    TRACE(("CASE_REP\n"));
5386	    if (CharWidth(screen, sp->lastchar) > 0) {
5387		IChar repeated[2];
5388		count = one_if_default(0);
5389		repeated[0] = (IChar) sp->lastchar;
5390		while (count-- > 0) {
5391		    dotext(xw,
5392			   screen->gsets[(int) (screen->curgl)],
5393			   repeated, 1);
5394		}
5395	    }
5396	    ResetState(sp);
5397	    break;
5398
5399	case CASE_LS2:
5400	    TRACE(("CASE_LS2\n"));
5401	    screen->curgl = 2;
5402	    ResetState(sp);
5403	    break;
5404
5405	case CASE_LS3:
5406	    TRACE(("CASE_LS3\n"));
5407	    screen->curgl = 3;
5408	    ResetState(sp);
5409	    break;
5410
5411	case CASE_LS3R:
5412	    TRACE(("CASE_LS3R\n"));
5413	    screen->curgr = 3;
5414	    ResetState(sp);
5415	    break;
5416
5417	case CASE_LS2R:
5418	    TRACE(("CASE_LS2R\n"));
5419	    screen->curgr = 2;
5420	    ResetState(sp);
5421	    break;
5422
5423	case CASE_LS1R:
5424	    TRACE(("CASE_LS1R\n"));
5425	    screen->curgr = 1;
5426	    ResetState(sp);
5427	    break;
5428
5429	case CASE_XTERM_SAVE:
5430	    savemodes(xw);
5431	    ResetState(sp);
5432	    break;
5433
5434	case CASE_XTERM_RESTORE:
5435	    restoremodes(xw);
5436	    ResetState(sp);
5437	    break;
5438
5439	case CASE_XTERM_WINOPS:
5440	    TRACE(("CASE_XTERM_WINOPS\n"));
5441	    window_ops(xw);
5442	    ResetState(sp);
5443	    break;
5444#if OPT_WIDE_CHARS
5445	case CASE_ESC_PERCENT:
5446	    TRACE(("CASE_ESC_PERCENT\n"));
5447	    sp->parsestate = esc_pct_table;
5448	    break;
5449
5450	case CASE_UTF8:
5451	    /* If we did not set UTF-8 mode from resource or the
5452	     * command-line, allow it to be enabled/disabled by
5453	     * control sequence.
5454	     */
5455	    TRACE(("CASE_UTF8 wide:%d, utf8:%d, req:%s\n",
5456		   screen->wide_chars,
5457		   screen->utf8_mode,
5458		   BtoS(c == 'G')));
5459	    if ((!screen->wide_chars) && (c == 'G')) {
5460		WriteNow();
5461		ChangeToWide(xw);
5462	    }
5463	    if (screen->wide_chars
5464		&& !screen->utf8_always) {
5465		switchPtyData(screen, c == 'G');
5466		TRACE(("UTF8 mode %s\n",
5467		       BtoS(screen->utf8_mode)));
5468	    } else {
5469		TRACE(("UTF8 mode NOT turned %s (%s)\n",
5470		       BtoS(c == 'G'),
5471		       (screen->utf8_mode == uAlways)
5472		       ? "UTF-8 mode set from command-line"
5473		       : "wideChars resource was not set"));
5474	    }
5475	    ResetState(sp);
5476	    break;
5477
5478	case CASE_SCS_DQUOTE:
5479	    TRACE(("CASE_SCS_DQUOTE\n"));
5480	    sp->parsestate = scs_2qt_table;
5481	    break;
5482
5483	case CASE_GSETS_DQUOTE:
5484	    if (screen->vtXX_level >= 5) {
5485		TRACE(("CASE_GSETS_DQUOTE(%d) = '%c'\n", sp->scstype, c));
5486		xtermDecodeSCS(xw, sp->scstype, 5, '"', (int) c);
5487	    }
5488	    ResetState(sp);
5489	    break;
5490
5491	case CASE_SCS_AMPRSND:
5492	    TRACE(("CASE_SCS_AMPRSND\n"));
5493	    sp->parsestate = scs_amp_table;
5494	    break;
5495
5496	case CASE_GSETS_AMPRSND:
5497	    if (screen->vtXX_level >= 5) {
5498		TRACE(("CASE_GSETS_AMPRSND(%d) = '%c'\n", sp->scstype, c));
5499		xtermDecodeSCS(xw, sp->scstype, 5, '&', (int) c);
5500	    }
5501	    ResetState(sp);
5502	    break;
5503
5504	case CASE_SCS_PERCENT:
5505	    TRACE(("CASE_SCS_PERCENT\n"));
5506	    sp->parsestate = scs_pct_table;
5507	    break;
5508
5509	case CASE_GSETS_PERCENT:
5510	    if (screen->vtXX_level >= 3) {
5511		TRACE(("CASE_GSETS_PERCENT(%d) = '%c'\n", sp->scstype, c));
5512		switch (c) {
5513		case '0':	/* DEC Turkish */
5514		case '2':	/* Turkish */
5515		case '=':	/* Hebrew */
5516		    value = 5;
5517		    break;
5518		case '5':	/* DEC Supplemental Graphics */
5519		case '6':	/* Portuguese */
5520		default:
5521		    value = 3;
5522		    break;
5523		}
5524		xtermDecodeSCS(xw, sp->scstype, value, '%', (int) c);
5525	    }
5526	    ResetState(sp);
5527	    break;
5528#endif
5529	case CASE_XTERM_SHIFT_ESCAPE:
5530	    TRACE(("CASE_XTERM_SHIFT_ESCAPE\n"));
5531	    value = ((nparam == 0)
5532		     ? 0
5533		     : one_if_default(0));
5534	    if (value >= 0 && value <= 1)
5535		xw->keyboard.shift_escape = value;
5536	    ResetState(sp);
5537	    break;
5538
5539#if OPT_MOD_FKEYS
5540	case CASE_SET_MOD_FKEYS:
5541	    TRACE(("CASE_SET_MOD_FKEYS\n"));
5542	    if (nparam >= 1) {
5543		set_mod_fkeys(xw,
5544			      GetParam(0),
5545			      ((nparam > 1)
5546			       ? GetParam(1)
5547			       : DEFAULT),
5548			      True);
5549	    } else {
5550		for (value = 1; value <= 5; ++value)
5551		    set_mod_fkeys(xw, value, DEFAULT, True);
5552	    }
5553	    ResetState(sp);
5554	    break;
5555
5556	case CASE_SET_MOD_FKEYS0:
5557	    TRACE(("CASE_SET_MOD_FKEYS0\n"));
5558	    if (nparam >= 1 && GetParam(0) != DEFAULT) {
5559		set_mod_fkeys(xw, GetParam(0), -1, False);
5560	    } else {
5561		xw->keyboard.modify_now.function_keys = -1;
5562	    }
5563	    ResetState(sp);
5564	    break;
5565#endif
5566	case CASE_HIDE_POINTER:
5567	    TRACE(("CASE_HIDE_POINTER\n"));
5568	    if (nparam >= 1 && GetParam(0) != DEFAULT) {
5569		screen->pointer_mode = GetParam(0);
5570	    } else {
5571		screen->pointer_mode = DEF_POINTER_MODE;
5572	    }
5573	    ResetState(sp);
5574	    break;
5575
5576	case CASE_XTERM_SM_TITLE:
5577	    TRACE(("CASE_XTERM_SM_TITLE\n"));
5578	    if (nparam >= 1) {
5579		int n;
5580		for (n = 0; n < nparam; ++n) {
5581		    if (GetParam(n) != DEFAULT)
5582			screen->title_modes |= (1 << GetParam(n));
5583		}
5584	    } else {
5585		screen->title_modes = DEF_TITLE_MODES;
5586	    }
5587	    TRACE(("...title_modes %#x\n", screen->title_modes));
5588	    ResetState(sp);
5589	    break;
5590
5591	case CASE_XTERM_RM_TITLE:
5592	    TRACE(("CASE_XTERM_RM_TITLE\n"));
5593	    if (nparam >= 1) {
5594		int n;
5595		for (n = 0; n < nparam; ++n) {
5596		    if (GetParam(n) != DEFAULT)
5597			screen->title_modes &= ~(1 << GetParam(n));
5598		}
5599	    } else {
5600		screen->title_modes = DEF_TITLE_MODES;
5601	    }
5602	    TRACE(("...title_modes %#x\n", screen->title_modes));
5603	    ResetState(sp);
5604	    break;
5605
5606	case CASE_CSI_IGNORE:
5607	    sp->parsestate = cigtable;
5608	    break;
5609
5610	case CASE_DECSWBV:
5611	    TRACE(("CASE_DECSWBV\n"));
5612	    switch (zero_if_default(0)) {
5613	    case 2:
5614		/* FALLTHRU */
5615	    case 3:
5616		/* FALLTHRU */
5617	    case 4:
5618		screen->warningVolume = bvLow;
5619		break;
5620	    case 5:
5621		/* FALLTHRU */
5622	    case 6:
5623		/* FALLTHRU */
5624	    case 7:
5625		/* FALLTHRU */
5626	    case 8:
5627		screen->warningVolume = bvHigh;
5628		break;
5629	    default:
5630		screen->warningVolume = bvOff;
5631		break;
5632	    }
5633	    TRACE(("...warningVolume %d\n", screen->warningVolume));
5634	    ResetState(sp);
5635	    break;
5636
5637	case CASE_DECSMBV:
5638	    TRACE(("CASE_DECSMBV\n"));
5639	    switch (zero_if_default(0)) {
5640	    case 2:
5641		/* FALLTHRU */
5642	    case 3:
5643		/* FALLTHRU */
5644	    case 4:
5645		screen->marginVolume = bvLow;
5646		break;
5647	    case 0:
5648		/* FALLTHRU */
5649	    case 5:
5650		/* FALLTHRU */
5651	    case 6:
5652		/* FALLTHRU */
5653	    case 7:
5654		/* FALLTHRU */
5655	    case 8:
5656		screen->marginVolume = bvHigh;
5657		break;
5658	    default:
5659		screen->marginVolume = bvOff;
5660		break;
5661	    }
5662	    TRACE(("...marginVolume %d\n", screen->marginVolume));
5663	    ResetState(sp);
5664	    break;
5665	}
5666	if (sp->parsestate == sp->groundtable)
5667	    sp->lastchar = thischar;
5668    } while (0);
5669
5670#if OPT_WIDE_CHARS
5671    screen->utf8_inparse = (Boolean) ((screen->utf8_mode != uFalse)
5672				      && (sp->parsestate != sos_table));
5673#endif
5674
5675    if (sp->check_recur)
5676	sp->check_recur--;
5677    return True;
5678}
5679
5680static void
5681VTparse(XtermWidget xw)
5682{
5683    Boolean keep_running;
5684
5685    /* We longjmp back to this point in VTReset() */
5686    (void) setjmp(vtjmpbuf);
5687    init_parser(xw, &myState);
5688
5689    do {
5690	keep_running = doparsing(xw, doinput(xw), &myState);
5691	if (myState.check_recur == 0 && myState.defer_used != 0) {
5692	    while (myState.defer_used) {
5693		Char *deferred = myState.defer_area;
5694		size_t len = myState.defer_used;
5695		size_t i;
5696		myState.defer_area = NULL;
5697		myState.defer_size = 0;
5698		myState.defer_used = 0;
5699		for (i = 0; i < len; i++) {
5700		    (void) doparsing(xw, deferred[i], &myState);
5701		}
5702		free(deferred);
5703	    }
5704	} else {
5705	    free(myState.defer_area);
5706	}
5707	myState.defer_area = NULL;
5708	myState.defer_size = 0;
5709	myState.defer_used = 0;
5710    } while (keep_running);
5711}
5712
5713static Char *v_buffer;		/* pointer to physical buffer */
5714static Char *v_bufstr = NULL;	/* beginning of area to write */
5715static Char *v_bufptr;		/* end of area to write */
5716static Char *v_bufend;		/* end of physical buffer */
5717
5718/* Write data to the pty as typed by the user, pasted with the mouse,
5719   or generated by us in response to a query ESC sequence. */
5720
5721void
5722v_write(int f, const Char *data, unsigned len)
5723{
5724    TRACE2(("v_write(%d:%s)\n", len, visibleChars(data, len)));
5725    if (v_bufstr == NULL) {
5726	if (len > 0) {
5727	    v_buffer = (Char *) XtMalloc((Cardinal) len);
5728	    v_bufstr = v_buffer;
5729	    v_bufptr = v_buffer;
5730	    v_bufend = v_buffer + len;
5731	}
5732	if (v_bufstr == NULL) {
5733	    return;
5734	}
5735    }
5736    if_DEBUG({
5737	fprintf(stderr, "v_write called with %u bytes (%ld left over)",
5738		len, (long) (v_bufptr - v_bufstr));
5739	if (len > 1 && len < 10)
5740	    fprintf(stderr, " \"%.*s\"", len, (const char *) data);
5741	fprintf(stderr, "\n");
5742    });
5743
5744#ifdef VMS
5745    if ((1 << f) != pty_mask) {
5746	tt_write((const char *) data, len);
5747	return;
5748    }
5749#else /* VMS */
5750    if (!FD_ISSET(f, &pty_mask)) {
5751	IGNORE_RC(write(f, (const char *) data, (size_t) len));
5752	return;
5753    }
5754#endif /* VMS */
5755
5756    /*
5757     * Append to the block we already have.
5758     * Always doing this simplifies the code, and
5759     * isn't too bad, either.  If this is a short
5760     * block, it isn't too expensive, and if this is
5761     * a long block, we won't be able to write it all
5762     * anyway.
5763     */
5764
5765    if (len > 0) {
5766#if OPT_DABBREV
5767	TScreenOf(term)->dabbrev_working = False;	/* break dabbrev sequence */
5768#endif
5769	if (v_bufend < v_bufptr + len) {	/* we've run out of room */
5770	    if (v_bufstr != v_buffer) {
5771		/* there is unused space, move everything down */
5772		/* possibly overlapping memmove here */
5773		if_DEBUG({
5774		    fprintf(stderr, "moving data down %ld\n",
5775			    (long) (v_bufstr - v_buffer));
5776		});
5777		memmove(v_buffer, v_bufstr, (size_t) (v_bufptr - v_bufstr));
5778		v_bufptr -= v_bufstr - v_buffer;
5779		v_bufstr = v_buffer;
5780	    }
5781	    if (v_bufend < v_bufptr + len) {
5782		/* still won't fit: get more space */
5783		/* Don't use XtRealloc because an error is not fatal. */
5784		unsigned size = (unsigned) (v_bufptr - v_buffer);
5785		v_buffer = TypeRealloc(Char, size + len, v_buffer);
5786		if (v_buffer) {
5787		    if_DEBUG({
5788			fprintf(stderr, "expanded buffer to %u\n",
5789				size + len);
5790		    });
5791		    v_bufstr = v_buffer;
5792		    v_bufptr = v_buffer + size;
5793		    v_bufend = v_bufptr + len;
5794		} else {
5795		    /* no memory: ignore entire write request */
5796		    xtermWarning("cannot allocate buffer space\n");
5797		    v_buffer = v_bufstr;	/* restore clobbered pointer */
5798		}
5799	    }
5800	}
5801	if (v_bufend >= v_bufptr + len) {
5802	    /* new stuff will fit */
5803	    memmove(v_bufptr, data, (size_t) len);
5804	    v_bufptr += len;
5805	}
5806    }
5807
5808    /*
5809     * Write out as much of the buffer as we can.
5810     * Be careful not to overflow the pty's input silo.
5811     * We are conservative here and only write
5812     * a small amount at a time.
5813     *
5814     * If we can't push all the data into the pty yet, we expect write
5815     * to return a non-negative number less than the length requested
5816     * (if some data written) or -1 and set errno to EAGAIN,
5817     * EWOULDBLOCK, or EINTR (if no data written).
5818     *
5819     * (Not all systems do this, sigh, so the code is actually
5820     * a little more forgiving.)
5821     */
5822
5823#define MAX_PTY_WRITE 128	/* 1/2 POSIX minimum MAX_INPUT */
5824
5825    if (v_bufptr > v_bufstr) {
5826	int riten;
5827
5828#ifdef VMS
5829	riten = tt_write(v_bufstr,
5830			 ((v_bufptr - v_bufstr <= VMS_TERM_BUFFER_SIZE)
5831			  ? v_bufptr - v_bufstr
5832			  : VMS_TERM_BUFFER_SIZE));
5833	if (riten == 0)
5834	    return (riten);
5835#else /* VMS */
5836	riten = (int) write(f, v_bufstr,
5837			    (size_t) ((v_bufptr - v_bufstr <= MAX_PTY_WRITE)
5838				      ? v_bufptr - v_bufstr
5839				      : MAX_PTY_WRITE));
5840	if (riten < 0)
5841#endif /* VMS */
5842	{
5843	    if_DEBUG({
5844		perror("write");
5845	    });
5846	    riten = 0;
5847	}
5848	if_DEBUG({
5849	    fprintf(stderr, "write called with %ld, wrote %d\n",
5850		    ((long) ((v_bufptr - v_bufstr) <= MAX_PTY_WRITE)
5851		     ? (long) (v_bufptr - v_bufstr)
5852		     : MAX_PTY_WRITE),
5853		    riten);
5854	});
5855	v_bufstr += riten;
5856	if (v_bufstr >= v_bufptr)	/* we wrote it all */
5857	    v_bufstr = v_bufptr = v_buffer;
5858    }
5859
5860    /*
5861     * If we have lots of unused memory allocated, return it
5862     */
5863    if (v_bufend - v_bufptr > 1024) {	/* arbitrary hysteresis */
5864	/* save pointers across realloc */
5865	int start = (int) (v_bufstr - v_buffer);
5866	int size = (int) (v_bufptr - v_buffer);
5867	unsigned allocsize = (unsigned) (size ? size : 1);
5868
5869	v_buffer = TypeRealloc(Char, allocsize, v_buffer);
5870	if (v_buffer) {
5871	    v_bufstr = v_buffer + start;
5872	    v_bufptr = v_buffer + size;
5873	    v_bufend = v_buffer + allocsize;
5874	    if_DEBUG({
5875		fprintf(stderr, "shrunk buffer to %u\n", allocsize);
5876	    });
5877	} else {
5878	    /* should we print a warning if couldn't return memory? */
5879	    v_buffer = v_bufstr - start;	/* restore clobbered pointer */
5880	}
5881    }
5882}
5883
5884static void
5885updateCursor(XtermWidget xw)
5886{
5887    TScreen *screen = TScreenOf(xw);
5888
5889    if (screen->cursor_set != screen->cursor_state) {
5890	if (screen->cursor_set)
5891	    ShowCursor(xw);
5892	else
5893	    HideCursor(xw);
5894    }
5895}
5896
5897#if OPT_BLINK_CURS || OPT_BLINK_TEXT
5898static void
5899reallyStopBlinking(XtermWidget xw)
5900{
5901    TScreen *screen = TScreenOf(xw);
5902
5903    if (screen->cursor_state == BLINKED_OFF) {
5904	/* force cursor to display if it is enabled */
5905	screen->cursor_state = !screen->cursor_set;
5906	updateCursor(xw);
5907	xevents(xw);
5908    }
5909}
5910#endif
5911
5912static void
5913update_the_screen(XtermWidget xw)
5914{
5915    TScreen *screen = TScreenOf(xw);
5916    Boolean moved;
5917
5918    if (screen->scroll_amt)
5919	FlushScroll(xw);
5920    moved = CursorMoved(screen);
5921    if (screen->cursor_set && moved) {
5922	if (screen->cursor_state)
5923	    HideCursor(xw);
5924	ShowCursor(xw);
5925#if OPT_INPUT_METHOD
5926	PreeditPosition(xw);
5927#endif
5928    } else {
5929#if OPT_INPUT_METHOD
5930	if (moved)
5931	    PreeditPosition(xw);
5932#endif
5933	updateCursor(xw);
5934    }
5935}
5936
5937#ifdef VMS
5938#define	ptymask()	(v_bufptr > v_bufstr ? pty_mask : 0)
5939
5940static void
5941in_put(XtermWidget xw)
5942{
5943    static PtySelect select_mask;
5944    static PtySelect write_mask;
5945    int update = VTbuffer->update;
5946    int size;
5947
5948    int status;
5949    Dimension replyWidth, replyHeight;
5950    XtGeometryResult stat;
5951
5952    TScreen *screen = TScreenOf(xw);
5953    char *cp;
5954    int i;
5955
5956    select_mask = pty_mask;	/* force initial read */
5957    for (;;) {
5958
5959	/* if the terminal changed size, resize the widget */
5960	if (tt_changed) {
5961	    tt_changed = False;
5962
5963	    stat = REQ_RESIZE((Widget) xw,
5964			      ((Dimension) FontWidth(screen)
5965			       * (tt_width)
5966			       + 2 * screen->border
5967			       + screen->fullVwin.sb_info.width),
5968			      ((Dimension) FontHeight(screen)
5969			       * (tt_length)
5970			       + 2 * screen->border),
5971			      &replyWidth, &replyHeight);
5972
5973	    if (stat == XtGeometryYes || stat == XtGeometryDone) {
5974		xw->core.width = replyWidth;
5975		xw->core.height = replyHeight;
5976
5977		ScreenResize(xw, replyWidth, replyHeight, &xw->flags);
5978	    }
5979	    repairSizeHints();
5980	}
5981
5982	if (screen->eventMode == NORMAL
5983	    && readPtyData(xw, &select_mask, VTbuffer)) {
5984	    if (screen->scrollWidget
5985		&& screen->scrollttyoutput
5986		&& screen->topline < 0)
5987		/* Scroll to bottom */
5988		WindowScroll(xw, 0, False);
5989	    break;
5990	}
5991	update_the_screen(xw);
5992
5993	if (QLength(screen->display)) {
5994	    select_mask = X_mask;
5995	} else {
5996	    write_mask = ptymask();
5997	    XFlush(screen->display);
5998	    select_mask = Select_mask;
5999	    if (screen->eventMode != NORMAL)
6000		select_mask = X_mask;
6001	}
6002	if (write_mask & ptymask()) {
6003	    v_write(screen->respond, 0, 0);	/* flush buffer */
6004	}
6005
6006	if (select_mask & X_mask) {
6007	    xevents(xw);
6008	    if (VTbuffer->update != update)
6009		break;
6010	}
6011    }
6012}
6013#else /* VMS */
6014
6015static void
6016init_timeval(struct timeval *target, long usecs)
6017{
6018    target->tv_sec = 0;
6019    target->tv_usec = usecs;
6020    while (target->tv_usec > 1000000) {
6021	target->tv_usec -= 1000000;
6022	target->tv_sec++;
6023    }
6024}
6025
6026static Boolean
6027better_timeout(struct timeval *check, struct timeval *against)
6028{
6029    Boolean result = False;
6030    if (against->tv_sec == 0 && against->tv_usec == 0) {
6031	result = True;
6032    } else if (check->tv_sec == against->tv_sec) {
6033	if (check->tv_usec < against->tv_usec) {
6034	    result = True;
6035	}
6036    } else if (check->tv_sec < against->tv_sec) {
6037	result = True;
6038    }
6039    return result;
6040}
6041
6042#if OPT_BLINK_CURS
6043static long
6044smaller_timeout(long value)
6045{
6046    /* 1000 for msec/usec, 8 for "much" smaller */
6047    value *= (1000 / 8);
6048    if (value < 1)
6049	value = 1;
6050    return value;
6051}
6052#endif
6053
6054static void
6055in_put(XtermWidget xw)
6056{
6057    static PtySelect select_mask;
6058    static PtySelect write_mask;
6059
6060    TScreen *screen = TScreenOf(xw);
6061    int i;
6062    int update = VTbuffer->update;
6063#if USE_DOUBLE_BUFFER
6064    int should_wait = 1;
6065#endif
6066    struct timeval my_timeout;
6067
6068    for (;;) {
6069	int size;
6070	int time_select;
6071
6072	if (screen->eventMode == NORMAL
6073	    && (size = readPtyData(xw, &select_mask, VTbuffer)) != 0) {
6074	    if (screen->scrollWidget
6075		&& screen->scrollttyoutput
6076		&& screen->topline < 0)
6077		WindowScroll(xw, 0, False);	/* Scroll to bottom */
6078	    /* stop speed reading at some point to look for X stuff */
6079	    TRACE(("VTbuffer uses %ld/%d\n",
6080		   (long) (VTbuffer->last - VTbuffer->buffer),
6081		   BUF_SIZE));
6082	    if ((VTbuffer->last - VTbuffer->buffer) > BUF_SIZE) {
6083		FD_CLR(screen->respond, &select_mask);
6084		break;
6085	    }
6086#if USE_DOUBLE_BUFFER
6087	    if (resource.buffered && should_wait) {
6088		/* wait for potential extra data (avoids some flickering) */
6089		usleep((unsigned) DbeMsecs(xw));
6090		should_wait = 0;
6091	    }
6092#endif
6093#if defined(HAVE_SCHED_YIELD)
6094	    /*
6095	     * If we've read a full (small/fragment) buffer, let the operating
6096	     * system have a turn, and we'll resume reading until we've either
6097	     * read only a fragment of the buffer, or we've filled the large
6098	     * buffer (see above).  Doing this helps keep up with large bursts
6099	     * of output.
6100	     */
6101	    if (size == FRG_SIZE) {
6102		init_timeval(&my_timeout, 0);
6103		i = Select(max_plus1, &select_mask, &write_mask, 0, &my_timeout);
6104		if (i > 0 && FD_ISSET(screen->respond, &select_mask)) {
6105		    sched_yield();
6106		} else
6107		    break;
6108	    } else {
6109		break;
6110	    }
6111#else
6112	    (void) size;	/* unused in this branch */
6113	    break;
6114#endif
6115	}
6116	update_the_screen(xw);
6117
6118	XFlush(screen->display);	/* always flush writes before waiting */
6119
6120	/* Update the masks and, unless X events are already in the queue,
6121	   wait for I/O to be possible. */
6122	XFD_COPYSET(&Select_mask, &select_mask);
6123	/* in selection mode xterm does not read pty */
6124	if (screen->eventMode != NORMAL)
6125	    FD_CLR(screen->respond, &select_mask);
6126
6127	if (v_bufptr > v_bufstr) {
6128	    XFD_COPYSET(&pty_mask, &write_mask);
6129	} else
6130	    FD_ZERO(&write_mask);
6131	init_timeval(&my_timeout, 0);
6132	time_select = 0;
6133
6134	/*
6135	 * if there's either an XEvent or an XtTimeout pending, just take
6136	 * a quick peek, i.e. timeout from the select() immediately.  If
6137	 * there's nothing pending, let select() block a little while, but
6138	 * for a shorter interval than the arrow-style scrollbar timeout.
6139	 * The blocking is optional, because it tends to increase the load
6140	 * on the host.
6141	 */
6142	if (xtermAppPending()) {
6143	    time_select = 1;
6144	} else {
6145#define ImproveTimeout(usecs) \
6146		struct timeval try_timeout; \
6147		init_timeval(&try_timeout, usecs); \
6148		if (better_timeout(&try_timeout, &my_timeout)) { \
6149		    my_timeout = try_timeout; \
6150		}
6151#if OPT_STATUS_LINE
6152	    if ((screen->status_type == 1) && screen->status_timeout) {
6153		ImproveTimeout(find_SL_Timeout(xw) * 1000);
6154		time_select = 1;
6155	    }
6156#endif
6157	    if (screen->awaitInput) {
6158		ImproveTimeout(50000);
6159		time_select = 1;
6160	    }
6161#if OPT_BLINK_CURS
6162	    if ((screen->blink_timer != 0 &&
6163		 ((screen->select & FOCUS) || screen->always_highlight)) ||
6164		(screen->cursor_state == BLINKED_OFF)) {
6165		/*
6166		 * Compute the timeout for the blinking cursor to be much
6167		 * smaller than the "on" or "off" interval.
6168		 */
6169		long tick = smaller_timeout((screen->blink_on < screen->blink_off)
6170					    ? screen->blink_on
6171					    : screen->blink_off);
6172		ImproveTimeout(tick);
6173		time_select = 1;
6174	    }
6175#endif
6176	}
6177#if OPT_SESSION_MGT
6178	if (resource.sessionMgt && (ice_fd >= 0)) {
6179	    FD_SET(ice_fd, &select_mask);
6180	}
6181#endif
6182	if (need_cleanup)
6183	    NormalExit();
6184	xtermFlushDbe(xw);
6185	i = Select(max_plus1, &select_mask, &write_mask, 0,
6186		   (time_select ? &my_timeout : 0));
6187	if (i < 0) {
6188	    if (errno != EINTR)
6189		SysError(ERROR_SELECT);
6190	    continue;
6191	}
6192
6193	/* if there is room to write more data to the pty, go write more */
6194	if (FD_ISSET(screen->respond, &write_mask)) {
6195	    v_write(screen->respond, (Char *) 0, 0);	/* flush buffer */
6196	}
6197
6198	/* if there are X events already in our queue, it
6199	   counts as being readable */
6200	if (xtermAppPending() ||
6201	    FD_ISSET(ConnectionNumber(screen->display), &select_mask)) {
6202	    xevents(xw);
6203	    if (VTbuffer->update != update)	/* HandleInterpret */
6204		break;
6205	}
6206
6207    }
6208}
6209#endif /* VMS */
6210
6211static IChar
6212doinput(XtermWidget xw)
6213{
6214    TScreen *screen = TScreenOf(xw);
6215
6216    while (!morePtyData(screen, VTbuffer))
6217	in_put(xw);
6218    return nextPtyData(screen, VTbuffer);
6219}
6220
6221#if OPT_INPUT_METHOD
6222/*
6223 *  For OverTheSpot, client has to inform the position for XIM preedit.
6224 */
6225static void
6226PreeditPosition(XtermWidget xw)
6227{
6228    TInput *input = lookupTInput(xw, (Widget) xw);
6229    TScreen *screen = TScreenOf(xw);
6230    CLineData *ld;
6231    XPoint spot;
6232    XVaNestedList list;
6233
6234    if (input && input->xic
6235	&& (ld = getLineData(screen, screen->cur_row)) != 0) {
6236	spot.x = (short) LineCursorX(screen, ld, screen->cur_col);
6237	spot.y = (short) (CursorY(screen, screen->cur_row) + xw->work.xim_fs_ascent);
6238	list = XVaCreateNestedList(0,
6239				   XNSpotLocation, &spot,
6240				   XNForeground, T_COLOR(screen, TEXT_FG),
6241				   XNBackground, T_COLOR(screen, TEXT_BG),
6242				   (void *) 0);
6243	XSetICValues(input->xic, XNPreeditAttributes, list, (void *) 0);
6244	XFree(list);
6245    }
6246}
6247#endif
6248
6249static void
6250WrapLine(XtermWidget xw)
6251{
6252    TScreen *screen = TScreenOf(xw);
6253    LineData *ld = getLineData(screen, screen->cur_row);
6254
6255    if (ld != 0) {
6256	/* mark that we had to wrap this line */
6257	LineSetFlag(ld, LINEWRAPPED);
6258	ShowWrapMarks(xw, screen->cur_row, ld);
6259	xtermAutoPrint(xw, '\n');
6260	xtermIndex(xw, 1);
6261	set_cur_col(screen, ScrnLeftMargin(xw));
6262    }
6263}
6264
6265/*
6266 * Process a string of characters according to the character set indicated by
6267 * charset.  Worry about end of line conditions (wraparound if selected).
6268 *
6269 * It is possible to use CUP, etc., to move outside margins.  In that case, the
6270 * right-margin is ineffective until the text (may) wrap and get within the
6271 * margins.
6272 */
6273void
6274dotext(XtermWidget xw,
6275       DECNRCM_codes charset,
6276       IChar *buf,		/* start of characters to process */
6277       Cardinal len)		/* end */
6278{
6279    TScreen *screen = TScreenOf(xw);
6280#if OPT_WIDE_CHARS
6281    Cardinal chars_chomped = 1;
6282    int next_col = screen->cur_col;
6283#else
6284    int next_col, this_col;	/* must be signed */
6285#endif
6286    Cardinal offset;
6287    int rmargin = ScrnRightMargin(xw);
6288
6289#if OPT_WIDE_CHARS
6290    if (screen->vt100_graphics)
6291#endif
6292	if (!(len = (Cardinal) xtermCharSetOut(xw, buf, buf + len, charset)))
6293	    return;
6294
6295    if_OPT_XMC_GLITCH(screen, {
6296	Cardinal n;
6297	if (charset != '?') {
6298	    for (n = 0; n < len; n++) {
6299		if (buf[n] == XMC_GLITCH)
6300		    buf[n] = XMC_GLITCH + 1;
6301	    }
6302	}
6303    });
6304
6305#if OPT_WIDE_CHARS
6306    for (offset = 0;
6307	 offset < len && (chars_chomped > 0 || screen->do_wrap);
6308	 offset += chars_chomped) {
6309#if OPT_DEC_CHRSET
6310	CLineData *ld = getLineData(screen, screen->cur_row);
6311	int real_rmargin = (CSET_DOUBLE(GetLineDblCS(ld))
6312			    ? (rmargin / 2)
6313			    : rmargin);
6314#else
6315	int real_rmargin = rmargin;
6316#endif
6317	int last_col = LineMaxCol(screen, ld);
6318	int width_here = 0;
6319	int last_chomp = 0;
6320	Boolean force_wrap;
6321
6322	chars_chomped = 0;
6323	do {
6324	    int right = ((screen->cur_col > real_rmargin)
6325			 ? last_col
6326			 : real_rmargin);
6327	    int width_available = right + 1 - screen->cur_col;
6328	    Boolean need_wrap = False;
6329	    Boolean did_wrap = False;
6330
6331	    force_wrap = False;
6332
6333	    if (screen->do_wrap) {
6334		screen->do_wrap = False;
6335		if ((xw->flags & WRAPAROUND)) {
6336		    WrapLine(xw);
6337		    right = ((screen->cur_col > real_rmargin)
6338			     ? last_col
6339			     : real_rmargin);
6340		    width_available = right + 1 - screen->cur_col;
6341		    next_col = screen->cur_col;
6342		    did_wrap = True;
6343		}
6344	    }
6345
6346	    /*
6347	     * This can happen with left/right margins...
6348	     */
6349	    if (width_available <= 0) {
6350		break;
6351	    }
6352
6353	    /*
6354	     * Regarding the soft-hyphen aberration, see
6355	     * http://archives.miloush.net/michkap/archive/2006/09/02/736881.html
6356	     */
6357	    while (width_here <= width_available
6358		   && chars_chomped < (len - offset)) {
6359		Cardinal n = chars_chomped + offset;
6360		if (!screen->utf8_mode
6361		    || (screen->vt100_graphics && charset == '0')) {
6362		    last_chomp = 1;
6363		} else if (screen->c1_printable &&
6364			   buf[n] >= 0x80 &&
6365			   buf[n] <= 0xa0) {
6366		    last_chomp = 1;
6367		} else {
6368		    last_chomp = CharWidth(screen, buf[n]);
6369		    if (last_chomp <= 0) {
6370			IChar ch = buf[n];
6371			Bool eat_it = !screen->utf8_mode && (ch > 127);
6372			if (ch == 0xad) {
6373			    /*
6374			     * Only display soft-hyphen if it happens to be at
6375			     * the right-margin.  While that means that only
6376			     * the displayed character could be selected for
6377			     * pasting, a well-behaved application would never
6378			     * send this, anyway...
6379			     */
6380			    if (width_here < width_available - 1) {
6381				eat_it = True;
6382			    } else {
6383				last_chomp = 1;
6384				eat_it = False;
6385			    }
6386			    TRACE(("...will%s display soft-hyphen\n",
6387				   eat_it ? " not" : ""));
6388			}
6389			/*
6390			 * Supposedly we dealt with combining characters and
6391			 * control characters in doparse().  Anything left over
6392			 * is junk that we will not attempt to display.
6393			 */
6394			if (eat_it) {
6395			    TRACE(("...will not display U+%04X\n", ch));
6396			    --len;
6397			    while (n < len) {
6398				buf[n] = buf[n + 1];
6399				++n;
6400			    }
6401			    last_chomp = 0;
6402			    chars_chomped--;
6403			}
6404		    }
6405		}
6406		width_here += last_chomp;
6407		chars_chomped++;
6408	    }
6409
6410	    if (width_here > width_available) {
6411		if (last_chomp > right + 1) {
6412		    break;	/* give up - it is too big */
6413		} else if (chars_chomped-- == 0) {
6414		    /* This can happen with left/right margins... */
6415		    break;
6416		}
6417		width_here -= last_chomp;
6418		if (chars_chomped > 0) {
6419		    if (!(xw->flags & WRAPAROUND)) {
6420			buf[chars_chomped + offset - 1] = buf[len - 1];
6421		    } else {
6422			need_wrap = True;
6423		    }
6424		}
6425	    } else if (width_here == width_available) {
6426		need_wrap = True;
6427	    } else if (chars_chomped != (len - offset)) {
6428		need_wrap = True;
6429	    }
6430
6431	    if (chars_chomped != 0 && next_col <= last_col) {
6432		WriteText(xw, buf + offset, chars_chomped);
6433	    } else if (!did_wrap
6434		       && len > 0
6435		       && (xw->flags & WRAPAROUND)
6436		       && screen->cur_col > ScrnLeftMargin(xw)) {
6437		force_wrap = True;
6438		need_wrap = True;
6439	    }
6440	    next_col += width_here;
6441	    screen->do_wrap = need_wrap;
6442	} while (force_wrap);
6443    }
6444
6445    /*
6446     * Remember that we wrote something to the screen, for use as a base of
6447     * combining characters.  The logic above may have called cursor-forward
6448     * or carriage-return operations which resets this flag, so we set it at
6449     * the very end.
6450     */
6451    screen->char_was_written = True;
6452#else /* ! OPT_WIDE_CHARS */
6453
6454    for (offset = 0; offset < len; offset += (Cardinal) this_col) {
6455#if OPT_DEC_CHRSET
6456	CLineData *ld = getLineData(screen, screen->cur_row);
6457#endif
6458	int right = ((screen->cur_col > rmargin)
6459		     ? screen->max_col
6460		     : rmargin);
6461
6462	int last_col = LineMaxCol(screen, ld);
6463	if (last_col > right)
6464	    last_col = right;
6465	this_col = last_col - screen->cur_col + 1;
6466	if (screen->do_wrap) {
6467	    screen->do_wrap = False;
6468	    if ((xw->flags & WRAPAROUND)) {
6469		WrapLine(xw);
6470	    }
6471	    this_col = 1;
6472	}
6473	if (offset + (Cardinal) this_col > len) {
6474	    this_col = (int) (len - offset);
6475	}
6476	next_col = screen->cur_col + this_col;
6477
6478	WriteText(xw, buf + offset, (unsigned) this_col);
6479
6480	/*
6481	 * The call to WriteText updates screen->cur_col.
6482	 * If screen->cur_col is less than next_col, we must have
6483	 * hit the right margin - so set the do_wrap flag.
6484	 */
6485	screen->do_wrap = (Boolean) (screen->cur_col < next_col);
6486    }
6487
6488#endif /* OPT_WIDE_CHARS */
6489}
6490
6491#if OPT_WIDE_CHARS
6492unsigned
6493visual_width(const IChar *str, Cardinal len)
6494{
6495    /* returns the visual width of a string (doublewide characters count
6496       as 2, normalwide characters count as 1) */
6497    unsigned my_len = 0;
6498    while (len) {
6499	int ch = (int) *str++;
6500	if (isWide(ch))
6501	    my_len += 2;
6502	else
6503	    my_len++;
6504	len--;
6505    }
6506    return my_len;
6507}
6508#endif
6509
6510#if HANDLE_STRUCT_NOTIFY
6511/* Flag icon name with "***" on window output when iconified.
6512 */
6513static void
6514HandleStructNotify(Widget w GCC_UNUSED,
6515		   XtPointer closure GCC_UNUSED,
6516		   XEvent *event,
6517		   Boolean *cont GCC_UNUSED)
6518{
6519    XtermWidget xw = term;
6520    TScreen *screen = TScreenOf(xw);
6521
6522    (void) screen;
6523    TRACE_EVENT("HandleStructNotify", event, NULL, 0);
6524    switch (event->type) {
6525    case MapNotify:
6526	resetZIconBeep(xw);
6527	mapstate = !IsUnmapped;
6528	break;
6529    case UnmapNotify:
6530	mapstate = IsUnmapped;
6531	break;
6532    case MappingNotify:
6533	XRefreshKeyboardMapping(&(event->xmapping));
6534	VTInitModifiers(xw);
6535	break;
6536    case ConfigureNotify:
6537	if (event->xconfigure.window == XtWindow(toplevel)) {
6538#if !OPT_TOOLBAR
6539	    int height = event->xconfigure.height;
6540	    int width = event->xconfigure.width;
6541#endif
6542
6543#if USE_DOUBLE_BUFFER
6544	    discardRenderDraw(screen);
6545#endif /* USE_DOUBLE_BUFFER */
6546#if OPT_TOOLBAR
6547	    /*
6548	     * The notification is for the top-level widget, but we care about
6549	     * vt100 (ignore the tek4014 window).
6550	     */
6551	    if (screen->Vshow) {
6552		VTwin *Vwin = WhichVWin(screen);
6553		TbInfo *info = &(Vwin->tb_info);
6554		TbInfo save = *info;
6555
6556		if (info->menu_bar) {
6557		    XtVaGetValues(info->menu_bar,
6558				  XtNheight, &info->menu_height,
6559				  XtNborderWidth, &info->menu_border,
6560				  (XtPointer) 0);
6561
6562		    if (save.menu_height != info->menu_height
6563			|| save.menu_border != info->menu_border) {
6564
6565			TRACE(("...menu_height %d\n", info->menu_height));
6566			TRACE(("...menu_border %d\n", info->menu_border));
6567			TRACE(("...had height  %d, border %d\n",
6568			       save.menu_height,
6569			       save.menu_border));
6570
6571			/*
6572			 * Window manager still may be using the old values.
6573			 * Try to fool it.
6574			 */
6575			REQ_RESIZE((Widget) xw,
6576				   screen->fullVwin.fullwidth,
6577				   (Dimension) (info->menu_height
6578						- save.menu_height
6579						+ screen->fullVwin.fullheight),
6580				   NULL, NULL);
6581			repairSizeHints();
6582		    }
6583		}
6584	    }
6585#else
6586	    if (!xw->work.doing_resize
6587#if OPT_RENDERFONT && USE_DOUBLE_BUFFER
6588		&& !(resource.buffered && UsingRenderFont(xw))	/* buggyXft */
6589#endif
6590		&& (height != xw->hints.height
6591		    || width != xw->hints.width)) {
6592		/*
6593		 * This is a special case: other calls to RequestResize that
6594		 * could set the screensize arbitrarily are via escape
6595		 * sequences, and we've limited resizing.  But a configure
6596		 * notify is from the window manager, presumably under control
6597		 * of the interactive user (ignoring abuse of wmctrl).  Ignore
6598		 * the limit for this case.
6599		 */
6600		int saved_limit = xw->misc.limit_resize;
6601		xw->misc.limit_resize = 0;
6602		RequestResize(xw, height, width, False);
6603		xw->misc.limit_resize = saved_limit;
6604	    }
6605#endif /* OPT_TOOLBAR */
6606	}
6607	break;
6608    }
6609}
6610#endif /* HANDLE_STRUCT_NOTIFY */
6611
6612#if OPT_BLINK_CURS
6613static int
6614DoStartBlinking(TScreen *screen)
6615{
6616    int actual = ((screen->cursor_blink == cbTrue ||
6617		   screen->cursor_blink == cbAlways)
6618		  ? 1
6619		  : 0);
6620    int wanted = screen->cursor_blink_esc ? 1 : 0;
6621    int result;
6622    if (screen->cursor_blink_xor) {
6623	result = actual ^ wanted;
6624    } else {
6625	result = actual | wanted;
6626    }
6627    return result;
6628}
6629
6630static void
6631SetCursorBlink(XtermWidget xw, BlinkOps enable)
6632{
6633    TScreen *screen = TScreenOf(xw);
6634
6635    if (SettableCursorBlink(screen)) {
6636	screen->cursor_blink = enable;
6637    }
6638    if (DoStartBlinking(screen)) {
6639	StartBlinking(xw);
6640    } else {
6641	/* EMPTY */
6642#if OPT_BLINK_TEXT
6643	reallyStopBlinking(xw);
6644#else
6645	StopBlinking(xw);
6646#endif
6647    }
6648    update_cursorblink();
6649}
6650
6651void
6652ToggleCursorBlink(XtermWidget xw)
6653{
6654    TScreen *screen = TScreenOf(xw);
6655
6656    if (screen->cursor_blink == cbTrue) {
6657	SetCursorBlink(xw, cbFalse);
6658    } else if (screen->cursor_blink == cbFalse) {
6659	SetCursorBlink(xw, cbTrue);
6660    }
6661}
6662#endif
6663
6664/*
6665 * process ANSI modes set, reset
6666 */
6667static void
6668ansi_modes(XtermWidget xw, BitFunc func)
6669{
6670    int i;
6671
6672    for (i = 0; i < nparam; ++i) {
6673	switch (GetParam(i)) {
6674	case 2:		/* KAM (if set, keyboard locked */
6675	    (*func) (&xw->keyboard.flags, MODE_KAM);
6676	    break;
6677
6678	case 4:		/* IRM                          */
6679	    (*func) (&xw->flags, INSERT);
6680	    break;
6681
6682	case 12:		/* SRM (if set, local echo      */
6683	    (*func) (&xw->keyboard.flags, MODE_SRM);
6684	    break;
6685
6686	case 20:		/* LNM                          */
6687	    (*func) (&xw->flags, LINEFEED);
6688	    update_autolinefeed();
6689	    break;
6690	}
6691    }
6692}
6693
6694#define IsSM() (func == bitset)
6695
6696#define set_bool_mode(flag) \
6697	flag = (Boolean) IsSM()
6698
6699static void
6700really_set_mousemode(XtermWidget xw,
6701		     Bool enabled,
6702		     XtermMouseModes mode)
6703{
6704    TScreenOf(xw)->send_mouse_pos = enabled ? mode : MOUSE_OFF;
6705    if (okSendMousePos(xw) != MOUSE_OFF)
6706	xtermShowPointer(xw, True);
6707}
6708
6709#define set_mousemode(mode) really_set_mousemode(xw, IsSM(), mode)
6710
6711#if OPT_PASTE64 || OPT_READLINE
6712#define set_mouseflag(f)		\
6713	(IsSM()				\
6714	 ? SCREEN_FLAG_set(screen, f)	\
6715	 : SCREEN_FLAG_unset(screen, f))
6716#endif
6717
6718/*
6719 * DEC 070, pp 5-29 to 5-30 (DECLRMM).
6720 * DEC 070, pp 5-71 to 5-72 (DECCOLM).
6721 *
6722 * The descriptions for DECLRMM and DECCOLM agree that setting DECLRMM resets
6723 * double-sized mode to single-size, and that if DECLRMM is being set, then
6724 * double-sized mode is disabled.  Resetting DECLRMM has no effect on the
6725 * double-sized mode.  The description of DECCOLM has an apparent error in its
6726 * pseudo-code (because it is inconsistent with the description of DECLRMM),
6727 * indicating that left_right_margins_mode is changed to SETABLE no matter
6728 * which way DECCOLM is set.
6729 */
6730static void
6731set_column_mode(XtermWidget xw)
6732{
6733    TScreen *screen = TScreenOf(xw);
6734
6735    /* switch 80/132 columns clears the screen and sets to single-width */
6736    xterm_ResetDouble(xw);
6737    resetMargins(xw);
6738    CursorSet(screen, 0, 0, xw->flags);
6739}
6740
6741/*
6742 * DEC 070, pp 5-29 to 5-30.
6743 */
6744static void
6745set_left_right_margin_mode(XtermWidget xw)
6746{
6747    TScreen *screen = TScreenOf(xw);
6748
6749    if (screen->vtXX_level >= 4) {
6750	if (IsLeftRightMode(xw)) {
6751	    xterm_ResetDouble(xw);
6752	} else {
6753	    reset_lr_margins(screen);
6754	}
6755    }
6756}
6757
6758/*
6759 * process DEC private modes set, reset
6760 */
6761static void
6762dpmodes(XtermWidget xw, BitFunc func)
6763{
6764    TScreen *screen = TScreenOf(xw);
6765    int i, j;
6766    unsigned myflags;
6767
6768    TRACE(("changing %d DEC private modes\n", nparam));
6769    if_STATUS_LINE(screen, {
6770	return;
6771    });
6772    for (i = 0; i < nparam; ++i) {
6773	int code = GetParam(i);
6774
6775	TRACE(("%s %d\n", IsSM()? "DECSET" : "DECRST", code));
6776	switch ((DECSET_codes) code) {
6777	case srm_DECCKM:
6778	    (*func) (&xw->keyboard.flags, MODE_DECCKM);
6779	    update_appcursor();
6780	    break;
6781	case srm_DECANM:	/* ANSI/VT52 mode      */
6782	    if (IsSM()) {	/* ANSI (VT100) */
6783		/*
6784		 * Setting DECANM should have no effect, since this function
6785		 * cannot be reached from vt52 mode.
6786		 */
6787		/* EMPTY */ ;
6788	    }
6789#if OPT_VT52_MODE
6790	    else if (screen->terminal_id >= 100) {	/* VT52 */
6791		TRACE(("DECANM terminal_id %d, vtXX_level %d\n",
6792		       screen->terminal_id,
6793		       screen->vtXX_level));
6794		/*
6795		 * According to DEC STD 070 section A.5.5, the various VT100
6796		 * modes have undefined behavior when entering/exiting VT52
6797		 * mode.  xterm saves/restores/initializes the most commonly
6798		 * used settings, but a real VT100 or VT520 may differ.
6799		 *
6800		 * For instance, DEC's documentation goes on to comment that
6801		 * while the VT52 uses hardware tabs (8 columns), the emulation
6802		 * (e.g., a VT420) does not alter those tab settings when
6803		 * switching modes.
6804		 */
6805		screen->vtXX_level = 0;
6806		screen->vt52_save_flags = xw->flags;
6807		xw->flags = 0;
6808		screen->vt52_save_curgl = screen->curgl;
6809		screen->vt52_save_curgr = screen->curgr;
6810		screen->vt52_save_curss = screen->curss;
6811		saveCharsets(screen, screen->vt52_save_gsets);
6812		resetCharsets(screen);
6813		InitParams();	/* ignore the remaining params, if any */
6814		update_vt52_vt100_settings();
6815		RequestResize(xw, -1, 80, True);
6816	    }
6817#endif
6818	    break;
6819	case srm_DECCOLM:
6820	    if (screen->c132) {
6821		Boolean willResize = ((j = IsSM()
6822				       ? 132
6823				       : 80)
6824				      != ((xw->flags & IN132COLUMNS)
6825					  ? 132
6826					  : 80)
6827				      || j != MaxCols(screen));
6828		if (!(xw->flags & NOCLEAR_COLM))
6829		    ClearScreen(xw);
6830		if (willResize)
6831		    RequestResize(xw, -1, j, True);
6832		(*func) (&xw->flags, IN132COLUMNS);
6833		set_column_mode(xw);
6834	    }
6835	    break;
6836	case srm_DECSCLM:	/* (slow scroll)        */
6837	    if (IsSM()) {
6838		screen->jumpscroll = 0;
6839		if (screen->scroll_amt)
6840		    FlushScroll(xw);
6841	    } else
6842		screen->jumpscroll = 1;
6843	    (*func) (&xw->flags, SMOOTHSCROLL);
6844	    update_jumpscroll();
6845	    break;
6846	case srm_DECSCNM:
6847	    myflags = xw->flags;
6848	    (*func) (&xw->flags, REVERSE_VIDEO);
6849	    if ((xw->flags ^ myflags) & REVERSE_VIDEO)
6850		ReverseVideo(xw);
6851	    /* update_reversevideo done in RevVid */
6852	    break;
6853
6854	case srm_DECOM:
6855	    (*func) (&xw->flags, ORIGIN);
6856	    CursorSet(screen, 0, 0, xw->flags);
6857	    break;
6858
6859	case srm_DECAWM:
6860	    (*func) (&xw->flags, WRAPAROUND);
6861	    update_autowrap();
6862	    break;
6863	case srm_DECARM:
6864	    /* ignore autorepeat
6865	     * XAutoRepeatOn() and XAutoRepeatOff() can do this, but only
6866	     * for the whole display - not limited to a given window.
6867	     */
6868	    break;
6869	case srm_X10_MOUSE:	/* MIT bogus sequence           */
6870	    MotionOff(screen, xw);
6871	    set_mousemode(X10_MOUSE);
6872	    break;
6873#if OPT_TOOLBAR
6874	case srm_RXVT_TOOLBAR:
6875	    ShowToolbar(IsSM());
6876	    break;
6877#endif
6878#if OPT_BLINK_CURS
6879	case srm_ATT610_BLINK:	/* AT&T 610: Start/stop blinking cursor */
6880	    if (SettableCursorBlink(screen)) {
6881		set_bool_mode(screen->cursor_blink_esc);
6882		UpdateCursorBlink(xw);
6883	    }
6884	    break;
6885	case srm_CURSOR_BLINK_OPS:
6886	    /* intentionally ignored (this is user-preference) */
6887	    break;
6888	case srm_XOR_CURSOR_BLINKS:
6889	    /* intentionally ignored (this is user-preference) */
6890	    break;
6891#endif
6892	case srm_DECPFF:	/* print form feed */
6893	    set_bool_mode(PrinterOf(screen).printer_formfeed);
6894	    break;
6895	case srm_DECPEX:	/* print extent */
6896	    set_bool_mode(PrinterOf(screen).printer_extent);
6897	    break;
6898	case srm_DECTCEM:	/* Show/hide cursor (VT200) */
6899	    set_bool_mode(screen->cursor_set);
6900	    break;
6901	case srm_RXVT_SCROLLBAR:
6902	    if (screen->fullVwin.sb_info.width != (IsSM()? ON : OFF))
6903		ToggleScrollBar(xw);
6904	    break;
6905#if OPT_SHIFT_FONTS
6906	case srm_RXVT_FONTSIZE:
6907	    set_bool_mode(xw->misc.shift_fonts);
6908	    break;
6909#endif
6910#if OPT_TEK4014
6911	case srm_DECTEK:
6912	    if (IsSM() && !(screen->inhibit & I_TEK)) {
6913		FlushLog(xw);
6914		TEK4014_ACTIVE(xw) = True;
6915		TRACE(("Tek4014 is now active...\n"));
6916		update_vttekmode();
6917	    }
6918	    break;
6919#endif
6920	case srm_132COLS:	/* 132 column mode              */
6921	    set_bool_mode(screen->c132);
6922	    update_allow132();
6923	    break;
6924	case srm_CURSES_HACK:
6925	    set_bool_mode(screen->curses);
6926	    update_cursesemul();
6927	    break;
6928	case srm_DECNRCM:	/* national charset (VT220) */
6929	    if (screen->vtXX_level >= 2) {
6930		if ((*func) (&xw->flags, NATIONAL)) {
6931		    modified_DECNRCM(xw);
6932		}
6933	    }
6934	    break;
6935#if OPT_PRINT_GRAPHICS
6936	case srm_DECGEPM:	/* Graphics Expanded Print Mode */
6937	    set_bool_mode(screen->graphics_expanded_print_mode);
6938	    break;
6939#endif
6940	case srm_MARGIN_BELL:	/* margin bell (xterm) also DECGPCM (Graphics Print Color Mode) */
6941	    if_PRINT_GRAPHICS2(set_bool_mode(screen->graphics_print_color_mode)) {
6942		set_bool_mode(screen->marginbell);
6943		if (!screen->marginbell)
6944		    screen->bellArmed = -1;
6945		update_marginbell();
6946	    }
6947	    break;
6948	case srm_REVERSEWRAP:	/* reverse wraparound (xterm) also DECGPCS (Graphics Print Color Syntax) */
6949	    if_PRINT_GRAPHICS2(set_bool_mode(screen->graphics_print_color_syntax)) {
6950		(*func) (&xw->flags, REVERSEWRAP);
6951		update_reversewrap();
6952	    }
6953	    break;
6954#ifdef ALLOWLOGGING
6955	case srm_ALLOWLOGGING:	/* logging (xterm) also DECGPBM (Graphics Print Background Mode) */
6956	    if_PRINT_GRAPHICS2(set_bool_mode(screen->graphics_print_background_mode)) {
6957#ifdef ALLOWLOGFILEONOFF
6958		/*
6959		 * if this feature is enabled, logging may be
6960		 * enabled and disabled via escape sequences.
6961		 */
6962		if (IsSM())
6963		    StartLog(xw);
6964		else
6965		    CloseLog(xw);
6966#else
6967		Bell(xw, XkbBI_Info, 0);
6968		Bell(xw, XkbBI_Info, 0);
6969#endif /* ALLOWLOGFILEONOFF */
6970	    }
6971	    break;
6972#elif OPT_PRINT_GRAPHICS
6973	case srm_DECGPBM:	/* Graphics Print Background Mode */
6974	    set_bool_mode(screen->graphics_print_background_mode);
6975	    break;
6976#endif /* ALLOWLOGGING */
6977	case srm_OPT_ALTBUF_CURSOR:	/* optional alternate buffer and clear (xterm) */
6978	    if (!xw->misc.titeInhibit) {
6979		if (IsSM()) {
6980		    CursorSave(xw);
6981		    ToAlternate(xw, True);
6982		    ClearScreen(xw);
6983		} else {
6984		    FromAlternate(xw);
6985		    CursorRestore(xw);
6986		}
6987	    } else if (IsSM()) {
6988		do_ti_xtra_scroll(xw);
6989	    }
6990	    break;
6991	case srm_OPT_ALTBUF:	/* optional alternate buffer and clear (xterm) */
6992	    if (!xw->misc.titeInhibit) {
6993		if (IsSM()) {
6994		    ToAlternate(xw, False);
6995		} else {
6996		    if (screen->whichBuf)
6997			ClearScreen(xw);
6998		    FromAlternate(xw);
6999		}
7000	    } else if (IsSM()) {
7001		do_ti_xtra_scroll(xw);
7002	    }
7003	    break;
7004	case srm_ALTBUF:	/* alternate buffer (xterm) also DECGRPM (Graphics Rotated Print Mode) */
7005	    if_PRINT_GRAPHICS2(set_bool_mode(screen->graphics_rotated_print_mode)) {
7006		if (!xw->misc.titeInhibit) {
7007		    if (IsSM()) {
7008			ToAlternate(xw, False);
7009		    } else {
7010			FromAlternate(xw);
7011		    }
7012		} else if (IsSM()) {
7013		    do_ti_xtra_scroll(xw);
7014		}
7015	    }
7016	    break;
7017	case srm_DECNKM:
7018	    (*func) (&xw->keyboard.flags, MODE_DECKPAM);
7019	    update_appkeypad();
7020	    break;
7021	case srm_DECBKM:
7022	    /* back-arrow mapped to backspace or delete(D) */
7023	    (*func) (&xw->keyboard.flags, MODE_DECBKM);
7024	    TRACE(("DECSET DECBKM %s\n",
7025		   BtoS(xw->keyboard.flags & MODE_DECBKM)));
7026	    update_decbkm();
7027	    break;
7028	case srm_DECLRMM:
7029	    if (screen->vtXX_level >= 4) {	/* VT420 */
7030		(*func) (&xw->flags, LEFT_RIGHT);
7031		set_left_right_margin_mode(xw);
7032	    }
7033	    break;
7034#if OPT_SIXEL_GRAPHICS
7035	case srm_DECSDM:	/* sixel scrolling */
7036	    if (optSixelGraphics(screen)) {	/* FIXME: VT24x did not scroll sixel graphics */
7037		(*func) (&xw->keyboard.flags, MODE_DECSDM);
7038		TRACE(("DECSET/DECRST DECSDM %s (resource default is %d)\n",
7039		       BtoS(xw->keyboard.flags & MODE_DECSDM),
7040		       TScreenOf(xw)->sixel_scrolling));
7041		update_decsdm();
7042	    }
7043	    break;
7044#endif
7045	case srm_DECNCSM:
7046	    if (screen->vtXX_level >= 5) {	/* VT510 */
7047		(*func) (&xw->flags, NOCLEAR_COLM);
7048	    }
7049	    break;
7050	case srm_VT200_MOUSE:	/* xterm bogus sequence         */
7051	    MotionOff(screen, xw);
7052	    set_mousemode(VT200_MOUSE);
7053	    break;
7054	case srm_VT200_HIGHLIGHT_MOUSE:	/* xterm sequence w/hilite tracking */
7055	    MotionOff(screen, xw);
7056	    set_mousemode(VT200_HIGHLIGHT_MOUSE);
7057	    break;
7058	case srm_BTN_EVENT_MOUSE:
7059	    MotionOff(screen, xw);
7060	    set_mousemode(BTN_EVENT_MOUSE);
7061	    break;
7062	case srm_ANY_EVENT_MOUSE:
7063	    set_mousemode(ANY_EVENT_MOUSE);
7064	    if (screen->send_mouse_pos == MOUSE_OFF) {
7065		MotionOff(screen, xw);
7066	    } else {
7067		MotionOn(screen, xw);
7068	    }
7069	    break;
7070#if OPT_FOCUS_EVENT
7071	case srm_FOCUS_EVENT_MOUSE:
7072	    set_bool_mode(screen->send_focus_pos);
7073	    break;
7074#endif
7075	case srm_EXT_MODE_MOUSE:
7076	    /* FALLTHRU */
7077	case srm_SGR_EXT_MODE_MOUSE:
7078	    /* FALLTHRU */
7079	case srm_URXVT_EXT_MODE_MOUSE:
7080	    /* FALLTHRU */
7081	case srm_PIXEL_POSITION_MOUSE:
7082	    /*
7083	     * Rather than choose an arbitrary precedence among the coordinate
7084	     * modes, they are mutually exclusive.  For consistency, a reset is
7085	     * only effective against the matching mode.
7086	     */
7087	    if (IsSM()) {
7088		screen->extend_coords = code;
7089	    } else if (screen->extend_coords == code) {
7090		screen->extend_coords = 0;
7091	    }
7092	    break;
7093	case srm_ALTERNATE_SCROLL:
7094	    set_bool_mode(screen->alternateScroll);
7095	    break;
7096	case srm_RXVT_SCROLL_TTY_OUTPUT:
7097	    set_bool_mode(screen->scrollttyoutput);
7098	    update_scrollttyoutput();
7099	    break;
7100	case srm_RXVT_SCROLL_TTY_KEYPRESS:
7101	    set_bool_mode(screen->scrollkey);
7102	    update_scrollkey();
7103	    break;
7104	case srm_EIGHT_BIT_META:
7105	    if (screen->eight_bit_meta != ebNever) {
7106		set_bool_mode(screen->eight_bit_meta);
7107	    }
7108	    break;
7109#if OPT_NUM_LOCK
7110	case srm_REAL_NUMLOCK:
7111	    set_bool_mode(xw->misc.real_NumLock);
7112	    update_num_lock();
7113	    break;
7114	case srm_META_SENDS_ESC:
7115	    set_bool_mode(screen->meta_sends_esc);
7116	    update_meta_esc();
7117	    break;
7118#endif
7119	case srm_DELETE_IS_DEL:
7120	    set_bool_mode(screen->delete_is_del);
7121	    update_delete_del();
7122	    break;
7123#if OPT_NUM_LOCK
7124	case srm_ALT_SENDS_ESC:
7125	    set_bool_mode(screen->alt_sends_esc);
7126	    update_alt_esc();
7127	    break;
7128#endif
7129	case srm_KEEP_SELECTION:
7130	    set_bool_mode(screen->keepSelection);
7131	    update_keepSelection();
7132	    break;
7133	case srm_SELECT_TO_CLIPBOARD:
7134	    set_bool_mode(screen->selectToClipboard);
7135	    update_selectToClipboard();
7136	    break;
7137	case srm_BELL_IS_URGENT:
7138	    set_bool_mode(screen->bellIsUrgent);
7139	    update_bellIsUrgent();
7140	    break;
7141	case srm_POP_ON_BELL:
7142	    set_bool_mode(screen->poponbell);
7143	    update_poponbell();
7144	    break;
7145	case srm_KEEP_CLIPBOARD:
7146	    set_bool_mode(screen->keepClipboard);
7147	    update_keepClipboard();
7148	    break;
7149	case srm_ALLOW_ALTBUF:
7150	    if (IsSM()) {
7151		xw->misc.titeInhibit = False;
7152	    } else if (!xw->misc.titeInhibit) {
7153		xw->misc.titeInhibit = True;
7154		FromAlternate(xw);
7155	    }
7156	    update_titeInhibit();
7157	    break;
7158	case srm_SAVE_CURSOR:
7159	    if (!xw->misc.titeInhibit) {
7160		if (IsSM())
7161		    CursorSave(xw);
7162		else
7163		    CursorRestore(xw);
7164	    }
7165	    break;
7166#if OPT_TCAP_FKEYS
7167	case srm_TCAP_FKEYS:
7168	    set_keyboard_type(xw, keyboardIsTermcap, IsSM());
7169	    break;
7170#endif
7171#if OPT_SUN_FUNC_KEYS
7172	case srm_SUN_FKEYS:
7173	    set_keyboard_type(xw, keyboardIsSun, IsSM());
7174	    break;
7175#endif
7176#if OPT_HP_FUNC_KEYS
7177	case srm_HP_FKEYS:
7178	    set_keyboard_type(xw, keyboardIsHP, IsSM());
7179	    break;
7180#endif
7181#if OPT_SCO_FUNC_KEYS
7182	case srm_SCO_FKEYS:
7183	    set_keyboard_type(xw, keyboardIsSCO, IsSM());
7184	    break;
7185#endif
7186	case srm_LEGACY_FKEYS:
7187	    set_keyboard_type(xw, keyboardIsLegacy, IsSM());
7188	    break;
7189#if OPT_SUNPC_KBD
7190	case srm_VT220_FKEYS:
7191	    set_keyboard_type(xw, keyboardIsVT220, IsSM());
7192	    break;
7193#endif
7194#if OPT_PASTE64 || OPT_READLINE
7195	case srm_PASTE_IN_BRACKET:
7196	    set_mouseflag(paste_brackets);
7197	    break;
7198#endif
7199#if OPT_READLINE
7200	case srm_BUTTON1_MOVE_POINT:
7201	    set_mouseflag(click1_moves);
7202	    break;
7203	case srm_BUTTON2_MOVE_POINT:
7204	    set_mouseflag(paste_moves);
7205	    break;
7206	case srm_DBUTTON3_DELETE:
7207	    set_mouseflag(dclick3_deletes);
7208	    break;
7209	case srm_PASTE_QUOTE:
7210	    set_mouseflag(paste_quotes);
7211	    break;
7212	case srm_PASTE_LITERAL_NL:
7213	    set_mouseflag(paste_literal_nl);
7214	    break;
7215#endif /* OPT_READLINE */
7216#if OPT_GRAPHICS
7217	case srm_PRIVATE_COLOR_REGISTERS:	/* private color registers for each graphic */
7218	    TRACE(("DECSET/DECRST PRIVATE_COLOR_REGISTERS to %s (resource default is %s)\n",
7219		   BtoS(screen->privatecolorregisters),
7220		   BtoS(TScreenOf(xw)->privatecolorregisters)));
7221	    set_bool_mode(screen->privatecolorregisters);
7222	    update_privatecolorregisters();
7223	    break;
7224#endif
7225#if OPT_SIXEL_GRAPHICS
7226	case srm_SIXEL_SCROLLS_RIGHT:	/* sixel scrolling moves cursor to right */
7227	    if (optSixelGraphics(screen)) {	/* FIXME: VT24x did not scroll sixel graphics */
7228		set_bool_mode(screen->sixel_scrolls_right);
7229		TRACE(("DECSET/DECRST SIXEL_SCROLLS_RIGHT to %s (resource default is %s)\n",
7230		       BtoS(screen->sixel_scrolls_right),
7231		       BtoS(TScreenOf(xw)->sixel_scrolls_right)));
7232	    }
7233	    break;
7234#endif
7235	default:
7236	    TRACE(("DATA_ERROR: unknown private code %d\n", code));
7237	    break;
7238	}
7239    }
7240}
7241
7242/*
7243 * process xterm private modes save
7244 */
7245static void
7246savemodes(XtermWidget xw)
7247{
7248    TScreen *screen = TScreenOf(xw);
7249    int i;
7250
7251    if_STATUS_LINE(screen, {
7252	return;
7253    });
7254    for (i = 0; i < nparam; i++) {
7255	int code = GetParam(i);
7256
7257	TRACE(("savemodes %d\n", code));
7258	switch ((DECSET_codes) code) {
7259	case srm_DECCKM:
7260	    DoSM(DP_DECCKM, xw->keyboard.flags & MODE_DECCKM);
7261	    break;
7262	case srm_DECANM:	/* ANSI/VT52 mode      */
7263	    /* no effect */
7264	    break;
7265	case srm_DECCOLM:
7266	    if (screen->c132)
7267		DoSM(DP_DECCOLM, xw->flags & IN132COLUMNS);
7268	    break;
7269	case srm_DECSCLM:	/* (slow scroll)        */
7270	    DoSM(DP_DECSCLM, xw->flags & SMOOTHSCROLL);
7271	    break;
7272	case srm_DECSCNM:
7273	    DoSM(DP_DECSCNM, xw->flags & REVERSE_VIDEO);
7274	    break;
7275	case srm_DECOM:
7276	    DoSM(DP_DECOM, xw->flags & ORIGIN);
7277	    break;
7278	case srm_DECAWM:
7279	    DoSM(DP_DECAWM, xw->flags & WRAPAROUND);
7280	    break;
7281	case srm_DECARM:
7282	    /* ignore autorepeat */
7283	    break;
7284	case srm_X10_MOUSE:	/* mouse bogus sequence */
7285	    DoSM(DP_X_X10MSE, screen->send_mouse_pos);
7286	    break;
7287#if OPT_TOOLBAR
7288	case srm_RXVT_TOOLBAR:
7289	    DoSM(DP_TOOLBAR, resource.toolBar);
7290	    break;
7291#endif
7292#if OPT_BLINK_CURS
7293	case srm_ATT610_BLINK:	/* AT&T 610: Start/stop blinking cursor */
7294	    if (SettableCursorBlink(screen)) {
7295		DoSM(DP_CRS_BLINK, screen->cursor_blink_esc);
7296	    }
7297	    break;
7298	case srm_CURSOR_BLINK_OPS:
7299	    /* intentionally ignored (this is user-preference) */
7300	    break;
7301	case srm_XOR_CURSOR_BLINKS:
7302	    /* intentionally ignored (this is user-preference) */
7303	    break;
7304#endif
7305	case srm_DECPFF:	/* print form feed */
7306	    DoSM(DP_PRN_FORMFEED, PrinterOf(screen).printer_formfeed);
7307	    break;
7308	case srm_DECPEX:	/* print extent */
7309	    DoSM(DP_PRN_EXTENT, PrinterOf(screen).printer_extent);
7310	    break;
7311	case srm_DECTCEM:	/* Show/hide cursor (VT200) */
7312	    DoSM(DP_CRS_VISIBLE, screen->cursor_set);
7313	    break;
7314	case srm_RXVT_SCROLLBAR:
7315	    DoSM(DP_RXVT_SCROLLBAR, (screen->fullVwin.sb_info.width != 0));
7316	    break;
7317#if OPT_SHIFT_FONTS
7318	case srm_RXVT_FONTSIZE:
7319	    DoSM(DP_RXVT_FONTSIZE, xw->misc.shift_fonts);
7320	    break;
7321#endif
7322#if OPT_TEK4014
7323	case srm_DECTEK:
7324	    DoSM(DP_DECTEK, TEK4014_ACTIVE(xw));
7325	    break;
7326#endif
7327	case srm_132COLS:	/* 132 column mode              */
7328	    DoSM(DP_X_DECCOLM, screen->c132);
7329	    break;
7330	case srm_CURSES_HACK:	/* curses hack                  */
7331	    DoSM(DP_X_MORE, screen->curses);
7332	    break;
7333	case srm_DECNRCM:	/* national charset (VT220) */
7334	    if (screen->vtXX_level >= 2) {
7335		DoSM(DP_DECNRCM, xw->flags & NATIONAL);
7336	    }
7337	    break;
7338#if OPT_PRINT_GRAPHICS
7339	case srm_DECGEPM:	/* Graphics Expanded Print Mode */
7340	    DoSM(DP_DECGEPM, screen->graphics_expanded_print_mode);
7341	    break;
7342#endif
7343	case srm_MARGIN_BELL:	/* margin bell (xterm) also DECGPCM (Graphics Print Color Mode) */
7344	    if_PRINT_GRAPHICS2(DoSM(DP_DECGPCM, screen->graphics_print_color_mode)) {
7345		DoSM(DP_X_MARGIN, screen->marginbell);
7346	    }
7347	    break;
7348	case srm_REVERSEWRAP:	/* reverse wraparound (xterm) also DECGPCS (Graphics Print Color Syntax) */
7349	    if_PRINT_GRAPHICS2(DoSM(DP_DECGPCS, screen->graphics_print_color_syntax)) {
7350		DoSM(DP_X_REVWRAP, xw->flags & REVERSEWRAP);
7351	    }
7352	    break;
7353#ifdef ALLOWLOGGING
7354	case srm_ALLOWLOGGING:	/* logging (xterm) also DECGPBM (Graphics Print Background Mode) */
7355	    if_PRINT_GRAPHICS2(DoSM(DP_DECGPBM, screen->graphics_print_background_mode)) {
7356#ifdef ALLOWLOGFILEONOFF
7357		DoSM(DP_X_LOGGING, screen->logging);
7358#endif /* ALLOWLOGFILEONOFF */
7359	    }
7360	    break;
7361#elif OPT_PRINT_GRAPHICS
7362	case srm_DECGPBM:	/* Graphics Print Background Mode */
7363	    DoSM(DP_DECGPBM, screen->graphics_print_background_mode);
7364	    break;
7365#endif /* ALLOWLOGGING */
7366	case srm_OPT_ALTBUF_CURSOR:	/* optional alternate buffer and clear (xterm) */
7367	    /* FALLTHRU */
7368	case srm_OPT_ALTBUF:	/* optional alternate buffer and clear (xterm) */
7369	    DoSM(DP_X_ALTBUF, screen->whichBuf);
7370	    break;
7371	case srm_ALTBUF:	/* alternate buffer (xterm) also DECGRPM (Graphics Rotated Print Mode) */
7372	    if_PRINT_GRAPHICS2(DoSM(DP_DECGRPM, screen->graphics_rotated_print_mode)) {
7373		DoSM(DP_X_ALTBUF, screen->whichBuf);
7374	    }
7375	    break;
7376	case srm_DECNKM:
7377	    DoSM(DP_DECKPAM, xw->keyboard.flags & MODE_DECKPAM);
7378	    break;
7379	case srm_DECBKM:	/* backarrow mapping */
7380	    DoSM(DP_DECBKM, xw->keyboard.flags & MODE_DECBKM);
7381	    break;
7382	case srm_DECLRMM:	/* left-right */
7383	    DoSM(DP_X_LRMM, LEFT_RIGHT);
7384	    break;
7385#if OPT_SIXEL_GRAPHICS
7386	case srm_DECSDM:	/* sixel scrolling */
7387	    DoSM(DP_DECSDM, xw->keyboard.flags & MODE_DECSDM);
7388	    update_decsdm();
7389	    break;
7390#endif
7391	case srm_DECNCSM:	/* noclear */
7392	    DoSM(DP_X_NCSM, NOCLEAR_COLM);
7393	    break;
7394	case srm_VT200_MOUSE:	/* mouse bogus sequence         */
7395	    /* FALLTHRU */
7396	case srm_VT200_HIGHLIGHT_MOUSE:
7397	    /* FALLTHRU */
7398	case srm_BTN_EVENT_MOUSE:
7399	    /* FALLTHRU */
7400	case srm_ANY_EVENT_MOUSE:
7401	    DoSM(DP_X_MOUSE, screen->send_mouse_pos);
7402	    break;
7403#if OPT_FOCUS_EVENT
7404	case srm_FOCUS_EVENT_MOUSE:
7405	    DoSM(DP_X_FOCUS, screen->send_focus_pos);
7406	    break;
7407#endif
7408	case srm_EXT_MODE_MOUSE:
7409	    /* FALLTHRU */
7410	case srm_SGR_EXT_MODE_MOUSE:
7411	    /* FALLTHRU */
7412	case srm_URXVT_EXT_MODE_MOUSE:
7413	    /* FALLTHRU */
7414	case srm_PIXEL_POSITION_MOUSE:
7415	    DoSM(DP_X_EXT_MOUSE, screen->extend_coords);
7416	    break;
7417	case srm_ALTERNATE_SCROLL:
7418	    DoSM(DP_ALTERNATE_SCROLL, screen->alternateScroll);
7419	    break;
7420	case srm_RXVT_SCROLL_TTY_OUTPUT:
7421	    DoSM(DP_RXVT_SCROLL_TTY_OUTPUT, screen->scrollttyoutput);
7422	    break;
7423	case srm_RXVT_SCROLL_TTY_KEYPRESS:
7424	    DoSM(DP_RXVT_SCROLL_TTY_KEYPRESS, screen->scrollkey);
7425	    break;
7426	case srm_EIGHT_BIT_META:
7427	    DoSM(DP_EIGHT_BIT_META, screen->eight_bit_meta);
7428	    break;
7429#if OPT_NUM_LOCK
7430	case srm_REAL_NUMLOCK:
7431	    DoSM(DP_REAL_NUMLOCK, xw->misc.real_NumLock);
7432	    break;
7433	case srm_META_SENDS_ESC:
7434	    DoSM(DP_META_SENDS_ESC, screen->meta_sends_esc);
7435	    break;
7436#endif
7437	case srm_DELETE_IS_DEL:
7438	    DoSM(DP_DELETE_IS_DEL, screen->delete_is_del);
7439	    break;
7440#if OPT_NUM_LOCK
7441	case srm_ALT_SENDS_ESC:
7442	    DoSM(DP_ALT_SENDS_ESC, screen->alt_sends_esc);
7443	    break;
7444#endif
7445	case srm_KEEP_SELECTION:
7446	    DoSM(DP_KEEP_SELECTION, screen->keepSelection);
7447	    break;
7448	case srm_SELECT_TO_CLIPBOARD:
7449	    DoSM(DP_SELECT_TO_CLIPBOARD, screen->selectToClipboard);
7450	    break;
7451	case srm_BELL_IS_URGENT:
7452	    DoSM(DP_BELL_IS_URGENT, screen->bellIsUrgent);
7453	    break;
7454	case srm_POP_ON_BELL:
7455	    DoSM(DP_POP_ON_BELL, screen->poponbell);
7456	    break;
7457	case srm_KEEP_CLIPBOARD:
7458	    DoSM(DP_KEEP_CLIPBOARD, screen->keepClipboard);
7459	    break;
7460#if OPT_TCAP_FKEYS
7461	case srm_TCAP_FKEYS:
7462	    /* FALLTHRU */
7463#endif
7464#if OPT_SUN_FUNC_KEYS
7465	case srm_SUN_FKEYS:
7466	    /* FALLTHRU */
7467#endif
7468#if OPT_HP_FUNC_KEYS
7469	case srm_HP_FKEYS:
7470	    /* FALLTHRU */
7471#endif
7472#if OPT_SCO_FUNC_KEYS
7473	case srm_SCO_FKEYS:
7474	    /* FALLTHRU */
7475#endif
7476#if OPT_SUNPC_KBD
7477	case srm_VT220_FKEYS:
7478	    /* FALLTHRU */
7479#endif
7480	case srm_LEGACY_FKEYS:
7481	    DoSM(DP_KEYBOARD_TYPE, xw->keyboard.type);
7482	    break;
7483	case srm_ALLOW_ALTBUF:
7484	    DoSM(DP_ALLOW_ALTBUF, xw->misc.titeInhibit);
7485	    break;
7486	case srm_SAVE_CURSOR:
7487	    if (!xw->misc.titeInhibit) {
7488		CursorSave(xw);
7489	    }
7490	    break;
7491#if OPT_PASTE64 || OPT_READLINE
7492	case srm_PASTE_IN_BRACKET:
7493	    SCREEN_FLAG_save(screen, paste_brackets);
7494	    break;
7495#endif
7496#if OPT_READLINE
7497	case srm_BUTTON1_MOVE_POINT:
7498	    SCREEN_FLAG_save(screen, click1_moves);
7499	    break;
7500	case srm_BUTTON2_MOVE_POINT:
7501	    SCREEN_FLAG_save(screen, paste_moves);
7502	    break;
7503	case srm_DBUTTON3_DELETE:
7504	    SCREEN_FLAG_save(screen, dclick3_deletes);
7505	    break;
7506	case srm_PASTE_QUOTE:
7507	    SCREEN_FLAG_save(screen, paste_quotes);
7508	    break;
7509	case srm_PASTE_LITERAL_NL:
7510	    SCREEN_FLAG_save(screen, paste_literal_nl);
7511	    break;
7512#endif /* OPT_READLINE */
7513#if OPT_GRAPHICS
7514	case srm_PRIVATE_COLOR_REGISTERS:	/* private color registers for each graphic */
7515	    TRACE(("save PRIVATE_COLOR_REGISTERS %s\n",
7516		   BtoS(screen->privatecolorregisters)));
7517	    DoSM(DP_X_PRIVATE_COLOR_REGISTERS, screen->privatecolorregisters);
7518	    update_privatecolorregisters();
7519	    break;
7520#endif
7521#if OPT_SIXEL_GRAPHICS
7522	case srm_SIXEL_SCROLLS_RIGHT:
7523	    TRACE(("save SIXEL_SCROLLS_RIGHT %s\n",
7524		   BtoS(screen->sixel_scrolls_right)));
7525	    DoSM(DP_SIXEL_SCROLLS_RIGHT, screen->sixel_scrolls_right);
7526	    break;
7527#endif
7528	}
7529    }
7530}
7531
7532/*
7533 * process xterm private modes restore
7534 */
7535static void
7536restoremodes(XtermWidget xw)
7537{
7538    TScreen *screen = TScreenOf(xw);
7539    int i, j;
7540
7541    if_STATUS_LINE(screen, {
7542	return;
7543    });
7544    for (i = 0; i < nparam; i++) {
7545	int code = GetParam(i);
7546
7547	TRACE(("restoremodes %d\n", code));
7548	switch ((DECSET_codes) code) {
7549	case srm_DECCKM:
7550	    bitcpy(&xw->keyboard.flags,
7551		   screen->save_modes[DP_DECCKM], MODE_DECCKM);
7552	    update_appcursor();
7553	    break;
7554	case srm_DECANM:	/* ANSI/VT52 mode      */
7555	    /* no effect */
7556	    break;
7557	case srm_DECCOLM:
7558	    if (screen->c132) {
7559		if (!(xw->flags & NOCLEAR_COLM))
7560		    ClearScreen(xw);
7561		CursorSet(screen, 0, 0, xw->flags);
7562		if ((j = (screen->save_modes[DP_DECCOLM] & IN132COLUMNS)
7563		     ? 132 : 80) != ((xw->flags & IN132COLUMNS)
7564				     ? 132 : 80) || j != MaxCols(screen))
7565		    RequestResize(xw, -1, j, True);
7566		bitcpy(&xw->flags,
7567		       screen->save_modes[DP_DECCOLM],
7568		       IN132COLUMNS);
7569	    }
7570	    break;
7571	case srm_DECSCLM:	/* (slow scroll)        */
7572	    if (screen->save_modes[DP_DECSCLM] & SMOOTHSCROLL) {
7573		screen->jumpscroll = 0;
7574		if (screen->scroll_amt)
7575		    FlushScroll(xw);
7576	    } else
7577		screen->jumpscroll = 1;
7578	    bitcpy(&xw->flags, screen->save_modes[DP_DECSCLM], SMOOTHSCROLL);
7579	    update_jumpscroll();
7580	    break;
7581	case srm_DECSCNM:
7582	    if ((screen->save_modes[DP_DECSCNM] ^ xw->flags) & REVERSE_VIDEO) {
7583		bitcpy(&xw->flags, screen->save_modes[DP_DECSCNM], REVERSE_VIDEO);
7584		ReverseVideo(xw);
7585		/* update_reversevideo done in RevVid */
7586	    }
7587	    break;
7588	case srm_DECOM:
7589	    bitcpy(&xw->flags, screen->save_modes[DP_DECOM], ORIGIN);
7590	    CursorSet(screen, 0, 0, xw->flags);
7591	    break;
7592
7593	case srm_DECAWM:
7594	    bitcpy(&xw->flags, screen->save_modes[DP_DECAWM], WRAPAROUND);
7595	    update_autowrap();
7596	    break;
7597	case srm_DECARM:
7598	    /* ignore autorepeat */
7599	    break;
7600	case srm_X10_MOUSE:	/* MIT bogus sequence           */
7601	    DoRM0(DP_X_X10MSE, screen->send_mouse_pos);
7602	    really_set_mousemode(xw,
7603				 screen->send_mouse_pos != MOUSE_OFF,
7604				 (XtermMouseModes) screen->send_mouse_pos);
7605	    break;
7606#if OPT_TOOLBAR
7607	case srm_RXVT_TOOLBAR:
7608	    DoRM(DP_TOOLBAR, resource.toolBar);
7609	    ShowToolbar(resource.toolBar);
7610	    break;
7611#endif
7612#if OPT_BLINK_CURS
7613	case srm_ATT610_BLINK:	/* Start/stop blinking cursor */
7614	    if (SettableCursorBlink(screen)) {
7615		DoRM(DP_CRS_BLINK, screen->cursor_blink_esc);
7616		UpdateCursorBlink(xw);
7617	    }
7618	    break;
7619	case srm_CURSOR_BLINK_OPS:
7620	    /* intentionally ignored (this is user-preference) */
7621	    break;
7622	case srm_XOR_CURSOR_BLINKS:
7623	    /* intentionally ignored (this is user-preference) */
7624	    break;
7625#endif
7626	case srm_DECPFF:	/* print form feed */
7627	    DoRM(DP_PRN_FORMFEED, PrinterOf(screen).printer_formfeed);
7628	    break;
7629	case srm_DECPEX:	/* print extent */
7630	    DoRM(DP_PRN_EXTENT, PrinterOf(screen).printer_extent);
7631	    break;
7632	case srm_DECTCEM:	/* Show/hide cursor (VT200) */
7633	    DoRM(DP_CRS_VISIBLE, screen->cursor_set);
7634	    updateCursor(xw);
7635	    break;
7636	case srm_RXVT_SCROLLBAR:
7637	    if ((screen->fullVwin.sb_info.width != 0) !=
7638		screen->save_modes[DP_RXVT_SCROLLBAR]) {
7639		ToggleScrollBar(xw);
7640	    }
7641	    break;
7642#if OPT_SHIFT_FONTS
7643	case srm_RXVT_FONTSIZE:
7644	    DoRM(DP_RXVT_FONTSIZE, xw->misc.shift_fonts);
7645	    break;
7646#endif
7647#if OPT_TEK4014
7648	case srm_DECTEK:
7649	    if (!(screen->inhibit & I_TEK) &&
7650		(TEK4014_ACTIVE(xw) != (Boolean) screen->save_modes[DP_DECTEK])) {
7651		FlushLog(xw);
7652		TEK4014_ACTIVE(xw) = (Boolean) screen->save_modes[DP_DECTEK];
7653		update_vttekmode();
7654	    }
7655	    break;
7656#endif
7657	case srm_132COLS:	/* 132 column mode              */
7658	    DoRM(DP_X_DECCOLM, screen->c132);
7659	    update_allow132();
7660	    break;
7661	case srm_CURSES_HACK:	/* curses hack                  */
7662	    DoRM(DP_X_MORE, screen->curses);
7663	    update_cursesemul();
7664	    break;
7665	case srm_DECNRCM:	/* national charset (VT220) */
7666	    if (screen->vtXX_level >= 2) {
7667		if (bitcpy(&xw->flags, screen->save_modes[DP_DECNRCM], NATIONAL))
7668		    modified_DECNRCM(xw);
7669	    }
7670	    break;
7671#if OPT_PRINT_GRAPHICS
7672	case srm_DECGEPM:	/* Graphics Expanded Print Mode */
7673	    DoRM(DP_DECGEPM, screen->graphics_expanded_print_mode);
7674	    break;
7675#endif
7676	case srm_MARGIN_BELL:	/* margin bell (xterm) also DECGPCM (Graphics Print Color Mode) */
7677	    if_PRINT_GRAPHICS2(DoRM(DP_DECGPCM, screen->graphics_print_color_mode)) {
7678		if ((DoRM(DP_X_MARGIN, screen->marginbell)) == 0)
7679		    screen->bellArmed = -1;
7680		update_marginbell();
7681	    }
7682	    break;
7683	case srm_REVERSEWRAP:	/* reverse wraparound (xterm) also DECGPCS (Graphics Print Color Syntax) */
7684	    if_PRINT_GRAPHICS2(DoRM(DP_DECGPCS, screen->graphics_print_color_syntax)) {
7685		bitcpy(&xw->flags, screen->save_modes[DP_X_REVWRAP], REVERSEWRAP);
7686		update_reversewrap();
7687	    }
7688	    break;
7689#ifdef ALLOWLOGGING
7690	case srm_ALLOWLOGGING:	/* logging (xterm) also DECGPBM (Graphics Print Background Mode) */
7691	    if_PRINT_GRAPHICS2(DoRM(DP_DECGPBM, screen->graphics_print_background_mode)) {
7692#ifdef ALLOWLOGFILEONOFF
7693		if (screen->save_modes[DP_X_LOGGING])
7694		    StartLog(xw);
7695		else
7696		    CloseLog(xw);
7697#endif /* ALLOWLOGFILEONOFF */
7698		/* update_logging done by StartLog and CloseLog */
7699	    }
7700	    break;
7701#elif OPT_PRINT_GRAPHICS
7702	case srm_DECGPBM:	/* Graphics Print Background Mode */
7703	    DoRM(DP_DECGPBM, screen->graphics_print_background_mode);
7704	    break;
7705#endif /* ALLOWLOGGING */
7706	case srm_OPT_ALTBUF_CURSOR:	/* optional alternate buffer and clear (xterm) */
7707	    /* FALLTHRU */
7708	case srm_OPT_ALTBUF:	/* optional alternate buffer and clear (xterm) */
7709	    if (!xw->misc.titeInhibit) {
7710		if (screen->save_modes[DP_X_ALTBUF])
7711		    ToAlternate(xw, False);
7712		else
7713		    FromAlternate(xw);
7714		/* update_altscreen done by ToAlt and FromAlt */
7715	    } else if (screen->save_modes[DP_X_ALTBUF]) {
7716		do_ti_xtra_scroll(xw);
7717	    }
7718	    break;
7719	case srm_ALTBUF:	/* alternate buffer (xterm) also DECGRPM (Graphics Rotated Print Mode) */
7720	    if_PRINT_GRAPHICS2(DoRM(DP_DECGRPM, screen->graphics_rotated_print_mode)) {
7721		if (!xw->misc.titeInhibit) {
7722		    if (screen->save_modes[DP_X_ALTBUF])
7723			ToAlternate(xw, False);
7724		    else
7725			FromAlternate(xw);
7726		    /* update_altscreen done by ToAlt and FromAlt */
7727		} else if (screen->save_modes[DP_X_ALTBUF]) {
7728		    do_ti_xtra_scroll(xw);
7729		}
7730	    }
7731	    break;
7732	case srm_DECNKM:
7733	    bitcpy(&xw->flags, screen->save_modes[DP_DECKPAM], MODE_DECKPAM);
7734	    update_appkeypad();
7735	    break;
7736	case srm_DECBKM:	/* backarrow mapping */
7737	    bitcpy(&xw->flags, screen->save_modes[DP_DECBKM], MODE_DECBKM);
7738	    update_decbkm();
7739	    break;
7740	case srm_DECLRMM:	/* left-right */
7741	    bitcpy(&xw->flags, screen->save_modes[DP_X_LRMM], LEFT_RIGHT);
7742	    if (IsLeftRightMode(xw)) {
7743		xterm_ResetDouble(xw);
7744	    } else {
7745		reset_lr_margins(screen);
7746	    }
7747	    break;
7748#if OPT_SIXEL_GRAPHICS
7749	case srm_DECSDM:	/* sixel scrolling */
7750	    bitcpy(&xw->keyboard.flags, screen->save_modes[DP_DECSDM], MODE_DECSDM);
7751	    update_decsdm();
7752	    break;
7753#endif
7754	case srm_DECNCSM:	/* noclear */
7755	    bitcpy(&xw->flags, screen->save_modes[DP_X_NCSM], NOCLEAR_COLM);
7756	    break;
7757	case srm_VT200_MOUSE:	/* mouse bogus sequence         */
7758	    /* FALLTHRU */
7759	case srm_VT200_HIGHLIGHT_MOUSE:
7760	    /* FALLTHRU */
7761	case srm_BTN_EVENT_MOUSE:
7762	    /* FALLTHRU */
7763	case srm_ANY_EVENT_MOUSE:
7764	    DoRM0(DP_X_MOUSE, screen->send_mouse_pos);
7765	    really_set_mousemode(xw,
7766				 screen->send_mouse_pos != MOUSE_OFF,
7767				 (XtermMouseModes) screen->send_mouse_pos);
7768	    break;
7769#if OPT_FOCUS_EVENT
7770	case srm_FOCUS_EVENT_MOUSE:
7771	    DoRM(DP_X_FOCUS, screen->send_focus_pos);
7772	    break;
7773#endif
7774	case srm_EXT_MODE_MOUSE:
7775	    /* FALLTHRU */
7776	case srm_SGR_EXT_MODE_MOUSE:
7777	    /* FALLTHRU */
7778	case srm_URXVT_EXT_MODE_MOUSE:
7779	    /* FALLTHRU */
7780	case srm_PIXEL_POSITION_MOUSE:
7781	    DoRM(DP_X_EXT_MOUSE, screen->extend_coords);
7782	    break;
7783	case srm_ALLOW_ALTBUF:
7784	    DoRM(DP_ALLOW_ALTBUF, xw->misc.titeInhibit);
7785	    if (xw->misc.titeInhibit)
7786		FromAlternate(xw);
7787	    update_titeInhibit();
7788	    break;
7789	case srm_SAVE_CURSOR:
7790	    if (!xw->misc.titeInhibit) {
7791		CursorRestore(xw);
7792	    }
7793	    break;
7794	case srm_ALTERNATE_SCROLL:
7795	    DoRM(DP_ALTERNATE_SCROLL, screen->alternateScroll);
7796	    break;
7797	case srm_RXVT_SCROLL_TTY_OUTPUT:
7798	    DoRM(DP_RXVT_SCROLL_TTY_OUTPUT, screen->scrollttyoutput);
7799	    update_scrollttyoutput();
7800	    break;
7801	case srm_RXVT_SCROLL_TTY_KEYPRESS:
7802	    DoRM(DP_RXVT_SCROLL_TTY_KEYPRESS, screen->scrollkey);
7803	    update_scrollkey();
7804	    break;
7805	case srm_EIGHT_BIT_META:
7806	    DoRM(DP_EIGHT_BIT_META, screen->eight_bit_meta);
7807	    break;
7808#if OPT_NUM_LOCK
7809	case srm_REAL_NUMLOCK:
7810	    DoRM(DP_REAL_NUMLOCK, xw->misc.real_NumLock);
7811	    update_num_lock();
7812	    break;
7813	case srm_META_SENDS_ESC:
7814	    DoRM(DP_META_SENDS_ESC, screen->meta_sends_esc);
7815	    update_meta_esc();
7816	    break;
7817#endif
7818	case srm_DELETE_IS_DEL:
7819	    DoRM(DP_DELETE_IS_DEL, screen->delete_is_del);
7820	    update_delete_del();
7821	    break;
7822#if OPT_NUM_LOCK
7823	case srm_ALT_SENDS_ESC:
7824	    DoRM(DP_ALT_SENDS_ESC, screen->alt_sends_esc);
7825	    update_alt_esc();
7826	    break;
7827#endif
7828	case srm_KEEP_SELECTION:
7829	    DoRM(DP_KEEP_SELECTION, screen->keepSelection);
7830	    update_keepSelection();
7831	    break;
7832	case srm_SELECT_TO_CLIPBOARD:
7833	    DoRM(DP_SELECT_TO_CLIPBOARD, screen->selectToClipboard);
7834	    update_selectToClipboard();
7835	    break;
7836	case srm_BELL_IS_URGENT:
7837	    DoRM(DP_BELL_IS_URGENT, screen->bellIsUrgent);
7838	    update_bellIsUrgent();
7839	    break;
7840	case srm_POP_ON_BELL:
7841	    DoRM(DP_POP_ON_BELL, screen->poponbell);
7842	    update_poponbell();
7843	    break;
7844	case srm_KEEP_CLIPBOARD:
7845	    DoRM(DP_KEEP_CLIPBOARD, screen->keepClipboard);
7846	    update_keepClipboard();
7847	    break;
7848#if OPT_TCAP_FKEYS
7849	case srm_TCAP_FKEYS:
7850	    /* FALLTHRU */
7851#endif
7852#if OPT_SUN_FUNC_KEYS
7853	case srm_SUN_FKEYS:
7854	    /* FALLTHRU */
7855#endif
7856#if OPT_HP_FUNC_KEYS
7857	case srm_HP_FKEYS:
7858	    /* FALLTHRU */
7859#endif
7860#if OPT_SCO_FUNC_KEYS
7861	case srm_SCO_FKEYS:
7862	    /* FALLTHRU */
7863#endif
7864#if OPT_SUNPC_KBD
7865	case srm_VT220_FKEYS:
7866	    /* FALLTHRU */
7867#endif
7868	case srm_LEGACY_FKEYS:
7869	    xw->keyboard.type = (xtermKeyboardType) screen->save_modes[DP_KEYBOARD_TYPE];
7870	    break;
7871#if OPT_PASTE64 || OPT_READLINE
7872	case srm_PASTE_IN_BRACKET:
7873	    SCREEN_FLAG_restore(screen, paste_brackets);
7874	    break;
7875#endif
7876#if OPT_READLINE
7877	case srm_BUTTON1_MOVE_POINT:
7878	    SCREEN_FLAG_restore(screen, click1_moves);
7879	    break;
7880	case srm_BUTTON2_MOVE_POINT:
7881	    SCREEN_FLAG_restore(screen, paste_moves);
7882	    break;
7883	case srm_DBUTTON3_DELETE:
7884	    SCREEN_FLAG_restore(screen, dclick3_deletes);
7885	    break;
7886	case srm_PASTE_QUOTE:
7887	    SCREEN_FLAG_restore(screen, paste_quotes);
7888	    break;
7889	case srm_PASTE_LITERAL_NL:
7890	    SCREEN_FLAG_restore(screen, paste_literal_nl);
7891	    break;
7892#endif /* OPT_READLINE */
7893#if OPT_GRAPHICS
7894	case srm_PRIVATE_COLOR_REGISTERS:	/* private color registers for each graphic */
7895	    TRACE(("restore PRIVATE_COLOR_REGISTERS before: %s\n",
7896		   BtoS(screen->privatecolorregisters)));
7897	    DoRM(DP_X_PRIVATE_COLOR_REGISTERS, screen->privatecolorregisters);
7898	    TRACE(("restore PRIVATE_COLOR_REGISTERS after: %s\n",
7899		   BtoS(screen->privatecolorregisters)));
7900	    update_privatecolorregisters();
7901	    break;
7902#endif
7903#if OPT_SIXEL_GRAPHICS
7904	case srm_SIXEL_SCROLLS_RIGHT:
7905	    TRACE(("restore SIXEL_SCROLLS_RIGHT before: %s\n",
7906		   BtoS(screen->sixel_scrolls_right)));
7907	    DoRM(DP_SIXEL_SCROLLS_RIGHT, screen->sixel_scrolls_right);
7908	    TRACE(("restore SIXEL_SCROLLS_RIGHT after: %s\n",
7909		   BtoS(screen->sixel_scrolls_right)));
7910	    break;
7911#endif
7912	}
7913    }
7914}
7915
7916/*
7917 * Convert an XTextProperty to a string.
7918 *
7919 * This frees the data owned by the XTextProperty, and returns in its place the
7920 * string, which must be freed by the caller.
7921 */
7922static char *
7923property_to_string(XtermWidget xw, XTextProperty * text)
7924{
7925    TScreen *screen = TScreenOf(xw);
7926    Display *dpy = screen->display;
7927    char *result = 0;
7928    char **list = NULL;
7929    int length = 0;
7930    int rc;
7931
7932    TRACE(("property_to_string value %p, encoding %s, format %d, nitems %ld\n",
7933	   text->value,
7934	   TraceAtomName(dpy, text->encoding),
7935	   text->format,
7936	   text->nitems));
7937
7938#if OPT_WIDE_CHARS
7939    /*
7940     * We will use the XmbTextPropertyToTextList call to extract UTF-8 data.
7941     * The xtermUtf8ToTextList() call is used to convert UTF-8 explicitly to
7942     * ISO-8859-1.
7943     */
7944    rc = -1;
7945    if ((text->format != 8)
7946	|| IsTitleMode(xw, tmGetUtf8)
7947	|| (text->encoding == XA_UTF8_STRING(dpy) &&
7948	    !(screen->wide_chars || screen->c1_printable) &&
7949	    (rc = xtermUtf8ToTextList(xw, text, &list, &length)) < 0)
7950	|| (rc < 0))
7951#endif
7952	if ((rc = XmbTextPropertyToTextList(dpy, text, &list, &length)) < 0)
7953	    rc = XTextPropertyToStringList(text, &list, &length);
7954
7955    if (rc >= 0) {
7956	int n, c, pass;
7957	size_t need;
7958
7959	for (pass = 0; pass < 2; ++pass) {
7960	    for (n = 0, need = 0; n < length; n++) {
7961		char *s = list[n];
7962		while ((c = *s++) != '\0') {
7963		    if (pass)
7964			result[need] = (char) c;
7965		    ++need;
7966		}
7967	    }
7968	    if (pass)
7969		result[need] = '\0';
7970	    else
7971		result = malloc(need + 1);
7972	    if (result == 0)
7973		break;
7974	}
7975	XFreeStringList(list);
7976    }
7977    if (text->value != 0)
7978	XFree(text->value);
7979
7980    return result;
7981}
7982
7983static char *
7984get_icon_label(XtermWidget xw)
7985{
7986    XTextProperty text;
7987    char *result = 0;
7988
7989    if (XGetWMIconName(TScreenOf(xw)->display, VShellWindow(xw), &text)) {
7990	result = property_to_string(xw, &text);
7991    }
7992    return result;
7993}
7994
7995static char *
7996get_window_label(XtermWidget xw)
7997{
7998    XTextProperty text;
7999    char *result = 0;
8000
8001    if (XGetWMName(TScreenOf(xw)->display, VShellWindow(xw), &text)) {
8002	result = property_to_string(xw, &text);
8003    }
8004    return result;
8005}
8006
8007/*
8008 * Report window label (icon or title) in dtterm protocol
8009 * ESC ] code label ESC backslash
8010 */
8011static void
8012report_win_label(XtermWidget xw,
8013		 int code,
8014		 char *text)
8015{
8016    unparseputc(xw, ANSI_ESC);
8017    unparseputc(xw, ']');
8018    unparseputc(xw, code);
8019
8020    if (text != 0) {
8021	int copy = IsTitleMode(xw, tmGetBase16);
8022	if (copy) {
8023	    TRACE(("Encoding hex:%s\n", text));
8024	    text = x_encode_hex(text);
8025	}
8026	unparseputs(xw, text);
8027	if (copy)
8028	    free(text);
8029    }
8030
8031    unparseputc(xw, ANSI_ESC);
8032    unparseputc(xw, '\\');	/* should be ST */
8033    unparse_end(xw);
8034}
8035
8036/*
8037 * Window operations (from CDE dtterm description, as well as extensions).
8038 * See also "allowWindowOps" resource.
8039 */
8040static void
8041window_ops(XtermWidget xw)
8042{
8043    TScreen *screen = TScreenOf(xw);
8044    XWindowChanges values;
8045    XWindowAttributes win_attrs;
8046#if OPT_MAXIMIZE
8047    unsigned root_width;
8048    unsigned root_height;
8049#endif
8050    int code = zero_if_default(0);
8051    char *label;
8052
8053    TRACE(("window_ops %d\n", code));
8054    switch (code) {
8055    case ewRestoreWin:		/* Restore (de-iconify) window */
8056	if (AllowWindowOps(xw, ewRestoreWin)) {
8057	    xtermDeiconify(xw);
8058	}
8059	break;
8060
8061    case ewMinimizeWin:	/* Minimize (iconify) window */
8062	if (AllowWindowOps(xw, ewMinimizeWin)) {
8063	    xtermIconify(xw);
8064	}
8065	break;
8066
8067    case ewSetWinPosition:	/* Move the window to the given position */
8068	if (AllowWindowOps(xw, ewSetWinPosition)) {
8069	    unsigned value_mask;
8070
8071	    values.x = (Position) zero_if_default(1);
8072	    values.y = (Position) zero_if_default(2);
8073	    TRACE(("...move window to %d,%d\n", values.x, values.y));
8074	    value_mask = (CWX | CWY);
8075	    XReconfigureWMWindow(screen->display,
8076				 VShellWindow(xw),
8077				 DefaultScreen(screen->display),
8078				 value_mask,
8079				 &values);
8080	}
8081	break;
8082
8083    case ewSetWinSizePixels:	/* Resize the window to given size in pixels */
8084	if (AllowWindowOps(xw, ewSetWinSizePixels)) {
8085	    RequestResize(xw, optional_param(1), optional_param(2), False);
8086	}
8087	break;
8088
8089    case ewRaiseWin:		/* Raise the window to the front of the stack */
8090	if (AllowWindowOps(xw, ewRaiseWin)) {
8091	    TRACE(("...raise window\n"));
8092	    XRaiseWindow(screen->display, VShellWindow(xw));
8093	}
8094	break;
8095
8096    case ewLowerWin:		/* Lower the window to the bottom of the stack */
8097	if (AllowWindowOps(xw, ewLowerWin)) {
8098	    TRACE(("...lower window\n"));
8099	    XLowerWindow(screen->display, VShellWindow(xw));
8100	}
8101	break;
8102
8103    case ewRefreshWin:		/* Refresh the window */
8104	if (AllowWindowOps(xw, ewRefreshWin)) {
8105	    TRACE(("...redraw window\n"));
8106	    Redraw();
8107	}
8108	break;
8109
8110    case ewSetWinSizeChars:	/* Resize the text-area, in characters */
8111	if (AllowWindowOps(xw, ewSetWinSizeChars)) {
8112	    RequestResize(xw, optional_param(1), optional_param(2), True);
8113	}
8114	break;
8115
8116#if OPT_MAXIMIZE
8117    case ewMaximizeWin:	/* Maximize or restore */
8118	if (AllowWindowOps(xw, ewMaximizeWin)) {
8119	    RequestMaximize(xw, zero_if_default(1));
8120	}
8121	break;
8122    case ewFullscreenWin:	/* Fullscreen or restore */
8123	if (AllowWindowOps(xw, ewFullscreenWin)) {
8124	    switch (zero_if_default(1)) {
8125	    default:
8126		RequestMaximize(xw, 0);
8127		break;
8128	    case 1:
8129		RequestMaximize(xw, 1);
8130		break;
8131	    case 2:
8132		RequestMaximize(xw, !(screen->restore_data));
8133		break;
8134	    }
8135	}
8136	break;
8137#endif
8138
8139    case ewGetWinState:	/* Report the window's state */
8140	if (AllowWindowOps(xw, ewGetWinState)) {
8141	    TRACE(("...get window attributes\n"));
8142	    init_reply(ANSI_CSI);
8143	    reply.a_pintro = 0;
8144	    reply.a_nparam = 1;
8145	    reply.a_param[0] = (ParmType) (xtermIsIconified(xw) ? 2 : 1);
8146	    reply.a_inters = 0;
8147	    reply.a_final = 't';
8148	    unparseseq(xw, &reply);
8149	}
8150	break;
8151
8152    case ewGetWinPosition:	/* Report the window's position */
8153	if (AllowWindowOps(xw, ewGetWinPosition)) {
8154	    Window win;
8155	    Window result_win;
8156	    int result_y, result_x;
8157
8158	    TRACE(("...get window position\n"));
8159	    init_reply(ANSI_CSI);
8160	    reply.a_pintro = 0;
8161	    reply.a_nparam = 3;
8162	    reply.a_param[0] = 3;
8163	    switch (zero_if_default(1)) {
8164	    case 2:		/* report the text-window's position */
8165		result_y = 0;
8166		result_x = 0;
8167		{
8168		    Widget mw;
8169		    for (mw = (Widget) xw; mw != 0; mw = XtParent(mw)) {
8170			result_x += mw->core.x;
8171			result_y += mw->core.y;
8172			if (mw == SHELL_OF(xw))
8173			    break;
8174		    }
8175		}
8176		result_x += OriginX(screen);
8177		result_y += OriginY(screen);
8178		break;
8179	    default:
8180		win = WMFrameWindow(xw);
8181		xtermGetWinAttrs(screen->display,
8182				 win,
8183				 &win_attrs);
8184		XTranslateCoordinates(screen->display,
8185				      VShellWindow(xw),
8186				      win_attrs.root,
8187				      -win_attrs.border_width,
8188				      -win_attrs.border_width,
8189				      &result_x, &result_y, &result_win);
8190		TRACE(("translated position %d,%d vs %d,%d\n",
8191		       result_y, result_x,
8192		       win_attrs.y, win_attrs.x));
8193		if (!discount_frame_extents(xw, &result_y, &result_x)) {
8194		    TRACE(("...cancelled translation\n"));
8195		    result_y = win_attrs.y;
8196		    result_x = win_attrs.x;
8197		}
8198		break;
8199	    }
8200	    reply.a_param[1] = (ParmType) result_x;
8201	    reply.a_param[2] = (ParmType) result_y;
8202	    reply.a_inters = 0;
8203	    reply.a_final = 't';
8204	    unparseseq(xw, &reply);
8205	}
8206	break;
8207
8208    case ewGetWinSizePixels:	/* Report the window's size in pixels */
8209	if (AllowWindowOps(xw, ewGetWinSizePixels)) {
8210	    ParmType high = (ParmType) Height(screen);
8211	    ParmType wide = (ParmType) Width(screen);
8212
8213	    TRACE(("...get window size in pixels\n"));
8214	    init_reply(ANSI_CSI);
8215	    reply.a_pintro = 0;
8216	    reply.a_nparam = 3;
8217	    reply.a_param[0] = 4;
8218	    switch (zero_if_default(1)) {
8219	    case 2:		/* report the shell-window's size */
8220		xtermGetWinAttrs(screen->display,
8221				 WMFrameWindow(xw),
8222				 &win_attrs);
8223		high = (ParmType) win_attrs.height;
8224		wide = (ParmType) win_attrs.width;
8225		/* FALLTHRU */
8226	    default:
8227		reply.a_param[1] = high;
8228		reply.a_param[2] = wide;
8229		break;
8230	    }
8231	    reply.a_inters = 0;
8232	    reply.a_final = 't';
8233	    unparseseq(xw, &reply);
8234	}
8235	break;
8236
8237#if OPT_MAXIMIZE
8238    case ewGetScreenSizePixels:	/* Report the screen's size, in Pixels */
8239	if (AllowWindowOps(xw, ewGetScreenSizePixels)) {
8240	    TRACE(("...get screen size in pixels\n"));
8241	    (void) QueryMaximize(xw, &root_width, &root_height);
8242	    init_reply(ANSI_CSI);
8243	    reply.a_pintro = 0;
8244	    reply.a_nparam = 3;
8245	    reply.a_param[0] = 5;
8246	    reply.a_param[1] = (ParmType) root_height;
8247	    reply.a_param[2] = (ParmType) root_width;
8248	    reply.a_inters = 0;
8249	    reply.a_final = 't';
8250	    unparseseq(xw, &reply);
8251	}
8252	break;
8253    case ewGetCharSizePixels:	/* Report the font's size, in pixel */
8254	if (AllowWindowOps(xw, ewGetScreenSizeChars)) {
8255	    TRACE(("...get font size in pixels\n"));
8256	    TRACE(("...using font size %dx%d\n",
8257		   FontHeight(screen),
8258		   FontWidth(screen)));
8259	    init_reply(ANSI_CSI);
8260	    reply.a_pintro = 0;
8261	    reply.a_nparam = 3;
8262	    reply.a_param[0] = 6;
8263	    reply.a_param[1] = (ParmType) FontHeight(screen);
8264	    reply.a_param[2] = (ParmType) FontWidth(screen);
8265	    reply.a_inters = 0;
8266	    reply.a_final = 't';
8267	    unparseseq(xw, &reply);
8268	}
8269	break;
8270#endif
8271
8272    case ewGetWinSizeChars:	/* Report the text's size in characters */
8273	if (AllowWindowOps(xw, ewGetWinSizeChars)) {
8274	    TRACE(("...get window size in characters\n"));
8275	    init_reply(ANSI_CSI);
8276	    reply.a_pintro = 0;
8277	    reply.a_nparam = 3;
8278	    reply.a_param[0] = 8;
8279	    reply.a_param[1] = (ParmType) MaxRows(screen);
8280	    reply.a_param[2] = (ParmType) MaxCols(screen);
8281	    reply.a_inters = 0;
8282	    reply.a_final = 't';
8283	    unparseseq(xw, &reply);
8284	}
8285	break;
8286
8287#if OPT_MAXIMIZE
8288    case ewGetScreenSizeChars:	/* Report the screen's size, in characters */
8289	if (AllowWindowOps(xw, ewGetScreenSizeChars)) {
8290	    TRACE(("...get screen size in characters\n"));
8291	    TRACE(("...using font size %dx%d\n",
8292		   FontHeight(screen),
8293		   FontWidth(screen)));
8294	    (void) QueryMaximize(xw, &root_width, &root_height);
8295	    init_reply(ANSI_CSI);
8296	    reply.a_pintro = 0;
8297	    reply.a_nparam = 3;
8298	    reply.a_param[0] = 9;
8299	    reply.a_param[1] = (ParmType) (root_height
8300					   / (unsigned) FontHeight(screen));
8301	    reply.a_param[2] = (ParmType) (root_width
8302					   / (unsigned) FontWidth(screen));
8303	    reply.a_inters = 0;
8304	    reply.a_final = 't';
8305	    unparseseq(xw, &reply);
8306	}
8307	break;
8308#endif
8309
8310    case ewGetIconTitle:	/* Report the icon's label */
8311	if (AllowWindowOps(xw, ewGetIconTitle)) {
8312	    TRACE(("...get icon's label\n"));
8313	    report_win_label(xw, 'L', label = get_icon_label(xw));
8314	    free(label);
8315	}
8316	break;
8317
8318    case ewGetWinTitle:	/* Report the window's title */
8319	if (AllowWindowOps(xw, ewGetWinTitle)) {
8320	    TRACE(("...get window's label\n"));
8321	    report_win_label(xw, 'l', label = get_window_label(xw));
8322	    free(label);
8323	}
8324	break;
8325
8326    case ewPushTitle:		/* save the window's title(s) on stack */
8327	if (AllowWindowOps(xw, ewPushTitle)) {
8328	    SaveTitle *last = screen->save_title;
8329	    SaveTitle *item = TypeCalloc(SaveTitle);
8330
8331	    TRACE(("...push title onto stack\n"));
8332	    if (item != 0) {
8333		switch (zero_if_default(1)) {
8334		case 0:
8335		    item->iconName = get_icon_label(xw);
8336		    item->windowName = get_window_label(xw);
8337		    break;
8338		case 1:
8339		    item->iconName = get_icon_label(xw);
8340		    break;
8341		case 2:
8342		    item->windowName = get_window_label(xw);
8343		    break;
8344		}
8345		item->next = last;
8346		if (item->iconName == 0) {
8347		    item->iconName = ((last == 0)
8348				      ? get_icon_label(xw)
8349				      : x_strdup(last->iconName));
8350		}
8351		if (item->windowName == 0) {
8352		    item->windowName = ((last == 0)
8353					? get_window_label(xw)
8354					: x_strdup(last->windowName));
8355		}
8356		screen->save_title = item;
8357	    }
8358	}
8359	break;
8360
8361    case ewPopTitle:		/* restore the window's title(s) from stack */
8362	if (AllowWindowOps(xw, ewPopTitle)) {
8363	    SaveTitle *item = screen->save_title;
8364
8365	    TRACE(("...pop title off stack\n"));
8366	    if (item != 0) {
8367		switch (zero_if_default(1)) {
8368		case 0:
8369		    ChangeIconName(xw, item->iconName);
8370		    ChangeTitle(xw, item->windowName);
8371		    break;
8372		case 1:
8373		    ChangeIconName(xw, item->iconName);
8374		    break;
8375		case 2:
8376		    ChangeTitle(xw, item->windowName);
8377		    break;
8378		}
8379		screen->save_title = item->next;
8380		free(item->iconName);
8381		free(item->windowName);
8382		free(item);
8383	    }
8384	}
8385	break;
8386
8387    default:			/* DECSLPP (24, 25, 36, 48, 72, 144) */
8388	if (AllowWindowOps(xw, ewSetWinLines)) {
8389	    if (code >= 24)
8390		RequestResize(xw, code, -1, True);
8391	}
8392	break;
8393    }
8394}
8395
8396/*
8397 * set a bit in a word given a pointer to the word and a mask.
8398 */
8399static int
8400bitset(unsigned *p, unsigned mask)
8401{
8402    unsigned before = *p;
8403    *p |= mask;
8404    return (before != *p);
8405}
8406
8407/*
8408 * clear a bit in a word given a pointer to the word and a mask.
8409 */
8410static int
8411bitclr(unsigned *p, unsigned mask)
8412{
8413    unsigned before = *p;
8414    *p &= ~mask;
8415    return (before != *p);
8416}
8417
8418/*
8419 * Copy bits from one word to another, given a mask
8420 */
8421static int
8422bitcpy(unsigned *p, unsigned q, unsigned mask)
8423{
8424    unsigned before = *p;
8425    bitclr(p, mask);
8426    bitset(p, q & mask);
8427    return (before != *p);
8428}
8429
8430void
8431unparseputc1(XtermWidget xw, int c)
8432{
8433    if (c >= 0x80 && c <= 0x9F) {
8434	if (!TScreenOf(xw)->control_eight_bits) {
8435	    unparseputc(xw, A2E(ANSI_ESC));
8436	    c = A2E(c - 0x40);
8437	}
8438    }
8439    unparseputc(xw, c);
8440}
8441
8442void
8443unparseseq(XtermWidget xw, ANSI *ap)
8444{
8445    int c;
8446
8447    assert(ap->a_nparam < NPARAM);
8448    unparseputc1(xw, c = ap->a_type);
8449    if (c == ANSI_ESC
8450	|| c == ANSI_DCS
8451	|| c == ANSI_CSI
8452	|| c == ANSI_OSC
8453	|| c == ANSI_PM
8454	|| c == ANSI_APC
8455	|| c == ANSI_SS3) {
8456	int i;
8457	int inters;
8458	char temp[8];
8459
8460	if (ap->a_pintro != 0)
8461	    unparseputc(xw, ap->a_pintro);
8462	for (i = 0; i < ap->a_nparam; ++i) {
8463	    if (i != 0) {
8464		if (ap->a_radix[i] == 1 || ap->a_radix[i - 1] == 1) {
8465		    ;
8466		} else if (ap->a_delim) {
8467		    unparseputs(xw, ap->a_delim);
8468		} else {
8469		    unparseputc(xw, ';');
8470		}
8471	    }
8472	    switch (ap->a_radix[i]) {
8473	    case 16:
8474		sprintf(temp, "%04X", ap->a_param[i] & 0xffff);
8475		unparseputs(xw, temp);
8476		break;
8477	    case 1:
8478		unparseputc(xw, ap->a_param[i]);
8479		break;
8480	    default:
8481		unparseputn(xw, (unsigned) (UParm) ap->a_param[i]);
8482		break;
8483	    }
8484	}
8485	if ((inters = ap->a_inters) != 0) {
8486	    for (i = 3; i >= 0; --i) {
8487		c = CharOf(inters >> (8 * i));
8488		if (c != 0)
8489		    unparseputc(xw, c);
8490	    }
8491	}
8492	switch (ap->a_type) {
8493	case ANSI_DCS:
8494	    /* FALLTHRU */
8495	case ANSI_OSC:
8496	    /* FALLTHRU */
8497	case ANSI_PM:
8498	    /* FALLTHRU */
8499	case ANSI_APC:
8500	    unparseputc1(xw, ANSI_ST);
8501	    break;
8502	default:
8503	    unparseputc(xw, (char) ap->a_final);
8504	    break;
8505	}
8506    }
8507    unparse_end(xw);
8508}
8509
8510void
8511unparseputn(XtermWidget xw, unsigned n)
8512{
8513    unsigned q;
8514
8515    q = n / 10;
8516    if (q != 0)
8517	unparseputn(xw, q);
8518    unparseputc(xw, (char) ('0' + (n % 10)));
8519}
8520
8521void
8522unparseputs(XtermWidget xw, const char *s)
8523{
8524    if (s != 0) {
8525	while (*s)
8526	    unparseputc(xw, *s++);
8527    }
8528}
8529
8530void
8531unparseputc(XtermWidget xw, int c)
8532{
8533    TScreen *screen = TScreenOf(xw);
8534    IChar *buf = screen->unparse_bfr;
8535    unsigned len;
8536
8537    if ((screen->unparse_len + 2) >= screen->unparse_max)
8538	unparse_end(xw);
8539
8540    len = screen->unparse_len;
8541
8542#if OPT_TCAP_QUERY
8543    /*
8544     * If we're returning a termcap string, it has to be translated since
8545     * a DCS must not contain any characters except for the normal 7-bit
8546     * printable ASCII (counting tab, carriage return, etc).  For now,
8547     * just use hexadecimal for the whole thing.
8548     */
8549    if (screen->tc_query_code >= 0) {
8550	char tmp[3];
8551	sprintf(tmp, "%02X", c & 0xFF);
8552	buf[len++] = CharOf(tmp[0]);
8553	buf[len++] = CharOf(tmp[1]);
8554    } else
8555#endif
8556    if ((buf[len++] = (IChar) c) == '\r' && (xw->flags & LINEFEED)) {
8557	buf[len++] = '\n';
8558    }
8559
8560    screen->unparse_len = len;
8561
8562    /* If send/receive mode is reset, we echo characters locally */
8563    if ((xw->keyboard.flags & MODE_SRM) == 0) {
8564	doparsing(xw, (unsigned) c, &myState);
8565    }
8566}
8567
8568void
8569unparse_end(XtermWidget xw)
8570{
8571    TScreen *screen = TScreenOf(xw);
8572
8573#if OPT_TCAP_QUERY
8574    /*
8575     * tcap-query works by simulating key-presses, which ordinarily would be
8576     * flushed out at the end of each key.  For better efficiency, do not do
8577     * the flush unless we are about to fill the buffer used to capture the
8578     * response.
8579     */
8580    if ((screen->tc_query_code >= 0)
8581	&& (screen->unparse_len + 2 < screen->unparse_max)) {
8582	return;
8583    }
8584#endif
8585    if (screen->unparse_len) {
8586	TRACE(("unparse_end %u:%s\n",
8587	       screen->unparse_len,
8588	       visibleIChars(screen->unparse_bfr, screen->unparse_len)));
8589#ifdef VMS
8590	tt_write(screen->unparse_bfr, screen->unparse_len);
8591#else /* VMS */
8592	writePtyData(screen->respond, screen->unparse_bfr, screen->unparse_len);
8593#endif /* VMS */
8594	screen->unparse_len = 0;
8595    }
8596}
8597
8598void
8599ToggleAlternate(XtermWidget xw)
8600{
8601    if (TScreenOf(xw)->whichBuf)
8602	FromAlternate(xw);
8603    else
8604	ToAlternate(xw, False);
8605}
8606
8607static void
8608ToAlternate(XtermWidget xw, Bool clearFirst)
8609{
8610    TScreen *screen = TScreenOf(xw);
8611
8612    if (screen->whichBuf == 0) {
8613	TRACE(("ToAlternate\n"));
8614	if (!screen->editBuf_index[1]) {
8615	    screen->editBuf_index[1] = allocScrnBuf(xw,
8616						    (unsigned) MaxRows(screen),
8617						    (unsigned) MaxCols(screen),
8618						    &screen->editBuf_data[1]);
8619	}
8620	SwitchBufs(xw, 1, clearFirst);
8621	screen->visbuf = screen->editBuf_index[screen->whichBuf];
8622	update_altscreen();
8623    }
8624}
8625
8626static void
8627FromAlternate(XtermWidget xw)
8628{
8629    TScreen *screen = TScreenOf(xw);
8630
8631    if (screen->whichBuf != 0) {
8632	TRACE(("FromAlternate\n"));
8633	if (screen->scroll_amt) {
8634	    FlushScroll(xw);
8635	}
8636	SwitchBufs(xw, 0, False);
8637	screen->visbuf = screen->editBuf_index[screen->whichBuf];
8638	update_altscreen();
8639    }
8640}
8641
8642static void
8643SwitchBufs(XtermWidget xw, int toBuf, Bool clearFirst)
8644{
8645    TScreen *screen = TScreenOf(xw);
8646    int rows, top;
8647
8648    screen->whichBuf = toBuf;
8649    if (screen->cursor_state)
8650	HideCursor(xw);
8651
8652    rows = MaxRows(screen);
8653    SwitchBufPtrs(screen, toBuf);
8654
8655    if ((top = INX2ROW(screen, 0)) < rows) {
8656	if (screen->scroll_amt) {
8657	    FlushScroll(xw);
8658	}
8659	xtermClear2(xw,
8660		    (int) OriginX(screen),
8661		    (int) top * FontHeight(screen) + screen->border,
8662		    (unsigned) Width(screen),
8663		    (unsigned) ((rows - top) * FontHeight(screen)));
8664	if (clearFirst) {
8665	    ClearBufRows(xw, top, rows);
8666	}
8667    }
8668    ScrnUpdate(xw, 0, 0, rows, MaxCols(screen), False);
8669}
8670
8671Bool
8672CheckBufPtrs(TScreen *screen)
8673{
8674    return (screen->visbuf != 0
8675	    && screen->editBuf_index[0] != 0
8676	    && screen->editBuf_index[1] != 0);
8677}
8678
8679/*
8680 * Swap buffer line pointers between alternate and regular screens.
8681 */
8682void
8683SwitchBufPtrs(TScreen *screen, int toBuf)
8684{
8685    if (CheckBufPtrs(screen)) {
8686	screen->visbuf = screen->editBuf_index[toBuf];
8687    }
8688}
8689
8690void
8691VTRun(XtermWidget xw)
8692{
8693    TScreen *screen = TScreenOf(xw);
8694
8695    TRACE(("VTRun ...\n"));
8696
8697    if (!screen->Vshow) {
8698	set_vt_visibility(True);
8699    }
8700    update_vttekmode();
8701    update_vtshow();
8702    update_tekshow();
8703    set_vthide_sensitivity();
8704
8705    ScrnAllocBuf(xw);
8706
8707    screen->cursor_state = OFF;
8708    screen->cursor_set = ON;
8709#if OPT_BLINK_CURS
8710    if (DoStartBlinking(screen))
8711	StartBlinking(xw);
8712#endif
8713
8714#if OPT_TEK4014
8715    if (Tpushb > Tpushback) {
8716	fillPtyData(xw, VTbuffer, (char *) Tpushback, (int) (Tpushb - Tpushback));
8717	Tpushb = Tpushback;
8718    }
8719#endif
8720    screen->is_running = True;
8721    if (screen->embed_high && screen->embed_wide) {
8722	ScreenResize(xw, screen->embed_wide, screen->embed_high, &(xw->flags));
8723    }
8724#if OPT_MAXIMIZE
8725    else if (resource.fullscreen == esTrue || resource.fullscreen == esAlways)
8726	FullScreen(xw, True);
8727#endif
8728    if (!setjmp(VTend))
8729	VTparse(xw);
8730    StopBlinking(xw);
8731    HideCursor(xw);
8732    screen->cursor_set = OFF;
8733    TRACE(("... VTRun\n"));
8734}
8735
8736/*ARGSUSED*/
8737static void
8738VTExpose(Widget w GCC_UNUSED,
8739	 XEvent *event,
8740	 Region region GCC_UNUSED)
8741{
8742    DEBUG_MSG("Expose\n");
8743    if (event->type == Expose)
8744	HandleExposure(term, event);
8745}
8746
8747static void
8748VTGraphicsOrNoExpose(XEvent *event)
8749{
8750    XtermWidget xw = term;
8751    TScreen *screen = TScreenOf(xw);
8752    if (screen->incopy <= 0) {
8753	screen->incopy = 1;
8754	if (screen->scrolls > 0)
8755	    screen->scrolls--;
8756    }
8757    if (event->type == GraphicsExpose)
8758	if (HandleExposure(xw, event))
8759	    screen->cursor_state = OFF;
8760    if ((event->type == NoExpose)
8761	|| ((XGraphicsExposeEvent *) event)->count == 0) {
8762	if (screen->incopy <= 0 && screen->scrolls > 0)
8763	    screen->scrolls--;
8764	if (screen->scrolls)
8765	    screen->incopy = -1;
8766	else
8767	    screen->incopy = 0;
8768    }
8769}
8770
8771/*ARGSUSED*/
8772static void
8773VTNonMaskableEvent(Widget w GCC_UNUSED,
8774		   XtPointer closure GCC_UNUSED,
8775		   XEvent *event,
8776		   Boolean *cont GCC_UNUSED)
8777{
8778    switch (event->type) {
8779    case GraphicsExpose:
8780	/* FALLTHRU */
8781    case NoExpose:
8782	VTGraphicsOrNoExpose(event);
8783	break;
8784    }
8785}
8786
8787static void
8788VTResize(Widget w)
8789{
8790    if (XtIsRealized(w)) {
8791	XtermWidget xw = (XtermWidget) w;
8792	ScreenResize(xw, xw->core.width, xw->core.height, &xw->flags);
8793    }
8794}
8795
8796#define okDimension(src,dst) ((src <= MAX_U_COORD) \
8797			  && ((dst = (Dimension) src) == src))
8798
8799static void
8800RequestResize(XtermWidget xw, int rows, int cols, Bool text)
8801{
8802    TScreen *screen = TScreenOf(xw);
8803    Dimension replyWidth, replyHeight;
8804    Dimension askedWidth, askedHeight;
8805    XtGeometryResult status;
8806    XWindowAttributes attrs;
8807#if OPT_RENDERFONT && USE_DOUBLE_BUFFER
8808    Boolean buggyXft = False;
8809    Cardinal ignore = 0;
8810#endif
8811
8812    TRACE(("RequestResize(rows=%d, cols=%d, text=%d)\n", rows, cols, text));
8813#if OPT_STATUS_LINE
8814    if (IsStatusShown(screen) && (rows > 0)) {
8815	TRACE(("...reserve a row for status-line\n"));
8816	++rows;
8817    }
8818#endif
8819
8820    /* check first if the row/column values fit into a Dimension */
8821    if (cols > 0) {
8822	if ((int) (askedWidth = (Dimension) cols) < cols) {
8823	    TRACE(("... cols too large for Dimension\n"));
8824	    return;
8825	}
8826    } else {
8827	askedWidth = 0;
8828    }
8829    if (rows > 0) {
8830	if ((int) (askedHeight = (Dimension) rows) < rows) {
8831	    TRACE(("... rows too large for Dimension\n"));
8832	    return;
8833	}
8834    } else {
8835	askedHeight = 0;
8836    }
8837
8838    xw->work.doing_resize = True;
8839
8840#if OPT_RENDERFONT && USE_DOUBLE_BUFFER
8841    /*
8842     * Work around a bug seen when vttest switches from 132 columns back to 80
8843     * columns, while double-buffering is active.  If Xft is active during the
8844     * resize, the screen will be blank thereafter.  This workaround causes
8845     * some extra flickering, but that is preferable to a blank screen.
8846     *
8847     * Since the bitmap- and TrueType-fonts do not always have identical sizes,
8848     * do this switching early, to use the updated font-sizes in the request
8849     * for resizing the window.
8850     */
8851#define ToggleXft() HandleRenderFont((Widget)xw, (XEvent *)0, (String *)0, &ignore)
8852    if (resource.buffered
8853	&& UsingRenderFont(xw)) {
8854	ToggleXft();
8855	buggyXft = True;
8856    }
8857#endif
8858
8859    /*
8860     * If the requested values will fit into a Dimension, and one or both are
8861     * zero, get the current corresponding screen dimension to use as a limit.
8862     */
8863    if (askedHeight == 0
8864	|| askedWidth == 0
8865	|| xw->misc.limit_resize > 0) {
8866	xtermGetWinAttrs(XtDisplay(xw),
8867			 RootWindowOfScreen(XtScreen(xw)), &attrs);
8868    }
8869
8870    /*
8871     * Using the current font metrics, translate the requested character
8872     * rows/columns into pixels.
8873     */
8874    if (text) {
8875	unsigned long value;
8876
8877	if ((value = (unsigned long) rows) != 0) {
8878	    if (rows < 0)
8879		value = (unsigned long) MaxRows(screen);
8880	    value *= (unsigned long) FontHeight(screen);
8881	    value += (unsigned long) (2 * screen->border);
8882	    if (!okDimension(value, askedHeight))
8883		goto give_up;
8884	}
8885
8886	if ((value = (unsigned long) cols) != 0) {
8887	    if (cols < 0)
8888		value = (unsigned long) MaxCols(screen);
8889	    value *= (unsigned long) FontWidth(screen);
8890	    value += (unsigned long) ((2 * screen->border)
8891				      + ScrollbarWidth(screen));
8892	    if (!okDimension(value, askedWidth))
8893		goto give_up;
8894	}
8895
8896    } else {
8897	if (rows < 0)
8898	    askedHeight = FullHeight(screen);
8899	if (cols < 0)
8900	    askedWidth = FullWidth(screen);
8901    }
8902
8903    if (rows == 0) {
8904	askedHeight = (Dimension) attrs.height;
8905    }
8906    if (cols == 0) {
8907	askedWidth = (Dimension) attrs.width;
8908    }
8909
8910    if (xw->misc.limit_resize > 0) {
8911	Dimension high = (Dimension) (xw->misc.limit_resize * attrs.height);
8912	Dimension wide = (Dimension) (xw->misc.limit_resize * attrs.width);
8913	if ((int) high < attrs.height)
8914	    high = (Dimension) attrs.height;
8915	if (askedHeight > high)
8916	    askedHeight = high;
8917	if ((int) wide < attrs.width)
8918	    wide = (Dimension) attrs.width;
8919	if (askedWidth > wide)
8920	    askedWidth = wide;
8921    }
8922#ifndef nothack
8923    getXtermSizeHints(xw);
8924#endif
8925
8926    TRACE(("...requesting resize %dx%d (%dx%d)\n",
8927	   askedHeight, askedWidth,
8928	   askedHeight / FontHeight(screen),
8929	   askedWidth / FontWidth(screen)));
8930    status = REQ_RESIZE((Widget) xw,
8931			askedWidth, askedHeight,
8932			&replyWidth, &replyHeight);
8933
8934    if (status == XtGeometryYes ||
8935	status == XtGeometryDone) {
8936	ScreenResize(xw, replyWidth, replyHeight, &xw->flags);
8937    }
8938#ifndef nothack
8939    /*
8940     * XtMakeResizeRequest() has the undesirable side-effect of clearing
8941     * the window manager's hints, even on a failed request.  This would
8942     * presumably be fixed if the shell did its own work.
8943     */
8944    if (xw->hints.flags
8945	&& replyHeight
8946	&& replyWidth) {
8947	xw->hints.height = replyHeight;
8948	xw->hints.width = replyWidth;
8949
8950	TRACE(("%s@%d -- ", __FILE__, __LINE__));
8951	TRACE_HINTS(&xw->hints);
8952	XSetWMNormalHints(screen->display, VShellWindow(xw), &xw->hints);
8953	TRACE(("%s@%d -- ", __FILE__, __LINE__));
8954	TRACE_WM_HINTS(xw);
8955    }
8956#endif
8957
8958    XSync(screen->display, False);	/* synchronize */
8959    if (xtermAppPending()) {
8960	xevents(xw);
8961    }
8962
8963  give_up:
8964#if OPT_RENDERFONT && USE_DOUBLE_BUFFER
8965    if (buggyXft) {
8966	ToggleXft();
8967	if (xtermAppPending()) {
8968	    xevents(xw);
8969	}
8970    }
8971#endif
8972
8973    xw->work.doing_resize = False;
8974
8975    TRACE(("...RequestResize done\n"));
8976    return;
8977}
8978
8979static String xterm_trans =
8980"<ClientMessage>WM_PROTOCOLS: DeleteWindow()\n\
8981     <MappingNotify>: KeyboardMapping()\n";
8982
8983int
8984VTInit(XtermWidget xw)
8985{
8986    Widget vtparent = SHELL_OF(xw);
8987
8988    TRACE(("VTInit " TRACE_L "\n"));
8989
8990    XtRealizeWidget(vtparent);
8991    XtOverrideTranslations(vtparent, XtParseTranslationTable(xterm_trans));
8992    (void) XSetWMProtocols(XtDisplay(vtparent), XtWindow(vtparent),
8993			   &wm_delete_window, 1);
8994
8995    if (IsEmpty(xw->keyboard.print_translations)) {
8996	TRACE_TRANS("shell", vtparent);
8997	TRACE_TRANS("vt100", (Widget) (xw));
8998	xtermButtonInit(xw);
8999    }
9000
9001    ScrnAllocBuf(xw);
9002
9003    TRACE(("..." TRACE_R " VTInit\n"));
9004    return (1);
9005}
9006
9007static void
9008VTClassInit(void)
9009{
9010    XtAddConverter(XtRString, XtRGravity, XmuCvtStringToGravity,
9011		   (XtConvertArgList) NULL, (Cardinal) 0);
9012}
9013
9014/*
9015 * Override the use of XtDefaultForeground/XtDefaultBackground to make some
9016 * colors, such as cursor color, use the actual foreground/background value
9017 * if there is no explicit resource value used.
9018 */
9019static Pixel
9020fill_Tres(XtermWidget target, XtermWidget source, int offset)
9021{
9022    char *name;
9023    ScrnColors temp;
9024    TScreen *src = TScreenOf(source);
9025    TScreen *dst = TScreenOf(target);
9026
9027    dst->Tcolors[offset] = src->Tcolors[offset];
9028    dst->Tcolors[offset].mode = False;
9029
9030    if ((name = x_strtrim(dst->Tcolors[offset].resource)) != 0)
9031	dst->Tcolors[offset].resource = name;
9032
9033    if (name == 0) {
9034	dst->Tcolors[offset].value = target->dft_foreground;
9035    } else if (isDefaultForeground(name)) {
9036	dst->Tcolors[offset].value = ((offset == TEXT_FG || offset == TEXT_BG)
9037				      ? target->dft_foreground
9038				      : dst->Tcolors[TEXT_FG].value);
9039    } else if (isDefaultBackground(name)) {
9040	dst->Tcolors[offset].value = ((offset == TEXT_FG || offset == TEXT_BG)
9041				      ? target->dft_background
9042				      : dst->Tcolors[TEXT_BG].value);
9043    } else {
9044	memset(&temp, 0, sizeof(temp));
9045	if (AllocateTermColor(target, &temp, offset, name, True)) {
9046	    if (COLOR_DEFINED(&(temp), offset))
9047		free(temp.names[offset]);
9048	    dst->Tcolors[offset].value = temp.colors[offset];
9049	} else if (offset == TEXT_FG || offset == TEXT_BG) {
9050	    free(name);
9051	    dst->Tcolors[offset].resource = 0;
9052	}
9053    }
9054    return dst->Tcolors[offset].value;
9055}
9056
9057/*
9058 * If one or both of the foreground/background colors cannot be allocated,
9059 * e.g., due to gross misconfiguration, recover by setting both to the
9060 * display's default values.
9061 */
9062static void
9063repairColors(XtermWidget target)
9064{
9065    TScreen *screen = TScreenOf(target);
9066
9067    if (screen->Tcolors[TEXT_FG].resource == 0 ||
9068	screen->Tcolors[TEXT_BG].resource == 0) {
9069	xtermWarning("unable to allocate fg/bg colors\n");
9070	screen->Tcolors[TEXT_FG].resource = x_strdup(XtDefaultForeground);
9071	screen->Tcolors[TEXT_BG].resource = x_strdup(XtDefaultBackground);
9072	if (screen->Tcolors[TEXT_FG].resource == 0 ||
9073	    screen->Tcolors[TEXT_BG].resource == 0) {
9074	    Exit(1);
9075	}
9076	screen->Tcolors[TEXT_FG].value = target->dft_foreground;
9077	screen->Tcolors[TEXT_BG].value = target->dft_background;
9078    }
9079}
9080
9081#if OPT_WIDE_CHARS
9082static void
9083set_utf8_feature(TScreen *screen, int *feature)
9084{
9085    if (*feature == uDefault) {
9086	switch (screen->utf8_mode) {
9087	case uFalse:
9088	    /* FALLTHRU */
9089	case uTrue:
9090	    *feature = screen->utf8_mode;
9091	    break;
9092	case uDefault:
9093	    /* should not happen */
9094	    *feature = uTrue;
9095	    break;
9096	case uAlways:
9097	    /* use this to disable menu entry */
9098	    break;
9099	}
9100    }
9101}
9102
9103static void
9104VTInitialize_locale(XtermWidget xw)
9105{
9106    TScreen *screen = TScreenOf(xw);
9107    Bool is_utf8 = xtermEnvUTF8();
9108
9109    TRACE(("VTInitialize_locale\n"));
9110    TRACE(("... request screen.utf8_mode = %d\n", screen->utf8_mode));
9111    TRACE(("... request screen.utf8_fonts = %d\n", screen->utf8_fonts));
9112    TRACE(("... request screen.utf8_title = %d\n", screen->utf8_title));
9113
9114    screen->utf8_always = (screen->utf8_mode == uAlways);
9115    if (screen->utf8_mode < 0)
9116	screen->utf8_mode = uFalse;
9117
9118    if (screen->utf8_mode > 3)
9119	screen->utf8_mode = uDefault;
9120
9121    screen->latin9_mode = 0;
9122    screen->unicode_font = 0;
9123#if OPT_LUIT_PROG
9124    xw->misc.callfilter = 0;
9125    xw->misc.use_encoding = 0;
9126
9127    TRACE(("... setup for luit:\n"));
9128    TRACE(("... request misc.locale_str = \"%s\"\n", xw->misc.locale_str));
9129
9130    if (screen->utf8_mode == uFalse) {
9131	TRACE(("... command-line +u8 overrides\n"));
9132    } else
9133#if OPT_MINI_LUIT
9134    if (x_strcasecmp(xw->misc.locale_str, "CHECKFONT") == 0) {
9135	int fl = (int) strlen(DefaultFontN(xw));
9136	if (fl > 11
9137	    && x_strcasecmp(DefaultFontN(xw) + fl - 11, "-ISO10646-1") == 0) {
9138	    screen->unicode_font = 1;
9139	    /* unicode font, use True */
9140#ifdef HAVE_LANGINFO_CODESET
9141	    if (!strcmp(xtermEnvEncoding(), "ANSI_X3.4-1968")
9142		|| !strcmp(xtermEnvEncoding(), "ISO-8859-1")) {
9143		if (screen->utf8_mode == uDefault)
9144		    screen->utf8_mode = uFalse;
9145	    } else if (!strcmp(xtermEnvEncoding(), "ISO-8859-15")) {
9146		if (screen->utf8_mode == uDefault)
9147		    screen->utf8_mode = uFalse;
9148		screen->latin9_mode = 1;
9149	    } else {
9150		xw->misc.callfilter = (Boolean) (is_utf8 ? 0 : 1);
9151		screen->utf8_mode = uAlways;
9152	    }
9153#else
9154	    xw->misc.callfilter = is_utf8 ? 0 : 1;
9155	    screen->utf8_mode = uAlways;
9156#endif
9157	} else {
9158	    /* other encoding, use False */
9159	    if (screen->utf8_mode == uDefault) {
9160		screen->utf8_mode = is_utf8 ? uAlways : uFalse;
9161	    }
9162	}
9163    } else
9164#endif /* OPT_MINI_LUIT */
9165	if (x_strcasecmp(xw->misc.locale_str, "TRUE") == 0 ||
9166	    x_strcasecmp(xw->misc.locale_str, "ON") == 0 ||
9167	    x_strcasecmp(xw->misc.locale_str, "YES") == 0 ||
9168	    x_strcasecmp(xw->misc.locale_str, "AUTO") == 0 ||
9169	    strcmp(xw->misc.locale_str, "1") == 0) {
9170	/* when true ... fully obeying LC_CTYPE locale */
9171	xw->misc.callfilter = (Boolean) (is_utf8 ? 0 : 1);
9172	screen->utf8_mode = uAlways;
9173    } else if (x_strcasecmp(xw->misc.locale_str, "FALSE") == 0 ||
9174	       x_strcasecmp(xw->misc.locale_str, "OFF") == 0 ||
9175	       x_strcasecmp(xw->misc.locale_str, "NO") == 0 ||
9176	       strcmp(xw->misc.locale_str, "0") == 0) {
9177	/* when false ... original value of utf8_mode is effective */
9178	if (screen->utf8_mode == uDefault) {
9179	    screen->utf8_mode = is_utf8 ? uAlways : uFalse;
9180	}
9181    } else if (x_strcasecmp(xw->misc.locale_str, "MEDIUM") == 0 ||
9182	       x_strcasecmp(xw->misc.locale_str, "SEMIAUTO") == 0) {
9183	/* when medium ... obeying locale only for UTF-8 and Asian */
9184	if (is_utf8) {
9185	    screen->utf8_mode = uAlways;
9186	} else if (
9187#ifdef MB_CUR_MAX
9188		      MB_CUR_MAX > 1 ||
9189#else
9190		      !strncmp(xtermEnvLocale(), "ja", (size_t) 2) ||
9191		      !strncmp(xtermEnvLocale(), "ko", (size_t) 2) ||
9192		      !strncmp(xtermEnvLocale(), "zh", (size_t) 2) ||
9193#endif
9194		      !strncmp(xtermEnvLocale(), "th", (size_t) 2) ||
9195		      !strncmp(xtermEnvLocale(), "vi", (size_t) 2)) {
9196	    xw->misc.callfilter = 1;
9197	    screen->utf8_mode = uAlways;
9198	} else {
9199	    screen->utf8_mode = uFalse;
9200	}
9201    } else if (x_strcasecmp(xw->misc.locale_str, "UTF-8") == 0 ||
9202	       x_strcasecmp(xw->misc.locale_str, "UTF8") == 0) {
9203	/* when UTF-8 ... UTF-8 mode */
9204	screen->utf8_mode = uAlways;
9205    } else {
9206	/* other words are regarded as encoding name passed to luit */
9207	xw->misc.callfilter = 1;
9208	screen->utf8_mode = uAlways;
9209	xw->misc.use_encoding = 1;
9210    }
9211    TRACE(("... updated misc.callfilter = %s\n", BtoS(xw->misc.callfilter)));
9212    TRACE(("... updated misc.use_encoding = %s\n", BtoS(xw->misc.use_encoding)));
9213#else
9214    if (screen->utf8_mode == uDefault) {
9215	screen->utf8_mode = is_utf8 ? uAlways : uFalse;
9216    }
9217#endif /* OPT_LUIT_PROG */
9218
9219    set_utf8_feature(screen, &screen->utf8_fonts);
9220    set_utf8_feature(screen, &screen->utf8_title);
9221
9222    screen->utf8_inparse = (Boolean) (screen->utf8_mode != uFalse);
9223
9224    TRACE(("... updated screen.utf8_mode = %d\n", screen->utf8_mode));
9225    TRACE(("... updated screen.utf8_fonts = %d\n", screen->utf8_fonts));
9226    TRACE(("... updated screen.utf8_title = %d\n", screen->utf8_title));
9227    TRACE(("...VTInitialize_locale done\n"));
9228}
9229#endif
9230
9231void
9232lookupSelectUnit(XtermWidget xw, Cardinal item, String value)
9233{
9234    /* *INDENT-OFF* */
9235    static const struct {
9236	const char *	name;
9237	SelectUnit	code;
9238    } table[] = {
9239    	{ "char",	Select_CHAR },
9240    	{ "word",	Select_WORD },
9241    	{ "line",	Select_LINE },
9242    	{ "group",	Select_GROUP },
9243    	{ "page",	Select_PAGE },
9244    	{ "all",	Select_ALL },
9245#if OPT_SELECT_REGEX
9246    	{ "regex",	Select_REGEX },
9247#endif
9248    };
9249    /* *INDENT-ON* */
9250
9251    TScreen *screen = TScreenOf(xw);
9252    String next = x_skip_nonblanks(value);
9253    Cardinal n;
9254
9255    screen->selectMap[item] = NSELECTUNITS;
9256    for (n = 0; n < XtNumber(table); ++n) {
9257	if (!x_strncasecmp(table[n].name, value, (unsigned) (next - value))) {
9258	    screen->selectMap[item] = table[n].code;
9259#if OPT_SELECT_REGEX
9260	    if (table[n].code == Select_REGEX) {
9261		screen->selectExpr[item] = x_strtrim(next);
9262		TRACE(("Parsed regex \"%s\"\n", screen->selectExpr[item]));
9263	    }
9264#endif
9265	    break;
9266	}
9267    }
9268}
9269
9270static void
9271ParseOnClicks(XtermWidget wnew, XtermWidget wreq, Cardinal item)
9272{
9273    lookupSelectUnit(wnew, item, TScreenOf(wreq)->onClick[item]);
9274}
9275
9276/*
9277 * Parse a comma-separated list, returning a string which the caller must
9278 * free, and updating the source pointer.
9279 */
9280static char *
9281ParseList(const char **source)
9282{
9283    const char *base = *source;
9284    const char *next;
9285    char *value = 0;
9286    char *result;
9287
9288    /* ignore empty values */
9289    while (*base == ',')
9290	++base;
9291
9292    if (*base != '\0') {
9293	size_t size;
9294
9295	next = base;
9296	while (*next != '\0' && *next != ',')
9297	    ++next;
9298	size = (size_t) (1 + next - base);
9299	value = malloc(size);
9300	if (value != 0) {
9301	    memcpy(value, base, size);
9302	    value[size - 1] = '\0';
9303	}
9304	*source = next;
9305    } else {
9306	*source = base;
9307    }
9308    result = x_strtrim(value);
9309    free(value);
9310    return result;
9311}
9312
9313static void
9314set_flags_from_list(char *target,
9315		    const char *source,
9316		    const FlagList * list)
9317{
9318    Cardinal n;
9319
9320    while (!IsEmpty(source)) {
9321	char *next = ParseList(&source);
9322	Boolean found = False;
9323	char flag = 1;
9324
9325	if (next == 0)
9326	    break;
9327	if (*next == '~') {
9328	    flag = 0;
9329	    next++;
9330	}
9331	if (isdigit(CharOf(*next))) {
9332	    char *temp;
9333	    int value = (int) strtol(next, &temp, 0);
9334	    if (!FullS2L(next, temp)) {
9335		xtermWarning("Expected a number: %s\n", next);
9336	    } else {
9337		for (n = 0; list[n].name != 0; ++n) {
9338		    if (list[n].code == value) {
9339			target[value] = flag;
9340			found = True;
9341			TRACE(("...found %s (%d)\n", list[n].name, value));
9342			break;
9343		    }
9344		}
9345	    }
9346	} else {
9347	    for (n = 0; list[n].name != 0; ++n) {
9348		if (!x_wildstrcmp(next, list[n].name)) {
9349		    int value = list[n].code;
9350		    target[value] = flag;
9351		    found = True;
9352		    TRACE(("...found %s (%d)\n", list[n].name, value));
9353		}
9354	    }
9355	}
9356	if (!found) {
9357	    xtermWarning("Unrecognized keyword: %s\n", next);
9358	}
9359	free(next);
9360    }
9361}
9362
9363#define InitCursorShape(target, source) \
9364    target->cursor_shape = source->cursor_underline \
9365	? CURSOR_UNDERLINE \
9366	: CURSOR_BLOCK
9367
9368#if OPT_XRES_QUERY
9369static XtResource *
9370findVT100Resource(const char *name)
9371{
9372    Cardinal n;
9373    XtResource *result = 0;
9374
9375    if (!IsEmpty(name)) {
9376	XrmQuark quarkName = XrmPermStringToQuark(name);
9377	for (n = 0; n < XtNumber(xterm_resources); ++n) {
9378	    if ((int) xterm_resources[n].resource_offset >= 0
9379		&& !strcmp(xterm_resources[n].resource_name, name)) {
9380		result = &xterm_resources[n];
9381		break;
9382	    } else if (xterm_resources[n].resource_name
9383		       == (String) (intptr_t) quarkName) {
9384		result = &xterm_resources[n];
9385		break;
9386	    }
9387	}
9388    }
9389    return result;
9390}
9391
9392static int
9393cmp_resources(const void *a, const void *b)
9394{
9395    return strcmp((*(const String *) a),
9396		  (*(const String *) b));
9397}
9398
9399static void
9400reportResources(XtermWidget xw)
9401{
9402    String *list = TypeMallocN(String, XtNumber(xterm_resources));
9403    Cardinal n;
9404    int widest = 0;
9405
9406    if (list == NULL)
9407	return;
9408
9409    for (n = 0; n < XtNumber(xterm_resources); ++n) {
9410	int width;
9411	list[n] = (((int) xterm_resources[n].resource_offset < 0)
9412		   ? XrmQuarkToString((XrmQuark) (intptr_t)
9413				      xterm_resources[n].resource_name)
9414		   : xterm_resources[n].resource_name);
9415	width = (int) strlen(list[n]);
9416	if (widest < width)
9417	    widest = width;
9418    }
9419    qsort(list, (size_t) XtNumber(xterm_resources), sizeof(String), cmp_resources);
9420    for (n = 0; n < XtNumber(xterm_resources); ++n) {
9421	char *value = vt100ResourceToString(xw, list[n]);
9422	printf("%-*s : %s\n", widest, list[n], value ? value : "(skip)");
9423	free(value);
9424    }
9425    free(list);
9426}
9427
9428char *
9429vt100ResourceToString(XtermWidget xw, const char *name)
9430{
9431    XtResource *data;
9432    char *result = NULL;
9433
9434    if ((data = findVT100Resource(name)) != 0) {
9435	int fake_offset = (int) data->resource_offset;
9436	void *res_addr;
9437	int real_offset;
9438	String res_type;
9439
9440	/*
9441	 * X Toolkit "compiles" the resource-list into quarks and changes the
9442	 * resource-offset at the same time to a negative value.
9443	 */
9444	if (fake_offset < 0) {
9445	    real_offset = -(fake_offset + 1);
9446	    res_type = XrmQuarkToString((XrmQuark) (intptr_t) data->resource_type);
9447	} else {
9448	    real_offset = fake_offset;
9449	    res_type = data->resource_type;
9450	}
9451	res_addr = (void *) ((char *) xw + real_offset);
9452
9453	if (!strcmp(res_type, XtRString)) {
9454	    char *value = *(char **) res_addr;
9455	    if (value != NULL) {
9456		size_t need = strlen(value);
9457		if ((result = malloc(1 + need)) != 0)
9458		    strcpy(result, value);
9459	    }
9460	} else if (!strcmp(res_type, XtRInt)) {
9461	    if ((result = malloc(1 + (size_t) (3 * data->resource_size))) != 0)
9462		sprintf(result, "%d", *(int *) res_addr);
9463	} else if (!strcmp(res_type, XtRFloat)) {
9464	    if ((result = malloc(1 + (size_t) (3 * data->resource_size))) != 0)
9465		sprintf(result, "%f", (double) (*(float *) res_addr));
9466	} else if (!strcmp(res_type, XtRBoolean)) {
9467	    if ((result = malloc((size_t) 6)) != 0)
9468		strcpy(result, *(Boolean *) res_addr ? "true" : "false");
9469	}
9470    }
9471    TRACE(("vt100ResourceToString(%s) %s\n", name, NonNull(result)));
9472    return result;
9473}
9474#endif /* OPT_XRES_QUERY */
9475
9476/*
9477 * Decode a terminal-ID or graphics-terminal-ID, using the default terminal-ID
9478 * if the value is outside a (looser) range than limitedTerminalID.  This uses
9479 * a wider range, to avoid being a nuisance when using X resources with
9480 * different configurations of xterm.
9481 */
9482static int
9483decodeTerminalID(const char *value)
9484{
9485    const char *s;
9486    char *t;
9487    long result;
9488
9489    for (s = value; *s; s++) {
9490	if (!isalpha(CharOf(*s)))
9491	    break;
9492    }
9493    result = strtol(s, &t, 10);
9494    if (t == s || *t != '\0' || result <= 0L || result > 1000L) {
9495	xtermWarning("unexpected value for terminalID: \"%s\"\n", value);
9496	result = atoi(DFT_DECID);
9497    }
9498    TRACE(("decodeTerminalID \"%s\" ->%d\n", value, (int) result));
9499    return (int) result;
9500}
9501
9502/*
9503 * Ensures that the value returned by decodeTerminalID is either in the range
9504 * of IDs matching a known terminal, or (failing that), set to the built-in
9505 * default.  The DA response relies on having the ID being set to a known
9506 * value.
9507 */
9508static int
9509limitedTerminalID(int terminal_id)
9510{
9511    if (terminal_id < MIN_DECID)
9512	terminal_id = MIN_DECID;
9513    else if (terminal_id > MAX_DECID)
9514	terminal_id = MAX_DECID;
9515    else
9516	terminal_id = atoi(DFT_DECID);
9517    return terminal_id;
9518}
9519
9520/* ARGSUSED */
9521static void
9522VTInitialize(Widget wrequest,
9523	     Widget new_arg,
9524	     ArgList args GCC_UNUSED,
9525	     Cardinal *num_args GCC_UNUSED)
9526{
9527#define Kolor(name) TScreenOf(wnew)->name.resource
9528#define TxtFg(name) !x_strcasecmp(Kolor(Tcolors[TEXT_FG]), Kolor(name))
9529#define TxtBg(name) !x_strcasecmp(Kolor(Tcolors[TEXT_BG]), Kolor(name))
9530#define DftFg(name) isDefaultForeground(Kolor(name))
9531#define DftBg(name) isDefaultBackground(Kolor(name))
9532
9533#define DATA_END   { NULL,  -1       }
9534
9535#if OPT_BLINK_CURS
9536#define DATA(name) { #name, cb##name }
9537    static const FlagList tblBlinkOps[] =
9538    {
9539	DATA(Always)
9540	,DATA(Never)
9541	,DATA_END
9542    };
9543#undef DATA
9544#endif
9545
9546#define DATA(name) { #name, ec##name }
9547    static const FlagList tblColorOps[] =
9548    {
9549	DATA(SetColor)
9550	,DATA(GetColor)
9551	,DATA(GetAnsiColor)
9552	,DATA_END
9553    };
9554#undef DATA
9555
9556#define DATA(name) { #name, ef##name }
9557    static const FlagList tblFontOps[] =
9558    {
9559	DATA(SetFont)
9560	,DATA(GetFont)
9561	,DATA_END
9562    };
9563#undef DATA
9564
9565#define DATA(name) { #name, em##name }
9566    static const FlagList tblMouseOps[] =
9567    {
9568	DATA(X10)
9569	,DATA(Locator)
9570	,DATA(VT200Click)
9571	,DATA(VT200Hilite)
9572	,DATA(AnyButton)
9573	,DATA(AnyEvent)
9574	,DATA(FocusEvent)
9575	,DATA(Extended)
9576	,DATA(SGR)
9577	,DATA(URXVT)
9578	,DATA(AlternateScroll)
9579	,DATA_END
9580    };
9581#undef DATA
9582
9583#define DATA(name) { #name, ep##name }
9584#define DATA2(alias,name) { #alias, ep##name }
9585    static const FlagList tblPasteControls[] =
9586    {
9587	DATA(NUL)
9588	,DATA(SOH)
9589	,DATA(STX)
9590	,DATA(ETX)
9591	,DATA(EOT)
9592	,DATA(ENQ)
9593	,DATA(ACK)
9594	,DATA(BEL)
9595	,DATA(BS)
9596	,DATA(HT)
9597	,DATA(LF)
9598	,DATA(VT)
9599	,DATA(FF)
9600	,DATA(CR)
9601	,DATA(SO)
9602	,DATA(SI)
9603	,DATA(DLE)
9604	,DATA(DC1)
9605	,DATA(DC2)
9606	,DATA(DC3)
9607	,DATA(DC4)
9608	,DATA(NAK)
9609	,DATA(SYN)
9610	,DATA(ETB)
9611	,DATA(CAN)
9612	,DATA(EM)
9613	,DATA(SUB)
9614	,DATA(ESC)
9615	,DATA(FS)
9616	,DATA(GS)
9617	,DATA(RS)
9618	,DATA(US)
9619    /* aliases */
9620	,DATA2(NL, LF)
9621	,DATA(C0)
9622	,DATA(DEL)
9623	,DATA_END
9624    };
9625#undef DATA
9626#undef DATA2
9627
9628#define DATA(name) { #name, et##name }
9629    static const FlagList tblTcapOps[] =
9630    {
9631	DATA(SetTcap)
9632	,DATA(GetTcap)
9633	,DATA_END
9634    };
9635#undef DATA
9636
9637#define DATA(name) { #name, ew##name }
9638    static const FlagList tblWindowOps[] =
9639    {
9640	DATA(RestoreWin)
9641	,DATA(MinimizeWin)
9642	,DATA(SetWinPosition)
9643	,DATA(SetWinSizePixels)
9644	,DATA(RaiseWin)
9645	,DATA(LowerWin)
9646	,DATA(RefreshWin)
9647	,DATA(SetWinSizeChars)
9648#if OPT_MAXIMIZE
9649	,DATA(MaximizeWin)
9650	,DATA(FullscreenWin)
9651#endif
9652	,DATA(GetWinState)
9653	,DATA(GetWinPosition)
9654	,DATA(GetWinSizePixels)
9655	,DATA(GetWinSizeChars)
9656#if OPT_MAXIMIZE
9657	,DATA(GetScreenSizeChars)
9658#endif
9659	,DATA(GetIconTitle)
9660	,DATA(GetWinTitle)
9661	,DATA(PushTitle)
9662	,DATA(PopTitle)
9663    /* this item uses all remaining numbers in the sequence */
9664	,DATA(SetWinLines)
9665    /* starting at this point, numbers do not apply */
9666	,DATA(SetXprop)
9667	,DATA(GetSelection)
9668	,DATA(SetSelection)
9669	,DATA(GetChecksum)
9670	,DATA(SetChecksum)
9671	,DATA_END
9672    };
9673#undef DATA
9674
9675#if OPT_RENDERFONT
9676#define DATA(name) { #name, er##name }
9677    static const FlagList tblRenderFont[] =
9678    {
9679	DATA(Default)
9680	,DATA(DefaultOff)
9681	,DATA_END
9682    };
9683#undef DATA
9684#endif
9685
9686#define DATA(name) { #name, ss##name }
9687    static const FlagList tblShift2S[] =
9688    {
9689	DATA(Always)
9690	,DATA(Never)
9691	,DATA_END
9692    };
9693#undef DATA
9694
9695#if OPT_WIDE_CHARS
9696#define DATA(name) { #name, u##name }
9697    static const FlagList tblUtf8Mode[] =
9698    {
9699	DATA(Always)
9700	,DATA(Default)
9701	,DATA_END
9702    };
9703#undef DATA
9704#endif
9705
9706#ifndef NO_ACTIVE_ICON
9707#define DATA(name) { #name, ei##name }
9708    static const FlagList tblAIconOps[] =
9709    {
9710	DATA(Default)
9711	,DATA_END
9712    };
9713#undef DATA
9714#endif
9715
9716#define DATA(name) { #name, eb##name }
9717    static const FlagList tbl8BitMeta[] =
9718    {
9719	DATA(Never)
9720	,DATA(Locale)
9721	,DATA_END
9722    };
9723#undef DATA
9724
9725#define DATA(name) { #name, ed##name }
9726    static const FlagList tblCdXtraScroll[] =
9727    {
9728	DATA(Trim)
9729	,DATA_END
9730    };
9731#undef DATA
9732
9733    XtermWidget request = (XtermWidget) wrequest;
9734    XtermWidget wnew = (XtermWidget) new_arg;
9735    Widget my_parent = SHELL_OF(wnew);
9736    int i;
9737
9738#if OPT_ISO_COLORS
9739    Bool color_ok;
9740#endif
9741
9742#if OPT_ISO_COLORS
9743    static XtResource fake_resources[] =
9744    {
9745#if OPT_256_COLORS
9746# include <256colres.h>
9747#elif OPT_88_COLORS
9748# include <88colres.h>
9749#endif
9750    };
9751#endif
9752
9753    TScreen *screen = TScreenOf(wnew);
9754    char *saveLocale = xtermSetLocale(LC_NUMERIC, "C");
9755#if OPT_BLINK_CURS
9756    int ebValue;
9757#endif
9758
9759#if OPT_TRACE
9760    check_bitmasks();
9761    check_tables();
9762#endif
9763
9764    TRACE(("VTInitialize wnew %p, %d / %d resources " TRACE_L "\n",
9765	   (void *) wnew, XtNumber(xterm_resources), MAXRESOURCES));
9766    assert(XtNumber(xterm_resources) < MAXRESOURCES);
9767
9768    /* Zero out the entire "screen" component of "wnew" widget, then do
9769     * field-by-field assignment of "screen" fields that are named in the
9770     * resource list.
9771     */
9772    memset(screen, 0, sizeof(wnew->screen));
9773
9774    /* DESCO Sys#67660
9775     * Zero out the entire "keyboard" component of "wnew" widget.
9776     */
9777    memset(&wnew->keyboard, 0, sizeof(wnew->keyboard));
9778
9779    /*
9780     * The workspace has no resources - clear it.
9781     */
9782    memset(&wnew->work, 0, sizeof(wnew->work));
9783
9784    /* dummy values so that we don't try to Realize the parent shell with height
9785     * or width of 0, which is illegal in X.  The real size is computed in the
9786     * xtermWidget's Realize proc, but the shell's Realize proc is called first,
9787     * and must see a valid size.
9788     */
9789    wnew->core.height = wnew->core.width = 1;
9790
9791    /*
9792     * The definition of -rv now is that it changes the definition of
9793     * XtDefaultForeground and XtDefaultBackground.  So, we no longer
9794     * need to do anything special.
9795     */
9796    screen->display = wnew->core.screen->display;
9797
9798    /* prep getVisualInfo() */
9799    wnew->visInfo = 0;
9800    wnew->numVisuals = 0;
9801    (void) getVisualInfo(wnew);
9802
9803#if OPT_STATUS_LINE
9804    StatusInit(&screen->status_data[0]);
9805    StatusInit(&screen->status_data[1]);
9806#endif
9807
9808    /*
9809     * We use the default foreground/background colors to compare/check if a
9810     * color-resource has been set.
9811     */
9812#define MyBlackPixel(dpy) BlackPixel(dpy,DefaultScreen(dpy))
9813#define MyWhitePixel(dpy) WhitePixel(dpy,DefaultScreen(dpy))
9814
9815    if (request->misc.re_verse) {
9816	wnew->dft_foreground = MyWhitePixel(screen->display);
9817	wnew->dft_background = MyBlackPixel(screen->display);
9818    } else {
9819	wnew->dft_foreground = MyBlackPixel(screen->display);
9820	wnew->dft_background = MyWhitePixel(screen->display);
9821    }
9822
9823    init_Tres(TEXT_FG);
9824    init_Tres(TEXT_BG);
9825    repairColors(wnew);
9826
9827    wnew->old_foreground = T_COLOR(screen, TEXT_FG);
9828    wnew->old_background = T_COLOR(screen, TEXT_BG);
9829
9830    TRACE(("Color resource initialization:\n"));
9831    TRACE(("   Default foreground 0x%06lx\n", wnew->dft_foreground));
9832    TRACE(("   Default background 0x%06lx\n", wnew->dft_background));
9833    TRACE(("   Screen foreground  0x%06lx\n", T_COLOR(screen, TEXT_FG)));
9834    TRACE(("   Screen background  0x%06lx\n", T_COLOR(screen, TEXT_BG)));
9835    TRACE(("   Actual  foreground 0x%06lx\n", wnew->old_foreground));
9836    TRACE(("   Actual  background 0x%06lx\n", wnew->old_background));
9837
9838    screen->mouse_button = 0;
9839    screen->mouse_row = -1;
9840    screen->mouse_col = -1;
9841
9842#if OPT_BOX_CHARS
9843    init_Bres(screen.force_box_chars);
9844    init_Bres(screen.force_packed);
9845    init_Bres(screen.force_all_chars);
9846    init_Bres(screen.assume_all_chars);
9847#endif
9848    init_Bres(screen.free_bold_box);
9849    init_Bres(screen.allowBoldFonts);
9850
9851    init_Bres(screen.c132);
9852    init_Bres(screen.curses);
9853    init_Bres(screen.hp_ll_bc);
9854#if OPT_XMC_GLITCH
9855    init_Ires(screen.xmc_glitch);
9856    init_Ires(screen.xmc_attributes);
9857    init_Bres(screen.xmc_inline);
9858    init_Bres(screen.move_sgr_ok);
9859#endif
9860#if OPT_BLINK_CURS
9861    init_Sres(screen.cursor_blink_s);
9862    ebValue = extendedBoolean(wnew->screen.cursor_blink_s, tblBlinkOps, cbLAST);
9863    wnew->screen.cursor_blink = (BlinkOps) ebValue;
9864    init_Bres(screen.cursor_blink_xor);
9865    init_Ires(screen.blink_on);
9866    init_Ires(screen.blink_off);
9867    screen->cursor_blink_i = screen->cursor_blink;
9868#endif
9869    init_Bres(screen.cursor_underline);
9870    /* resources allow for underline or block, not (yet) bar */
9871    InitCursorShape(screen, TScreenOf(request));
9872#if OPT_BLINK_CURS
9873    TRACE(("cursor_shape:%d blinks:%d\n",
9874	   screen->cursor_shape,
9875	   screen->cursor_blink));
9876#endif
9877#if OPT_BLINK_TEXT
9878    init_Ires(screen.blink_as_bold);
9879#endif
9880    init_Ires(screen.border);
9881    init_Bres(screen.jumpscroll);
9882    init_Bres(screen.fastscroll);
9883
9884    init_Bres(screen.old_fkeys);
9885    wnew->screen.old_fkeys0 = wnew->screen.old_fkeys;
9886    wnew->keyboard.type = screen->old_fkeys
9887	? keyboardIsLegacy
9888	: keyboardIsDefault;
9889
9890    init_Mres(screen.delete_is_del);
9891#ifdef ALLOWLOGGING
9892    init_Bres(misc.logInhibit);
9893    init_Bres(misc.log_on);
9894    init_Sres(screen.logfile);
9895#endif
9896    init_Bres(screen.bellIsUrgent);
9897    init_Bres(screen.bellOnReset);
9898    init_Bres(screen.marginbell);
9899    init_Bres(screen.multiscroll);
9900    init_Ires(screen.nmarginbell);
9901    init_Ires(screen.savelines);
9902    init_Ires(screen.scrollBarBorder);
9903    init_Ires(screen.scrolllines);
9904    init_Bres(screen.alternateScroll);
9905    init_Bres(screen.scrollttyoutput);
9906    init_Bres(screen.scrollkey);
9907
9908    init_Dres(screen.scale_height);
9909    if (screen->scale_height < MIN_SCALE_HEIGHT)
9910	screen->scale_height = MIN_SCALE_HEIGHT;
9911    if (screen->scale_height > MAX_SCALE_HEIGHT)
9912	screen->scale_height = MAX_SCALE_HEIGHT;
9913
9914    init_Bres(misc.autoWrap);
9915    init_Bres(misc.login_shell);
9916    init_Bres(misc.reverseWrap);
9917    init_Bres(misc.scrollbar);
9918    init_Sres(misc.geo_metry);
9919    init_Sres(misc.T_geometry);
9920
9921    init_Sres(screen.term_id);
9922    screen->terminal_id = decodeTerminalID(TScreenOf(request)->term_id);
9923    /*
9924     * (1) If a known terminal model, and not a graphical terminal, preserve
9925     *     the terminal id.
9926     * (2) Otherwise, if ReGIS or sixel graphics are enabled, preserve the ID,
9927     *     even if it is not a known terminal.
9928     * (3) Otherwise force the terminal ID to the min, max, or VT420 depending
9929     *     on the input.
9930     */
9931    switch (screen->terminal_id) {
9932    case 52:			/* MIN_DECID */
9933    case 100:
9934    case 101:
9935    case 102:
9936    case 131:
9937    case 132:
9938    case 220:
9939    case 320:
9940    case 420:			/* DFT_DECID, unless overridden in configure */
9941    case 510:
9942    case 520:
9943    case 525:			/* MAX_DECID */
9944	break;
9945    default:
9946#if OPT_REGIS_GRAPHICS
9947	if (optRegisGraphics(screen))
9948	    break;
9949#endif
9950#if OPT_SIXEL_GRAPHICS
9951	if (optSixelGraphics(screen))
9952	    break;
9953#endif
9954	screen->terminal_id = limitedTerminalID(screen->terminal_id);
9955	break;
9956    }
9957    TRACE(("term_id '%s' -> terminal_id %d\n",
9958	   screen->term_id,
9959	   screen->terminal_id));
9960
9961    screen->vtXX_level = (screen->terminal_id / 100);
9962
9963    init_Ires(screen.title_modes);
9964    screen->title_modes0 = screen->title_modes;
9965
9966    init_Ires(screen.nextEventDelay);
9967    if (screen->nextEventDelay <= 0)
9968	screen->nextEventDelay = 1;
9969
9970    init_Bres(screen.visualbell);
9971    init_Bres(screen.flash_line);
9972    init_Ires(screen.visualBellDelay);
9973    init_Bres(screen.poponbell);
9974
9975    init_Bres(screen.eraseSavedLines0);
9976    screen->eraseSavedLines = screen->eraseSavedLines0;
9977
9978    init_Ires(misc.limit_resize);
9979
9980#if OPT_NUM_LOCK
9981    init_Bres(misc.real_NumLock);
9982    init_Bres(misc.alwaysUseMods);
9983#endif
9984
9985#if OPT_INPUT_METHOD
9986    init_Bres(misc.open_im);
9987    init_Ires(misc.retry_im);
9988    init_Sres(misc.f_x);
9989    init_Sres(misc.input_method);
9990    init_Sres(misc.preedit_type);
9991#endif
9992
9993#if OPT_SHIFT_FONTS
9994    init_Bres(misc.shift_fonts);
9995#endif
9996#if OPT_SUNPC_KBD
9997    init_Ires(misc.ctrl_fkeys);
9998#endif
9999#if OPT_TEK4014
10000    TEK4014_SHOWN(wnew) = False;	/* not a resource... */
10001    init_Bres(misc.tekInhibit);
10002    init_Bres(misc.tekSmall);
10003    init_Bres(misc.TekEmu);
10004#endif
10005#if OPT_TCAP_QUERY
10006    screen->tc_query_code = -1;
10007#endif
10008    wnew->misc.re_verse0 = request->misc.re_verse;
10009    init_Bres(misc.re_verse);
10010    init_Ires(screen.multiClickTime);
10011    init_Ires(screen.bellSuppressTime);
10012    init_Sres(screen.charClass);
10013
10014    init_Bres(screen.always_highlight);
10015    init_Bres(screen.brokenSelections);
10016    init_Bres(screen.cutNewline);
10017    init_Bres(screen.cutToBeginningOfLine);
10018    init_Bres(screen.highlight_selection);
10019    init_Bres(screen.show_wrap_marks);
10020    init_Bres(screen.i18nSelections);
10021    init_Bres(screen.keepClipboard);
10022    init_Bres(screen.keepSelection);
10023    init_Bres(screen.selectToClipboard);
10024    init_Bres(screen.trim_selection);
10025
10026    screen->pointer_cursor = TScreenOf(request)->pointer_cursor;
10027    init_Ires(screen.pointer_mode);
10028    wnew->screen.pointer_mode0 = wnew->screen.pointer_mode;
10029
10030    init_Sres(screen.answer_back);
10031
10032    wnew->SPS.printer_checked = False;
10033    init_Sres(SPS.printer_command);
10034    init_Bres(SPS.printer_autoclose);
10035    init_Bres(SPS.printer_extent);
10036    init_Bres(SPS.printer_formfeed);
10037    init_Bres(SPS.printer_newline);
10038    init_Ires(SPS.printer_controlmode);
10039#if OPT_PRINT_COLORS
10040    init_Ires(SPS.print_attributes);
10041#endif
10042
10043    init_Sres(screen.keyboard_dialect);
10044
10045    init_Sres(screen.cursor_font_name);
10046    init_Sres(screen.pointer_shape);
10047
10048    init_Bres(screen.input_eight_bits);
10049    init_Bres(screen.output_eight_bits);
10050    init_Bres(screen.control_eight_bits);
10051    init_Bres(screen.backarrow_key);
10052    init_Bres(screen.alt_is_not_meta);
10053    init_Bres(screen.alt_sends_esc);
10054    init_Bres(screen.meta_sends_esc);
10055
10056    init_Bres(screen.allowPasteControl0);
10057    init_Bres(screen.allowSendEvent0);
10058    init_Bres(screen.allowColorOp0);
10059    init_Bres(screen.allowFontOp0);
10060    init_Bres(screen.allowMouseOp0);
10061    init_Bres(screen.allowTcapOp0);
10062    init_Bres(screen.allowTitleOp0);
10063    init_Bres(screen.allowWindowOp0);
10064
10065#if OPT_SCROLL_LOCK
10066    init_Bres(screen.allowScrollLock0);
10067    init_Bres(screen.autoScrollLock);
10068#endif
10069
10070    init_Sres(screen.disallowedColorOps);
10071
10072    set_flags_from_list(screen->disallow_color_ops,
10073			screen->disallowedColorOps,
10074			tblColorOps);
10075
10076    init_Sres(screen.disallowedFontOps);
10077
10078    set_flags_from_list(screen->disallow_font_ops,
10079			screen->disallowedFontOps,
10080			tblFontOps);
10081
10082    init_Sres(screen.disallowedMouseOps);
10083
10084    set_flags_from_list(screen->disallow_mouse_ops,
10085			screen->disallowedMouseOps,
10086			tblMouseOps);
10087
10088    init_Sres(screen.disallowedPasteControls);
10089
10090    set_flags_from_list(screen->disallow_paste_controls,
10091			screen->disallowedPasteControls,
10092			tblPasteControls);
10093
10094    init_Sres(screen.disallowedTcapOps);
10095
10096    set_flags_from_list(screen->disallow_tcap_ops,
10097			screen->disallowedTcapOps,
10098			tblTcapOps);
10099
10100    init_Sres(screen.disallowedWinOps);
10101
10102    set_flags_from_list(screen->disallow_win_ops,
10103			screen->disallowedWinOps,
10104			tblWindowOps);
10105
10106    init_Sres(screen.default_string);
10107    init_Sres(screen.eightbit_select_types);
10108#if OPT_WIDE_CHARS
10109    init_Sres(screen.utf8_select_types);
10110#endif
10111
10112    /* make a copy so that editres cannot change the resource after startup */
10113    screen->allowPasteControls = screen->allowPasteControl0;
10114    screen->allowSendEvents = screen->allowSendEvent0;
10115    screen->allowColorOps = screen->allowColorOp0;
10116    screen->allowFontOps = screen->allowFontOp0;
10117    screen->allowMouseOps = screen->allowMouseOp0;
10118    screen->allowTcapOps = screen->allowTcapOp0;
10119    screen->allowTitleOps = screen->allowTitleOp0;
10120    screen->allowWindowOps = screen->allowWindowOp0;
10121
10122#if OPT_SCROLL_LOCK
10123    screen->allowScrollLock = screen->allowScrollLock0;
10124#endif
10125
10126    init_Bres(screen.quiet_grab);
10127
10128#ifndef NO_ACTIVE_ICON
10129    init_Sres(screen.icon_fontname);
10130    getIconicFont(screen)->fs = xtermLoadQueryFont(wnew,
10131						   screen->icon_fontname);
10132    TRACE(("iconFont '%s' %sloaded successfully\n",
10133	   screen->icon_fontname,
10134	   getIconicFont(screen)->fs ? "" : "NOT "));
10135    init_Sres(misc.active_icon_s);
10136    wnew->work.active_icon =
10137	(Boolean) extendedBoolean(wnew->misc.active_icon_s,
10138				  tblAIconOps, eiLAST);
10139    init_Ires(misc.icon_border_width);
10140    wnew->misc.icon_border_pixel = request->misc.icon_border_pixel;
10141#endif /* NO_ACTIVE_ICON */
10142
10143    init_Bres(misc.signalInhibit);
10144    init_Bres(misc.titeInhibit);
10145    init_Bres(misc.color_inner_border);
10146    init_Bres(misc.dynamicColors);
10147    init_Bres(misc.resizeByPixel);
10148
10149    init_Sres(misc.cdXtraScroll_s);
10150    wnew->misc.cdXtraScroll =
10151	extendedBoolean(request->misc.cdXtraScroll_s, tblCdXtraScroll, edLast);
10152
10153    init_Sres(misc.tiXtraScroll_s);
10154    wnew->misc.tiXtraScroll =
10155	extendedBoolean(request->misc.tiXtraScroll_s, tblCdXtraScroll, edLast);
10156
10157#if OPT_DEC_CHRSET
10158    for (i = 0; i < NUM_CHRSET; i++) {
10159	screen->double_fonts[i].warn = fwResource;
10160    }
10161#endif
10162    for (i = fontMenu_font1; i <= fontMenu_lastBuiltin; i++) {
10163	init_Sres2(screen.MenuFontName, i);
10164    }
10165    for (i = 0; i < fMAX; i++) {
10166	screen->fnts[i].warn = fwResource;
10167#if OPT_WIDE_ATTRS
10168	screen->ifnts[i].warn = fwResource;
10169#endif
10170    }
10171#ifndef NO_ACTIVE_ICON
10172    screen->fnt_icon.warn = fwResource;
10173#endif
10174
10175    init_Ires(misc.fontWarnings);
10176
10177    initFontLists(wnew);
10178
10179#define DefaultFontNames screen->menu_font_names[fontMenu_default]
10180
10181    /*
10182     * Process Xft font resources first, since faceName may contain X11 fonts
10183     * that should override the "font" resource.
10184     */
10185#if OPT_RENDERFONT
10186    init_Bres(screen.force_xft_height);
10187    for (i = 0; i <= fontMenu_lastBuiltin; ++i) {
10188	init_Dres2(misc.face_size, i);
10189    }
10190
10191#define ALLOC_FONTLIST(name,which,field) \
10192    init_Sres(misc.default_xft.field);\
10193    allocFontList(wnew,\
10194		  name,\
10195		  &(wnew->work.fonts),\
10196		  which,\
10197		  wnew->misc.default_xft.field,\
10198		  True)
10199
10200    ALLOC_FONTLIST(XtNfaceName, fNorm, f_n);
10201
10202#if OPT_WIDE_CHARS
10203    ALLOC_FONTLIST(XtNfaceNameDoublesize, fWide, f_w);
10204#endif
10205
10206#undef ALLOC_FONTLIST
10207
10208#endif
10209
10210    /*
10211     * Process X11 (XLFD) font specifications.
10212     */
10213#define ALLOC_FONTLIST(name,which,field) \
10214    init_Sres(misc.default_font.field);\
10215    allocFontList(wnew,\
10216		  name,\
10217		  &(wnew->work.fonts),\
10218		  which,\
10219		  wnew->misc.default_font.field,\
10220		  False)
10221
10222    ALLOC_FONTLIST(XtNfont, fNorm, f_n);
10223    ALLOC_FONTLIST(XtNboldFont, fBold, f_b);
10224
10225    DefaultFontNames[fNorm] = x_strdup(DefaultFontN(wnew));
10226    DefaultFontNames[fBold] = x_strdup(DefaultFontB(wnew));
10227
10228#if OPT_WIDE_CHARS
10229    ALLOC_FONTLIST(XtNwideFont, fWide, f_w);
10230    ALLOC_FONTLIST(XtNwideBoldFont, fWBold, f_wb);
10231
10232    DefaultFontNames[fWide] = x_strdup(DefaultFontW(wnew));
10233    DefaultFontNames[fWBold] = x_strdup(DefaultFontWB(wnew));
10234#endif
10235
10236#undef ALLOC_FONTLIST
10237
10238    screen->EscapeFontName() = NULL;
10239    screen->SelectFontName() = NULL;
10240
10241    screen->menu_font_number = fontMenu_default;
10242    init_Sres(screen.initial_font);
10243    if (screen->initial_font != 0) {
10244	int result = xtermGetFont(screen->initial_font);
10245	if (result >= 0)
10246	    screen->menu_font_number = result;
10247    }
10248#if OPT_BROKEN_OSC
10249    init_Bres(screen.brokenLinuxOSC);
10250#endif
10251
10252#if OPT_BROKEN_ST
10253    init_Bres(screen.brokenStringTerm);
10254#endif
10255
10256#if OPT_C1_PRINT
10257    init_Bres(screen.c1_printable);
10258#endif
10259
10260#if OPT_CLIP_BOLD
10261    init_Bres(screen.use_border_clipping);
10262    init_Bres(screen.use_clipping);
10263#endif
10264
10265#if OPT_DEC_CHRSET
10266    init_Bres(screen.font_doublesize);
10267    init_Ires(screen.cache_doublesize);
10268    if (screen->cache_doublesize > NUM_CHRSET)
10269	screen->cache_doublesize = NUM_CHRSET;
10270    if (screen->cache_doublesize == 0)
10271	screen->font_doublesize = False;
10272    TRACE(("Doublesize%s enabled, up to %d fonts\n",
10273	   screen->font_doublesize ? "" : " not",
10274	   screen->cache_doublesize));
10275#endif
10276#if OPT_DEC_RECTOPS
10277    init_Ires(screen.checksum_ext0);
10278    screen->checksum_ext = screen->checksum_ext0;
10279#endif
10280
10281#if OPT_ISO_COLORS
10282    init_Ires(screen.veryBoldColors);
10283    init_Bres(screen.boldColors);
10284    init_Bres(screen.colorAttrMode);
10285    init_Bres(screen.colorBDMode);
10286    init_Bres(screen.colorBLMode);
10287    init_Bres(screen.colorMode);
10288    init_Bres(screen.colorULMode);
10289    init_Bres(screen.italicULMode);
10290    init_Bres(screen.colorRVMode);
10291
10292#if OPT_WIDE_ATTRS
10293    init_Bres(screen.colorITMode);
10294#endif
10295#if OPT_DIRECT_COLOR
10296    init_Bres(screen.direct_color);
10297#endif
10298
10299    TRACE(("...will fake resources for color%d to color%d\n",
10300	   MIN_ANSI_COLORS,
10301	   NUM_ANSI_COLORS - 1));
10302
10303    for (i = 0, color_ok = False; i < MAXCOLORS; i++) {
10304	/*
10305	 * Xt has a hardcoded limit on the maximum number of resources that can
10306	 * be used in a widget.  If we configured both luit (which implies
10307	 * wide-characters) and 256-colors, it goes over that limit.  Most
10308	 * people would not need a resource-file with 256-colors; the default
10309	 * values in our table are sufficient.  Fake the resource setting by
10310	 * copying the default value from the table.  The #define's can be
10311	 * overridden to make these true resources.
10312	 */
10313	if (i >= MIN_ANSI_COLORS && i < NUM_ANSI_COLORS) {
10314	    screen->Acolors[i].resource =
10315		x_strtrim(fake_resources[i - MIN_ANSI_COLORS].default_addr);
10316	    if (screen->Acolors[i].resource == 0)
10317		screen->Acolors[i].resource = XtDefaultForeground;
10318	} else {
10319	    screen->Acolors[i] = TScreenOf(request)->Acolors[i];
10320	    screen->Acolors[i].resource =
10321		x_strtrim(screen->Acolors[i].resource);
10322	}
10323
10324	TRACE(("Acolors[%d] = %s\n", i, screen->Acolors[i].resource));
10325	screen->Acolors[i].mode = False;
10326	if (DftFg(Acolors[i])) {
10327	    screen->Acolors[i].value = T_COLOR(screen, TEXT_FG);
10328	    screen->Acolors[i].mode = True;
10329	} else if (DftBg(Acolors[i])) {
10330	    screen->Acolors[i].value = T_COLOR(screen, TEXT_BG);
10331	    screen->Acolors[i].mode = True;
10332	} else {
10333	    color_ok = True;
10334	}
10335    }
10336
10337    /*
10338     * Check if we're trying to use color in a monochrome screen.  Disable
10339     * color in that case, since that would make ANSI colors unusable.  A 4-bit
10340     * or 8-bit display is usable, so we do not have to check for anything more
10341     * specific.
10342     */
10343    if (color_ok) {
10344	if (getVisualDepth(wnew) <= 1) {
10345	    TRACE(("disabling color since screen is monochrome\n"));
10346	    color_ok = False;
10347	}
10348    }
10349
10350    /* If none of the colors are anything other than the foreground or
10351     * background, we'll assume this isn't color, no matter what the colorMode
10352     * resource says.  (There doesn't seem to be any good way to determine if
10353     * the resource lookup failed versus the user having misconfigured this).
10354     */
10355    if (!color_ok) {
10356	screen->colorMode = False;
10357	TRACE(("All colors are foreground or background: disable colorMode\n"));
10358    }
10359    wnew->sgr_foreground = -1;
10360    wnew->sgr_background = -1;
10361    wnew->sgr_38_xcolors = False;
10362    clrDirectFG(wnew->flags);
10363    clrDirectFG(wnew->flags);
10364#endif /* OPT_ISO_COLORS */
10365
10366    /*
10367     * Decode the resources that control the behavior on multiple mouse clicks.
10368     * A single click is always bound to normal character selection, but the
10369     * other flavors can be changed.
10370     */
10371    for (i = 0; i < NSELECTUNITS; ++i) {
10372	int ck = (i + 1);
10373	screen->maxClicks = ck;
10374	if (i == Select_CHAR)
10375	    screen->selectMap[i] = Select_CHAR;
10376	else if (TScreenOf(request)->onClick[i] != 0)
10377	    ParseOnClicks(wnew, request, (unsigned) i);
10378	else if (i <= Select_LINE)
10379	    screen->selectMap[i] = (SelectUnit) i;
10380	else
10381	    break;
10382#if OPT_XRES_QUERY
10383	init_Sres(screen.onClick[i]);
10384#endif
10385	TRACE(("on%dClicks %s=%d\n", ck,
10386	       NonNull(TScreenOf(request)->onClick[i]),
10387	       screen->selectMap[i]));
10388	if (screen->selectMap[i] == NSELECTUNITS)
10389	    break;
10390    }
10391    TRACE(("maxClicks %d\n", screen->maxClicks));
10392
10393    init_Tres(MOUSE_FG);
10394    init_Tres(MOUSE_BG);
10395    init_Tres(TEXT_CURSOR);
10396#if OPT_HIGHLIGHT_COLOR
10397    init_Tres(HIGHLIGHT_BG);
10398    init_Tres(HIGHLIGHT_FG);
10399    init_Bres(screen.hilite_reverse);
10400    init_Mres(screen.hilite_color);
10401    if (screen->hilite_color == Maybe) {
10402	screen->hilite_color = False;
10403	/*
10404	 * If the highlight text/background are both set, and if they are
10405	 * not equal to either the text/background or background/text, then
10406	 * set the highlightColorMode automatically.
10407	 */
10408	if (!DftFg(Tcolors[HIGHLIGHT_BG])
10409	    && !DftBg(Tcolors[HIGHLIGHT_FG])
10410	    && !TxtFg(Tcolors[HIGHLIGHT_BG])
10411	    && !TxtBg(Tcolors[HIGHLIGHT_FG])
10412	    && !TxtBg(Tcolors[HIGHLIGHT_BG])
10413	    && !TxtFg(Tcolors[HIGHLIGHT_FG])) {
10414	    TRACE(("...setting hilite_color automatically\n"));
10415	    screen->hilite_color = True;
10416	}
10417    }
10418#endif
10419
10420#if OPT_TEK4014
10421    /*
10422     * The Tek4014 window has no separate resources for foreground, background
10423     * and cursor color.  Since xterm always creates the vt100 widget first, we
10424     * can set the Tektronix colors here.  That lets us use escape sequences to
10425     * set its dynamic colors and get consistent behavior whether or not the
10426     * window is displayed.
10427     */
10428    screen->Tcolors[TEK_BG] = screen->Tcolors[TEXT_BG];
10429    screen->Tcolors[TEK_FG] = screen->Tcolors[TEXT_FG];
10430    screen->Tcolors[TEK_CURSOR] = screen->Tcolors[TEXT_CURSOR];
10431#endif
10432
10433#ifdef SCROLLBAR_RIGHT
10434    init_Bres(misc.useRight);
10435#endif
10436
10437#if OPT_RENDERFONT
10438    init_Ires(misc.limit_fontsets);
10439    wnew->work.max_fontsets = (unsigned) wnew->misc.limit_fontsets;
10440
10441    init_Sres(misc.render_font_s);
10442    wnew->work.render_font =
10443	(Boolean) extendedBoolean(wnew->misc.render_font_s,
10444				  tblRenderFont, erLast);
10445    if (wnew->work.render_font == erDefault) {
10446	if (IsEmpty(CurrentXftFont(wnew))) {
10447	    free((void *) CurrentXftFont(wnew));
10448	    CurrentXftFont(wnew) = x_strdup(DEFFACENAME_AUTO);
10449	    TRACE(("will allow runtime switch to render_font using \"%s\"\n",
10450		   CurrentXftFont(wnew)));
10451	} else {
10452	    wnew->work.render_font = erTrue;
10453	    TRACE(("initially using TrueType font\n"));
10454	}
10455    } else if (wnew->work.render_font == erDefaultOff) {
10456	wnew->work.render_font = erFalse;
10457    }
10458    /* minor tweak to make debug traces consistent: */
10459    if (wnew->work.render_font) {
10460	if (IsEmpty(CurrentXftFont(wnew))) {
10461	    wnew->work.render_font = False;
10462	    TRACE(("reset render_font since there is no face_name\n"));
10463	}
10464    }
10465#endif
10466
10467#if OPT_WIDE_CHARS
10468    /* setup data for next call */
10469    init_Sres(screen.utf8_mode_s);
10470    request->screen.utf8_mode =
10471	extendedBoolean(request->screen.utf8_mode_s, tblUtf8Mode, uLast);
10472
10473    init_Sres(screen.utf8_fonts_s);
10474    request->screen.utf8_fonts =
10475	extendedBoolean(request->screen.utf8_fonts_s, tblUtf8Mode, uLast);
10476
10477    init_Sres(screen.utf8_title_s);
10478    request->screen.utf8_title =
10479	extendedBoolean(request->screen.utf8_title_s, tblUtf8Mode, uLast);
10480
10481    /*
10482     * Make a copy in the input/request so that DefaultFontN() works for
10483     * the "CHECKFONT" option.
10484     */
10485    copyFontList(&(request->work.fonts.x11.list_n),
10486		 wnew->work.fonts.x11.list_n);
10487
10488    VTInitialize_locale(request);
10489    init_Bres(screen.normalized_c);
10490    init_Bres(screen.utf8_latin1);
10491    init_Bres(screen.utf8_weblike);
10492
10493#if OPT_LUIT_PROG
10494    init_Bres(misc.callfilter);
10495    init_Bres(misc.use_encoding);
10496    init_Sres(misc.locale_str);
10497    init_Sres(misc.localefilter);
10498#endif
10499
10500    init_Ires(screen.utf8_inparse);
10501    init_Ires(screen.utf8_mode);
10502    init_Ires(screen.utf8_fonts);
10503    init_Ires(screen.utf8_title);
10504    init_Ires(screen.max_combining);
10505
10506    init_Ires(screen.utf8_always);	/* from utf8_mode, used in doparse */
10507
10508    if (screen->max_combining < 0) {
10509	screen->max_combining = 0;
10510    }
10511    if (screen->max_combining > 5) {
10512	screen->max_combining = 5;
10513    }
10514
10515    init_Bres(screen.vt100_graphics);
10516    init_Bres(screen.wide_chars);
10517    init_Bres(misc.mk_width);
10518    init_Bres(misc.cjk_width);
10519
10520    init_Ires(misc.mk_samplesize);
10521    init_Ires(misc.mk_samplepass);
10522
10523    if (wnew->misc.mk_samplesize > 0xffff)
10524	wnew->misc.mk_samplesize = 0xffff;
10525    if (wnew->misc.mk_samplesize < 0)
10526	wnew->misc.mk_samplesize = 0;
10527
10528    if (wnew->misc.mk_samplepass > wnew->misc.mk_samplesize)
10529	wnew->misc.mk_samplepass = wnew->misc.mk_samplesize;
10530    if (wnew->misc.mk_samplepass < 0)
10531	wnew->misc.mk_samplepass = 0;
10532
10533    if (TScreenOf(request)->utf8_mode) {
10534	TRACE(("setting wide_chars on\n"));
10535	screen->wide_chars = True;
10536    } else {
10537	TRACE(("setting utf8_mode to 0\n"));
10538	screen->utf8_mode = uFalse;
10539    }
10540    mk_wcwidth_init(screen->utf8_mode);
10541    TRACE(("initialized UTF-8 mode to %d\n", screen->utf8_mode));
10542
10543#if OPT_MINI_LUIT
10544    if (TScreenOf(request)->latin9_mode) {
10545	screen->latin9_mode = True;
10546    }
10547    if (TScreenOf(request)->unicode_font) {
10548	screen->unicode_font = True;
10549    }
10550    TRACE(("initialized Latin9 mode to %d\n", screen->latin9_mode));
10551    TRACE(("initialized unicode_font to %d\n", screen->unicode_font));
10552#endif
10553
10554    decode_wcwidth(wnew);
10555    xtermSaveVTFonts(wnew);
10556#endif /* OPT_WIDE_CHARS */
10557
10558    init_Sres(screen.eight_bit_meta_s);
10559    wnew->screen.eight_bit_meta =
10560	extendedBoolean(request->screen.eight_bit_meta_s, tbl8BitMeta, ebLast);
10561    if (wnew->screen.eight_bit_meta == ebLocale) {
10562#if OPT_WIDE_CHARS
10563	if (xtermEnvUTF8()) {
10564	    wnew->screen.eight_bit_meta = ebFalse;
10565	    TRACE(("...eightBitMeta is false due to locale\n"));
10566	} else
10567#endif /* OPT_WIDE_CHARS */
10568	{
10569	    wnew->screen.eight_bit_meta = ebTrue;
10570	    TRACE(("...eightBitMeta is true due to locale\n"));
10571	}
10572    }
10573
10574    init_Bres(screen.always_bold_mode);
10575    init_Bres(screen.bold_mode);
10576    init_Bres(screen.underline);
10577
10578    wnew->cur_foreground = 0;
10579    wnew->cur_background = 0;
10580
10581    wnew->keyboard.flags = MODE_SRM;
10582
10583    if (screen->backarrow_key)
10584	wnew->keyboard.flags |= MODE_DECBKM;
10585    TRACE(("initialized DECBKM %s\n",
10586	   BtoS(wnew->keyboard.flags & MODE_DECBKM)));
10587
10588#if OPT_SIXEL_GRAPHICS
10589    init_Bres(screen.sixel_scrolling);
10590    if (screen->sixel_scrolling)
10591	wnew->keyboard.flags |= MODE_DECSDM;
10592    TRACE(("initialized DECSDM %s\n",
10593	   BtoS(wnew->keyboard.flags & MODE_DECSDM)));
10594#endif
10595
10596#if OPT_GRAPHICS
10597    init_Sres(screen.graph_termid);
10598    screen->graphics_termid = decodeTerminalID(TScreenOf(request)->graph_termid);
10599    switch (screen->graphics_termid) {
10600    case 125:
10601    case 240:
10602    case 241:
10603    case 330:
10604    case 340:
10605    case 382:
10606	break;
10607    default:
10608	screen->graphics_termid = 0;
10609	break;
10610    }
10611    TRACE(("graph_termid '%s' -> graphics_termid %d\n",
10612	   screen->graph_termid,
10613	   screen->graphics_termid));
10614
10615    init_Ires(screen.numcolorregisters);
10616    TRACE(("initialized NUM_COLOR_REGISTERS to resource default: %d\n",
10617	   screen->numcolorregisters));
10618
10619    init_Bres(screen.privatecolorregisters);	/* FIXME: should this be off unconditionally here? */
10620    TRACE(("initialized PRIVATE_COLOR_REGISTERS to resource default: %s\n",
10621	   BtoS(screen->privatecolorregisters)));
10622#endif
10623
10624#if OPT_GRAPHICS
10625    {
10626	int native_w, native_h;
10627
10628	switch (GraphicsTermId(screen)) {
10629	case 125:
10630	    native_w = 768;
10631	    native_h = 460;
10632	    break;
10633	case 240:
10634	    /* FALLTHRU */
10635	case 241:
10636	    native_w = 800;
10637	    native_h = 460;
10638	    break;
10639	case 330:
10640	    /* FALLTHRU */
10641	case 340:
10642	    native_w = 800;
10643	    native_h = 480;
10644	    break;
10645	default:
10646	    native_w = 800;
10647	    native_h = 480;
10648	    break;
10649	case 382:
10650	    native_w = 960;
10651	    native_h = 750;
10652	    break;
10653	}
10654
10655# if OPT_REGIS_GRAPHICS
10656	init_Sres(screen.graphics_regis_default_font);
10657	TRACE(("default ReGIS font: %s\n",
10658	       screen->graphics_regis_default_font));
10659
10660	init_Sres(screen.graphics_regis_screensize);
10661	screen->graphics_regis_def_high = 1000;
10662	screen->graphics_regis_def_wide = 1000;
10663	if (!x_strcasecmp(screen->graphics_regis_screensize, "auto")) {
10664	    TRACE(("setting default ReGIS screensize based on graphics_id %d\n",
10665		   GraphicsTermId(screen)));
10666	    screen->graphics_regis_def_high = (Dimension) native_h;
10667	    screen->graphics_regis_def_wide = (Dimension) native_w;
10668	} else {
10669	    int conf_high;
10670	    int conf_wide;
10671	    char ignore;
10672
10673	    if (sscanf(screen->graphics_regis_screensize,
10674		       "%dx%d%c",
10675		       &conf_wide,
10676		       &conf_high,
10677		       &ignore) == 2) {
10678		if (conf_high > 0 && conf_wide > 0) {
10679		    screen->graphics_regis_def_high =
10680			(Dimension) conf_high;
10681		    screen->graphics_regis_def_wide =
10682			(Dimension) conf_wide;
10683		} else {
10684		    TRACE(("ignoring invalid regisScreenSize %s\n",
10685			   screen->graphics_regis_screensize));
10686		}
10687	    } else {
10688		TRACE(("ignoring invalid regisScreenSize %s\n",
10689		       screen->graphics_regis_screensize));
10690	    }
10691	}
10692	TRACE(("default ReGIS graphics screensize %dx%d\n",
10693	       (int) screen->graphics_regis_def_wide,
10694	       (int) screen->graphics_regis_def_high));
10695# endif
10696
10697	init_Sres(screen.graphics_max_size);
10698	screen->graphics_max_high = 1000;
10699	screen->graphics_max_wide = 1000;
10700	if (!x_strcasecmp(screen->graphics_max_size, "auto")) {
10701	    TRACE(("setting max graphics screensize based on graphics_id %d\n",
10702		   GraphicsTermId(screen)));
10703	    screen->graphics_max_high = (Dimension) native_h;
10704	    screen->graphics_max_wide = (Dimension) native_w;
10705	} else {
10706	    int conf_high;
10707	    int conf_wide;
10708	    char ignore;
10709
10710	    if (sscanf(screen->graphics_max_size,
10711		       "%dx%d%c",
10712		       &conf_wide,
10713		       &conf_high,
10714		       &ignore) == 2) {
10715		if (conf_high > 0 && conf_wide > 0) {
10716		    screen->graphics_max_high = (Dimension) conf_high;
10717		    screen->graphics_max_wide = (Dimension) conf_wide;
10718		} else {
10719		    TRACE(("ignoring invalid maxGraphicSize %s\n",
10720			   screen->graphics_max_size));
10721		}
10722	    } else {
10723		TRACE(("ignoring invalid maxGraphicSize %s\n",
10724		       screen->graphics_max_size));
10725	    }
10726	}
10727# if OPT_REGIS_GRAPHICS
10728	/* Make sure the max is large enough for the default ReGIS size. */
10729	if (screen->graphics_regis_def_high >
10730	    screen->graphics_max_high) {
10731	    screen->graphics_max_high =
10732		screen->graphics_regis_def_high;
10733	}
10734	if (screen->graphics_regis_def_wide >
10735	    screen->graphics_max_wide) {
10736	    screen->graphics_max_wide =
10737		screen->graphics_regis_def_wide;
10738	}
10739# endif
10740	TRACE(("max graphics screensize %dx%d\n",
10741	       (int) screen->graphics_max_wide,
10742	       (int) screen->graphics_max_high));
10743    }
10744#endif
10745
10746#if OPT_SIXEL_GRAPHICS
10747    init_Bres(screen.sixel_scrolls_right);
10748#endif
10749#if OPT_PRINT_GRAPHICS
10750    init_Bres(screen.graphics_print_to_host);
10751    init_Bres(screen.graphics_expanded_print_mode);
10752    init_Bres(screen.graphics_print_color_mode);
10753    init_Bres(screen.graphics_print_color_syntax);
10754    init_Bres(screen.graphics_print_background_mode);
10755    init_Bres(screen.graphics_rotated_print_mode);
10756#endif
10757
10758#if OPT_STATUS_LINE
10759    init_Sres(screen.status_fmt);
10760#endif
10761
10762    /* look for focus related events on the shell, because we need
10763     * to care about the shell's border being part of our focus.
10764     */
10765    TRACE(("adding event handlers for my_parent %p\n", (void *) my_parent));
10766    XtAddEventHandler(my_parent, EnterWindowMask, False,
10767		      HandleEnterWindow, (Opaque) NULL);
10768    XtAddEventHandler(my_parent, LeaveWindowMask, False,
10769		      HandleLeaveWindow, (Opaque) NULL);
10770    XtAddEventHandler(my_parent, FocusChangeMask, False,
10771		      HandleFocusChange, (Opaque) NULL);
10772    XtAddEventHandler((Widget) wnew, 0L, True,
10773		      VTNonMaskableEvent, (Opaque) NULL);
10774    XtAddEventHandler((Widget) wnew, PropertyChangeMask, False,
10775		      HandleBellPropertyChange, (Opaque) NULL);
10776
10777#if HANDLE_STRUCT_NOTIFY
10778#if OPT_TOOLBAR
10779    wnew->VT100_TB_INFO(menu_bar) = request->VT100_TB_INFO(menu_bar);
10780    init_Ires(VT100_TB_INFO(menu_height));
10781#endif
10782    XtAddEventHandler(my_parent, MappingNotify | StructureNotifyMask, False,
10783		      HandleStructNotify, (Opaque) 0);
10784#endif /* HANDLE_STRUCT_NOTIFY */
10785
10786    screen->bellInProgress = False;
10787
10788    set_character_class(screen->charClass);
10789#if OPT_REPORT_CCLASS
10790    if (resource.reportCClass)
10791	report_char_class(wnew);
10792#endif
10793
10794    /* create it, but don't realize it */
10795    ScrollBarOn(wnew, True);
10796
10797    /* make sure that the resize gravity acceptable */
10798    if (!GravityIsNorthWest(wnew) &&
10799	!GravityIsSouthWest(wnew)) {
10800	char value[80];
10801	String temp[2];
10802	Cardinal nparams = 1;
10803
10804	sprintf(value, "%d", wnew->misc.resizeGravity);
10805	temp[0] = value;
10806	temp[1] = 0;
10807	XtAppWarningMsg(app_con, "rangeError", "resizeGravity", "XTermError",
10808			"unsupported resizeGravity resource value (%s)",
10809			temp, &nparams);
10810	wnew->misc.resizeGravity = SouthWestGravity;
10811    }
10812#ifndef NO_ACTIVE_ICON
10813    screen->whichVwin = &screen->fullVwin;
10814#endif /* NO_ACTIVE_ICON */
10815
10816    init_Ires(screen.unparse_max);
10817    if ((int) screen->unparse_max < 256)
10818	screen->unparse_max = 256;
10819    screen->unparse_bfr = (IChar *) (void *) XtCalloc(screen->unparse_max,
10820						      (Cardinal) sizeof(IChar));
10821
10822    if (screen->savelines < 0)
10823	screen->savelines = 0;
10824
10825    init_Bres(screen.awaitInput);
10826
10827    wnew->flags = 0;
10828    if (!screen->jumpscroll)
10829	wnew->flags |= SMOOTHSCROLL;
10830    if (wnew->misc.reverseWrap)
10831	wnew->flags |= REVERSEWRAP;
10832    if (wnew->misc.autoWrap)
10833	wnew->flags |= WRAPAROUND;
10834    if (wnew->misc.re_verse != wnew->misc.re_verse0)
10835	wnew->flags |= REVERSE_VIDEO;
10836    if (screen->c132)
10837	wnew->flags |= IN132COLUMNS;
10838
10839    wnew->initflags = wnew->flags;
10840
10841    init_Sres(keyboard.shift_escape_s);
10842    wnew->keyboard.shift_escape =
10843	extendedBoolean(wnew->keyboard.shift_escape_s, tblShift2S, ssLAST);
10844
10845#if OPT_MOD_FKEYS
10846    init_Ires(keyboard.modify_1st.allow_keys);
10847    init_Ires(keyboard.modify_1st.cursor_keys);
10848    init_Ires(keyboard.modify_1st.function_keys);
10849    init_Ires(keyboard.modify_1st.keypad_keys);
10850    init_Ires(keyboard.modify_1st.other_keys);
10851    init_Ires(keyboard.modify_1st.string_keys);
10852    init_Ires(keyboard.format_keys);
10853    wnew->keyboard.modify_now = wnew->keyboard.modify_1st;
10854#endif
10855
10856    init_Ires(misc.appcursorDefault);
10857    if (wnew->misc.appcursorDefault)
10858	wnew->keyboard.flags |= MODE_DECCKM;
10859
10860    init_Ires(misc.appkeypadDefault);
10861    if (wnew->misc.appkeypadDefault)
10862	wnew->keyboard.flags |= MODE_DECKPAM;
10863
10864    initLineData(wnew);
10865#if OPT_WIDE_CHARS
10866    freeFontList(&(request->work.fonts.x11.list_n));
10867#endif
10868#if OPT_XRES_QUERY
10869    if (resource.reportXRes)
10870	reportResources(wnew);
10871#endif
10872    xtermResetLocale(LC_NUMERIC, saveLocale);
10873    TRACE(("" TRACE_R " VTInitialize\n"));
10874    return;
10875}
10876
10877void
10878releaseCursorGCs(XtermWidget xw)
10879{
10880    TScreen *screen = TScreenOf(xw);
10881    VTwin *win = WhichVWin(screen);
10882    int n;
10883
10884    for_each_curs_gc(n) {
10885	freeCgs(xw, win, (CgsEnum) n);
10886    }
10887}
10888
10889void
10890releaseWindowGCs(XtermWidget xw, VTwin *win)
10891{
10892    int n;
10893
10894    for_each_text_gc(n) {
10895	switch (n) {
10896	case gcBorder:
10897	case gcFiller:
10898	    break;
10899	default:
10900	    freeCgs(xw, win, (CgsEnum) n);
10901	    break;
10902	}
10903    }
10904}
10905
10906#define TRACE_FREE_LEAK(name) \
10907	if (name) { \
10908	    TRACE(("freed " #name ": %p\n", (const void *) name)); \
10909	    FreeAndNull(name); \
10910	}
10911
10912#define TRACE_FREE_GC(name,part) \
10913	if (part) { \
10914	    TRACE(("freed %s " #part ": %p\n", name, (const void *) part)); \
10915	    XFreeGC(dpy, part); \
10916	    part = 0; \
10917	}
10918
10919#if OPT_INPUT_METHOD
10920static void
10921cleanupInputMethod(XtermWidget xw)
10922{
10923    TInput *input = lookupTInput(xw, (Widget) xw);
10924
10925    if (input && input->xim) {
10926	XCloseIM(input->xim);
10927	input->xim = 0;
10928	TRACE(("freed screen->xim\n"));
10929    }
10930}
10931#else
10932#define cleanupInputMethod(xw)	/* nothing */
10933#endif
10934
10935#ifdef NO_LEAKS
10936#define FREE_VT_WIN(name) freeVTwin(dpy, #name, &(screen->name))
10937static void
10938freeVTwin(Display *dpy, const char *whichWin, VTwin *win)
10939{
10940    (void) whichWin;
10941    TRACE_FREE_GC(whichWin, win->filler_gc);
10942    TRACE_FREE_GC(whichWin, win->border_gc);
10943    TRACE_FREE_GC(whichWin, win->marker_gc[0]);
10944    TRACE_FREE_GC(whichWin, win->marker_gc[1]);
10945}
10946#endif
10947
10948static void
10949VTDestroy(Widget w GCC_UNUSED)
10950{
10951#ifdef NO_LEAKS
10952    XtermWidget xw = (XtermWidget) w;
10953    TScreen *screen = TScreenOf(xw);
10954    Display *dpy = screen->display;
10955    Cardinal n, k;
10956
10957    StopBlinking(xw);
10958
10959    if (screen->scrollWidget) {
10960	XtUninstallTranslations(screen->scrollWidget);
10961	XtDestroyWidget(screen->scrollWidget);
10962    }
10963
10964    while (screen->saved_fifo > 0) {
10965	deleteScrollback(screen);
10966    }
10967
10968    while (screen->save_title != 0) {
10969	SaveTitle *last = screen->save_title;
10970	screen->save_title = last->next;
10971	free(last->iconName);
10972	free(last->windowName);
10973	free(last);
10974    }
10975#ifndef NO_ACTIVE_ICON
10976    TRACE_FREE_LEAK(xw->misc.active_icon_s);
10977#endif
10978#if OPT_ISO_COLORS
10979    TRACE_FREE_LEAK(screen->cmap_data);
10980    for (n = 0; n < MAXCOLORS; n++) {
10981	TRACE_FREE_LEAK(screen->Acolors[n].resource);
10982    }
10983    for (n = 0; n < MAX_SAVED_SGR; n++) {
10984	TRACE_FREE_LEAK(xw->saved_colors.palettes[n]);
10985    }
10986#endif
10987    for (n = 0; n < NCOLORS; n++) {
10988	switch (n) {
10989#if OPT_TEK4014
10990	case TEK_BG:
10991	    /* FALLTHRU */
10992	case TEK_FG:
10993	    /* FALLTHRU */
10994	case TEK_CURSOR:
10995	    break;
10996#endif
10997	default:
10998	    TRACE_FREE_LEAK(screen->Tcolors[n].resource);
10999	    break;
11000	}
11001    }
11002    FreeMarkGCs(xw);
11003    TRACE_FREE_LEAK(screen->unparse_bfr);
11004    TRACE_FREE_LEAK(screen->save_ptr);
11005    TRACE_FREE_LEAK(screen->saveBuf_data);
11006    TRACE_FREE_LEAK(screen->saveBuf_index);
11007    for (n = 0; n < 2; ++n) {
11008	TRACE_FREE_LEAK(screen->editBuf_data[n]);
11009	TRACE_FREE_LEAK(screen->editBuf_index[n]);
11010    }
11011    TRACE_FREE_LEAK(screen->keyboard_dialect);
11012    TRACE_FREE_LEAK(screen->cursor_font_name);
11013    TRACE_FREE_LEAK(screen->pointer_shape);
11014    TRACE_FREE_LEAK(screen->term_id);
11015#if OPT_WIDE_CHARS
11016    TRACE_FREE_LEAK(screen->utf8_mode_s);
11017    TRACE_FREE_LEAK(screen->utf8_fonts_s);
11018    TRACE_FREE_LEAK(screen->utf8_title_s);
11019#if OPT_LUIT_PROG
11020    TRACE_FREE_LEAK(xw->misc.locale_str);
11021    TRACE_FREE_LEAK(xw->misc.localefilter);
11022#endif
11023#endif
11024    TRACE_FREE_LEAK(xw->misc.T_geometry);
11025    TRACE_FREE_LEAK(xw->misc.geo_metry);
11026#if OPT_INPUT_METHOD
11027    cleanupInputMethod(xw);
11028    TRACE_FREE_LEAK(xw->misc.f_x);
11029    TRACE_FREE_LEAK(xw->misc.input_method);
11030    TRACE_FREE_LEAK(xw->misc.preedit_type);
11031#endif
11032    releaseCursorGCs(xw);
11033    releaseWindowGCs(xw, &(screen->fullVwin));
11034#ifndef NO_ACTIVE_ICON
11035    XFreeFont(screen->display, getIconicFont(screen)->fs);
11036    releaseWindowGCs(xw, &(screen->iconVwin));
11037#endif
11038    XtUninstallTranslations((Widget) xw);
11039#if OPT_TOOLBAR
11040    XtUninstallTranslations((Widget) XtParent(xw));
11041#endif
11042    XtUninstallTranslations((Widget) SHELL_OF(xw));
11043
11044    if (screen->hidden_cursor)
11045	XFreeCursor(screen->display, screen->hidden_cursor);
11046
11047    xtermCloseFonts(xw, screen->fnts);
11048#if OPT_WIDE_ATTRS
11049    xtermCloseFonts(xw, screen->ifnts);
11050#endif
11051    noleaks_cachedCgs(xw);
11052    free_termcap(xw);
11053
11054    FREE_VT_WIN(fullVwin);
11055#ifndef NO_ACTIVE_ICON
11056    FREE_VT_WIN(iconVwin);
11057#endif /* NO_ACTIVE_ICON */
11058
11059    TRACE_FREE_LEAK(screen->selection_targets_8bit);
11060#if OPT_SELECT_REGEX
11061    for (n = 0; n < NSELECTUNITS; ++n) {
11062	if (screen->selectMap[n] == Select_REGEX) {
11063	    TRACE_FREE_LEAK(screen->selectExpr[n]);
11064	}
11065    }
11066#endif
11067
11068#if OPT_RENDERFONT
11069    for (n = 0; n < NMENUFONTS; ++n) {
11070	int e;
11071	for (e = 0; e < fMAX; ++e) {
11072	    xtermCloseXft(screen, getMyXftFont(xw, e, (int) n));
11073	}
11074    }
11075    discardRenderDraw(screen);
11076    {
11077	ListXftFonts *p;
11078	while ((p = screen->list_xft_fonts) != 0) {
11079	    screen->list_xft_fonts = p->next;
11080	    free(p);
11081	}
11082    }
11083#endif
11084
11085    /* free things allocated via init_Sres or Init_Sres2 */
11086#ifndef NO_ACTIVE_ICON
11087    TRACE_FREE_LEAK(screen->icon_fontname);
11088#endif
11089#ifdef ALLOWLOGGING
11090    TRACE_FREE_LEAK(screen->logfile);
11091#endif
11092    TRACE_FREE_LEAK(screen->eight_bit_meta_s);
11093    TRACE_FREE_LEAK(screen->charClass);
11094    TRACE_FREE_LEAK(screen->answer_back);
11095    TRACE_FREE_LEAK(screen->printer_state.printer_command);
11096    TRACE_FREE_LEAK(screen->disallowedColorOps);
11097    TRACE_FREE_LEAK(screen->disallowedFontOps);
11098    TRACE_FREE_LEAK(screen->disallowedMouseOps);
11099    TRACE_FREE_LEAK(screen->disallowedPasteControls);
11100    TRACE_FREE_LEAK(screen->disallowedTcapOps);
11101    TRACE_FREE_LEAK(screen->disallowedWinOps);
11102    TRACE_FREE_LEAK(screen->default_string);
11103    TRACE_FREE_LEAK(screen->eightbit_select_types);
11104
11105#if OPT_WIDE_CHARS
11106    TRACE_FREE_LEAK(screen->utf8_select_types);
11107#endif
11108
11109#if 0
11110    for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; n++) {
11111	TRACE_FREE_LEAK(screen->MenuFontName(n));
11112    }
11113#endif
11114
11115    TRACE_FREE_LEAK(screen->initial_font);
11116
11117#if OPT_LUIT_PROG
11118    TRACE_FREE_LEAK(xw->misc.locale_str);
11119    TRACE_FREE_LEAK(xw->misc.localefilter);
11120#endif
11121
11122#if OPT_RENDERFONT
11123    TRACE_FREE_LEAK(xw->misc.default_xft.f_n);
11124#if OPT_WIDE_CHARS
11125    TRACE_FREE_LEAK(xw->misc.default_xft.f_w);
11126#endif
11127    TRACE_FREE_LEAK(xw->misc.render_font_s);
11128#endif
11129
11130    TRACE_FREE_LEAK(xw->misc.default_font.f_n);
11131    TRACE_FREE_LEAK(xw->misc.default_font.f_b);
11132
11133#if OPT_WIDE_CHARS
11134    TRACE_FREE_LEAK(xw->misc.default_font.f_w);
11135    TRACE_FREE_LEAK(xw->misc.default_font.f_wb);
11136#endif
11137
11138    TRACE_FREE_LEAK(xw->work.wm_name);
11139    freeFontLists(&(xw->work.fonts.x11));
11140#if OPT_RENDERFONT
11141    freeFontLists(&(xw->work.fonts.xft));
11142#endif
11143
11144    xtermFontName(NULL);
11145#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS
11146    TRACE_FREE_LEAK(screen->cacheVTFonts.default_font.f_n);
11147    TRACE_FREE_LEAK(screen->cacheVTFonts.default_font.f_b);
11148#if OPT_WIDE_CHARS
11149    TRACE_FREE_LEAK(screen->cacheVTFonts.default_font.f_w);
11150    TRACE_FREE_LEAK(screen->cacheVTFonts.default_font.f_wb);
11151#endif
11152    freeFontLists(&(screen->cacheVTFonts.fonts.x11));
11153    for (n = 0; n < NMENUFONTS; ++n) {
11154	for (k = 0; k < fMAX; ++k) {
11155	    if (screen->menu_font_names[n][k] !=
11156		screen->cacheVTFonts.menu_font_names[n][k]) {
11157		if (screen->menu_font_names[n][k] != _Font_Selected_) {
11158		    TRACE_FREE_LEAK(screen->menu_font_names[n][k]);
11159		}
11160		TRACE_FREE_LEAK(screen->cacheVTFonts.menu_font_names[n][k]);
11161	    } else {
11162		TRACE_FREE_LEAK(screen->menu_font_names[n][k]);
11163	    }
11164	}
11165    }
11166#endif
11167
11168#if OPT_BLINK_CURS
11169    TRACE_FREE_LEAK(screen->cursor_blink_s);
11170#endif
11171
11172#if OPT_REGIS_GRAPHICS
11173    TRACE_FREE_LEAK(screen->graphics_regis_default_font);
11174    TRACE_FREE_LEAK(screen->graphics_regis_screensize);
11175#endif
11176#if OPT_GRAPHICS
11177    TRACE_FREE_LEAK(screen->graph_termid);
11178    TRACE_FREE_LEAK(screen->graphics_max_size);
11179#endif
11180
11181    for (n = 0; n < NSELECTUNITS; ++n) {
11182#if OPT_SELECT_REGEX
11183	TRACE_FREE_LEAK(screen->selectExpr[n]);
11184#endif
11185#if OPT_XRES_QUERY
11186	TRACE_FREE_LEAK(screen->onClick[n]);
11187#endif
11188    }
11189
11190    XtFree((void *) (screen->selection_atoms));
11191
11192    for (n = 0; n < MAX_SELECTIONS; ++n) {
11193	free(screen->selected_cells[n].data_buffer);
11194    }
11195
11196    if (defaultTranslations != xtermClassRec.core_class.tm_table) {
11197	TRACE_FREE_LEAK(defaultTranslations);
11198    }
11199    TRACE_FREE_LEAK(xtermClassRec.core_class.tm_table);
11200    TRACE_FREE_LEAK(xw->keyboard.shift_escape_s);
11201    TRACE_FREE_LEAK(xw->keyboard.extra_translations);
11202    TRACE_FREE_LEAK(xw->keyboard.shell_translations);
11203    TRACE_FREE_LEAK(xw->keyboard.xterm_translations);
11204    TRACE_FREE_LEAK(xw->keyboard.print_translations);
11205    UnmapSelections(xw);
11206
11207    XtFree((void *) (xw->visInfo));
11208
11209#if OPT_WIDE_CHARS
11210    FreeTypedBuffer(XChar2b);
11211    FreeTypedBuffer(char);
11212#endif
11213#if OPT_RENDERFONT
11214#if OPT_RENDERWIDE
11215    FreeTypedBuffer(XftCharSpec);
11216#else
11217    FreeTypedBuffer(XftChar8);
11218#endif
11219#endif
11220
11221    TRACE_FREE_LEAK(myState.print_area);
11222    TRACE_FREE_LEAK(myState.string_area);
11223    memset(&myState, 0, sizeof(myState));
11224
11225#endif /* defined(NO_LEAKS) */
11226}
11227
11228#ifndef NO_ACTIVE_ICON
11229static void *
11230getProperty(Display *dpy,
11231	    Window w,
11232	    Atom req_type,
11233	    const char *prop_name)
11234{
11235    Atom property;
11236    Atom actual_return_type;
11237    int actual_format_return = 0;
11238    unsigned long nitems_return = 0;
11239    unsigned long bytes_after_return = 0;
11240    unsigned char *prop_return = 0;
11241    long long_length = 1024;
11242    size_t limit;
11243    char *result = 0;
11244
11245    TRACE(("getProperty %s(%s)\n", prop_name,
11246	   req_type ? TraceAtomName(dpy, req_type) : "?"));
11247    property = XInternAtom(dpy, prop_name, False);
11248
11249    if (!xtermGetWinProp(dpy,
11250			 w,
11251			 property,
11252			 0L,
11253			 long_length,
11254			 req_type,
11255			 &actual_return_type,
11256			 &actual_format_return,
11257			 &nitems_return,
11258			 &bytes_after_return,
11259			 &prop_return)) {
11260	TRACE((".. Cannot get %s property.\n", prop_name));
11261    } else if (prop_return != 0) {
11262
11263	if (nitems_return != 0 &&
11264	    actual_format_return != 0 &&
11265	    actual_return_type == req_type) {
11266	    /*
11267	     * Null-terminate the result to make string handling easier.
11268	     * The format==8 corresponds to strings, and the number of items
11269	     * is the number of characters.
11270	     */
11271	    if (actual_format_return == 8) {
11272		limit = nitems_return;
11273	    } else {
11274		/* manpage is misleading - X really uses 'long', not 32-bits */
11275		limit = sizeof(long) * nitems_return;
11276	    }
11277	    if ((result = malloc(limit + 1)) != 0) {
11278		memcpy(result, prop_return, limit);
11279		result[limit] = '\0';
11280	    }
11281	    TRACE(("... result %s\n", result ? ("ok") : "null"));
11282	}
11283	XFree(prop_return);
11284    } else {
11285	TRACE((".. no property returned\n"));
11286    }
11287    return (void *) result;
11288}
11289
11290/*
11291 * Active icons are supported by fvwm.  This feature is not supported by
11292 * metacity (gnome) or kwin (kde).  Both metacity and kwin support (in
11293 * incompatible ways, e.g., one uses the icon theme as a fallback for window
11294 * decorations but the other does not, etc, ...) an icon as part of the window
11295 * decoration (usually on the upper-left of the window).
11296 *
11297 * In either case, xterm's icon will only be shown in the window decorations if
11298 * xterm does not use the active icon feature.
11299 *
11300 * This function (tries to) determine the window manager's name, so that we can
11301 * provide a useful automatic default for active icons.  It is based on reading
11302 * wmctrl, which covers most of EWMH and ICCM.
11303 */
11304static char *
11305getWindowManagerName(XtermWidget xw)
11306{
11307    TScreen *screen = TScreenOf(xw);
11308    Display *dpy = screen->display;
11309    Window *sup_window = NULL;
11310    char *result = 0;
11311
11312    TRACE(("getWindowManagerName\n"));
11313#define getWinProp(type, name) \
11314    (Window *)getProperty(dpy, DefaultRootWindow(dpy), type, name)
11315    if ((sup_window = getWinProp(XA_WINDOW, "_NET_SUPPORTING_WM_CHECK")) == 0) {
11316	sup_window = getWinProp(XA_CARDINAL, "_WIN_SUPPORTING_WM_CHECK");
11317    }
11318
11319    /*
11320     * If we found the supporting window, get the property containing the
11321     * window manager's name.  EWMH defines _NET_WM_NAME, while ICCM defines
11322     * WM_CLASS.  There is no standard for the names stored there;
11323     * conventionally it is mixed case.  In practice, the former is more often
11324     * set; the latter is not given (or is a lowercased version of the former).
11325     */
11326    if (sup_window != 0) {
11327#define getStringProp(type,name) \
11328	(char *)getProperty(dpy, *sup_window, type, name)
11329	if ((result = getStringProp(XA_UTF8_STRING(dpy), "_NET_WM_NAME")) == 0
11330	    && (result = getStringProp(XA_STRING, "_NET_WM_NAME")) == 0
11331	    && (result = getStringProp(XA_STRING, "WM_CLASS")) == 0) {
11332	    TRACE(("... window manager does not tell its name\n"));
11333	}
11334	free(sup_window);
11335    } else {
11336	TRACE(("... Cannot get window manager info properties\n"));
11337    }
11338    if (result == 0)
11339	result = x_strdup("unknown");
11340    TRACE(("... window manager name is %s\n", result));
11341    return result;
11342}
11343
11344static Boolean
11345discount_frame_extents(XtermWidget xw, int *high, int *wide)
11346{
11347    TScreen *screen = TScreenOf(xw);
11348    Display *dpy = screen->display;
11349
11350    Atom atom_supported = XInternAtom(dpy, "_NET_FRAME_EXTENTS", False);
11351    Atom actual_type;
11352    int actual_format;
11353    long long_offset = 0;
11354    long long_length = 128;	/* number of items to ask for at a time */
11355    unsigned long nitems;
11356    unsigned long bytes_after;
11357    unsigned char *args;
11358    Boolean rc;
11359
11360    rc = xtermGetWinProp(dpy,
11361			 VShellWindow(xw),
11362			 atom_supported,
11363			 long_offset,
11364			 long_length,
11365			 XA_CARDINAL,	/* req_type */
11366			 &actual_type,	/* actual_type_return */
11367			 &actual_format,	/* actual_format_return */
11368			 &nitems,	/* nitems_return */
11369			 &bytes_after,	/* bytes_after_return */
11370			 &args	/* prop_return */
11371	);
11372
11373    if (rc && args && (nitems == 4) && (actual_format == 32)) {
11374	long *extents = (long *) (void *) args;
11375
11376	TRACE(("_NET_FRAME_EXTENTS:\n"));
11377	TRACE(("   left:   %ld\n", extents[0]));
11378	TRACE(("   right:  %ld\n", extents[1]));
11379	TRACE(("   top:    %ld\n", extents[2]));
11380	TRACE(("   bottom: %ld\n", extents[3]));
11381
11382	if (!x_strncasecmp(xw->work.wm_name, "gnome shell", 11)) {
11383	    *wide -= (int) (extents[0] + extents[1]);	/* -= (left+right) */
11384	    *high -= (int) (extents[2] + extents[3]);	/* -= (top+bottom) */
11385	    TRACE(("...applied extents %d,%d\n", *high, *wide));
11386	} else if (!x_strncasecmp(xw->work.wm_name, "compiz", 6)) {
11387	    /* Ubuntu 16.04 is really off-by-one */
11388	    *wide -= (int) (extents[0] + extents[1] - 1);
11389	    *high -= (int) (extents[2] + extents[3] - 1);
11390	    TRACE(("...applied extents %d,%d\n", *high, *wide));
11391	} else if (!x_strncasecmp(xw->work.wm_name, "fvwm", 4)) {
11392	    TRACE(("...skipping extents\n"));
11393	} else {
11394	    TRACE(("...ignoring extents\n"));
11395	    rc = False;
11396	}
11397	XFree(args);
11398    } else {
11399	rc = False;
11400    }
11401    return rc;
11402}
11403#endif /* !NO_ACTIVE_ICON */
11404
11405void
11406initBorderGC(XtermWidget xw, VTwin *win)
11407{
11408    TScreen *screen = TScreenOf(xw);
11409    Pixel filler;
11410
11411    TRACE(("initBorderGC(%s) core bg %#lx, bd %#lx text fg %#lx, bg %#lx %s\n",
11412	   (win == &(screen->fullVwin)) ? "full" : "icon",
11413	   xw->core.background_pixel,
11414	   xw->core.border_pixel,
11415	   T_COLOR(screen, TEXT_FG),
11416	   T_COLOR(screen, TEXT_BG),
11417	   xw->misc.re_verse ? "reverse" : "normal"));
11418    if (xw->misc.color_inner_border
11419	&& (xw->core.background_pixel != xw->core.border_pixel)) {
11420	/*
11421	 * By default, try to match the inner window's background.
11422	 */
11423	if ((xw->core.background_pixel == T_COLOR(screen, TEXT_BG)) &&
11424	    (xw->core.border_pixel == T_COLOR(screen, TEXT_FG))) {
11425	    filler = T_COLOR(screen, TEXT_BG);
11426	} else {
11427	    filler = xw->core.border_pixel;
11428	}
11429	TRACE((" border %#lx\n", filler));
11430	setCgsFore(xw, win, gcBorder, filler);
11431	setCgsBack(xw, win, gcBorder, filler);
11432	win->border_gc = getCgsGC(xw, win, gcBorder);
11433    }
11434#if USE_DOUBLE_BUFFER
11435    else if (resource.buffered) {
11436	filler = T_COLOR(screen, TEXT_BG);
11437	TRACE((" border %#lx (buffered)\n", filler));
11438	setCgsFore(xw, win, gcBorder, filler);
11439	setCgsBack(xw, win, gcBorder, filler);
11440	win->border_gc = getCgsGC(xw, win, gcBorder);
11441    }
11442#endif
11443    else {
11444	TRACE((" border unused\n"));
11445	win->border_gc = 0;
11446    }
11447
11448    /*
11449     * Initialize a GC for double-buffering, needed for XFillRectangle call
11450     * in xtermClear2().  When not double-buffering, the XClearArea call works,
11451     * without requiring a separate GC.
11452     */
11453#if USE_DOUBLE_BUFFER
11454    if (resource.buffered) {
11455	filler = (((xw->flags & BG_COLOR) && (xw->cur_background >= 0))
11456		  ? getXtermBG(xw, xw->flags, xw->cur_background)
11457		  : T_COLOR(screen, TEXT_BG));
11458
11459	TRACE((" filler %#lx %s\n",
11460	       filler,
11461	       xw->misc.re_verse ? "reverse" : "normal"));
11462
11463	setCgsFore(xw, win, gcFiller, filler);
11464	setCgsBack(xw, win, gcFiller, filler);
11465
11466	win->filler_gc = getCgsGC(xw, win, gcFiller);
11467    }
11468#endif
11469}
11470#if USE_DOUBLE_BUFFER
11471static Boolean
11472allocateDbe(XtermWidget xw, VTwin *target)
11473{
11474    TScreen *screen = TScreenOf(xw);
11475    Boolean result = False;
11476
11477    target->drawable = target->window;
11478
11479    if (resource.buffered) {
11480	Window win = target->window;
11481	Drawable d;
11482	int major, minor;
11483	if (XdbeQueryExtension(XtDisplay(xw), &major, &minor)) {
11484	    d = XdbeAllocateBackBufferName(XtDisplay(xw), win,
11485					   (XdbeSwapAction) XdbeCopied);
11486	    if (d == None) {
11487		fprintf(stderr, "Couldn't allocate a back buffer!\n");
11488		exit(3);
11489	    }
11490	    target->drawable = d;
11491	    screen->needSwap = 1;
11492	    TRACE(("initialized double-buffering\n"));
11493	    result = True;
11494	} else {
11495	    resource.buffered = False;
11496	}
11497    }
11498    return result;
11499}
11500#endif /* USE_DOUBLE_BUFFER */
11501
11502/*ARGSUSED*/
11503static void
11504VTRealize(Widget w,
11505	  XtValueMask * valuemask,
11506	  XSetWindowAttributes * values)
11507{
11508    XtermWidget xw = (XtermWidget) w;
11509    TScreen *screen = TScreenOf(xw);
11510
11511    const VTFontNames *myfont;
11512    struct Xinerama_geometry pos;
11513    int pr;
11514    Atom pid_atom;
11515    int i;
11516
11517    TRACE(("VTRealize " TRACE_L "\n"));
11518
11519    TabReset(xw->tabs);
11520
11521    if (screen->menu_font_number == fontMenu_default) {
11522	myfont = defaultVTFontNames(xw);
11523    } else {
11524	myfont = xtermFontName(screen->MenuFontName(screen->menu_font_number));
11525    }
11526    memset(screen->fnts, 0, sizeof(screen->fnts));
11527
11528    if (!xtermLoadFont(xw,
11529		       myfont,
11530		       False,
11531		       screen->menu_font_number)) {
11532	if (XmuCompareISOLatin1(myfont->f_n, DEFFONT) != 0) {
11533	    char *use_font = x_strdup(DEFFONT);
11534	    xtermWarning("unable to open font \"%s\", trying \"%s\"....\n",
11535			 myfont->f_n, use_font);
11536	    (void) xtermLoadFont(xw,
11537				 xtermFontName(use_font),
11538				 False,
11539				 screen->menu_font_number);
11540	    screen->MenuFontName(screen->menu_font_number) = use_font;
11541	}
11542    }
11543
11544    /* really screwed if we couldn't open default font */
11545    if (!GetNormalFont(screen, fNorm)->fs) {
11546	xtermWarning("unable to locate a suitable font\n");
11547	Exit(1);
11548    }
11549#if OPT_WIDE_CHARS
11550    if (screen->utf8_mode) {
11551	TRACE(("check if this is a wide font, if not try again\n"));
11552	if (xtermLoadWideFonts(xw, False)) {
11553	    SetVTFont(xw, screen->menu_font_number, True, NULL);
11554	    /* we will not be able to switch to ISO-8859-1 */
11555	    if (!screen->mergedVTFonts) {
11556		screen->utf8_fonts = uAlways;
11557		update_font_utf8_fonts();
11558	    }
11559	}
11560    }
11561#endif
11562
11563    xtermSetupPointer(xw, screen->pointer_shape);
11564
11565    /* set defaults */
11566    pos.x = 1;
11567    pos.y = 1;
11568    pos.w = 80;
11569    pos.h = 24;
11570
11571    TRACE(("parsing geo_metry %s\n", NonNull(xw->misc.geo_metry)));
11572    pr = XParseXineramaGeometry(screen->display, xw->misc.geo_metry, &pos);
11573    TRACE(("... position %d,%d size %dx%d\n", pos.y, pos.x, pos.h, pos.w));
11574
11575    set_max_col(screen, (int) (pos.w - 1));	/* units in character cells */
11576    set_max_row(screen, (int) (pos.h - 1));	/* units in character cells */
11577    xtermUpdateFontInfo(xw, False);
11578
11579    pos.w = screen->fullVwin.fullwidth;
11580    pos.h = screen->fullVwin.fullheight;
11581
11582    TRACE(("... BorderWidth: widget %d parent %d shell %d\n",
11583	   BorderWidth(xw),
11584	   BorderWidth(XtParent(xw)),
11585	   BorderWidth(SHELL_OF(xw))));
11586
11587    if ((pr & XValue) && (XNegative & pr)) {
11588	pos.x = (Position) (pos.x + (pos.scr_w
11589				     - (int) pos.w
11590				     - (BorderWidth(XtParent(xw)) * 2)));
11591    }
11592    if ((pr & YValue) && (YNegative & pr)) {
11593	pos.y = (Position) (pos.y + (pos.scr_h
11594				     - (int) pos.h
11595				     - (BorderWidth(XtParent(xw)) * 2)));
11596    }
11597    pos.x = (Position) (pos.x + pos.scr_x);
11598    pos.y = (Position) (pos.y + pos.scr_y);
11599
11600    /* set up size hints for window manager; min 1 char by 1 char */
11601    getXtermSizeHints(xw);
11602    xtermSizeHints(xw, (xw->misc.scrollbar
11603			? (screen->scrollWidget->core.width
11604			   + BorderWidth(screen->scrollWidget))
11605			: 0));
11606
11607    xw->hints.x = pos.x;
11608    xw->hints.y = pos.y;
11609#if OPT_MAXIMIZE
11610    /* assure single-increment resize for fullscreen */
11611    if (xw->work.ewmh[0].mode) {
11612	xw->hints.width_inc = 1;
11613	xw->hints.height_inc = 1;
11614    }
11615#endif
11616    if ((XValue & pr) || (YValue & pr)) {
11617	xw->hints.flags |= USSize | USPosition;
11618	xw->hints.flags |= PWinGravity;
11619	switch (pr & (XNegative | YNegative)) {
11620	case 0:
11621	    xw->hints.win_gravity = NorthWestGravity;
11622	    break;
11623	case XNegative:
11624	    xw->hints.win_gravity = NorthEastGravity;
11625	    break;
11626	case YNegative:
11627	    xw->hints.win_gravity = SouthWestGravity;
11628	    break;
11629	default:
11630	    xw->hints.win_gravity = SouthEastGravity;
11631	    break;
11632	}
11633    } else {
11634	/* set a default size, but do *not* set position */
11635	xw->hints.flags |= PSize;
11636    }
11637    xw->hints.height = xw->hints.base_height
11638	+ xw->hints.height_inc * MaxRows(screen);
11639    xw->hints.width = xw->hints.base_width
11640	+ xw->hints.width_inc * MaxCols(screen);
11641
11642    if ((WidthValue & pr) || (HeightValue & pr))
11643	xw->hints.flags |= USSize;
11644    else
11645	xw->hints.flags |= PSize;
11646
11647    /*
11648     * Note that the size-hints are for the shell, while the resize-request
11649     * is for the vt100 widget.  They are not the same size.
11650     */
11651    (void) REQ_RESIZE((Widget) xw,
11652		      (Dimension) pos.w, (Dimension) pos.h,
11653		      &xw->core.width, &xw->core.height);
11654
11655    /* XXX This is bogus.  We are parsing geometries too late.  This
11656     * is information that the shell widget ought to have before we get
11657     * realized, so that it can do the right thing.
11658     */
11659    if (xw->hints.flags & USPosition)
11660	XMoveWindow(XtDisplay(xw), VShellWindow(xw),
11661		    xw->hints.x, xw->hints.y);
11662
11663    TRACE(("%s@%d -- ", __FILE__, __LINE__));
11664    TRACE_HINTS(&xw->hints);
11665    XSetWMNormalHints(XtDisplay(xw), VShellWindow(xw), &xw->hints);
11666    TRACE(("%s@%d -- ", __FILE__, __LINE__));
11667    TRACE_WM_HINTS(xw);
11668
11669    if ((pid_atom = XInternAtom(XtDisplay(xw), "_NET_WM_PID", False)) != None) {
11670	/* XChangeProperty format 32 really is "long" */
11671	unsigned long pid_l = (unsigned long) getpid();
11672	TRACE(("Setting _NET_WM_PID property to %lu\n", pid_l));
11673	XChangeProperty(XtDisplay(xw), VShellWindow(xw),
11674			pid_atom, XA_CARDINAL, 32, PropModeReplace,
11675			(unsigned char *) &pid_l, 1);
11676    }
11677
11678    XFlush(XtDisplay(xw));	/* get it out to window manager */
11679
11680    /* use ForgetGravity instead of SouthWestGravity because translating
11681       the Expose events for ConfigureNotifys is too hard */
11682    values->bit_gravity = (GravityIsNorthWest(xw)
11683			   ? NorthWestGravity
11684			   : ForgetGravity);
11685    screen->fullVwin.window = XtWindow(xw) =
11686	XCreateWindow(XtDisplay(xw), XtWindow(XtParent(xw)),
11687		      xw->core.x, xw->core.y,
11688		      xw->core.width, xw->core.height, BorderWidth(xw),
11689		      (int) xw->core.depth,
11690		      InputOutput, CopyFromParent,
11691		      *valuemask | CWBitGravity, values);
11692#if USE_DOUBLE_BUFFER
11693    if (allocateDbe(xw, &(screen->fullVwin))) {
11694	screen->needSwap = 1;
11695	TRACE(("initialized full double-buffering\n"));
11696    } else {
11697	resource.buffered = False;
11698	screen->fullVwin.drawable = screen->fullVwin.window;
11699    }
11700#endif /* USE_DOUBLE_BUFFER */
11701    screen->event_mask = values->event_mask;
11702
11703#ifndef NO_ACTIVE_ICON
11704    /*
11705     * Normally, the font-number for icon fonts does not correspond with any of
11706     * the menu-selectable fonts.  If we cannot load the font given for the
11707     * iconFont resource, try with font1 aka "Unreadable".
11708     */
11709    screen->icon_fontnum = -1;
11710    if (getIconicFont(screen)->fs == 0) {
11711	getIconicFont(screen)->fs =
11712	    xtermLoadQueryFont(xw, screen->MenuFontName(fontMenu_font1));
11713	ReportIcons(("%susing font1 '%s' as iconFont\n",
11714		     (getIconicFont(screen)->fs
11715		      ? ""
11716		      : "NOT "),
11717		     screen->MenuFontName(fontMenu_font1)));
11718    }
11719#if OPT_RENDERFONT
11720    /*
11721     * If we still have no result from iconFont resource (perhaps because fonts
11722     * are missing) but are using Xft, try to use that instead.  We prefer
11723     * bitmap fonts in any case, since scaled fonts are usually less readable,
11724     * particularly at small sizes.
11725     */
11726    if (UsingRenderFont(xw)
11727	&& getIconicFont(screen)->fs == 0) {
11728	screen->icon_fontnum = fontMenu_default;
11729	getIconicFont(screen)->fs = GetNormalFont(screen, fNorm)->fs;	/* need for next-if */
11730	ReportIcons(("using TrueType font as iconFont\n"));
11731    }
11732#endif
11733    xw->work.wm_name = getWindowManagerName(xw);
11734    if ((xw->work.active_icon == eiDefault) && getIconicFont(screen)->fs) {
11735	ReportIcons(("window manager name is %s\n", xw->work.wm_name));
11736	if (x_strncasecmp(xw->work.wm_name, "fvwm", 4) &&
11737	    x_strncasecmp(xw->work.wm_name, "window maker", 12)) {
11738	    xw->work.active_icon = eiFalse;
11739	    TRACE(("... disable active_icon\n"));
11740	}
11741    }
11742    TRACE((".. if active_icon (%d), get its font\n", xw->work.active_icon));
11743    if (xw->work.active_icon && getIconicFont(screen)->fs) {
11744	int iconX = 0, iconY = 0;
11745	Widget shell = SHELL_OF(xw);
11746	VTwin *win = &(screen->iconVwin);
11747	int save_fontnum = screen->menu_font_number;
11748
11749	ReportIcons(("initializing active-icon %d\n", screen->icon_fontnum));
11750	screen->menu_font_number = screen->icon_fontnum;
11751	XtVaGetValues(shell,
11752		      XtNiconX, &iconX,
11753		      XtNiconY, &iconY,
11754		      (XtPointer) 0);
11755	xtermComputeFontInfo(xw, &(screen->iconVwin),
11756			     getIconicFont(screen)->fs, 0);
11757	screen->menu_font_number = save_fontnum;
11758
11759	/* since only one client is permitted to select for Button
11760	 * events, we have to let the window manager get 'em...
11761	 */
11762	values->event_mask &= ~(ButtonPressMask | ButtonReleaseMask);
11763	values->border_pixel = xw->misc.icon_border_pixel;
11764
11765	screen->iconVwin.window =
11766	    XCreateWindow(XtDisplay(xw),
11767			  RootWindowOfScreen(XtScreen(shell)),
11768			  iconX, iconY,
11769			  screen->iconVwin.fullwidth,
11770			  screen->iconVwin.fullheight,
11771			  xw->misc.icon_border_width,
11772			  (int) xw->core.depth,
11773			  InputOutput, CopyFromParent,
11774			  *valuemask | CWBitGravity | CWBorderPixel,
11775			  values);
11776#if USE_DOUBLE_BUFFER
11777	if (allocateDbe(xw, &(screen->iconVwin))) {
11778	    TRACE(("initialized icon double-buffering\n"));
11779	} else {
11780	    resource.buffered = False;
11781	    screen->iconVwin.drawable = screen->iconVwin.window;
11782	    screen->fullVwin.drawable = screen->fullVwin.window;
11783	}
11784#endif /* USE_DOUBLE_BUFFER */
11785	XtVaSetValues(shell,
11786		      XtNiconWindow, screen->iconVwin.window,
11787		      (XtPointer) 0);
11788	XtRegisterDrawable(XtDisplay(xw), screen->iconVwin.window, w);
11789
11790	setCgsFont(xw, win, gcNorm, getIconicFont(screen));
11791	setCgsFore(xw, win, gcNorm, T_COLOR(screen, TEXT_FG));
11792	setCgsBack(xw, win, gcNorm, T_COLOR(screen, TEXT_BG));
11793
11794	copyCgs(xw, win, gcBold, gcNorm);
11795
11796	setCgsFont(xw, win, gcNormReverse, getIconicFont(screen));
11797	setCgsFore(xw, win, gcNormReverse, T_COLOR(screen, TEXT_BG));
11798	setCgsBack(xw, win, gcNormReverse, T_COLOR(screen, TEXT_FG));
11799
11800	copyCgs(xw, win, gcBoldReverse, gcNormReverse);
11801
11802	initBorderGC(xw, win);
11803
11804#if OPT_TOOLBAR
11805	/*
11806	 * Toolbar is initialized before we get here.  Enable the menu item
11807	 * and set it properly.
11808	 */
11809	SetItemSensitivity(vtMenuEntries[vtMenu_activeicon].widget, True);
11810	update_activeicon();
11811#endif
11812    } else {
11813	ReportIcons(("disabled active-icon\n"));
11814	xw->work.active_icon = eiFalse;
11815    }
11816#endif /* NO_ACTIVE_ICON */
11817
11818#if OPT_INPUT_METHOD
11819    VTInitI18N(xw);
11820#endif
11821#if OPT_NUM_LOCK
11822    VTInitModifiers(xw);
11823#if OPT_EXTRA_PASTE
11824    if (xw->keyboard.extra_translations) {
11825	XtOverrideTranslations((Widget) xw,
11826			       XtParseTranslationTable(xw->keyboard.extra_translations));
11827    }
11828#endif
11829#endif
11830
11831    set_cursor_gcs(xw);
11832    initBorderGC(xw, &(screen->fullVwin));
11833
11834    /* Reset variables used by ANSI emulation. */
11835
11836    resetCharsets(screen);
11837
11838    XDefineCursor(screen->display, VShellWindow(xw), screen->pointer_cursor);
11839
11840    set_cur_col(screen, 0);
11841    set_cur_row(screen, 0);
11842    set_max_col(screen, Width(screen) / screen->fullVwin.f_width - 1);
11843    set_max_row(screen, Height(screen) / screen->fullVwin.f_height - 1);
11844    resetMarginMode(xw);
11845
11846    memset(screen->sc, 0, sizeof(screen->sc));
11847
11848    /* Mark screen buffer as unallocated.  We wait until the run loop so
11849       that the child process does not fork and exec with all the dynamic
11850       memory it will never use.  If we were to do it here, the
11851       swap space for new process would be huge for huge savelines. */
11852#if OPT_TEK4014
11853    if (!tekWidget)		/* if not called after fork */
11854#endif
11855    {
11856	screen->visbuf = NULL;
11857	screen->saveBuf_index = NULL;
11858    }
11859
11860    ResetWrap(screen);
11861    screen->scrolls = screen->incopy = 0;
11862    xtermSetCursorBox(screen);
11863
11864    screen->savedlines = 0;
11865
11866    for (i = 0; i < 2; ++i) {
11867	screen->whichBuf = !screen->whichBuf;
11868	CursorSave(xw);
11869    }
11870
11871#ifndef NO_ACTIVE_ICON
11872    if (!xw->work.active_icon)
11873#endif
11874	xtermLoadIcon(xw, resource.icon_hint);
11875
11876    /*
11877     * Do this last, since it may change the layout via a resize.
11878     */
11879    if (xw->misc.scrollbar) {
11880	screen->fullVwin.sb_info.width = 0;
11881	ScrollBarOn(xw, False);
11882    }
11883
11884    xtermSetWinSize(xw);
11885    TRACE(("" TRACE_R " VTRealize\n"));
11886}
11887
11888#if OPT_INPUT_METHOD
11889
11890/* limit this feature to recent XFree86 since X11R6.x core dumps */
11891#if defined(XtSpecificationRelease) && XtSpecificationRelease >= 6 && defined(X_HAVE_UTF8_STRING)
11892#define USE_XIM_INSTANTIATE_CB
11893
11894static void
11895xim_instantiate_cb(Display *display,
11896		   XPointer client_data GCC_UNUSED,
11897		   XPointer call_data GCC_UNUSED)
11898{
11899    XtermWidget xw = term;
11900
11901    TRACE(("xim_instantiate_cb client=%p, call=%p\n", client_data, call_data));
11902
11903    if (display == XtDisplay(xw)) {
11904	VTInitI18N(xw);
11905    }
11906}
11907
11908static void
11909xim_destroy_cb(XIM im GCC_UNUSED,
11910	       XPointer client_data GCC_UNUSED,
11911	       XPointer call_data GCC_UNUSED)
11912{
11913    XtermWidget xw = term;
11914    TInput *input = lookupTInput(xw, (Widget) xw);
11915
11916    TRACE(("xim_destroy_cb im=%lx, client=%p, call=%p\n",
11917	   (long) im, client_data, call_data));
11918    if (input)
11919	input->xic = NULL;
11920    XRegisterIMInstantiateCallback(XtDisplay(xw), NULL, NULL, NULL,
11921				   xim_instantiate_cb, NULL);
11922}
11923#endif /* X11R6+ */
11924
11925static Boolean
11926xim_create_fs(XtermWidget xw)
11927{
11928    XFontStruct **fonts;
11929    char **font_name_list;
11930    char **missing_charset_list;
11931    char *def_string;
11932    int missing_charset_count;
11933    unsigned i, j;
11934
11935    if (xw->work.xim_fs == 0) {
11936	xw->work.xim_fs = XCreateFontSet(XtDisplay(xw),
11937					 xw->misc.f_x,
11938					 &missing_charset_list,
11939					 &missing_charset_count,
11940					 &def_string);
11941	if (xw->work.xim_fs == NULL) {
11942	    xtermWarning("Preparation of font set "
11943			 "\"%s\" for XIM failed.\n", xw->misc.f_x);
11944	    xw->work.xim_fs = XCreateFontSet(XtDisplay(xw),
11945					     DEFXIMFONT,
11946					     &missing_charset_list,
11947					     &missing_charset_count,
11948					     &def_string);
11949	}
11950    }
11951    if (xw->work.xim_fs == NULL) {
11952	xtermWarning("Preparation of default font set "
11953		     "\"%s\" for XIM failed.\n", DEFXIMFONT);
11954	cleanupInputMethod(xw);
11955	xw->work.cannot_im = True;
11956    } else {
11957	(void) XExtentsOfFontSet(xw->work.xim_fs);
11958	j = (unsigned) XFontsOfFontSet(xw->work.xim_fs, &fonts, &font_name_list);
11959	for (i = 0, xw->work.xim_fs_ascent = 0; i < j; i++) {
11960	    if (xw->work.xim_fs_ascent < (*fonts)->ascent)
11961		xw->work.xim_fs_ascent = (*fonts)->ascent;
11962	}
11963    }
11964    return (Boolean) !(xw->work.cannot_im);
11965}
11966
11967static void
11968xim_create_xic(XtermWidget xw, Widget theInput)
11969{
11970    Display *myDisplay = XtDisplay(theInput);
11971    Window myWindow = XtWindow(theInput);
11972    unsigned i, j;
11973    char *p = NULL, *s, *t, *ns, *end, buf[32];
11974    XIMStyles *xim_styles;
11975    XIMStyle input_style = 0;
11976    Bool found;
11977    static struct {
11978	const char *name;
11979	unsigned long code;
11980    } known_style[] = {
11981	{
11982	    "OverTheSpot", (XIMPreeditPosition | XIMStatusNothing)
11983	},
11984	{
11985	    "OffTheSpot", (XIMPreeditArea | XIMStatusArea)
11986	},
11987	{
11988	    "Root", (XIMPreeditNothing | XIMStatusNothing)
11989	},
11990    };
11991    TInput *input = lookupTInput(xw, theInput);
11992
11993    if (xw->work.cannot_im) {
11994	return;
11995    }
11996
11997    if (input == 0) {
11998	for (i = 0; i < NINPUTWIDGETS; ++i) {
11999	    if (xw->work.inputs[i].w == 0) {
12000		input = xw->work.inputs + i;
12001		input->w = theInput;
12002		break;
12003	    }
12004	}
12005    }
12006
12007    if (input == 0) {
12008	xtermWarning("attempted to add too many input widgets\n");
12009	return;
12010    }
12011
12012    TRACE(("xim_real_init\n"));
12013
12014    if (IsEmpty(xw->misc.input_method)) {
12015	if ((p = XSetLocaleModifiers("")) != NULL && *p) {
12016	    input->xim = XOpenIM(myDisplay, NULL, NULL, NULL);
12017	}
12018    } else {
12019	s = xw->misc.input_method;
12020	i = 5 + (unsigned) strlen(s);
12021
12022	t = (char *) MyStackAlloc(i, buf);
12023	if (t == NULL) {
12024	    SysError(ERROR_VINIT);
12025	} else {
12026
12027	    for (ns = s; ns && *s;) {
12028		while (*s && isspace(CharOf(*s)))
12029		    s++;
12030		if (!*s)
12031		    break;
12032		if ((ns = end = strchr(s, ',')) == 0)
12033		    end = s + strlen(s);
12034		while ((end != s) && isspace(CharOf(end[-1])))
12035		    end--;
12036
12037		if (end != s) {
12038		    strcpy(t, "@im=");
12039		    strncat(t, s, (size_t) (end - s));
12040
12041		    if ((p = XSetLocaleModifiers(t)) != 0 && *p
12042			&& (input->xim = XOpenIM(myDisplay,
12043						 NULL,
12044						 NULL,
12045						 NULL)) != 0) {
12046			break;
12047		    }
12048
12049		}
12050		s = ns + 1;
12051	    }
12052	    MyStackFree(t, buf);
12053	}
12054    }
12055
12056    if (input->xim == NULL
12057	&& (p = XSetLocaleModifiers("@im=none")) != NULL
12058	&& *p) {
12059	input->xim = XOpenIM(myDisplay, NULL, NULL, NULL);
12060    }
12061
12062    if (!input->xim) {
12063	xtermWarning("Failed to open input method\n");
12064	return;
12065    }
12066    TRACE(("VTInitI18N opened input method:%s\n", NonNull(p)));
12067
12068    if (XGetIMValues(input->xim, XNQueryInputStyle, &xim_styles, (void *) 0)
12069	|| !xim_styles
12070	|| !xim_styles->count_styles) {
12071	xtermWarning("input method doesn't support any style\n");
12072	cleanupInputMethod(xw);
12073	xw->work.cannot_im = True;
12074	return;
12075    }
12076
12077    found = False;
12078    for (s = xw->misc.preedit_type; s && !found;) {
12079	while (*s && isspace(CharOf(*s)))
12080	    s++;
12081	if (!*s)
12082	    break;
12083	if ((ns = end = strchr(s, ',')) != 0)
12084	    ns++;
12085	else
12086	    end = s + strlen(s);
12087	while ((end != s) && isspace(CharOf(end[-1])))
12088	    end--;
12089
12090	if (end != s) {		/* just in case we have a spurious comma */
12091	    TRACE(("looking for style '%.*s'\n", (int) (end - s), s));
12092	    for (i = 0; i < XtNumber(known_style); i++) {
12093		if ((int) strlen(known_style[i].name) == (end - s)
12094		    && !strncmp(s, known_style[i].name, (size_t) (end - s))) {
12095		    input_style = known_style[i].code;
12096		    for (j = 0; j < xim_styles->count_styles; j++) {
12097			if (input_style == xim_styles->supported_styles[j]) {
12098			    found = True;
12099			    break;
12100			}
12101		    }
12102		    if (found)
12103			break;
12104		}
12105	    }
12106	}
12107
12108	s = ns;
12109    }
12110    XFree(xim_styles);
12111
12112    if (!found) {
12113	xtermWarning("input method doesn't support my preedit type (%s)\n",
12114		     xw->misc.preedit_type);
12115	cleanupInputMethod(xw);
12116	xw->work.cannot_im = True;
12117	return;
12118    }
12119
12120    /*
12121     * Check for styles we do not yet support.
12122     */
12123    TRACE(("input_style %#lx\n", input_style));
12124    if (input_style == (XIMPreeditArea | XIMStatusArea)) {
12125	xtermWarning("This program doesn't support the 'OffTheSpot' preedit type\n");
12126	cleanupInputMethod(xw);
12127	xw->work.cannot_im = True;
12128	return;
12129    }
12130
12131    /*
12132     * For XIMPreeditPosition (or OverTheSpot), XIM client has to
12133     * prepare a font.
12134     * The font has to be locale-dependent XFontSet, whereas
12135     * XTerm use Unicode font.  This leads a problem that the
12136     * same font cannot be used for XIM preedit.
12137     */
12138    if (input_style != (XIMPreeditNothing | XIMStatusNothing)) {
12139	XVaNestedList p_list;
12140	XPoint spot =
12141	{0, 0};
12142
12143	if (xim_create_fs(xw)) {
12144	    p_list = XVaCreateNestedList(0,
12145					 XNSpotLocation, &spot,
12146					 XNFontSet, xw->work.xim_fs,
12147					 (void *) 0);
12148	    input->xic = XCreateIC(input->xim,
12149				   XNInputStyle, input_style,
12150				   XNClientWindow, myWindow,
12151				   XNFocusWindow, myWindow,
12152				   XNPreeditAttributes, p_list,
12153				   (void *) 0);
12154	}
12155    } else {
12156	input->xic = XCreateIC(input->xim, XNInputStyle, input_style,
12157			       XNClientWindow, myWindow,
12158			       XNFocusWindow, myWindow,
12159			       (void *) 0);
12160    }
12161
12162    if (!input->xic) {
12163	xtermWarning("Failed to create input context\n");
12164	cleanupInputMethod(xw);
12165    }
12166#if defined(USE_XIM_INSTANTIATE_CB)
12167    else {
12168	XIMCallback destroy_cb;
12169
12170	destroy_cb.callback = xim_destroy_cb;
12171	destroy_cb.client_data = NULL;
12172	if (XSetIMValues(input->xim,
12173			 XNDestroyCallback,
12174			 &destroy_cb,
12175			 (void *) 0)) {
12176	    xtermWarning("Could not set destroy callback to IM\n");
12177	}
12178    }
12179#endif
12180
12181    return;
12182}
12183
12184static void
12185xim_real_init(XtermWidget xw)
12186{
12187    xim_create_xic(xw, (Widget) xw);
12188}
12189
12190static void
12191VTInitI18N(XtermWidget xw)
12192{
12193    if (xw->misc.open_im) {
12194	xim_real_init(xw);
12195
12196#if defined(USE_XIM_INSTANTIATE_CB)
12197	if (lookupTInput(xw, (Widget) xw) == NULL
12198	    && !xw->work.cannot_im
12199	    && xw->misc.retry_im-- > 0) {
12200	    sleep(3);
12201	    XRegisterIMInstantiateCallback(XtDisplay(xw), NULL, NULL, NULL,
12202					   xim_instantiate_cb, NULL);
12203	}
12204#endif
12205    }
12206}
12207
12208TInput *
12209lookupTInput(XtermWidget xw, Widget w)
12210{
12211    TInput *result = 0;
12212    unsigned n;
12213
12214    for (n = 0; n < NINPUTWIDGETS; ++n) {
12215	if (xw->work.inputs[n].w == w) {
12216	    result = xw->work.inputs + n;
12217	    break;
12218	}
12219    }
12220
12221    return result;
12222}
12223#endif /* OPT_INPUT_METHOD */
12224
12225static void
12226set_cursor_outline_gc(XtermWidget xw,
12227		      Bool filled,
12228		      Pixel fg,
12229		      Pixel bg,
12230		      Pixel cc)
12231{
12232    TScreen *screen = TScreenOf(xw);
12233    VTwin *win = WhichVWin(screen);
12234    CgsEnum cgsId = gcVTcursOutline;
12235
12236    if (cc == bg)
12237	cc = fg;
12238
12239    if (filled) {
12240	setCgsFore(xw, win, cgsId, bg);
12241	setCgsBack(xw, win, cgsId, cc);
12242    } else {
12243	setCgsFore(xw, win, cgsId, cc);
12244	setCgsBack(xw, win, cgsId, bg);
12245    }
12246}
12247
12248static Boolean
12249VTSetValues(Widget cur,
12250	    Widget request GCC_UNUSED,
12251	    Widget wnew,
12252	    ArgList args GCC_UNUSED,
12253	    Cardinal *num_args GCC_UNUSED)
12254{
12255    XtermWidget curvt = (XtermWidget) cur;
12256    XtermWidget newvt = (XtermWidget) wnew;
12257    Boolean refresh_needed = False;
12258    Boolean fonts_redone = False;
12259
12260    if ((T_COLOR(TScreenOf(curvt), TEXT_BG) !=
12261	 T_COLOR(TScreenOf(newvt), TEXT_BG)) ||
12262	(T_COLOR(TScreenOf(curvt), TEXT_FG) !=
12263	 T_COLOR(TScreenOf(newvt), TEXT_FG)) ||
12264	(TScreenOf(curvt)->MenuFontName(TScreenOf(curvt)->menu_font_number) !=
12265	 TScreenOf(newvt)->MenuFontName(TScreenOf(newvt)->menu_font_number)) ||
12266	strcmp(DefaultFontN(curvt), DefaultFontN(newvt))) {
12267	if (strcmp(DefaultFontN(curvt), DefaultFontN(newvt))) {
12268	    TScreenOf(newvt)->MenuFontName(fontMenu_default) = DefaultFontN(newvt);
12269	}
12270	if (xtermLoadFont(newvt,
12271			  xtermFontName(TScreenOf(newvt)->MenuFontName(TScreenOf(curvt)->menu_font_number)),
12272			  True, TScreenOf(newvt)->menu_font_number)) {
12273	    /* resizing does the redisplay, so don't ask for it here */
12274	    refresh_needed = True;
12275	    fonts_redone = True;
12276	} else if (strcmp(DefaultFontN(curvt), DefaultFontN(newvt))) {
12277	    TScreenOf(newvt)->MenuFontName(fontMenu_default) = DefaultFontN(curvt);
12278	}
12279    }
12280    if (!fonts_redone
12281	&& (T_COLOR(TScreenOf(curvt), TEXT_CURSOR) !=
12282	    T_COLOR(TScreenOf(newvt), TEXT_CURSOR))) {
12283	if (set_cursor_gcs(newvt))
12284	    refresh_needed = True;
12285    }
12286    if (curvt->misc.re_verse != newvt->misc.re_verse) {
12287	newvt->flags ^= REVERSE_VIDEO;
12288	ReverseVideo(newvt);
12289	/* ReverseVideo toggles */
12290	newvt->misc.re_verse = (Boolean) (!newvt->misc.re_verse);
12291	refresh_needed = True;
12292    }
12293    if ((T_COLOR(TScreenOf(curvt), MOUSE_FG) !=
12294	 T_COLOR(TScreenOf(newvt), MOUSE_FG)) ||
12295	(T_COLOR(TScreenOf(curvt), MOUSE_BG) !=
12296	 T_COLOR(TScreenOf(newvt), MOUSE_BG))) {
12297	recolor_cursor(TScreenOf(newvt),
12298		       TScreenOf(newvt)->pointer_cursor,
12299		       T_COLOR(TScreenOf(newvt), MOUSE_FG),
12300		       T_COLOR(TScreenOf(newvt), MOUSE_BG));
12301	refresh_needed = True;
12302    }
12303    if (curvt->misc.scrollbar != newvt->misc.scrollbar) {
12304	ToggleScrollBar(newvt);
12305    }
12306
12307    return refresh_needed;
12308}
12309
12310/*
12311 * Given a font-slot and information about selection/reverse, find the
12312 * corresponding cached-GC slot.
12313 */
12314#if OPT_WIDE_ATTRS
12315static int
12316reverseCgs(XtermWidget xw, unsigned attr_flags, Bool hilite, int font)
12317{
12318    TScreen *screen = TScreenOf(xw);
12319    CgsEnum result = gcMAX;
12320
12321    (void) screen;
12322    if (ReverseOrHilite(screen, attr_flags, hilite)) {
12323	switch (font) {
12324	case fNorm:
12325	    result = gcNormReverse;
12326	    break;
12327	case fBold:
12328	    result = gcBoldReverse;
12329	    break;
12330#if OPT_WIDE_ATTRS || OPT_RENDERWIDE
12331	case fItal:
12332	    result = gcNormReverse;	/* FIXME */
12333	    break;
12334#endif
12335#if OPT_WIDE_CHARS
12336	case fWide:
12337	    result = gcWideReverse;
12338	    break;
12339	case fWBold:
12340	    result = gcWBoldReverse;
12341	    break;
12342	case fWItal:
12343	    result = gcWideReverse;	/* FIXME */
12344	    break;
12345#endif
12346	}
12347    } else {
12348	switch (font) {
12349	case fNorm:
12350	    result = gcNorm;
12351	    break;
12352	case fBold:
12353	    result = gcBold;
12354	    break;
12355#if OPT_WIDE_ATTRS || OPT_RENDERWIDE
12356	case fItal:
12357	    result = gcNorm;	/* FIXME */
12358	    break;
12359#endif
12360#if OPT_WIDE_CHARS
12361	case fWide:
12362	    result = gcWide;
12363	    break;
12364	case fWBold:
12365	    result = gcWBold;
12366	    break;
12367	case fWItal:
12368	    result = gcWide;	/* FIXME */
12369	    break;
12370#endif
12371	}
12372    }
12373    return (int) result;
12374}
12375#endif
12376
12377#define setGC(code) set_at = __LINE__, currentCgs = code
12378
12379#define OutsideSelection(screen,srow,scol)  \
12380	 ((srow) > (screen)->endH.row || \
12381	  ((srow) == (screen)->endH.row && \
12382	   (scol) >= (screen)->endH.col) || \
12383	  (srow) < (screen)->startH.row || \
12384	  ((srow) == (screen)->startH.row && \
12385	   (scol) < (screen)->startH.col))
12386
12387/*
12388 * Shows cursor at new cursor position in screen.
12389 */
12390void
12391ShowCursor(XtermWidget xw)
12392{
12393    TScreen *screen = TScreenOf(xw);
12394    XTermDraw params;
12395    IChar base;
12396    unsigned flags;
12397    CellColor fg_bg = initCColor;
12398    GC currentGC;
12399    GC outlineGC;
12400    CgsEnum currentCgs = gcMAX;
12401    VTwin *currentWin = WhichVWin(screen);
12402    int set_at;
12403    Bool in_selection;
12404    Bool reversed;
12405    Bool filled;
12406    Pixel fg_pix;
12407    Pixel bg_pix;
12408    Pixel tmp;
12409#if OPT_HIGHLIGHT_COLOR
12410    Pixel selbg_pix = T_COLOR(screen, HIGHLIGHT_BG);
12411    Pixel selfg_pix = T_COLOR(screen, HIGHLIGHT_FG);
12412    Boolean use_selbg;
12413    Boolean use_selfg;
12414#endif
12415#if OPT_WIDE_CHARS
12416    int my_col = 0;
12417#endif
12418    int cursor_col;
12419    CLineData *ld = 0;
12420
12421    if (screen->cursor_state == BLINKED_OFF)
12422	return;
12423
12424    if (screen->eventMode != NORMAL)
12425	return;
12426
12427    if (INX2ROW(screen, screen->cur_row) > screen->max_row)
12428	return;
12429
12430    screen->cursorp.row = screen->cur_row;
12431    cursor_col = screen->cursorp.col = screen->cur_col;
12432    screen->cursor_moved = False;
12433
12434#ifndef NO_ACTIVE_ICON
12435    if (IsIcon(screen)) {
12436	screen->cursor_state = ON;
12437	return;
12438    }
12439#endif /* NO_ACTIVE_ICON */
12440
12441    ld = getLineData(screen, screen->cur_row);
12442
12443    base = ld->charData[cursor_col];
12444    flags = ld->attribs[cursor_col];
12445
12446    if_OPT_WIDE_CHARS(screen, {
12447	if (base == HIDDEN_CHAR && cursor_col > 0) {
12448	    /* if cursor points to non-initial part of wide character,
12449	     * back it up
12450	     */
12451	    --cursor_col;
12452	    base = ld->charData[cursor_col];
12453	}
12454	my_col = cursor_col;
12455	if (base == 0)
12456	    base = ' ';
12457	if (isWide((int) base))
12458	    my_col += 1;
12459    });
12460
12461    if (base == 0) {
12462	base = ' ';
12463    }
12464#if OPT_ISO_COLORS
12465#ifdef EXP_BOGUS_FG
12466    /*
12467     * If the cursor happens to be on blanks, and we have not set both
12468     * foreground and background color, do not treat it as a colored cell.
12469     */
12470    if (base == ' ') {
12471	if ((flags & (FG_COLOR | BG_COLOR)) == BG_COLOR) {
12472	    TRACE(("ShowCursor - do not treat as a colored cell\n"));
12473	    flags &= ~(FG_COLOR | BG_COLOR);
12474	} else if ((flags & (FG_COLOR | BG_COLOR)) == FG_COLOR) {
12475	    TRACE(("ShowCursor - should we treat as a colored cell?\n"));
12476	    if (!(xw->flags & FG_COLOR)) {
12477		if (CheckBogusForeground(screen, "ShowCursor")) {
12478		    flags &= ~(FG_COLOR | BG_COLOR);
12479		}
12480	    }
12481	}
12482    }
12483#else /* !EXP_BOGUS_FG */
12484    /*
12485     * If the cursor happens to be on blanks, and the foreground color is set
12486     * but not the background, do not treat it as a colored cell.
12487     */
12488    if ((flags & TERM_COLOR_FLAGS(xw)) == FG_COLOR
12489	&& base == ' ') {
12490	flags &= ~TERM_COLOR_FLAGS(xw);
12491    }
12492#endif
12493#endif
12494
12495    /*
12496     * Compare the current cell to the last set of colors used for the
12497     * cursor and update the GC's if needed.
12498     */
12499    (void) fg_bg;
12500    if_OPT_ISO_COLORS(screen, {
12501	fg_bg = ld->color[cursor_col];
12502    });
12503
12504    fg_pix = getXtermFG(xw, flags, (int) extract_fg(xw, fg_bg, flags));
12505    bg_pix = getXtermBG(xw, flags, (int) extract_bg(xw, fg_bg, flags));
12506
12507    /*
12508     * If we happen to have the same foreground/background colors, choose
12509     * a workable foreground color from which we can obtain a visible cursor.
12510     */
12511    if (fg_pix == bg_pix) {
12512	long bg_diff = (long) (bg_pix - T_COLOR(TScreenOf(xw), TEXT_BG));
12513	long fg_diff = (long) (bg_pix - T_COLOR(TScreenOf(xw), TEXT_FG));
12514	if (bg_diff < 0)
12515	    bg_diff = -bg_diff;
12516	if (fg_diff < 0)
12517	    fg_diff = -fg_diff;
12518	if (bg_diff < fg_diff) {
12519	    fg_pix = T_COLOR(TScreenOf(xw), TEXT_FG);
12520	} else {
12521	    fg_pix = T_COLOR(TScreenOf(xw), TEXT_BG);
12522	}
12523    }
12524
12525    if (OutsideSelection(screen, screen->cur_row, screen->cur_col))
12526	in_selection = False;
12527    else
12528	in_selection = True;
12529
12530    reversed = ReverseOrHilite(screen, flags, in_selection);
12531
12532    /* This is like updatedXtermGC(), except that we have to worry about
12533     * whether the window has focus, since in that case we want just an
12534     * outline for the cursor.
12535     */
12536    filled = (screen->select || screen->always_highlight) && isCursorBlock(screen);
12537#if OPT_HIGHLIGHT_COLOR
12538    use_selbg = isNotForeground(xw, fg_pix, bg_pix, selbg_pix);
12539    use_selfg = isNotBackground(xw, fg_pix, bg_pix, selfg_pix);
12540#endif
12541    if (filled) {
12542	if (reversed) {		/* text is reverse video */
12543	    if (getCgsGC(xw, currentWin, gcVTcursNormal)) {
12544		setGC(gcVTcursNormal);
12545	    } else {
12546		if (flags & BOLDATTR(screen)) {
12547		    setGC(gcBold);
12548		} else {
12549		    setGC(gcNorm);
12550		}
12551	    }
12552	    EXCHANGE(fg_pix, bg_pix, tmp);
12553#if OPT_HIGHLIGHT_COLOR
12554	    if (screen->hilite_reverse) {
12555		if (use_selbg && !use_selfg)
12556		    fg_pix = bg_pix;
12557		if (use_selfg && !use_selbg)
12558		    bg_pix = fg_pix;
12559		if (use_selbg)
12560		    bg_pix = selbg_pix;
12561		if (use_selfg)
12562		    fg_pix = selfg_pix;
12563	    }
12564#endif
12565	} else {		/* normal video */
12566	    if (getCgsGC(xw, currentWin, gcVTcursReverse)) {
12567		setGC(gcVTcursReverse);
12568	    } else {
12569		if (flags & BOLDATTR(screen)) {
12570		    setGC(gcBoldReverse);
12571		} else {
12572		    setGC(gcNormReverse);
12573		}
12574	    }
12575	}
12576
12577#define CUR_XX T_COLOR(screen, TEXT_CURSOR)
12578#define CGS_FG getCgsFore(xw, currentWin, getCgsGC(xw, currentWin, currentCgs))
12579#define CGS_BG getCgsBack(xw, currentWin, getCgsGC(xw, currentWin, currentCgs))
12580
12581#define FIX_311 (CUR_XX == (reversed ? xw->dft_background : xw->dft_foreground))
12582#define FIX_328 (CUR_XX == bg_pix)
12583#define FIX_330 (FIX_328 && reversed && in_selection)
12584
12585	if (FIX_330 || FIX_311) {
12586	    setCgsBack(xw, currentWin, currentCgs, fg_pix);
12587	}
12588	setCgsFore(xw, currentWin, currentCgs, bg_pix);
12589    } else {			/* not selected */
12590	if (reversed) {		/* text is reverse video */
12591	    EXCHANGE(fg_pix, bg_pix, tmp);
12592	    setGC(gcNormReverse);
12593	} else {		/* normal video */
12594	    setGC(gcNorm);
12595	}
12596#if OPT_HIGHLIGHT_COLOR
12597	if (screen->hilite_reverse) {
12598	    if (in_selection && !reversed) {
12599		/* EMPTY */
12600		/* really INVERSE ... */
12601		;
12602	    } else if (in_selection || reversed) {
12603		if (use_selbg) {
12604		    if (use_selfg) {
12605			bg_pix = fg_pix;
12606		    } else {
12607			fg_pix = bg_pix;
12608			bg_pix = selbg_pix;
12609		    }
12610		}
12611		if (use_selfg) {
12612		    fg_pix = selfg_pix;
12613		}
12614	    }
12615	} else {
12616	    if (in_selection) {
12617		if (use_selbg) {
12618		    bg_pix = selbg_pix;
12619		}
12620		if (use_selfg) {
12621		    fg_pix = selfg_pix;
12622		}
12623	    }
12624	}
12625#endif
12626	setCgsFore(xw, currentWin, currentCgs, fg_pix);
12627	setCgsBack(xw, currentWin, currentCgs, bg_pix);
12628    }
12629
12630    if (screen->cursor_busy == 0
12631	&& (screen->cursor_state != ON || screen->cursor_GC != set_at)) {
12632	int x, y;
12633
12634	screen->cursor_GC = set_at;
12635	TRACE(("ShowCursor calling drawXtermText cur(%d,%d) %s-%s, set_at %d\n",
12636	       screen->cur_row, screen->cur_col,
12637	       (filled ? "filled" : "outline"),
12638	       (isCursorBlock(screen) ? "box" :
12639		isCursorUnderline(screen) ? "underline" : "bar"),
12640	       set_at));
12641
12642	currentGC = getCgsGC(xw, currentWin, currentCgs);
12643	x = LineCursorX(screen, ld, cursor_col);
12644	y = CursorY(screen, screen->cur_row);
12645
12646	if (!isCursorBlock(screen)) {
12647	    /*
12648	     * Overriding the combination of filled, reversed, in_selection is
12649	     * too complicated since the underline or bar and the text-cell use
12650	     * different rules.  Just redraw the text-cell, and draw the
12651	     * underline or bar on top of it.
12652	     */
12653	    HideCursor(xw);
12654
12655	    /*
12656	     * Our current-GC is likely to have been modified in HideCursor().
12657	     * Set up a new request.
12658	     */
12659	    if (filled) {
12660		if (FIX_330 || FIX_311) {
12661		    setCgsBack(xw, currentWin, currentCgs, fg_pix);
12662		}
12663		setCgsFore(xw, currentWin, currentCgs, bg_pix);
12664	    } else {
12665		setCgsFore(xw, currentWin, currentCgs, fg_pix);
12666		setCgsBack(xw, currentWin, currentCgs, bg_pix);
12667	    }
12668	}
12669
12670	/*
12671	 * Update the outline-gc, to keep the cursor color distinct from the
12672	 * background color.
12673	 */
12674	set_cursor_outline_gc(xw,
12675			      filled,
12676			      fg_pix,
12677			      bg_pix,
12678			      T_COLOR(screen, TEXT_CURSOR));
12679
12680	outlineGC = getCgsGC(xw, currentWin, gcVTcursOutline);
12681	if (outlineGC == 0)
12682	    outlineGC = currentGC;
12683
12684	if (isCursorUnderline(screen)) {
12685
12686	    /*
12687	     * Finally, draw the underline.
12688	     */
12689	    screen->box->x = (short) x;
12690	    screen->box->y = (short) (y + FontHeight(screen) - 2);
12691	    XDrawLines(screen->display, VDrawable(screen), outlineGC,
12692		       screen->box, NBOX, CoordModePrevious);
12693	} else if (isCursorBar(screen)) {
12694
12695	    /*
12696	     * Or draw the bar.
12697	     */
12698	    screen->box->x = (short) x;
12699	    screen->box->y = (short) y;
12700	    XDrawLines(screen->display, VDrawable(screen), outlineGC,
12701		       screen->box, NBOX, CoordModePrevious);
12702	} else {
12703#if OPT_WIDE_ATTRS
12704	    int italics_on = ((ld->attribs[cursor_col] & ATR_ITALIC) != 0);
12705	    int italics_off = ((xw->flags & ATR_ITALIC) != 0);
12706	    int fix_italics = (italics_on != italics_off);
12707	    int which_font = ((xw->flags & BOLD) ? fBold : fNorm);
12708	    MyGetFont getter = italics_on ? getItalicFont : getNormalFont;
12709
12710	    if_OPT_WIDE_CHARS(screen, {
12711		if (isWide((int) base)) {
12712		    which_font = ((xw->flags & BOLD) ? fWBold : fWide);
12713		}
12714	    });
12715
12716	    if (fix_italics && UseItalicFont(screen)) {
12717		xtermLoadItalics(xw);
12718		setCgsFont(xw, currentWin, currentCgs,
12719			   getter(screen, which_font));
12720		getter = (((xw->flags & ATR_ITALIC) && UseItalicFont(screen))
12721			  ? getItalicFont
12722			  : getNormalFont);
12723	    }
12724	    currentGC = getCgsGC(xw, currentWin, currentCgs);
12725#endif /* OPT_WIDE_ATTRS */
12726
12727	    /* *INDENT-EQLS* */
12728	    params.xw          = xw;
12729	    params.attr_flags  = (flags & DRAWX_MASK);
12730	    params.draw_flags  = 0;
12731	    params.this_chrset = LineCharSet(screen, ld);
12732	    params.real_chrset = CSET_SWL;
12733	    params.on_wide     = 0;
12734
12735	    drawXtermText(&params,
12736			  currentGC, x, y,
12737			  &base, 1);
12738
12739#if OPT_WIDE_CHARS
12740	    if_OPT_WIDE_CHARS(screen, {
12741		size_t off;
12742
12743		/* *INDENT-EQLS* */
12744		params.draw_flags = NOBACKGROUND;
12745		params.on_wide    = isWide((int) base);
12746
12747		for_each_combData(off, ld) {
12748		    if (!(ld->combData[off][my_col]))
12749			break;
12750		    drawXtermText(&params,
12751				  currentGC, x, y,
12752				  ld->combData[off] + my_col, 1);
12753		}
12754	    });
12755#endif
12756
12757	    if (!filled) {
12758		screen->box->x = (short) x;
12759		screen->box->y = (short) y;
12760		XDrawLines(screen->display, VDrawable(screen), outlineGC,
12761			   screen->box, NBOX, CoordModePrevious);
12762	    }
12763#if OPT_WIDE_ATTRS
12764	    if (fix_italics && UseItalicFont(screen)) {
12765		setCgsFont(xw, currentWin, currentCgs,
12766			   getter(screen, which_font));
12767	    }
12768#endif
12769	}
12770    }
12771    screen->cursor_state = ON;
12772
12773    return;
12774}
12775
12776/*
12777 * hide cursor at previous cursor position in screen.
12778 */
12779void
12780HideCursor(XtermWidget xw)
12781{
12782    TScreen *screen = TScreenOf(xw);
12783    XTermDraw params;
12784    GC currentGC;
12785    int x, y;
12786    IChar base;
12787    unsigned flags;
12788    CellColor fg_bg = initCColor;
12789    Bool in_selection;
12790#if OPT_WIDE_CHARS
12791    int my_col = 0;
12792#endif
12793    int cursor_col;
12794    CLineData *ld = 0;
12795#if OPT_WIDE_ATTRS
12796    int which_Cgs = gcMAX;
12797    unsigned attr_flags;
12798    int which_font = fNorm;
12799    MyGetFont getter = getNormalFont;
12800#endif
12801
12802    if (screen->cursor_state == OFF)
12803	return;
12804    if (INX2ROW(screen, screen->cursorp.row) > screen->max_row)
12805	return;
12806
12807    cursor_col = screen->cursorp.col;
12808
12809#ifndef NO_ACTIVE_ICON
12810    if (IsIcon(screen)) {
12811	screen->cursor_state = OFF;
12812	return;
12813    }
12814#endif /* NO_ACTIVE_ICON */
12815
12816    ld = getLineData(screen, screen->cursorp.row);
12817
12818    base = ld->charData[cursor_col];
12819    flags = ld->attribs[cursor_col];
12820
12821    if_OPT_WIDE_CHARS(screen, {
12822	if (base == HIDDEN_CHAR && cursor_col > 0) {
12823	    /* if cursor points to non-initial part of wide character,
12824	     * back it up
12825	     */
12826	    --cursor_col;
12827	    base = ld->charData[cursor_col];
12828	}
12829	my_col = cursor_col;
12830	if (base == 0)
12831	    base = ' ';
12832	if (isWide((int) base))
12833	    my_col += 1;
12834    });
12835
12836    if (base == 0) {
12837	base = ' ';
12838    }
12839#ifdef EXP_BOGUS_FG
12840    /*
12841     * If the cursor happens to be on blanks, and we have not set both
12842     * foreground and background color, do not treat it as a colored cell.
12843     */
12844#if OPT_ISO_COLORS
12845    if (base == ' ') {
12846	if ((flags & (FG_COLOR | BG_COLOR)) == BG_COLOR) {
12847	    TRACE(("HideCursor - do not treat as a colored cell\n"));
12848	    flags &= ~(FG_COLOR | BG_COLOR);
12849	} else if ((flags & (FG_COLOR | BG_COLOR)) == FG_COLOR) {
12850	    TRACE(("HideCursor - should we treat as a colored cell?\n"));
12851	    if (!(xw->flags & FG_COLOR))
12852		if (CheckBogusForeground(screen, "HideCursor"))
12853		    flags &= ~(FG_COLOR | BG_COLOR);
12854	}
12855    }
12856#endif
12857#endif
12858
12859    /*
12860     * Compare the current cell to the last set of colors used for the
12861     * cursor and update the GC's if needed.
12862     */
12863    if_OPT_ISO_COLORS(screen, {
12864	fg_bg = ld->color[cursor_col];
12865    });
12866
12867    if (OutsideSelection(screen, screen->cursorp.row, screen->cursorp.col))
12868	in_selection = False;
12869    else
12870	in_selection = True;
12871
12872#if OPT_WIDE_ATTRS
12873    attr_flags = ld->attribs[cursor_col];
12874    if ((attr_flags & ATR_ITALIC) ^ (xw->flags & ATR_ITALIC)) {
12875	which_font = ((attr_flags & BOLD) ? fBold : fNorm);
12876	if ((attr_flags & ATR_ITALIC) && UseItalicFont(screen))
12877	    getter = getItalicFont;
12878
12879	if_OPT_WIDE_CHARS(screen, {
12880	    if (isWide((int) base)) {
12881		which_font = ((attr_flags & BOLD) ? fWBold : fWide);
12882	    }
12883	});
12884
12885	which_Cgs = reverseCgs(xw, attr_flags, in_selection, which_font);
12886	if (which_Cgs != gcMAX) {
12887	    setCgsFont(xw, WhichVWin(screen),
12888		       (CgsEnum) which_Cgs,
12889		       getter(screen, which_font));
12890	    getter = (((xw->flags & ATR_ITALIC) && UseItalicFont(screen))
12891		      ? getItalicFont
12892		      : getNormalFont);
12893	}
12894    }
12895#endif
12896
12897    currentGC = updatedXtermGC(xw, flags, fg_bg, in_selection);
12898
12899    TRACE(("HideCursor calling drawXtermText cur(%d,%d)\n",
12900	   screen->cursorp.row, screen->cursorp.col));
12901
12902    x = LineCursorX(screen, ld, cursor_col);
12903    y = CursorY(screen, screen->cursorp.row);
12904
12905    /* *INDENT-EQLS* */
12906    params.xw          = xw;
12907    params.attr_flags  = (flags & DRAWX_MASK);
12908    params.draw_flags  = 0;
12909    params.this_chrset = LineCharSet(screen, ld);
12910    params.real_chrset = CSET_SWL;
12911    params.on_wide     = 0;
12912
12913    drawXtermText(&params,
12914		  currentGC, x, y,
12915		  &base, 1);
12916
12917#if OPT_WIDE_CHARS
12918    if_OPT_WIDE_CHARS(screen, {
12919	size_t off;
12920
12921	/* *INDENT-EQLS* */
12922	params.draw_flags  = NOBACKGROUND;
12923	params.on_wide     = isWide((int) base);
12924
12925	for_each_combData(off, ld) {
12926	    if (!(ld->combData[off][my_col]))
12927		break;
12928	    drawXtermText(&params,
12929			  currentGC, x, y,
12930			  ld->combData[off] + my_col, 1);
12931	}
12932    });
12933#endif
12934    screen->cursor_state = OFF;
12935
12936#if OPT_WIDE_ATTRS
12937    if (which_Cgs != gcMAX) {
12938	setCgsFont(xw, WhichVWin(screen),
12939		   (CgsEnum) which_Cgs,
12940		   getter(screen, which_font));
12941    }
12942#endif
12943    resetXtermGC(xw, flags, in_selection);
12944
12945    refresh_displayed_graphics(xw,
12946			       screen->cursorp.col,
12947			       screen->cursorp.row,
12948			       1, 1);
12949
12950    return;
12951}
12952
12953#if OPT_BLINK_CURS || OPT_BLINK_TEXT
12954static void
12955StartBlinking(XtermWidget xw)
12956{
12957    TScreen *screen = TScreenOf(xw);
12958
12959    if (screen->blink_timer == 0) {
12960	unsigned long interval = (unsigned long) ((screen->cursor_state == ON)
12961						  ? screen->blink_on
12962						  : screen->blink_off);
12963	if (interval == 0)	/* wow! */
12964	    interval = 1;	/* let's humor him anyway */
12965	screen->blink_timer = XtAppAddTimeOut(app_con,
12966					      interval,
12967					      HandleBlinking,
12968					      xw);
12969    }
12970}
12971
12972static void
12973StopBlinking(XtermWidget xw)
12974{
12975    TScreen *screen = TScreenOf(xw);
12976
12977    if (screen->blink_timer) {
12978	XtRemoveTimeOut(screen->blink_timer);
12979	screen->blink_timer = 0;
12980	reallyStopBlinking(xw);
12981    } else {
12982	screen->blink_timer = 0;
12983    }
12984}
12985
12986#if OPT_BLINK_TEXT
12987Bool
12988LineHasBlinking(TScreen *screen, CLineData *ld)
12989{
12990    Bool result = False;
12991    if (ld != 0) {
12992	int col;
12993
12994	for (col = 0; col < MaxCols(screen); ++col) {
12995	    if (ld->attribs[col] & BLINK) {
12996		result = True;
12997		break;
12998	    }
12999	}
13000    }
13001    return result;
13002}
13003#endif
13004
13005/*
13006 * Blink the cursor by alternately showing/hiding cursor.  We leave the timer
13007 * running all the time (even though that's a little inefficient) to make the
13008 * logic simple.
13009 */
13010static void
13011HandleBlinking(XtPointer closure, XtIntervalId * id GCC_UNUSED)
13012{
13013    XtermWidget xw = (XtermWidget) closure;
13014    TScreen *screen = TScreenOf(xw);
13015    Bool resume = False;
13016
13017    screen->blink_timer = 0;
13018    screen->blink_state = !screen->blink_state;
13019
13020#if OPT_BLINK_CURS
13021    if (DoStartBlinking(screen)) {
13022	if (screen->cursor_state == ON) {
13023	    if (screen->select || screen->always_highlight) {
13024		HideCursor(xw);
13025		if (screen->cursor_state == OFF)
13026		    screen->cursor_state = BLINKED_OFF;
13027	    }
13028	} else if (screen->cursor_state == BLINKED_OFF) {
13029	    screen->cursor_state = OFF;
13030	    ShowCursor(xw);
13031	    if (screen->cursor_state == OFF)
13032		screen->cursor_state = BLINKED_OFF;
13033	}
13034	resume = True;
13035    }
13036#endif
13037
13038#if OPT_BLINK_TEXT
13039    /*
13040     * Inspect the lines on the current screen to see if any have the BLINK flag
13041     * associated with them.  Prune off any that have had the corresponding
13042     * cells reset.  If any are left, repaint those lines with ScrnRefresh().
13043     */
13044    if (!(screen->blink_as_bold)) {
13045	int row;
13046	int start_row = LastRowNumber(screen);
13047	int first_row = start_row;
13048	int last_row = -1;
13049
13050	for (row = start_row; row >= 0; row--) {
13051	    LineData *ld = getLineData(screen, ROW2INX(screen, row));
13052
13053	    if (ld != 0 && LineTstBlinked(ld)) {
13054		if (LineHasBlinking(screen, ld)) {
13055		    resume = True;
13056		    if (row > last_row)
13057			last_row = row;
13058		    if (row < first_row)
13059			first_row = row;
13060		} else {
13061		    LineClrBlinked(ld);
13062		}
13063	    }
13064	}
13065	/*
13066	 * FIXME: this could be a little more efficient, e.g,. by limiting the
13067	 * columns which are updated.
13068	 */
13069	if (first_row <= last_row) {
13070	    ScrnRefresh(xw,
13071			first_row,
13072			0,
13073			last_row + 1 - first_row,
13074			MaxCols(screen),
13075			True);
13076	}
13077    }
13078#endif
13079
13080    /*
13081     * If either the cursor or text is blinking, restart the timer.
13082     */
13083    if (resume)
13084	StartBlinking(xw);
13085}
13086#endif /* OPT_BLINK_CURS || OPT_BLINK_TEXT */
13087
13088void
13089RestartBlinking(XtermWidget xw)
13090{
13091#if OPT_BLINK_CURS || OPT_BLINK_TEXT
13092    TScreen *screen = TScreenOf(xw);
13093
13094    if (screen->blink_timer == 0) {
13095	Bool resume = False;
13096
13097#if OPT_BLINK_CURS
13098	if (DoStartBlinking(screen)) {
13099	    resume = True;
13100	}
13101#endif
13102#if OPT_BLINK_TEXT
13103	if (!resume) {
13104	    int row;
13105
13106	    for (row = screen->max_row; row >= 0; row--) {
13107		CLineData *ld = getLineData(screen, ROW2INX(screen, row));
13108
13109		if (ld != 0 && LineTstBlinked(ld)) {
13110		    if (LineHasBlinking(screen, ld)) {
13111			resume = True;
13112			break;
13113		    }
13114		}
13115	    }
13116	}
13117#endif
13118	if (resume)
13119	    StartBlinking(xw);
13120    }
13121#else
13122    (void) xw;
13123#endif
13124}
13125
13126/*
13127 * Implement soft or hard (full) reset of the VTxxx emulation.  There are a
13128 * couple of differences from real DEC VTxxx terminals (to avoid breaking
13129 * applications which have come to rely on xterm doing this):
13130 *
13131 *	+ autowrap mode should be reset (instead it's reset to the resource
13132 *	  default).
13133 *	+ the popup menu offers a choice of resetting the savedLines, or not.
13134 *	  (but the control sequence does this anyway).
13135 */
13136static void
13137ReallyReset(XtermWidget xw, Bool full, Bool saved)
13138{
13139    TScreen *screen = TScreenOf(xw);
13140    IFlags saveflags = xw->flags;
13141
13142    TRACE(("ReallyReset %s, %s\n",
13143	   full ? "hard" : "soft",
13144	   saved ? "clear savedLines" : "keep savedLines"));
13145
13146    if (!XtIsRealized((Widget) xw) || (CURRENT_EMU() != (Widget) xw)) {
13147	Bell(xw, XkbBI_MinorError, 0);
13148	return;
13149    }
13150
13151    if (saved) {
13152	screen->savedlines = 0;
13153	ScrollBarDrawThumb(xw, 0);
13154    }
13155
13156    /* make cursor visible */
13157    screen->cursor_set = ON;
13158    InitCursorShape(screen, screen);
13159    xtermSetCursorBox(screen);
13160#if OPT_BLINK_CURS
13161    screen->cursor_blink = screen->cursor_blink_i;
13162    screen->cursor_blink_esc = 0;
13163    TRACE(("cursor_shape:%d blinks:%d\n",
13164	   screen->cursor_shape,
13165	   screen->cursor_blink));
13166#endif
13167
13168    /* reset scrolling region */
13169    resetMarginMode(xw);
13170
13171    bitclr(&xw->flags, ORIGIN);
13172
13173    if_OPT_ISO_COLORS(screen, {
13174	static char empty[1];
13175	reset_SGR_Colors(xw);
13176	if (ResetAnsiColorRequest(xw, empty, 0))
13177	    xtermRepaint(xw);
13178    });
13179
13180    /* Reset character-sets to initial state */
13181    resetCharsets(screen);
13182
13183#if OPT_MOD_FKEYS
13184    /* Reset modifier-resources to initial state */
13185    xw->keyboard.modify_now = xw->keyboard.modify_1st;
13186#endif
13187#if OPT_DEC_RECTOPS
13188    screen->checksum_ext = screen->checksum_ext0;
13189#endif
13190
13191    /* Reset DECSCA */
13192    bitclr(&xw->flags, PROTECTED);
13193    screen->protected_mode = OFF_PROTECT;
13194
13195    if (full) {			/* RIS */
13196	if (screen->bellOnReset)
13197	    Bell(xw, XkbBI_TerminalBell, 0);
13198
13199	reset_displayed_graphics(screen);
13200
13201	/* reset the mouse mode */
13202	screen->send_mouse_pos = MOUSE_OFF;
13203	screen->send_focus_pos = OFF;
13204	screen->extend_coords = 0;
13205	screen->waitingForTrackInfo = False;
13206	screen->eventMode = NORMAL;
13207
13208	xtermShowPointer(xw, True);
13209
13210	TabReset(xw->tabs);
13211	xw->keyboard.flags = MODE_SRM;
13212
13213	guard_keyboard_type = False;
13214	screen->old_fkeys = screen->old_fkeys0;
13215	decode_keyboard_type(xw, &resource);
13216	update_keyboard_type();
13217
13218#if OPT_INITIAL_ERASE
13219	if (xw->keyboard.reset_DECBKM == 1)
13220	    xw->keyboard.flags |= MODE_DECBKM;
13221	else if (xw->keyboard.reset_DECBKM == 2)
13222#endif
13223	    if (TScreenOf(xw)->backarrow_key)
13224		xw->keyboard.flags |= MODE_DECBKM;
13225	TRACE(("full reset DECBKM %s\n",
13226	       BtoS(xw->keyboard.flags & MODE_DECBKM)));
13227
13228#if OPT_SCROLL_LOCK
13229	xtermClearLEDs(screen);
13230#endif
13231	screen->title_modes = screen->title_modes0;
13232	screen->pointer_mode = screen->pointer_mode0;
13233#if OPT_SIXEL_GRAPHICS
13234	if (TScreenOf(xw)->sixel_scrolling)
13235	    xw->keyboard.flags |= MODE_DECSDM;
13236	TRACE(("full reset DECSDM to %s (resource default is %s)\n",
13237	       BtoS(xw->keyboard.flags & MODE_DECSDM),
13238	       BtoS(TScreenOf(xw)->sixel_scrolling)));
13239#endif
13240
13241#if OPT_GRAPHICS
13242	screen->privatecolorregisters = TScreenOf(xw)->privatecolorregisters;
13243	TRACE(("full reset PRIVATE_COLOR_REGISTERS to %s (resource default is %s)\n",
13244	       BtoS(screen->privatecolorregisters),
13245	       BtoS(TScreenOf(xw)->privatecolorregisters)));
13246#endif
13247
13248#if OPT_SIXEL_GRAPHICS
13249	screen->sixel_scrolls_right = TScreenOf(xw)->sixel_scrolls_right;
13250	TRACE(("full reset SIXEL_SCROLLS_RIGHT to %s (resource default is %s)\n",
13251	       BtoS(screen->sixel_scrolls_right),
13252	       BtoS(TScreenOf(xw)->sixel_scrolls_right)));
13253#endif
13254
13255	update_appcursor();
13256	update_appkeypad();
13257	update_decbkm();
13258	update_decsdm();
13259	show_8bit_control(False);
13260	reset_decudk(xw);
13261
13262	FromAlternate(xw);
13263	ClearScreen(xw);
13264	screen->cursor_state = OFF;
13265
13266	if (xw->flags & REVERSE_VIDEO)
13267	    ReverseVideo(xw);
13268	ResetItalics(xw);
13269	xw->flags = xw->initflags;
13270
13271	update_reversevideo();
13272	update_autowrap();
13273	update_reversewrap();
13274	update_autolinefeed();
13275
13276	screen->jumpscroll = (Boolean) (!(xw->flags & SMOOTHSCROLL));
13277	update_jumpscroll();
13278
13279#if OPT_DEC_RECTOPS
13280	screen->cur_decsace = 0;
13281#endif
13282#if OPT_PASTE64 || OPT_READLINE
13283	screen->paste_brackets = OFF;
13284#endif
13285#if OPT_READLINE
13286	screen->click1_moves = OFF;
13287	screen->paste_moves = OFF;
13288	screen->dclick3_deletes = OFF;
13289	screen->paste_quotes = OFF;
13290	screen->paste_literal_nl = OFF;
13291#endif /* OPT_READLINE */
13292
13293	if (screen->c132 && (saveflags & IN132COLUMNS)) {
13294	    TRACE(("Making resize-request to restore 80-columns %dx%d\n",
13295		   MaxRows(screen), MaxCols(screen)));
13296	    RequestResize(xw, MaxRows(screen), 80, True);
13297	    repairSizeHints();
13298	    XSync(screen->display, False);	/* synchronize */
13299	    if (xtermAppPending())
13300		xevents(xw);
13301	}
13302
13303	CursorSet(screen, 0, 0, xw->flags);
13304	CursorSave(xw);
13305    } else {			/* DECSTR */
13306	/*
13307	 * There's a tiny difference, to accommodate usage of xterm.
13308	 * We reset autowrap to the resource values rather than turning
13309	 * it off.
13310	 */
13311	UIntClr(xw->keyboard.flags, (MODE_DECCKM | MODE_KAM | MODE_DECKPAM));
13312	bitcpy(&xw->flags, xw->initflags, WRAPAROUND | REVERSEWRAP);
13313	bitclr(&xw->flags, INSERT | INVERSE | BOLD | BLINK | UNDERLINE | INVISIBLE);
13314	ResetItalics(xw);
13315	if_OPT_ISO_COLORS(screen, {
13316	    reset_SGR_Colors(xw);
13317	});
13318	update_appcursor();
13319	update_autowrap();
13320	update_reversewrap();
13321
13322	CursorSave(xw);
13323	screen->sc[screen->whichBuf].row =
13324	    screen->sc[screen->whichBuf].col = 0;
13325    }
13326}
13327
13328void
13329VTReset(XtermWidget xw, Bool full, Bool saved)
13330{
13331    ReallyReset(xw, full, saved);
13332
13333    FreeAndNull(myState.string_area);
13334    FreeAndNull(myState.print_area);
13335
13336    longjmp(vtjmpbuf, 1);	/* force ground state in parser */
13337}
13338
13339typedef enum {
13340    ccLO,
13341    ccDASH,
13342    ccHI,
13343    ccCOLON,
13344    ccID,
13345    ccCOMMA
13346} CCLASS;
13347
13348/*
13349 * set_character_class - takes a string of the form
13350 *
13351 *   low[-high][:id][,low[-high][:id][...]]
13352 *
13353 * and sets the indicated ranges to the indicated values.
13354 */
13355static int
13356set_character_class(char *s)
13357{
13358#define FMT "%s in range string \"%s\" (position %d)\n"
13359
13360    TRACE(("set_character_class(%s) " TRACE_L "\n", NonNull(s)));
13361    if (IsEmpty(s)) {
13362	TRACE((TRACE_R " ERR set_character_class\n"));
13363	return -1;
13364    } else {
13365	CCLASS state = ccLO;
13366	int arg[3];
13367	int i;
13368	int len = (int) strlen(s);
13369
13370	arg[0] =
13371	    arg[1] =
13372	    arg[2] = -1;
13373
13374	for (i = 0; i < len; ++i) {
13375	    int ch = CharOf(s[i]);
13376	    char *t = 0;
13377	    long value = 0;
13378
13379	    if (isspace(ch))
13380		continue;
13381
13382	    switch (state) {
13383	    case ccLO:
13384	    case ccHI:
13385	    case ccID:
13386		if (!isdigit(ch)) {
13387		    xtermWarning(FMT, "missing number", s, i);
13388		    TRACE((TRACE_R " ERR set_character_class\n"));
13389		    return (-1);
13390		}
13391		value = strtol(s + i, &t, 0);
13392		i = (int) (t - s - 1);
13393		break;
13394	    case ccDASH:
13395	    case ccCOLON:
13396	    case ccCOMMA:
13397		break;
13398	    }
13399
13400	    switch (state) {
13401	    case ccLO:
13402		arg[0] =
13403		    arg[1] = (int) value;
13404		arg[2] = -1;
13405		state = ccDASH;
13406		break;
13407
13408	    case ccDASH:
13409		if (ch == '-') {
13410		    state = ccHI;
13411		} else {
13412		    goto parse_class;
13413		}
13414		break;
13415
13416	    case ccHI:
13417		arg[1] = (int) value;
13418		state = ccCOLON;
13419		break;
13420
13421	      parse_class:
13422	    case ccCOLON:
13423		if (ch == ':') {
13424		    state = ccID;
13425		} else if (ch == ',') {
13426		    goto apply_class;
13427		} else {
13428		    xtermWarning(FMT, "unexpected character", s, i);
13429		    TRACE((TRACE_R " ERR set_character_class\n"));
13430		    return (-1);
13431		}
13432		break;
13433
13434	    case ccID:
13435		arg[2] = (int) value;
13436		state = ccCOMMA;
13437		break;
13438
13439	      apply_class:
13440	    case ccCOMMA:
13441		if (SetCharacterClassRange(arg[0], arg[1], arg[2]) != 0) {
13442		    xtermWarning(FMT, "bad range", s, i);
13443		    TRACE((TRACE_R " ERR set_character_class\n"));
13444		    return -1;
13445		}
13446		state = ccLO;
13447		break;
13448	    }
13449	}
13450	if (state >= ccDASH) {
13451	    if (SetCharacterClassRange(arg[0], arg[1], arg[2]) != 0) {
13452		xtermWarning(FMT, "bad range", s, i);
13453		TRACE((TRACE_R " ERR set_character_class\n"));
13454		return -1;
13455	    }
13456	}
13457    }
13458
13459    TRACE((TRACE_R " OK set_character_class\n"));
13460    return (0);
13461#undef FMT
13462}
13463
13464void
13465getKeymapResources(Widget w,
13466		   const char *mapName,
13467		   const char *mapClass,
13468		   const char *type,
13469		   void *result,
13470		   size_t size)
13471{
13472    XtResource key_resources[1];
13473    key_resources[0].resource_name = XtNtranslations;
13474    key_resources[0].resource_class = XtCTranslations;
13475    key_resources[0].resource_type = (char *) type;
13476    key_resources[0].resource_size = (Cardinal) size;
13477    key_resources[0].resource_offset = 0;
13478    key_resources[0].default_type = key_resources[0].resource_type;
13479    key_resources[0].default_addr = 0;
13480    XtGetSubresources(w, (XtPointer) result, mapName, mapClass,
13481		      key_resources, (Cardinal) 1, NULL, (Cardinal) 0);
13482}
13483
13484/* ARGSUSED */
13485static void
13486HandleKeymapChange(Widget w,
13487		   XEvent *event GCC_UNUSED,
13488		   String *params,
13489		   Cardinal *param_count)
13490{
13491    static XtTranslations keymap, original;
13492
13493    TRACE(("HandleKeymapChange(%#lx, %s)\n",
13494	   (unsigned long) w,
13495	   (*param_count
13496	    ? params[0]
13497	    : "missing")));
13498
13499    if (*param_count != 1)
13500	return;
13501
13502    if (original == NULL) {
13503	TRACE(("...saving original keymap-translations\n"));
13504	original = w->core.tm.translations;
13505    }
13506
13507    if (strcmp(params[0], "None") == 0) {
13508	TRACE(("...restoring original keymap-translations\n"));
13509	XtOverrideTranslations(w, original);
13510    } else {
13511	char mapName[1000];
13512	char mapClass[1000];
13513	char *pmapName;
13514	char *pmapClass;
13515	size_t len;
13516
13517	len = strlen(params[0]) + 7;
13518
13519	pmapName = (char *) MyStackAlloc(len, mapName);
13520	pmapClass = (char *) MyStackAlloc(len, mapClass);
13521	if (pmapName == NULL
13522	    || pmapClass == NULL) {
13523	    SysError(ERROR_KMMALLOC1);
13524	} else {
13525
13526	    (void) sprintf(pmapName, "%sKeymap", params[0]);
13527	    (void) strcpy(pmapClass, pmapName);
13528	    if (islower(CharOf(pmapClass[0])))
13529		pmapClass[0] = x_toupper(pmapClass[0]);
13530	    getKeymapResources(w, pmapName, pmapClass, XtRTranslationTable,
13531			       &keymap, sizeof(keymap));
13532	    if (keymap != NULL) {
13533		TRACE(("...applying keymap \"%s\"\n", pmapName));
13534		XtOverrideTranslations(w, keymap);
13535	    } else {
13536		TRACE(("...found no match for keymap \"%s\"\n", pmapName));
13537	    }
13538
13539	    MyStackFree(pmapName, mapName);
13540	    MyStackFree(pmapClass, mapClass);
13541	}
13542    }
13543}
13544
13545/* ARGSUSED */
13546static void
13547HandleBell(Widget w GCC_UNUSED,
13548	   XEvent *event GCC_UNUSED,
13549	   String *params,	/* [0] = volume */
13550	   Cardinal *param_count)	/* 0 or 1 */
13551{
13552    int percent = (*param_count) ? atoi(params[0]) : 0;
13553
13554    Bell(term, XkbBI_TerminalBell, percent);
13555}
13556
13557/* ARGSUSED */
13558static void
13559HandleVisualBell(Widget w GCC_UNUSED,
13560		 XEvent *event GCC_UNUSED,
13561		 String *params GCC_UNUSED,
13562		 Cardinal *param_count GCC_UNUSED)
13563{
13564    VisualBell();
13565}
13566
13567/* ARGSUSED */
13568static void
13569HandleIgnore(Widget w,
13570	     XEvent *event,
13571	     String *params GCC_UNUSED,
13572	     Cardinal *param_count GCC_UNUSED)
13573{
13574    XtermWidget xw;
13575
13576    TRACE(("Handle ignore for %p %s\n",
13577	   (void *) w, visibleEventType(event->type)));
13578    if ((xw = getXtermWidget(w)) != 0) {
13579	/* do nothing, but check for funny escape sequences */
13580	switch (event->type) {
13581	case ButtonPress:
13582	case ButtonRelease:
13583	case MotionNotify:
13584	    (void) SendMousePosition(xw, event);
13585	    break;
13586	}
13587    }
13588}
13589
13590/* ARGSUSED */
13591static void
13592DoSetSelectedFont(Widget w,
13593		  XtPointer client_data GCC_UNUSED,
13594		  Atom *selection GCC_UNUSED,
13595		  Atom *type,
13596		  XtPointer value,
13597		  unsigned long *length,
13598		  int *format)
13599{
13600    XtermWidget xw = getXtermWidget(w);
13601
13602    if (xw == 0) {
13603	xtermWarning("unexpected widget in DoSetSelectedFont\n");
13604    } else if (*type != XA_STRING || *format != 8) {
13605	Bell(xw, XkbBI_MinorError, 0);
13606    } else {
13607	Boolean failed = False;
13608	int oldFont = TScreenOf(xw)->menu_font_number;
13609	char *save = TScreenOf(xw)->SelectFontName();
13610	char *val;
13611	char *test;
13612	unsigned len = (unsigned) *length;
13613	unsigned tst;
13614
13615	/*
13616	 * Some versions of X deliver null-terminated selections, some do not.
13617	 */
13618	for (tst = 0; tst < len; ++tst) {
13619	    if (((char *) value)[tst] == '\0') {
13620		len = tst;
13621		break;
13622	    }
13623	}
13624
13625	if (len > 0 && (val = TypeMallocN(char, len + 1)) != 0) {
13626	    char *used;
13627
13628	    memcpy(val, value, (size_t) len);
13629	    val[len] = '\0';
13630	    used = x_strtrim(val);
13631	    TRACE(("DoSetSelectedFont(%s)\n", used));
13632	    /* Do some sanity checking to avoid sending a long selection
13633	       back to the server in an OpenFont that is unlikely to succeed.
13634	       XLFD allows up to 255 characters and no control characters;
13635	       we are a little more liberal here. */
13636	    if (len < 1000
13637		&& used != 0
13638		&& !strchr(used, '\n')
13639		&& (test = x_strdup(used)) != 0) {
13640		TScreenOf(xw)->SelectFontName() = test;
13641		if (!xtermLoadFont(xw,
13642				   xtermFontName(used),
13643				   True,
13644				   fontMenu_fontsel)) {
13645		    failed = True;
13646		    free(test);
13647		    TScreenOf(xw)->SelectFontName() = save;
13648		}
13649	    } else {
13650		failed = True;
13651	    }
13652	    if (failed) {
13653		(void) xtermLoadFont(xw,
13654				     xtermFontName(TScreenOf(xw)->MenuFontName(oldFont)),
13655				     True,
13656				     oldFont);
13657		Bell(xw, XkbBI_MinorError, 0);
13658	    }
13659	    free(used);
13660	    free(val);
13661	}
13662    }
13663}
13664
13665void
13666FindFontSelection(XtermWidget xw, const char *atom_name, Bool justprobe)
13667{
13668    TScreen *screen = TScreenOf(xw);
13669    static AtomPtr *atoms;
13670    static unsigned int atomCount = 0;
13671    AtomPtr *pAtom;
13672    unsigned a;
13673    Atom target;
13674
13675    if (!atom_name)
13676	atom_name = ((screen->mappedSelect && atomCount)
13677		     ? screen->mappedSelect[0]
13678		     : "PRIMARY");
13679    TRACE(("FindFontSelection(%s)\n", atom_name));
13680
13681    for (pAtom = atoms, a = atomCount; a; a--, pAtom++) {
13682	if (strcmp(atom_name, XmuNameOfAtom(*pAtom)) == 0) {
13683	    TRACE(("...found atom %d:%s\n", a + 1, atom_name));
13684	    break;
13685	}
13686    }
13687    if (!a) {
13688	atoms = TypeXtReallocN(AtomPtr, atoms, atomCount + 1);
13689	*(pAtom = &atoms[atomCount]) = XmuMakeAtom(atom_name);
13690	++atomCount;
13691	TRACE(("...added atom %d:%s\n", atomCount, atom_name));
13692    }
13693
13694    target = XmuInternAtom(XtDisplay(xw), *pAtom);
13695    if (justprobe) {
13696	screen->SelectFontName() =
13697	    XGetSelectionOwner(XtDisplay(xw), target) ? _Font_Selected_ : 0;
13698	TRACE(("...selected fontname '%s'\n",
13699	       NonNull(screen->SelectFontName())));
13700    } else {
13701	XtGetSelectionValue((Widget) xw, target, XA_STRING,
13702			    DoSetSelectedFont, NULL,
13703			    XtLastTimestampProcessed(XtDisplay(xw)));
13704    }
13705    return;
13706}
13707
13708Bool
13709set_cursor_gcs(XtermWidget xw)
13710{
13711    TScreen *screen = TScreenOf(xw);
13712    VTwin *win = WhichVWin(screen);
13713
13714    Pixel cc = T_COLOR(screen, TEXT_CURSOR);
13715    Pixel fg = T_COLOR(screen, TEXT_FG);
13716    Pixel bg = T_COLOR(screen, TEXT_BG);
13717    Bool changed = False;
13718
13719    /*
13720     * Let's see, there are three things that have "color":
13721     *
13722     *     background
13723     *     text
13724     *     cursorblock
13725     *
13726     * And, there are four situations when drawing a cursor, if we decide
13727     * that we like have a solid block of cursor color with the letter
13728     * that it is highlighting shown in the background color to make it
13729     * stand out:
13730     *
13731     *     selected window, normal video - background on cursor
13732     *     selected window, reverse video - foreground on cursor
13733     *     unselected window, normal video - foreground on background
13734     *     unselected window, reverse video - background on foreground
13735     *
13736     * Since the last two are really just normalGC and reverseGC, we only
13737     * need two new GC's.  Under monochrome, we get the same effect as
13738     * above by setting cursor color to foreground.
13739     */
13740
13741    TRACE(("set_cursor_gcs cc=%#lx, fg=%#lx, bg=%#lx\n", cc, fg, bg));
13742    if (win != 0 && (cc != bg)) {
13743	Pixel xx = ((fg == cc) ? bg : cc);
13744
13745	/* set the fonts to the current one */
13746	setCgsFont(xw, win, gcVTcursNormal, 0);
13747	setCgsFont(xw, win, gcVTcursFilled, 0);
13748	setCgsFont(xw, win, gcVTcursReverse, 0);
13749	setCgsFont(xw, win, gcVTcursOutline, 0);
13750
13751	/* we have a colored cursor */
13752	setCgsFore(xw, win, gcVTcursNormal, fg);
13753	setCgsBack(xw, win, gcVTcursNormal, xx);
13754
13755	setCgsFore(xw, win, gcVTcursFilled, xx);
13756	setCgsBack(xw, win, gcVTcursFilled, fg);
13757
13758	if (screen->always_highlight) {
13759	    /* both GC's use the same color */
13760	    setCgsFore(xw, win, gcVTcursReverse, bg);
13761	    setCgsBack(xw, win, gcVTcursReverse, cc);
13762	} else {
13763	    setCgsFore(xw, win, gcVTcursReverse, bg);
13764	    setCgsBack(xw, win, gcVTcursReverse, cc);
13765	}
13766	set_cursor_outline_gc(xw, screen->always_highlight, fg, bg, cc);
13767	changed = True;
13768	FreeMarkGCs(xw);
13769    }
13770
13771    if (changed) {
13772	TRACE(("...set_cursor_gcs - done\n"));
13773    }
13774    return changed;
13775}
13776
13777/*
13778 * Build up the default translations string, allowing the user to suppress
13779 * some of the features.
13780 */
13781void
13782VTInitTranslations(void)
13783{
13784    /* *INDENT-OFF* */
13785    static struct {
13786	Boolean wanted;
13787	const char *name;
13788	const char *value;
13789    } table[] = {
13790#define DATA(name,value) { False, name, value }
13791	DATA("select",
13792"\
13793         Shift <KeyPress> Select:select-cursor-start() select-cursor-end(SELECT, CUT_BUFFER0) \n\
13794         Shift <KeyPress> Insert:insert-selection(SELECT, CUT_BUFFER0) \n\
13795"
13796	),
13797#if OPT_MAXIMIZE
13798	DATA("fullscreen",
13799"\
13800                 Alt <Key>Return:fullscreen() \n\
13801"
13802	),
13803#endif
13804#if OPT_SCROLL_LOCK
13805	DATA("scroll-lock",
13806"\
13807        <KeyRelease> Scroll_Lock:scroll-lock() \n\
13808"
13809	),
13810#endif
13811#if OPT_SHIFT_FONTS
13812	DATA("shift-fonts",
13813"\
13814    Shift~Ctrl <KeyPress> KP_Add:larger-vt-font() \n\
13815    Shift Ctrl <KeyPress> KP_Add:smaller-vt-font() \n\
13816    Shift <KeyPress> KP_Subtract:smaller-vt-font() \n\
13817"
13818	),
13819#endif
13820	DATA("paging",
13821"\
13822          Shift <KeyPress> Prior:scroll-back(1,halfpage) \n\
13823           Shift <KeyPress> Next:scroll-forw(1,halfpage) \n\
13824"
13825	),
13826	/* This must be the last set mentioning "KeyPress" */
13827	DATA("keypress",
13828"\
13829                ~Meta <KeyPress>:insert-seven-bit() \n\
13830                 Meta <KeyPress>:insert-eight-bit() \n\
13831"
13832	),
13833	DATA("popup-menu",
13834"\
13835                !Ctrl <Btn1Down>:popup-menu(mainMenu) \n\
13836           !Lock Ctrl <Btn1Down>:popup-menu(mainMenu) \n\
13837 !Lock Ctrl @Num_Lock <Btn1Down>:popup-menu(mainMenu) \n\
13838     ! @Num_Lock Ctrl <Btn1Down>:popup-menu(mainMenu) \n\
13839                !Ctrl <Btn2Down>:popup-menu(vtMenu) \n\
13840           !Lock Ctrl <Btn2Down>:popup-menu(vtMenu) \n\
13841 !Lock Ctrl @Num_Lock <Btn2Down>:popup-menu(vtMenu) \n\
13842     ! @Num_Lock Ctrl <Btn2Down>:popup-menu(vtMenu) \n\
13843                !Ctrl <Btn3Down>:popup-menu(fontMenu) \n\
13844           !Lock Ctrl <Btn3Down>:popup-menu(fontMenu) \n\
13845 !Lock Ctrl @Num_Lock <Btn3Down>:popup-menu(fontMenu) \n\
13846     ! @Num_Lock Ctrl <Btn3Down>:popup-menu(fontMenu) \n\
13847"
13848	),
13849	/* PROCURA added "Meta <Btn2Down>:clear-saved-lines()" */
13850	DATA("reset",
13851"\
13852                 Meta <Btn2Down>:clear-saved-lines() \n\
13853"
13854	),
13855	DATA("select",
13856"\
13857                ~Meta <Btn1Down>:select-start() \n\
13858              ~Meta <Btn1Motion>:select-extend() \n\
13859          ~Ctrl ~Meta <Btn2Down>:ignore() \n\
13860            ~Ctrl ~Meta <Btn2Up>:insert-selection(SELECT, CUT_BUFFER0) \n\
13861          ~Ctrl ~Meta <Btn3Down>:start-extend() \n\
13862              ~Meta <Btn3Motion>:select-extend() \n\
13863                         <BtnUp>:select-end(SELECT, CUT_BUFFER0) \n\
13864"
13865	),
13866	DATA("wheel-mouse",
13867"\
13868                 Ctrl <Btn4Down>:scroll-back(1,halfpage,m) \n\
13869            Lock Ctrl <Btn4Down>:scroll-back(1,halfpage,m) \n\
13870  Lock @Num_Lock Ctrl <Btn4Down>:scroll-back(1,halfpage,m) \n\
13871       @Num_Lock Ctrl <Btn4Down>:scroll-back(1,halfpage,m) \n\
13872                      <Btn4Down>:scroll-back(5,line,m)     \n\
13873                 Ctrl <Btn5Down>:scroll-forw(1,halfpage,m) \n\
13874            Lock Ctrl <Btn5Down>:scroll-forw(1,halfpage,m) \n\
13875  Lock @Num_Lock Ctrl <Btn5Down>:scroll-forw(1,halfpage,m) \n\
13876       @Num_Lock Ctrl <Btn5Down>:scroll-forw(1,halfpage,m) \n\
13877                      <Btn5Down>:scroll-forw(5,line,m)     \n\
13878"
13879	),
13880	DATA("pointer",
13881"\
13882                     <BtnMotion>:pointer-motion() \n\
13883                       <BtnDown>:pointer-button() \n\
13884                         <BtnUp>:pointer-button() \n\
13885"
13886	),
13887	DATA("default",
13888"\
13889                         <BtnUp>:ignore() \n\
13890"
13891	)
13892    };
13893#undef DATA
13894    /* *INDENT-ON* */
13895
13896    char *result = 0;
13897
13898    int pass;
13899    Cardinal item;
13900
13901    TRACE(("VTInitTranslations\n"));
13902    for (item = 0; item < XtNumber(table); ++item) {
13903	table[item].wanted = True;
13904    }
13905#if OPT_MAXIMIZE
13906    /*
13907     * As a special case, allow for disabling the alt-enter translation if
13908     * the resource settings prevent fullscreen from being used.  We would
13909     * do the same for scroll-lock and shift-fonts if they were application
13910     * resources too, rather than in the widget.
13911     */
13912    if (resource.fullscreen == esNever) {
13913	for (item = 0; item < XtNumber(table); ++item) {
13914	    if (!strcmp(table[item].name, "fullscreen")) {
13915		table[item].wanted = False;
13916		TRACE(("omit(%s):\n%s\n", table[item].name, table[item].value));
13917	    }
13918	}
13919    }
13920#endif
13921    if (!IsEmpty(resource.omitTranslation)) {
13922	char *value;
13923	const char *source = resource.omitTranslation;
13924
13925	while (*source != '\0' && (value = ParseList(&source)) != 0) {
13926	    size_t len = strlen(value);
13927
13928	    TRACE(("parsed:%s\n", value));
13929	    for (item = 0; item < XtNumber(table); ++item) {
13930		if (strlen(table[item].name) >= len
13931		    && x_strncasecmp(table[item].name,
13932				     value,
13933				     (unsigned) len) == 0) {
13934		    table[item].wanted = False;
13935		    TRACE(("omit(%s):\n%s\n", table[item].name, table[item].value));
13936		    /* continue: "select", for instance is two chunks */
13937		}
13938	    }
13939	    free(value);
13940	}
13941    }
13942
13943    for (pass = 0; pass < 2; ++pass) {
13944	size_t needed = 0;
13945	for (item = 0; item < XtNumber(table); ++item) {
13946	    if (table[item].wanted) {
13947		if (pass) {
13948		    strcat(result, table[item].value);
13949		} else {
13950		    needed += strlen(table[item].value) + 1;
13951		}
13952	    }
13953	}
13954	if (!pass) {
13955	    result = XtMalloc((Cardinal) needed);
13956	    *result = '\0';
13957	}
13958    }
13959
13960    TRACE(("result:\n%s\n", result));
13961
13962    defaultTranslations = result;
13963    free((void *) xtermClassRec.core_class.tm_table);
13964    xtermClassRec.core_class.tm_table = result;
13965}
13966
13967#ifdef NO_LEAKS
13968void
13969noleaks_charproc(void)
13970{
13971    free(v_buffer);
13972}
13973#endif
13974