charproc.c revision ae137402
1/* $XTermId: charproc.c,v 1.1832 2021/06/07 19:51:06 tom Exp $ */
2
3/*
4 * Copyright 1999-2020,2021 by Thomas E. Dickey
5 *
6 *                         All Rights Reserved
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the
10 * "Software"), to deal in the Software without restriction, including
11 * without limitation the rights to use, copy, modify, merge, publish,
12 * distribute, sublicense, and/or sell copies of the Software, and to
13 * permit persons to whom the Software is furnished to do so, subject to
14 * the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
23 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 *
27 * Except as contained in this notice, the name(s) of the above copyright
28 * holders shall not be used in advertising or otherwise to promote the
29 * sale, use or other dealings in this Software without prior written
30 * authorization.
31 *
32 *
33 * Copyright 1988  X Consortium
34 *
35 * Permission to use, copy, modify, distribute, and sell this software and its
36 * documentation for any purpose is hereby granted without fee, provided that
37 * the above copyright notice appear in all copies and that both that
38 * copyright notice and this permission notice appear in supporting
39 * documentation.
40 *
41 * The above copyright notice and this permission notice shall be included in
42 * all copies or substantial portions of the Software.
43 *
44 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
45 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
46 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
47 * OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
48 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
49 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
50 *
51 * Except as contained in this notice, the name of the X Consortium shall not be
52 * used in advertising or otherwise to promote the sale, use or other dealings
53 * in this Software without prior written authorization from the X Consortium.
54 *
55 */
56/*
57 * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
58 *
59 *                         All Rights Reserved
60 *
61 * Permission to use, copy, modify, and distribute this software and its
62 * documentation for any purpose and without fee is hereby granted,
63 * provided that the above copyright notice appear in all copies and that
64 * both that copyright notice and this permission notice appear in
65 * supporting documentation, and that the name of Digital Equipment
66 * Corporation not be used in advertising or publicity pertaining to
67 * distribution of the software without specific, written prior permission.
68 *
69 *
70 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
71 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
72 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
73 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
74 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
75 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
76 * SOFTWARE.
77 */
78
79/* charproc.c */
80
81#include <version.h>
82#include <xterm.h>
83
84#include <X11/Xatom.h>
85#include <X11/Xutil.h>
86#include <X11/Xmu/Atoms.h>
87#include <X11/Xmu/CharSet.h>
88#include <X11/Xmu/Converters.h>
89
90#if OPT_INPUT_METHOD
91
92#if defined(HAVE_LIB_XAW)
93#include <X11/Xaw/XawImP.h>
94#elif defined(HAVE_LIB_XAW3D)
95#include <X11/Xaw3d/XawImP.h>
96#elif defined(HAVE_LIB_XAW3DXFT)
97#include <X11/Xaw3dxft/XawImP.h>
98#elif defined(HAVE_LIB_NEXTAW)
99#include <X11/neXtaw/XawImP.h>
100#elif defined(HAVE_LIB_XAWPLUS)
101#include <X11/XawPlus/XawImP.h>
102#endif
103
104#endif
105
106#if OPT_WIDE_CHARS
107#include <xutf8.h>
108#include <wcwidth.h>
109#include <precompose.h>
110#ifdef HAVE_LANGINFO_CODESET
111#include <langinfo.h>
112#endif
113#endif
114
115#if USE_DOUBLE_BUFFER
116#include <X11/extensions/Xdbe.h>
117#endif
118
119#include <stdio.h>
120#include <ctype.h>
121#include <assert.h>
122
123#if defined(HAVE_SCHED_YIELD)
124#include <sched.h>
125#endif
126
127#include <VTparse.h>
128#include <data.h>
129#include <error.h>
130#include <menu.h>
131#include <main.h>
132#include <fontutils.h>
133#include <charclass.h>
134#include <xstrings.h>
135#include <graphics.h>
136
137#ifdef NO_LEAKS
138#include <xtermcap.h>
139#endif
140
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_SCREEN_DUMPS
343    { "dump-html",	        HandleDumpHtml },
344    { "dump-svg",	        HandleDumpSvg },
345#endif
346#if OPT_EXEC_XTERM
347    { "spawn-new-terminal",	HandleSpawnTerminal },
348#endif
349#if OPT_HP_FUNC_KEYS
350    { "set-hp-function-keys",	HandleHpFunctionKeys },
351#endif
352#if OPT_LOAD_VTFONTS
353    { "load-vt-fonts",		HandleLoadVTFonts },
354#endif
355#if OPT_MAXIMIZE
356    { "deiconify",		HandleDeIconify },
357    { "fullscreen",		HandleFullscreen },
358    { "iconify",		HandleIconify },
359    { "maximize",		HandleMaximize },
360    { "restore",		HandleRestoreSize },
361#endif
362#if OPT_NUM_LOCK
363    { "alt-sends-escape",	HandleAltEsc },
364    { "meta-sends-escape",	HandleMetaEsc },
365    { "set-num-lock",		HandleNumLock },
366#endif
367#ifdef OPT_PRINT_ON_EXIT
368    { "print-immediate",	HandlePrintImmediate },
369    { "print-on-error",		HandlePrintOnError },
370#endif
371#if OPT_READLINE
372    { "readline-button",	ReadLineButton },
373#endif
374#if OPT_RENDERFONT
375    { "set-render-font",	HandleRenderFont },
376#endif
377#if OPT_SCO_FUNC_KEYS
378    { "set-sco-function-keys",	HandleScoFunctionKeys },
379#endif
380#if OPT_SCROLL_LOCK
381    { "scroll-lock",		HandleScrollLock },
382#endif
383#if OPT_SELECTION_OPS
384    { "exec-formatted",		HandleExecFormatted },
385    { "exec-selectable",	HandleExecSelectable },
386    { "insert-formatted",	HandleInsertFormatted },
387    { "insert-selectable",	HandleInsertSelectable },
388#endif
389#if OPT_SHIFT_FONTS
390    { "larger-vt-font",		HandleLargerFont },
391    { "smaller-vt-font",	HandleSmallerFont },
392#endif
393#if OPT_SIXEL_GRAPHICS
394    { "set-sixel-scrolling",	HandleSixelScrolling },
395#endif
396#if OPT_GRAPHICS
397    { "set-private-colors",	HandleSetPrivateColorRegisters },
398#endif
399#if OPT_SUN_FUNC_KEYS
400    { "set-sun-function-keys",	HandleSunFunctionKeys },
401#endif
402#if OPT_TEK4014
403    { "set-terminal-type",	HandleSetTerminalType },
404    { "set-visibility",		HandleVisibility },
405    { "set-tek-text",		HandleSetTekText },
406    { "tek-page",		HandleTekPage },
407    { "tek-reset",		HandleTekReset },
408    { "tek-copy",		HandleTekCopy },
409#endif
410#if OPT_TOOLBAR
411    { "set-toolbar",		HandleToolbar },
412#endif
413#if OPT_WIDE_CHARS
414    { "set-utf8-mode",		HandleUTF8Mode },
415    { "set-utf8-fonts",		HandleUTF8Fonts },
416    { "set-utf8-title",		HandleUTF8Title },
417#endif
418};
419/* *INDENT-ON* */
420
421#define SPS screen.printer_state
422
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    Bres(XtNcdXtraScroll, XtCCdXtraScroll, misc.cdXtraScroll, False),
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    Bres(XtNtiXtraScroll, XtCTiXtraScroll, misc.tiXtraScroll, False),
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#if !OPT_COLOR_RES2
687#if OPT_256_COLORS
688# include <256colres.h>
689#elif OPT_88_COLORS
690# include <88colres.h>
691#endif
692#endif				/* !OPT_COLOR_RES2 */
693
694#endif				/* OPT_ISO_COLORS */
695
696    CLICK_RES("2", screen.onClick[1], "word"),
697    CLICK_RES("3", screen.onClick[2], "line"),
698    CLICK_RES("4", screen.onClick[3], 0),
699    CLICK_RES("5", screen.onClick[4], 0),
700
701    Sres(XtNshiftEscape, XtCShiftEscape, keyboard.shift_escape_s, "false"),
702
703#if OPT_MOD_FKEYS
704    Ires(XtNmodifyKeyboard, XtCModifyKeyboard,
705	 keyboard.modify_1st.allow_keys, 0),
706    Ires(XtNmodifyCursorKeys, XtCModifyCursorKeys,
707	 keyboard.modify_1st.cursor_keys, 2),
708    Ires(XtNmodifyFunctionKeys, XtCModifyFunctionKeys,
709	 keyboard.modify_1st.function_keys, 2),
710    Ires(XtNmodifyKeypadKeys, XtCModifyKeypadKeys,
711	 keyboard.modify_1st.keypad_keys, 0),
712    Ires(XtNmodifyOtherKeys, XtCModifyOtherKeys,
713	 keyboard.modify_1st.other_keys, 0),
714    Ires(XtNmodifyStringKeys, XtCModifyStringKeys,
715	 keyboard.modify_1st.string_keys, 0),
716    Ires(XtNformatOtherKeys, XtCFormatOtherKeys,
717	 keyboard.format_keys, 0),
718#endif
719
720#if OPT_NUM_LOCK
721    Bres(XtNalwaysUseMods, XtCAlwaysUseMods, misc.alwaysUseMods, False),
722    Bres(XtNnumLock, XtCNumLock, misc.real_NumLock, True),
723#endif
724
725#if OPT_PRINT_COLORS
726    Ires(XtNprintAttributes, XtCPrintAttributes, SPS.print_attributes, 1),
727#endif
728
729#if OPT_REGIS_GRAPHICS
730    Sres(XtNregisDefaultFont, XtCRegisDefaultFont,
731	 screen.graphics_regis_default_font, ""),
732    Sres(XtNregisScreenSize, XtCRegisScreenSize,
733	 screen.graphics_regis_screensize, "auto"),
734#endif
735
736#if OPT_GRAPHICS
737    Sres(XtNdecGraphicsID, XtCDecGraphicsID, screen.graph_termid, DFT_DECID),
738    Sres(XtNmaxGraphicSize, XtCMaxGraphicSize, screen.graphics_max_size,
739	 "1000x1000"),
740#endif
741
742#if OPT_SHIFT_FONTS
743    Bres(XtNshiftFonts, XtCShiftFonts, misc.shift_fonts, True),
744#endif
745
746#if OPT_SIXEL_GRAPHICS
747    Bres(XtNsixelScrolling, XtCSixelScrolling, screen.sixel_scrolling, True),
748    Bres(XtNsixelScrollsRight, XtCSixelScrollsRight,
749	 screen.sixel_scrolls_right, False),
750#endif
751
752#if OPT_GRAPHICS
753    Ires(XtNnumColorRegisters, XtCNumColorRegisters,
754	 screen.numcolorregisters, 0),
755    Bres(XtNprivateColorRegisters, XtCPrivateColorRegisters,
756	 screen.privatecolorregisters, True),
757#endif
758
759#if OPT_SUNPC_KBD
760    Ires(XtNctrlFKeys, XtCCtrlFKeys, misc.ctrl_fkeys, 10),
761#endif
762
763#if OPT_TEK4014
764    Bres(XtNtekInhibit, XtCTekInhibit, misc.tekInhibit, False),
765    Bres(XtNtekSmall, XtCTekSmall, misc.tekSmall, False),
766    Bres(XtNtekStartup, XtCTekStartup, misc.TekEmu, False),
767#endif
768
769#if OPT_TOOLBAR
770    Wres(XtNmenuBar, XtCMenuBar, VT100_TB_INFO(menu_bar), 0),
771    Ires(XtNmenuHeight, XtCMenuHeight, VT100_TB_INFO(menu_height), 25),
772#endif
773
774#if OPT_WIDE_CHARS
775    Bres(XtNcjkWidth, XtCCjkWidth, misc.cjk_width, False),
776    Bres(XtNmkWidth, XtCMkWidth, misc.mk_width, False),
777    Bres(XtNprecompose, XtCPrecompose, screen.normalized_c, True),
778    Bres(XtNutf8Latin1, XtCUtf8Latin1, screen.utf8_latin1, False),
779    Bres(XtNutf8Weblike, XtCUtf8Weblike, screen.utf8_weblike, False),
780    Bres(XtNvt100Graphics, XtCVT100Graphics, screen.vt100_graphics, True),
781    Bres(XtNwideChars, XtCWideChars, screen.wide_chars, False),
782    Ires(XtNcombiningChars, XtCCombiningChars, screen.max_combining, 2),
783    Ires(XtNmkSamplePass, XtCMkSamplePass, misc.mk_samplepass, 655),
784    Ires(XtNmkSampleSize, XtCMkSampleSize, misc.mk_samplesize, 65536),
785    Sres(XtNutf8, XtCUtf8, screen.utf8_mode_s, "default"),
786    Sres(XtNutf8Fonts, XtCUtf8Fonts, screen.utf8_fonts_s, "default"),
787    Sres(XtNutf8Title, XtCUtf8Title, screen.utf8_title_s, "default"),
788    Sres(XtNwideBoldFont, XtCWideBoldFont, misc.default_font.f_wb, DEFWIDEBOLDFONT),
789    Sres(XtNwideFont, XtCWideFont, misc.default_font.f_w, DEFWIDEFONT),
790    Sres(XtNutf8SelectTypes, XtCUtf8SelectTypes, screen.utf8_select_types, NULL),
791#endif
792
793#if OPT_LUIT_PROG
794    Sres(XtNlocale, XtCLocale, misc.locale_str, "medium"),
795    Sres(XtNlocaleFilter, XtCLocaleFilter, misc.localefilter, DEFLOCALEFILTER),
796#endif
797
798#if OPT_INPUT_METHOD
799    Sres(XtNximFont, XtCXimFont, misc.f_x, DEFXIMFONT),
800#endif
801
802#if OPT_SCROLL_LOCK
803    Bres(XtNallowScrollLock, XtCAllowScrollLock, screen.allowScrollLock0, False),
804    Bres(XtNautoScrollLock, XtCAutoScrollLock, screen.autoScrollLock, False),
805#endif
806
807    /* these are used only for testing ncurses, not in the manual page */
808#if OPT_XMC_GLITCH
809    Bres(XtNxmcInline, XtCXmcInline, screen.xmc_inline, False),
810    Bres(XtNxmcMoveSGR, XtCXmcMoveSGR, screen.move_sgr_ok, True),
811    Ires(XtNxmcAttributes, XtCXmcAttributes, screen.xmc_attributes, 1),
812    Ires(XtNxmcGlitch, XtCXmcGlitch, screen.xmc_glitch, 0),
813#endif
814
815#ifdef SCROLLBAR_RIGHT
816    Bres(XtNrightScrollBar, XtCRightScrollBar, misc.useRight, False),
817#endif
818
819#if OPT_RENDERFONT
820    Bres(XtNforceXftHeight, XtCForceXftHeight, screen.force_xft_height, False),
821#define RES_FACESIZE(n) Dres(XtNfaceSize #n, XtCFaceSize #n, misc.face_size[n], "0.0")
822    RES_FACESIZE(1),
823    RES_FACESIZE(2),
824    RES_FACESIZE(3),
825    RES_FACESIZE(4),
826    RES_FACESIZE(5),
827    RES_FACESIZE(6),
828    Dres(XtNfaceSize, XtCFaceSize, misc.face_size[0], DEFFACESIZE),
829    Sres(XtNfaceName, XtCFaceName, misc.default_xft.f_n, DEFFACENAME),
830    Sres(XtNrenderFont, XtCRenderFont, misc.render_font_s, "default"),
831    Ires(XtNlimitFontsets, XtCLimitFontsets, misc.limit_fontsets, DEF_XFT_CACHE),
832#if OPT_RENDERWIDE
833    Sres(XtNfaceNameDoublesize, XtCFaceNameDoublesize, misc.default_xft.f_w, DEFFACENAME),
834#endif
835#endif
836};
837
838static Boolean VTSetValues(Widget cur, Widget request, Widget new_arg,
839			   ArgList args, Cardinal *num_args);
840static void VTClassInit(void);
841static void VTDestroy(Widget w);
842static void VTExpose(Widget w, XEvent *event, Region region);
843static void VTInitialize(Widget wrequest, Widget new_arg, ArgList args,
844			 Cardinal *num_args);
845static void VTRealize(Widget w, XtValueMask * valuemask,
846		      XSetWindowAttributes * values);
847static void VTResize(Widget w);
848
849#if OPT_INPUT_METHOD
850static void VTInitI18N(XtermWidget);
851#endif
852
853#ifdef VMS
854globaldef {
855    "xtermclassrec"
856} noshare
857
858#else
859static
860#endif				/* VMS */
861WidgetClassRec xtermClassRec =
862{
863    {
864	/* core_class fields */
865	(WidgetClass) & widgetClassRec,		/* superclass   */
866	"VT100",		/* class_name                   */
867	sizeof(XtermWidgetRec),	/* widget_size                  */
868	VTClassInit,		/* class_initialize             */
869	NULL,			/* class_part_initialize        */
870	False,			/* class_inited                 */
871	VTInitialize,		/* initialize                   */
872	NULL,			/* initialize_hook              */
873	VTRealize,		/* realize                      */
874	actionsList,		/* actions                      */
875	XtNumber(actionsList),	/* num_actions                  */
876	xterm_resources,	/* resources                    */
877	XtNumber(xterm_resources),	/* num_resources        */
878	NULLQUARK,		/* xrm_class                    */
879	True,			/* compress_motion              */
880	False,			/* compress_exposure            */
881	True,			/* compress_enterleave          */
882	False,			/* visible_interest             */
883	VTDestroy,		/* destroy                      */
884	VTResize,		/* resize                       */
885	VTExpose,		/* expose                       */
886	VTSetValues,		/* set_values                   */
887	NULL,			/* set_values_hook              */
888	XtInheritSetValuesAlmost,	/* set_values_almost    */
889	NULL,			/* get_values_hook              */
890	NULL,			/* accept_focus                 */
891	XtVersion,		/* version                      */
892	NULL,			/* callback_offsets             */
893	0,			/* tm_table                     */
894	XtInheritQueryGeometry,	/* query_geometry               */
895	XtInheritDisplayAccelerator,	/* display_accelerator  */
896	NULL			/* extension                    */
897    }
898};
899
900#ifdef VMS
901globaldef {
902    "xtermwidgetclass"
903}
904noshare
905#endif /* VMS */
906WidgetClass xtermWidgetClass = (WidgetClass) & xtermClassRec;
907
908/*
909 * Add input-actions for widgets that are overlooked (scrollbar and toolbar):
910 *
911 *	a) Sometimes the scrollbar passes through translations, sometimes it
912 *	   doesn't.  We add the KeyPress translations here, just to be sure.
913 *	b) In the normal (non-toolbar) configuration, the xterm widget covers
914 *	   almost all of the window.  With a toolbar, there's a relatively
915 *	   large area that the user would expect to enter keystrokes since the
916 *	   program can get the focus.
917 */
918void
919xtermAddInput(Widget w)
920{
921    /* *INDENT-OFF* */
922    XtActionsRec input_actions[] = {
923	{ "insert",		    HandleKeyPressed }, /* alias */
924	{ "insert-eight-bit",	    HandleEightBitKeyPressed },
925	{ "insert-seven-bit",	    HandleKeyPressed },
926	{ "pointer-motion",	    HandlePointerMotion },
927	{ "pointer-button",	    HandlePointerButton },
928	{ "secure",		    HandleSecure },
929	{ "string",		    HandleStringEvent },
930	{ "scroll-back",	    HandleScrollBack },
931	{ "scroll-forw",	    HandleScrollForward },
932	{ "scroll-to",		    HandleScrollTo },
933	{ "select-cursor-end",	    HandleKeyboardSelectEnd },
934	{ "select-cursor-extend",   HandleKeyboardSelectExtend },
935	{ "select-cursor-start",    HandleKeyboardSelectStart },
936	{ "insert-selection",	    HandleInsertSelection },
937	{ "select-start",	    HandleSelectStart },
938	{ "select-extend",	    HandleSelectExtend },
939	{ "start-extend",	    HandleStartExtend },
940	{ "select-end",		    HandleSelectEnd },
941	{ "clear-saved-lines",	    HandleClearSavedLines },
942	{ "popup-menu",		    HandlePopupMenu },
943	{ "bell",		    HandleBell },
944	{ "ignore",		    HandleIgnore },
945#if OPT_DABBREV
946	{ "dabbrev-expand",	    HandleDabbrevExpand },
947#endif
948#if OPT_MAXIMIZE
949	{ "fullscreen",		    HandleFullscreen },
950#endif
951#if OPT_SCROLL_LOCK
952	{ "scroll-lock",	    HandleScrollLock },
953#endif
954#if OPT_SHIFT_FONTS
955	{ "larger-vt-font",	    HandleLargerFont },
956	{ "smaller-vt-font",	    HandleSmallerFont },
957#endif
958    };
959    /* *INDENT-ON* */
960
961    TRACE_TRANS("BEFORE", w);
962    XtAppAddActions(app_con, input_actions, XtNumber(input_actions));
963    XtAugmentTranslations(w, XtParseTranslationTable(defaultTranslations));
964    TRACE_TRANS("AFTER:", w);
965
966#if OPT_EXTRA_PASTE
967    if (term && term->keyboard.extra_translations)
968	XtOverrideTranslations((Widget) term, XtParseTranslationTable(term->keyboard.extra_translations));
969#endif
970}
971
972#if OPT_ISO_COLORS
973#ifdef EXP_BOGUS_FG
974static Bool
975CheckBogusForeground(TScreen *screen, const char *tag)
976{
977    int row = -1, col = -1, pass;
978    Bool isClear = True;
979
980    (void) tag;
981    for (pass = 0; pass < 2; ++pass) {
982	row = screen->cur_row;
983	for (; isClear && (row <= screen->max_row); ++row) {
984	    CLineData *ld = getLineData(screen, row);
985
986	    if (ld != 0) {
987		IAttr *attribs = ld->attribs;
988
989		col = (row == screen->cur_row) ? screen->cur_col : 0;
990		for (; isClear && (col <= screen->max_col); ++col) {
991		    unsigned flags = attribs[col];
992		    if (pass) {
993			flags &= ~FG_COLOR;
994			attribs[col] = (IAttr) flags;
995		    } else if ((flags & BG_COLOR)) {
996			isClear = False;
997		    } else if ((flags & FG_COLOR)) {
998			unsigned ch = ld->charData[col];
999			isClear = ((ch == ' ') || (ch == 0));
1000		    } else {
1001			isClear = False;
1002		    }
1003		}
1004	    }
1005	}
1006    }
1007    TRACE(("%s checked %d,%d to %d,%d %s pass %d\n",
1008	   tag, screen->cur_row, screen->cur_col,
1009	   row, col,
1010	   isClear && pass ? "cleared" : "unchanged",
1011	   pass));
1012
1013    return isClear;
1014}
1015#endif
1016
1017/*
1018 * The terminal's foreground and background colors are set via two mechanisms:
1019 *	text (cur_foreground, cur_background values that are passed down to
1020 *		XDrawImageString and XDrawString)
1021 *	area (X11 graphics context used in XClearArea and XFillRectangle)
1022 */
1023void
1024SGR_Foreground(XtermWidget xw, int color)
1025{
1026    TScreen *screen = TScreenOf(xw);
1027    Pixel fg;
1028
1029    if (color >= 0) {
1030	UIntSet(xw->flags, FG_COLOR);
1031    } else {
1032	UIntClr(xw->flags, FG_COLOR);
1033    }
1034    fg = getXtermFG(xw, xw->flags, color);
1035    xw->cur_foreground = color;
1036
1037    setCgsFore(xw, WhichVWin(screen), gcNorm, fg);
1038    setCgsBack(xw, WhichVWin(screen), gcNormReverse, fg);
1039
1040    setCgsFore(xw, WhichVWin(screen), gcBold, fg);
1041    setCgsBack(xw, WhichVWin(screen), gcBoldReverse, fg);
1042
1043#ifdef EXP_BOGUS_FG
1044    /*
1045     * If we've just turned off the foreground color, check for blank cells
1046     * which have no background color, but do have foreground color.  This
1047     * could happen due to setting the foreground color just before scrolling.
1048     *
1049     * Those cells look uncolored, but will confuse ShowCursor(), which looks
1050     * for the colors in the current cell, and will see the foreground color.
1051     * In that case, remove the foreground color from the blank cells.
1052     */
1053    if (color < 0) {
1054	CheckBogusForeground(screen, "SGR_Foreground");
1055    }
1056#endif
1057}
1058
1059void
1060SGR_Background(XtermWidget xw, int color)
1061{
1062    TScreen *screen = TScreenOf(xw);
1063    Pixel bg;
1064
1065    /*
1066     * An indexing operation may have set screen->scroll_amt, which would
1067     * normally result in calling FlushScroll() in WriteText().  However,
1068     * if we're changing the background color now, then the new value
1069     * should not apply to the pending blank lines.
1070     */
1071    if (screen->scroll_amt && (color != xw->cur_background))
1072	FlushScroll(xw);
1073
1074    if (color >= 0) {
1075	UIntSet(xw->flags, BG_COLOR);
1076    } else {
1077	UIntClr(xw->flags, BG_COLOR);
1078    }
1079    bg = getXtermBG(xw, xw->flags, color);
1080    xw->cur_background = color;
1081
1082    setCgsBack(xw, WhichVWin(screen), gcNorm, bg);
1083    setCgsFore(xw, WhichVWin(screen), gcNormReverse, bg);
1084
1085    setCgsBack(xw, WhichVWin(screen), gcBold, bg);
1086    setCgsFore(xw, WhichVWin(screen), gcBoldReverse, bg);
1087}
1088
1089/* Invoked after updating bold/underline flags, computes the extended color
1090 * index to use for foreground.  (See also 'extract_fg()').
1091 */
1092static void
1093setExtendedFG(XtermWidget xw)
1094{
1095    int fg = xw->sgr_foreground;
1096
1097    if (TScreenOf(xw)->colorAttrMode
1098	|| (fg < 0)) {
1099	fg = MapToColorMode(fg, TScreenOf(xw), xw->flags);
1100    }
1101
1102    /* This implements the IBM PC-style convention of 8-colors, with one
1103     * bit for bold, thus mapping the 0-7 codes to 8-15.  It won't make
1104     * much sense for 16-color applications, but we keep it to retain
1105     * compatibility with ANSI-color applications.
1106     */
1107#if OPT_PC_COLORS		/* XXXJTL should be settable at runtime (resource or OSC?) */
1108    if (TScreenOf(xw)->boldColors
1109	&& (!xw->sgr_38_xcolors)
1110	&& (fg >= 0)
1111	&& (fg < 8)
1112	&& (xw->flags & BOLD))
1113	fg |= 8;
1114#endif
1115
1116    SGR_Foreground(xw, fg);
1117}
1118
1119/* Invoked after updating inverse flag, computes the extended color
1120 * index to use for background.  (See also 'extract_bg()').
1121 */
1122static void
1123setExtendedBG(XtermWidget xw)
1124{
1125    int bg = xw->sgr_background;
1126
1127    if (TScreenOf(xw)->colorAttrMode
1128	|| (bg < 0)) {
1129	if (TScreenOf(xw)->colorRVMode && (xw->flags & INVERSE))
1130	    bg = COLOR_RV;
1131    }
1132
1133    SGR_Background(xw, bg);
1134}
1135
1136void
1137setExtendedColors(XtermWidget xw)
1138{
1139    setExtendedFG(xw);
1140    setExtendedBG(xw);
1141}
1142
1143static void
1144reset_SGR_Foreground(XtermWidget xw)
1145{
1146    xw->sgr_foreground = -1;
1147    xw->sgr_38_xcolors = False;
1148    clrDirectFG(xw->flags);
1149    setExtendedFG(xw);
1150}
1151
1152static void
1153reset_SGR_Background(XtermWidget xw)
1154{
1155    xw->sgr_background = -1;
1156    clrDirectBG(xw->flags);
1157    setExtendedBG(xw);
1158}
1159
1160static void
1161reset_SGR_Colors(XtermWidget xw)
1162{
1163    reset_SGR_Foreground(xw);
1164    reset_SGR_Background(xw);
1165}
1166#endif /* OPT_ISO_COLORS */
1167
1168#if OPT_WIDE_ATTRS
1169/*
1170 * Call this before changing the state of ATR_ITALIC, to update the GC fonts.
1171 */
1172static void
1173setItalicFont(XtermWidget xw, Bool enable)
1174{
1175    if (enable) {
1176	if ((xw->flags & ATR_ITALIC) == 0) {
1177	    xtermLoadItalics(xw);
1178	    TRACE(("setItalicFont: enabling Italics\n"));
1179	    xtermUpdateFontGCs(xw, getItalicFont);
1180	}
1181    } else if ((xw->flags & ATR_ITALIC) != 0) {
1182	TRACE(("setItalicFont: disabling Italics\n"));
1183	xtermUpdateFontGCs(xw, getNormalFont);
1184    }
1185}
1186
1187static void
1188ResetItalics(XtermWidget xw)
1189{
1190    setItalicFont(xw, False);
1191    UIntClr(xw->flags, ATR_ITALIC);
1192}
1193
1194#else
1195#define ResetItalics(xw)	/* nothing */
1196#endif
1197
1198static void
1199initCharset(TScreen *screen, int which, DECNRCM_codes code)
1200{
1201    screen->gsets[which] = code;
1202}
1203
1204void
1205saveCharsets(TScreen *screen, DECNRCM_codes * target)
1206{
1207    int g;
1208    for (g = 0; g < NUM_GSETS; ++g) {
1209	target[g] = screen->gsets[g];
1210    }
1211}
1212
1213void
1214restoreCharsets(TScreen *screen, DECNRCM_codes * source)
1215{
1216    int g;
1217    for (g = 0; g < NUM_GSETS; ++g) {
1218	screen->gsets[g] = source[g];
1219    }
1220}
1221
1222void
1223resetCharsets(TScreen *screen)
1224{
1225    TRACE(("resetCharsets\n"));
1226
1227    initCharset(screen, 0, nrc_ASCII);
1228    initCharset(screen, 1, nrc_ASCII);
1229    initCharset(screen, 2, nrc_ASCII);
1230    initCharset(screen, 3, nrc_ASCII);
1231
1232    screen->curgl = 0;		/* G0 => GL.            */
1233    screen->curgr = 2;		/* G2 => GR.            */
1234    screen->curss = 0;		/* No single shift.     */
1235
1236#if OPT_VT52_MODE
1237    if (screen->vtXX_level == 0)
1238	initCharset(screen, 1, nrc_DEC_Spec_Graphic);	/* Graphics */
1239#endif
1240}
1241
1242static void
1243modified_DECNRCM(XtermWidget xw)
1244{
1245#if OPT_WIDE_CHARS
1246    TScreen *screen = TScreenOf(xw);
1247    if (screen->wide_chars && (screen->utf8_mode || screen->utf8_nrc_mode)) {
1248	int enabled = ((xw->flags & NATIONAL) != 0);
1249	int modefix;
1250	EXCHANGE(screen->utf8_nrc_mode, screen->utf8_mode, modefix);
1251	switchPtyData(screen, !enabled);
1252	TRACE(("UTF8 mode temporarily %s\n", enabled ? "ON" : "OFF"));
1253    }
1254#else
1255    (void) xw;
1256#endif
1257}
1258
1259/*
1260 * VT300 and up support three ANSI conformance levels, defined according to
1261 * the dpANSI X3.134.1 standard.  DEC's manuals equate levels 1 and 2, and
1262 * are unclear.  This code is written based on the manuals.
1263 */
1264static void
1265set_ansi_conformance(TScreen *screen, int level)
1266{
1267    TRACE(("set_ansi_conformance(%d) dec_level %d:%d, ansi_level %d\n",
1268	   level,
1269	   screen->vtXX_level * 100,
1270	   screen->terminal_id,
1271	   screen->ansi_level));
1272    if (screen->vtXX_level >= 3) {
1273	switch (screen->ansi_level = level) {
1274	case 1:
1275	    /* FALLTHRU */
1276	case 2:
1277	    initCharset(screen, 0, nrc_ASCII);	/* G0 is ASCII */
1278	    initCharset(screen, 1, nrc_ASCII);	/* G1 is ISO Latin-1 */
1279	    screen->curgl = 0;
1280	    screen->curgr = 1;
1281	    break;
1282	case 3:
1283	    initCharset(screen, 0, nrc_ASCII);	/* G0 is ASCII */
1284	    screen->curgl = 0;
1285	    break;
1286	}
1287    }
1288}
1289
1290/*
1291 * Set scrolling margins.  VTxxx terminals require that the top/bottom are
1292 * different, so we have at least two lines in the scrolling region.
1293 */
1294static void
1295set_tb_margins(TScreen *screen, int top, int bottom)
1296{
1297    TRACE(("set_tb_margins %d..%d, prior %d..%d\n",
1298	   top, bottom,
1299	   screen->top_marg,
1300	   screen->bot_marg));
1301    if (bottom > top) {
1302	screen->top_marg = top;
1303	screen->bot_marg = bottom;
1304    }
1305    if (screen->top_marg > screen->max_row)
1306	screen->top_marg = screen->max_row;
1307    if (screen->bot_marg > screen->max_row)
1308	screen->bot_marg = screen->max_row;
1309}
1310
1311static void
1312set_lr_margins(TScreen *screen, int left, int right)
1313{
1314    TRACE(("set_lr_margins %d..%d, prior %d..%d\n",
1315	   left, right,
1316	   screen->lft_marg,
1317	   screen->rgt_marg));
1318    if (right > left) {
1319	screen->lft_marg = left;
1320	screen->rgt_marg = right;
1321    }
1322    if (screen->lft_marg > screen->max_col)
1323	screen->lft_marg = screen->max_col;
1324    if (screen->rgt_marg > screen->max_col)
1325	screen->rgt_marg = screen->max_col;
1326}
1327
1328#define reset_tb_margins(screen) set_tb_margins(screen, 0, screen->max_row)
1329#define reset_lr_margins(screen) set_lr_margins(screen, 0, screen->max_col)
1330
1331void
1332resetMargins(XtermWidget xw)
1333{
1334    TScreen *screen = TScreenOf(xw);
1335
1336    UIntClr(xw->flags, LEFT_RIGHT);
1337    reset_tb_margins(screen);
1338    reset_lr_margins(screen);
1339}
1340
1341static void
1342resetRendition(XtermWidget xw)
1343{
1344    TScreen *screen = TScreenOf(xw);
1345    (void) screen;
1346    ResetItalics(xw);
1347    UIntClr(xw->flags,
1348	    (SGR_MASK | SGR_MASK2 | INVISIBLE));
1349}
1350
1351void
1352set_max_col(TScreen *screen, int cols)
1353{
1354    TRACE(("set_max_col %d, prior %d\n", cols, screen->max_col));
1355    if (cols < 0)
1356	cols = 0;
1357    screen->max_col = cols;
1358}
1359
1360void
1361set_max_row(TScreen *screen, int rows)
1362{
1363    TRACE(("set_max_row %d, prior %d\n", rows, screen->max_row));
1364    if (rows < 0)
1365	rows = 0;
1366    screen->max_row = rows;
1367}
1368
1369#if OPT_MOD_FKEYS
1370static void
1371set_mod_fkeys(XtermWidget xw, int which, int what, Bool enabled)
1372{
1373#define SET_MOD_FKEYS(field) \
1374    xw->keyboard.modify_now.field = ((what == DEFAULT) && enabled) \
1375				     ? xw->keyboard.modify_1st.field \
1376				     : what; \
1377    TRACE(("set modify_now.%s to %d\n", #field, \
1378	   xw->keyboard.modify_now.field));
1379
1380    switch (which) {
1381    case 0:
1382	SET_MOD_FKEYS(allow_keys);
1383	break;
1384    case 1:
1385	SET_MOD_FKEYS(cursor_keys);
1386	break;
1387    case 2:
1388	SET_MOD_FKEYS(function_keys);
1389	break;
1390    case 3:
1391	SET_MOD_FKEYS(keypad_keys);
1392	break;
1393    case 4:
1394	SET_MOD_FKEYS(other_keys);
1395	break;
1396    case 5:
1397	SET_MOD_FKEYS(string_keys);
1398	break;
1399    }
1400}
1401#endif /* OPT_MOD_FKEYS */
1402
1403#if OPT_TRACE
1404#define DATA(name) { name, #name }
1405static const struct {
1406    Const PARSE_T *table;
1407    const char *name;
1408} all_tables[] = {
1409
1410    DATA(ansi_table)
1411	,DATA(cigtable)
1412	,DATA(csi2_table)
1413	,DATA(csi_ex_table)
1414	,DATA(csi_quo_table)
1415	,DATA(csi_table)
1416	,DATA(dec2_table)
1417	,DATA(dec3_table)
1418	,DATA(dec_table)
1419	,DATA(eigtable)
1420	,DATA(esc_sp_table)
1421	,DATA(esc_table)
1422	,DATA(scrtable)
1423	,DATA(scs96table)
1424	,DATA(scstable)
1425	,DATA(sos_table)
1426#if OPT_BLINK_CURS
1427	,DATA(csi_sp_table)
1428#endif
1429#if OPT_DEC_LOCATOR
1430	,DATA(csi_tick_table)
1431#endif
1432#if OPT_DEC_RECTOPS
1433	,DATA(csi_dollar_table)
1434	,DATA(csi_star_table)
1435	,DATA(csi_dec_dollar_table)
1436#endif
1437#if OPT_WIDE_CHARS
1438	,DATA(esc_pct_table)
1439	,DATA(scs_amp_table)
1440	,DATA(scs_pct_table)
1441	,DATA(scs_2qt_table)
1442#endif
1443#if OPT_VT52_MODE
1444	,DATA(vt52_table)
1445	,DATA(vt52_esc_table)
1446	,DATA(vt52_ignore_table)
1447#endif
1448#if OPT_XTERM_SGR
1449	,DATA(csi_hash_table)
1450#endif
1451#undef DATA
1452};
1453
1454#define WHICH_TABLE(name) if (table == name) result = #name
1455static const char *
1456which_table(Const PARSE_T * table)
1457{
1458    const char *result = "?";
1459    Cardinal n;
1460    for (n = 0; n < XtNumber(all_tables); ++n) {
1461	if (table == all_tables[n].table) {
1462	    result = all_tables[n].name;
1463	    break;
1464	}
1465    }
1466
1467    return result;
1468}
1469
1470static void
1471check_tables(void)
1472{
1473    Cardinal n;
1474    int ch;
1475    int total_codes = 0;
1476    int total_ground = 0;
1477    int total_ignored = 0;
1478
1479    TRACE(("** check_tables\n"));
1480    for (n = 0; n < XtNumber(all_tables); ++n) {
1481	Const PARSE_T *table = all_tables[n].table;
1482	TRACE(("*** %s\n", all_tables[n].name));
1483	/*
1484	 * Most of the tables should use the same codes in 0..31, 128..159
1485	 * as the "ansi" table.
1486	 */
1487	if (strncmp(all_tables[n].name, "ansi", 4) &&
1488	    strncmp(all_tables[n].name, "sos_", 4) &&
1489	    strncmp(all_tables[n].name, "vt52", 4)) {
1490	    for (ch = 0; ch < 32; ++ch) {
1491		int c1 = ch + 128;
1492		PARSE_T st_l = table[ch];
1493		PARSE_T st_r = table[c1];
1494		if (st_l != ansi_table[ch]) {
1495		    TRACE(("  %3d: %d vs %d\n", ch, st_l, ansi_table[ch]));
1496		}
1497		if (st_r != ansi_table[c1]) {
1498		    TRACE(("  %3d: %d vs %d\n", c1, st_r, ansi_table[c1]));
1499		}
1500	    }
1501	}
1502	/*
1503	 * All of the tables should have their GL/GR parts encoded the same.
1504	 */
1505	for (ch = 32; ch < 127; ++ch) {
1506	    PARSE_T st_l = table[ch];
1507	    PARSE_T st_r = table[ch + 128];
1508	    if (st_l != st_r) {
1509		if (st_r == CASE_IGNORE &&
1510		    !strncmp(all_tables[n].name, "vt52", 4)) {
1511		    ;
1512		} else {
1513		    TRACE(("  %3d: %d vs %d\n", ch, st_l, st_r));
1514		}
1515	    }
1516	}
1517	/*
1518	 * Just for amusement, show how sparse the encoding tables are.
1519	 */
1520	for (ch = 0; ch < 256; ++ch) {
1521	    ++total_codes;
1522	    switch (table[ch]) {
1523	    case CASE_GROUND_STATE:
1524		total_ground++;
1525		break;
1526	    case CASE_ESC_IGNORE:
1527		/* FALLTHRU */
1528	    case CASE_IGNORE:
1529		/* FALLTHRU */
1530	    case CASE_VT52_IGNORE:
1531		total_ignored++;
1532		break;
1533	    }
1534	}
1535    }
1536    TRACE(("VTPrsTbl:\n"));
1537    TRACE(("%d total codes\n", total_codes));
1538    TRACE(("%d total ignored\n", total_ignored));
1539    TRACE(("%d total reset/ground\n", total_ground));
1540}
1541
1542static void
1543check_bitmasks(void)
1544{
1545#define dMSK 0x100
1546#define DATA(mode,name) { mode, name, #name }
1547#define DMSK(what) (dMSK | (what))
1548#define DGRP(offs) (1 << ((offs) - 1))
1549    static struct {
1550	int mode;
1551	int code;
1552	Const char *name;
1553    } table[] = {
1554	DATA(DGRP(1), INVERSE),
1555	    DATA(DGRP(1), UNDERLINE),
1556	    DATA(DGRP(1), BOLD),
1557	    DATA(DGRP(1), BLINK),
1558	    DATA(DMSK(DGRP(1)), SGR_MASK),
1559	    DATA(DGRP(2), BG_COLOR),
1560	    DATA(DGRP(2), FG_COLOR),
1561	    DATA(DGRP(2), PROTECTED),
1562	    DATA(DGRP(4), CHARDRAWN),
1563#if OPT_WIDE_ATTRS
1564	    DATA(DGRP(2), ATR_FAINT),
1565	    DATA(DGRP(2), ATR_ITALIC),
1566	    DATA(DGRP(2), ATR_STRIKEOUT),
1567	    DATA(DGRP(2), ATR_DBL_UNDER),
1568	    DATA(DGRP(2), ATR_DIRECT_FG),
1569	    DATA(DGRP(2), ATR_DIRECT_BG),
1570#endif
1571	    DATA(DMSK(DGRP(2)), SGR_MASK2),
1572	    DATA(DGRP(3), WRAPAROUND),
1573	    DATA(DGRP(3), REVERSEWRAP),
1574	    DATA(DGRP(3), REVERSE_VIDEO),
1575	    DATA(DGRP(3), LINEFEED),
1576	    DATA(DGRP(3), ORIGIN),
1577	    DATA(DGRP(3), INSERT),
1578	    DATA(DGRP(3), SMOOTHSCROLL),
1579	    DATA(DGRP(3), IN132COLUMNS),
1580	    DATA(DGRP(3), INVISIBLE),
1581	    DATA(DMSK(DGRP(3)), ATTRIBUTES),
1582	    DATA(DGRP(5), NATIONAL),
1583	    DATA(DGRP(5), LEFT_RIGHT),
1584	    DATA(DGRP(5), NOCLEAR_COLM),
1585	    DATA(DGRP(4), NOBACKGROUND),
1586	    DATA(DGRP(4), NOTRANSLATION),
1587	    DATA(DGRP(4), DOUBLEWFONT),
1588	    DATA(DGRP(4), DOUBLEHFONT),
1589	    DATA(DGRP(4), CHARBYCHAR),
1590	    DATA(DGRP(4), NORESOLUTION),
1591	    DATA(DMSK(DGRP(1) | DGRP(2) | DGRP(4)), DRAWX_MASK),
1592	    DATA(-1, EOF)
1593    };
1594#undef DATA
1595    int j, k;
1596    TRACE(("** check_bitmasks:\n"));
1597    for (j = 0; table[j].mode >= 0; ++j) {
1598	TRACE(("%4X %8X %s\n", table[j].mode, table[j].code, table[j].name));
1599	if (table[j].mode & dMSK) {
1600	    int mask = dMSK;
1601	    for (k = 0; table[k].mode >= 0; ++k) {
1602		if (j == k)
1603		    continue;
1604		if (table[k].mode & dMSK)
1605		    continue;
1606		if ((table[j].mode & table[k].mode) != 0)
1607		    mask |= table[k].mode;
1608	    }
1609	    if (mask != table[j].mode) {
1610		TRACE(("...expected %08X\n", mask));
1611	    }
1612	} else {
1613	    for (k = 0; table[k].mode >= 0; ++k) {
1614		if (j == k)
1615		    continue;
1616		if (table[k].mode & dMSK)
1617		    continue;
1618		if ((table[j].code & table[k].code) != 0) {
1619		    TRACE(("...same bits %s\n", table[k].name));
1620		}
1621	    }
1622	}
1623    }
1624}
1625#endif
1626
1627static int
1628init_params(void)
1629{
1630    while (parms.count-- > 0) {
1631	parms.is_sub[parms.count] = 0;
1632	parms.params[parms.count] = 0;
1633    }
1634    parms.count = 0;
1635    parms.has_subparams = 0;
1636    return 0;
1637}
1638
1639#if OPT_TRACE > 0
1640static void
1641dump_params(void)
1642{
1643    int n;
1644    int arg;
1645    TRACE(("params %d (%d)\n", nparam, parms.has_subparams));
1646    for (arg = 1, n = 0; n < nparam; ++n) {
1647	TRACE(("%3d.%d %d\n", arg, parms.is_sub[n], parms.params[n]));
1648	if (!parms.is_sub[n])
1649	    ++arg;
1650    }
1651}
1652#define DumpParams() dump_params()
1653#else
1654#define DumpParams()		/* nothing */
1655#endif
1656
1657	/* allocate larger buffer if needed/possible */
1658#define SafeAlloc(type, area, used, size) \
1659		type *new_string = area; \
1660		size_t new_length = size; \
1661		if (new_length == 0) { \
1662		    new_length = 1024; \
1663		    new_string = TypeMallocN(type, new_length); \
1664		} else if (used+1 >= new_length) { \
1665		    new_length = size * 2; \
1666		    new_string = TypeMallocN(type, new_length); \
1667		    if (new_string != 0 \
1668		     && area != 0 \
1669		     && used != 0) { \
1670			memcpy(new_string, area, used * sizeof(type)); \
1671		     } \
1672		}
1673#define SafeFree(area, size) \
1674		if (area != new_string) { \
1675		    free(area); \
1676		    area = new_string; \
1677		} \
1678		size = new_length
1679
1680#define WriteNow() {						\
1681	    unsigned single = 0;				\
1682								\
1683	    if (screen->curss) {				\
1684		dotext(xw,					\
1685		       screen->gsets[(int) (screen->curss)],	\
1686		       sp->print_area,				\
1687		       (Cardinal) 1);				\
1688		screen->curss = 0;				\
1689		single++;					\
1690	    }							\
1691	    if (sp->print_used > single) {			\
1692		dotext(xw,					\
1693		       screen->gsets[(int) (screen->curgl)],	\
1694		       sp->print_area + single,			\
1695		       (Cardinal) (sp->print_used - single));	\
1696	    }							\
1697	    sp->print_used = 0;					\
1698	}							\
1699
1700#define PARSE_SRM 1
1701
1702struct ParseState {
1703    unsigned check_recur;
1704#if OPT_VT52_MODE
1705    Bool vt52_cup;
1706#endif
1707    Const PARSE_T *groundtable;
1708    Const PARSE_T *parsestate;
1709    int scstype;
1710    int scssize;
1711    Bool private_function;	/* distinguish private-mode from standard */
1712    int string_mode;		/* nonzero iff we're processing a string */
1713    int lastchar;		/* positive iff we had a graphic character */
1714    int nextstate;
1715#if OPT_WIDE_CHARS
1716    int last_was_wide;
1717#endif
1718    /* Buffer for processing printable text */
1719    IChar *print_area;
1720    size_t print_size;
1721    size_t print_used;
1722    /* Buffer for processing strings (e.g., OSC ... ST) */
1723    Char *string_area;
1724    size_t string_size;
1725    size_t string_used;
1726    /* Buffer for deferring input */
1727    Char *defer_area;
1728    size_t defer_size;
1729    size_t defer_used;
1730};
1731
1732static struct ParseState myState;
1733
1734static void
1735init_groundtable(TScreen *screen, struct ParseState *sp)
1736{
1737    (void) screen;
1738
1739#if OPT_VT52_MODE
1740    if (!(screen->vtXX_level)) {
1741	sp->groundtable = vt52_table;
1742    } else if (screen->terminal_id >= 100)
1743#endif
1744    {
1745	sp->groundtable = ansi_table;
1746    }
1747}
1748
1749static void
1750select_charset(struct ParseState *sp, int type, int size)
1751{
1752    TRACE(("select_charset G%d size %d -> G%d size %d\n",
1753	   sp->scstype, sp->scssize,
1754	   type, size));
1755
1756    sp->scstype = type;
1757    sp->scssize = size;
1758    if (size == 94) {
1759	sp->parsestate = scstable;
1760    } else {
1761	sp->parsestate = scs96table;
1762    }
1763}
1764/* *INDENT-OFF* */
1765static const struct {
1766    DECNRCM_codes result;
1767    int prefix;
1768    int suffix;
1769    int min_level;
1770    int max_level;
1771    int need_nrc;
1772} scs_table[] = {
1773    { nrc_ASCII,             0,   'B', 1, 9, 0 },
1774    { nrc_British,           0,   'A', 1, 9, 0 },
1775    { nrc_DEC_Spec_Graphic,  0,   '0', 1, 9, 0 },
1776    { nrc_DEC_Alt_Chars,     0,   '1', 1, 1, 0 },
1777    { nrc_DEC_Alt_Graphics,  0,   '2', 1, 1, 0 },
1778    /* VT2xx */
1779    { nrc_DEC_Supp,          0,   '<', 2, 9, 0 },
1780    { nrc_Dutch,             0,   '4', 2, 9, 1 },
1781    { nrc_Finnish,           0,   '5', 2, 9, 1 },
1782    { nrc_Finnish2,          0,   'C', 2, 9, 1 },
1783    { nrc_French,            0,   'R', 2, 9, 1 },
1784    { nrc_French2,           0,   'f', 2, 9, 1 },
1785    { nrc_French_Canadian,   0,   'Q', 2, 9, 1 },
1786    { nrc_German,            0,   'K', 2, 9, 1 },
1787    { nrc_Italian,           0,   'Y', 2, 9, 1 },
1788    { nrc_Norwegian_Danish2, 0,   'E', 2, 9, 1 },
1789    { nrc_Norwegian_Danish3, 0,   '6', 2, 9, 1 },
1790    { nrc_Spanish,           0,   'Z', 2, 9, 1 },
1791    { nrc_Swedish,           0,   '7', 2, 9, 1 },
1792    { nrc_Swedish2,          0,   'H', 2, 9, 1 },
1793    { nrc_Swiss,             0,   '=', 2, 9, 1 },
1794    /* VT3xx */
1795    { nrc_British_Latin_1,   0,   'A', 3, 9, 1 },
1796    { nrc_DEC_Supp_Graphic,  '%', '5', 3, 9, 0 },
1797    { nrc_DEC_Technical,     0,   '>', 3, 9, 0 },
1798    { nrc_French_Canadian2,  0,   '9', 3, 9, 1 },
1799    { nrc_Norwegian_Danish,  0,   '`', 3, 9, 1 },
1800    { nrc_Portugese,         '%', '6', 3, 9, 1 },
1801    { nrc_ISO_Latin_1_Supp,  0,   'A', 3, 9, 0 },
1802    /* VT5xx */
1803    { nrc_Greek,             '"', '>', 5, 9, 1 },
1804    { nrc_Hebrew,            '%', '=', 5, 9, 1 },
1805    { nrc_Turkish,	     '%', '2', 5, 9, 1 },
1806    { nrc_DEC_Cyrillic,      '&', '4', 5, 9, 0 },
1807    { nrc_DEC_Greek_Supp,    '"', '?', 5, 9, 0 },
1808    { nrc_DEC_Hebrew_Supp,   '"', '4', 5, 9, 0 },
1809    { nrc_DEC_Turkish_Supp,  '%', '0', 5, 9, 0 },
1810    { nrc_ISO_Greek_Supp,    0,   'F', 5, 9, 0 },
1811    { nrc_ISO_Hebrew_Supp,   0,   'H', 5, 9, 0 },
1812    { nrc_ISO_Latin_2_Supp,  0,   'B', 5, 9, 0 },
1813    { nrc_ISO_Latin_5_Supp,  0,   'M', 5, 9, 0 },
1814    { nrc_ISO_Latin_Cyrillic,0,   'L', 5, 9, 0 },
1815    /* VT5xx (not implemented) */
1816#if 0
1817    { nrc_Russian,           '&', '5', 5, 9, 1 },
1818    { nrc_SCS_NRCS,          '%', '3', 5, 9, 0 },
1819#endif
1820};
1821/* *INDENT-ON* */
1822
1823#if OPT_DEC_RECTOPS
1824static char *
1825encode_scs(DECNRCM_codes value)
1826{
1827    static char buffer[3];
1828    Cardinal n;
1829    char *result = buffer;
1830    for (n = 0; n < XtNumber(scs_table); ++n) {
1831	if (scs_table[n].result == value) {
1832	    if (scs_table[n].prefix)
1833		*result++ = (char) scs_table[n].prefix;
1834	    if (scs_table[n].suffix)
1835		*result++ = (char) scs_table[n].suffix;
1836	    break;
1837	}
1838    }
1839    *result = '\0';
1840    return buffer;
1841}
1842#endif
1843
1844void
1845xtermDecodeSCS(XtermWidget xw, int which, int sgroup, int prefix, int suffix)
1846{
1847    TScreen *screen = TScreenOf(xw);
1848    Cardinal n;
1849    DECNRCM_codes result = nrc_Unknown;
1850
1851    suffix &= 0x7f;
1852    for (n = 0; n < XtNumber(scs_table); ++n) {
1853	if (prefix == scs_table[n].prefix
1854	    && suffix == scs_table[n].suffix
1855	    && sgroup == scs_table[n].min_level
1856	    && screen->vtXX_level >= scs_table[n].min_level
1857	    && screen->vtXX_level <= scs_table[n].max_level
1858	    && (scs_table[n].need_nrc == 0 || (xw->flags & NATIONAL) != 0)) {
1859	    result = scs_table[n].result;
1860	    break;
1861	}
1862    }
1863    if (result != nrc_Unknown) {
1864	initCharset(screen, which, result);
1865	TRACE(("setting G%d to table #%d %s",
1866	       which, n, visibleScsCode((int) result)));
1867    } else {
1868	TRACE(("...unknown GSET"));
1869	initCharset(screen, which, nrc_ASCII);
1870    }
1871#if OPT_TRACE
1872    TRACE((" ("));
1873    if (prefix)
1874	TRACE(("prefix='%c', ", prefix));
1875    TRACE(("suffix='%c', sgroup=%d", suffix, sgroup));
1876    TRACE((")\n"));
1877#endif
1878}
1879
1880/*
1881 * Given a parameter number, and subparameter (starting in each case from zero)
1882 * return the corresponding index into the parameter array.  If the combination
1883 * is not found, return -1.
1884 */
1885static int
1886subparam_index(int p, int s)
1887{
1888    int result = -1;
1889    int j, p2, s2;
1890
1891    for (j = p2 = 0; j < nparam; ++j, ++p2) {
1892	if (parms.is_sub[j]) {
1893	    s2 = 0;
1894
1895	    do {
1896		if ((p == p2) && (s == s2)) {
1897		    result = j;
1898		    break;
1899		}
1900		++s2;
1901	    } while ((++j < nparam) && (parms.is_sub[j - 1] < parms.is_sub[j]));
1902
1903	    if (result >= 0)
1904		break;
1905
1906	    --j;		/* undo the last "while" */
1907	} else if (p == p2) {
1908	    if (s == 0) {
1909		result = j;
1910	    }
1911	    break;
1912	}
1913    }
1914    TRACE2(("...subparam_index %d.%d = %d\n", p + 1, s + 1, result));
1915    return result;
1916}
1917
1918/*
1919 * Check if the given item in the parameter array has subparameters.
1920 * If so, return the number of subparameters to use as a loop limit, etc.
1921 */
1922static int
1923param_has_subparams(int item)
1924{
1925    int result = 0;
1926    if (parms.has_subparams) {
1927	int n = subparam_index(item, 0);
1928	if (n >= 0 && parms.is_sub[n]) {
1929	    while (++n < nparam && parms.is_sub[n - 1] < parms.is_sub[n]) {
1930		result++;
1931	    }
1932	}
1933    }
1934    TRACE(("...param_has_subparams(%d) ->%d\n", item, result));
1935    return result;
1936}
1937
1938#if OPT_DIRECT_COLOR || OPT_256_COLORS || OPT_88_COLORS || OPT_ISO_COLORS
1939/*
1940 * Given an index into the parameter array, return the corresponding parameter
1941 * number (starting from zero).
1942 */
1943static int
1944param_number(int item)
1945{
1946    int result = -1;
1947    int j, p;
1948
1949    for (j = p = 0; j < nparam; ++j, ++p) {
1950	if (p >= item) {
1951	    result = j;
1952	    break;
1953	}
1954	if (parms.is_sub[j]) {
1955	    while ((++j < nparam) && (parms.is_sub[j - 1] < parms.is_sub[j])) {
1956		/* EMPTY */
1957	    }
1958	    --j;
1959	}
1960    }
1961
1962    TRACE2(("...param_number(%d) = %d\n", item, result));
1963    return result;
1964}
1965
1966static int
1967get_subparam(int p, int s)
1968{
1969    int item = subparam_index(p, s);
1970    int result = (item >= 0) ? parms.params[item] : DEFAULT;
1971    TRACE(("...get_subparam[%d] = %d\n", item, result));
1972    return result;
1973}
1974
1975/*
1976 * Some background -
1977 *
1978 * Todd Larason provided the initial changes to support 256-colors in July 1999.
1979 * I pointed out that the description of SGR 38/48 in ECMA-48 was vague, and
1980 * was unsure if there would be some standard using those codes.  His response
1981 * was that this was documented (it turns out, in equally vague terms) in ITU
1982 * T.416
1983 *
1984 * Discussing this with Todd Larason in mid-1999, my point was that given the
1985 * high cost of obtaining ITU T.416 (ISO-8613-6), the standard was not going
1986 * to be effective (more than $100 then, more than $200 in 2012)
1987 *
1988 * We overlooked the detail about ":" as a subparameter delimiter (documented
1989 * in 5.4.2 in ECMA-48).  Some discussion in KDE in mid-2006 led Lars Doelle
1990 * to discuss the issue with me.  Lars' initial concern dealt with the fact
1991 * that a sequence such as
1992 *	CSI 38 ; 5 ; 1 m
1993 * violated the principle that SGR parameters could be used in any order.
1994 * Further discussion (see KDE #107487) resolved that the standard expected
1995 * that the sequence would look like
1996 *	CSI 38 ; 5 : 1 m
1997 * which still violates that principle, since the "5:1" parameter has to
1998 * follow the "38" to be useful.
1999 *
2000 * This function accepts either format (per request by Paul Leonerd Evans).
2001 * It also accepts
2002 *	CSI 38 : 5 : 1 m
2003 * according to Lars' original assumption.  While implementing that, I added
2004 * support for Konsole's interpretation of "CSI 38 : 2" as a 24-bit RGB value.
2005 * ISO-8613-6 documents that as "direct color".
2006 *
2007 * At the time in 2012, no one noticed (or commented) regarding ISO-8613-6's
2008 * quirk in the description of direct color:  it mentions a color space
2009 * identifier parameter which should follow the "2" (as parameter 1).  In the
2010 * same section, ISO-8613-6 mentions a parameter 6 which can be ignored, as
2011 * well as parameters 7 and 8.  Like parameter 1, parameters 7 and 8 are not
2012 * defined clearly in the standard, and a close reading indicates they are
2013 * optional, saying they "may be used".  This implementation ignores parameters
2014 * 6 (and above), and provides for the color space identifier by checking the
2015 * number of parameters:
2016 *	3 after "2" (no color space identifier)
2017 *	4 or more after "2" (color space identifier)
2018 *
2019 * By the way - all of the parameters are decimal integers, and missing
2020 * parameters represent a default value.  ISO-8613-6 is clear about that.
2021 *
2022 * Aside from ISO-8613-3, there is no standard use of ":" as a delimiter.
2023 * ECMA-48 says only:
2024 *
2025 *	5.4.2 Parameter string format
2026 *
2027 *	A parameter string which does not start with a bit combination in the
2028 *	range 03/12 to 03/15 shall have the following format:
2029 *
2030 *	    a) A parameter string consists of one or more parameter
2031 *	       sub-strings, each of which represents a number in decimal
2032 *	       notation.
2033 *
2034 *	    b) Each parameter sub-string consists of one or more bit
2035 *	       combinations from 03/00 to 03/10; the bit combinations from
2036 *	       03/00 to 03/09 represent the digits ZERO to NINE; bit
2037 *	       combination 03/10 may be used as a separator in a parameter
2038 *	       sub-string, for example, to separate the fractional part of a
2039 *	       decimal number from the integer part of that number.
2040 *
2041 * That is, there is no mention in ECMA-48 of the possibility that a parameter
2042 * string might be a list of parameters, as done in ISO-8613-3 (nor does
2043 * ECMA-48 provide an example where the ":" separator might be used).  Because
2044 * of this, xterm treats other cases than those needed for ISO-8613-3 as an
2045 * error, and stops interpreting the sequence.
2046 */
2047#define extended_colors_limit(n) ((n) == 5 ? 1 : ((n) == 2 ? 3 : 0))
2048static Boolean
2049parse_extended_colors(XtermWidget xw, int *colorp, int *itemp, Boolean *extended)
2050{
2051    Boolean result = False;
2052    int item = *itemp;
2053    int next = item;
2054    int base = param_number(item);
2055    int code = -1;
2056    int values[3];		/* maximum number of subparameters */
2057    int need = 0;		/* number of subparameters needed */
2058    int have;
2059    int n;
2060
2061    /*
2062     * On entry, 'item' points to the 38/48 code in the parameter array.
2063     * If that has subparameters, we will expect all of the values to
2064     * be subparameters of that item.
2065     */
2066    if ((have = param_has_subparams(item)) != 0) {
2067	/* accept CSI 38 : 5 : 1 m */
2068	/* accept CSI 38 : 2 : 1 : 2 : 3 m */
2069	code = get_subparam(base, 1);
2070	need = extended_colors_limit(code);
2071	next = item + have;
2072	for (n = 0; n < need && n < 3; ++n) {
2073	    values[n] = get_subparam(base, 2 + n + (have > 4));
2074	}
2075    } else if (++item < nparam) {
2076	++base;
2077	if ((have = param_has_subparams(item)) != 0) {
2078	    /* accept CSI 38 ; 5 : 1 m */
2079	    /* accept CSI 38 ; 2 : 1 : 2 : 3 m */
2080	    code = get_subparam(base, 0);
2081	    need = extended_colors_limit(code);
2082	    next = base + have;
2083	    for (n = 0; n < need && n < 3; ++n) {
2084		values[n] = get_subparam(base, 1 + n + (have > 3));
2085	    }
2086	} else {
2087	    /* accept CSI 38 ; 5 ; 1 m */
2088	    /* accept CSI 38 ; 2 ; 1 ; 2 ; 3 m */
2089	    code = GetParam(item);
2090	    need = extended_colors_limit(code);
2091	    next = item + need;
2092	    for (n = 0; n < need && n < 3; ++n) {
2093		values[n] = GetParam(item + 1 + n);
2094	    }
2095	}
2096    }
2097    item = next;
2098
2099    *extended = False;
2100    switch (code) {
2101    case 2:
2102	/* direct color in rgb space */
2103	if ((values[0] >= 0 && values[0] < 256) &&
2104	    (values[1] >= 0 && values[1] < 256) &&
2105	    (values[2] >= 0 && values[2] < 256)) {
2106#if OPT_DIRECT_COLOR
2107	    if (TScreenOf(xw)->direct_color && xw->has_rgb) {
2108		*colorp = getDirectColor(xw, values[0], values[1], values[2]);
2109		result = True;
2110		*extended = True;
2111	    } else
2112#endif
2113	    {
2114		*colorp = xtermClosestColor(xw, values[0], values[1], values[2]);
2115		result = okIndexedColor(*colorp);
2116	    }
2117	} else {
2118	    *colorp = -1;
2119	}
2120	break;
2121    case 5:
2122	/* indexed color */
2123	*colorp = values[0];
2124	result = okIndexedColor(*colorp);
2125	break;
2126    default:
2127	*colorp = -1;
2128	break;
2129    }
2130
2131    TRACE(("...resulting color %d/%d %s\n",
2132	   *colorp, NUM_ANSI_COLORS,
2133	   result ? "OK" : "ERR"));
2134
2135    *itemp = item;
2136    return result;
2137}
2138#endif /* ...extended_colors */
2139
2140static int
2141optional_param(int which)
2142{
2143    return (nparam > which) ? GetParam(which) : DEFAULT;
2144}
2145
2146static int
2147zero_if_default(int which)
2148{
2149    int result = (nparam > which) ? GetParam(which) : 0;
2150    if (result <= 0)
2151	result = 0;
2152    return result;
2153}
2154
2155static int
2156one_if_default(int which)
2157{
2158    int result = (nparam > which) ? GetParam(which) : 0;
2159    if (result <= 0)
2160	result = 1;
2161    return result;
2162}
2163
2164/*
2165 * Color palette changes using the OSC controls require a repaint of the
2166 * screen - but not immediately.  Do the repaint as soon as we detect a
2167 * state which will not lead to another color palette change.
2168 */
2169static void
2170repaintWhenPaletteChanged(XtermWidget xw, struct ParseState *sp)
2171{
2172    Boolean ignore = False;
2173
2174    switch (sp->nextstate) {
2175    case CASE_ESC:
2176	ignore = ((sp->parsestate == ansi_table) ||
2177		  (sp->parsestate == sos_table));
2178#if USE_DOUBLE_BUFFER
2179	if (resource.buffered && TScreenOf(xw)->needSwap) {
2180	    ignore = False;
2181	}
2182#endif
2183	break;
2184    case CASE_OSC:
2185	ignore = ((sp->parsestate == ansi_table) ||
2186		  (sp->parsestate == esc_table));
2187	break;
2188    case CASE_IGNORE:
2189	ignore = (sp->parsestate == sos_table);
2190	break;
2191    case CASE_ST:
2192	ignore = ((sp->parsestate == esc_table) ||
2193		  (sp->parsestate == sos_table));
2194	break;
2195    case CASE_ESC_DIGIT:
2196	ignore = (sp->parsestate == csi_table);
2197	break;
2198    case CASE_ESC_SEMI:
2199	ignore = (sp->parsestate == csi2_table);
2200	break;
2201    }
2202
2203    if (!ignore) {
2204	TRACE(("repaintWhenPaletteChanged\n"));
2205	xw->work.palette_changed = False;
2206	xtermRepaint(xw);
2207	xtermFlushDbe(xw);
2208    }
2209}
2210
2211#if OPT_C1_PRINT || OPT_WIDE_CHARS
2212#define ParseSOS(screen) ((screen)->c1_printable == 0)
2213#else
2214#define ParseSOS(screen) 0
2215#endif
2216
2217#define ResetState(sp) InitParams(), (sp)->parsestate = (sp)->groundtable
2218
2219static void
2220illegal_parse(XtermWidget xw, unsigned c, struct ParseState *sp)
2221{
2222    ResetState(sp);
2223    sp->nextstate = sp->parsestate[E2A(c)];
2224    Bell(xw, XkbBI_MinorError, 0);
2225}
2226
2227static void
2228init_parser(XtermWidget xw, struct ParseState *sp)
2229{
2230    TScreen *screen = TScreenOf(xw);
2231
2232    memset(sp, 0, sizeof(*sp));
2233    sp->scssize = 94;		/* number of printable/nonspace ASCII */
2234    sp->lastchar = -1;		/* not a legal IChar */
2235    sp->nextstate = -1;		/* not a legal state */
2236
2237    init_groundtable(screen, sp);
2238    ResetState(sp);
2239}
2240
2241static void
2242init_reply(unsigned type)
2243{
2244    memset(&reply, 0, sizeof(reply));
2245    reply.a_type = (Char) type;
2246}
2247
2248static void
2249deferparsing(unsigned c, struct ParseState *sp)
2250{
2251    SafeAlloc(Char, sp->defer_area, sp->defer_used, sp->defer_size);
2252    if (new_string == 0) {
2253	xtermWarning("Cannot allocate %lu bytes for deferred parsing of %u\n",
2254		     (unsigned long) new_length, c);
2255	return;
2256    }
2257    SafeFree(sp->defer_area, sp->defer_size);
2258    sp->defer_area[(sp->defer_used)++] = CharOf(c);
2259}
2260
2261#if OPT_VT52_MODE
2262static void
2263update_vt52_vt100_settings(void)
2264{
2265    update_autowrap();
2266    update_reversewrap();
2267    update_autolinefeed();
2268    update_appcursor();
2269    update_appkeypad();
2270    update_allow132();
2271}
2272#endif
2273
2274static Boolean
2275doparsing(XtermWidget xw, unsigned c, struct ParseState *sp)
2276{
2277    TScreen *screen = TScreenOf(xw);
2278    int item;
2279    int count;
2280    int value;
2281    int laststate;
2282    int thischar = -1;
2283    XTermRect myRect;
2284#if OPT_DEC_RECTOPS
2285    int thispage = 1;
2286#endif
2287
2288    if (sp->check_recur) {
2289	/* Defer parsing when parser is already running as the parser is not
2290	 * safe to reenter.
2291	 */
2292	deferparsing(c, sp);
2293	return True;
2294    }
2295    sp->check_recur++;
2296
2297    do {
2298#if OPT_WIDE_CHARS
2299	int this_is_wide = 0;
2300
2301	/*
2302	 * Handle zero-width combining characters.  Make it faster by noting
2303	 * that according to the Unicode charts, the majority of Western
2304	 * character sets do not use this feature.  There are some unassigned
2305	 * codes at 0x242, but no zero-width characters until past 0x300.
2306	 */
2307	if (c >= 0x300
2308	    && screen->wide_chars
2309	    && CharWidth(c) == 0
2310	    && !isWideControl(c)) {
2311	    int prev, test;
2312	    Boolean used = True;
2313	    int use_row;
2314	    int use_col;
2315
2316	    WriteNow();
2317	    use_row = (screen->char_was_written
2318		       ? screen->last_written_row
2319		       : screen->cur_row);
2320	    use_col = (screen->char_was_written
2321		       ? screen->last_written_col
2322		       : screen->cur_col);
2323
2324	    /*
2325	     * Check if the latest data can be added to the base character.
2326	     * If there is already a combining character stored for the cell,
2327	     * we cannot, since that would change the order.
2328	     */
2329	    if (screen->normalized_c
2330		&& !IsCellCombined(screen, use_row, use_col)) {
2331		prev = (int) XTERM_CELL(use_row, use_col);
2332		test = do_precomposition(prev, (int) c);
2333		TRACE(("do_precomposition (U+%04X [%d], U+%04X [%d]) -> U+%04X [%d]\n",
2334		       prev, CharWidth(prev),
2335		       (int) c, CharWidth(c),
2336		       test, CharWidth(test)));
2337	    } else {
2338		prev = -1;
2339		test = -1;
2340	    }
2341
2342	    /* substitute combined character with precomposed character
2343	     * only if it does not change the width of the base character
2344	     */
2345	    if (test != -1
2346		&& CharWidth(test) == CharWidth(prev)) {
2347		putXtermCell(screen, use_row, use_col, test);
2348	    } else if (screen->char_was_written
2349		       || getXtermCell(screen, use_row, use_col) >= ' ') {
2350		addXtermCombining(screen, use_row, use_col, c);
2351	    } else {
2352		/*
2353		 * none of the above... we will add the combining character as
2354		 * a base character.
2355		 */
2356		used = False;
2357	    }
2358
2359	    if (used) {
2360		if (!screen->scroll_amt)
2361		    ScrnUpdate(xw, use_row, use_col, 1, 1, 1);
2362		continue;
2363	    }
2364	}
2365#endif
2366
2367	/* Intercept characters for printer controller mode */
2368	if (PrinterOf(screen).printer_controlmode == 2) {
2369	    if ((c = (unsigned) xtermPrinterControl(xw, (int) c)) == 0)
2370		continue;
2371	}
2372
2373	/*
2374	 * VT52 is a little ugly in the one place it has a parameterized
2375	 * control sequence, since the parameter falls after the character
2376	 * that denotes the type of sequence.
2377	 */
2378#if OPT_VT52_MODE
2379	if (sp->vt52_cup) {
2380	    if (nparam < NPARAM - 1) {
2381		SetParam(nparam++, (int) (c & 0x7f) - 32);
2382		parms.is_sub[nparam] = 0;
2383	    }
2384	    if (nparam < 2)
2385		continue;
2386	    sp->vt52_cup = False;
2387	    CursorSet(screen, zero_if_default(0), zero_if_default(1), xw->flags);
2388	    sp->parsestate = vt52_table;
2389	    SetParam(0, 0);
2390	    SetParam(1, 0);
2391	    continue;
2392	}
2393#endif
2394
2395	laststate = sp->nextstate;
2396	if (c == ANSI_DEL
2397	    && sp->parsestate == sp->groundtable
2398	    && sp->scssize == 96
2399	    && sp->scstype != 0) {
2400	    /*
2401	     * Handle special case of shifts for 96-character sets by checking
2402	     * if we have a DEL.  The other special case for SPACE will always
2403	     * be printable.
2404	     */
2405	    sp->nextstate = CASE_PRINT;
2406	} else
2407#if OPT_WIDE_CHARS
2408	if (c > 255) {
2409	    /*
2410	     * The parsing tables all have 256 entries.  If we're supporting
2411	     * wide characters, we handle them by treating them the same as
2412	     * printing characters.
2413	     */
2414	    if (sp->parsestate == sp->groundtable) {
2415		sp->nextstate = CASE_PRINT;
2416	    } else if (sp->parsestate == sos_table) {
2417		c &= WIDEST_ICHAR;
2418		if (c > 255) {
2419		    TRACE(("Found code > 255 while in SOS state: %04X\n", c));
2420		    c = BAD_ASCII;
2421		}
2422	    } else {
2423		sp->nextstate = CASE_GROUND_STATE;
2424	    }
2425	} else
2426#endif
2427	    sp->nextstate = sp->parsestate[E2A(c)];
2428
2429#if OPT_BROKEN_OSC
2430	/*
2431	 * Linux console palette escape sequences start with an OSC, but do
2432	 * not terminate correctly.  Some scripts do not check before writing
2433	 * them, making xterm appear to hang (it's awaiting a valid string
2434	 * terminator).  Just ignore these if we see them - there's no point
2435	 * in emulating bad code.
2436	 */
2437	if (screen->brokenLinuxOSC
2438	    && sp->parsestate == sos_table) {
2439	    if (sp->string_used) {
2440		switch (sp->string_area[0]) {
2441		case 'P':
2442		    if (sp->string_used <= 7)
2443			break;
2444		    /* FALLTHRU */
2445		case 'R':
2446		    illegal_parse(xw, c, sp);
2447		    TRACE(("Reset to ground state (brokenLinuxOSC)\n"));
2448		    break;
2449		}
2450	    }
2451	}
2452#endif
2453
2454#if OPT_BROKEN_ST
2455	/*
2456	 * Before patch #171, carriage control embedded within an OSC string
2457	 * would terminate it.  Some (buggy, of course) applications rely on
2458	 * this behavior.  Accommodate them by allowing one to compile xterm
2459	 * and emulate the old behavior.
2460	 */
2461	if (screen->brokenStringTerm
2462	    && sp->parsestate == sos_table
2463	    && c < 32) {
2464	    switch (c) {
2465	    case ANSI_EOT:	/* FALLTHRU */
2466	    case ANSI_BS:	/* FALLTHRU */
2467	    case ANSI_HT:	/* FALLTHRU */
2468	    case ANSI_LF:	/* FALLTHRU */
2469	    case ANSI_VT:	/* FALLTHRU */
2470	    case ANSI_FF:	/* FALLTHRU */
2471	    case ANSI_CR:	/* FALLTHRU */
2472	    case ANSI_SO:	/* FALLTHRU */
2473	    case ANSI_SI:	/* FALLTHRU */
2474	    case ANSI_XON:	/* FALLTHRU */
2475	    case ANSI_CAN:
2476		illegal_parse(xw, c, sp);
2477		TRACE(("Reset to ground state (brokenStringTerm)\n"));
2478		break;
2479	    }
2480	}
2481#endif
2482
2483#if OPT_C1_PRINT
2484	/*
2485	 * This is not completely foolproof, but will allow an application
2486	 * with values in the C1 range to use them as printable characters,
2487	 * provided that they are not intermixed with an escape sequence.
2488	 */
2489	if (screen->c1_printable
2490	    && (c >= 128 && c < 256)) {
2491	    sp->nextstate = (sp->parsestate == esc_table
2492			     ? CASE_ESC_IGNORE
2493			     : sp->parsestate[E2A(160)]);
2494	    TRACE(("allowC1Printable %04X %s ->%s\n",
2495		   c, which_table(sp->parsestate),
2496		   visibleVTparse(sp->nextstate)));
2497	}
2498#endif
2499
2500#if OPT_WIDE_CHARS
2501	/*
2502	 * If we have a C1 code and the c1_printable flag is not set, simply
2503	 * ignore it when it was translated from UTF-8.  That is because the
2504	 * value could not have been present as-is in the UTF-8.
2505	 *
2506	 * To see that CASE_IGNORE is a consistent value, note that it is
2507	 * always used for NUL and other uninteresting C0 controls.
2508	 */
2509#if OPT_C1_PRINT
2510	if (!screen->c1_printable)
2511#endif
2512	    if (screen->wide_chars
2513		&& (c >= 128 && c < 160)) {
2514		sp->nextstate = CASE_IGNORE;
2515	    }
2516
2517	/*
2518	 * If this character is a different width than the last one, put the
2519	 * previous text into the buffer and draw it now.
2520	 */
2521	this_is_wide = isWide((int) c);
2522	if (this_is_wide != sp->last_was_wide) {
2523	    WriteNow();
2524	}
2525#endif
2526
2527	/*
2528	 * Accumulate string for printable text.  This may be 8/16-bit
2529	 * characters.
2530	 */
2531	if (sp->nextstate == CASE_PRINT) {
2532	    SafeAlloc(IChar, sp->print_area, sp->print_used, sp->print_size);
2533	    if (new_string == 0) {
2534		xtermWarning("Cannot allocate %lu bytes for printable text\n",
2535			     (unsigned long) new_length);
2536		continue;
2537	    }
2538	    SafeFree(sp->print_area, sp->print_size);
2539#if OPT_VT52_MODE
2540	    /*
2541	     * Strip output text to 7-bits for VT52.  We should do this for
2542	     * VT100 also (which is a 7-bit device), but xterm has been
2543	     * doing this for so long we shouldn't change this behavior.
2544	     */
2545	    if (screen->vtXX_level < 1)
2546		c &= 0x7f;
2547#endif
2548	    sp->print_area[sp->print_used++] = (IChar) c;
2549	    sp->lastchar = thischar = (int) c;
2550#if OPT_WIDE_CHARS
2551	    sp->last_was_wide = this_is_wide;
2552#endif
2553	    if (morePtyData(screen, VTbuffer)) {
2554		continue;
2555	    }
2556	}
2557
2558	if (sp->nextstate == CASE_PRINT
2559	    || (laststate == CASE_PRINT && sp->print_used)) {
2560	    WriteNow();
2561	}
2562
2563	/*
2564	 * Accumulate string for APC, DCS, PM, OSC, SOS controls
2565	 * This should always be 8-bit characters.
2566	 */
2567	if (sp->parsestate == sos_table) {
2568	    SafeAlloc(Char, sp->string_area, sp->string_used, sp->string_size);
2569	    if (new_string == 0) {
2570		xtermWarning("Cannot allocate %lu bytes for string mode %d\n",
2571			     (unsigned long) new_length, sp->string_mode);
2572		continue;
2573	    }
2574	    SafeFree(sp->string_area, sp->string_size);
2575#if OPT_WIDE_CHARS
2576	    /*
2577	     * We cannot display codes above 255, but let's try to
2578	     * accommodate the application a little by not aborting the
2579	     * string.
2580	     */
2581	    if ((c & WIDEST_ICHAR) > 255) {
2582		sp->nextstate = CASE_PRINT;
2583		c = BAD_ASCII;
2584	    }
2585#endif
2586	    sp->string_area[(sp->string_used)++] = CharOf(c);
2587	} else if (sp->parsestate != esc_table) {
2588	    /* if we were accumulating, we're not any more */
2589	    sp->string_mode = 0;
2590	    sp->string_used = 0;
2591	}
2592
2593	DumpParams();
2594	TRACE(("parse %04X -> %s %s (used=%lu)\n",
2595	       c, visibleVTparse(sp->nextstate),
2596	       which_table(sp->parsestate),
2597	       (unsigned long) sp->string_used));
2598
2599	/*
2600	 * If the parameter list has subparameters (tokens separated by ":")
2601	 * reject any controls that do not accept subparameters.
2602	 */
2603	if (parms.has_subparams) {
2604	    switch (sp->nextstate) {
2605	    case CASE_GROUND_STATE:
2606	    case CASE_CSI_IGNORE:
2607		/* FALLTHRU */
2608
2609	    case CASE_ESC_DIGIT:
2610	    case CASE_ESC_SEMI:
2611	    case CASE_ESC_COLON:
2612		/* these states are required to parse parameter lists */
2613		break;
2614
2615	    case CASE_SGR:
2616		TRACE(("...possible subparam usage\n"));
2617		break;
2618
2619	    case CASE_CSI_DEC_DOLLAR_STATE:
2620	    case CASE_CSI_DOLLAR_STATE:
2621	    case CASE_CSI_HASH_STATE:
2622	    case CASE_CSI_EX_STATE:
2623	    case CASE_CSI_QUOTE_STATE:
2624	    case CASE_CSI_SPACE_STATE:
2625	    case CASE_CSI_STAR_STATE:
2626	    case CASE_CSI_TICK_STATE:
2627	    case CASE_DEC2_STATE:
2628	    case CASE_DEC3_STATE:
2629	    case CASE_DEC_STATE:
2630		/* use this branch when we do not yet have the final character */
2631		TRACE(("...unexpected subparam usage\n"));
2632		InitParams();
2633		sp->nextstate = CASE_CSI_IGNORE;
2634		break;
2635
2636	    default:
2637		/* use this branch for cases where we have the final character
2638		 * in the table that processed the parameter list.
2639		 */
2640		TRACE(("...unexpected subparam usage\n"));
2641		ResetState(sp);
2642		continue;
2643	    }
2644	}
2645
2646	if (xw->work.palette_changed) {
2647	    repaintWhenPaletteChanged(xw, sp);
2648	}
2649
2650	switch (sp->nextstate) {
2651	case CASE_PRINT:
2652	    TRACE(("CASE_PRINT - printable characters\n"));
2653	    break;
2654
2655	case CASE_GROUND_STATE:
2656	    TRACE(("CASE_GROUND_STATE - exit ignore mode\n"));
2657	    ResetState(sp);
2658	    break;
2659
2660	case CASE_IGNORE:
2661	    TRACE(("CASE_IGNORE - Ignore character %02X\n", c));
2662	    break;
2663
2664	case CASE_ENQ:
2665	    TRACE(("CASE_ENQ - answerback\n"));
2666	    if (((xw->keyboard.flags & MODE_SRM) == 0)
2667		? (sp->check_recur == 0)
2668		: (sp->check_recur <= 1)) {
2669		for (count = 0; screen->answer_back[count] != 0; count++)
2670		    unparseputc(xw, screen->answer_back[count]);
2671		unparse_end(xw);
2672	    }
2673	    break;
2674
2675	case CASE_BELL:
2676	    TRACE(("CASE_BELL - bell\n"));
2677	    if (sp->string_mode == ANSI_OSC) {
2678		if (sp->string_used)
2679		    sp->string_area[--(sp->string_used)] = '\0';
2680		if (sp->check_recur <= 1)
2681		    do_osc(xw, sp->string_area, sp->string_used, (int) c);
2682		ResetState(sp);
2683	    } else {
2684		/* bell */
2685		Bell(xw, XkbBI_TerminalBell, 0);
2686	    }
2687	    break;
2688
2689	case CASE_BS:
2690	    TRACE(("CASE_BS - backspace\n"));
2691	    CursorBack(xw, 1);
2692	    break;
2693
2694	case CASE_CR:
2695	    TRACE(("CASE_CR\n"));
2696	    CarriageReturn(xw);
2697	    break;
2698
2699	case CASE_ESC:
2700	    if_OPT_VT52_MODE(screen, {
2701		sp->parsestate = vt52_esc_table;
2702		break;
2703	    });
2704	    sp->parsestate = esc_table;
2705	    break;
2706
2707#if OPT_VT52_MODE
2708	case CASE_VT52_CUP:
2709	    TRACE(("CASE_VT52_CUP - VT52 cursor addressing\n"));
2710	    sp->vt52_cup = True;
2711	    ResetState(sp);
2712	    break;
2713
2714	case CASE_VT52_IGNORE:
2715	    TRACE(("CASE_VT52_IGNORE - VT52 ignore-character\n"));
2716	    sp->parsestate = vt52_ignore_table;
2717	    break;
2718#endif
2719
2720	case CASE_VMOT:
2721	    TRACE(("CASE_VMOT\n"));
2722	    /*
2723	     * form feed, line feed, vertical tab
2724	     */
2725	    xtermAutoPrint(xw, c);
2726	    xtermIndex(xw, 1);
2727	    if (xw->flags & LINEFEED)
2728		CarriageReturn(xw);
2729	    else
2730		do_xevents(xw);
2731	    break;
2732
2733	case CASE_CBT:
2734	    TRACE(("CASE_CBT\n"));
2735	    /* cursor backward tabulation */
2736	    count = one_if_default(0);
2737	    while ((count-- > 0)
2738		   && (TabToPrevStop(xw))) ;
2739	    ResetState(sp);
2740	    break;
2741
2742	case CASE_CHT:
2743	    TRACE(("CASE_CHT\n"));
2744	    /* cursor forward tabulation */
2745	    count = one_if_default(0);
2746	    while ((count-- > 0)
2747		   && (TabToNextStop(xw))) ;
2748	    ResetState(sp);
2749	    break;
2750
2751	case CASE_TAB:
2752	    /* tab */
2753	    TabToNextStop(xw);
2754	    break;
2755
2756	case CASE_SI:
2757	    screen->curgl = 0;
2758	    if_OPT_VT52_MODE(screen, {
2759		ResetState(sp);
2760	    });
2761	    break;
2762
2763	case CASE_SO:
2764	    screen->curgl = 1;
2765	    if_OPT_VT52_MODE(screen, {
2766		ResetState(sp);
2767	    });
2768	    break;
2769
2770	case CASE_DECDHL:
2771	    xterm_DECDHL(xw, c == '3');
2772	    ResetState(sp);
2773	    break;
2774
2775	case CASE_DECSWL:
2776	    xterm_DECSWL(xw);
2777	    ResetState(sp);
2778	    break;
2779
2780	case CASE_DECDWL:
2781	    xterm_DECDWL(xw);
2782	    ResetState(sp);
2783	    break;
2784
2785	case CASE_SCR_STATE:
2786	    /* enter scr state */
2787	    sp->parsestate = scrtable;
2788	    break;
2789
2790	case CASE_SCS0_STATE:
2791	    /* enter scs state 0 */
2792	    select_charset(sp, 0, 94);
2793	    break;
2794
2795	case CASE_SCS1_STATE:
2796	    /* enter scs state 1 */
2797	    select_charset(sp, 1, 94);
2798	    break;
2799
2800	case CASE_SCS2_STATE:
2801	    /* enter scs state 2 */
2802	    select_charset(sp, 2, 94);
2803	    break;
2804
2805	case CASE_SCS3_STATE:
2806	    /* enter scs state 3 */
2807	    select_charset(sp, 3, 94);
2808	    break;
2809
2810	case CASE_SCS1A_STATE:
2811	    /* enter scs state 1 */
2812	    select_charset(sp, 1, 96);
2813	    break;
2814
2815	case CASE_SCS2A_STATE:
2816	    /* enter scs state 2 */
2817	    select_charset(sp, 2, 96);
2818	    break;
2819
2820	case CASE_SCS3A_STATE:
2821	    /* enter scs state 3 */
2822	    select_charset(sp, 3, 96);
2823	    break;
2824
2825	case CASE_ESC_IGNORE:
2826	    /* unknown escape sequence */
2827	    sp->parsestate = eigtable;
2828	    break;
2829
2830	case CASE_ESC_DIGIT:
2831	    /* digit in csi or dec mode */
2832	    if (nparam > 0) {
2833		value = zero_if_default(nparam - 1);
2834		SetParam(nparam - 1, (10 * value) + ((int) c - '0'));
2835		if (GetParam(nparam - 1) > MAX_I_PARAM)
2836		    SetParam(nparam - 1, MAX_I_PARAM);
2837		if (sp->parsestate == csi_table)
2838		    sp->parsestate = csi2_table;
2839	    }
2840	    break;
2841
2842	case CASE_ESC_SEMI:
2843	    /* semicolon in csi or dec mode */
2844	    if (nparam < NPARAM) {
2845		parms.is_sub[nparam] = 0;
2846		SetParam(nparam++, DEFAULT);
2847	    }
2848	    if (sp->parsestate == csi_table)
2849		sp->parsestate = csi2_table;
2850	    break;
2851
2852	    /*
2853	     * A _few_ commands accept colon-separated subparameters.
2854	     * Mark the parameter list so that we can exclude (most) bogus
2855	     * commands with simple/fast checks.
2856	     */
2857	case CASE_ESC_COLON:
2858	    if (nparam < NPARAM) {
2859		parms.has_subparams = 1;
2860		if (nparam == 0) {
2861		    parms.is_sub[nparam] = 1;
2862		    SetParam(nparam++, DEFAULT);
2863		} else if (parms.is_sub[nparam - 1] == 0) {
2864		    parms.is_sub[nparam - 1] = 1;
2865		    parms.is_sub[nparam] = 2;
2866		    parms.params[nparam] = 0;
2867		    ++nparam;
2868		} else {
2869		    parms.is_sub[nparam] = 1 + parms.is_sub[nparam - 1];
2870		    parms.params[nparam] = 0;
2871		    ++nparam;
2872		}
2873	    }
2874	    break;
2875
2876	case CASE_DEC_STATE:
2877	    /* enter dec mode */
2878	    sp->parsestate = dec_table;
2879	    break;
2880
2881	case CASE_DEC2_STATE:
2882	    /* enter dec2 mode */
2883	    sp->parsestate = dec2_table;
2884	    break;
2885
2886	case CASE_DEC3_STATE:
2887	    /* enter dec3 mode */
2888	    sp->parsestate = dec3_table;
2889	    break;
2890
2891	case CASE_ICH:
2892	    TRACE(("CASE_ICH - insert char\n"));
2893	    InsertChar(xw, (unsigned) one_if_default(0));
2894	    ResetState(sp);
2895	    break;
2896
2897	case CASE_CUU:
2898	    TRACE(("CASE_CUU - cursor up\n"));
2899	    CursorUp(screen, one_if_default(0));
2900	    ResetState(sp);
2901	    break;
2902
2903	case CASE_CUD:
2904	    TRACE(("CASE_CUD - cursor down\n"));
2905	    CursorDown(screen, one_if_default(0));
2906	    ResetState(sp);
2907	    break;
2908
2909	case CASE_CUF:
2910	    TRACE(("CASE_CUF - cursor forward\n"));
2911	    CursorForward(xw, one_if_default(0));
2912	    ResetState(sp);
2913	    break;
2914
2915	case CASE_CUB:
2916	    TRACE(("CASE_CUB - cursor backward\n"));
2917	    CursorBack(xw, one_if_default(0));
2918	    ResetState(sp);
2919	    break;
2920
2921	case CASE_CUP:
2922	    TRACE(("CASE_CUP - cursor position\n"));
2923	    if_OPT_XMC_GLITCH(screen, {
2924		Jump_XMC(xw);
2925	    });
2926	    CursorSet(screen, one_if_default(0) - 1, one_if_default(1) - 1, xw->flags);
2927	    ResetState(sp);
2928	    break;
2929
2930	case CASE_VPA:
2931	    TRACE(("CASE_VPA - vertical position absolute\n"));
2932	    CursorSet(screen, one_if_default(0) - 1, CursorCol(xw), xw->flags);
2933	    ResetState(sp);
2934	    break;
2935
2936	case CASE_HPA:
2937	    TRACE(("CASE_HPA - horizontal position absolute\n"));
2938	    CursorSet(screen, CursorRow(xw), one_if_default(0) - 1, xw->flags);
2939	    ResetState(sp);
2940	    break;
2941
2942	case CASE_VPR:
2943	    TRACE(("CASE_VPR - vertical position relative\n"));
2944	    CursorSet(screen,
2945		      CursorRow(xw) + one_if_default(0),
2946		      CursorCol(xw),
2947		      xw->flags);
2948	    ResetState(sp);
2949	    break;
2950
2951	case CASE_HPR:
2952	    TRACE(("CASE_HPR - horizontal position relative\n"));
2953	    CursorSet(screen,
2954		      CursorRow(xw),
2955		      CursorCol(xw) + one_if_default(0),
2956		      xw->flags);
2957	    ResetState(sp);
2958	    break;
2959
2960	case CASE_HP_BUGGY_LL:
2961	    TRACE(("CASE_HP_BUGGY_LL\n"));
2962	    /* Some HP-UX applications have the bug that they
2963	       assume ESC F goes to the lower left corner of
2964	       the screen, regardless of what terminfo says. */
2965	    if (screen->hp_ll_bc)
2966		CursorSet(screen, screen->max_row, 0, xw->flags);
2967	    ResetState(sp);
2968	    break;
2969
2970	case CASE_ED:
2971	    TRACE(("CASE_ED - erase display\n"));
2972	    do_cd_xtra_scroll(xw);
2973	    do_erase_display(xw, zero_if_default(0), OFF_PROTECT);
2974	    ResetState(sp);
2975	    break;
2976
2977	case CASE_EL:
2978	    TRACE(("CASE_EL - erase line\n"));
2979	    do_erase_line(xw, zero_if_default(0), OFF_PROTECT);
2980	    ResetState(sp);
2981	    break;
2982
2983	case CASE_ECH:
2984	    TRACE(("CASE_ECH - erase char\n"));
2985	    /* ECH */
2986	    do_erase_char(xw, one_if_default(0), OFF_PROTECT);
2987	    ResetState(sp);
2988	    break;
2989
2990	case CASE_IL:
2991	    TRACE(("CASE_IL - insert line\n"));
2992	    InsertLine(xw, one_if_default(0));
2993	    ResetState(sp);
2994	    break;
2995
2996	case CASE_DL:
2997	    TRACE(("CASE_DL - delete line\n"));
2998	    DeleteLine(xw, one_if_default(0));
2999	    ResetState(sp);
3000	    break;
3001
3002	case CASE_DCH:
3003	    TRACE(("CASE_DCH - delete char\n"));
3004	    DeleteChar(xw, (unsigned) one_if_default(0));
3005	    ResetState(sp);
3006	    break;
3007
3008	case CASE_TRACK_MOUSE:
3009	    /*
3010	     * A single parameter other than zero is always scroll-down.
3011	     * A zero-parameter is used to reset the mouse mode, and is
3012	     * not useful for scrolling anyway.
3013	     */
3014	    if (nparam > 1 || GetParam(0) == 0) {
3015		CELL start;
3016
3017		TRACE(("CASE_TRACK_MOUSE\n"));
3018		/* Track mouse as long as in window and between
3019		 * specified rows
3020		 */
3021		start.row = one_if_default(2) - 1;
3022		start.col = GetParam(1) - 1;
3023		TrackMouse(xw,
3024			   GetParam(0),
3025			   &start,
3026			   GetParam(3) - 1, GetParam(4) - 2);
3027	    } else {
3028		TRACE(("CASE_SD - scroll down\n"));
3029		/* SD */
3030		RevScroll(xw, one_if_default(0));
3031		do_xevents(xw);
3032	    }
3033	    ResetState(sp);
3034	    break;
3035
3036	case CASE_SD:
3037	    /*
3038	     * Cater to ECMA-48's typographical error...
3039	     */
3040	    TRACE(("CASE_SD - scroll down\n"));
3041	    RevScroll(xw, one_if_default(0));
3042	    do_xevents(xw);
3043	    ResetState(sp);
3044	    break;
3045
3046	case CASE_DECID:
3047	    TRACE(("CASE_DECID\n"));
3048	    if_OPT_VT52_MODE(screen, {
3049		unparseputc(xw, ANSI_ESC);
3050		unparseputc(xw, '/');
3051		unparseputc(xw, 'Z');
3052		unparse_end(xw);
3053		ResetState(sp);
3054		break;
3055	    });
3056	    SetParam(0, DEFAULT);	/* Default ID parameter */
3057	    /* FALLTHRU */
3058	case CASE_DA1:
3059	    TRACE(("CASE_DA1\n"));
3060	    if (GetParam(0) <= 0) {	/* less than means DEFAULT */
3061		count = 0;
3062		init_reply(ANSI_CSI);
3063		reply.a_pintro = '?';
3064
3065		/*
3066		 * The first parameter corresponds to the highest operating
3067		 * level (i.e., service level) of the emulation.  A DEC
3068		 * terminal can be setup to respond with a different DA
3069		 * response, but there's no control sequence that modifies
3070		 * this.  We set it via a resource.
3071		 */
3072		if (screen->terminal_id < 200) {
3073		    switch (screen->terminal_id) {
3074		    case 132:
3075			reply.a_param[count++] = 4;	/* VT132 */
3076#if OPT_REGIS_GRAPHICS
3077			reply.a_param[count++] = 6;	/* no STP, AVO, GPO (ReGIS) */
3078#else
3079			reply.a_param[count++] = 2;	/* no STP, AVO, no GPO (ReGIS) */
3080#endif
3081			break;
3082		    case 131:
3083			reply.a_param[count++] = 7;	/* VT131 */
3084			break;
3085		    case 125:
3086			reply.a_param[count++] = 12;	/* VT125 */
3087#if OPT_REGIS_GRAPHICS
3088			reply.a_param[count++] = 0 | 2 | 1;	/* no STP, AVO, GPO (ReGIS) */
3089#else
3090			reply.a_param[count++] = 0 | 2 | 0;	/* no STP, AVO, no GPO (ReGIS) */
3091#endif
3092			reply.a_param[count++] = 0;	/* no printer */
3093			reply.a_param[count++] = XTERM_PATCH;	/* ROM version */
3094			break;
3095		    case 102:
3096			reply.a_param[count++] = 6;	/* VT102 */
3097			break;
3098		    case 101:
3099			reply.a_param[count++] = 1;	/* VT101 */
3100			reply.a_param[count++] = 0;	/* no options */
3101			break;
3102		    default:	/* VT100 */
3103			reply.a_param[count++] = 1;	/* VT100 */
3104			reply.a_param[count++] = 0 | 2 | 0;	/* no STP, AVO, no GPO (ReGIS) */
3105			break;
3106		    }
3107		} else {
3108		    reply.a_param[count++] = (ParmType) (60
3109							 + screen->terminal_id
3110							 / 100);
3111		    reply.a_param[count++] = 1;		/* 132-columns */
3112		    reply.a_param[count++] = 2;		/* printer */
3113#if OPT_REGIS_GRAPHICS
3114		    if (optRegisGraphics(screen)) {
3115			reply.a_param[count++] = 3;	/* ReGIS graphics */
3116		    }
3117#endif
3118#if OPT_SIXEL_GRAPHICS
3119		    if (optSixelGraphics(screen)) {
3120			reply.a_param[count++] = 4;	/* sixel graphics */
3121		    }
3122#endif
3123		    reply.a_param[count++] = 6;		/* selective-erase */
3124#if OPT_SUNPC_KBD
3125		    if (xw->keyboard.type == keyboardIsVT220)
3126#endif
3127			reply.a_param[count++] = 8;	/* user-defined-keys */
3128		    reply.a_param[count++] = 9;		/* national replacement charsets */
3129		    reply.a_param[count++] = 15;	/* technical characters */
3130		    reply.a_param[count++] = 16;	/* locator port */
3131		    if (screen->terminal_id >= 400) {
3132			reply.a_param[count++] = 17;	/* terminal state interrogation */
3133			reply.a_param[count++] = 18;	/* windowing extension */
3134			reply.a_param[count++] = 21;	/* horizontal scrolling */
3135		    }
3136		    if_OPT_ISO_COLORS(screen, {
3137			reply.a_param[count++] = 22;	/* ANSI color, VT525 */
3138		    });
3139		    reply.a_param[count++] = 28;	/* rectangular editing */
3140#if OPT_DEC_LOCATOR
3141		    reply.a_param[count++] = 29;	/* ANSI text locator */
3142#endif
3143		}
3144		reply.a_nparam = (ParmType) count;
3145		reply.a_inters = 0;
3146		reply.a_final = 'c';
3147		unparseseq(xw, &reply);
3148	    }
3149	    ResetState(sp);
3150	    break;
3151
3152	case CASE_DA2:
3153	    TRACE(("CASE_DA2\n"));
3154	    if (GetParam(0) <= 0) {	/* less than means DEFAULT */
3155		count = 0;
3156		init_reply(ANSI_CSI);
3157		reply.a_pintro = '>';
3158
3159		if (screen->terminal_id >= 200) {
3160		    switch (screen->terminal_id) {
3161		    case 220:
3162		    default:
3163			reply.a_param[count++] = 1;	/* VT220 */
3164			break;
3165		    case 240:
3166		    case 241:
3167			/* http://www.decuslib.com/DECUS/vax87a/gendyn/vt200_kind.lis */
3168			reply.a_param[count++] = 2;	/* VT240 */
3169			break;
3170		    case 320:
3171			/* http://www.vt100.net/docs/vt320-uu/appendixe.html */
3172			reply.a_param[count++] = 24;	/* VT320 */
3173			break;
3174		    case 330:
3175			reply.a_param[count++] = 18;	/* VT330 */
3176			break;
3177		    case 340:
3178			reply.a_param[count++] = 19;	/* VT340 */
3179			break;
3180		    case 382:
3181			reply.a_param[count++] = 32;	/* VT382 */
3182			break;
3183		    case 420:
3184			reply.a_param[count++] = 41;	/* VT420 */
3185			break;
3186		    case 510:
3187			/* http://www.vt100.net/docs/vt510-rm/DA2 */
3188			reply.a_param[count++] = 61;	/* VT510 */
3189			break;
3190		    case 520:
3191			reply.a_param[count++] = 64;	/* VT520 */
3192			break;
3193		    case 525:
3194			reply.a_param[count++] = 65;	/* VT525 */
3195			break;
3196		    }
3197		} else {
3198		    reply.a_param[count++] = 0;		/* VT100 (nonstandard) */
3199		}
3200		reply.a_param[count++] = XTERM_PATCH;	/* Version */
3201		reply.a_param[count++] = 0;	/* options (none) */
3202		reply.a_nparam = (ParmType) count;
3203		reply.a_inters = 0;
3204		reply.a_final = 'c';
3205		unparseseq(xw, &reply);
3206	    }
3207	    ResetState(sp);
3208	    break;
3209
3210	case CASE_DECRPTUI:
3211	    TRACE(("CASE_DECRPTUI\n"));
3212	    if ((screen->vtXX_level >= 4)
3213		&& (GetParam(0) <= 0)) {	/* less than means DEFAULT */
3214		unparseputc1(xw, ANSI_DCS);
3215		unparseputc(xw, '!');
3216		unparseputc(xw, '|');
3217		/* report the "terminal unit id" as 4 pairs of hexadecimal
3218		 * digits -- meaningless for a terminal emulator, but some
3219		 * host may care about the format.
3220		 */
3221		for (count = 0; count < 8; ++count) {
3222		    unparseputc(xw, '0');
3223		}
3224		unparseputc1(xw, ANSI_ST);
3225		unparse_end(xw);
3226	    }
3227	    ResetState(sp);
3228	    break;
3229
3230	case CASE_TBC:
3231	    TRACE(("CASE_TBC - tab clear\n"));
3232	    if ((value = GetParam(0)) <= 0)	/* less than means default */
3233		TabClear(xw->tabs, screen->cur_col);
3234	    else if (value == 3)
3235		TabZonk(xw->tabs);
3236	    ResetState(sp);
3237	    break;
3238
3239	case CASE_SET:
3240	    TRACE(("CASE_SET - set mode\n"));
3241	    ansi_modes(xw, bitset);
3242	    ResetState(sp);
3243	    break;
3244
3245	case CASE_RST:
3246	    TRACE(("CASE_RST - reset mode\n"));
3247	    ansi_modes(xw, bitclr);
3248	    ResetState(sp);
3249	    break;
3250
3251	case CASE_SGR:
3252	    for (item = 0; item < nparam; ++item) {
3253		int op = GetParam(item);
3254		int skip;
3255
3256		if_OPT_XMC_GLITCH(screen, {
3257		    Mark_XMC(xw, op);
3258		});
3259		TRACE(("CASE_SGR %d\n", op));
3260
3261		/*
3262		 * Only SGR 38/48 accept subparameters, and in those cases
3263		 * the values will not be seen at this point.
3264		 */
3265		if ((skip = param_has_subparams(item))) {
3266		    switch (op) {
3267		    case 38:
3268			/* FALLTHRU */
3269		    case 48:
3270			if_OPT_ISO_COLORS(screen, {
3271			    break;
3272			});
3273			/* FALLTHRU */
3274		    default:
3275			TRACE(("...unexpected subparameter in SGR\n"));
3276			item += skip;	/* ignore this */
3277			op = NPARAM;	/* will never use this, anyway */
3278			break;
3279		    }
3280		}
3281
3282		switch (op) {
3283		case DEFAULT:
3284		    /* FALLTHRU */
3285		case 0:
3286		    resetRendition(xw);
3287		    if_OPT_ISO_COLORS(screen, {
3288			reset_SGR_Colors(xw);
3289		    });
3290		    break;
3291		case 1:	/* Bold                 */
3292		    UIntSet(xw->flags, BOLD);
3293		    if_OPT_ISO_COLORS(screen, {
3294			setExtendedFG(xw);
3295		    });
3296		    break;
3297#if OPT_WIDE_ATTRS
3298		case 2:	/* faint, decreased intensity or second colour */
3299		    UIntSet(xw->flags, ATR_FAINT);
3300		    if_OPT_ISO_COLORS(screen, {
3301			setExtendedFG(xw);
3302		    });
3303		    break;
3304		case 3:	/* italicized */
3305		    setItalicFont(xw, UseItalicFont(screen));
3306		    UIntSet(xw->flags, ATR_ITALIC);
3307		    if_OPT_ISO_COLORS(screen, {
3308			setExtendedFG(xw);
3309		    });
3310		    break;
3311#endif
3312		case 4:	/* Underscore           */
3313		    UIntSet(xw->flags, UNDERLINE);
3314		    if_OPT_ISO_COLORS(screen, {
3315			setExtendedFG(xw);
3316		    });
3317		    break;
3318		case 5:	/* Blink (less than 150 per minute) */
3319		    /* FALLTHRU */
3320		case 6:	/* Blink (150 per minute, or more) */
3321		    UIntSet(xw->flags, BLINK);
3322		    StartBlinking(xw);
3323		    if_OPT_ISO_COLORS(screen, {
3324			setExtendedFG(xw);
3325		    });
3326		    break;
3327		case 7:
3328		    UIntSet(xw->flags, INVERSE);
3329		    if_OPT_ISO_COLORS(screen, {
3330			setExtendedBG(xw);
3331		    });
3332		    break;
3333		case 8:
3334		    UIntSet(xw->flags, INVISIBLE);
3335		    break;
3336#if OPT_WIDE_ATTRS
3337		case 9:	/* crossed-out characters */
3338		    UIntSet(xw->flags, ATR_STRIKEOUT);
3339		    break;
3340#endif
3341#if OPT_WIDE_ATTRS
3342		case 21:	/* doubly-underlined */
3343		    UIntSet(xw->flags, ATR_DBL_UNDER);
3344		    break;
3345#endif
3346		case 22:	/* reset 'bold' */
3347		    UIntClr(xw->flags, BOLD);
3348#if OPT_WIDE_ATTRS
3349		    UIntClr(xw->flags, ATR_FAINT);
3350#endif
3351		    if_OPT_ISO_COLORS(screen, {
3352			setExtendedFG(xw);
3353		    });
3354		    break;
3355#if OPT_WIDE_ATTRS
3356		case 23:	/* not italicized */
3357		    ResetItalics(xw);
3358		    if_OPT_ISO_COLORS(screen, {
3359			setExtendedFG(xw);
3360		    });
3361		    break;
3362#endif
3363		case 24:
3364		    UIntClr(xw->flags, UNDERLINE);
3365#if OPT_WIDE_ATTRS
3366		    UIntClr(xw->flags, ATR_DBL_UNDER);
3367#endif
3368		    if_OPT_ISO_COLORS(screen, {
3369			setExtendedFG(xw);
3370		    });
3371		    break;
3372		case 25:	/* reset 'blink' */
3373		    UIntClr(xw->flags, BLINK);
3374		    if_OPT_ISO_COLORS(screen, {
3375			setExtendedFG(xw);
3376		    });
3377		    break;
3378		case 27:
3379		    UIntClr(xw->flags, INVERSE);
3380		    if_OPT_ISO_COLORS(screen, {
3381			setExtendedBG(xw);
3382		    });
3383		    break;
3384		case 28:
3385		    UIntClr(xw->flags, INVISIBLE);
3386		    break;
3387#if OPT_WIDE_ATTRS
3388		case 29:	/* not crossed out */
3389		    UIntClr(xw->flags, ATR_STRIKEOUT);
3390		    break;
3391#endif
3392		case 30:
3393		    /* FALLTHRU */
3394		case 31:
3395		    /* FALLTHRU */
3396		case 32:
3397		    /* FALLTHRU */
3398		case 33:
3399		    /* FALLTHRU */
3400		case 34:
3401		    /* FALLTHRU */
3402		case 35:
3403		    /* FALLTHRU */
3404		case 36:
3405		    /* FALLTHRU */
3406		case 37:
3407		    if_OPT_ISO_COLORS(screen, {
3408			xw->sgr_foreground = (op - 30);
3409			xw->sgr_38_xcolors = False;
3410			clrDirectFG(xw->flags);
3411			setExtendedFG(xw);
3412		    });
3413		    break;
3414		case 38:
3415		    /* This is more complicated than I'd like, but it should
3416		     * properly eat all the parameters for unsupported modes.
3417		     */
3418		    if_OPT_ISO_COLORS(screen, {
3419			Boolean extended;
3420			if (parse_extended_colors(xw, &value, &item,
3421						  &extended)) {
3422			    xw->sgr_foreground = value;
3423			    xw->sgr_38_xcolors = True;
3424			    setDirectFG(xw->flags, extended);
3425			    setExtendedFG(xw);
3426			}
3427		    });
3428		    break;
3429		case 39:
3430		    if_OPT_ISO_COLORS(screen, {
3431			reset_SGR_Foreground(xw);
3432		    });
3433		    break;
3434		case 40:
3435		    /* FALLTHRU */
3436		case 41:
3437		    /* FALLTHRU */
3438		case 42:
3439		    /* FALLTHRU */
3440		case 43:
3441		    /* FALLTHRU */
3442		case 44:
3443		    /* FALLTHRU */
3444		case 45:
3445		    /* FALLTHRU */
3446		case 46:
3447		    /* FALLTHRU */
3448		case 47:
3449		    if_OPT_ISO_COLORS(screen, {
3450			xw->sgr_background = (op - 40);
3451			clrDirectBG(xw->flags);
3452			setExtendedBG(xw);
3453		    });
3454		    break;
3455		case 48:
3456		    if_OPT_ISO_COLORS(screen, {
3457			Boolean extended;
3458			if (parse_extended_colors(xw, &value, &item,
3459						  &extended)) {
3460			    xw->sgr_background = value;
3461			    setDirectBG(xw->flags, extended);
3462			    setExtendedBG(xw);
3463			}
3464		    });
3465		    break;
3466		case 49:
3467		    if_OPT_ISO_COLORS(screen, {
3468			reset_SGR_Background(xw);
3469		    });
3470		    break;
3471		case 90:
3472		    /* FALLTHRU */
3473		case 91:
3474		    /* FALLTHRU */
3475		case 92:
3476		    /* FALLTHRU */
3477		case 93:
3478		    /* FALLTHRU */
3479		case 94:
3480		    /* FALLTHRU */
3481		case 95:
3482		    /* FALLTHRU */
3483		case 96:
3484		    /* FALLTHRU */
3485		case 97:
3486		    if_OPT_AIX_COLORS(screen, {
3487			xw->sgr_foreground = (op - 90 + 8);
3488			clrDirectFG(xw->flags);
3489			setExtendedFG(xw);
3490		    });
3491		    break;
3492		case 100:
3493#if !OPT_AIX_COLORS
3494		    if_OPT_ISO_COLORS(screen, {
3495			reset_SGR_Foreground(xw);
3496			reset_SGR_Background(xw);
3497		    });
3498		    break;
3499#endif
3500		case 101:
3501		    /* FALLTHRU */
3502		case 102:
3503		    /* FALLTHRU */
3504		case 103:
3505		    /* FALLTHRU */
3506		case 104:
3507		    /* FALLTHRU */
3508		case 105:
3509		    /* FALLTHRU */
3510		case 106:
3511		    /* FALLTHRU */
3512		case 107:
3513		    if_OPT_AIX_COLORS(screen, {
3514			xw->sgr_background = (op - 100 + 8);
3515			clrDirectBG(xw->flags);
3516			setExtendedBG(xw);
3517		    });
3518		    break;
3519		default:
3520		    /* later: skip += NPARAM; */
3521		    break;
3522		}
3523	    }
3524	    ResetState(sp);
3525	    break;
3526
3527	    /* DSR (except for the '?') is a superset of CPR */
3528	case CASE_DSR:
3529	    sp->private_function = True;
3530
3531	    /* FALLTHRU */
3532	case CASE_CPR:
3533	    TRACE(("CASE_DSR - device status report\n"));
3534	    count = 0;
3535	    init_reply(ANSI_CSI);
3536	    reply.a_pintro = CharOf(sp->private_function ? '?' : 0);
3537	    reply.a_inters = 0;
3538	    reply.a_final = 'n';
3539
3540	    switch (GetParam(0)) {
3541	    case 5:
3542		TRACE(("...request operating status\n"));
3543		/* operating status */
3544		reply.a_param[count++] = 0;	/* (no malfunction ;-) */
3545		break;
3546	    case 6:
3547		TRACE(("...request %s\n",
3548		       (sp->private_function
3549			? "DECXCPR"
3550			: "CPR")));
3551		/* CPR */
3552		/* DECXCPR (with page=1) */
3553		value = (screen->cur_row + 1);
3554		if ((xw->flags & ORIGIN) != 0) {
3555		    value -= screen->top_marg;
3556		}
3557		reply.a_param[count++] = (ParmType) value;
3558
3559		value = (screen->cur_col + 1);
3560		if ((xw->flags & ORIGIN) != 0) {
3561		    value -= screen->lft_marg;
3562		}
3563		reply.a_param[count++] = (ParmType) value;
3564
3565		if (sp->private_function
3566		    && screen->vtXX_level >= 4) {	/* VT420 */
3567		    reply.a_param[count++] = 1;
3568		}
3569		reply.a_final = 'R';
3570		break;
3571	    case 15:
3572		TRACE(("...request printer status\n"));
3573		if (sp->private_function
3574		    && screen->vtXX_level >= 2) {	/* VT220 */
3575		    reply.a_param[count++] = 13;	/* no printer detected */
3576		}
3577		break;
3578	    case 25:
3579		TRACE(("...request UDK status\n"));
3580		if (sp->private_function
3581		    && screen->vtXX_level >= 2) {	/* VT220 */
3582		    reply.a_param[count++] = 20;	/* UDK always unlocked */
3583		}
3584		break;
3585	    case 26:
3586		TRACE(("...request keyboard status\n"));
3587		if (sp->private_function
3588		    && screen->vtXX_level >= 2) {	/* VT220 */
3589		    reply.a_param[count++] = 27;
3590		    reply.a_param[count++] = 1;		/* North American */
3591		    if (screen->vtXX_level >= 3) {	/* VT320 */
3592			reply.a_param[count++] = 0;	/* ready */
3593		    }
3594		    if (screen->vtXX_level >= 4) {	/* VT420 */
3595			reply.a_param[count++] = 0;	/* LK201 */
3596		    }
3597		}
3598		break;
3599	    case 53:		/* according to existing xterm handling */
3600		/* FALLTHRU */
3601	    case 55:		/* according to the VT330/VT340 Text Programming Manual */
3602		TRACE(("...request locator status\n"));
3603		if (sp->private_function
3604		    && screen->vtXX_level >= 3) {	/* VT330 */
3605#if OPT_DEC_LOCATOR
3606		    reply.a_param[count++] = 50;	/* locator ready */
3607#else
3608		    reply.a_param[count++] = 53;	/* no locator */
3609#endif
3610		}
3611		break;
3612	    case 56:
3613		TRACE(("...request locator type\n"));
3614		if (sp->private_function
3615		    && screen->vtXX_level >= 3) {	/* VT330 */
3616		    reply.a_param[count++] = 57;
3617#if OPT_DEC_LOCATOR
3618		    reply.a_param[count++] = 1;		/* mouse */
3619#else
3620		    reply.a_param[count++] = 0;		/* unknown */
3621#endif
3622		}
3623		break;
3624	    case 62:
3625		TRACE(("...request DECMSR - macro space\n"));
3626		if (sp->private_function
3627		    && screen->vtXX_level >= 4) {	/* VT420 */
3628		    reply.a_pintro = 0;
3629		    reply.a_radix[count] = 16;	/* no data */
3630		    reply.a_param[count++] = 0;		/* no space for macros */
3631		    reply.a_inters = '*';
3632		    reply.a_final = L_CURL;
3633		}
3634		break;
3635	    case 63:
3636		TRACE(("...request DECCKSR - memory checksum\n"));
3637		/* DECCKSR - Memory checksum */
3638		if (sp->private_function
3639		    && screen->vtXX_level >= 4) {	/* VT420 */
3640		    init_reply(ANSI_DCS);
3641		    reply.a_param[count++] = (ParmType) GetParam(1);	/* PID */
3642		    reply.a_delim = "!~";	/* delimiter */
3643		    reply.a_radix[count] = 16;	/* use hex */
3644		    reply.a_param[count++] = 0;		/* no data */
3645		}
3646		break;
3647	    case 75:
3648		TRACE(("...request data integrity\n"));
3649		if (sp->private_function
3650		    && screen->vtXX_level >= 4) {	/* VT420 */
3651		    reply.a_param[count++] = 70;	/* no errors */
3652		}
3653		break;
3654	    case 85:
3655		TRACE(("...request multi-session configuration\n"));
3656		if (sp->private_function
3657		    && screen->vtXX_level >= 4) {	/* VT420 */
3658		    reply.a_param[count++] = 83;	/* not configured */
3659		}
3660		break;
3661	    default:
3662		break;
3663	    }
3664
3665	    if ((reply.a_nparam = (ParmType) count) != 0)
3666		unparseseq(xw, &reply);
3667
3668	    ResetState(sp);
3669	    sp->private_function = False;
3670	    break;
3671
3672	case CASE_MC:
3673	    TRACE(("CASE_MC - media control\n"));
3674	    xtermMediaControl(xw, GetParam(0), False);
3675	    ResetState(sp);
3676	    break;
3677
3678	case CASE_DEC_MC:
3679	    TRACE(("CASE_DEC_MC - DEC media control\n"));
3680	    xtermMediaControl(xw, GetParam(0), True);
3681	    ResetState(sp);
3682	    break;
3683
3684	case CASE_HP_MEM_LOCK:
3685	    /* FALLTHRU */
3686	case CASE_HP_MEM_UNLOCK:
3687	    TRACE(("%s\n", ((sp->parsestate[c] == CASE_HP_MEM_LOCK)
3688			    ? "CASE_HP_MEM_LOCK"
3689			    : "CASE_HP_MEM_UNLOCK")));
3690	    if (screen->scroll_amt)
3691		FlushScroll(xw);
3692	    if (sp->parsestate[c] == CASE_HP_MEM_LOCK)
3693		set_tb_margins(screen, screen->cur_row, screen->bot_marg);
3694	    else
3695		set_tb_margins(screen, 0, screen->bot_marg);
3696	    ResetState(sp);
3697	    break;
3698
3699	case CASE_DECSTBM:
3700	    TRACE(("CASE_DECSTBM - set scrolling region\n"));
3701	    {
3702		int top;
3703		int bot;
3704		top = one_if_default(0);
3705		if (nparam < 2 || (bot = GetParam(1)) == DEFAULT
3706		    || bot > MaxRows(screen)
3707		    || bot == 0)
3708		    bot = MaxRows(screen);
3709		if (bot > top) {
3710		    if (screen->scroll_amt)
3711			FlushScroll(xw);
3712		    set_tb_margins(screen, top - 1, bot - 1);
3713		    CursorSet(screen, 0, 0, xw->flags);
3714		}
3715		ResetState(sp);
3716	    }
3717	    break;
3718
3719	case CASE_DECREQTPARM:
3720	    TRACE(("CASE_DECREQTPARM\n"));
3721	    if (screen->terminal_id < 200) {	/* VT102 */
3722		value = zero_if_default(0);
3723		if (value == 0 || value == 1) {
3724		    init_reply(ANSI_CSI);
3725		    reply.a_pintro = 0;
3726		    reply.a_nparam = 7;
3727		    reply.a_param[0] = (ParmType) (value + 2);
3728		    reply.a_param[1] = 1;	/* no parity */
3729		    reply.a_param[2] = 1;	/* eight bits */
3730		    reply.a_param[3] = 128;	/* transmit 38.4k baud */
3731		    reply.a_param[4] = 128;	/* receive 38.4k baud */
3732		    reply.a_param[5] = 1;	/* clock multiplier ? */
3733		    reply.a_param[6] = 0;	/* STP flags ? */
3734		    reply.a_inters = 0;
3735		    reply.a_final = 'x';
3736		    unparseseq(xw, &reply);
3737		}
3738	    }
3739	    ResetState(sp);
3740	    break;
3741
3742	case CASE_DECSET:
3743	    /* DECSET */
3744#if OPT_VT52_MODE
3745	    if (screen->vtXX_level != 0)
3746#endif
3747		dpmodes(xw, bitset);
3748	    ResetState(sp);
3749#if OPT_TEK4014
3750	    if (TEK4014_ACTIVE(xw)) {
3751		TRACE(("Tek4014 is now active...\n"));
3752		if (sp->check_recur)
3753		    sp->check_recur--;
3754		return False;
3755	    }
3756#endif
3757	    break;
3758
3759	case CASE_DECRST:
3760	    /* DECRST */
3761	    dpmodes(xw, bitclr);
3762	    init_groundtable(screen, sp);
3763	    ResetState(sp);
3764	    break;
3765
3766	case CASE_DECALN:
3767	    TRACE(("CASE_DECALN - alignment test\n"));
3768	    if (screen->cursor_state)
3769		HideCursor(xw);
3770	    /*
3771	     * DEC STD 070 does not mention left/right margins.  Likely the
3772	     * text was for VT100, and not updated for VT420.
3773	     */
3774	    resetRendition(xw);
3775	    resetMargins(xw);
3776	    CursorSet(screen, 0, 0, xw->flags);
3777	    xtermParseRect(xw, 0, 0, &myRect);
3778	    ScrnFillRectangle(xw, &myRect, 'E', 0, False);
3779	    ResetState(sp);
3780	    break;
3781
3782	case CASE_GSETS5:
3783	    if (screen->vtXX_level >= 5) {
3784		TRACE(("CASE_GSETS5(%d) = '%c'\n", sp->scstype, c));
3785		xtermDecodeSCS(xw, sp->scstype, 5, 0, (int) c);
3786	    }
3787	    ResetState(sp);
3788	    break;
3789
3790	case CASE_GSETS3:
3791	    if (screen->vtXX_level >= 3) {
3792		TRACE(("CASE_GSETS3(%d) = '%c'\n", sp->scstype, c));
3793		xtermDecodeSCS(xw, sp->scstype, 3, 0, (int) c);
3794	    }
3795	    ResetState(sp);
3796	    break;
3797
3798	case CASE_GSETS:
3799	    if (strchr("012AB", (int) c) != 0) {
3800		TRACE(("CASE_GSETS(%d) = '%c'\n", sp->scstype, c));
3801		xtermDecodeSCS(xw, sp->scstype, 1, 0, (int) c);
3802	    } else if (screen->vtXX_level >= 2) {
3803		TRACE(("CASE_GSETS(%d) = '%c'\n", sp->scstype, c));
3804		xtermDecodeSCS(xw, sp->scstype, 2, 0, (int) c);
3805	    }
3806	    ResetState(sp);
3807	    break;
3808
3809	case CASE_ANSI_SC:
3810	    if (IsLeftRightMode(xw)) {
3811		int left;
3812		int right;
3813
3814		TRACE(("CASE_DECSLRM - set left and right margin\n"));
3815		left = one_if_default(0);
3816		if (nparam < 2 || (right = GetParam(1)) == DEFAULT
3817		    || right > MaxCols(screen)
3818		    || right == 0)
3819		    right = MaxCols(screen);
3820		if (right > left) {
3821		    set_lr_margins(screen, left - 1, right - 1);
3822		    CursorSet(screen, 0, 0, xw->flags);
3823		}
3824	    } else {
3825		TRACE(("CASE_ANSI_SC - save cursor\n"));
3826		CursorSave(xw);
3827	    }
3828	    ResetState(sp);
3829	    break;
3830
3831	case CASE_DECSC:
3832	    TRACE(("CASE_DECSC - save cursor\n"));
3833	    CursorSave(xw);
3834	    ResetState(sp);
3835	    break;
3836
3837	case CASE_ANSI_RC:
3838	    /* FALLTHRU */
3839	case CASE_DECRC:
3840	    TRACE(("CASE_%sRC - restore cursor\n",
3841		   (sp->nextstate == CASE_DECRC) ? "DEC" : "ANSI_"));
3842	    CursorRestore(xw);
3843	    if_OPT_ISO_COLORS(screen, {
3844		setExtendedFG(xw);
3845	    });
3846	    ResetState(sp);
3847	    break;
3848
3849	case CASE_DECKPAM:
3850	    TRACE(("CASE_DECKPAM\n"));
3851	    xw->keyboard.flags |= MODE_DECKPAM;
3852	    update_appkeypad();
3853	    ResetState(sp);
3854	    break;
3855
3856	case CASE_DECKPNM:
3857	    TRACE(("CASE_DECKPNM\n"));
3858	    UIntClr(xw->keyboard.flags, MODE_DECKPAM);
3859	    update_appkeypad();
3860	    ResetState(sp);
3861	    break;
3862
3863	case CASE_CSI_QUOTE_STATE:
3864	    sp->parsestate = csi_quo_table;
3865	    break;
3866
3867#if OPT_BLINK_CURS
3868	case CASE_CSI_SPACE_STATE:
3869	    sp->parsestate = csi_sp_table;
3870	    break;
3871
3872	case CASE_DECSCUSR:
3873	    TRACE(("CASE_DECSCUSR\n"));
3874	    {
3875		Boolean change = True;
3876		int blinks = screen->cursor_blink_esc;
3877
3878		HideCursor(xw);
3879
3880		switch (GetParam(0)) {
3881		case DEFAULT:
3882		    /* FALLTHRU */
3883		case DEFAULT_STYLE:
3884		    /* FALLTHRU */
3885		case BLINK_BLOCK:
3886		    blinks = True;
3887		    screen->cursor_shape = CURSOR_BLOCK;
3888		    break;
3889		case STEADY_BLOCK:
3890		    blinks = False;
3891		    screen->cursor_shape = CURSOR_BLOCK;
3892		    break;
3893		case BLINK_UNDERLINE:
3894		    blinks = True;
3895		    screen->cursor_shape = CURSOR_UNDERLINE;
3896		    break;
3897		case STEADY_UNDERLINE:
3898		    blinks = False;
3899		    screen->cursor_shape = CURSOR_UNDERLINE;
3900		    break;
3901		case BLINK_BAR:
3902		    blinks = True;
3903		    screen->cursor_shape = CURSOR_BAR;
3904		    break;
3905		case STEADY_BAR:
3906		    blinks = False;
3907		    screen->cursor_shape = CURSOR_BAR;
3908		    break;
3909		default:
3910		    change = False;
3911		    break;
3912		}
3913		TRACE(("cursor_shape:%d blinks:%s\n",
3914		       screen->cursor_shape, BtoS(blinks)));
3915		if (change) {
3916		    xtermSetCursorBox(screen);
3917		    screen->cursor_blink_esc = blinks;
3918		    UpdateCursorBlink(xw);
3919		}
3920	    }
3921	    ResetState(sp);
3922	    break;
3923#endif
3924
3925#if OPT_SCROLL_LOCK
3926	case CASE_DECLL:
3927	    TRACE(("CASE_DECLL\n"));
3928	    if (nparam > 0) {
3929		for (count = 0; count < nparam; ++count) {
3930		    int op = zero_if_default(count);
3931		    switch (op) {
3932		    case 0:
3933		    case DEFAULT:
3934			xtermClearLEDs(screen);
3935			break;
3936		    case 1:
3937			/* FALLTHRU */
3938		    case 2:
3939			/* FALLTHRU */
3940		    case 3:
3941			xtermShowLED(screen,
3942				     (Cardinal) op,
3943				     True);
3944			break;
3945		    case 21:
3946			/* FALLTHRU */
3947		    case 22:
3948			/* FALLTHRU */
3949		    case 23:
3950			xtermShowLED(screen,
3951				     (Cardinal) (op - 20),
3952				     True);
3953			break;
3954		    }
3955		}
3956	    } else {
3957		xtermClearLEDs(screen);
3958	    }
3959	    ResetState(sp);
3960	    break;
3961#endif
3962
3963#if OPT_VT52_MODE
3964	case CASE_VT52_FINISH:
3965	    TRACE(("CASE_VT52_FINISH terminal_id %d, vtXX_level %d\n",
3966		   screen->terminal_id,
3967		   screen->vtXX_level));
3968	    if (screen->terminal_id >= 100
3969		&& screen->vtXX_level == 0) {
3970		sp->groundtable =
3971		    sp->parsestate = ansi_table;
3972		/*
3973		 * On restore, the terminal does not recognize DECRQSS for
3974		 * DECSCL (per vttest).
3975		 */
3976		screen->vtXX_level = 1;
3977		xw->flags = screen->vt52_save_flags;
3978		screen->curgl = screen->vt52_save_curgl;
3979		screen->curgr = screen->vt52_save_curgr;
3980		screen->curss = screen->vt52_save_curss;
3981		restoreCharsets(screen, screen->vt52_save_gsets);
3982		update_vt52_vt100_settings();
3983	    }
3984	    break;
3985#endif
3986
3987	case CASE_ANSI_LEVEL_1:
3988	    TRACE(("CASE_ANSI_LEVEL_1\n"));
3989	    set_ansi_conformance(screen, 1);
3990	    ResetState(sp);
3991	    break;
3992
3993	case CASE_ANSI_LEVEL_2:
3994	    TRACE(("CASE_ANSI_LEVEL_2\n"));
3995	    set_ansi_conformance(screen, 2);
3996	    ResetState(sp);
3997	    break;
3998
3999	case CASE_ANSI_LEVEL_3:
4000	    TRACE(("CASE_ANSI_LEVEL_3\n"));
4001	    set_ansi_conformance(screen, 3);
4002	    ResetState(sp);
4003	    break;
4004
4005	case CASE_DECSCL:
4006	    TRACE(("CASE_DECSCL(%d,%d)\n", GetParam(0), GetParam(1)));
4007	    /*
4008	     * This changes the emulation level, and is not recognized by
4009	     * VT100s.  However, a VT220 or above can be set to conformance
4010	     * level 1 to act like a VT100.
4011	     */
4012	    if (screen->terminal_id >= 200) {
4013		/*
4014		 * Disallow unrecognized parameters, as well as attempts to set
4015		 * the operating level higher than the given terminal-id.
4016		 */
4017		if (GetParam(0) >= 61
4018		    && GetParam(0) <= 60 + (screen->terminal_id / 100)) {
4019		    int new_vtXX_level = GetParam(0) - 60;
4020		    int case_value = zero_if_default(1);
4021		    /*
4022		     * Note:
4023		     *
4024		     * The VT300, VT420, VT520 manuals claim that DECSCL does a
4025		     * hard reset (RIS).
4026		     *
4027		     * Both the VT220 manual and DEC STD 070 (which documents
4028		     * levels 1-4 in detail) state that it is a soft reset.
4029		     *
4030		     * Perhaps both sets of manuals are right (unlikely).
4031		     * Kermit says it's soft.
4032		     */
4033		    ReallyReset(xw, False, False);
4034		    init_parser(xw, sp);
4035		    screen->vtXX_level = new_vtXX_level;
4036		    if (new_vtXX_level > 1) {
4037			switch (case_value) {
4038			case 1:
4039			    show_8bit_control(False);
4040			    break;
4041			case 0:
4042			case 2:
4043			    show_8bit_control(True);
4044			    break;
4045			}
4046		    }
4047		}
4048	    }
4049	    ResetState(sp);
4050	    break;
4051
4052	case CASE_DECSCA:
4053	    TRACE(("CASE_DECSCA\n"));
4054	    screen->protected_mode = DEC_PROTECT;
4055	    if (GetParam(0) <= 0 || GetParam(0) == 2) {
4056		UIntClr(xw->flags, PROTECTED);
4057		TRACE(("...clear PROTECTED\n"));
4058	    } else if (GetParam(0) == 1) {
4059		xw->flags |= PROTECTED;
4060		TRACE(("...set PROTECTED\n"));
4061	    }
4062	    ResetState(sp);
4063	    break;
4064
4065	case CASE_DECSED:
4066	    TRACE(("CASE_DECSED\n"));
4067	    do_erase_display(xw, zero_if_default(0), DEC_PROTECT);
4068	    ResetState(sp);
4069	    break;
4070
4071	case CASE_DECSEL:
4072	    TRACE(("CASE_DECSEL\n"));
4073	    do_erase_line(xw, zero_if_default(0), DEC_PROTECT);
4074	    ResetState(sp);
4075	    break;
4076
4077	case CASE_GRAPHICS_ATTRIBUTES:
4078#if OPT_GRAPHICS
4079	    TRACE(("CASE_GRAPHICS_ATTRIBUTES\n"));
4080	    {
4081		/* request: item, action, value */
4082		/* reply: item, status, value */
4083		if (nparam != 3) {
4084		    TRACE(("DATA_ERROR: malformed CASE_GRAPHICS_ATTRIBUTES request with %d parameters\n", nparam));
4085		} else {
4086		    int status = 3;	/* assume failure */
4087		    int result = 0;
4088		    int result2 = 0;
4089
4090		    TRACE(("CASE_GRAPHICS_ATTRIBUTES request: %d, %d, %d\n",
4091			   GetParam(0), GetParam(1), GetParam(2)));
4092		    switch (GetParam(0)) {
4093		    case 1:	/* color register count */
4094			switch (GetParam(1)) {
4095			case 1:	/* read */
4096			    status = 0;		/* success */
4097			    result = (int) get_color_register_count(screen);
4098			    break;
4099			case 2:	/* reset */
4100			    screen->numcolorregisters = 0;
4101			    status = 0;		/* success */
4102			    result = (int) get_color_register_count(screen);
4103			    break;
4104			case 3:	/* set */
4105			    if (GetParam(2) > 1 &&
4106				(unsigned) GetParam(2) <= MAX_COLOR_REGISTERS) {
4107				screen->numcolorregisters = GetParam(2);
4108				status = 0;	/* success */
4109				result = (int) get_color_register_count(screen);
4110			    }
4111			    break;
4112			case 4:	/* read maximum */
4113			    status = 0;		/* success */
4114			    result = MAX_COLOR_REGISTERS;
4115			    break;
4116			default:
4117			    TRACE(("DATA_ERROR: CASE_GRAPHICS_ATTRIBUTES color register count request with unknown action parameter: %d\n",
4118				   GetParam(1)));
4119			    status = 2;		/* error in Pa */
4120			    break;
4121			}
4122			break;
4123		    case 2:	/* graphics geometry */
4124			switch (GetParam(1)) {
4125			case 1:	/* read */
4126			    TRACE(("Get sixel graphics geometry\n"));
4127			    status = 0;		/* success */
4128			    result = Min(Width(screen), (int) screen->graphics_max_wide);
4129			    result2 = Min(Height(screen), (int) screen->graphics_max_high);
4130			    break;
4131			case 2:	/* reset */
4132			    /* FALLTHRU */
4133			case 3:	/* set */
4134			    break;
4135			case 4:	/* read maximum */
4136			    status = 0;		/* success */
4137			    result = screen->graphics_max_wide;
4138			    result2 = screen->graphics_max_high;
4139			    break;
4140			default:
4141			    TRACE(("DATA_ERROR: CASE_GRAPHICS_ATTRIBUTES graphics geometry request with unknown action parameter: %d\n",
4142				   GetParam(1)));
4143			    status = 2;		/* error in Pa */
4144			    break;
4145			}
4146			break;
4147# if OPT_REGIS_GRAPHICS
4148		    case 3:	/* ReGIS geometry */
4149			switch (GetParam(1)) {
4150			case 1:	/* read */
4151			    status = 0;		/* success */
4152			    result = screen->graphics_regis_def_wide;
4153			    result2 = screen->graphics_regis_def_high;
4154			    break;
4155			case 2:	/* reset */
4156			    /* FALLTHRU */
4157			case 3:	/* set */
4158			    /* FALLTHRU */
4159			case 4:	/* read maximum */
4160			    /* not implemented */
4161			    break;
4162			default:
4163			    TRACE(("DATA_ERROR: CASE_GRAPHICS_ATTRIBUTES ReGIS geometry request with unknown action parameter: %d\n",
4164				   GetParam(1)));
4165			    status = 2;		/* error in Pa */
4166			    break;
4167			}
4168			break;
4169#endif
4170		    default:
4171			TRACE(("DATA_ERROR: CASE_GRAPHICS_ATTRIBUTES request with unknown item parameter: %d\n",
4172			       GetParam(0)));
4173			status = 1;
4174			break;
4175		    }
4176
4177		    init_reply(ANSI_CSI);
4178		    reply.a_pintro = '?';
4179		    count = 0;
4180		    reply.a_param[count++] = (ParmType) GetParam(0);
4181		    reply.a_param[count++] = (ParmType) status;
4182		    reply.a_param[count++] = (ParmType) result;
4183		    if (GetParam(0) >= 2)
4184			reply.a_param[count++] = (ParmType) result2;
4185		    reply.a_nparam = (ParmType) count;
4186		    reply.a_inters = 0;
4187		    reply.a_final = 'S';
4188		    unparseseq(xw, &reply);
4189		}
4190	    }
4191#endif
4192	    ResetState(sp);
4193	    break;
4194
4195	case CASE_ST:
4196	    TRACE(("CASE_ST: End of String (%lu bytes) (mode=%d)\n",
4197		   (unsigned long) sp->string_used,
4198		   sp->string_mode));
4199	    ResetState(sp);
4200	    if (!sp->string_used)
4201		break;
4202	    sp->string_area[--(sp->string_used)] = '\0';
4203	    if (sp->check_recur <= 1)
4204		switch (sp->string_mode) {
4205		case ANSI_APC:
4206		    /* ignored */
4207		    break;
4208		case ANSI_DCS:
4209		    do_dcs(xw, sp->string_area, sp->string_used);
4210		    break;
4211		case ANSI_OSC:
4212		    do_osc(xw, sp->string_area, sp->string_used, ANSI_ST);
4213		    break;
4214		case ANSI_PM:
4215		    /* ignored */
4216		    break;
4217		case ANSI_SOS:
4218		    /* ignored */
4219		    break;
4220		default:
4221		    TRACE(("unknown mode\n"));
4222		    break;
4223		}
4224	    break;
4225
4226	case CASE_SOS:
4227	    TRACE(("CASE_SOS: Start of String\n"));
4228	    if (ParseSOS(screen)) {
4229		sp->string_mode = ANSI_SOS;
4230		sp->parsestate = sos_table;
4231	    } else {
4232		illegal_parse(xw, c, sp);
4233	    }
4234	    break;
4235
4236	case CASE_PM:
4237	    TRACE(("CASE_PM: Privacy Message\n"));
4238	    if (ParseSOS(screen)) {
4239		sp->string_mode = ANSI_PM;
4240		sp->parsestate = sos_table;
4241	    } else {
4242		illegal_parse(xw, c, sp);
4243	    }
4244	    break;
4245
4246	case CASE_DCS:
4247	    TRACE(("CASE_DCS: Device Control String\n"));
4248	    sp->string_mode = ANSI_DCS;
4249	    sp->parsestate = sos_table;
4250	    break;
4251
4252	case CASE_APC:
4253	    TRACE(("CASE_APC: Application Program Command\n"));
4254	    if (ParseSOS(screen)) {
4255		sp->string_mode = ANSI_APC;
4256		sp->parsestate = sos_table;
4257	    } else {
4258		illegal_parse(xw, c, sp);
4259	    }
4260	    break;
4261
4262	case CASE_SPA:
4263	    TRACE(("CASE_SPA - start protected area\n"));
4264	    screen->protected_mode = ISO_PROTECT;
4265	    xw->flags |= PROTECTED;
4266	    ResetState(sp);
4267	    break;
4268
4269	case CASE_EPA:
4270	    TRACE(("CASE_EPA - end protected area\n"));
4271	    UIntClr(xw->flags, PROTECTED);
4272	    ResetState(sp);
4273	    break;
4274
4275	case CASE_SU:
4276	    TRACE(("CASE_SU - scroll up\n"));
4277	    xtermScroll(xw, one_if_default(0));
4278	    ResetState(sp);
4279	    break;
4280
4281	case CASE_SL:		/* ISO 6429, non-DEC */
4282	    TRACE(("CASE_SL - scroll left\n"));
4283	    xtermScrollLR(xw, one_if_default(0), True);
4284	    ResetState(sp);
4285	    break;
4286
4287	case CASE_SR:		/* ISO 6429, non-DEC */
4288	    TRACE(("CASE_SR - scroll right\n"));
4289	    xtermScrollLR(xw, one_if_default(0), False);
4290	    ResetState(sp);
4291	    break;
4292
4293	case CASE_DECDC:
4294	    TRACE(("CASE_DC - delete column\n"));
4295	    if (screen->vtXX_level >= 4) {
4296		xtermColScroll(xw, one_if_default(0), True, screen->cur_col);
4297	    }
4298	    ResetState(sp);
4299	    break;
4300
4301	case CASE_DECIC:
4302	    TRACE(("CASE_IC - insert column\n"));
4303	    if (screen->vtXX_level >= 4) {
4304		xtermColScroll(xw, one_if_default(0), False, screen->cur_col);
4305	    }
4306	    ResetState(sp);
4307	    break;
4308
4309	case CASE_DECBI:
4310	    TRACE(("CASE_BI - back index\n"));
4311	    if (screen->vtXX_level >= 4) {
4312		xtermColIndex(xw, True);
4313	    }
4314	    ResetState(sp);
4315	    break;
4316
4317	case CASE_DECFI:
4318	    TRACE(("CASE_FI - forward index\n"));
4319	    if (screen->vtXX_level >= 4) {
4320		xtermColIndex(xw, False);
4321	    }
4322	    ResetState(sp);
4323	    break;
4324
4325	case CASE_IND:
4326	    TRACE(("CASE_IND - index\n"));
4327	    xtermIndex(xw, 1);
4328	    do_xevents(xw);
4329	    ResetState(sp);
4330	    break;
4331
4332	case CASE_CPL:
4333	    TRACE(("CASE_CPL - cursor prev line\n"));
4334	    CursorPrevLine(xw, one_if_default(0));
4335	    ResetState(sp);
4336	    break;
4337
4338	case CASE_CNL:
4339	    TRACE(("CASE_CNL - cursor next line\n"));
4340	    CursorNextLine(xw, one_if_default(0));
4341	    ResetState(sp);
4342	    break;
4343
4344	case CASE_NEL:
4345	    TRACE(("CASE_NEL\n"));
4346	    xtermIndex(xw, 1);
4347	    CarriageReturn(xw);
4348	    ResetState(sp);
4349	    break;
4350
4351	case CASE_HTS:
4352	    TRACE(("CASE_HTS - horizontal tab set\n"));
4353	    TabSet(xw->tabs, screen->cur_col);
4354	    ResetState(sp);
4355	    break;
4356
4357	case CASE_REPORT_VERSION:
4358	    TRACE(("CASE_REPORT_VERSION - report terminal version\n"));
4359	    if (GetParam(0) <= 0) {
4360		unparseputc1(xw, ANSI_DCS);
4361		unparseputc(xw, '>');
4362		unparseputc(xw, '|');
4363		unparseputs(xw, xtermVersion());
4364		unparseputc1(xw, ANSI_ST);
4365		unparse_end(xw);
4366	    }
4367	    ResetState(sp);
4368	    break;
4369
4370	case CASE_RI:
4371	    TRACE(("CASE_RI - reverse index\n"));
4372	    RevIndex(xw, 1);
4373	    ResetState(sp);
4374	    break;
4375
4376	case CASE_SS2:
4377	    TRACE(("CASE_SS2\n"));
4378	    screen->curss = 2;
4379	    ResetState(sp);
4380	    break;
4381
4382	case CASE_SS3:
4383	    TRACE(("CASE_SS3\n"));
4384	    screen->curss = 3;
4385	    ResetState(sp);
4386	    break;
4387
4388	case CASE_CSI_STATE:
4389	    /* enter csi state */
4390	    InitParams();
4391	    SetParam(nparam++, DEFAULT);
4392	    sp->parsestate = csi_table;
4393	    break;
4394
4395	case CASE_ESC_SP_STATE:
4396	    /* esc space */
4397	    sp->parsestate = esc_sp_table;
4398	    break;
4399
4400	case CASE_CSI_EX_STATE:
4401	    /* csi exclamation */
4402	    sp->parsestate = csi_ex_table;
4403	    break;
4404
4405	case CASE_CSI_TICK_STATE:
4406	    /* csi tick (') */
4407	    sp->parsestate = csi_tick_table;
4408	    break;
4409
4410#if OPT_DEC_LOCATOR
4411	case CASE_DECEFR:
4412	    TRACE(("CASE_DECEFR - Enable Filter Rectangle\n"));
4413	    if (okSendMousePos(xw) == DEC_LOCATOR) {
4414		MotionOff(screen, xw);
4415		if ((screen->loc_filter_top = GetParam(0)) < 1)
4416		    screen->loc_filter_top = LOC_FILTER_POS;
4417		if (nparam < 2
4418		    || (screen->loc_filter_left = GetParam(1)) < 1)
4419		    screen->loc_filter_left = LOC_FILTER_POS;
4420		if (nparam < 3
4421		    || (screen->loc_filter_bottom = GetParam(2)) < 1)
4422		    screen->loc_filter_bottom = LOC_FILTER_POS;
4423		if (nparam < 4
4424		    || (screen->loc_filter_right = GetParam(3)) < 1)
4425		    screen->loc_filter_right = LOC_FILTER_POS;
4426		InitLocatorFilter(xw);
4427	    }
4428	    ResetState(sp);
4429	    break;
4430
4431	case CASE_DECELR:
4432	    MotionOff(screen, xw);
4433	    if (GetParam(0) <= 0 || GetParam(0) > 2) {
4434		screen->send_mouse_pos = MOUSE_OFF;
4435		TRACE(("DECELR - Disable Locator Reports\n"));
4436	    } else {
4437		TRACE(("DECELR - Enable Locator Reports\n"));
4438		screen->send_mouse_pos = DEC_LOCATOR;
4439		xtermShowPointer(xw, True);
4440		if (GetParam(0) == 2) {
4441		    screen->locator_reset = True;
4442		} else {
4443		    screen->locator_reset = False;
4444		}
4445		if (nparam < 2 || GetParam(1) != 1) {
4446		    screen->locator_pixels = False;
4447		} else {
4448		    screen->locator_pixels = True;
4449		}
4450		screen->loc_filter = False;
4451	    }
4452	    ResetState(sp);
4453	    break;
4454
4455	case CASE_DECSLE:
4456	    TRACE(("DECSLE - Select Locator Events\n"));
4457	    for (count = 0; count < nparam; ++count) {
4458		switch (zero_if_default(count)) {
4459		case 0:
4460		    MotionOff(screen, xw);
4461		    screen->loc_filter = False;
4462		    screen->locator_events = 0;
4463		    break;
4464		case 1:
4465		    screen->locator_events |= LOC_BTNS_DN;
4466		    break;
4467		case 2:
4468		    UIntClr(screen->locator_events, LOC_BTNS_DN);
4469		    break;
4470		case 3:
4471		    screen->locator_events |= LOC_BTNS_UP;
4472		    break;
4473		case 4:
4474		    UIntClr(screen->locator_events, LOC_BTNS_UP);
4475		    break;
4476		}
4477	    }
4478	    ResetState(sp);
4479	    break;
4480
4481	case CASE_DECRQLP:
4482	    TRACE(("DECRQLP - Request Locator Position\n"));
4483	    if (GetParam(0) < 2) {
4484		/* Issue DECLRP Locator Position Report */
4485		GetLocatorPosition(xw);
4486	    }
4487	    ResetState(sp);
4488	    break;
4489#endif /* OPT_DEC_LOCATOR */
4490
4491#if OPT_DEC_RECTOPS
4492	case CASE_CSI_DOLLAR_STATE:
4493	    TRACE(("CASE_CSI_DOLLAR_STATE\n"));
4494	    /* csi dollar ($) */
4495	    if (screen->vtXX_level >= 3)
4496		sp->parsestate = csi_dollar_table;
4497	    else
4498		sp->parsestate = eigtable;
4499	    break;
4500
4501	case CASE_CSI_STAR_STATE:
4502	    TRACE(("CASE_CSI_STAR_STATE\n"));
4503	    /* csi star (*) */
4504	    if (screen->vtXX_level >= 4)
4505		sp->parsestate = csi_star_table;
4506	    else
4507		sp->parsestate = eigtable;
4508	    break;
4509
4510	case CASE_DECRQCRA:
4511	    if (screen->vtXX_level >= 4 && AllowWindowOps(xw, ewGetChecksum)) {
4512		int checksum;
4513		int pid;
4514
4515		TRACE(("CASE_DECRQCRA - Request checksum of rectangular area\n"));
4516		xtermCheckRect(xw, ParamPair(0), &checksum);
4517		init_reply(ANSI_DCS);
4518		count = 0;
4519		checksum &= 0xffff;
4520		pid = GetParam(0);
4521		reply.a_param[count++] = (ParmType) pid;
4522		reply.a_delim = "!~";	/* delimiter */
4523		reply.a_radix[count] = 16;
4524		reply.a_param[count++] = (ParmType) checksum;
4525		reply.a_nparam = (ParmType) count;
4526		TRACE(("...checksum(%d) = %04X\n", pid, checksum));
4527		unparseseq(xw, &reply);
4528	    }
4529	    ResetState(sp);
4530	    break;
4531
4532	case CASE_DECCRA:
4533	    if (screen->vtXX_level >= 4) {
4534		TRACE(("CASE_DECCRA - Copy rectangular area\n"));
4535		xtermParseRect(xw, ParamPair(0), &myRect);
4536		ScrnCopyRectangle(xw, &myRect, ParamPair(5));
4537	    }
4538	    ResetState(sp);
4539	    break;
4540
4541	case CASE_DECERA:
4542	    if (screen->vtXX_level >= 4) {
4543		TRACE(("CASE_DECERA - Erase rectangular area\n"));
4544		xtermParseRect(xw, ParamPair(0), &myRect);
4545		ScrnFillRectangle(xw, &myRect, ' ', xw->flags, True);
4546	    }
4547	    ResetState(sp);
4548	    break;
4549
4550	case CASE_DECFRA:
4551	    if (screen->vtXX_level >= 4) {
4552		value = zero_if_default(0);
4553
4554		TRACE(("CASE_DECFRA - Fill rectangular area\n"));
4555		if (nparam > 0 && CharWidth(value) > 0) {
4556		    xtermParseRect(xw, ParamPair(1), &myRect);
4557		    ScrnFillRectangle(xw, &myRect, value, xw->flags, True);
4558		}
4559	    }
4560	    ResetState(sp);
4561	    break;
4562
4563	case CASE_DECSERA:
4564	    if (screen->vtXX_level >= 4) {
4565		TRACE(("CASE_DECSERA - Selective erase rectangular area\n"));
4566		xtermParseRect(xw, ParamPair(0), &myRect);
4567		ScrnWipeRectangle(xw, &myRect);
4568	    }
4569	    ResetState(sp);
4570	    break;
4571
4572	case CASE_DECSACE:
4573	    TRACE(("CASE_DECSACE - Select attribute change extent\n"));
4574	    screen->cur_decsace = zero_if_default(0);
4575	    ResetState(sp);
4576	    break;
4577
4578	case CASE_DECCARA:
4579	    if (screen->vtXX_level >= 4) {
4580		TRACE(("CASE_DECCARA - Change attributes in rectangular area\n"));
4581		xtermParseRect(xw, ParamPair(0), &myRect);
4582		ScrnMarkRectangle(xw, &myRect, False, ParamPair(4));
4583	    }
4584	    ResetState(sp);
4585	    break;
4586
4587	case CASE_DECRARA:
4588	    if (screen->vtXX_level >= 4) {
4589		TRACE(("CASE_DECRARA - Reverse attributes in rectangular area\n"));
4590		xtermParseRect(xw, ParamPair(0), &myRect);
4591		ScrnMarkRectangle(xw, &myRect, True, ParamPair(4));
4592	    }
4593	    ResetState(sp);
4594	    break;
4595
4596	case CASE_DECSCPP:
4597	    if (screen->vtXX_level >= 3) {
4598		TRACE(("CASE_DECSCPP\n"));
4599		/* default and 0 are "80", with "132" as the other legal choice */
4600		switch (zero_if_default(0)) {
4601		case 0:
4602		case 80:
4603		    value = 80;
4604		    break;
4605		case 132:
4606		    value = 132;
4607		    break;
4608		default:
4609		    value = -1;
4610		    break;
4611		}
4612		if (value > 0) {
4613		    if (screen->cur_col + 1 > value)
4614			CursorSet(screen, screen->cur_row, value - 1, xw->flags);
4615		    UIntClr(xw->flags, IN132COLUMNS);
4616		    if (value == 132)
4617			UIntSet(xw->flags, IN132COLUMNS);
4618		    RequestResize(xw, -1, value, True);
4619		}
4620	    }
4621	    ResetState(sp);
4622	    break;
4623
4624	case CASE_DECSNLS:
4625	    if (screen->vtXX_level >= 4 && AllowWindowOps(xw, ewSetWinLines)) {
4626		TRACE(("CASE_DECSNLS\n"));
4627		value = zero_if_default(0);
4628		if (value >= 1 && value <= 255) {
4629		    RequestResize(xw, value, -1, True);
4630		}
4631	    }
4632	    ResetState(sp);
4633	    break;
4634
4635	case CASE_DECRQPSR:
4636#define reply_char(n,c) do { reply.a_radix[(n)] = 1; reply.a_param[(n)++] = (ParmType)(c); } while (0)
4637#define reply_bit(n,c) ((n) ? (c) : 0)
4638	    if (screen->vtXX_level >= 3) {
4639		TRACE(("CASE_DECRQPSR\n"));
4640		switch (GetParam(0)) {
4641		case 1:
4642		    TRACE(("...DECCIR\n"));
4643		    init_reply(ANSI_DCS);
4644		    count = 0;
4645		    reply_char(count, '1');
4646		    reply_char(count, '$');
4647		    reply_char(count, 'u');
4648		    reply.a_param[count++] = (ParmType) (screen->cur_row + 1);
4649		    reply.a_param[count++] = (ParmType) (screen->cur_col + 1);
4650		    reply.a_param[count++] = (ParmType) thispage;
4651		    reply_char(count, ';');
4652		    reply_char(count, (0x40
4653				       | reply_bit(xw->flags & INVERSE, 8)
4654				       | reply_bit(xw->flags & BLINK, 4)
4655				       | reply_bit(xw->flags & UNDERLINE, 2)
4656				       | reply_bit(xw->flags & BOLD, 1)
4657			       ));
4658		    reply_char(count, ';');
4659		    reply_char(count, 0x40 |
4660			       reply_bit(screen->protected_mode &
4661					 DEC_PROTECT, 1)
4662			);
4663		    reply_char(count, ';');
4664		    reply_char(count, (0x40
4665				       | reply_bit(screen->do_wrap, 8)
4666				       | reply_bit((screen->curss == 3), 4)
4667				       | reply_bit((screen->curss == 2), 2)
4668				       | reply_bit(xw->flags & ORIGIN, 1)
4669			       ));
4670		    reply_char(count, ';');
4671		    reply.a_param[count++] = screen->curgl;
4672		    reply.a_param[count++] = screen->curgr;
4673		    reply_char(count, ';');
4674		    reply_char(count, 0x4f);	/* assert all 96's */
4675		    reply_char(count, ';');
4676		    for (item = 0; item < NUM_GSETS; ++item) {
4677			char *temp = encode_scs(screen->gsets[item]);
4678			while (*temp != '\0') {
4679			    reply_char(count, *temp++);
4680			}
4681		    }
4682		    reply.a_nparam = (ParmType) count;
4683		    unparseseq(xw, &reply);
4684		    break;
4685		case 2:
4686		    TRACE(("...DECTABSR\n"));
4687		    init_reply(ANSI_DCS);
4688		    reply.a_delim = "/";
4689		    count = 0;
4690		    reply_char(count, '2');
4691		    reply_char(count, '$');
4692		    reply_char(count, 'u');
4693		    for (item = 0; item < MAX_TABS; ++item) {
4694			if (count + 1 >= NPARAM)
4695			    break;
4696			if (TabIsSet(xw->tabs, item)) {
4697			    reply.a_param[count++] = (ParmType) (item + 1);
4698			}
4699			if (item > screen->max_col)
4700			    break;
4701		    }
4702		    reply.a_nparam = (ParmType) count;
4703		    unparseseq(xw, &reply);
4704		    break;
4705		}
4706	    }
4707	    ResetState(sp);
4708	    break;
4709
4710	case CASE_RQM:
4711	    TRACE(("CASE_RQM\n"));
4712	    do_ansi_rqm(xw, ParamPair(0));
4713	    ResetState(sp);
4714	    break;
4715
4716	case CASE_DECRQM:
4717	    TRACE(("CASE_DECRQM\n"));
4718	    do_dec_rqm(xw, ParamPair(0));
4719	    ResetState(sp);
4720	    break;
4721
4722	case CASE_CSI_DEC_DOLLAR_STATE:
4723	    TRACE(("CASE_CSI_DEC_DOLLAR_STATE\n"));
4724	    /* csi ? dollar ($) */
4725	    sp->parsestate = csi_dec_dollar_table;
4726	    break;
4727#else
4728	case CASE_CSI_DOLLAR_STATE:
4729	    /* csi dollar ($) */
4730	    sp->parsestate = eigtable;
4731	    break;
4732
4733	case CASE_CSI_STAR_STATE:
4734	    /* csi dollar (*) */
4735	    sp->parsestate = eigtable;
4736	    break;
4737
4738	case CASE_CSI_DEC_DOLLAR_STATE:
4739	    /* csi ? dollar ($) */
4740	    sp->parsestate = eigtable;
4741	    break;
4742#endif /* OPT_DEC_RECTOPS */
4743
4744#if OPT_XTERM_SGR
4745	case CASE_CSI_HASH_STATE:
4746	    TRACE(("CASE_CSI_HASH_STATE\n"));
4747	    /* csi hash (#) */
4748	    sp->parsestate = csi_hash_table;
4749	    break;
4750
4751	case CASE_XTERM_CHECKSUM:
4752#if OPT_DEC_RECTOPS
4753	    if (screen->vtXX_level >= 4 && AllowWindowOps(xw, ewSetChecksum)) {
4754		TRACE(("CASE_XTERM_CHECKSUM\n"));
4755		screen->checksum_ext = zero_if_default(0);
4756	    }
4757#endif
4758	    ResetState(sp);
4759	    break;
4760
4761	case CASE_XTERM_PUSH_SGR:
4762	    TRACE(("CASE_XTERM_PUSH_SGR\n"));
4763	    value = 0;
4764	    if (nparam == 0 || (nparam == 1 && GetParam(0) == DEFAULT)) {
4765		value = DEFAULT;
4766	    } else if (nparam > 0) {
4767		for (count = 0; count < nparam; ++count) {
4768		    item = zero_if_default(count);
4769		    /* deprecated - for compatibility */
4770#if OPT_ISO_COLORS
4771		    if (item == psFG_COLOR_obs) {
4772			item = psFG_COLOR;
4773		    } else if (item == psBG_COLOR_obs) {
4774			item = psBG_COLOR;
4775		    }
4776#endif
4777		    if (item > 0 && item < MAX_PUSH_SGR) {
4778			value |= (1 << (item - 1));
4779		    }
4780		}
4781	    }
4782	    xtermPushSGR(xw, value);
4783	    ResetState(sp);
4784	    break;
4785
4786	case CASE_XTERM_REPORT_SGR:
4787	    TRACE(("CASE_XTERM_REPORT_SGR\n"));
4788	    xtermParseRect(xw, ParamPair(0), &myRect);
4789	    xtermReportSGR(xw, &myRect);
4790	    ResetState(sp);
4791	    break;
4792
4793	case CASE_XTERM_POP_SGR:
4794	    TRACE(("CASE_XTERM_POP_SGR\n"));
4795	    xtermPopSGR(xw);
4796	    ResetState(sp);
4797	    break;
4798
4799	case CASE_XTERM_PUSH_COLORS:
4800	    TRACE(("CASE_XTERM_PUSH_COLORS\n"));
4801	    if (nparam == 0) {
4802		xtermPushColors(xw, DEFAULT);
4803	    } else {
4804		for (count = 0; count < nparam; ++count) {
4805		    xtermPushColors(xw, GetParam(count));
4806		}
4807	    }
4808	    ResetState(sp);
4809	    break;
4810
4811	case CASE_XTERM_POP_COLORS:
4812	    TRACE(("CASE_XTERM_POP_COLORS\n"));
4813	    if (nparam == 0) {
4814		xtermPopColors(xw, DEFAULT);
4815	    } else {
4816		for (count = 0; count < nparam; ++count) {
4817		    xtermPopColors(xw, GetParam(count));
4818		}
4819	    }
4820	    ResetState(sp);
4821	    break;
4822
4823	case CASE_XTERM_REPORT_COLORS:
4824	    TRACE(("CASE_XTERM_REPORT_COLORS\n"));
4825	    xtermReportColors(xw);
4826	    ResetState(sp);
4827	    break;
4828#endif
4829
4830	case CASE_S7C1T:
4831	    TRACE(("CASE_S7C1T\n"));
4832	    if (screen->vtXX_level >= 2) {
4833		show_8bit_control(False);
4834		ResetState(sp);
4835	    }
4836	    break;
4837
4838	case CASE_S8C1T:
4839	    TRACE(("CASE_S8C1T\n"));
4840	    if (screen->vtXX_level >= 2) {
4841		show_8bit_control(True);
4842		ResetState(sp);
4843	    }
4844	    break;
4845
4846	case CASE_OSC:
4847	    TRACE(("CASE_OSC: Operating System Command\n"));
4848	    sp->parsestate = sos_table;
4849	    sp->string_mode = ANSI_OSC;
4850	    break;
4851
4852	case CASE_RIS:
4853	    TRACE(("CASE_RIS\n"));
4854	    VTReset(xw, True, True);
4855	    /* NOTREACHED */
4856
4857	case CASE_DECSTR:
4858	    TRACE(("CASE_DECSTR\n"));
4859	    VTReset(xw, False, False);
4860	    /* NOTREACHED */
4861
4862	case CASE_REP:
4863	    TRACE(("CASE_REP\n"));
4864	    if (CharWidth(sp->lastchar) > 0) {
4865		IChar repeated[2];
4866		count = one_if_default(0);
4867		repeated[0] = (IChar) sp->lastchar;
4868		while (count-- > 0) {
4869		    dotext(xw,
4870			   screen->gsets[(int) (screen->curgl)],
4871			   repeated, 1);
4872		}
4873	    }
4874	    ResetState(sp);
4875	    break;
4876
4877	case CASE_LS2:
4878	    TRACE(("CASE_LS2\n"));
4879	    screen->curgl = 2;
4880	    ResetState(sp);
4881	    break;
4882
4883	case CASE_LS3:
4884	    TRACE(("CASE_LS3\n"));
4885	    screen->curgl = 3;
4886	    ResetState(sp);
4887	    break;
4888
4889	case CASE_LS3R:
4890	    TRACE(("CASE_LS3R\n"));
4891	    screen->curgr = 3;
4892	    ResetState(sp);
4893	    break;
4894
4895	case CASE_LS2R:
4896	    TRACE(("CASE_LS2R\n"));
4897	    screen->curgr = 2;
4898	    ResetState(sp);
4899	    break;
4900
4901	case CASE_LS1R:
4902	    TRACE(("CASE_LS1R\n"));
4903	    screen->curgr = 1;
4904	    ResetState(sp);
4905	    break;
4906
4907	case CASE_XTERM_SAVE:
4908	    savemodes(xw);
4909	    ResetState(sp);
4910	    break;
4911
4912	case CASE_XTERM_RESTORE:
4913	    restoremodes(xw);
4914	    ResetState(sp);
4915	    break;
4916
4917	case CASE_XTERM_WINOPS:
4918	    TRACE(("CASE_XTERM_WINOPS\n"));
4919	    window_ops(xw);
4920	    ResetState(sp);
4921	    break;
4922#if OPT_WIDE_CHARS
4923	case CASE_ESC_PERCENT:
4924	    TRACE(("CASE_ESC_PERCENT\n"));
4925	    sp->parsestate = esc_pct_table;
4926	    break;
4927
4928	case CASE_UTF8:
4929	    /* If we did not set UTF-8 mode from resource or the
4930	     * command-line, allow it to be enabled/disabled by
4931	     * control sequence.
4932	     */
4933	    TRACE(("CASE_UTF8 wide:%d, utf8:%d, req:%s\n",
4934		   screen->wide_chars,
4935		   screen->utf8_mode,
4936		   BtoS(c == 'G')));
4937	    if ((!screen->wide_chars) && (c == 'G')) {
4938		WriteNow();
4939		ChangeToWide(xw);
4940	    }
4941	    if (screen->wide_chars
4942		&& !screen->utf8_always) {
4943		switchPtyData(screen, c == 'G');
4944		TRACE(("UTF8 mode %s\n",
4945		       BtoS(screen->utf8_mode)));
4946	    } else {
4947		TRACE(("UTF8 mode NOT turned %s (%s)\n",
4948		       BtoS(c == 'G'),
4949		       (screen->utf8_mode == uAlways)
4950		       ? "UTF-8 mode set from command-line"
4951		       : "wideChars resource was not set"));
4952	    }
4953	    ResetState(sp);
4954	    break;
4955
4956	case CASE_SCS_DQUOTE:
4957	    TRACE(("CASE_SCS_DQUOTE\n"));
4958	    sp->parsestate = scs_2qt_table;
4959	    break;
4960
4961	case CASE_GSETS_DQUOTE:
4962	    if (screen->vtXX_level >= 5) {
4963		TRACE(("CASE_GSETS_DQUOTE(%d) = '%c'\n", sp->scstype, c));
4964		xtermDecodeSCS(xw, sp->scstype, 5, '"', (int) c);
4965	    }
4966	    ResetState(sp);
4967	    break;
4968
4969	case CASE_SCS_AMPRSND:
4970	    TRACE(("CASE_SCS_AMPRSND\n"));
4971	    sp->parsestate = scs_amp_table;
4972	    break;
4973
4974	case CASE_GSETS_AMPRSND:
4975	    if (screen->vtXX_level >= 5) {
4976		TRACE(("CASE_GSETS_AMPRSND(%d) = '%c'\n", sp->scstype, c));
4977		xtermDecodeSCS(xw, sp->scstype, 5, '&', (int) c);
4978	    }
4979	    ResetState(sp);
4980	    break;
4981
4982	case CASE_SCS_PERCENT:
4983	    TRACE(("CASE_SCS_PERCENT\n"));
4984	    sp->parsestate = scs_pct_table;
4985	    break;
4986
4987	case CASE_GSETS_PERCENT:
4988	    if (screen->vtXX_level >= 3) {
4989		TRACE(("CASE_GSETS_PERCENT(%d) = '%c'\n", sp->scstype, c));
4990		switch (c) {
4991		case '0':	/* DEC Turkish */
4992		case '2':	/* Turkish */
4993		case '=':	/* Hebrew */
4994		    value = 5;
4995		    break;
4996		case '5':	/* DEC Supplemental Graphics */
4997		case '6':	/* Portuguese */
4998		default:
4999		    value = 3;
5000		    break;
5001		}
5002		xtermDecodeSCS(xw, sp->scstype, value, '%', (int) c);
5003	    }
5004	    ResetState(sp);
5005	    break;
5006#endif
5007	case CASE_XTERM_SHIFT_ESCAPE:
5008	    TRACE(("CASE_XTERM_SHIFT_ESCAPE\n"));
5009	    value = ((nparam == 0)
5010		     ? 0
5011		     : one_if_default(0));
5012	    if (value >= 0 && value <= 1)
5013		xw->keyboard.shift_escape = value;
5014	    ResetState(sp);
5015	    break;
5016
5017#if OPT_MOD_FKEYS
5018	case CASE_SET_MOD_FKEYS:
5019	    TRACE(("CASE_SET_MOD_FKEYS\n"));
5020	    if (nparam >= 1) {
5021		set_mod_fkeys(xw,
5022			      GetParam(0),
5023			      ((nparam > 1)
5024			       ? GetParam(1)
5025			       : DEFAULT),
5026			      True);
5027	    } else {
5028		for (value = 1; value <= 5; ++value)
5029		    set_mod_fkeys(xw, value, DEFAULT, True);
5030	    }
5031	    ResetState(sp);
5032	    break;
5033
5034	case CASE_SET_MOD_FKEYS0:
5035	    TRACE(("CASE_SET_MOD_FKEYS0\n"));
5036	    if (nparam >= 1 && GetParam(0) != DEFAULT) {
5037		set_mod_fkeys(xw, GetParam(0), -1, False);
5038	    } else {
5039		xw->keyboard.modify_now.function_keys = -1;
5040	    }
5041	    ResetState(sp);
5042	    break;
5043#endif
5044	case CASE_HIDE_POINTER:
5045	    TRACE(("CASE_HIDE_POINTER\n"));
5046	    if (nparam >= 1 && GetParam(0) != DEFAULT) {
5047		screen->pointer_mode = GetParam(0);
5048	    } else {
5049		screen->pointer_mode = DEF_POINTER_MODE;
5050	    }
5051	    ResetState(sp);
5052	    break;
5053
5054	case CASE_XTERM_SM_TITLE:
5055	    TRACE(("CASE_XTERM_SM_TITLE\n"));
5056	    if (nparam >= 1) {
5057		int n;
5058		for (n = 0; n < nparam; ++n) {
5059		    if (GetParam(n) != DEFAULT)
5060			screen->title_modes |= (1 << GetParam(n));
5061		}
5062	    } else {
5063		screen->title_modes = DEF_TITLE_MODES;
5064	    }
5065	    TRACE(("...title_modes %#x\n", screen->title_modes));
5066	    ResetState(sp);
5067	    break;
5068
5069	case CASE_XTERM_RM_TITLE:
5070	    TRACE(("CASE_XTERM_RM_TITLE\n"));
5071	    if (nparam >= 1) {
5072		int n;
5073		for (n = 0; n < nparam; ++n) {
5074		    if (GetParam(n) != DEFAULT)
5075			screen->title_modes &= ~(1 << GetParam(n));
5076		}
5077	    } else {
5078		screen->title_modes = DEF_TITLE_MODES;
5079	    }
5080	    TRACE(("...title_modes %#x\n", screen->title_modes));
5081	    ResetState(sp);
5082	    break;
5083
5084	case CASE_CSI_IGNORE:
5085	    sp->parsestate = cigtable;
5086	    break;
5087
5088	case CASE_DECSWBV:
5089	    TRACE(("CASE_DECSWBV\n"));
5090	    switch (zero_if_default(0)) {
5091	    case 2:
5092		/* FALLTHRU */
5093	    case 3:
5094		/* FALLTHRU */
5095	    case 4:
5096		screen->warningVolume = bvLow;
5097		break;
5098	    case 5:
5099		/* FALLTHRU */
5100	    case 6:
5101		/* FALLTHRU */
5102	    case 7:
5103		/* FALLTHRU */
5104	    case 8:
5105		screen->warningVolume = bvHigh;
5106		break;
5107	    default:
5108		screen->warningVolume = bvOff;
5109		break;
5110	    }
5111	    TRACE(("...warningVolume %d\n", screen->warningVolume));
5112	    ResetState(sp);
5113	    break;
5114
5115	case CASE_DECSMBV:
5116	    TRACE(("CASE_DECSMBV\n"));
5117	    switch (zero_if_default(0)) {
5118	    case 2:
5119		/* FALLTHRU */
5120	    case 3:
5121		/* FALLTHRU */
5122	    case 4:
5123		screen->marginVolume = bvLow;
5124		break;
5125	    case 0:
5126		/* FALLTHRU */
5127	    case 5:
5128		/* FALLTHRU */
5129	    case 6:
5130		/* FALLTHRU */
5131	    case 7:
5132		/* FALLTHRU */
5133	    case 8:
5134		screen->marginVolume = bvHigh;
5135		break;
5136	    default:
5137		screen->marginVolume = bvOff;
5138		break;
5139	    }
5140	    TRACE(("...marginVolume %d\n", screen->marginVolume));
5141	    ResetState(sp);
5142	    break;
5143	}
5144	if (sp->parsestate == sp->groundtable)
5145	    sp->lastchar = thischar;
5146    } while (0);
5147
5148#if OPT_WIDE_CHARS
5149    screen->utf8_inparse = (Boolean) ((screen->utf8_mode != uFalse)
5150				      && (sp->parsestate != sos_table));
5151#endif
5152
5153    if (sp->check_recur)
5154	sp->check_recur--;
5155    return True;
5156}
5157
5158static void
5159VTparse(XtermWidget xw)
5160{
5161    Boolean keep_running;
5162
5163    /* We longjmp back to this point in VTReset() */
5164    (void) setjmp(vtjmpbuf);
5165    init_parser(xw, &myState);
5166
5167    do {
5168	keep_running = doparsing(xw, doinput(xw), &myState);
5169	if (myState.check_recur == 0 && myState.defer_used != 0) {
5170	    while (myState.defer_used) {
5171		Char *deferred = myState.defer_area;
5172		size_t len = myState.defer_used;
5173		size_t i;
5174		myState.defer_area = NULL;
5175		myState.defer_size = 0;
5176		myState.defer_used = 0;
5177		for (i = 0; i < len; i++) {
5178		    (void) doparsing(xw, deferred[i], &myState);
5179		}
5180		free(deferred);
5181	    }
5182	} else {
5183	    free(myState.defer_area);
5184	}
5185	myState.defer_area = NULL;
5186	myState.defer_size = 0;
5187	myState.defer_used = 0;
5188    } while (keep_running);
5189}
5190
5191static Char *v_buffer;		/* pointer to physical buffer */
5192static Char *v_bufstr = NULL;	/* beginning of area to write */
5193static Char *v_bufptr;		/* end of area to write */
5194static Char *v_bufend;		/* end of physical buffer */
5195
5196/* Write data to the pty as typed by the user, pasted with the mouse,
5197   or generated by us in response to a query ESC sequence. */
5198
5199void
5200v_write(int f, const Char *data, unsigned len)
5201{
5202    TRACE2(("v_write(%d:%s)\n", len, visibleChars(data, len)));
5203    if (v_bufstr == NULL) {
5204	if (len > 0) {
5205	    v_buffer = (Char *) XtMalloc((Cardinal) len);
5206	    v_bufstr = v_buffer;
5207	    v_bufptr = v_buffer;
5208	    v_bufend = v_buffer + len;
5209	}
5210	if (v_bufstr == NULL) {
5211	    return;
5212	}
5213    }
5214    if_DEBUG({
5215	fprintf(stderr, "v_write called with %u bytes (%ld left over)",
5216		len, (long) (v_bufptr - v_bufstr));
5217	if (len > 1 && len < 10)
5218	    fprintf(stderr, " \"%.*s\"", len, (const char *) data);
5219	fprintf(stderr, "\n");
5220    });
5221
5222#ifdef VMS
5223    if ((1 << f) != pty_mask) {
5224	tt_write((const char *) data, len);
5225	return;
5226    }
5227#else /* VMS */
5228    if (!FD_ISSET(f, &pty_mask)) {
5229	IGNORE_RC(write(f, (const char *) data, (size_t) len));
5230	return;
5231    }
5232#endif /* VMS */
5233
5234    /*
5235     * Append to the block we already have.
5236     * Always doing this simplifies the code, and
5237     * isn't too bad, either.  If this is a short
5238     * block, it isn't too expensive, and if this is
5239     * a long block, we won't be able to write it all
5240     * anyway.
5241     */
5242
5243    if (len > 0) {
5244#if OPT_DABBREV
5245	TScreenOf(term)->dabbrev_working = False;	/* break dabbrev sequence */
5246#endif
5247	if (v_bufend < v_bufptr + len) {	/* we've run out of room */
5248	    if (v_bufstr != v_buffer) {
5249		/* there is unused space, move everything down */
5250		/* possibly overlapping memmove here */
5251		if_DEBUG({
5252		    fprintf(stderr, "moving data down %ld\n",
5253			    (long) (v_bufstr - v_buffer));
5254		});
5255		memmove(v_buffer, v_bufstr, (size_t) (v_bufptr - v_bufstr));
5256		v_bufptr -= v_bufstr - v_buffer;
5257		v_bufstr = v_buffer;
5258	    }
5259	    if (v_bufend < v_bufptr + len) {
5260		/* still won't fit: get more space */
5261		/* Don't use XtRealloc because an error is not fatal. */
5262		unsigned size = (unsigned) (v_bufptr - v_buffer);
5263		v_buffer = TypeRealloc(Char, size + len, v_buffer);
5264		if (v_buffer) {
5265		    if_DEBUG({
5266			fprintf(stderr, "expanded buffer to %u\n",
5267				size + len);
5268		    });
5269		    v_bufstr = v_buffer;
5270		    v_bufptr = v_buffer + size;
5271		    v_bufend = v_bufptr + len;
5272		} else {
5273		    /* no memory: ignore entire write request */
5274		    xtermWarning("cannot allocate buffer space\n");
5275		    v_buffer = v_bufstr;	/* restore clobbered pointer */
5276		}
5277	    }
5278	}
5279	if (v_bufend >= v_bufptr + len) {
5280	    /* new stuff will fit */
5281	    memmove(v_bufptr, data, (size_t) len);
5282	    v_bufptr += len;
5283	}
5284    }
5285
5286    /*
5287     * Write out as much of the buffer as we can.
5288     * Be careful not to overflow the pty's input silo.
5289     * We are conservative here and only write
5290     * a small amount at a time.
5291     *
5292     * If we can't push all the data into the pty yet, we expect write
5293     * to return a non-negative number less than the length requested
5294     * (if some data written) or -1 and set errno to EAGAIN,
5295     * EWOULDBLOCK, or EINTR (if no data written).
5296     *
5297     * (Not all systems do this, sigh, so the code is actually
5298     * a little more forgiving.)
5299     */
5300
5301#define MAX_PTY_WRITE 128	/* 1/2 POSIX minimum MAX_INPUT */
5302
5303    if (v_bufptr > v_bufstr) {
5304	int riten;
5305
5306#ifdef VMS
5307	riten = tt_write(v_bufstr,
5308			 ((v_bufptr - v_bufstr <= VMS_TERM_BUFFER_SIZE)
5309			  ? v_bufptr - v_bufstr
5310			  : VMS_TERM_BUFFER_SIZE));
5311	if (riten == 0)
5312	    return (riten);
5313#else /* VMS */
5314	riten = (int) write(f, v_bufstr,
5315			    (size_t) ((v_bufptr - v_bufstr <= MAX_PTY_WRITE)
5316				      ? v_bufptr - v_bufstr
5317				      : MAX_PTY_WRITE));
5318	if (riten < 0)
5319#endif /* VMS */
5320	{
5321	    if_DEBUG({
5322		perror("write");
5323	    });
5324	    riten = 0;
5325	}
5326	if_DEBUG({
5327	    fprintf(stderr, "write called with %ld, wrote %d\n",
5328		    ((long) ((v_bufptr - v_bufstr) <= MAX_PTY_WRITE)
5329		     ? (long) (v_bufptr - v_bufstr)
5330		     : MAX_PTY_WRITE),
5331		    riten);
5332	});
5333	v_bufstr += riten;
5334	if (v_bufstr >= v_bufptr)	/* we wrote it all */
5335	    v_bufstr = v_bufptr = v_buffer;
5336    }
5337
5338    /*
5339     * If we have lots of unused memory allocated, return it
5340     */
5341    if (v_bufend - v_bufptr > 1024) {	/* arbitrary hysteresis */
5342	/* save pointers across realloc */
5343	int start = (int) (v_bufstr - v_buffer);
5344	int size = (int) (v_bufptr - v_buffer);
5345	unsigned allocsize = (unsigned) (size ? size : 1);
5346
5347	v_buffer = TypeRealloc(Char, allocsize, v_buffer);
5348	if (v_buffer) {
5349	    v_bufstr = v_buffer + start;
5350	    v_bufptr = v_buffer + size;
5351	    v_bufend = v_buffer + allocsize;
5352	    if_DEBUG({
5353		fprintf(stderr, "shrunk buffer to %u\n", allocsize);
5354	    });
5355	} else {
5356	    /* should we print a warning if couldn't return memory? */
5357	    v_buffer = v_bufstr - start;	/* restore clobbered pointer */
5358	}
5359    }
5360}
5361
5362static void
5363updateCursor(XtermWidget xw)
5364{
5365    TScreen *screen = TScreenOf(xw);
5366
5367    if (screen->cursor_set != screen->cursor_state) {
5368	if (screen->cursor_set)
5369	    ShowCursor(xw);
5370	else
5371	    HideCursor(xw);
5372    }
5373}
5374
5375#if OPT_BLINK_CURS || OPT_BLINK_TEXT
5376static void
5377reallyStopBlinking(XtermWidget xw)
5378{
5379    TScreen *screen = TScreenOf(xw);
5380
5381    if (screen->cursor_state == BLINKED_OFF) {
5382	/* force cursor to display if it is enabled */
5383	screen->cursor_state = !screen->cursor_set;
5384	updateCursor(xw);
5385	xevents(xw);
5386    }
5387}
5388#endif
5389
5390static void
5391update_the_screen(XtermWidget xw)
5392{
5393    TScreen *screen = TScreenOf(xw);
5394    Boolean moved;
5395
5396    if (screen->scroll_amt)
5397	FlushScroll(xw);
5398    moved = CursorMoved(screen);
5399    if (screen->cursor_set && moved) {
5400	if (screen->cursor_state)
5401	    HideCursor(xw);
5402	ShowCursor(xw);
5403#if OPT_INPUT_METHOD
5404	PreeditPosition(xw);
5405#endif
5406    } else {
5407#if OPT_INPUT_METHOD
5408	if (moved)
5409	    PreeditPosition(xw);
5410#endif
5411	updateCursor(xw);
5412    }
5413}
5414
5415#ifdef VMS
5416#define	ptymask()	(v_bufptr > v_bufstr ? pty_mask : 0)
5417
5418static void
5419in_put(XtermWidget xw)
5420{
5421    static PtySelect select_mask;
5422    static PtySelect write_mask;
5423    int update = VTbuffer->update;
5424    int size;
5425
5426    int status;
5427    Dimension replyWidth, replyHeight;
5428    XtGeometryResult stat;
5429
5430    TScreen *screen = TScreenOf(xw);
5431    char *cp;
5432    int i;
5433
5434    select_mask = pty_mask;	/* force initial read */
5435    for (;;) {
5436
5437	/* if the terminal changed size, resize the widget */
5438	if (tt_changed) {
5439	    tt_changed = False;
5440
5441	    stat = REQ_RESIZE((Widget) xw,
5442			      ((Dimension) FontWidth(screen)
5443			       * (tt_width)
5444			       + 2 * screen->border
5445			       + screen->fullVwin.sb_info.width),
5446			      ((Dimension) FontHeight(screen)
5447			       * (tt_length)
5448			       + 2 * screen->border),
5449			      &replyWidth, &replyHeight);
5450
5451	    if (stat == XtGeometryYes || stat == XtGeometryDone) {
5452		xw->core.width = replyWidth;
5453		xw->core.height = replyHeight;
5454
5455		ScreenResize(xw, replyWidth, replyHeight, &xw->flags);
5456	    }
5457	    repairSizeHints();
5458	}
5459
5460	if (screen->eventMode == NORMAL
5461	    && readPtyData(xw, &select_mask, VTbuffer)) {
5462	    if (screen->scrollWidget
5463		&& screen->scrollttyoutput
5464		&& screen->topline < 0)
5465		/* Scroll to bottom */
5466		WindowScroll(xw, 0, False);
5467	    break;
5468	}
5469	update_the_screen(xw);
5470
5471	if (QLength(screen->display)) {
5472	    select_mask = X_mask;
5473	} else {
5474	    write_mask = ptymask();
5475	    XFlush(screen->display);
5476	    select_mask = Select_mask;
5477	    if (screen->eventMode != NORMAL)
5478		select_mask = X_mask;
5479	}
5480	if (write_mask & ptymask()) {
5481	    v_write(screen->respond, 0, 0);	/* flush buffer */
5482	}
5483
5484	if (select_mask & X_mask) {
5485	    xevents(xw);
5486	    if (VTbuffer->update != update)
5487		break;
5488	}
5489    }
5490}
5491#else /* VMS */
5492
5493static void
5494in_put(XtermWidget xw)
5495{
5496    static PtySelect select_mask;
5497    static PtySelect write_mask;
5498
5499    TScreen *screen = TScreenOf(xw);
5500    int i;
5501    int update = VTbuffer->update;
5502#if USE_DOUBLE_BUFFER
5503    int should_wait = 1;
5504#endif
5505
5506    static struct timeval select_timeout;
5507
5508#if OPT_BLINK_CURS
5509    /*
5510     * Compute the timeout for the blinking cursor to be much smaller than
5511     * the "on" or "off" interval.
5512     */
5513    int tick = ((screen->blink_on < screen->blink_off)
5514		? screen->blink_on
5515		: screen->blink_off);
5516    tick *= (1000 / 8);		/* 1000 for msec/usec, 8 for "much" smaller */
5517    if (tick < 1)
5518	tick = 1;
5519#endif
5520
5521    for (;;) {
5522	int size;
5523	int time_select;
5524
5525	if (screen->eventMode == NORMAL
5526	    && (size = readPtyData(xw, &select_mask, VTbuffer)) != 0) {
5527	    if (screen->scrollWidget
5528		&& screen->scrollttyoutput
5529		&& screen->topline < 0)
5530		WindowScroll(xw, 0, False);	/* Scroll to bottom */
5531	    /* stop speed reading at some point to look for X stuff */
5532	    TRACE(("VTbuffer uses %ld/%d\n",
5533		   (long) (VTbuffer->last - VTbuffer->buffer),
5534		   BUF_SIZE));
5535	    if ((VTbuffer->last - VTbuffer->buffer) > BUF_SIZE) {
5536		FD_CLR(screen->respond, &select_mask);
5537		break;
5538	    }
5539#if USE_DOUBLE_BUFFER
5540	    if (resource.buffered && should_wait) {
5541		/* wait for potential extra data (avoids some flickering) */
5542		usleep((unsigned) DbeMsecs(xw));
5543		should_wait = 0;
5544	    }
5545#endif
5546#if defined(HAVE_SCHED_YIELD)
5547	    /*
5548	     * If we've read a full (small/fragment) buffer, let the operating
5549	     * system have a turn, and we'll resume reading until we've either
5550	     * read only a fragment of the buffer, or we've filled the large
5551	     * buffer (see above).  Doing this helps keep up with large bursts
5552	     * of output.
5553	     */
5554	    if (size == FRG_SIZE) {
5555		select_timeout.tv_sec = 0;
5556		i = Select(max_plus1, &select_mask, &write_mask, 0,
5557			   &select_timeout);
5558		if (i > 0 && FD_ISSET(screen->respond, &select_mask)) {
5559		    sched_yield();
5560		} else
5561		    break;
5562	    } else {
5563		break;
5564	    }
5565#else
5566	    (void) size;	/* unused in this branch */
5567	    break;
5568#endif
5569	}
5570	update_the_screen(xw);
5571
5572	XFlush(screen->display);	/* always flush writes before waiting */
5573
5574	/* Update the masks and, unless X events are already in the queue,
5575	   wait for I/O to be possible. */
5576	XFD_COPYSET(&Select_mask, &select_mask);
5577	/* in selection mode xterm does not read pty */
5578	if (screen->eventMode != NORMAL)
5579	    FD_CLR(screen->respond, &select_mask);
5580
5581	if (v_bufptr > v_bufstr) {
5582	    XFD_COPYSET(&pty_mask, &write_mask);
5583	} else
5584	    FD_ZERO(&write_mask);
5585	select_timeout.tv_sec = 0;
5586	time_select = 0;
5587
5588	/*
5589	 * if there's either an XEvent or an XtTimeout pending, just take
5590	 * a quick peek, i.e. timeout from the select() immediately.  If
5591	 * there's nothing pending, let select() block a little while, but
5592	 * for a shorter interval than the arrow-style scrollbar timeout.
5593	 * The blocking is optional, because it tends to increase the load
5594	 * on the host.
5595	 */
5596	if (xtermAppPending()) {
5597	    select_timeout.tv_usec = 0;
5598	    time_select = 1;
5599	} else if (screen->awaitInput) {
5600	    select_timeout.tv_usec = 50000;
5601	    time_select = 1;
5602#if OPT_BLINK_CURS
5603	} else if ((screen->blink_timer != 0 &&
5604		    ((screen->select & FOCUS) || screen->always_highlight)) ||
5605		   (screen->cursor_state == BLINKED_OFF)) {
5606	    select_timeout.tv_usec = tick;
5607	    while (select_timeout.tv_usec > 1000000) {
5608		select_timeout.tv_usec -= 1000000;
5609		select_timeout.tv_sec++;
5610	    }
5611	    time_select = 1;
5612#endif
5613#if OPT_SESSION_MGT
5614	} else if (resource.sessionMgt) {
5615	    if (ice_fd >= 0)
5616		FD_SET(ice_fd, &select_mask);
5617#endif
5618	}
5619	if (need_cleanup)
5620	    NormalExit();
5621	xtermFlushDbe(xw);
5622	i = Select(max_plus1, &select_mask, &write_mask, 0,
5623		   (time_select ? &select_timeout : 0));
5624	if (i < 0) {
5625	    if (errno != EINTR)
5626		SysError(ERROR_SELECT);
5627	    continue;
5628	}
5629
5630	/* if there is room to write more data to the pty, go write more */
5631	if (FD_ISSET(screen->respond, &write_mask)) {
5632	    v_write(screen->respond, (Char *) 0, 0);	/* flush buffer */
5633	}
5634
5635	/* if there are X events already in our queue, it
5636	   counts as being readable */
5637	if (xtermAppPending() ||
5638	    FD_ISSET(ConnectionNumber(screen->display), &select_mask)) {
5639	    xevents(xw);
5640	    if (VTbuffer->update != update)	/* HandleInterpret */
5641		break;
5642	}
5643
5644    }
5645}
5646#endif /* VMS */
5647
5648static IChar
5649doinput(XtermWidget xw)
5650{
5651    TScreen *screen = TScreenOf(xw);
5652
5653    while (!morePtyData(screen, VTbuffer))
5654	in_put(xw);
5655    return nextPtyData(screen, VTbuffer);
5656}
5657
5658#if OPT_INPUT_METHOD
5659/*
5660 *  For OverTheSpot, client has to inform the position for XIM preedit.
5661 */
5662static void
5663PreeditPosition(XtermWidget xw)
5664{
5665    TInput *input = lookupTInput(xw, (Widget) xw);
5666    TScreen *screen = TScreenOf(xw);
5667    CLineData *ld;
5668    XPoint spot;
5669    XVaNestedList list;
5670
5671    if (input && input->xic
5672	&& (ld = getLineData(screen, screen->cur_row)) != 0) {
5673	spot.x = (short) LineCursorX(screen, ld, screen->cur_col);
5674	spot.y = (short) (CursorY(screen, screen->cur_row) + xw->work.xim_fs_ascent);
5675	list = XVaCreateNestedList(0,
5676				   XNSpotLocation, &spot,
5677				   XNForeground, T_COLOR(screen, TEXT_FG),
5678				   XNBackground, T_COLOR(screen, TEXT_BG),
5679				   (void *) 0);
5680	XSetICValues(input->xic, XNPreeditAttributes, list, (void *) 0);
5681	XFree(list);
5682    }
5683}
5684#endif
5685
5686static void
5687WrapLine(XtermWidget xw)
5688{
5689    TScreen *screen = TScreenOf(xw);
5690    LineData *ld = getLineData(screen, screen->cur_row);
5691
5692    if (ld != 0) {
5693	/* mark that we had to wrap this line */
5694	LineSetFlag(ld, LINEWRAPPED);
5695	ShowWrapMarks(xw, screen->cur_row, ld);
5696	xtermAutoPrint(xw, '\n');
5697	xtermIndex(xw, 1);
5698	set_cur_col(screen, ScrnLeftMargin(xw));
5699    }
5700}
5701
5702/*
5703 * Process a string of characters according to the character set indicated by
5704 * charset.  Worry about end of line conditions (wraparound if selected).
5705 *
5706 * It is possible to use CUP, etc., to move outside margins.  In that case, the
5707 * right-margin is ineffective until the text (may) wrap and get within the
5708 * margins.
5709 */
5710void
5711dotext(XtermWidget xw,
5712       DECNRCM_codes charset,
5713       IChar *buf,		/* start of characters to process */
5714       Cardinal len)		/* end */
5715{
5716    TScreen *screen = TScreenOf(xw);
5717#if OPT_WIDE_CHARS
5718    Cardinal chars_chomped = 1;
5719    int next_col = screen->cur_col;
5720#else
5721    int next_col, this_col;	/* must be signed */
5722#endif
5723    Cardinal offset;
5724    int rmargin = ScrnRightMargin(xw);
5725
5726#if OPT_WIDE_CHARS
5727    if (screen->vt100_graphics)
5728#endif
5729	if (!(len = (Cardinal) xtermCharSetOut(xw, buf, buf + len, charset)))
5730	    return;
5731
5732    if_OPT_XMC_GLITCH(screen, {
5733	Cardinal n;
5734	if (charset != '?') {
5735	    for (n = 0; n < len; n++) {
5736		if (buf[n] == XMC_GLITCH)
5737		    buf[n] = XMC_GLITCH + 1;
5738	    }
5739	}
5740    });
5741
5742#if OPT_WIDE_CHARS
5743    for (offset = 0;
5744	 offset < len && (chars_chomped > 0 || screen->do_wrap);
5745	 offset += chars_chomped) {
5746	int width_here = 0;
5747	int last_chomp = 0;
5748	Boolean force_wrap;
5749
5750	chars_chomped = 0;
5751	do {
5752	    int right = ((screen->cur_col > rmargin)
5753			 ? screen->max_col
5754			 : rmargin);
5755	    int width_available = right + 1 - screen->cur_col;
5756	    Boolean need_wrap = False;
5757	    Boolean did_wrap = False;
5758
5759	    force_wrap = False;
5760
5761	    if (screen->do_wrap) {
5762		screen->do_wrap = False;
5763		if ((xw->flags & WRAPAROUND)) {
5764		    WrapLine(xw);
5765		    right = ((screen->cur_col > rmargin)
5766			     ? screen->max_col
5767			     : rmargin);
5768		    width_available = right + 1 - screen->cur_col;
5769		    next_col = screen->cur_col;
5770		    did_wrap = True;
5771		}
5772	    }
5773
5774	    /*
5775	     * This can happen with left/right margins...
5776	     */
5777	    if (width_available <= 0) {
5778		break;
5779	    }
5780
5781	    /*
5782	     * Regarding the soft-hyphen aberration, see
5783	     * http://archives.miloush.net/michkap/archive/2006/09/02/736881.html
5784	     */
5785	    while (width_here <= width_available
5786		   && chars_chomped < (len - offset)) {
5787		Cardinal n = chars_chomped + offset;
5788		if (!screen->utf8_mode
5789		    || (screen->vt100_graphics && charset == '0')) {
5790		    last_chomp = 1;
5791		} else if (screen->c1_printable &&
5792			   buf[n] >= 0x80 &&
5793			   buf[n] <= 0xa0) {
5794		    last_chomp = 1;
5795		} else {
5796		    last_chomp = CharWidth(buf[n]);
5797		    if (last_chomp <= 0) {
5798			IChar ch = buf[n];
5799			Bool eat_it = !screen->utf8_mode && (ch > 127);
5800			if (ch == 0xad) {
5801			    /*
5802			     * Only display soft-hyphen if it happens to be at
5803			     * the right-margin.  While that means that only
5804			     * the displayed character could be selected for
5805			     * pasting, a well-behaved application would never
5806			     * send this, anyway...
5807			     */
5808			    if (width_here < width_available - 1) {
5809				eat_it = True;
5810			    } else {
5811				last_chomp = 1;
5812				eat_it = False;
5813			    }
5814			    TRACE(("...will%s display soft-hyphen\n",
5815				   eat_it ? " not" : ""));
5816			}
5817			/*
5818			 * Supposedly we dealt with combining characters and
5819			 * control characters in doparse().  Anything left over
5820			 * is junk that we will not attempt to display.
5821			 */
5822			if (eat_it) {
5823			    TRACE(("...will not display U+%04X\n", ch));
5824			    --len;
5825			    while (n < len) {
5826				buf[n] = buf[n + 1];
5827				++n;
5828			    }
5829			    last_chomp = 0;
5830			    chars_chomped--;
5831			}
5832		    }
5833		}
5834		width_here += last_chomp;
5835		chars_chomped++;
5836	    }
5837
5838	    if (width_here > width_available) {
5839		if (last_chomp > right + 1) {
5840		    break;	/* give up - it is too big */
5841		} else if (chars_chomped-- == 0) {
5842		    /* This can happen with left/right margins... */
5843		    break;
5844		}
5845		width_here -= last_chomp;
5846		if (chars_chomped > 0) {
5847		    if (!(xw->flags & WRAPAROUND)) {
5848			buf[chars_chomped + offset - 1] = buf[len - 1];
5849		    } else {
5850			need_wrap = True;
5851		    }
5852		}
5853	    } else if (width_here == width_available) {
5854		need_wrap = True;
5855	    } else if (chars_chomped != (len - offset)) {
5856		need_wrap = True;
5857	    }
5858
5859	    if (chars_chomped != 0 && next_col <= screen->max_col) {
5860		WriteText(xw, buf + offset, chars_chomped);
5861	    } else if (!did_wrap
5862		       && len > 0
5863		       && (xw->flags & WRAPAROUND)
5864		       && screen->cur_col > ScrnLeftMargin(xw)) {
5865		force_wrap = True;
5866		need_wrap = True;
5867	    }
5868	    next_col += width_here;
5869	    screen->do_wrap = need_wrap;
5870	} while (force_wrap);
5871    }
5872
5873    /*
5874     * Remember that we wrote something to the screen, for use as a base of
5875     * combining characters.  The logic above may have called cursor-forward
5876     * or carriage-return operations which resets this flag, so we set it at
5877     * the very end.
5878     */
5879    screen->char_was_written = True;
5880#else /* ! OPT_WIDE_CHARS */
5881
5882    for (offset = 0; offset < len; offset += (Cardinal) this_col) {
5883#if OPT_DEC_CHRSET
5884	CLineData *ld = getLineData(screen, screen->cur_row);
5885#endif
5886	int right = ((screen->cur_col > rmargin)
5887		     ? screen->max_col
5888		     : rmargin);
5889
5890	int last_col = LineMaxCol(screen, ld);
5891	if (last_col > right)
5892	    last_col = right;
5893	this_col = last_col - screen->cur_col + 1;
5894	if (screen->do_wrap) {
5895	    screen->do_wrap = False;
5896	    if ((xw->flags & WRAPAROUND)) {
5897		WrapLine(xw);
5898	    }
5899	    this_col = 1;
5900	}
5901	if (offset + (Cardinal) this_col > len) {
5902	    this_col = (int) (len - offset);
5903	}
5904	next_col = screen->cur_col + this_col;
5905
5906	WriteText(xw, buf + offset, (unsigned) this_col);
5907
5908	/*
5909	 * The call to WriteText updates screen->cur_col.
5910	 * If screen->cur_col is less than next_col, we must have
5911	 * hit the right margin - so set the do_wrap flag.
5912	 */
5913	screen->do_wrap = (Boolean) (screen->cur_col < next_col);
5914    }
5915
5916#endif /* OPT_WIDE_CHARS */
5917}
5918
5919#if OPT_WIDE_CHARS
5920unsigned
5921visual_width(const IChar *str, Cardinal len)
5922{
5923    /* returns the visual width of a string (doublewide characters count
5924       as 2, normalwide characters count as 1) */
5925    unsigned my_len = 0;
5926    while (len) {
5927	int ch = (int) *str++;
5928	if (isWide(ch))
5929	    my_len += 2;
5930	else
5931	    my_len++;
5932	len--;
5933    }
5934    return my_len;
5935}
5936#endif
5937
5938#if HANDLE_STRUCT_NOTIFY
5939/* Flag icon name with "***" on window output when iconified.
5940 */
5941static void
5942HandleStructNotify(Widget w GCC_UNUSED,
5943		   XtPointer closure GCC_UNUSED,
5944		   XEvent *event,
5945		   Boolean *cont GCC_UNUSED)
5946{
5947    XtermWidget xw = term;
5948    TScreen *screen = TScreenOf(xw);
5949
5950    (void) screen;
5951    TRACE_EVENT("HandleStructNotify", event, NULL, 0);
5952    switch (event->type) {
5953    case MapNotify:
5954	resetZIconBeep(xw);
5955	mapstate = !IsUnmapped;
5956	break;
5957    case UnmapNotify:
5958	mapstate = IsUnmapped;
5959	break;
5960    case MappingNotify:
5961	XRefreshKeyboardMapping(&(event->xmapping));
5962	VTInitModifiers(xw);
5963	break;
5964    case ConfigureNotify:
5965	if (event->xconfigure.window == XtWindow(toplevel)) {
5966#if !OPT_TOOLBAR
5967	    int height = event->xconfigure.height;
5968	    int width = event->xconfigure.width;
5969#endif
5970
5971#if USE_DOUBLE_BUFFER
5972	    discardRenderDraw(screen);
5973#endif /* USE_DOUBLE_BUFFER */
5974#if OPT_TOOLBAR
5975	    /*
5976	     * The notification is for the top-level widget, but we care about
5977	     * vt100 (ignore the tek4014 window).
5978	     */
5979	    if (screen->Vshow) {
5980		VTwin *Vwin = WhichVWin(screen);
5981		TbInfo *info = &(Vwin->tb_info);
5982		TbInfo save = *info;
5983
5984		if (info->menu_bar) {
5985		    XtVaGetValues(info->menu_bar,
5986				  XtNheight, &info->menu_height,
5987				  XtNborderWidth, &info->menu_border,
5988				  (XtPointer) 0);
5989
5990		    if (save.menu_height != info->menu_height
5991			|| save.menu_border != info->menu_border) {
5992
5993			TRACE(("...menu_height %d\n", info->menu_height));
5994			TRACE(("...menu_border %d\n", info->menu_border));
5995			TRACE(("...had height  %d, border %d\n",
5996			       save.menu_height,
5997			       save.menu_border));
5998
5999			/*
6000			 * Window manager still may be using the old values.
6001			 * Try to fool it.
6002			 */
6003			REQ_RESIZE((Widget) xw,
6004				   screen->fullVwin.fullwidth,
6005				   (Dimension) (info->menu_height
6006						- save.menu_height
6007						+ screen->fullVwin.fullheight),
6008				   NULL, NULL);
6009			repairSizeHints();
6010		    }
6011		}
6012	    }
6013#else
6014	    if (!xw->work.doing_resize
6015#if OPT_RENDERFONT && USE_DOUBLE_BUFFER
6016		&& !(resource.buffered && UsingRenderFont(xw))	/* buggyXft */
6017#endif
6018		&& (height != xw->hints.height
6019		    || width != xw->hints.width)) {
6020		/*
6021		 * This is a special case: other calls to RequestResize that
6022		 * could set the screensize arbitrarily are via escape
6023		 * sequences, and we've limited resizing.  But a configure
6024		 * notify is from the window manager, presumably under control
6025		 * of the interactive user (ignoring abuse of wmctrl).  Ignore
6026		 * the limit for this case.
6027		 */
6028		int saved_limit = xw->misc.limit_resize;
6029		xw->misc.limit_resize = 0;
6030		RequestResize(xw, height, width, False);
6031		xw->misc.limit_resize = saved_limit;
6032	    }
6033#endif /* OPT_TOOLBAR */
6034	}
6035	break;
6036    }
6037}
6038#endif /* HANDLE_STRUCT_NOTIFY */
6039
6040#if OPT_BLINK_CURS
6041static int
6042DoStartBlinking(TScreen *screen)
6043{
6044    int actual = ((screen->cursor_blink == cbTrue ||
6045		   screen->cursor_blink == cbAlways)
6046		  ? 1
6047		  : 0);
6048    int wanted = screen->cursor_blink_esc ? 1 : 0;
6049    int result;
6050    if (screen->cursor_blink_xor) {
6051	result = actual ^ wanted;
6052    } else {
6053	result = actual | wanted;
6054    }
6055    return result;
6056}
6057
6058static void
6059SetCursorBlink(XtermWidget xw, BlinkOps enable)
6060{
6061    TScreen *screen = TScreenOf(xw);
6062
6063    if (SettableCursorBlink(screen)) {
6064	screen->cursor_blink = enable;
6065    }
6066    if (DoStartBlinking(screen)) {
6067	StartBlinking(xw);
6068    } else {
6069	/* EMPTY */
6070#if OPT_BLINK_TEXT
6071	reallyStopBlinking(xw);
6072#else
6073	StopBlinking(xw);
6074#endif
6075    }
6076    update_cursorblink();
6077}
6078
6079void
6080ToggleCursorBlink(XtermWidget xw)
6081{
6082    TScreen *screen = TScreenOf(xw);
6083
6084    if (screen->cursor_blink == cbTrue) {
6085	SetCursorBlink(xw, cbFalse);
6086    } else if (screen->cursor_blink == cbFalse) {
6087	SetCursorBlink(xw, cbTrue);
6088    }
6089}
6090#endif
6091
6092/*
6093 * process ANSI modes set, reset
6094 */
6095static void
6096ansi_modes(XtermWidget xw, BitFunc func)
6097{
6098    int i;
6099
6100    for (i = 0; i < nparam; ++i) {
6101	switch (GetParam(i)) {
6102	case 2:		/* KAM (if set, keyboard locked */
6103	    (*func) (&xw->keyboard.flags, MODE_KAM);
6104	    break;
6105
6106	case 4:		/* IRM                          */
6107	    (*func) (&xw->flags, INSERT);
6108	    break;
6109
6110	case 12:		/* SRM (if set, local echo      */
6111	    (*func) (&xw->keyboard.flags, MODE_SRM);
6112	    break;
6113
6114	case 20:		/* LNM                          */
6115	    (*func) (&xw->flags, LINEFEED);
6116	    update_autolinefeed();
6117	    break;
6118	}
6119    }
6120}
6121
6122#define IsSM() (func == bitset)
6123
6124#define set_bool_mode(flag) \
6125	flag = (Boolean) IsSM()
6126
6127static void
6128really_set_mousemode(XtermWidget xw,
6129		     Bool enabled,
6130		     XtermMouseModes mode)
6131{
6132    TScreenOf(xw)->send_mouse_pos = enabled ? mode : MOUSE_OFF;
6133    if (okSendMousePos(xw) != MOUSE_OFF)
6134	xtermShowPointer(xw, True);
6135}
6136
6137#define set_mousemode(mode) really_set_mousemode(xw, IsSM(), mode)
6138
6139#if OPT_PASTE64 || OPT_READLINE
6140#define set_mouseflag(f)		\
6141	(IsSM()				\
6142	 ? SCREEN_FLAG_set(screen, f)	\
6143	 : SCREEN_FLAG_unset(screen, f))
6144#endif
6145
6146/*
6147 * process DEC private modes set, reset
6148 */
6149static void
6150dpmodes(XtermWidget xw, BitFunc func)
6151{
6152    TScreen *screen = TScreenOf(xw);
6153    int i, j;
6154    unsigned myflags;
6155
6156    TRACE(("changing %d DEC private modes\n", nparam));
6157    for (i = 0; i < nparam; ++i) {
6158	int code = GetParam(i);
6159
6160	TRACE(("%s %d\n", IsSM()? "DECSET" : "DECRST", code));
6161	switch ((DECSET_codes) code) {
6162	case srm_DECCKM:
6163	    (*func) (&xw->keyboard.flags, MODE_DECCKM);
6164	    update_appcursor();
6165	    break;
6166	case srm_DECANM:	/* ANSI/VT52 mode      */
6167	    if (IsSM()) {	/* ANSI (VT100) */
6168		/*
6169		 * Setting DECANM should have no effect, since this function
6170		 * cannot be reached from vt52 mode.
6171		 */
6172		/* EMPTY */ ;
6173	    }
6174#if OPT_VT52_MODE
6175	    else if (screen->terminal_id >= 100) {	/* VT52 */
6176		TRACE(("DECANM terminal_id %d, vtXX_level %d\n",
6177		       screen->terminal_id,
6178		       screen->vtXX_level));
6179		/*
6180		 * According to DEC STD 070 section A.5.5, the various VT100
6181		 * modes have undefined behavior when entering/exiting VT52
6182		 * mode.  xterm saves/restores/initializes the most commonly
6183		 * used settings, but a real VT100 or VT520 may differ.
6184		 *
6185		 * For instance, DEC's documentation goes on to comment that
6186		 * while the VT52 uses hardware tabs (8 columns), the emulation
6187		 * (e.g., a VT420) does not alter those tab settings when
6188		 * switching modes.
6189		 */
6190		screen->vtXX_level = 0;
6191		screen->vt52_save_flags = xw->flags;
6192		xw->flags = 0;
6193		screen->vt52_save_curgl = screen->curgl;
6194		screen->vt52_save_curgr = screen->curgr;
6195		screen->vt52_save_curss = screen->curss;
6196		saveCharsets(screen, screen->vt52_save_gsets);
6197		resetCharsets(screen);
6198		InitParams();	/* ignore the remaining params, if any */
6199		update_vt52_vt100_settings();
6200		RequestResize(xw, -1, 80, True);
6201	    }
6202#endif
6203	    break;
6204	case srm_DECCOLM:
6205	    if (screen->c132) {
6206		Boolean willResize = ((j = IsSM()
6207				       ? 132
6208				       : 80)
6209				      != ((xw->flags & IN132COLUMNS)
6210					  ? 132
6211					  : 80)
6212				      || j != MaxCols(screen));
6213		if (!(xw->flags & NOCLEAR_COLM))
6214		    ClearScreen(xw);
6215		if (willResize)
6216		    RequestResize(xw, -1, j, True);
6217		(*func) (&xw->flags, IN132COLUMNS);
6218		resetMargins(xw);
6219		CursorSet(screen, 0, 0, xw->flags);
6220	    }
6221	    break;
6222	case srm_DECSCLM:	/* (slow scroll)        */
6223	    if (IsSM()) {
6224		screen->jumpscroll = 0;
6225		if (screen->scroll_amt)
6226		    FlushScroll(xw);
6227	    } else
6228		screen->jumpscroll = 1;
6229	    (*func) (&xw->flags, SMOOTHSCROLL);
6230	    update_jumpscroll();
6231	    break;
6232	case srm_DECSCNM:
6233	    myflags = xw->flags;
6234	    (*func) (&xw->flags, REVERSE_VIDEO);
6235	    if ((xw->flags ^ myflags) & REVERSE_VIDEO)
6236		ReverseVideo(xw);
6237	    /* update_reversevideo done in RevVid */
6238	    break;
6239
6240	case srm_DECOM:
6241	    (*func) (&xw->flags, ORIGIN);
6242	    CursorSet(screen, 0, 0, xw->flags);
6243	    break;
6244
6245	case srm_DECAWM:
6246	    (*func) (&xw->flags, WRAPAROUND);
6247	    update_autowrap();
6248	    break;
6249	case srm_DECARM:
6250	    /* ignore autorepeat
6251	     * XAutoRepeatOn() and XAutoRepeatOff() can do this, but only
6252	     * for the whole display - not limited to a given window.
6253	     */
6254	    break;
6255	case srm_X10_MOUSE:	/* MIT bogus sequence           */
6256	    MotionOff(screen, xw);
6257	    set_mousemode(X10_MOUSE);
6258	    break;
6259#if OPT_TOOLBAR
6260	case srm_RXVT_TOOLBAR:
6261	    ShowToolbar(IsSM());
6262	    break;
6263#endif
6264#if OPT_BLINK_CURS
6265	case srm_ATT610_BLINK:	/* AT&T 610: Start/stop blinking cursor */
6266	    if (SettableCursorBlink(screen)) {
6267		set_bool_mode(screen->cursor_blink_esc);
6268		UpdateCursorBlink(xw);
6269	    }
6270	    break;
6271	case srm_CURSOR_BLINK_OPS:
6272	    /* intentionally ignored (this is user-preference) */
6273	    break;
6274	case srm_XOR_CURSOR_BLINKS:
6275	    /* intentionally ignored (this is user-preference) */
6276	    break;
6277#endif
6278	case srm_DECPFF:	/* print form feed */
6279	    set_bool_mode(PrinterOf(screen).printer_formfeed);
6280	    break;
6281	case srm_DECPEX:	/* print extent */
6282	    set_bool_mode(PrinterOf(screen).printer_extent);
6283	    break;
6284	case srm_DECTCEM:	/* Show/hide cursor (VT200) */
6285	    set_bool_mode(screen->cursor_set);
6286	    break;
6287	case srm_RXVT_SCROLLBAR:
6288	    if (screen->fullVwin.sb_info.width != (IsSM()? ON : OFF))
6289		ToggleScrollBar(xw);
6290	    break;
6291#if OPT_SHIFT_FONTS
6292	case srm_RXVT_FONTSIZE:
6293	    set_bool_mode(xw->misc.shift_fonts);
6294	    break;
6295#endif
6296#if OPT_TEK4014
6297	case srm_DECTEK:
6298	    if (IsSM() && !(screen->inhibit & I_TEK)) {
6299		FlushLog(xw);
6300		TEK4014_ACTIVE(xw) = True;
6301		TRACE(("Tek4014 is now active...\n"));
6302		update_vttekmode();
6303	    }
6304	    break;
6305#endif
6306	case srm_132COLS:	/* 132 column mode              */
6307	    set_bool_mode(screen->c132);
6308	    update_allow132();
6309	    break;
6310	case srm_CURSES_HACK:
6311	    set_bool_mode(screen->curses);
6312	    update_cursesemul();
6313	    break;
6314	case srm_DECNRCM:	/* national charset (VT220) */
6315	    if (screen->vtXX_level >= 2) {
6316		if ((*func) (&xw->flags, NATIONAL)) {
6317		    modified_DECNRCM(xw);
6318		}
6319	    }
6320	    break;
6321#if OPT_PRINT_GRAPHICS
6322	case srm_DECGEPM:	/* Graphics Expanded Print Mode */
6323	    set_bool_mode(screen->graphics_expanded_print_mode);
6324	    break;
6325#endif
6326	case srm_MARGIN_BELL:	/* margin bell (xterm) also DECGPCM (Graphics Print Color Mode) */
6327	    if_PRINT_GRAPHICS2(set_bool_mode(screen->graphics_print_color_mode)) {
6328		set_bool_mode(screen->marginbell);
6329		if (!screen->marginbell)
6330		    screen->bellArmed = -1;
6331		update_marginbell();
6332	    }
6333	    break;
6334	case srm_REVERSEWRAP:	/* reverse wraparound (xterm) also DECGPCS (Graphics Print Color Syntax) */
6335	    if_PRINT_GRAPHICS2(set_bool_mode(screen->graphics_print_color_syntax)) {
6336		(*func) (&xw->flags, REVERSEWRAP);
6337		update_reversewrap();
6338	    }
6339	    break;
6340#ifdef ALLOWLOGGING
6341	case srm_ALLOWLOGGING:	/* logging (xterm) also DECGPBM (Graphics Print Background Mode) */
6342	    if_PRINT_GRAPHICS2(set_bool_mode(screen->graphics_print_background_mode)) {
6343#ifdef ALLOWLOGFILEONOFF
6344		/*
6345		 * if this feature is enabled, logging may be
6346		 * enabled and disabled via escape sequences.
6347		 */
6348		if (IsSM())
6349		    StartLog(xw);
6350		else
6351		    CloseLog(xw);
6352#else
6353		Bell(xw, XkbBI_Info, 0);
6354		Bell(xw, XkbBI_Info, 0);
6355#endif /* ALLOWLOGFILEONOFF */
6356	    }
6357	    break;
6358#elif OPT_PRINT_GRAPHICS
6359	case srm_DECGPBM:	/* Graphics Print Background Mode */
6360	    set_bool_mode(screen->graphics_print_background_mode);
6361	    break;
6362#endif /* ALLOWLOGGING */
6363	case srm_OPT_ALTBUF_CURSOR:	/* optional alternate buffer and clear (xterm) */
6364	    if (!xw->misc.titeInhibit) {
6365		if (IsSM()) {
6366		    CursorSave(xw);
6367		    ToAlternate(xw, True);
6368		    ClearScreen(xw);
6369		} else {
6370		    FromAlternate(xw);
6371		    CursorRestore(xw);
6372		}
6373	    } else if (IsSM()) {
6374		do_ti_xtra_scroll(xw);
6375	    }
6376	    break;
6377	case srm_OPT_ALTBUF:	/* optional alternate buffer and clear (xterm) */
6378	    if (!xw->misc.titeInhibit) {
6379		if (IsSM()) {
6380		    ToAlternate(xw, False);
6381		} else {
6382		    if (screen->whichBuf)
6383			ClearScreen(xw);
6384		    FromAlternate(xw);
6385		}
6386	    } else if (IsSM()) {
6387		do_ti_xtra_scroll(xw);
6388	    }
6389	    break;
6390	case srm_ALTBUF:	/* alternate buffer (xterm) also DECGRPM (Graphics Rotated Print Mode) */
6391	    if_PRINT_GRAPHICS2(set_bool_mode(screen->graphics_rotated_print_mode)) {
6392		if (!xw->misc.titeInhibit) {
6393		    if (IsSM()) {
6394			ToAlternate(xw, False);
6395		    } else {
6396			FromAlternate(xw);
6397		    }
6398		} else if (IsSM()) {
6399		    do_ti_xtra_scroll(xw);
6400		}
6401	    }
6402	    break;
6403	case srm_DECNKM:
6404	    (*func) (&xw->keyboard.flags, MODE_DECKPAM);
6405	    update_appkeypad();
6406	    break;
6407	case srm_DECBKM:
6408	    /* back-arrow mapped to backspace or delete(D) */
6409	    (*func) (&xw->keyboard.flags, MODE_DECBKM);
6410	    TRACE(("DECSET DECBKM %s\n",
6411		   BtoS(xw->keyboard.flags & MODE_DECBKM)));
6412	    update_decbkm();
6413	    break;
6414	case srm_DECLRMM:
6415	    if (screen->vtXX_level >= 4) {	/* VT420 */
6416		(*func) (&xw->flags, LEFT_RIGHT);
6417		if (IsLeftRightMode(xw)) {
6418		    xterm_ResetDouble(xw);
6419		} else {
6420		    reset_lr_margins(screen);
6421		}
6422	    }
6423	    break;
6424#if OPT_SIXEL_GRAPHICS
6425	case srm_DECSDM:	/* sixel scrolling */
6426	    if (optSixelGraphics(screen)) {	/* FIXME: VT24x did not scroll sixel graphics */
6427		(*func) (&xw->keyboard.flags, MODE_DECSDM);
6428		TRACE(("DECSET/DECRST DECSDM %s (resource default is %d)\n",
6429		       BtoS(xw->keyboard.flags & MODE_DECSDM),
6430		       TScreenOf(xw)->sixel_scrolling));
6431		update_decsdm();
6432	    }
6433	    break;
6434#endif
6435	case srm_DECNCSM:
6436	    if (screen->vtXX_level >= 5) {	/* VT510 */
6437		(*func) (&xw->flags, NOCLEAR_COLM);
6438	    }
6439	    break;
6440	case srm_VT200_MOUSE:	/* xterm bogus sequence         */
6441	    MotionOff(screen, xw);
6442	    set_mousemode(VT200_MOUSE);
6443	    break;
6444	case srm_VT200_HIGHLIGHT_MOUSE:	/* xterm sequence w/hilite tracking */
6445	    MotionOff(screen, xw);
6446	    set_mousemode(VT200_HIGHLIGHT_MOUSE);
6447	    break;
6448	case srm_BTN_EVENT_MOUSE:
6449	    MotionOff(screen, xw);
6450	    set_mousemode(BTN_EVENT_MOUSE);
6451	    break;
6452	case srm_ANY_EVENT_MOUSE:
6453	    set_mousemode(ANY_EVENT_MOUSE);
6454	    if (screen->send_mouse_pos == MOUSE_OFF) {
6455		MotionOff(screen, xw);
6456	    } else {
6457		MotionOn(screen, xw);
6458	    }
6459	    break;
6460#if OPT_FOCUS_EVENT
6461	case srm_FOCUS_EVENT_MOUSE:
6462	    set_bool_mode(screen->send_focus_pos);
6463	    break;
6464#endif
6465	case srm_EXT_MODE_MOUSE:
6466	    /* FALLTHRU */
6467	case srm_SGR_EXT_MODE_MOUSE:
6468	    /* FALLTHRU */
6469	case srm_URXVT_EXT_MODE_MOUSE:
6470	    /* FALLTHRU */
6471	case srm_PIXEL_POSITION_MOUSE:
6472	    /*
6473	     * Rather than choose an arbitrary precedence among the coordinate
6474	     * modes, they are mutually exclusive.  For consistency, a reset is
6475	     * only effective against the matching mode.
6476	     */
6477	    if (IsSM()) {
6478		screen->extend_coords = code;
6479	    } else if (screen->extend_coords == code) {
6480		screen->extend_coords = 0;
6481	    }
6482	    break;
6483	case srm_ALTERNATE_SCROLL:
6484	    set_bool_mode(screen->alternateScroll);
6485	    break;
6486	case srm_RXVT_SCROLL_TTY_OUTPUT:
6487	    set_bool_mode(screen->scrollttyoutput);
6488	    update_scrollttyoutput();
6489	    break;
6490	case srm_RXVT_SCROLL_TTY_KEYPRESS:
6491	    set_bool_mode(screen->scrollkey);
6492	    update_scrollkey();
6493	    break;
6494	case srm_EIGHT_BIT_META:
6495	    if (screen->eight_bit_meta != ebNever) {
6496		set_bool_mode(screen->eight_bit_meta);
6497	    }
6498	    break;
6499#if OPT_NUM_LOCK
6500	case srm_REAL_NUMLOCK:
6501	    set_bool_mode(xw->misc.real_NumLock);
6502	    update_num_lock();
6503	    break;
6504	case srm_META_SENDS_ESC:
6505	    set_bool_mode(screen->meta_sends_esc);
6506	    update_meta_esc();
6507	    break;
6508#endif
6509	case srm_DELETE_IS_DEL:
6510	    set_bool_mode(screen->delete_is_del);
6511	    update_delete_del();
6512	    break;
6513#if OPT_NUM_LOCK
6514	case srm_ALT_SENDS_ESC:
6515	    set_bool_mode(screen->alt_sends_esc);
6516	    update_alt_esc();
6517	    break;
6518#endif
6519	case srm_KEEP_SELECTION:
6520	    set_bool_mode(screen->keepSelection);
6521	    update_keepSelection();
6522	    break;
6523	case srm_SELECT_TO_CLIPBOARD:
6524	    set_bool_mode(screen->selectToClipboard);
6525	    update_selectToClipboard();
6526	    break;
6527	case srm_BELL_IS_URGENT:
6528	    set_bool_mode(screen->bellIsUrgent);
6529	    update_bellIsUrgent();
6530	    break;
6531	case srm_POP_ON_BELL:
6532	    set_bool_mode(screen->poponbell);
6533	    update_poponbell();
6534	    break;
6535	case srm_KEEP_CLIPBOARD:
6536	    set_bool_mode(screen->keepClipboard);
6537	    update_keepClipboard();
6538	    break;
6539	case srm_ALLOW_ALTBUF:
6540	    if (IsSM()) {
6541		xw->misc.titeInhibit = False;
6542	    } else if (!xw->misc.titeInhibit) {
6543		xw->misc.titeInhibit = True;
6544		FromAlternate(xw);
6545	    }
6546	    update_titeInhibit();
6547	    break;
6548	case srm_SAVE_CURSOR:
6549	    if (!xw->misc.titeInhibit) {
6550		if (IsSM())
6551		    CursorSave(xw);
6552		else
6553		    CursorRestore(xw);
6554	    }
6555	    break;
6556#if OPT_TCAP_FKEYS
6557	case srm_TCAP_FKEYS:
6558	    set_keyboard_type(xw, keyboardIsTermcap, IsSM());
6559	    break;
6560#endif
6561#if OPT_SUN_FUNC_KEYS
6562	case srm_SUN_FKEYS:
6563	    set_keyboard_type(xw, keyboardIsSun, IsSM());
6564	    break;
6565#endif
6566#if OPT_HP_FUNC_KEYS
6567	case srm_HP_FKEYS:
6568	    set_keyboard_type(xw, keyboardIsHP, IsSM());
6569	    break;
6570#endif
6571#if OPT_SCO_FUNC_KEYS
6572	case srm_SCO_FKEYS:
6573	    set_keyboard_type(xw, keyboardIsSCO, IsSM());
6574	    break;
6575#endif
6576	case srm_LEGACY_FKEYS:
6577	    set_keyboard_type(xw, keyboardIsLegacy, IsSM());
6578	    break;
6579#if OPT_SUNPC_KBD
6580	case srm_VT220_FKEYS:
6581	    set_keyboard_type(xw, keyboardIsVT220, IsSM());
6582	    break;
6583#endif
6584#if OPT_PASTE64 || OPT_READLINE
6585	case srm_PASTE_IN_BRACKET:
6586	    set_mouseflag(paste_brackets);
6587	    break;
6588#endif
6589#if OPT_READLINE
6590	case srm_BUTTON1_MOVE_POINT:
6591	    set_mouseflag(click1_moves);
6592	    break;
6593	case srm_BUTTON2_MOVE_POINT:
6594	    set_mouseflag(paste_moves);
6595	    break;
6596	case srm_DBUTTON3_DELETE:
6597	    set_mouseflag(dclick3_deletes);
6598	    break;
6599	case srm_PASTE_QUOTE:
6600	    set_mouseflag(paste_quotes);
6601	    break;
6602	case srm_PASTE_LITERAL_NL:
6603	    set_mouseflag(paste_literal_nl);
6604	    break;
6605#endif /* OPT_READLINE */
6606#if OPT_GRAPHICS
6607	case srm_PRIVATE_COLOR_REGISTERS:	/* private color registers for each graphic */
6608	    TRACE(("DECSET/DECRST PRIVATE_COLOR_REGISTERS to %s (resource default is %s)\n",
6609		   BtoS(screen->privatecolorregisters),
6610		   BtoS(TScreenOf(xw)->privatecolorregisters)));
6611	    set_bool_mode(screen->privatecolorregisters);
6612	    update_privatecolorregisters();
6613	    break;
6614#endif
6615#if OPT_SIXEL_GRAPHICS
6616	case srm_SIXEL_SCROLLS_RIGHT:	/* sixel scrolling moves cursor to right */
6617	    if (optSixelGraphics(screen)) {	/* FIXME: VT24x did not scroll sixel graphics */
6618		set_bool_mode(screen->sixel_scrolls_right);
6619		TRACE(("DECSET/DECRST SIXEL_SCROLLS_RIGHT to %s (resource default is %s)\n",
6620		       BtoS(screen->sixel_scrolls_right),
6621		       BtoS(TScreenOf(xw)->sixel_scrolls_right)));
6622	    }
6623	    break;
6624#endif
6625	default:
6626	    TRACE(("DATA_ERROR: unknown private code %d\n", code));
6627	    break;
6628	}
6629    }
6630}
6631
6632/*
6633 * process xterm private modes save
6634 */
6635static void
6636savemodes(XtermWidget xw)
6637{
6638    TScreen *screen = TScreenOf(xw);
6639    int i;
6640
6641    for (i = 0; i < nparam; i++) {
6642	int code = GetParam(i);
6643
6644	TRACE(("savemodes %d\n", code));
6645	switch ((DECSET_codes) code) {
6646	case srm_DECCKM:
6647	    DoSM(DP_DECCKM, xw->keyboard.flags & MODE_DECCKM);
6648	    break;
6649	case srm_DECANM:	/* ANSI/VT52 mode      */
6650	    /* no effect */
6651	    break;
6652	case srm_DECCOLM:
6653	    if (screen->c132)
6654		DoSM(DP_DECCOLM, xw->flags & IN132COLUMNS);
6655	    break;
6656	case srm_DECSCLM:	/* (slow scroll)        */
6657	    DoSM(DP_DECSCLM, xw->flags & SMOOTHSCROLL);
6658	    break;
6659	case srm_DECSCNM:
6660	    DoSM(DP_DECSCNM, xw->flags & REVERSE_VIDEO);
6661	    break;
6662	case srm_DECOM:
6663	    DoSM(DP_DECOM, xw->flags & ORIGIN);
6664	    break;
6665	case srm_DECAWM:
6666	    DoSM(DP_DECAWM, xw->flags & WRAPAROUND);
6667	    break;
6668	case srm_DECARM:
6669	    /* ignore autorepeat */
6670	    break;
6671	case srm_X10_MOUSE:	/* mouse bogus sequence */
6672	    DoSM(DP_X_X10MSE, screen->send_mouse_pos);
6673	    break;
6674#if OPT_TOOLBAR
6675	case srm_RXVT_TOOLBAR:
6676	    DoSM(DP_TOOLBAR, resource.toolBar);
6677	    break;
6678#endif
6679#if OPT_BLINK_CURS
6680	case srm_ATT610_BLINK:	/* AT&T 610: Start/stop blinking cursor */
6681	    if (SettableCursorBlink(screen)) {
6682		DoSM(DP_CRS_BLINK, screen->cursor_blink_esc);
6683	    }
6684	    break;
6685	case srm_CURSOR_BLINK_OPS:
6686	    /* intentionally ignored (this is user-preference) */
6687	    break;
6688	case srm_XOR_CURSOR_BLINKS:
6689	    /* intentionally ignored (this is user-preference) */
6690	    break;
6691#endif
6692	case srm_DECPFF:	/* print form feed */
6693	    DoSM(DP_PRN_FORMFEED, PrinterOf(screen).printer_formfeed);
6694	    break;
6695	case srm_DECPEX:	/* print extent */
6696	    DoSM(DP_PRN_EXTENT, PrinterOf(screen).printer_extent);
6697	    break;
6698	case srm_DECTCEM:	/* Show/hide cursor (VT200) */
6699	    DoSM(DP_CRS_VISIBLE, screen->cursor_set);
6700	    break;
6701	case srm_RXVT_SCROLLBAR:
6702	    DoSM(DP_RXVT_SCROLLBAR, (screen->fullVwin.sb_info.width != 0));
6703	    break;
6704#if OPT_SHIFT_FONTS
6705	case srm_RXVT_FONTSIZE:
6706	    DoSM(DP_RXVT_FONTSIZE, xw->misc.shift_fonts);
6707	    break;
6708#endif
6709#if OPT_TEK4014
6710	case srm_DECTEK:
6711	    DoSM(DP_DECTEK, TEK4014_ACTIVE(xw));
6712	    break;
6713#endif
6714	case srm_132COLS:	/* 132 column mode              */
6715	    DoSM(DP_X_DECCOLM, screen->c132);
6716	    break;
6717	case srm_CURSES_HACK:	/* curses hack                  */
6718	    DoSM(DP_X_MORE, screen->curses);
6719	    break;
6720	case srm_DECNRCM:	/* national charset (VT220) */
6721	    if (screen->vtXX_level >= 2) {
6722		DoSM(DP_DECNRCM, xw->flags & NATIONAL);
6723	    }
6724	    break;
6725#if OPT_PRINT_GRAPHICS
6726	case srm_DECGEPM:	/* Graphics Expanded Print Mode */
6727	    DoSM(DP_DECGEPM, screen->graphics_expanded_print_mode);
6728	    break;
6729#endif
6730	case srm_MARGIN_BELL:	/* margin bell (xterm) also DECGPCM (Graphics Print Color Mode) */
6731	    if_PRINT_GRAPHICS2(DoSM(DP_DECGPCM, screen->graphics_print_color_mode)) {
6732		DoSM(DP_X_MARGIN, screen->marginbell);
6733	    }
6734	    break;
6735	case srm_REVERSEWRAP:	/* reverse wraparound (xterm) also DECGPCS (Graphics Print Color Syntax) */
6736	    if_PRINT_GRAPHICS2(DoSM(DP_DECGPCS, screen->graphics_print_color_syntax)) {
6737		DoSM(DP_X_REVWRAP, xw->flags & REVERSEWRAP);
6738	    }
6739	    break;
6740#ifdef ALLOWLOGGING
6741	case srm_ALLOWLOGGING:	/* logging (xterm) also DECGPBM (Graphics Print Background Mode) */
6742	    if_PRINT_GRAPHICS2(DoSM(DP_DECGPBM, screen->graphics_print_background_mode)) {
6743#ifdef ALLOWLOGFILEONOFF
6744		DoSM(DP_X_LOGGING, screen->logging);
6745#endif /* ALLOWLOGFILEONOFF */
6746	    }
6747	    break;
6748#elif OPT_PRINT_GRAPHICS
6749	case srm_DECGPBM:	/* Graphics Print Background Mode */
6750	    DoSM(DP_DECGPBM, screen->graphics_print_background_mode);
6751	    break;
6752#endif /* ALLOWLOGGING */
6753	case srm_OPT_ALTBUF_CURSOR:	/* optional alternate buffer and clear (xterm) */
6754	    /* FALLTHRU */
6755	case srm_OPT_ALTBUF:	/* optional alternate buffer and clear (xterm) */
6756	    DoSM(DP_X_ALTBUF, screen->whichBuf);
6757	    break;
6758	case srm_ALTBUF:	/* alternate buffer (xterm) also DECGRPM (Graphics Rotated Print Mode) */
6759	    if_PRINT_GRAPHICS2(DoSM(DP_DECGRPM, screen->graphics_rotated_print_mode)) {
6760		DoSM(DP_X_ALTBUF, screen->whichBuf);
6761	    }
6762	    break;
6763	case srm_DECNKM:
6764	    DoSM(DP_DECKPAM, xw->keyboard.flags & MODE_DECKPAM);
6765	    break;
6766	case srm_DECBKM:	/* backarrow mapping */
6767	    DoSM(DP_DECBKM, xw->keyboard.flags & MODE_DECBKM);
6768	    break;
6769	case srm_DECLRMM:	/* left-right */
6770	    DoSM(DP_X_LRMM, LEFT_RIGHT);
6771	    break;
6772#if OPT_SIXEL_GRAPHICS
6773	case srm_DECSDM:	/* sixel scrolling */
6774	    DoSM(DP_DECSDM, xw->keyboard.flags & MODE_DECSDM);
6775	    update_decsdm();
6776	    break;
6777#endif
6778	case srm_DECNCSM:	/* noclear */
6779	    DoSM(DP_X_NCSM, NOCLEAR_COLM);
6780	    break;
6781	case srm_VT200_MOUSE:	/* mouse bogus sequence         */
6782	    /* FALLTHRU */
6783	case srm_VT200_HIGHLIGHT_MOUSE:
6784	    /* FALLTHRU */
6785	case srm_BTN_EVENT_MOUSE:
6786	    /* FALLTHRU */
6787	case srm_ANY_EVENT_MOUSE:
6788	    DoSM(DP_X_MOUSE, screen->send_mouse_pos);
6789	    break;
6790#if OPT_FOCUS_EVENT
6791	case srm_FOCUS_EVENT_MOUSE:
6792	    DoSM(DP_X_FOCUS, screen->send_focus_pos);
6793	    break;
6794#endif
6795	case srm_EXT_MODE_MOUSE:
6796	    /* FALLTHRU */
6797	case srm_SGR_EXT_MODE_MOUSE:
6798	    /* FALLTHRU */
6799	case srm_URXVT_EXT_MODE_MOUSE:
6800	    /* FALLTHRU */
6801	case srm_PIXEL_POSITION_MOUSE:
6802	    DoSM(DP_X_EXT_MOUSE, screen->extend_coords);
6803	    break;
6804	case srm_ALTERNATE_SCROLL:
6805	    DoSM(DP_ALTERNATE_SCROLL, screen->alternateScroll);
6806	    break;
6807	case srm_RXVT_SCROLL_TTY_OUTPUT:
6808	    DoSM(DP_RXVT_SCROLL_TTY_OUTPUT, screen->scrollttyoutput);
6809	    break;
6810	case srm_RXVT_SCROLL_TTY_KEYPRESS:
6811	    DoSM(DP_RXVT_SCROLL_TTY_KEYPRESS, screen->scrollkey);
6812	    break;
6813	case srm_EIGHT_BIT_META:
6814	    DoSM(DP_EIGHT_BIT_META, screen->eight_bit_meta);
6815	    break;
6816#if OPT_NUM_LOCK
6817	case srm_REAL_NUMLOCK:
6818	    DoSM(DP_REAL_NUMLOCK, xw->misc.real_NumLock);
6819	    break;
6820	case srm_META_SENDS_ESC:
6821	    DoSM(DP_META_SENDS_ESC, screen->meta_sends_esc);
6822	    break;
6823#endif
6824	case srm_DELETE_IS_DEL:
6825	    DoSM(DP_DELETE_IS_DEL, screen->delete_is_del);
6826	    break;
6827#if OPT_NUM_LOCK
6828	case srm_ALT_SENDS_ESC:
6829	    DoSM(DP_ALT_SENDS_ESC, screen->alt_sends_esc);
6830	    break;
6831#endif
6832	case srm_KEEP_SELECTION:
6833	    DoSM(DP_KEEP_SELECTION, screen->keepSelection);
6834	    break;
6835	case srm_SELECT_TO_CLIPBOARD:
6836	    DoSM(DP_SELECT_TO_CLIPBOARD, screen->selectToClipboard);
6837	    break;
6838	case srm_BELL_IS_URGENT:
6839	    DoSM(DP_BELL_IS_URGENT, screen->bellIsUrgent);
6840	    break;
6841	case srm_POP_ON_BELL:
6842	    DoSM(DP_POP_ON_BELL, screen->poponbell);
6843	    break;
6844	case srm_KEEP_CLIPBOARD:
6845	    DoSM(DP_KEEP_CLIPBOARD, screen->keepClipboard);
6846	    break;
6847#if OPT_TCAP_FKEYS
6848	case srm_TCAP_FKEYS:
6849	    /* FALLTHRU */
6850#endif
6851#if OPT_SUN_FUNC_KEYS
6852	case srm_SUN_FKEYS:
6853	    /* FALLTHRU */
6854#endif
6855#if OPT_HP_FUNC_KEYS
6856	case srm_HP_FKEYS:
6857	    /* FALLTHRU */
6858#endif
6859#if OPT_SCO_FUNC_KEYS
6860	case srm_SCO_FKEYS:
6861	    /* FALLTHRU */
6862#endif
6863#if OPT_SUNPC_KBD
6864	case srm_VT220_FKEYS:
6865	    /* FALLTHRU */
6866#endif
6867	case srm_LEGACY_FKEYS:
6868	    DoSM(DP_KEYBOARD_TYPE, xw->keyboard.type);
6869	    break;
6870	case srm_ALLOW_ALTBUF:
6871	    DoSM(DP_ALLOW_ALTBUF, xw->misc.titeInhibit);
6872	    break;
6873	case srm_SAVE_CURSOR:
6874	    if (!xw->misc.titeInhibit) {
6875		CursorSave(xw);
6876	    }
6877	    break;
6878#if OPT_PASTE64 || OPT_READLINE
6879	case srm_PASTE_IN_BRACKET:
6880	    SCREEN_FLAG_save(screen, paste_brackets);
6881	    break;
6882#endif
6883#if OPT_READLINE
6884	case srm_BUTTON1_MOVE_POINT:
6885	    SCREEN_FLAG_save(screen, click1_moves);
6886	    break;
6887	case srm_BUTTON2_MOVE_POINT:
6888	    SCREEN_FLAG_save(screen, paste_moves);
6889	    break;
6890	case srm_DBUTTON3_DELETE:
6891	    SCREEN_FLAG_save(screen, dclick3_deletes);
6892	    break;
6893	case srm_PASTE_QUOTE:
6894	    SCREEN_FLAG_save(screen, paste_quotes);
6895	    break;
6896	case srm_PASTE_LITERAL_NL:
6897	    SCREEN_FLAG_save(screen, paste_literal_nl);
6898	    break;
6899#endif /* OPT_READLINE */
6900#if OPT_GRAPHICS
6901	case srm_PRIVATE_COLOR_REGISTERS:	/* private color registers for each graphic */
6902	    TRACE(("save PRIVATE_COLOR_REGISTERS %s\n",
6903		   BtoS(screen->privatecolorregisters)));
6904	    DoSM(DP_X_PRIVATE_COLOR_REGISTERS, screen->privatecolorregisters);
6905	    update_privatecolorregisters();
6906	    break;
6907#endif
6908#if OPT_SIXEL_GRAPHICS
6909	case srm_SIXEL_SCROLLS_RIGHT:
6910	    TRACE(("save SIXEL_SCROLLS_RIGHT %s\n",
6911		   BtoS(screen->sixel_scrolls_right)));
6912	    DoSM(DP_SIXEL_SCROLLS_RIGHT, screen->sixel_scrolls_right);
6913	    break;
6914#endif
6915	}
6916    }
6917}
6918
6919/*
6920 * process xterm private modes restore
6921 */
6922static void
6923restoremodes(XtermWidget xw)
6924{
6925    TScreen *screen = TScreenOf(xw);
6926    int i, j;
6927
6928    for (i = 0; i < nparam; i++) {
6929	int code = GetParam(i);
6930
6931	TRACE(("restoremodes %d\n", code));
6932	switch ((DECSET_codes) code) {
6933	case srm_DECCKM:
6934	    bitcpy(&xw->keyboard.flags,
6935		   screen->save_modes[DP_DECCKM], MODE_DECCKM);
6936	    update_appcursor();
6937	    break;
6938	case srm_DECANM:	/* ANSI/VT52 mode      */
6939	    /* no effect */
6940	    break;
6941	case srm_DECCOLM:
6942	    if (screen->c132) {
6943		if (!(xw->flags & NOCLEAR_COLM))
6944		    ClearScreen(xw);
6945		CursorSet(screen, 0, 0, xw->flags);
6946		if ((j = (screen->save_modes[DP_DECCOLM] & IN132COLUMNS)
6947		     ? 132 : 80) != ((xw->flags & IN132COLUMNS)
6948				     ? 132 : 80) || j != MaxCols(screen))
6949		    RequestResize(xw, -1, j, True);
6950		bitcpy(&xw->flags,
6951		       screen->save_modes[DP_DECCOLM],
6952		       IN132COLUMNS);
6953	    }
6954	    break;
6955	case srm_DECSCLM:	/* (slow scroll)        */
6956	    if (screen->save_modes[DP_DECSCLM] & SMOOTHSCROLL) {
6957		screen->jumpscroll = 0;
6958		if (screen->scroll_amt)
6959		    FlushScroll(xw);
6960	    } else
6961		screen->jumpscroll = 1;
6962	    bitcpy(&xw->flags, screen->save_modes[DP_DECSCLM], SMOOTHSCROLL);
6963	    update_jumpscroll();
6964	    break;
6965	case srm_DECSCNM:
6966	    if ((screen->save_modes[DP_DECSCNM] ^ xw->flags) & REVERSE_VIDEO) {
6967		bitcpy(&xw->flags, screen->save_modes[DP_DECSCNM], REVERSE_VIDEO);
6968		ReverseVideo(xw);
6969		/* update_reversevideo done in RevVid */
6970	    }
6971	    break;
6972	case srm_DECOM:
6973	    bitcpy(&xw->flags, screen->save_modes[DP_DECOM], ORIGIN);
6974	    CursorSet(screen, 0, 0, xw->flags);
6975	    break;
6976
6977	case srm_DECAWM:
6978	    bitcpy(&xw->flags, screen->save_modes[DP_DECAWM], WRAPAROUND);
6979	    update_autowrap();
6980	    break;
6981	case srm_DECARM:
6982	    /* ignore autorepeat */
6983	    break;
6984	case srm_X10_MOUSE:	/* MIT bogus sequence           */
6985	    DoRM0(DP_X_X10MSE, screen->send_mouse_pos);
6986	    really_set_mousemode(xw,
6987				 screen->send_mouse_pos != MOUSE_OFF,
6988				 (XtermMouseModes) screen->send_mouse_pos);
6989	    break;
6990#if OPT_TOOLBAR
6991	case srm_RXVT_TOOLBAR:
6992	    DoRM(DP_TOOLBAR, resource.toolBar);
6993	    ShowToolbar(resource.toolBar);
6994	    break;
6995#endif
6996#if OPT_BLINK_CURS
6997	case srm_ATT610_BLINK:	/* Start/stop blinking cursor */
6998	    if (SettableCursorBlink(screen)) {
6999		DoRM(DP_CRS_BLINK, screen->cursor_blink_esc);
7000		UpdateCursorBlink(xw);
7001	    }
7002	    break;
7003	case srm_CURSOR_BLINK_OPS:
7004	    /* intentionally ignored (this is user-preference) */
7005	    break;
7006	case srm_XOR_CURSOR_BLINKS:
7007	    /* intentionally ignored (this is user-preference) */
7008	    break;
7009#endif
7010	case srm_DECPFF:	/* print form feed */
7011	    DoRM(DP_PRN_FORMFEED, PrinterOf(screen).printer_formfeed);
7012	    break;
7013	case srm_DECPEX:	/* print extent */
7014	    DoRM(DP_PRN_EXTENT, PrinterOf(screen).printer_extent);
7015	    break;
7016	case srm_DECTCEM:	/* Show/hide cursor (VT200) */
7017	    DoRM(DP_CRS_VISIBLE, screen->cursor_set);
7018	    break;
7019	case srm_RXVT_SCROLLBAR:
7020	    if ((screen->fullVwin.sb_info.width != 0) !=
7021		screen->save_modes[DP_RXVT_SCROLLBAR]) {
7022		ToggleScrollBar(xw);
7023	    }
7024	    break;
7025#if OPT_SHIFT_FONTS
7026	case srm_RXVT_FONTSIZE:
7027	    DoRM(DP_RXVT_FONTSIZE, xw->misc.shift_fonts);
7028	    break;
7029#endif
7030#if OPT_TEK4014
7031	case srm_DECTEK:
7032	    if (!(screen->inhibit & I_TEK) &&
7033		(TEK4014_ACTIVE(xw) != (Boolean) screen->save_modes[DP_DECTEK])) {
7034		FlushLog(xw);
7035		TEK4014_ACTIVE(xw) = (Boolean) screen->save_modes[DP_DECTEK];
7036		update_vttekmode();
7037	    }
7038	    break;
7039#endif
7040	case srm_132COLS:	/* 132 column mode              */
7041	    DoRM(DP_X_DECCOLM, screen->c132);
7042	    update_allow132();
7043	    break;
7044	case srm_CURSES_HACK:	/* curses hack                  */
7045	    DoRM(DP_X_MORE, screen->curses);
7046	    update_cursesemul();
7047	    break;
7048	case srm_DECNRCM:	/* national charset (VT220) */
7049	    if (screen->vtXX_level >= 2) {
7050		if (bitcpy(&xw->flags, screen->save_modes[DP_DECNRCM], NATIONAL))
7051		    modified_DECNRCM(xw);
7052	    }
7053	    break;
7054#if OPT_PRINT_GRAPHICS
7055	case srm_DECGEPM:	/* Graphics Expanded Print Mode */
7056	    DoRM(DP_DECGEPM, screen->graphics_expanded_print_mode);
7057	    break;
7058#endif
7059	case srm_MARGIN_BELL:	/* margin bell (xterm) also DECGPCM (Graphics Print Color Mode) */
7060	    if_PRINT_GRAPHICS2(DoRM(DP_DECGPCM, screen->graphics_print_color_mode)) {
7061		if ((DoRM(DP_X_MARGIN, screen->marginbell)) == 0)
7062		    screen->bellArmed = -1;
7063		update_marginbell();
7064	    }
7065	    break;
7066	case srm_REVERSEWRAP:	/* reverse wraparound (xterm) also DECGPCS (Graphics Print Color Syntax) */
7067	    if_PRINT_GRAPHICS2(DoRM(DP_DECGPCS, screen->graphics_print_color_syntax)) {
7068		bitcpy(&xw->flags, screen->save_modes[DP_X_REVWRAP], REVERSEWRAP);
7069		update_reversewrap();
7070	    }
7071	    break;
7072#ifdef ALLOWLOGGING
7073	case srm_ALLOWLOGGING:	/* logging (xterm) also DECGPBM (Graphics Print Background Mode) */
7074	    if_PRINT_GRAPHICS2(DoRM(DP_DECGPBM, screen->graphics_print_background_mode)) {
7075#ifdef ALLOWLOGFILEONOFF
7076		if (screen->save_modes[DP_X_LOGGING])
7077		    StartLog(xw);
7078		else
7079		    CloseLog(xw);
7080#endif /* ALLOWLOGFILEONOFF */
7081		/* update_logging done by StartLog and CloseLog */
7082	    }
7083	    break;
7084#elif OPT_PRINT_GRAPHICS
7085	case srm_DECGPBM:	/* Graphics Print Background Mode */
7086	    DoRM(DP_DECGPBM, screen->graphics_print_background_mode);
7087	    break;
7088#endif /* ALLOWLOGGING */
7089	case srm_OPT_ALTBUF_CURSOR:	/* optional alternate buffer and clear (xterm) */
7090	    /* FALLTHRU */
7091	case srm_OPT_ALTBUF:	/* optional alternate buffer and clear (xterm) */
7092	    if (!xw->misc.titeInhibit) {
7093		if (screen->save_modes[DP_X_ALTBUF])
7094		    ToAlternate(xw, False);
7095		else
7096		    FromAlternate(xw);
7097		/* update_altscreen done by ToAlt and FromAlt */
7098	    } else if (screen->save_modes[DP_X_ALTBUF]) {
7099		do_ti_xtra_scroll(xw);
7100	    }
7101	    break;
7102	case srm_ALTBUF:	/* alternate buffer (xterm) also DECGRPM (Graphics Rotated Print Mode) */
7103	    if_PRINT_GRAPHICS2(DoRM(DP_DECGRPM, screen->graphics_rotated_print_mode)) {
7104		if (!xw->misc.titeInhibit) {
7105		    if (screen->save_modes[DP_X_ALTBUF])
7106			ToAlternate(xw, False);
7107		    else
7108			FromAlternate(xw);
7109		    /* update_altscreen done by ToAlt and FromAlt */
7110		} else if (screen->save_modes[DP_X_ALTBUF]) {
7111		    do_ti_xtra_scroll(xw);
7112		}
7113	    }
7114	    break;
7115	case srm_DECNKM:
7116	    bitcpy(&xw->flags, screen->save_modes[DP_DECKPAM], MODE_DECKPAM);
7117	    update_appkeypad();
7118	    break;
7119	case srm_DECBKM:	/* backarrow mapping */
7120	    bitcpy(&xw->flags, screen->save_modes[DP_DECBKM], MODE_DECBKM);
7121	    update_decbkm();
7122	    break;
7123	case srm_DECLRMM:	/* left-right */
7124	    bitcpy(&xw->flags, screen->save_modes[DP_X_LRMM], LEFT_RIGHT);
7125	    if (IsLeftRightMode(xw)) {
7126		xterm_ResetDouble(xw);
7127	    } else {
7128		reset_lr_margins(screen);
7129	    }
7130	    break;
7131#if OPT_SIXEL_GRAPHICS
7132	case srm_DECSDM:	/* sixel scrolling */
7133	    bitcpy(&xw->keyboard.flags, screen->save_modes[DP_DECSDM], MODE_DECSDM);
7134	    update_decsdm();
7135	    break;
7136#endif
7137	case srm_DECNCSM:	/* noclear */
7138	    bitcpy(&xw->flags, screen->save_modes[DP_X_NCSM], NOCLEAR_COLM);
7139	    break;
7140	case srm_VT200_MOUSE:	/* mouse bogus sequence         */
7141	    /* FALLTHRU */
7142	case srm_VT200_HIGHLIGHT_MOUSE:
7143	    /* FALLTHRU */
7144	case srm_BTN_EVENT_MOUSE:
7145	    /* FALLTHRU */
7146	case srm_ANY_EVENT_MOUSE:
7147	    DoRM0(DP_X_MOUSE, screen->send_mouse_pos);
7148	    really_set_mousemode(xw,
7149				 screen->send_mouse_pos != MOUSE_OFF,
7150				 (XtermMouseModes) screen->send_mouse_pos);
7151	    break;
7152#if OPT_FOCUS_EVENT
7153	case srm_FOCUS_EVENT_MOUSE:
7154	    DoRM(DP_X_FOCUS, screen->send_focus_pos);
7155	    break;
7156#endif
7157	case srm_EXT_MODE_MOUSE:
7158	    /* FALLTHRU */
7159	case srm_SGR_EXT_MODE_MOUSE:
7160	    /* FALLTHRU */
7161	case srm_URXVT_EXT_MODE_MOUSE:
7162	    /* FALLTHRU */
7163	case srm_PIXEL_POSITION_MOUSE:
7164	    DoRM(DP_X_EXT_MOUSE, screen->extend_coords);
7165	    break;
7166	case srm_ALLOW_ALTBUF:
7167	    DoRM(DP_ALLOW_ALTBUF, xw->misc.titeInhibit);
7168	    if (xw->misc.titeInhibit)
7169		FromAlternate(xw);
7170	    update_titeInhibit();
7171	    break;
7172	case srm_SAVE_CURSOR:
7173	    if (!xw->misc.titeInhibit) {
7174		CursorRestore(xw);
7175	    }
7176	    break;
7177	case srm_ALTERNATE_SCROLL:
7178	    DoRM(DP_ALTERNATE_SCROLL, screen->alternateScroll);
7179	    break;
7180	case srm_RXVT_SCROLL_TTY_OUTPUT:
7181	    DoRM(DP_RXVT_SCROLL_TTY_OUTPUT, screen->scrollttyoutput);
7182	    update_scrollttyoutput();
7183	    break;
7184	case srm_RXVT_SCROLL_TTY_KEYPRESS:
7185	    DoRM(DP_RXVT_SCROLL_TTY_KEYPRESS, screen->scrollkey);
7186	    update_scrollkey();
7187	    break;
7188	case srm_EIGHT_BIT_META:
7189	    DoRM(DP_EIGHT_BIT_META, screen->eight_bit_meta);
7190	    break;
7191#if OPT_NUM_LOCK
7192	case srm_REAL_NUMLOCK:
7193	    DoRM(DP_REAL_NUMLOCK, xw->misc.real_NumLock);
7194	    update_num_lock();
7195	    break;
7196	case srm_META_SENDS_ESC:
7197	    DoRM(DP_META_SENDS_ESC, screen->meta_sends_esc);
7198	    update_meta_esc();
7199	    break;
7200#endif
7201	case srm_DELETE_IS_DEL:
7202	    DoRM(DP_DELETE_IS_DEL, screen->delete_is_del);
7203	    update_delete_del();
7204	    break;
7205#if OPT_NUM_LOCK
7206	case srm_ALT_SENDS_ESC:
7207	    DoRM(DP_ALT_SENDS_ESC, screen->alt_sends_esc);
7208	    update_alt_esc();
7209	    break;
7210#endif
7211	case srm_KEEP_SELECTION:
7212	    DoRM(DP_KEEP_SELECTION, screen->keepSelection);
7213	    update_keepSelection();
7214	    break;
7215	case srm_SELECT_TO_CLIPBOARD:
7216	    DoRM(DP_SELECT_TO_CLIPBOARD, screen->selectToClipboard);
7217	    update_selectToClipboard();
7218	    break;
7219	case srm_BELL_IS_URGENT:
7220	    DoRM(DP_BELL_IS_URGENT, screen->bellIsUrgent);
7221	    update_bellIsUrgent();
7222	    break;
7223	case srm_POP_ON_BELL:
7224	    DoRM(DP_POP_ON_BELL, screen->poponbell);
7225	    update_poponbell();
7226	    break;
7227	case srm_KEEP_CLIPBOARD:
7228	    DoRM(DP_KEEP_CLIPBOARD, screen->keepClipboard);
7229	    update_keepClipboard();
7230	    break;
7231#if OPT_TCAP_FKEYS
7232	case srm_TCAP_FKEYS:
7233	    /* FALLTHRU */
7234#endif
7235#if OPT_SUN_FUNC_KEYS
7236	case srm_SUN_FKEYS:
7237	    /* FALLTHRU */
7238#endif
7239#if OPT_HP_FUNC_KEYS
7240	case srm_HP_FKEYS:
7241	    /* FALLTHRU */
7242#endif
7243#if OPT_SCO_FUNC_KEYS
7244	case srm_SCO_FKEYS:
7245	    /* FALLTHRU */
7246#endif
7247#if OPT_SUNPC_KBD
7248	case srm_VT220_FKEYS:
7249	    /* FALLTHRU */
7250#endif
7251	case srm_LEGACY_FKEYS:
7252	    xw->keyboard.type = (xtermKeyboardType) screen->save_modes[DP_KEYBOARD_TYPE];
7253	    break;
7254#if OPT_PASTE64 || OPT_READLINE
7255	case srm_PASTE_IN_BRACKET:
7256	    SCREEN_FLAG_restore(screen, paste_brackets);
7257	    break;
7258#endif
7259#if OPT_READLINE
7260	case srm_BUTTON1_MOVE_POINT:
7261	    SCREEN_FLAG_restore(screen, click1_moves);
7262	    break;
7263	case srm_BUTTON2_MOVE_POINT:
7264	    SCREEN_FLAG_restore(screen, paste_moves);
7265	    break;
7266	case srm_DBUTTON3_DELETE:
7267	    SCREEN_FLAG_restore(screen, dclick3_deletes);
7268	    break;
7269	case srm_PASTE_QUOTE:
7270	    SCREEN_FLAG_restore(screen, paste_quotes);
7271	    break;
7272	case srm_PASTE_LITERAL_NL:
7273	    SCREEN_FLAG_restore(screen, paste_literal_nl);
7274	    break;
7275#endif /* OPT_READLINE */
7276#if OPT_GRAPHICS
7277	case srm_PRIVATE_COLOR_REGISTERS:	/* private color registers for each graphic */
7278	    TRACE(("restore PRIVATE_COLOR_REGISTERS before: %s\n",
7279		   BtoS(screen->privatecolorregisters)));
7280	    DoRM(DP_X_PRIVATE_COLOR_REGISTERS, screen->privatecolorregisters);
7281	    TRACE(("restore PRIVATE_COLOR_REGISTERS after: %s\n",
7282		   BtoS(screen->privatecolorregisters)));
7283	    update_privatecolorregisters();
7284	    break;
7285#endif
7286#if OPT_SIXEL_GRAPHICS
7287	case srm_SIXEL_SCROLLS_RIGHT:
7288	    TRACE(("restore SIXEL_SCROLLS_RIGHT before: %s\n",
7289		   BtoS(screen->sixel_scrolls_right)));
7290	    DoRM(DP_SIXEL_SCROLLS_RIGHT, screen->sixel_scrolls_right);
7291	    TRACE(("restore SIXEL_SCROLLS_RIGHT after: %s\n",
7292		   BtoS(screen->sixel_scrolls_right)));
7293	    break;
7294#endif
7295	}
7296    }
7297}
7298
7299/*
7300 * Convert an XTextProperty to a string.
7301 *
7302 * This frees the data owned by the XTextProperty, and returns in its place the
7303 * string, which must be freed by the caller.
7304 */
7305static char *
7306property_to_string(XtermWidget xw, XTextProperty * text)
7307{
7308    TScreen *screen = TScreenOf(xw);
7309    Display *dpy = screen->display;
7310    char *result = 0;
7311    char **list = NULL;
7312    int length = 0;
7313    int rc;
7314
7315    TRACE(("property_to_string value %p, encoding %s, format %d, nitems %ld\n",
7316	   text->value,
7317	   TraceAtomName(dpy, text->encoding),
7318	   text->format,
7319	   text->nitems));
7320
7321#if OPT_WIDE_CHARS
7322    /*
7323     * We will use the XmbTextPropertyToTextList call to extract UTF-8 data.
7324     * The xtermUtf8ToTextList() call is used to convert UTF-8 explicitly to
7325     * ISO-8859-1.
7326     */
7327    rc = -1;
7328    if ((text->format != 8)
7329	|| IsTitleMode(xw, tmGetUtf8)
7330	|| (text->encoding == XA_UTF8_STRING(dpy) &&
7331	    !(screen->wide_chars || screen->c1_printable) &&
7332	    (rc = xtermUtf8ToTextList(xw, text, &list, &length)) < 0)
7333	|| (rc < 0))
7334#endif
7335	if ((rc = XmbTextPropertyToTextList(dpy, text, &list, &length)) < 0)
7336	    rc = XTextPropertyToStringList(text, &list, &length);
7337
7338    if (rc >= 0) {
7339	int n, c, pass;
7340	size_t need;
7341
7342	for (pass = 0; pass < 2; ++pass) {
7343	    for (n = 0, need = 0; n < length; n++) {
7344		char *s = list[n];
7345		while ((c = *s++) != '\0') {
7346		    if (pass)
7347			result[need] = (char) c;
7348		    ++need;
7349		}
7350	    }
7351	    if (pass)
7352		result[need] = '\0';
7353	    else
7354		result = malloc(need + 1);
7355	    if (result == 0)
7356		break;
7357	}
7358	XFreeStringList(list);
7359    }
7360    if (text->value != 0)
7361	XFree(text->value);
7362
7363    return result;
7364}
7365
7366static char *
7367get_icon_label(XtermWidget xw)
7368{
7369    XTextProperty text;
7370    char *result = 0;
7371
7372    if (XGetWMIconName(TScreenOf(xw)->display, VShellWindow(xw), &text)) {
7373	result = property_to_string(xw, &text);
7374    }
7375    return result;
7376}
7377
7378static char *
7379get_window_label(XtermWidget xw)
7380{
7381    XTextProperty text;
7382    char *result = 0;
7383
7384    if (XGetWMName(TScreenOf(xw)->display, VShellWindow(xw), &text)) {
7385	result = property_to_string(xw, &text);
7386    }
7387    return result;
7388}
7389
7390/*
7391 * Report window label (icon or title) in dtterm protocol
7392 * ESC ] code label ESC backslash
7393 */
7394static void
7395report_win_label(XtermWidget xw,
7396		 int code,
7397		 char *text)
7398{
7399    unparseputc(xw, ANSI_ESC);
7400    unparseputc(xw, ']');
7401    unparseputc(xw, code);
7402
7403    if (text != 0) {
7404	int copy = IsTitleMode(xw, tmGetBase16);
7405	if (copy) {
7406	    TRACE(("Encoding hex:%s\n", text));
7407	    text = x_encode_hex(text);
7408	}
7409	unparseputs(xw, text);
7410	if (copy)
7411	    free(text);
7412    }
7413
7414    unparseputc(xw, ANSI_ESC);
7415    unparseputc(xw, '\\');	/* should be ST */
7416    unparse_end(xw);
7417}
7418
7419/*
7420 * Window operations (from CDE dtterm description, as well as extensions).
7421 * See also "allowWindowOps" resource.
7422 */
7423static void
7424window_ops(XtermWidget xw)
7425{
7426    TScreen *screen = TScreenOf(xw);
7427    XWindowChanges values;
7428    XWindowAttributes win_attrs;
7429#if OPT_MAXIMIZE
7430    unsigned root_width;
7431    unsigned root_height;
7432#endif
7433    int code = zero_if_default(0);
7434    char *label;
7435
7436    TRACE(("window_ops %d\n", code));
7437    switch (code) {
7438    case ewRestoreWin:		/* Restore (de-iconify) window */
7439	if (AllowWindowOps(xw, ewRestoreWin)) {
7440	    xtermDeiconify(xw);
7441	}
7442	break;
7443
7444    case ewMinimizeWin:	/* Minimize (iconify) window */
7445	if (AllowWindowOps(xw, ewMinimizeWin)) {
7446	    xtermIconify(xw);
7447	}
7448	break;
7449
7450    case ewSetWinPosition:	/* Move the window to the given position */
7451	if (AllowWindowOps(xw, ewSetWinPosition)) {
7452	    unsigned value_mask;
7453
7454	    values.x = (Position) zero_if_default(1);
7455	    values.y = (Position) zero_if_default(2);
7456	    TRACE(("...move window to %d,%d\n", values.x, values.y));
7457	    value_mask = (CWX | CWY);
7458	    XReconfigureWMWindow(screen->display,
7459				 VShellWindow(xw),
7460				 DefaultScreen(screen->display),
7461				 value_mask,
7462				 &values);
7463	}
7464	break;
7465
7466    case ewSetWinSizePixels:	/* Resize the window to given size in pixels */
7467	if (AllowWindowOps(xw, ewSetWinSizePixels)) {
7468	    RequestResize(xw, optional_param(1), optional_param(2), False);
7469	}
7470	break;
7471
7472    case ewRaiseWin:		/* Raise the window to the front of the stack */
7473	if (AllowWindowOps(xw, ewRaiseWin)) {
7474	    TRACE(("...raise window\n"));
7475	    XRaiseWindow(screen->display, VShellWindow(xw));
7476	}
7477	break;
7478
7479    case ewLowerWin:		/* Lower the window to the bottom of the stack */
7480	if (AllowWindowOps(xw, ewLowerWin)) {
7481	    TRACE(("...lower window\n"));
7482	    XLowerWindow(screen->display, VShellWindow(xw));
7483	}
7484	break;
7485
7486    case ewRefreshWin:		/* Refresh the window */
7487	if (AllowWindowOps(xw, ewRefreshWin)) {
7488	    TRACE(("...redraw window\n"));
7489	    Redraw();
7490	}
7491	break;
7492
7493    case ewSetWinSizeChars:	/* Resize the text-area, in characters */
7494	if (AllowWindowOps(xw, ewSetWinSizeChars)) {
7495	    RequestResize(xw, optional_param(1), optional_param(2), True);
7496	}
7497	break;
7498
7499#if OPT_MAXIMIZE
7500    case ewMaximizeWin:	/* Maximize or restore */
7501	if (AllowWindowOps(xw, ewMaximizeWin)) {
7502	    RequestMaximize(xw, zero_if_default(1));
7503	}
7504	break;
7505    case ewFullscreenWin:	/* Fullscreen or restore */
7506	if (AllowWindowOps(xw, ewFullscreenWin)) {
7507	    switch (zero_if_default(1)) {
7508	    default:
7509		RequestMaximize(xw, 0);
7510		break;
7511	    case 1:
7512		RequestMaximize(xw, 1);
7513		break;
7514	    case 2:
7515		RequestMaximize(xw, !(screen->restore_data));
7516		break;
7517	    }
7518	}
7519	break;
7520#endif
7521
7522    case ewGetWinState:	/* Report the window's state */
7523	if (AllowWindowOps(xw, ewGetWinState)) {
7524	    TRACE(("...get window attributes\n"));
7525	    init_reply(ANSI_CSI);
7526	    reply.a_pintro = 0;
7527	    reply.a_nparam = 1;
7528	    reply.a_param[0] = (ParmType) (xtermIsIconified(xw) ? 2 : 1);
7529	    reply.a_inters = 0;
7530	    reply.a_final = 't';
7531	    unparseseq(xw, &reply);
7532	}
7533	break;
7534
7535    case ewGetWinPosition:	/* Report the window's position */
7536	if (AllowWindowOps(xw, ewGetWinPosition)) {
7537	    Window win;
7538	    Window result_win;
7539	    int result_y, result_x;
7540
7541	    TRACE(("...get window position\n"));
7542	    init_reply(ANSI_CSI);
7543	    reply.a_pintro = 0;
7544	    reply.a_nparam = 3;
7545	    reply.a_param[0] = 3;
7546	    switch (zero_if_default(1)) {
7547	    case 2:		/* report the text-window's position */
7548		result_y = 0;
7549		result_x = 0;
7550		{
7551		    Widget mw;
7552		    for (mw = (Widget) xw; mw != 0; mw = XtParent(mw)) {
7553			result_x += mw->core.x;
7554			result_y += mw->core.y;
7555			if (mw == SHELL_OF(xw))
7556			    break;
7557		    }
7558		}
7559		result_x += OriginX(screen);
7560		result_y += OriginY(screen);
7561		break;
7562	    default:
7563		win = WMFrameWindow(xw);
7564		xtermGetWinAttrs(screen->display,
7565				 win,
7566				 &win_attrs);
7567		XTranslateCoordinates(screen->display,
7568				      VShellWindow(xw),
7569				      win_attrs.root,
7570				      -win_attrs.border_width,
7571				      -win_attrs.border_width,
7572				      &result_x, &result_y, &result_win);
7573		TRACE(("translated position %d,%d vs %d,%d\n",
7574		       result_y, result_x,
7575		       win_attrs.y, win_attrs.x));
7576		if (!discount_frame_extents(xw, &result_y, &result_x)) {
7577		    TRACE(("...cancelled translation\n"));
7578		    result_y = win_attrs.y;
7579		    result_x = win_attrs.x;
7580		}
7581		break;
7582	    }
7583	    reply.a_param[1] = (ParmType) result_x;
7584	    reply.a_param[2] = (ParmType) result_y;
7585	    reply.a_inters = 0;
7586	    reply.a_final = 't';
7587	    unparseseq(xw, &reply);
7588	}
7589	break;
7590
7591    case ewGetWinSizePixels:	/* Report the window's size in pixels */
7592	if (AllowWindowOps(xw, ewGetWinSizePixels)) {
7593	    ParmType high = (ParmType) Height(screen);
7594	    ParmType wide = (ParmType) Width(screen);
7595
7596	    TRACE(("...get window size in pixels\n"));
7597	    init_reply(ANSI_CSI);
7598	    reply.a_pintro = 0;
7599	    reply.a_nparam = 3;
7600	    reply.a_param[0] = 4;
7601	    switch (zero_if_default(1)) {
7602	    case 2:		/* report the shell-window's size */
7603		xtermGetWinAttrs(screen->display,
7604				 WMFrameWindow(xw),
7605				 &win_attrs);
7606		high = (ParmType) win_attrs.height;
7607		wide = (ParmType) win_attrs.width;
7608		/* FALLTHRU */
7609	    default:
7610		reply.a_param[1] = high;
7611		reply.a_param[2] = wide;
7612		break;
7613	    }
7614	    reply.a_inters = 0;
7615	    reply.a_final = 't';
7616	    unparseseq(xw, &reply);
7617	}
7618	break;
7619
7620#if OPT_MAXIMIZE
7621    case ewGetScreenSizePixels:	/* Report the screen's size, in Pixels */
7622	if (AllowWindowOps(xw, ewGetScreenSizePixels)) {
7623	    TRACE(("...get screen size in pixels\n"));
7624	    (void) QueryMaximize(xw, &root_width, &root_height);
7625	    init_reply(ANSI_CSI);
7626	    reply.a_pintro = 0;
7627	    reply.a_nparam = 3;
7628	    reply.a_param[0] = 5;
7629	    reply.a_param[1] = (ParmType) root_height;
7630	    reply.a_param[2] = (ParmType) root_width;
7631	    reply.a_inters = 0;
7632	    reply.a_final = 't';
7633	    unparseseq(xw, &reply);
7634	}
7635	break;
7636    case ewGetCharSizePixels:	/* Report the font's size, in pixel */
7637	if (AllowWindowOps(xw, ewGetScreenSizeChars)) {
7638	    TRACE(("...get font size in pixels\n"));
7639	    TRACE(("...using font size %dx%d\n",
7640		   FontHeight(screen),
7641		   FontWidth(screen)));
7642	    init_reply(ANSI_CSI);
7643	    reply.a_pintro = 0;
7644	    reply.a_nparam = 3;
7645	    reply.a_param[0] = 6;
7646	    reply.a_param[1] = (ParmType) FontHeight(screen);
7647	    reply.a_param[2] = (ParmType) FontWidth(screen);
7648	    reply.a_inters = 0;
7649	    reply.a_final = 't';
7650	    unparseseq(xw, &reply);
7651	}
7652	break;
7653#endif
7654
7655    case ewGetWinSizeChars:	/* Report the text's size in characters */
7656	if (AllowWindowOps(xw, ewGetWinSizeChars)) {
7657	    TRACE(("...get window size in characters\n"));
7658	    init_reply(ANSI_CSI);
7659	    reply.a_pintro = 0;
7660	    reply.a_nparam = 3;
7661	    reply.a_param[0] = 8;
7662	    reply.a_param[1] = (ParmType) MaxRows(screen);
7663	    reply.a_param[2] = (ParmType) MaxCols(screen);
7664	    reply.a_inters = 0;
7665	    reply.a_final = 't';
7666	    unparseseq(xw, &reply);
7667	}
7668	break;
7669
7670#if OPT_MAXIMIZE
7671    case ewGetScreenSizeChars:	/* Report the screen's size, in characters */
7672	if (AllowWindowOps(xw, ewGetScreenSizeChars)) {
7673	    TRACE(("...get screen size in characters\n"));
7674	    TRACE(("...using font size %dx%d\n",
7675		   FontHeight(screen),
7676		   FontWidth(screen)));
7677	    (void) QueryMaximize(xw, &root_width, &root_height);
7678	    init_reply(ANSI_CSI);
7679	    reply.a_pintro = 0;
7680	    reply.a_nparam = 3;
7681	    reply.a_param[0] = 9;
7682	    reply.a_param[1] = (ParmType) (root_height
7683					   / (unsigned) FontHeight(screen));
7684	    reply.a_param[2] = (ParmType) (root_width
7685					   / (unsigned) FontWidth(screen));
7686	    reply.a_inters = 0;
7687	    reply.a_final = 't';
7688	    unparseseq(xw, &reply);
7689	}
7690	break;
7691#endif
7692
7693    case ewGetIconTitle:	/* Report the icon's label */
7694	if (AllowWindowOps(xw, ewGetIconTitle)) {
7695	    TRACE(("...get icon's label\n"));
7696	    report_win_label(xw, 'L', label = get_icon_label(xw));
7697	    free(label);
7698	}
7699	break;
7700
7701    case ewGetWinTitle:	/* Report the window's title */
7702	if (AllowWindowOps(xw, ewGetWinTitle)) {
7703	    TRACE(("...get window's label\n"));
7704	    report_win_label(xw, 'l', label = get_window_label(xw));
7705	    free(label);
7706	}
7707	break;
7708
7709    case ewPushTitle:		/* save the window's title(s) on stack */
7710	if (AllowWindowOps(xw, ewPushTitle)) {
7711	    SaveTitle *last = screen->save_title;
7712	    SaveTitle *item = TypeCalloc(SaveTitle);
7713
7714	    TRACE(("...push title onto stack\n"));
7715	    if (item != 0) {
7716		switch (zero_if_default(1)) {
7717		case 0:
7718		    item->iconName = get_icon_label(xw);
7719		    item->windowName = get_window_label(xw);
7720		    break;
7721		case 1:
7722		    item->iconName = get_icon_label(xw);
7723		    break;
7724		case 2:
7725		    item->windowName = get_window_label(xw);
7726		    break;
7727		}
7728		item->next = last;
7729		if (item->iconName == 0) {
7730		    item->iconName = ((last == 0)
7731				      ? get_icon_label(xw)
7732				      : x_strdup(last->iconName));
7733		}
7734		if (item->windowName == 0) {
7735		    item->windowName = ((last == 0)
7736					? get_window_label(xw)
7737					: x_strdup(last->windowName));
7738		}
7739		screen->save_title = item;
7740	    }
7741	}
7742	break;
7743
7744    case ewPopTitle:		/* restore the window's title(s) from stack */
7745	if (AllowWindowOps(xw, ewPopTitle)) {
7746	    SaveTitle *item = screen->save_title;
7747
7748	    TRACE(("...pop title off stack\n"));
7749	    if (item != 0) {
7750		switch (zero_if_default(1)) {
7751		case 0:
7752		    ChangeIconName(xw, item->iconName);
7753		    ChangeTitle(xw, item->windowName);
7754		    break;
7755		case 1:
7756		    ChangeIconName(xw, item->iconName);
7757		    break;
7758		case 2:
7759		    ChangeTitle(xw, item->windowName);
7760		    break;
7761		}
7762		screen->save_title = item->next;
7763		free(item->iconName);
7764		free(item->windowName);
7765		free(item);
7766	    }
7767	}
7768	break;
7769
7770    default:			/* DECSLPP (24, 25, 36, 48, 72, 144) */
7771	if (AllowWindowOps(xw, ewSetWinLines)) {
7772	    if (code >= 24)
7773		RequestResize(xw, code, -1, True);
7774	}
7775	break;
7776    }
7777}
7778
7779/*
7780 * set a bit in a word given a pointer to the word and a mask.
7781 */
7782static int
7783bitset(unsigned *p, unsigned mask)
7784{
7785    unsigned before = *p;
7786    *p |= mask;
7787    return (before != *p);
7788}
7789
7790/*
7791 * clear a bit in a word given a pointer to the word and a mask.
7792 */
7793static int
7794bitclr(unsigned *p, unsigned mask)
7795{
7796    unsigned before = *p;
7797    *p &= ~mask;
7798    return (before != *p);
7799}
7800
7801/*
7802 * Copy bits from one word to another, given a mask
7803 */
7804static int
7805bitcpy(unsigned *p, unsigned q, unsigned mask)
7806{
7807    unsigned before = *p;
7808    bitclr(p, mask);
7809    bitset(p, q & mask);
7810    return (before != *p);
7811}
7812
7813void
7814unparseputc1(XtermWidget xw, int c)
7815{
7816    if (c >= 0x80 && c <= 0x9F) {
7817	if (!TScreenOf(xw)->control_eight_bits) {
7818	    unparseputc(xw, A2E(ANSI_ESC));
7819	    c = A2E(c - 0x40);
7820	}
7821    }
7822    unparseputc(xw, c);
7823}
7824
7825void
7826unparseseq(XtermWidget xw, ANSI *ap)
7827{
7828    int c;
7829
7830    assert(ap->a_nparam < NPARAM);
7831    unparseputc1(xw, c = ap->a_type);
7832    if (c == ANSI_ESC
7833	|| c == ANSI_DCS
7834	|| c == ANSI_CSI
7835	|| c == ANSI_OSC
7836	|| c == ANSI_PM
7837	|| c == ANSI_APC
7838	|| c == ANSI_SS3) {
7839	int i;
7840	int inters;
7841	char temp[8];
7842
7843	if (ap->a_pintro != 0)
7844	    unparseputc(xw, ap->a_pintro);
7845	for (i = 0; i < ap->a_nparam; ++i) {
7846	    if (i != 0) {
7847		if (ap->a_radix[i] == 1 || ap->a_radix[i - 1] == 1) {
7848		    ;
7849		} else if (ap->a_delim) {
7850		    unparseputs(xw, ap->a_delim);
7851		} else {
7852		    unparseputc(xw, ';');
7853		}
7854	    }
7855	    switch (ap->a_radix[i]) {
7856	    case 16:
7857		sprintf(temp, "%04X", ap->a_param[i] & 0xffff);
7858		unparseputs(xw, temp);
7859		break;
7860	    case 1:
7861		unparseputc(xw, ap->a_param[i]);
7862		break;
7863	    default:
7864		unparseputn(xw, (unsigned) (UParm) ap->a_param[i]);
7865		break;
7866	    }
7867	}
7868	if ((inters = ap->a_inters) != 0) {
7869	    for (i = 3; i >= 0; --i) {
7870		c = CharOf(inters >> (8 * i));
7871		if (c != 0)
7872		    unparseputc(xw, c);
7873	    }
7874	}
7875	switch (ap->a_type) {
7876	case ANSI_DCS:
7877	    /* FALLTHRU */
7878	case ANSI_OSC:
7879	    /* FALLTHRU */
7880	case ANSI_PM:
7881	    /* FALLTHRU */
7882	case ANSI_APC:
7883	    unparseputc1(xw, ANSI_ST);
7884	    break;
7885	default:
7886	    unparseputc(xw, (char) ap->a_final);
7887	    break;
7888	}
7889    }
7890    unparse_end(xw);
7891}
7892
7893void
7894unparseputn(XtermWidget xw, unsigned n)
7895{
7896    unsigned q;
7897
7898    q = n / 10;
7899    if (q != 0)
7900	unparseputn(xw, q);
7901    unparseputc(xw, (char) ('0' + (n % 10)));
7902}
7903
7904void
7905unparseputs(XtermWidget xw, const char *s)
7906{
7907    if (s != 0) {
7908	while (*s)
7909	    unparseputc(xw, *s++);
7910    }
7911}
7912
7913void
7914unparseputc(XtermWidget xw, int c)
7915{
7916    TScreen *screen = TScreenOf(xw);
7917    IChar *buf = screen->unparse_bfr;
7918    unsigned len;
7919
7920    if ((screen->unparse_len + 2) >= screen->unparse_max)
7921	unparse_end(xw);
7922
7923    len = screen->unparse_len;
7924
7925#if OPT_TCAP_QUERY
7926    /*
7927     * If we're returning a termcap string, it has to be translated since
7928     * a DCS must not contain any characters except for the normal 7-bit
7929     * printable ASCII (counting tab, carriage return, etc).  For now,
7930     * just use hexadecimal for the whole thing.
7931     */
7932    if (screen->tc_query_code >= 0) {
7933	char tmp[3];
7934	sprintf(tmp, "%02X", c & 0xFF);
7935	buf[len++] = CharOf(tmp[0]);
7936	buf[len++] = CharOf(tmp[1]);
7937    } else
7938#endif
7939    if ((buf[len++] = (IChar) c) == '\r' && (xw->flags & LINEFEED)) {
7940	buf[len++] = '\n';
7941    }
7942
7943    screen->unparse_len = len;
7944
7945    /* If send/receive mode is reset, we echo characters locally */
7946    if ((xw->keyboard.flags & MODE_SRM) == 0) {
7947	doparsing(xw, (unsigned) c, &myState);
7948    }
7949}
7950
7951void
7952unparse_end(XtermWidget xw)
7953{
7954    TScreen *screen = TScreenOf(xw);
7955
7956#if OPT_TCAP_QUERY
7957    /*
7958     * tcap-query works by simulating key-presses, which ordinarily would be
7959     * flushed out at the end of each key.  For better efficiency, do not do
7960     * the flush unless we are about to fill the buffer used to capture the
7961     * response.
7962     */
7963    if ((screen->tc_query_code >= 0)
7964	&& (screen->unparse_len + 2 < screen->unparse_max)) {
7965	return;
7966    }
7967#endif
7968    if (screen->unparse_len) {
7969	TRACE(("unparse_end %u:%s\n",
7970	       screen->unparse_len,
7971	       visibleIChars(screen->unparse_bfr, screen->unparse_len)));
7972#ifdef VMS
7973	tt_write(screen->unparse_bfr, screen->unparse_len);
7974#else /* VMS */
7975	writePtyData(screen->respond, screen->unparse_bfr, screen->unparse_len);
7976#endif /* VMS */
7977	screen->unparse_len = 0;
7978    }
7979}
7980
7981void
7982ToggleAlternate(XtermWidget xw)
7983{
7984    if (TScreenOf(xw)->whichBuf)
7985	FromAlternate(xw);
7986    else
7987	ToAlternate(xw, False);
7988}
7989
7990static void
7991ToAlternate(XtermWidget xw, Bool clearFirst)
7992{
7993    TScreen *screen = TScreenOf(xw);
7994
7995    if (screen->whichBuf == 0) {
7996	TRACE(("ToAlternate\n"));
7997	if (!screen->editBuf_index[1])
7998	    screen->editBuf_index[1] = allocScrnBuf(xw,
7999						    (unsigned) MaxRows(screen),
8000						    (unsigned) MaxCols(screen),
8001						    &screen->editBuf_data[1]);
8002	SwitchBufs(xw, 1, clearFirst);
8003#if OPT_SAVE_LINES
8004	screen->visbuf = screen->editBuf_index[screen->whichBuf];
8005#endif
8006	update_altscreen();
8007    }
8008}
8009
8010static void
8011FromAlternate(XtermWidget xw)
8012{
8013    TScreen *screen = TScreenOf(xw);
8014
8015    if (screen->whichBuf != 0) {
8016	TRACE(("FromAlternate\n"));
8017	if (screen->scroll_amt)
8018	    FlushScroll(xw);
8019	SwitchBufs(xw, 0, False);
8020#if OPT_SAVE_LINES
8021	screen->visbuf = screen->editBuf_index[screen->whichBuf];
8022#endif
8023	update_altscreen();
8024    }
8025}
8026
8027static void
8028SwitchBufs(XtermWidget xw, int toBuf, Bool clearFirst)
8029{
8030    TScreen *screen = TScreenOf(xw);
8031    int rows, top;
8032
8033    screen->whichBuf = toBuf;
8034    if (screen->cursor_state)
8035	HideCursor(xw);
8036
8037    rows = MaxRows(screen);
8038    SwitchBufPtrs(screen, toBuf);
8039
8040    if ((top = INX2ROW(screen, 0)) < rows) {
8041	if (screen->scroll_amt) {
8042	    FlushScroll(xw);
8043	}
8044	xtermClear2(xw,
8045		    (int) OriginX(screen),
8046		    (int) top * FontHeight(screen) + screen->border,
8047		    (unsigned) Width(screen),
8048		    (unsigned) ((rows - top) * FontHeight(screen)));
8049	if (clearFirst) {
8050	    ClearBufRows(xw, top, rows);
8051	}
8052    }
8053    ScrnUpdate(xw, 0, 0, rows, MaxCols(screen), False);
8054}
8055
8056Bool
8057CheckBufPtrs(TScreen *screen)
8058{
8059    return (screen->visbuf != 0
8060#if OPT_SAVE_LINES
8061	    && screen->editBuf_index[0] != 0
8062#endif
8063	    && screen->editBuf_index[1] != 0);
8064}
8065
8066/*
8067 * Swap buffer line pointers between alternate and regular screens.
8068 */
8069void
8070SwitchBufPtrs(TScreen *screen, int toBuf)
8071{
8072    if (CheckBufPtrs(screen)) {
8073#if OPT_SAVE_LINES
8074	screen->visbuf = screen->editBuf_index[toBuf];
8075#else
8076	size_t len = ScrnPointers(screen, (size_t) MaxRows(screen));
8077
8078	(void) toBuf;
8079	memcpy(screen->save_ptr, screen->visbuf, len);
8080	memcpy(screen->visbuf, screen->editBuf_index[1], len);
8081	memcpy(screen->editBuf_index[1], screen->save_ptr, len);
8082#endif
8083    }
8084}
8085
8086void
8087VTRun(XtermWidget xw)
8088{
8089    TScreen *screen = TScreenOf(xw);
8090
8091    TRACE(("VTRun ...\n"));
8092
8093    if (!screen->Vshow) {
8094	set_vt_visibility(True);
8095    }
8096    update_vttekmode();
8097    update_vtshow();
8098    update_tekshow();
8099    set_vthide_sensitivity();
8100
8101    ScrnAllocBuf(xw);
8102
8103    screen->cursor_state = OFF;
8104    screen->cursor_set = ON;
8105#if OPT_BLINK_CURS
8106    if (DoStartBlinking(screen))
8107	StartBlinking(xw);
8108#endif
8109
8110#if OPT_TEK4014
8111    if (Tpushb > Tpushback) {
8112	fillPtyData(xw, VTbuffer, (char *) Tpushback, (int) (Tpushb - Tpushback));
8113	Tpushb = Tpushback;
8114    }
8115#endif
8116    screen->is_running = True;
8117    if (screen->embed_high && screen->embed_wide) {
8118	ScreenResize(xw, screen->embed_wide, screen->embed_high, &(xw->flags));
8119    }
8120#if OPT_MAXIMIZE
8121    else if (resource.fullscreen == esTrue || resource.fullscreen == esAlways)
8122	FullScreen(xw, True);
8123#endif
8124    if (!setjmp(VTend))
8125	VTparse(xw);
8126    StopBlinking(xw);
8127    HideCursor(xw);
8128    screen->cursor_set = OFF;
8129    TRACE(("... VTRun\n"));
8130}
8131
8132/*ARGSUSED*/
8133static void
8134VTExpose(Widget w GCC_UNUSED,
8135	 XEvent *event,
8136	 Region region GCC_UNUSED)
8137{
8138    DEBUG_MSG("Expose\n");
8139    if (event->type == Expose)
8140	HandleExposure(term, event);
8141}
8142
8143static void
8144VTGraphicsOrNoExpose(XEvent *event)
8145{
8146    XtermWidget xw = term;
8147    TScreen *screen = TScreenOf(xw);
8148    if (screen->incopy <= 0) {
8149	screen->incopy = 1;
8150	if (screen->scrolls > 0)
8151	    screen->scrolls--;
8152    }
8153    if (event->type == GraphicsExpose)
8154	if (HandleExposure(xw, event))
8155	    screen->cursor_state = OFF;
8156    if ((event->type == NoExpose)
8157	|| ((XGraphicsExposeEvent *) event)->count == 0) {
8158	if (screen->incopy <= 0 && screen->scrolls > 0)
8159	    screen->scrolls--;
8160	if (screen->scrolls)
8161	    screen->incopy = -1;
8162	else
8163	    screen->incopy = 0;
8164    }
8165}
8166
8167/*ARGSUSED*/
8168static void
8169VTNonMaskableEvent(Widget w GCC_UNUSED,
8170		   XtPointer closure GCC_UNUSED,
8171		   XEvent *event,
8172		   Boolean *cont GCC_UNUSED)
8173{
8174    switch (event->type) {
8175    case GraphicsExpose:
8176	/* FALLTHRU */
8177    case NoExpose:
8178	VTGraphicsOrNoExpose(event);
8179	break;
8180    }
8181}
8182
8183static void
8184VTResize(Widget w)
8185{
8186    if (XtIsRealized(w)) {
8187	XtermWidget xw = (XtermWidget) w;
8188	ScreenResize(xw, xw->core.width, xw->core.height, &xw->flags);
8189    }
8190}
8191
8192#define okDimension(src,dst) ((src <= MAX_U_COORD) \
8193			  && ((dst = (Dimension) src) == src))
8194
8195static void
8196RequestResize(XtermWidget xw, int rows, int cols, Bool text)
8197{
8198    TScreen *screen = TScreenOf(xw);
8199    Dimension replyWidth, replyHeight;
8200    Dimension askedWidth, askedHeight;
8201    XtGeometryResult status;
8202    XWindowAttributes attrs;
8203#if OPT_RENDERFONT && USE_DOUBLE_BUFFER
8204    Boolean buggyXft = False;
8205    Cardinal ignore = 0;
8206#endif
8207
8208    TRACE(("RequestResize(rows=%d, cols=%d, text=%d)\n", rows, cols, text));
8209
8210    /* check first if the row/column values fit into a Dimension */
8211    if (cols > 0) {
8212	if ((int) (askedWidth = (Dimension) cols) < cols) {
8213	    TRACE(("... cols too large for Dimension\n"));
8214	    return;
8215	}
8216    } else {
8217	askedWidth = 0;
8218    }
8219    if (rows > 0) {
8220	if ((int) (askedHeight = (Dimension) rows) < rows) {
8221	    TRACE(("... rows too large for Dimension\n"));
8222	    return;
8223	}
8224    } else {
8225	askedHeight = 0;
8226    }
8227
8228    xw->work.doing_resize = True;
8229
8230#if OPT_RENDERFONT && USE_DOUBLE_BUFFER
8231    /*
8232     * Work around a bug seen when vttest switches from 132 columns back to 80
8233     * columns, while double-buffering is active.  If Xft is active during the
8234     * resize, the screen will be blank thereafter.  This workaround causes
8235     * some extra flickering, but that is preferable to a blank screen.
8236     *
8237     * Since the bitmap- and TrueType-fonts do not always have identical sizes,
8238     * do this switching early, to use the updated font-sizes in the request
8239     * for resizing the window.
8240     */
8241#define ToggleXft() HandleRenderFont((Widget)xw, (XEvent *)0, (String *)0, &ignore)
8242    if (resource.buffered
8243	&& UsingRenderFont(xw)) {
8244	ToggleXft();
8245	buggyXft = True;
8246    }
8247#endif
8248
8249    /*
8250     * If the requested values will fit into a Dimension, and one or both are
8251     * zero, get the current corresponding screen dimension to use as a limit.
8252     */
8253    if (askedHeight == 0
8254	|| askedWidth == 0
8255	|| xw->misc.limit_resize > 0) {
8256	xtermGetWinAttrs(XtDisplay(xw),
8257			 RootWindowOfScreen(XtScreen(xw)), &attrs);
8258    }
8259
8260    /*
8261     * Using the current font metrics, translate the requested character
8262     * rows/columns into pixels.
8263     */
8264    if (text) {
8265	unsigned long value;
8266
8267	if ((value = (unsigned long) rows) != 0) {
8268	    if (rows < 0)
8269		value = (unsigned long) MaxRows(screen);
8270	    value *= (unsigned long) FontHeight(screen);
8271	    value += (unsigned long) (2 * screen->border);
8272	    if (!okDimension(value, askedHeight))
8273		goto give_up;
8274	}
8275
8276	if ((value = (unsigned long) cols) != 0) {
8277	    if (cols < 0)
8278		value = (unsigned long) MaxCols(screen);
8279	    value *= (unsigned long) FontWidth(screen);
8280	    value += (unsigned long) ((2 * screen->border)
8281				      + ScrollbarWidth(screen));
8282	    if (!okDimension(value, askedWidth))
8283		goto give_up;
8284	}
8285
8286    } else {
8287	if (rows < 0)
8288	    askedHeight = FullHeight(screen);
8289	if (cols < 0)
8290	    askedWidth = FullWidth(screen);
8291    }
8292
8293    if (rows == 0) {
8294	askedHeight = (Dimension) attrs.height;
8295    }
8296    if (cols == 0) {
8297	askedWidth = (Dimension) attrs.width;
8298    }
8299
8300    if (xw->misc.limit_resize > 0) {
8301	Dimension high = (Dimension) (xw->misc.limit_resize * attrs.height);
8302	Dimension wide = (Dimension) (xw->misc.limit_resize * attrs.width);
8303	if ((int) high < attrs.height)
8304	    high = (Dimension) attrs.height;
8305	if (askedHeight > high)
8306	    askedHeight = high;
8307	if ((int) wide < attrs.width)
8308	    wide = (Dimension) attrs.width;
8309	if (askedWidth > wide)
8310	    askedWidth = wide;
8311    }
8312#ifndef nothack
8313    getXtermSizeHints(xw);
8314#endif
8315
8316    TRACE(("...requesting resize %dx%d\n", askedHeight, askedWidth));
8317    status = REQ_RESIZE((Widget) xw,
8318			askedWidth, askedHeight,
8319			&replyWidth, &replyHeight);
8320
8321    if (status == XtGeometryYes ||
8322	status == XtGeometryDone) {
8323	ScreenResize(xw, replyWidth, replyHeight, &xw->flags);
8324    }
8325#ifndef nothack
8326    /*
8327     * XtMakeResizeRequest() has the undesirable side-effect of clearing
8328     * the window manager's hints, even on a failed request.  This would
8329     * presumably be fixed if the shell did its own work.
8330     */
8331    if (xw->hints.flags
8332	&& replyHeight
8333	&& replyWidth) {
8334	xw->hints.height = replyHeight;
8335	xw->hints.width = replyWidth;
8336
8337	TRACE(("%s@%d -- ", __FILE__, __LINE__));
8338	TRACE_HINTS(&xw->hints);
8339	XSetWMNormalHints(screen->display, VShellWindow(xw), &xw->hints);
8340	TRACE(("%s@%d -- ", __FILE__, __LINE__));
8341	TRACE_WM_HINTS(xw);
8342    }
8343#endif
8344
8345    XSync(screen->display, False);	/* synchronize */
8346    if (xtermAppPending()) {
8347	xevents(xw);
8348    }
8349
8350  give_up:
8351#if OPT_RENDERFONT && USE_DOUBLE_BUFFER
8352    if (buggyXft) {
8353	ToggleXft();
8354	if (xtermAppPending()) {
8355	    xevents(xw);
8356	}
8357    }
8358#endif
8359
8360    xw->work.doing_resize = False;
8361
8362    TRACE(("...RequestResize done\n"));
8363    return;
8364}
8365
8366static String xterm_trans =
8367"<ClientMessage>WM_PROTOCOLS: DeleteWindow()\n\
8368     <MappingNotify>: KeyboardMapping()\n";
8369
8370int
8371VTInit(XtermWidget xw)
8372{
8373    Widget vtparent = SHELL_OF(xw);
8374
8375    TRACE(("VTInit " TRACE_L "\n"));
8376
8377    XtRealizeWidget(vtparent);
8378    XtOverrideTranslations(vtparent, XtParseTranslationTable(xterm_trans));
8379    (void) XSetWMProtocols(XtDisplay(vtparent), XtWindow(vtparent),
8380			   &wm_delete_window, 1);
8381
8382    if (IsEmpty(xw->keyboard.print_translations)) {
8383	TRACE_TRANS("shell", vtparent);
8384	TRACE_TRANS("vt100", (Widget) (xw));
8385	xtermButtonInit(xw);
8386    }
8387
8388    ScrnAllocBuf(xw);
8389
8390    TRACE(("..." TRACE_R " VTInit\n"));
8391    return (1);
8392}
8393
8394static void
8395VTClassInit(void)
8396{
8397    XtAddConverter(XtRString, XtRGravity, XmuCvtStringToGravity,
8398		   (XtConvertArgList) NULL, (Cardinal) 0);
8399}
8400
8401#if OPT_COLOR_RES
8402/*
8403 * Override the use of XtDefaultForeground/XtDefaultBackground to make some
8404 * colors, such as cursor color, use the actual foreground/background value
8405 * if there is no explicit resource value used.
8406 */
8407static Pixel
8408fill_Tres(XtermWidget target, XtermWidget source, int offset)
8409{
8410    char *name;
8411    ScrnColors temp;
8412    TScreen *src = TScreenOf(source);
8413    TScreen *dst = TScreenOf(target);
8414
8415    dst->Tcolors[offset] = src->Tcolors[offset];
8416    dst->Tcolors[offset].mode = False;
8417
8418    if ((name = x_strtrim(dst->Tcolors[offset].resource)) != 0)
8419	dst->Tcolors[offset].resource = name;
8420
8421    if (name == 0) {
8422	dst->Tcolors[offset].value = target->dft_foreground;
8423    } else if (isDefaultForeground(name)) {
8424	dst->Tcolors[offset].value = ((offset == TEXT_FG || offset == TEXT_BG)
8425				      ? target->dft_foreground
8426				      : dst->Tcolors[TEXT_FG].value);
8427    } else if (isDefaultBackground(name)) {
8428	dst->Tcolors[offset].value = ((offset == TEXT_FG || offset == TEXT_BG)
8429				      ? target->dft_background
8430				      : dst->Tcolors[TEXT_BG].value);
8431    } else {
8432	memset(&temp, 0, sizeof(temp));
8433	if (AllocateTermColor(target, &temp, offset, name, True)) {
8434	    if (COLOR_DEFINED(&(temp), offset))
8435		free(temp.names[offset]);
8436	    dst->Tcolors[offset].value = temp.colors[offset];
8437	} else if (offset == TEXT_FG || offset == TEXT_BG) {
8438	    free(name);
8439	    dst->Tcolors[offset].resource = 0;
8440	}
8441    }
8442    return dst->Tcolors[offset].value;
8443}
8444
8445/*
8446 * If one or both of the foreground/background colors cannot be allocated,
8447 * e.g., due to gross misconfiguration, recover by setting both to the
8448 * display's default values.
8449 */
8450static void
8451repairColors(XtermWidget target)
8452{
8453    TScreen *screen = TScreenOf(target);
8454
8455    if (screen->Tcolors[TEXT_FG].resource == 0 ||
8456	screen->Tcolors[TEXT_BG].resource == 0) {
8457	xtermWarning("unable to allocate fg/bg colors\n");
8458	screen->Tcolors[TEXT_FG].resource = x_strdup(XtDefaultForeground);
8459	screen->Tcolors[TEXT_BG].resource = x_strdup(XtDefaultBackground);
8460	if (screen->Tcolors[TEXT_FG].resource == 0 ||
8461	    screen->Tcolors[TEXT_BG].resource == 0) {
8462	    Exit(1);
8463	}
8464	screen->Tcolors[TEXT_FG].value = target->dft_foreground;
8465	screen->Tcolors[TEXT_BG].value = target->dft_background;
8466    }
8467}
8468#else
8469#define fill_Tres(target, source, offset) \
8470	TScreenOf(target)->Tcolors[offset] = TScreenOf(source)->Tcolors[offset]
8471#define repairColors(target)	/* nothing */
8472#endif
8473
8474#if OPT_WIDE_CHARS
8475static void
8476set_utf8_feature(TScreen *screen, int *feature)
8477{
8478    if (*feature == uDefault) {
8479	switch (screen->utf8_mode) {
8480	case uFalse:
8481	    /* FALLTHRU */
8482	case uTrue:
8483	    *feature = screen->utf8_mode;
8484	    break;
8485	case uDefault:
8486	    /* should not happen */
8487	    *feature = uTrue;
8488	    break;
8489	case uAlways:
8490	    /* use this to disable menu entry */
8491	    break;
8492	}
8493    }
8494}
8495
8496static void
8497VTInitialize_locale(XtermWidget xw)
8498{
8499    TScreen *screen = TScreenOf(xw);
8500    Bool is_utf8 = xtermEnvUTF8();
8501
8502    TRACE(("VTInitialize_locale\n"));
8503    TRACE(("... request screen.utf8_mode = %d\n", screen->utf8_mode));
8504    TRACE(("... request screen.utf8_fonts = %d\n", screen->utf8_fonts));
8505    TRACE(("... request screen.utf8_title = %d\n", screen->utf8_title));
8506
8507    screen->utf8_always = (screen->utf8_mode == uAlways);
8508    if (screen->utf8_mode < 0)
8509	screen->utf8_mode = uFalse;
8510
8511    if (screen->utf8_mode > 3)
8512	screen->utf8_mode = uDefault;
8513
8514    screen->latin9_mode = 0;
8515    screen->unicode_font = 0;
8516#if OPT_LUIT_PROG
8517    xw->misc.callfilter = 0;
8518    xw->misc.use_encoding = 0;
8519
8520    TRACE(("... setup for luit:\n"));
8521    TRACE(("... request misc.locale_str = \"%s\"\n", xw->misc.locale_str));
8522
8523    if (screen->utf8_mode == uFalse) {
8524	TRACE(("... command-line +u8 overrides\n"));
8525    } else
8526#if OPT_MINI_LUIT
8527    if (x_strcasecmp(xw->misc.locale_str, "CHECKFONT") == 0) {
8528	int fl = (int) strlen(DefaultFontN(xw));
8529	if (fl > 11
8530	    && x_strcasecmp(DefaultFontN(xw) + fl - 11, "-ISO10646-1") == 0) {
8531	    screen->unicode_font = 1;
8532	    /* unicode font, use True */
8533#ifdef HAVE_LANGINFO_CODESET
8534	    if (!strcmp(xtermEnvEncoding(), "ANSI_X3.4-1968")
8535		|| !strcmp(xtermEnvEncoding(), "ISO-8859-1")) {
8536		if (screen->utf8_mode == uDefault)
8537		    screen->utf8_mode = uFalse;
8538	    } else if (!strcmp(xtermEnvEncoding(), "ISO-8859-15")) {
8539		if (screen->utf8_mode == uDefault)
8540		    screen->utf8_mode = uFalse;
8541		screen->latin9_mode = 1;
8542	    } else {
8543		xw->misc.callfilter = (Boolean) (is_utf8 ? 0 : 1);
8544		screen->utf8_mode = uAlways;
8545	    }
8546#else
8547	    xw->misc.callfilter = is_utf8 ? 0 : 1;
8548	    screen->utf8_mode = uAlways;
8549#endif
8550	} else {
8551	    /* other encoding, use False */
8552	    if (screen->utf8_mode == uDefault) {
8553		screen->utf8_mode = is_utf8 ? uAlways : uFalse;
8554	    }
8555	}
8556    } else
8557#endif /* OPT_MINI_LUIT */
8558	if (x_strcasecmp(xw->misc.locale_str, "TRUE") == 0 ||
8559	    x_strcasecmp(xw->misc.locale_str, "ON") == 0 ||
8560	    x_strcasecmp(xw->misc.locale_str, "YES") == 0 ||
8561	    x_strcasecmp(xw->misc.locale_str, "AUTO") == 0 ||
8562	    strcmp(xw->misc.locale_str, "1") == 0) {
8563	/* when true ... fully obeying LC_CTYPE locale */
8564	xw->misc.callfilter = (Boolean) (is_utf8 ? 0 : 1);
8565	screen->utf8_mode = uAlways;
8566    } else if (x_strcasecmp(xw->misc.locale_str, "FALSE") == 0 ||
8567	       x_strcasecmp(xw->misc.locale_str, "OFF") == 0 ||
8568	       x_strcasecmp(xw->misc.locale_str, "NO") == 0 ||
8569	       strcmp(xw->misc.locale_str, "0") == 0) {
8570	/* when false ... original value of utf8_mode is effective */
8571	if (screen->utf8_mode == uDefault) {
8572	    screen->utf8_mode = is_utf8 ? uAlways : uFalse;
8573	}
8574    } else if (x_strcasecmp(xw->misc.locale_str, "MEDIUM") == 0 ||
8575	       x_strcasecmp(xw->misc.locale_str, "SEMIAUTO") == 0) {
8576	/* when medium ... obeying locale only for UTF-8 and Asian */
8577	if (is_utf8) {
8578	    screen->utf8_mode = uAlways;
8579	} else if (
8580#ifdef MB_CUR_MAX
8581		      MB_CUR_MAX > 1 ||
8582#else
8583		      !strncmp(xtermEnvLocale(), "ja", (size_t) 2) ||
8584		      !strncmp(xtermEnvLocale(), "ko", (size_t) 2) ||
8585		      !strncmp(xtermEnvLocale(), "zh", (size_t) 2) ||
8586#endif
8587		      !strncmp(xtermEnvLocale(), "th", (size_t) 2) ||
8588		      !strncmp(xtermEnvLocale(), "vi", (size_t) 2)) {
8589	    xw->misc.callfilter = 1;
8590	    screen->utf8_mode = uAlways;
8591	} else {
8592	    screen->utf8_mode = uFalse;
8593	}
8594    } else if (x_strcasecmp(xw->misc.locale_str, "UTF-8") == 0 ||
8595	       x_strcasecmp(xw->misc.locale_str, "UTF8") == 0) {
8596	/* when UTF-8 ... UTF-8 mode */
8597	screen->utf8_mode = uAlways;
8598    } else {
8599	/* other words are regarded as encoding name passed to luit */
8600	xw->misc.callfilter = 1;
8601	screen->utf8_mode = uAlways;
8602	xw->misc.use_encoding = 1;
8603    }
8604    TRACE(("... updated misc.callfilter = %s\n", BtoS(xw->misc.callfilter)));
8605    TRACE(("... updated misc.use_encoding = %s\n", BtoS(xw->misc.use_encoding)));
8606#else
8607    if (screen->utf8_mode == uDefault) {
8608	screen->utf8_mode = is_utf8 ? uAlways : uFalse;
8609    }
8610#endif /* OPT_LUIT_PROG */
8611
8612    set_utf8_feature(screen, &screen->utf8_fonts);
8613    set_utf8_feature(screen, &screen->utf8_title);
8614
8615    screen->utf8_inparse = (Boolean) (screen->utf8_mode != uFalse);
8616
8617    TRACE(("... updated screen.utf8_mode = %d\n", screen->utf8_mode));
8618    TRACE(("... updated screen.utf8_fonts = %d\n", screen->utf8_fonts));
8619    TRACE(("... updated screen.utf8_title = %d\n", screen->utf8_title));
8620    TRACE(("...VTInitialize_locale done\n"));
8621}
8622#endif
8623
8624void
8625lookupSelectUnit(XtermWidget xw, Cardinal item, String value)
8626{
8627    /* *INDENT-OFF* */
8628    static const struct {
8629	const char *	name;
8630	SelectUnit	code;
8631    } table[] = {
8632    	{ "char",	Select_CHAR },
8633    	{ "word",	Select_WORD },
8634    	{ "line",	Select_LINE },
8635    	{ "group",	Select_GROUP },
8636    	{ "page",	Select_PAGE },
8637    	{ "all",	Select_ALL },
8638#if OPT_SELECT_REGEX
8639    	{ "regex",	Select_REGEX },
8640#endif
8641    };
8642    /* *INDENT-ON* */
8643
8644    TScreen *screen = TScreenOf(xw);
8645    String next = x_skip_nonblanks(value);
8646    Cardinal n;
8647
8648    screen->selectMap[item] = NSELECTUNITS;
8649    for (n = 0; n < XtNumber(table); ++n) {
8650	if (!x_strncasecmp(table[n].name, value, (unsigned) (next - value))) {
8651	    screen->selectMap[item] = table[n].code;
8652#if OPT_SELECT_REGEX
8653	    if (table[n].code == Select_REGEX) {
8654		screen->selectExpr[item] = x_strtrim(next);
8655		TRACE(("Parsed regex \"%s\"\n", screen->selectExpr[item]));
8656	    }
8657#endif
8658	    break;
8659	}
8660    }
8661}
8662
8663static void
8664ParseOnClicks(XtermWidget wnew, XtermWidget wreq, Cardinal item)
8665{
8666    lookupSelectUnit(wnew, item, TScreenOf(wreq)->onClick[item]);
8667}
8668
8669/*
8670 * Parse a comma-separated list, returning a string which the caller must
8671 * free, and updating the source pointer.
8672 */
8673static char *
8674ParseList(const char **source)
8675{
8676    const char *base = *source;
8677    const char *next;
8678    char *value = 0;
8679    char *result;
8680
8681    /* ignore empty values */
8682    while (*base == ',')
8683	++base;
8684
8685    if (*base != '\0') {
8686	size_t size;
8687
8688	next = base;
8689	while (*next != '\0' && *next != ',')
8690	    ++next;
8691	size = (size_t) (1 + next - base);
8692	value = malloc(size);
8693	if (value != 0) {
8694	    memcpy(value, base, size);
8695	    value[size - 1] = '\0';
8696	}
8697	*source = next;
8698    } else {
8699	*source = base;
8700    }
8701    result = x_strtrim(value);
8702    free(value);
8703    return result;
8704}
8705
8706static void
8707set_flags_from_list(char *target,
8708		    const char *source,
8709		    const FlagList * list)
8710{
8711    Cardinal n;
8712
8713    while (!IsEmpty(source)) {
8714	char *next = ParseList(&source);
8715	Boolean found = False;
8716	char flag = 1;
8717
8718	if (next == 0)
8719	    break;
8720	if (*next == '~') {
8721	    flag = 0;
8722	    next++;
8723	}
8724	if (isdigit(CharOf(*next))) {
8725	    char *temp;
8726	    int value = (int) strtol(next, &temp, 0);
8727	    if (!FullS2L(next, temp)) {
8728		xtermWarning("Expected a number: %s\n", next);
8729	    } else {
8730		for (n = 0; list[n].name != 0; ++n) {
8731		    if (list[n].code == value) {
8732			target[value] = flag;
8733			found = True;
8734			TRACE(("...found %s (%d)\n", list[n].name, value));
8735			break;
8736		    }
8737		}
8738	    }
8739	} else {
8740	    for (n = 0; list[n].name != 0; ++n) {
8741		if (!x_wildstrcmp(next, list[n].name)) {
8742		    int value = list[n].code;
8743		    target[value] = flag;
8744		    found = True;
8745		    TRACE(("...found %s (%d)\n", list[n].name, value));
8746		}
8747	    }
8748	}
8749	if (!found) {
8750	    xtermWarning("Unrecognized keyword: %s\n", next);
8751	}
8752	free(next);
8753    }
8754}
8755
8756#define InitCursorShape(target, source) \
8757    target->cursor_shape = source->cursor_underline \
8758	? CURSOR_UNDERLINE \
8759	: CURSOR_BLOCK
8760
8761#if OPT_XRES_QUERY
8762static XtResource *
8763findVT100Resource(const char *name)
8764{
8765    Cardinal n;
8766    XtResource *result = 0;
8767
8768    if (!IsEmpty(name)) {
8769	XrmQuark quarkName = XrmPermStringToQuark(name);
8770	for (n = 0; n < XtNumber(xterm_resources); ++n) {
8771	    if ((int) xterm_resources[n].resource_offset >= 0
8772		&& !strcmp(xterm_resources[n].resource_name, name)) {
8773		result = &xterm_resources[n];
8774		break;
8775	    } else if (xterm_resources[n].resource_name
8776		       == (String) (intptr_t) quarkName) {
8777		result = &xterm_resources[n];
8778		break;
8779	    }
8780	}
8781    }
8782    return result;
8783}
8784
8785static int
8786cmp_resources(const void *a, const void *b)
8787{
8788    return strcmp((*(const String *) a),
8789		  (*(const String *) b));
8790}
8791
8792static void
8793reportResources(XtermWidget xw)
8794{
8795    String *list = TypeMallocN(String, XtNumber(xterm_resources));
8796    Cardinal n;
8797    int widest = 0;
8798
8799    if (list == NULL)
8800	return;
8801
8802    for (n = 0; n < XtNumber(xterm_resources); ++n) {
8803	int width;
8804	list[n] = (((int) xterm_resources[n].resource_offset < 0)
8805		   ? XrmQuarkToString((XrmQuark) (intptr_t)
8806				      xterm_resources[n].resource_name)
8807		   : xterm_resources[n].resource_name);
8808	width = (int) strlen(list[n]);
8809	if (widest < width)
8810	    widest = width;
8811    }
8812    qsort(list, (size_t) XtNumber(xterm_resources), sizeof(String), cmp_resources);
8813    for (n = 0; n < XtNumber(xterm_resources); ++n) {
8814	char *value = vt100ResourceToString(xw, list[n]);
8815	printf("%-*s : %s\n", widest, list[n], value ? value : "(skip)");
8816	free(value);
8817    }
8818    free(list);
8819}
8820
8821char *
8822vt100ResourceToString(XtermWidget xw, const char *name)
8823{
8824    XtResource *data;
8825    char *result = NULL;
8826
8827    if ((data = findVT100Resource(name)) != 0) {
8828	int fake_offset = (int) data->resource_offset;
8829	void *res_addr;
8830	int real_offset;
8831	String res_type;
8832
8833	/*
8834	 * X Toolkit "compiles" the resource-list into quarks and changes the
8835	 * resource-offset at the same time to a negative value.
8836	 */
8837	if (fake_offset < 0) {
8838	    real_offset = -(fake_offset + 1);
8839	    res_type = XrmQuarkToString((XrmQuark) (intptr_t) data->resource_type);
8840	} else {
8841	    real_offset = fake_offset;
8842	    res_type = data->resource_type;
8843	}
8844	res_addr = (void *) ((char *) xw + real_offset);
8845
8846	if (!strcmp(res_type, XtRString)) {
8847	    char *value = *(char **) res_addr;
8848	    if (value != NULL) {
8849		size_t need = strlen(value);
8850		if ((result = malloc(1 + need)) != 0)
8851		    strcpy(result, value);
8852	    }
8853	} else if (!strcmp(res_type, XtRInt)) {
8854	    if ((result = malloc(1 + (size_t) (3 * data->resource_size))) != 0)
8855		sprintf(result, "%d", *(int *) res_addr);
8856	} else if (!strcmp(res_type, XtRFloat)) {
8857	    if ((result = malloc(1 + (size_t) (3 * data->resource_size))) != 0)
8858		sprintf(result, "%f", (double) (*(float *) res_addr));
8859	} else if (!strcmp(res_type, XtRBoolean)) {
8860	    if ((result = malloc((size_t) 6)) != 0)
8861		strcpy(result, *(Boolean *) res_addr ? "true" : "false");
8862	}
8863    }
8864    TRACE(("vt100ResourceToString(%s) %s\n", name, NonNull(result)));
8865    return result;
8866}
8867#endif /* OPT_XRES_QUERY */
8868
8869/*
8870 * Decode a terminal-ID or graphics-terminal-ID, using the default terminal-ID
8871 * if the value is outside a (looser) range than limitedTerminalID.  This uses
8872 * a wider range, to avoid being a nuisance when using X resources with
8873 * different configurations of xterm.
8874 */
8875static int
8876decodeTerminalID(const char *value)
8877{
8878    const char *s;
8879    char *t;
8880    long result;
8881
8882    for (s = value; *s; s++) {
8883	if (!isalpha(CharOf(*s)))
8884	    break;
8885    }
8886    result = strtol(s, &t, 10);
8887    if (t == s || *t != '\0' || result <= 0L || result > 1000L) {
8888	xtermWarning("unexpected value for terminalID: \"%s\"\n", value);
8889	result = atoi(DFT_DECID);
8890    }
8891    TRACE(("decodeTerminalID \"%s\" ->%d\n", value, (int) result));
8892    return (int) result;
8893}
8894
8895/*
8896 * Ensures that the value returned by decodeTerminalID is either in the range
8897 * of IDs matching a known terminal, or (failing that), set to the built-in
8898 * default.  The DA response relies on having the ID being set to a known
8899 * value.
8900 */
8901static int
8902limitedTerminalID(int terminal_id)
8903{
8904    if (terminal_id < MIN_DECID)
8905	terminal_id = MIN_DECID;
8906    else if (terminal_id > MAX_DECID)
8907	terminal_id = MAX_DECID;
8908    else
8909	terminal_id = atoi(DFT_DECID);
8910    return terminal_id;
8911}
8912
8913/* ARGSUSED */
8914static void
8915VTInitialize(Widget wrequest,
8916	     Widget new_arg,
8917	     ArgList args GCC_UNUSED,
8918	     Cardinal *num_args GCC_UNUSED)
8919{
8920#define Kolor(name) TScreenOf(wnew)->name.resource
8921#define TxtFg(name) !x_strcasecmp(Kolor(Tcolors[TEXT_FG]), Kolor(name))
8922#define TxtBg(name) !x_strcasecmp(Kolor(Tcolors[TEXT_BG]), Kolor(name))
8923#define DftFg(name) isDefaultForeground(Kolor(name))
8924#define DftBg(name) isDefaultBackground(Kolor(name))
8925
8926#define DATA_END   { NULL,  -1       }
8927
8928#if OPT_BLINK_CURS
8929#define DATA(name) { #name, cb##name }
8930    static const FlagList tblBlinkOps[] =
8931    {
8932	DATA(Always)
8933	,DATA(Never)
8934	,DATA_END
8935    };
8936#undef DATA
8937#endif
8938
8939#define DATA(name) { #name, ec##name }
8940    static const FlagList tblColorOps[] =
8941    {
8942	DATA(SetColor)
8943	,DATA(GetColor)
8944	,DATA(GetAnsiColor)
8945	,DATA_END
8946    };
8947#undef DATA
8948
8949#define DATA(name) { #name, ef##name }
8950    static const FlagList tblFontOps[] =
8951    {
8952	DATA(SetFont)
8953	,DATA(GetFont)
8954	,DATA_END
8955    };
8956#undef DATA
8957
8958#define DATA(name) { #name, em##name }
8959    static const FlagList tblMouseOps[] =
8960    {
8961	DATA(X10)
8962	,DATA(Locator)
8963	,DATA(VT200Click)
8964	,DATA(VT200Hilite)
8965	,DATA(AnyButton)
8966	,DATA(AnyEvent)
8967	,DATA(FocusEvent)
8968	,DATA(Extended)
8969	,DATA(SGR)
8970	,DATA(URXVT)
8971	,DATA(AlternateScroll)
8972	,DATA_END
8973    };
8974#undef DATA
8975
8976#define DATA(name) { #name, ep##name }
8977#define DATA2(alias,name) { #alias, ep##name }
8978    static const FlagList tblPasteControls[] =
8979    {
8980	DATA(NUL)
8981	,DATA(SOH)
8982	,DATA(STX)
8983	,DATA(ETX)
8984	,DATA(EOT)
8985	,DATA(ENQ)
8986	,DATA(ACK)
8987	,DATA(BEL)
8988	,DATA(BS)
8989	,DATA(HT)
8990	,DATA(LF)
8991	,DATA(VT)
8992	,DATA(FF)
8993	,DATA(CR)
8994	,DATA(SO)
8995	,DATA(SI)
8996	,DATA(DLE)
8997	,DATA(DC1)
8998	,DATA(DC2)
8999	,DATA(DC3)
9000	,DATA(DC4)
9001	,DATA(NAK)
9002	,DATA(SYN)
9003	,DATA(ETB)
9004	,DATA(CAN)
9005	,DATA(EM)
9006	,DATA(SUB)
9007	,DATA(ESC)
9008	,DATA(FS)
9009	,DATA(GS)
9010	,DATA(RS)
9011	,DATA(US)
9012    /* aliases */
9013	,DATA2(NL, LF)
9014	,DATA(C0)
9015	,DATA(DEL)
9016	,DATA_END
9017    };
9018#undef DATA
9019#undef DATA2
9020
9021#define DATA(name) { #name, et##name }
9022    static const FlagList tblTcapOps[] =
9023    {
9024	DATA(SetTcap)
9025	,DATA(GetTcap)
9026	,DATA_END
9027    };
9028#undef DATA
9029
9030#define DATA(name) { #name, ew##name }
9031    static const FlagList tblWindowOps[] =
9032    {
9033	DATA(RestoreWin)
9034	,DATA(MinimizeWin)
9035	,DATA(SetWinPosition)
9036	,DATA(SetWinSizePixels)
9037	,DATA(RaiseWin)
9038	,DATA(LowerWin)
9039	,DATA(RefreshWin)
9040	,DATA(SetWinSizeChars)
9041#if OPT_MAXIMIZE
9042	,DATA(MaximizeWin)
9043	,DATA(FullscreenWin)
9044#endif
9045	,DATA(GetWinState)
9046	,DATA(GetWinPosition)
9047	,DATA(GetWinSizePixels)
9048	,DATA(GetWinSizeChars)
9049#if OPT_MAXIMIZE
9050	,DATA(GetScreenSizeChars)
9051#endif
9052	,DATA(GetIconTitle)
9053	,DATA(GetWinTitle)
9054	,DATA(PushTitle)
9055	,DATA(PopTitle)
9056    /* this item uses all remaining numbers in the sequence */
9057	,DATA(SetWinLines)
9058    /* starting at this point, numbers do not apply */
9059	,DATA(SetXprop)
9060	,DATA(GetSelection)
9061	,DATA(SetSelection)
9062	,DATA(GetChecksum)
9063	,DATA(SetChecksum)
9064	,DATA_END
9065    };
9066#undef DATA
9067
9068#if OPT_RENDERFONT
9069#define DATA(name) { #name, er##name }
9070    static const FlagList tblRenderFont[] =
9071    {
9072	DATA(Default)
9073	,DATA(DefaultOff)
9074	,DATA_END
9075    };
9076#undef DATA
9077#endif
9078
9079#define DATA(name) { #name, ss##name }
9080    static const FlagList tblShift2S[] =
9081    {
9082	DATA(Always)
9083	,DATA(Never)
9084	,DATA_END
9085    };
9086#undef DATA
9087
9088#if OPT_WIDE_CHARS
9089#define DATA(name) { #name, u##name }
9090    static const FlagList tblUtf8Mode[] =
9091    {
9092	DATA(Always)
9093	,DATA(Default)
9094	,DATA_END
9095    };
9096#undef DATA
9097#endif
9098
9099#ifndef NO_ACTIVE_ICON
9100#define DATA(name) { #name, ei##name }
9101    static const FlagList tblAIconOps[] =
9102    {
9103	DATA(Default)
9104	,DATA_END
9105    };
9106#undef DATA
9107#endif
9108
9109#define DATA(name) { #name, eb##name }
9110    static const FlagList tbl8BitMeta[] =
9111    {
9112	DATA(Never)
9113	,DATA(Locale)
9114	,DATA_END
9115    };
9116#undef DATA
9117
9118    XtermWidget request = (XtermWidget) wrequest;
9119    XtermWidget wnew = (XtermWidget) new_arg;
9120    Widget my_parent = SHELL_OF(wnew);
9121    int i;
9122
9123#if OPT_ISO_COLORS
9124    Bool color_ok;
9125#endif
9126
9127#if OPT_ISO_COLORS && OPT_COLOR_RES2
9128    static XtResource fake_resources[] =
9129    {
9130#if OPT_256_COLORS
9131# include <256colres.h>
9132#elif OPT_88_COLORS
9133# include <88colres.h>
9134#endif
9135    };
9136#endif /* OPT_COLOR_RES2 */
9137    TScreen *screen = TScreenOf(wnew);
9138    char *saveLocale = xtermSetLocale(LC_NUMERIC, "C");
9139#if OPT_BLINK_CURS
9140    int ebValue;
9141#endif
9142
9143#if OPT_TRACE
9144    check_bitmasks();
9145    check_tables();
9146#endif
9147
9148    TRACE(("VTInitialize wnew %p, %d / %d resources " TRACE_L "\n",
9149	   (void *) wnew, XtNumber(xterm_resources), MAXRESOURCES));
9150    assert(XtNumber(xterm_resources) < MAXRESOURCES);
9151
9152    /* Zero out the entire "screen" component of "wnew" widget, then do
9153     * field-by-field assignment of "screen" fields that are named in the
9154     * resource list.
9155     */
9156    memset(screen, 0, sizeof(wnew->screen));
9157
9158    /* DESCO Sys#67660
9159     * Zero out the entire "keyboard" component of "wnew" widget.
9160     */
9161    memset(&wnew->keyboard, 0, sizeof(wnew->keyboard));
9162
9163    /*
9164     * The workspace has no resources - clear it.
9165     */
9166    memset(&wnew->work, 0, sizeof(wnew->work));
9167
9168    /* dummy values so that we don't try to Realize the parent shell with height
9169     * or width of 0, which is illegal in X.  The real size is computed in the
9170     * xtermWidget's Realize proc, but the shell's Realize proc is called first,
9171     * and must see a valid size.
9172     */
9173    wnew->core.height = wnew->core.width = 1;
9174
9175    /*
9176     * The definition of -rv now is that it changes the definition of
9177     * XtDefaultForeground and XtDefaultBackground.  So, we no longer
9178     * need to do anything special.
9179     */
9180    screen->display = wnew->core.screen->display;
9181
9182    /* prep getVisualInfo() */
9183    wnew->visInfo = 0;
9184    wnew->numVisuals = 0;
9185    (void) getVisualInfo(wnew);
9186
9187    /*
9188     * We use the default foreground/background colors to compare/check if a
9189     * color-resource has been set.
9190     */
9191#define MyBlackPixel(dpy) BlackPixel(dpy,DefaultScreen(dpy))
9192#define MyWhitePixel(dpy) WhitePixel(dpy,DefaultScreen(dpy))
9193
9194    if (request->misc.re_verse) {
9195	wnew->dft_foreground = MyWhitePixel(screen->display);
9196	wnew->dft_background = MyBlackPixel(screen->display);
9197    } else {
9198	wnew->dft_foreground = MyBlackPixel(screen->display);
9199	wnew->dft_background = MyWhitePixel(screen->display);
9200    }
9201
9202    init_Tres(TEXT_FG);
9203    init_Tres(TEXT_BG);
9204    repairColors(wnew);
9205
9206    wnew->old_foreground = T_COLOR(screen, TEXT_FG);
9207    wnew->old_background = T_COLOR(screen, TEXT_BG);
9208
9209    TRACE(("Color resource initialization:\n"));
9210    TRACE(("   Default foreground 0x%06lx\n", wnew->dft_foreground));
9211    TRACE(("   Default background 0x%06lx\n", wnew->dft_background));
9212    TRACE(("   Screen foreground  0x%06lx\n", T_COLOR(screen, TEXT_FG)));
9213    TRACE(("   Screen background  0x%06lx\n", T_COLOR(screen, TEXT_BG)));
9214    TRACE(("   Actual  foreground 0x%06lx\n", wnew->old_foreground));
9215    TRACE(("   Actual  background 0x%06lx\n", wnew->old_background));
9216
9217    screen->mouse_button = 0;
9218    screen->mouse_row = -1;
9219    screen->mouse_col = -1;
9220
9221#if OPT_BOX_CHARS
9222    init_Bres(screen.force_box_chars);
9223    init_Bres(screen.force_packed);
9224    init_Bres(screen.force_all_chars);
9225    init_Bres(screen.assume_all_chars);
9226#endif
9227    init_Bres(screen.free_bold_box);
9228    init_Bres(screen.allowBoldFonts);
9229
9230    init_Bres(screen.c132);
9231    init_Bres(screen.curses);
9232    init_Bres(screen.hp_ll_bc);
9233#if OPT_XMC_GLITCH
9234    init_Ires(screen.xmc_glitch);
9235    init_Ires(screen.xmc_attributes);
9236    init_Bres(screen.xmc_inline);
9237    init_Bres(screen.move_sgr_ok);
9238#endif
9239#if OPT_BLINK_CURS
9240    init_Sres(screen.cursor_blink_s);
9241    ebValue = extendedBoolean(wnew->screen.cursor_blink_s, tblBlinkOps, cbLAST);
9242    wnew->screen.cursor_blink = (BlinkOps) ebValue;
9243    init_Bres(screen.cursor_blink_xor);
9244    init_Ires(screen.blink_on);
9245    init_Ires(screen.blink_off);
9246    screen->cursor_blink_i = screen->cursor_blink;
9247#endif
9248    init_Bres(screen.cursor_underline);
9249    /* resources allow for underline or block, not (yet) bar */
9250    InitCursorShape(screen, TScreenOf(request));
9251#if OPT_BLINK_CURS
9252    TRACE(("cursor_shape:%d blinks:%d\n",
9253	   screen->cursor_shape,
9254	   screen->cursor_blink));
9255#endif
9256#if OPT_BLINK_TEXT
9257    init_Ires(screen.blink_as_bold);
9258#endif
9259    init_Ires(screen.border);
9260    init_Bres(screen.jumpscroll);
9261    init_Bres(screen.fastscroll);
9262
9263    init_Bres(screen.old_fkeys);
9264    wnew->screen.old_fkeys0 = wnew->screen.old_fkeys;
9265    wnew->keyboard.type = screen->old_fkeys
9266	? keyboardIsLegacy
9267	: keyboardIsDefault;
9268
9269    init_Mres(screen.delete_is_del);
9270#ifdef ALLOWLOGGING
9271    init_Bres(misc.logInhibit);
9272    init_Bres(misc.log_on);
9273    init_Sres(screen.logfile);
9274#endif
9275    init_Bres(screen.bellIsUrgent);
9276    init_Bres(screen.bellOnReset);
9277    init_Bres(screen.marginbell);
9278    init_Bres(screen.multiscroll);
9279    init_Ires(screen.nmarginbell);
9280    init_Ires(screen.savelines);
9281    init_Ires(screen.scrollBarBorder);
9282    init_Ires(screen.scrolllines);
9283    init_Bres(screen.alternateScroll);
9284    init_Bres(screen.scrollttyoutput);
9285    init_Bres(screen.scrollkey);
9286
9287    init_Dres(screen.scale_height);
9288    if (screen->scale_height < MIN_SCALE_HEIGHT)
9289	screen->scale_height = MIN_SCALE_HEIGHT;
9290    if (screen->scale_height > MAX_SCALE_HEIGHT)
9291	screen->scale_height = MAX_SCALE_HEIGHT;
9292
9293    init_Bres(misc.autoWrap);
9294    init_Bres(misc.login_shell);
9295    init_Bres(misc.reverseWrap);
9296    init_Bres(misc.scrollbar);
9297    init_Sres(misc.geo_metry);
9298    init_Sres(misc.T_geometry);
9299
9300    init_Sres(screen.term_id);
9301    screen->terminal_id = decodeTerminalID(TScreenOf(request)->term_id);
9302    /*
9303     * (1) If a known terminal model, and not a graphical terminal, preserve
9304     *     the terminal id.
9305     * (2) Otherwise, if ReGIS or sixel graphics are enabled, preserve the ID,
9306     *     even if it is not a known terminal.
9307     * (3) Otherwise force the terminal ID to the min, max, or VT420 depending
9308     *     on the input.
9309     */
9310    switch (screen->terminal_id) {
9311    case 52:			/* MIN_DECID */
9312    case 100:
9313    case 101:
9314    case 102:
9315    case 131:
9316    case 132:
9317    case 220:
9318    case 320:
9319    case 420:			/* DFT_DECID, unless overridden in configure */
9320    case 510:
9321    case 520:
9322    case 525:			/* MAX_DECID */
9323	break;
9324    default:
9325#if OPT_REGIS_GRAPHICS
9326	if (optRegisGraphics(screen))
9327	    break;
9328#endif
9329#if OPT_SIXEL_GRAPHICS
9330	if (optSixelGraphics(screen))
9331	    break;
9332#endif
9333	screen->terminal_id = limitedTerminalID(screen->terminal_id);
9334	break;
9335    }
9336    TRACE(("term_id '%s' -> terminal_id %d\n",
9337	   screen->term_id,
9338	   screen->terminal_id));
9339
9340    screen->vtXX_level = (screen->terminal_id / 100);
9341
9342    init_Ires(screen.title_modes);
9343    screen->title_modes0 = screen->title_modes;
9344
9345    init_Ires(screen.nextEventDelay);
9346    if (screen->nextEventDelay <= 0)
9347	screen->nextEventDelay = 1;
9348
9349    init_Bres(screen.visualbell);
9350    init_Bres(screen.flash_line);
9351    init_Ires(screen.visualBellDelay);
9352    init_Bres(screen.poponbell);
9353
9354    init_Bres(screen.eraseSavedLines0);
9355    screen->eraseSavedLines = screen->eraseSavedLines0;
9356
9357    init_Ires(misc.limit_resize);
9358
9359#if OPT_NUM_LOCK
9360    init_Bres(misc.real_NumLock);
9361    init_Bres(misc.alwaysUseMods);
9362#endif
9363
9364#if OPT_INPUT_METHOD
9365    init_Bres(misc.open_im);
9366    init_Ires(misc.retry_im);
9367    init_Sres(misc.f_x);
9368    init_Sres(misc.input_method);
9369    init_Sres(misc.preedit_type);
9370#endif
9371
9372#if OPT_SHIFT_FONTS
9373    init_Bres(misc.shift_fonts);
9374#endif
9375#if OPT_SUNPC_KBD
9376    init_Ires(misc.ctrl_fkeys);
9377#endif
9378#if OPT_TEK4014
9379    TEK4014_SHOWN(wnew) = False;	/* not a resource... */
9380    init_Bres(misc.tekInhibit);
9381    init_Bres(misc.tekSmall);
9382    init_Bres(misc.TekEmu);
9383#endif
9384#if OPT_TCAP_QUERY
9385    screen->tc_query_code = -1;
9386#endif
9387    wnew->misc.re_verse0 = request->misc.re_verse;
9388    init_Bres(misc.re_verse);
9389    init_Ires(screen.multiClickTime);
9390    init_Ires(screen.bellSuppressTime);
9391    init_Sres(screen.charClass);
9392
9393    init_Bres(screen.always_highlight);
9394    init_Bres(screen.brokenSelections);
9395    init_Bres(screen.cutNewline);
9396    init_Bres(screen.cutToBeginningOfLine);
9397    init_Bres(screen.highlight_selection);
9398    init_Bres(screen.show_wrap_marks);
9399    init_Bres(screen.i18nSelections);
9400    init_Bres(screen.keepClipboard);
9401    init_Bres(screen.keepSelection);
9402    init_Bres(screen.selectToClipboard);
9403    init_Bres(screen.trim_selection);
9404
9405    screen->pointer_cursor = TScreenOf(request)->pointer_cursor;
9406    init_Ires(screen.pointer_mode);
9407    wnew->screen.pointer_mode0 = wnew->screen.pointer_mode;
9408
9409    init_Sres(screen.answer_back);
9410
9411    wnew->SPS.printer_checked = False;
9412    init_Sres(SPS.printer_command);
9413    init_Bres(SPS.printer_autoclose);
9414    init_Bres(SPS.printer_extent);
9415    init_Bres(SPS.printer_formfeed);
9416    init_Bres(SPS.printer_newline);
9417    init_Ires(SPS.printer_controlmode);
9418#if OPT_PRINT_COLORS
9419    init_Ires(SPS.print_attributes);
9420#endif
9421
9422    init_Sres(screen.keyboard_dialect);
9423
9424    init_Sres(screen.cursor_font_name);
9425    init_Sres(screen.pointer_shape);
9426
9427    init_Bres(screen.input_eight_bits);
9428    init_Bres(screen.output_eight_bits);
9429    init_Bres(screen.control_eight_bits);
9430    init_Bres(screen.backarrow_key);
9431    init_Bres(screen.alt_is_not_meta);
9432    init_Bres(screen.alt_sends_esc);
9433    init_Bres(screen.meta_sends_esc);
9434
9435    init_Bres(screen.allowPasteControl0);
9436    init_Bres(screen.allowSendEvent0);
9437    init_Bres(screen.allowColorOp0);
9438    init_Bres(screen.allowFontOp0);
9439    init_Bres(screen.allowMouseOp0);
9440    init_Bres(screen.allowTcapOp0);
9441    init_Bres(screen.allowTitleOp0);
9442    init_Bres(screen.allowWindowOp0);
9443
9444#if OPT_SCROLL_LOCK
9445    init_Bres(screen.allowScrollLock0);
9446    init_Bres(screen.autoScrollLock);
9447#endif
9448
9449    init_Sres(screen.disallowedColorOps);
9450
9451    set_flags_from_list(screen->disallow_color_ops,
9452			screen->disallowedColorOps,
9453			tblColorOps);
9454
9455    init_Sres(screen.disallowedFontOps);
9456
9457    set_flags_from_list(screen->disallow_font_ops,
9458			screen->disallowedFontOps,
9459			tblFontOps);
9460
9461    init_Sres(screen.disallowedMouseOps);
9462
9463    set_flags_from_list(screen->disallow_mouse_ops,
9464			screen->disallowedMouseOps,
9465			tblMouseOps);
9466
9467    init_Sres(screen.disallowedPasteControls);
9468
9469    set_flags_from_list(screen->disallow_paste_controls,
9470			screen->disallowedPasteControls,
9471			tblPasteControls);
9472
9473    init_Sres(screen.disallowedTcapOps);
9474
9475    set_flags_from_list(screen->disallow_tcap_ops,
9476			screen->disallowedTcapOps,
9477			tblTcapOps);
9478
9479    init_Sres(screen.disallowedWinOps);
9480
9481    set_flags_from_list(screen->disallow_win_ops,
9482			screen->disallowedWinOps,
9483			tblWindowOps);
9484
9485    init_Sres(screen.default_string);
9486    init_Sres(screen.eightbit_select_types);
9487#if OPT_WIDE_CHARS
9488    init_Sres(screen.utf8_select_types);
9489#endif
9490
9491    /* make a copy so that editres cannot change the resource after startup */
9492    screen->allowPasteControls = screen->allowPasteControl0;
9493    screen->allowSendEvents = screen->allowSendEvent0;
9494    screen->allowColorOps = screen->allowColorOp0;
9495    screen->allowFontOps = screen->allowFontOp0;
9496    screen->allowMouseOps = screen->allowMouseOp0;
9497    screen->allowTcapOps = screen->allowTcapOp0;
9498    screen->allowTitleOps = screen->allowTitleOp0;
9499    screen->allowWindowOps = screen->allowWindowOp0;
9500
9501#if OPT_SCROLL_LOCK
9502    screen->allowScrollLock = screen->allowScrollLock0;
9503#endif
9504
9505    init_Bres(screen.quiet_grab);
9506
9507#ifndef NO_ACTIVE_ICON
9508    init_Sres(screen.icon_fontname);
9509    getIconicFont(screen)->fs = xtermLoadQueryFont(wnew,
9510						   screen->icon_fontname);
9511    TRACE(("iconFont '%s' %sloaded successfully\n",
9512	   screen->icon_fontname,
9513	   getIconicFont(screen)->fs ? "" : "NOT "));
9514    init_Sres(misc.active_icon_s);
9515    wnew->work.active_icon =
9516	(Boolean) extendedBoolean(wnew->misc.active_icon_s,
9517				  tblAIconOps, eiLAST);
9518    init_Ires(misc.icon_border_width);
9519    wnew->misc.icon_border_pixel = request->misc.icon_border_pixel;
9520#endif /* NO_ACTIVE_ICON */
9521
9522    init_Bres(misc.signalInhibit);
9523    init_Bres(misc.titeInhibit);
9524    init_Bres(misc.tiXtraScroll);
9525    init_Bres(misc.cdXtraScroll);
9526    init_Bres(misc.color_inner_border);
9527    init_Bres(misc.dynamicColors);
9528    init_Bres(misc.resizeByPixel);
9529
9530#if OPT_DEC_CHRSET
9531    for (i = 0; i < NUM_CHRSET; i++) {
9532	screen->double_fonts[i].warn = fwResource;
9533    }
9534#endif
9535    for (i = fontMenu_font1; i <= fontMenu_lastBuiltin; i++) {
9536	init_Sres2(screen.MenuFontName, i);
9537    }
9538    for (i = 0; i < fMAX; i++) {
9539	screen->fnts[i].warn = fwResource;
9540#if OPT_WIDE_ATTRS
9541	screen->ifnts[i].warn = fwResource;
9542#endif
9543    }
9544#ifndef NO_ACTIVE_ICON
9545    screen->fnt_icon.warn = fwResource;
9546#endif
9547
9548    init_Ires(misc.fontWarnings);
9549
9550    initFontLists(wnew);
9551
9552#define DefaultFontNames screen->menu_font_names[fontMenu_default]
9553
9554    /*
9555     * Process Xft font resources first, since faceName may contain X11 fonts
9556     * that should override the "font" resource.
9557     */
9558#if OPT_RENDERFONT
9559    init_Bres(screen.force_xft_height);
9560    for (i = 0; i <= fontMenu_lastBuiltin; ++i) {
9561	init_Dres2(misc.face_size, i);
9562    }
9563
9564#define ALLOC_FONTLIST(name,which,field) \
9565    init_Sres(misc.default_xft.field);\
9566    allocFontList(wnew,\
9567		  name,\
9568		  &(wnew->work.fonts),\
9569		  which,\
9570		  wnew->misc.default_xft.field,\
9571		  True)
9572
9573    ALLOC_FONTLIST(XtNfaceName, fNorm, f_n);
9574
9575#if OPT_WIDE_CHARS
9576    ALLOC_FONTLIST(XtNfaceNameDoublesize, fWide, f_w);
9577#endif
9578
9579#undef ALLOC_FONTLIST
9580
9581#endif
9582
9583    /*
9584     * Process X11 (XLFD) font specifications.
9585     */
9586#define ALLOC_FONTLIST(name,which,field) \
9587    init_Sres(misc.default_font.field);\
9588    allocFontList(wnew,\
9589		  name,\
9590		  &(wnew->work.fonts),\
9591		  which,\
9592		  wnew->misc.default_font.field,\
9593		  False)
9594
9595    ALLOC_FONTLIST(XtNfont, fNorm, f_n);
9596    ALLOC_FONTLIST(XtNboldFont, fBold, f_b);
9597
9598    DefaultFontNames[fNorm] = x_strdup(DefaultFontN(wnew));
9599    DefaultFontNames[fBold] = x_strdup(DefaultFontB(wnew));
9600
9601#if OPT_WIDE_CHARS
9602    ALLOC_FONTLIST(XtNwideFont, fWide, f_w);
9603    ALLOC_FONTLIST(XtNwideBoldFont, fWBold, f_wb);
9604
9605    DefaultFontNames[fWide] = x_strdup(DefaultFontW(wnew));
9606    DefaultFontNames[fWBold] = x_strdup(DefaultFontWB(wnew));
9607#endif
9608
9609#undef ALLOC_FONTLIST
9610
9611    screen->EscapeFontName() = NULL;
9612    screen->SelectFontName() = NULL;
9613
9614    screen->menu_font_number = fontMenu_default;
9615    init_Sres(screen.initial_font);
9616    if (screen->initial_font != 0) {
9617	int result = xtermGetFont(screen->initial_font);
9618	if (result >= 0)
9619	    screen->menu_font_number = result;
9620    }
9621#if OPT_BROKEN_OSC
9622    init_Bres(screen.brokenLinuxOSC);
9623#endif
9624
9625#if OPT_BROKEN_ST
9626    init_Bres(screen.brokenStringTerm);
9627#endif
9628
9629#if OPT_C1_PRINT
9630    init_Bres(screen.c1_printable);
9631#endif
9632
9633#if OPT_CLIP_BOLD
9634    init_Bres(screen.use_border_clipping);
9635    init_Bres(screen.use_clipping);
9636#endif
9637
9638#if OPT_DEC_CHRSET
9639    init_Bres(screen.font_doublesize);
9640    init_Ires(screen.cache_doublesize);
9641    if (screen->cache_doublesize > NUM_CHRSET)
9642	screen->cache_doublesize = NUM_CHRSET;
9643    if (screen->cache_doublesize == 0)
9644	screen->font_doublesize = False;
9645    TRACE(("Doublesize%s enabled, up to %d fonts\n",
9646	   screen->font_doublesize ? "" : " not",
9647	   screen->cache_doublesize));
9648#endif
9649#if OPT_DEC_RECTOPS
9650    init_Ires(screen.checksum_ext0);
9651    screen->checksum_ext = screen->checksum_ext0;
9652#endif
9653
9654#if OPT_ISO_COLORS
9655    init_Ires(screen.veryBoldColors);
9656    init_Bres(screen.boldColors);
9657    init_Bres(screen.colorAttrMode);
9658    init_Bres(screen.colorBDMode);
9659    init_Bres(screen.colorBLMode);
9660    init_Bres(screen.colorMode);
9661    init_Bres(screen.colorULMode);
9662    init_Bres(screen.italicULMode);
9663    init_Bres(screen.colorRVMode);
9664
9665#if OPT_WIDE_ATTRS
9666    init_Bres(screen.colorITMode);
9667#endif
9668#if OPT_DIRECT_COLOR
9669    init_Bres(screen.direct_color);
9670#endif
9671
9672#if OPT_COLOR_RES2
9673    TRACE(("...will fake resources for color%d to color%d\n",
9674	   MIN_ANSI_COLORS,
9675	   NUM_ANSI_COLORS - 1));
9676#endif
9677    for (i = 0, color_ok = False; i < MAXCOLORS; i++) {
9678
9679#if OPT_COLOR_RES2
9680	/*
9681	 * Xt has a hardcoded limit on the maximum number of resources that can
9682	 * be used in a widget.  If we configure both luit (which implies
9683	 * wide-characters) and 256-colors, it goes over that limit.  Most
9684	 * people would not need a resource-file with 256-colors; the default
9685	 * values in our table are sufficient.  In that case, fake the resource
9686	 * setting by copying the default value from the table.  The #define's
9687	 * can be overridden to make these true resources.
9688	 */
9689	if (i >= MIN_ANSI_COLORS && i < NUM_ANSI_COLORS) {
9690	    screen->Acolors[i].resource =
9691		x_strtrim(fake_resources[i - MIN_ANSI_COLORS].default_addr);
9692	    if (screen->Acolors[i].resource == 0)
9693		screen->Acolors[i].resource = XtDefaultForeground;
9694	} else
9695#endif /* OPT_COLOR_RES2 */
9696	{
9697	    screen->Acolors[i] = TScreenOf(request)->Acolors[i];
9698	    screen->Acolors[i].resource =
9699		x_strtrim(screen->Acolors[i].resource);
9700	}
9701
9702#if OPT_COLOR_RES
9703	TRACE(("Acolors[%d] = %s\n", i, screen->Acolors[i].resource));
9704	screen->Acolors[i].mode = False;
9705	if (DftFg(Acolors[i])) {
9706	    screen->Acolors[i].value = T_COLOR(screen, TEXT_FG);
9707	    screen->Acolors[i].mode = True;
9708	} else if (DftBg(Acolors[i])) {
9709	    screen->Acolors[i].value = T_COLOR(screen, TEXT_BG);
9710	    screen->Acolors[i].mode = True;
9711	} else {
9712	    color_ok = True;
9713	}
9714#else
9715	TRACE(("Acolors[%d] = %#lx\n", i, TScreenOf(request)->Acolors[i]));
9716	if (screen->Acolors[i] != wnew->dft_foreground &&
9717	    screen->Acolors[i] != T_COLOR(screen, TEXT_FG) &&
9718	    screen->Acolors[i] != T_COLOR(screen, TEXT_BG))
9719	    color_ok = True;
9720#endif
9721    }
9722
9723    /*
9724     * Check if we're trying to use color in a monochrome screen.  Disable
9725     * color in that case, since that would make ANSI colors unusable.  A 4-bit
9726     * or 8-bit display is usable, so we do not have to check for anything more
9727     * specific.
9728     */
9729    if (color_ok) {
9730	if (getVisualDepth(wnew) <= 1) {
9731	    TRACE(("disabling color since screen is monochrome\n"));
9732	    color_ok = False;
9733	}
9734    }
9735
9736    /* If none of the colors are anything other than the foreground or
9737     * background, we'll assume this isn't color, no matter what the colorMode
9738     * resource says.  (There doesn't seem to be any good way to determine if
9739     * the resource lookup failed versus the user having misconfigured this).
9740     */
9741    if (!color_ok) {
9742	screen->colorMode = False;
9743	TRACE(("All colors are foreground or background: disable colorMode\n"));
9744    }
9745    wnew->sgr_foreground = -1;
9746    wnew->sgr_background = -1;
9747    wnew->sgr_38_xcolors = False;
9748    clrDirectFG(wnew->flags);
9749    clrDirectFG(wnew->flags);
9750#endif /* OPT_ISO_COLORS */
9751
9752    /*
9753     * Decode the resources that control the behavior on multiple mouse clicks.
9754     * A single click is always bound to normal character selection, but the
9755     * other flavors can be changed.
9756     */
9757    for (i = 0; i < NSELECTUNITS; ++i) {
9758	int ck = (i + 1);
9759	screen->maxClicks = ck;
9760	if (i == Select_CHAR)
9761	    screen->selectMap[i] = Select_CHAR;
9762	else if (TScreenOf(request)->onClick[i] != 0)
9763	    ParseOnClicks(wnew, request, (unsigned) i);
9764	else if (i <= Select_LINE)
9765	    screen->selectMap[i] = (SelectUnit) i;
9766	else
9767	    break;
9768#if OPT_XRES_QUERY
9769	init_Sres(screen.onClick[i]);
9770#endif
9771	TRACE(("on%dClicks %s=%d\n", ck,
9772	       NonNull(TScreenOf(request)->onClick[i]),
9773	       screen->selectMap[i]));
9774	if (screen->selectMap[i] == NSELECTUNITS)
9775	    break;
9776    }
9777    TRACE(("maxClicks %d\n", screen->maxClicks));
9778
9779    init_Tres(MOUSE_FG);
9780    init_Tres(MOUSE_BG);
9781    init_Tres(TEXT_CURSOR);
9782#if OPT_HIGHLIGHT_COLOR
9783    init_Tres(HIGHLIGHT_BG);
9784    init_Tres(HIGHLIGHT_FG);
9785    init_Bres(screen.hilite_reverse);
9786    init_Mres(screen.hilite_color);
9787    if (screen->hilite_color == Maybe) {
9788	screen->hilite_color = False;
9789#if OPT_COLOR_RES
9790	/*
9791	 * If the highlight text/background are both set, and if they are
9792	 * not equal to either the text/background or background/text, then
9793	 * set the highlightColorMode automatically.
9794	 */
9795	if (!DftFg(Tcolors[HIGHLIGHT_BG])
9796	    && !DftBg(Tcolors[HIGHLIGHT_FG])
9797	    && !TxtFg(Tcolors[HIGHLIGHT_BG])
9798	    && !TxtBg(Tcolors[HIGHLIGHT_FG])
9799	    && !TxtBg(Tcolors[HIGHLIGHT_BG])
9800	    && !TxtFg(Tcolors[HIGHLIGHT_FG])) {
9801	    TRACE(("...setting hilite_color automatically\n"));
9802	    screen->hilite_color = True;
9803	}
9804#endif
9805    }
9806#endif
9807
9808#if OPT_TEK4014
9809    /*
9810     * The Tek4014 window has no separate resources for foreground, background
9811     * and cursor color.  Since xterm always creates the vt100 widget first, we
9812     * can set the Tektronix colors here.  That lets us use escape sequences to
9813     * set its dynamic colors and get consistent behavior whether or not the
9814     * window is displayed.
9815     */
9816    screen->Tcolors[TEK_BG] = screen->Tcolors[TEXT_BG];
9817    screen->Tcolors[TEK_FG] = screen->Tcolors[TEXT_FG];
9818    screen->Tcolors[TEK_CURSOR] = screen->Tcolors[TEXT_CURSOR];
9819#endif
9820
9821#ifdef SCROLLBAR_RIGHT
9822    init_Bres(misc.useRight);
9823#endif
9824
9825#if OPT_RENDERFONT
9826    init_Ires(misc.limit_fontsets);
9827    wnew->work.max_fontsets = (unsigned) wnew->misc.limit_fontsets;
9828
9829    init_Sres(misc.render_font_s);
9830    wnew->work.render_font =
9831	(Boolean) extendedBoolean(wnew->misc.render_font_s,
9832				  tblRenderFont, erLast);
9833    if (wnew->work.render_font == erDefault) {
9834	if (IsEmpty(CurrentXftFont(wnew))) {
9835	    free((void *) CurrentXftFont(wnew));
9836	    CurrentXftFont(wnew) = x_strdup(DEFFACENAME_AUTO);
9837	    TRACE(("will allow runtime switch to render_font using \"%s\"\n",
9838		   CurrentXftFont(wnew)));
9839	} else {
9840	    wnew->work.render_font = erTrue;
9841	    TRACE(("initially using TrueType font\n"));
9842	}
9843    } else if (wnew->work.render_font == erDefaultOff) {
9844	wnew->work.render_font = erFalse;
9845    }
9846    /* minor tweak to make debug traces consistent: */
9847    if (wnew->work.render_font) {
9848	if (IsEmpty(CurrentXftFont(wnew))) {
9849	    wnew->work.render_font = False;
9850	    TRACE(("reset render_font since there is no face_name\n"));
9851	}
9852    }
9853#endif
9854
9855#if OPT_WIDE_CHARS
9856    /* setup data for next call */
9857    init_Sres(screen.utf8_mode_s);
9858    request->screen.utf8_mode =
9859	extendedBoolean(request->screen.utf8_mode_s, tblUtf8Mode, uLast);
9860
9861    init_Sres(screen.utf8_fonts_s);
9862    request->screen.utf8_fonts =
9863	extendedBoolean(request->screen.utf8_fonts_s, tblUtf8Mode, uLast);
9864
9865    init_Sres(screen.utf8_title_s);
9866    request->screen.utf8_title =
9867	extendedBoolean(request->screen.utf8_title_s, tblUtf8Mode, uLast);
9868
9869    /*
9870     * Make a copy in the input/request so that DefaultFontN() works for
9871     * the "CHECKFONT" option.
9872     */
9873    copyFontList(&(request->work.fonts.x11.list_n),
9874		 wnew->work.fonts.x11.list_n);
9875
9876    VTInitialize_locale(request);
9877    init_Bres(screen.normalized_c);
9878    init_Bres(screen.utf8_latin1);
9879    init_Bres(screen.utf8_weblike);
9880
9881#if OPT_LUIT_PROG
9882    init_Bres(misc.callfilter);
9883    init_Bres(misc.use_encoding);
9884    init_Sres(misc.locale_str);
9885    init_Sres(misc.localefilter);
9886#endif
9887
9888    init_Ires(screen.utf8_inparse);
9889    init_Ires(screen.utf8_mode);
9890    init_Ires(screen.utf8_fonts);
9891    init_Ires(screen.utf8_title);
9892    init_Ires(screen.max_combining);
9893
9894    init_Ires(screen.utf8_always);	/* from utf8_mode, used in doparse */
9895
9896    if (screen->max_combining < 0) {
9897	screen->max_combining = 0;
9898    }
9899    if (screen->max_combining > 5) {
9900	screen->max_combining = 5;
9901    }
9902
9903    init_Bres(screen.vt100_graphics);
9904    init_Bres(screen.wide_chars);
9905    init_Bres(misc.mk_width);
9906    init_Bres(misc.cjk_width);
9907
9908    init_Ires(misc.mk_samplesize);
9909    init_Ires(misc.mk_samplepass);
9910
9911    if (wnew->misc.mk_samplesize > 0xffff)
9912	wnew->misc.mk_samplesize = 0xffff;
9913    if (wnew->misc.mk_samplesize < 0)
9914	wnew->misc.mk_samplesize = 0;
9915
9916    if (wnew->misc.mk_samplepass > wnew->misc.mk_samplesize)
9917	wnew->misc.mk_samplepass = wnew->misc.mk_samplesize;
9918    if (wnew->misc.mk_samplepass < 0)
9919	wnew->misc.mk_samplepass = 0;
9920
9921    if (TScreenOf(request)->utf8_mode) {
9922	TRACE(("setting wide_chars on\n"));
9923	screen->wide_chars = True;
9924    } else {
9925	TRACE(("setting utf8_mode to 0\n"));
9926	screen->utf8_mode = uFalse;
9927    }
9928    mk_wcwidth_init(screen->utf8_mode);
9929    TRACE(("initialized UTF-8 mode to %d\n", screen->utf8_mode));
9930
9931#if OPT_MINI_LUIT
9932    if (TScreenOf(request)->latin9_mode) {
9933	screen->latin9_mode = True;
9934    }
9935    if (TScreenOf(request)->unicode_font) {
9936	screen->unicode_font = True;
9937    }
9938    TRACE(("initialized Latin9 mode to %d\n", screen->latin9_mode));
9939    TRACE(("initialized unicode_font to %d\n", screen->unicode_font));
9940#endif
9941
9942    decode_wcwidth(wnew);
9943    xtermSaveVTFonts(wnew);
9944#endif /* OPT_WIDE_CHARS */
9945
9946    init_Sres(screen.eight_bit_meta_s);
9947    wnew->screen.eight_bit_meta =
9948	extendedBoolean(request->screen.eight_bit_meta_s, tbl8BitMeta, ebLast);
9949    if (wnew->screen.eight_bit_meta == ebLocale) {
9950#if OPT_WIDE_CHARS
9951	if (xtermEnvUTF8()) {
9952	    wnew->screen.eight_bit_meta = ebFalse;
9953	    TRACE(("...eightBitMeta is false due to locale\n"));
9954	} else
9955#endif /* OPT_WIDE_CHARS */
9956	{
9957	    wnew->screen.eight_bit_meta = ebTrue;
9958	    TRACE(("...eightBitMeta is true due to locale\n"));
9959	}
9960    }
9961
9962    init_Bres(screen.always_bold_mode);
9963    init_Bres(screen.bold_mode);
9964    init_Bres(screen.underline);
9965
9966    wnew->cur_foreground = 0;
9967    wnew->cur_background = 0;
9968
9969    wnew->keyboard.flags = MODE_SRM;
9970
9971    if (screen->backarrow_key)
9972	wnew->keyboard.flags |= MODE_DECBKM;
9973    TRACE(("initialized DECBKM %s\n",
9974	   BtoS(wnew->keyboard.flags & MODE_DECBKM)));
9975
9976#if OPT_SIXEL_GRAPHICS
9977    init_Bres(screen.sixel_scrolling);
9978    if (screen->sixel_scrolling)
9979	wnew->keyboard.flags |= MODE_DECSDM;
9980    TRACE(("initialized DECSDM %s\n",
9981	   BtoS(wnew->keyboard.flags & MODE_DECSDM)));
9982#endif
9983
9984#if OPT_GRAPHICS
9985    init_Sres(screen.graph_termid);
9986    screen->graphics_termid = decodeTerminalID(TScreenOf(request)->graph_termid);
9987    switch (screen->graphics_termid) {
9988    case 125:
9989    case 240:
9990    case 241:
9991    case 330:
9992    case 340:
9993    case 382:
9994	break;
9995    default:
9996	screen->graphics_termid = 0;
9997	break;
9998    }
9999    TRACE(("graph_termid '%s' -> graphics_termid %d\n",
10000	   screen->graph_termid,
10001	   screen->graphics_termid));
10002
10003    init_Ires(screen.numcolorregisters);
10004    TRACE(("initialized NUM_COLOR_REGISTERS to resource default: %d\n",
10005	   screen->numcolorregisters));
10006
10007    init_Bres(screen.privatecolorregisters);	/* FIXME: should this be off unconditionally here? */
10008    TRACE(("initialized PRIVATE_COLOR_REGISTERS to resource default: %s\n",
10009	   BtoS(screen->privatecolorregisters)));
10010#endif
10011
10012#if OPT_GRAPHICS
10013    {
10014	int native_w, native_h;
10015
10016	switch (GraphicsTermId(screen)) {
10017	case 125:
10018	    native_w = 768;
10019	    native_h = 460;
10020	    break;
10021	case 240:
10022	    /* FALLTHRU */
10023	case 241:
10024	    native_w = 800;
10025	    native_h = 460;
10026	    break;
10027	case 330:
10028	    /* FALLTHRU */
10029	case 340:
10030	    native_w = 800;
10031	    native_h = 480;
10032	    break;
10033	default:
10034	    native_w = 800;
10035	    native_h = 480;
10036	    break;
10037	case 382:
10038	    native_w = 960;
10039	    native_h = 750;
10040	    break;
10041	}
10042
10043# if OPT_REGIS_GRAPHICS
10044	init_Sres(screen.graphics_regis_default_font);
10045	TRACE(("default ReGIS font: %s\n",
10046	       screen->graphics_regis_default_font));
10047
10048	init_Sres(screen.graphics_regis_screensize);
10049	screen->graphics_regis_def_high = 1000;
10050	screen->graphics_regis_def_wide = 1000;
10051	if (!x_strcasecmp(screen->graphics_regis_screensize, "auto")) {
10052	    TRACE(("setting default ReGIS screensize based on graphics_id %d\n",
10053		   GraphicsTermId(screen)));
10054	    screen->graphics_regis_def_high = (Dimension) native_h;
10055	    screen->graphics_regis_def_wide = (Dimension) native_w;
10056	} else {
10057	    int conf_high;
10058	    int conf_wide;
10059	    char ignore;
10060
10061	    if (sscanf(screen->graphics_regis_screensize,
10062		       "%dx%d%c",
10063		       &conf_wide,
10064		       &conf_high,
10065		       &ignore) == 2) {
10066		if (conf_high > 0 && conf_wide > 0) {
10067		    screen->graphics_regis_def_high =
10068			(Dimension) conf_high;
10069		    screen->graphics_regis_def_wide =
10070			(Dimension) conf_wide;
10071		} else {
10072		    TRACE(("ignoring invalid regisScreenSize %s\n",
10073			   screen->graphics_regis_screensize));
10074		}
10075	    } else {
10076		TRACE(("ignoring invalid regisScreenSize %s\n",
10077		       screen->graphics_regis_screensize));
10078	    }
10079	}
10080	TRACE(("default ReGIS graphics screensize %dx%d\n",
10081	       (int) screen->graphics_regis_def_wide,
10082	       (int) screen->graphics_regis_def_high));
10083# endif
10084
10085	init_Sres(screen.graphics_max_size);
10086	screen->graphics_max_high = 1000;
10087	screen->graphics_max_wide = 1000;
10088	if (!x_strcasecmp(screen->graphics_max_size, "auto")) {
10089	    TRACE(("setting max graphics screensize based on graphics_id %d\n",
10090		   GraphicsTermId(screen)));
10091	    screen->graphics_max_high = (Dimension) native_h;
10092	    screen->graphics_max_wide = (Dimension) native_w;
10093	} else {
10094	    int conf_high;
10095	    int conf_wide;
10096	    char ignore;
10097
10098	    if (sscanf(screen->graphics_max_size,
10099		       "%dx%d%c",
10100		       &conf_wide,
10101		       &conf_high,
10102		       &ignore) == 2) {
10103		if (conf_high > 0 && conf_wide > 0) {
10104		    screen->graphics_max_high = (Dimension) conf_high;
10105		    screen->graphics_max_wide = (Dimension) conf_wide;
10106		} else {
10107		    TRACE(("ignoring invalid maxGraphicSize %s\n",
10108			   screen->graphics_max_size));
10109		}
10110	    } else {
10111		TRACE(("ignoring invalid maxGraphicSize %s\n",
10112		       screen->graphics_max_size));
10113	    }
10114	}
10115# if OPT_REGIS_GRAPHICS
10116	/* Make sure the max is large enough for the default ReGIS size. */
10117	if (screen->graphics_regis_def_high >
10118	    screen->graphics_max_high) {
10119	    screen->graphics_max_high =
10120		screen->graphics_regis_def_high;
10121	}
10122	if (screen->graphics_regis_def_wide >
10123	    screen->graphics_max_wide) {
10124	    screen->graphics_max_wide =
10125		screen->graphics_regis_def_wide;
10126	}
10127# endif
10128	TRACE(("max graphics screensize %dx%d\n",
10129	       (int) screen->graphics_max_wide,
10130	       (int) screen->graphics_max_high));
10131    }
10132#endif
10133
10134#if OPT_SIXEL_GRAPHICS
10135    init_Bres(screen.sixel_scrolls_right);
10136#endif
10137#if OPT_PRINT_GRAPHICS
10138    init_Bres(screen.graphics_print_to_host);
10139    init_Bres(screen.graphics_expanded_print_mode);
10140    init_Bres(screen.graphics_print_color_mode);
10141    init_Bres(screen.graphics_print_color_syntax);
10142    init_Bres(screen.graphics_print_background_mode);
10143    init_Bres(screen.graphics_rotated_print_mode);
10144#endif
10145
10146    /* look for focus related events on the shell, because we need
10147     * to care about the shell's border being part of our focus.
10148     */
10149    TRACE(("adding event handlers for my_parent %p\n", (void *) my_parent));
10150    XtAddEventHandler(my_parent, EnterWindowMask, False,
10151		      HandleEnterWindow, (Opaque) NULL);
10152    XtAddEventHandler(my_parent, LeaveWindowMask, False,
10153		      HandleLeaveWindow, (Opaque) NULL);
10154    XtAddEventHandler(my_parent, FocusChangeMask, False,
10155		      HandleFocusChange, (Opaque) NULL);
10156    XtAddEventHandler((Widget) wnew, 0L, True,
10157		      VTNonMaskableEvent, (Opaque) NULL);
10158    XtAddEventHandler((Widget) wnew, PropertyChangeMask, False,
10159		      HandleBellPropertyChange, (Opaque) NULL);
10160
10161#if HANDLE_STRUCT_NOTIFY
10162#if OPT_TOOLBAR
10163    wnew->VT100_TB_INFO(menu_bar) = request->VT100_TB_INFO(menu_bar);
10164    init_Ires(VT100_TB_INFO(menu_height));
10165#endif
10166    XtAddEventHandler(my_parent, MappingNotify | StructureNotifyMask, False,
10167		      HandleStructNotify, (Opaque) 0);
10168#endif /* HANDLE_STRUCT_NOTIFY */
10169
10170    screen->bellInProgress = False;
10171
10172    set_character_class(screen->charClass);
10173#if OPT_REPORT_CCLASS
10174    if (resource.reportCClass)
10175	report_char_class(wnew);
10176#endif
10177
10178    /* create it, but don't realize it */
10179    ScrollBarOn(wnew, True);
10180
10181    /* make sure that the resize gravity acceptable */
10182    if (!GravityIsNorthWest(wnew) &&
10183	!GravityIsSouthWest(wnew)) {
10184	char value[80];
10185	String temp[2];
10186	Cardinal nparams = 1;
10187
10188	sprintf(value, "%d", wnew->misc.resizeGravity);
10189	temp[0] = value;
10190	temp[1] = 0;
10191	XtAppWarningMsg(app_con, "rangeError", "resizeGravity", "XTermError",
10192			"unsupported resizeGravity resource value (%s)",
10193			temp, &nparams);
10194	wnew->misc.resizeGravity = SouthWestGravity;
10195    }
10196#ifndef NO_ACTIVE_ICON
10197    screen->whichVwin = &screen->fullVwin;
10198#endif /* NO_ACTIVE_ICON */
10199
10200    init_Ires(screen.unparse_max);
10201    if ((int) screen->unparse_max < 256)
10202	screen->unparse_max = 256;
10203    screen->unparse_bfr = (IChar *) (void *) XtCalloc(screen->unparse_max,
10204						      (Cardinal) sizeof(IChar));
10205
10206    if (screen->savelines < 0)
10207	screen->savelines = 0;
10208
10209    init_Bres(screen.awaitInput);
10210
10211    wnew->flags = 0;
10212    if (!screen->jumpscroll)
10213	wnew->flags |= SMOOTHSCROLL;
10214    if (wnew->misc.reverseWrap)
10215	wnew->flags |= REVERSEWRAP;
10216    if (wnew->misc.autoWrap)
10217	wnew->flags |= WRAPAROUND;
10218    if (wnew->misc.re_verse != wnew->misc.re_verse0)
10219	wnew->flags |= REVERSE_VIDEO;
10220    if (screen->c132)
10221	wnew->flags |= IN132COLUMNS;
10222
10223    wnew->initflags = wnew->flags;
10224
10225    init_Sres(keyboard.shift_escape_s);
10226    wnew->keyboard.shift_escape =
10227	extendedBoolean(wnew->keyboard.shift_escape_s, tblShift2S, ssLAST);
10228
10229#if OPT_MOD_FKEYS
10230    init_Ires(keyboard.modify_1st.allow_keys);
10231    init_Ires(keyboard.modify_1st.cursor_keys);
10232    init_Ires(keyboard.modify_1st.function_keys);
10233    init_Ires(keyboard.modify_1st.keypad_keys);
10234    init_Ires(keyboard.modify_1st.other_keys);
10235    init_Ires(keyboard.modify_1st.string_keys);
10236    init_Ires(keyboard.format_keys);
10237    wnew->keyboard.modify_now = wnew->keyboard.modify_1st;
10238#endif
10239
10240    init_Ires(misc.appcursorDefault);
10241    if (wnew->misc.appcursorDefault)
10242	wnew->keyboard.flags |= MODE_DECCKM;
10243
10244    init_Ires(misc.appkeypadDefault);
10245    if (wnew->misc.appkeypadDefault)
10246	wnew->keyboard.flags |= MODE_DECKPAM;
10247
10248    initLineData(wnew);
10249#if OPT_WIDE_CHARS
10250    freeFontList(&(request->work.fonts.x11.list_n));
10251#endif
10252#if OPT_XRES_QUERY
10253    if (resource.reportXRes)
10254	reportResources(wnew);
10255#endif
10256    xtermResetLocale(LC_NUMERIC, saveLocale);
10257    TRACE(("" TRACE_R " VTInitialize\n"));
10258    return;
10259}
10260
10261void
10262releaseCursorGCs(XtermWidget xw)
10263{
10264    TScreen *screen = TScreenOf(xw);
10265    VTwin *win = WhichVWin(screen);
10266    int n;
10267
10268    for_each_curs_gc(n) {
10269	freeCgs(xw, win, (CgsEnum) n);
10270    }
10271}
10272
10273void
10274releaseWindowGCs(XtermWidget xw, VTwin *win)
10275{
10276    int n;
10277
10278    for_each_text_gc(n) {
10279	switch (n) {
10280	case gcBorder:
10281	case gcFiller:
10282	    break;
10283	default:
10284	    freeCgs(xw, win, (CgsEnum) n);
10285	    break;
10286	}
10287    }
10288}
10289
10290#define TRACE_FREE_LEAK(name) \
10291	if (name) { \
10292	    TRACE(("freed " #name ": %p\n", (const void *) name)); \
10293	    FreeAndNull(name); \
10294	}
10295
10296#define TRACE_FREE_GC(name,part) \
10297	if (part) { \
10298	    TRACE(("freed %s " #part ": %p\n", name, (const void *) part)); \
10299	    XFreeGC(dpy, part); \
10300	    part = 0; \
10301	}
10302
10303#if OPT_INPUT_METHOD
10304static void
10305cleanupInputMethod(XtermWidget xw)
10306{
10307    TInput *input = lookupTInput(xw, (Widget) xw);
10308
10309    if (input && input->xim) {
10310	XCloseIM(input->xim);
10311	input->xim = 0;
10312	TRACE(("freed screen->xim\n"));
10313    }
10314}
10315#else
10316#define cleanupInputMethod(xw)	/* nothing */
10317#endif
10318
10319#ifdef NO_LEAKS
10320#define FREE_VT_WIN(name) freeVTwin(dpy, #name, &(screen->name))
10321static void
10322freeVTwin(Display *dpy, const char *whichWin, VTwin *win)
10323{
10324    TRACE_FREE_GC(whichWin, win->filler_gc);
10325    TRACE_FREE_GC(whichWin, win->border_gc);
10326    TRACE_FREE_GC(whichWin, win->marker_gc[0]);
10327    TRACE_FREE_GC(whichWin, win->marker_gc[1]);
10328}
10329#endif
10330
10331static void
10332VTDestroy(Widget w GCC_UNUSED)
10333{
10334#ifdef NO_LEAKS
10335    XtermWidget xw = (XtermWidget) w;
10336    TScreen *screen = TScreenOf(xw);
10337    Display *dpy = screen->display;
10338    Cardinal n, k;
10339
10340    StopBlinking(xw);
10341
10342    if (screen->scrollWidget) {
10343	XtUninstallTranslations(screen->scrollWidget);
10344	XtDestroyWidget(screen->scrollWidget);
10345    }
10346#if OPT_FIFO_LINES
10347    while (screen->saved_fifo > 0) {
10348	deleteScrollback(screen);
10349    }
10350#endif
10351    while (screen->save_title != 0) {
10352	SaveTitle *last = screen->save_title;
10353	screen->save_title = last->next;
10354	free(last->iconName);
10355	free(last->windowName);
10356	free(last);
10357    }
10358#ifndef NO_ACTIVE_ICON
10359    TRACE_FREE_LEAK(xw->misc.active_icon_s);
10360#endif
10361#if OPT_ISO_COLORS
10362    TRACE_FREE_LEAK(screen->cmap_data);
10363    for (n = 0; n < MAXCOLORS; n++) {
10364	TRACE_FREE_LEAK(screen->Acolors[n].resource);
10365    }
10366    for (n = 0; n < MAX_SAVED_SGR; n++) {
10367	TRACE_FREE_LEAK(xw->saved_colors.palettes[n]);
10368    }
10369#endif
10370#if OPT_COLOR_RES
10371    for (n = 0; n < NCOLORS; n++) {
10372	switch (n) {
10373#if OPT_TEK4014
10374	case TEK_BG:
10375	    /* FALLTHRU */
10376	case TEK_FG:
10377	    /* FALLTHRU */
10378	case TEK_CURSOR:
10379	    break;
10380#endif
10381	default:
10382	    TRACE_FREE_LEAK(screen->Tcolors[n].resource);
10383	    break;
10384	}
10385    }
10386#endif
10387    FreeMarkGCs(xw);
10388    TRACE_FREE_LEAK(screen->unparse_bfr);
10389    TRACE_FREE_LEAK(screen->save_ptr);
10390    TRACE_FREE_LEAK(screen->saveBuf_data);
10391    TRACE_FREE_LEAK(screen->saveBuf_index);
10392    for (n = 0; n < 2; ++n) {
10393	TRACE_FREE_LEAK(screen->editBuf_data[n]);
10394	TRACE_FREE_LEAK(screen->editBuf_index[n]);
10395    }
10396    TRACE_FREE_LEAK(screen->keyboard_dialect);
10397    TRACE_FREE_LEAK(screen->cursor_font_name);
10398    TRACE_FREE_LEAK(screen->pointer_shape);
10399    TRACE_FREE_LEAK(screen->term_id);
10400#if OPT_WIDE_CHARS
10401    TRACE_FREE_LEAK(screen->utf8_mode_s);
10402    TRACE_FREE_LEAK(screen->utf8_fonts_s);
10403    TRACE_FREE_LEAK(screen->utf8_title_s);
10404#if OPT_LUIT_PROG
10405    TRACE_FREE_LEAK(xw->misc.locale_str);
10406    TRACE_FREE_LEAK(xw->misc.localefilter);
10407#endif
10408#endif
10409    TRACE_FREE_LEAK(xw->misc.T_geometry);
10410    TRACE_FREE_LEAK(xw->misc.geo_metry);
10411#if OPT_INPUT_METHOD
10412    cleanupInputMethod(xw);
10413    TRACE_FREE_LEAK(xw->misc.f_x);
10414    TRACE_FREE_LEAK(xw->misc.input_method);
10415    TRACE_FREE_LEAK(xw->misc.preedit_type);
10416#endif
10417    releaseCursorGCs(xw);
10418    releaseWindowGCs(xw, &(screen->fullVwin));
10419#ifndef NO_ACTIVE_ICON
10420    XFreeFont(screen->display, getIconicFont(screen)->fs);
10421    releaseWindowGCs(xw, &(screen->iconVwin));
10422#endif
10423    XtUninstallTranslations((Widget) xw);
10424#if OPT_TOOLBAR
10425    XtUninstallTranslations((Widget) XtParent(xw));
10426#endif
10427    XtUninstallTranslations((Widget) SHELL_OF(xw));
10428
10429    if (screen->hidden_cursor)
10430	XFreeCursor(screen->display, screen->hidden_cursor);
10431
10432    xtermCloseFonts(xw, screen->fnts);
10433#if OPT_WIDE_ATTRS
10434    xtermCloseFonts(xw, screen->ifnts);
10435#endif
10436    noleaks_cachedCgs(xw);
10437    free_termcap(xw);
10438
10439    FREE_VT_WIN(fullVwin);
10440#ifndef NO_ACTIVE_ICON
10441    FREE_VT_WIN(iconVwin);
10442#endif /* NO_ACTIVE_ICON */
10443
10444    TRACE_FREE_LEAK(screen->selection_targets_8bit);
10445#if OPT_SELECT_REGEX
10446    for (n = 0; n < NSELECTUNITS; ++n) {
10447	if (screen->selectMap[n] == Select_REGEX) {
10448	    TRACE_FREE_LEAK(screen->selectExpr[n]);
10449	}
10450    }
10451#endif
10452
10453#if OPT_RENDERFONT
10454    for (n = 0; n < NMENUFONTS; ++n) {
10455	int e;
10456	for (e = 0; e < fMAX; ++e) {
10457	    xtermCloseXft(screen, getMyXftFont(xw, e, (int) n));
10458	}
10459    }
10460    discardRenderDraw(screen);
10461    {
10462	ListXftFonts *p;
10463	while ((p = screen->list_xft_fonts) != 0) {
10464	    screen->list_xft_fonts = p->next;
10465	    free(p);
10466	}
10467    }
10468#endif
10469
10470    /* free things allocated via init_Sres or Init_Sres2 */
10471#ifndef NO_ACTIVE_ICON
10472    TRACE_FREE_LEAK(screen->icon_fontname);
10473#endif
10474#ifdef ALLOWLOGGING
10475    TRACE_FREE_LEAK(screen->logfile);
10476#endif
10477    TRACE_FREE_LEAK(screen->eight_bit_meta_s);
10478    TRACE_FREE_LEAK(screen->charClass);
10479    TRACE_FREE_LEAK(screen->answer_back);
10480    TRACE_FREE_LEAK(screen->printer_state.printer_command);
10481    TRACE_FREE_LEAK(screen->disallowedColorOps);
10482    TRACE_FREE_LEAK(screen->disallowedFontOps);
10483    TRACE_FREE_LEAK(screen->disallowedMouseOps);
10484    TRACE_FREE_LEAK(screen->disallowedPasteControls);
10485    TRACE_FREE_LEAK(screen->disallowedTcapOps);
10486    TRACE_FREE_LEAK(screen->disallowedWinOps);
10487    TRACE_FREE_LEAK(screen->default_string);
10488    TRACE_FREE_LEAK(screen->eightbit_select_types);
10489
10490#if OPT_WIDE_CHARS
10491    TRACE_FREE_LEAK(screen->utf8_select_types);
10492#endif
10493
10494#if 0
10495    for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; n++) {
10496	TRACE_FREE_LEAK(screen->MenuFontName(n));
10497    }
10498#endif
10499
10500    TRACE_FREE_LEAK(screen->initial_font);
10501
10502#if OPT_LUIT_PROG
10503    TRACE_FREE_LEAK(xw->misc.locale_str);
10504    TRACE_FREE_LEAK(xw->misc.localefilter);
10505#endif
10506
10507#if OPT_RENDERFONT
10508    TRACE_FREE_LEAK(xw->misc.default_xft.f_n);
10509#if OPT_WIDE_CHARS
10510    TRACE_FREE_LEAK(xw->misc.default_xft.f_w);
10511#endif
10512    TRACE_FREE_LEAK(xw->misc.render_font_s);
10513#endif
10514
10515    TRACE_FREE_LEAK(xw->misc.default_font.f_n);
10516    TRACE_FREE_LEAK(xw->misc.default_font.f_b);
10517
10518#if OPT_WIDE_CHARS
10519    TRACE_FREE_LEAK(xw->misc.default_font.f_w);
10520    TRACE_FREE_LEAK(xw->misc.default_font.f_wb);
10521#endif
10522
10523    TRACE_FREE_LEAK(xw->work.wm_name);
10524    freeFontLists(&(xw->work.fonts.x11));
10525#if OPT_RENDERFONT
10526    freeFontLists(&(xw->work.fonts.xft));
10527#endif
10528
10529    xtermFontName(NULL);
10530#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS
10531    TRACE_FREE_LEAK(screen->cacheVTFonts.default_font.f_n);
10532    TRACE_FREE_LEAK(screen->cacheVTFonts.default_font.f_b);
10533#if OPT_WIDE_CHARS
10534    TRACE_FREE_LEAK(screen->cacheVTFonts.default_font.f_w);
10535    TRACE_FREE_LEAK(screen->cacheVTFonts.default_font.f_wb);
10536#endif
10537    freeFontLists(&(screen->cacheVTFonts.fonts.x11));
10538    for (n = 0; n < NMENUFONTS; ++n) {
10539	for (k = 0; k < fMAX; ++k) {
10540	    if (screen->menu_font_names[n][k] !=
10541		screen->cacheVTFonts.menu_font_names[n][k]) {
10542		if (screen->menu_font_names[n][k] != _Font_Selected_) {
10543		    TRACE_FREE_LEAK(screen->menu_font_names[n][k]);
10544		}
10545		TRACE_FREE_LEAK(screen->cacheVTFonts.menu_font_names[n][k]);
10546	    } else {
10547		TRACE_FREE_LEAK(screen->menu_font_names[n][k]);
10548	    }
10549	}
10550    }
10551#endif
10552
10553#if OPT_BLINK_CURS
10554    TRACE_FREE_LEAK(screen->cursor_blink_s);
10555#endif
10556
10557#if OPT_REGIS_GRAPHICS
10558    TRACE_FREE_LEAK(screen->graphics_regis_default_font);
10559    TRACE_FREE_LEAK(screen->graphics_regis_screensize);
10560#endif
10561#if OPT_GRAPHICS
10562    TRACE_FREE_LEAK(screen->graph_termid);
10563    TRACE_FREE_LEAK(screen->graphics_max_size);
10564#endif
10565
10566    for (n = 0; n < NSELECTUNITS; ++n) {
10567#if OPT_SELECT_REGEX
10568	TRACE_FREE_LEAK(screen->selectExpr[n]);
10569#endif
10570#if OPT_XRES_QUERY
10571	TRACE_FREE_LEAK(screen->onClick[n]);
10572#endif
10573    }
10574
10575    XtFree((void *) (screen->selection_atoms));
10576
10577    for (n = 0; n < MAX_SELECTIONS; ++n) {
10578	free(screen->selected_cells[n].data_buffer);
10579    }
10580
10581    if (defaultTranslations != xtermClassRec.core_class.tm_table) {
10582	TRACE_FREE_LEAK(defaultTranslations);
10583    }
10584    TRACE_FREE_LEAK(xtermClassRec.core_class.tm_table);
10585    TRACE_FREE_LEAK(xw->keyboard.shift_escape_s);
10586    TRACE_FREE_LEAK(xw->keyboard.extra_translations);
10587    TRACE_FREE_LEAK(xw->keyboard.shell_translations);
10588    TRACE_FREE_LEAK(xw->keyboard.xterm_translations);
10589    TRACE_FREE_LEAK(xw->keyboard.print_translations);
10590    UnmapSelections(xw);
10591
10592    XtFree((void *) (xw->visInfo));
10593
10594#if OPT_WIDE_CHARS
10595    FreeTypedBuffer(XChar2b);
10596    FreeTypedBuffer(char);
10597#endif
10598#if OPT_RENDERFONT
10599#if OPT_RENDERWIDE
10600    FreeTypedBuffer(XftCharSpec);
10601#else
10602    FreeTypedBuffer(XftChar8);
10603#endif
10604#endif
10605
10606    TRACE_FREE_LEAK(myState.print_area);
10607    TRACE_FREE_LEAK(myState.string_area);
10608    memset(&myState, 0, sizeof(myState));
10609
10610#endif /* defined(NO_LEAKS) */
10611}
10612
10613#ifndef NO_ACTIVE_ICON
10614static void *
10615getProperty(Display *dpy,
10616	    Window w,
10617	    Atom req_type,
10618	    const char *prop_name)
10619{
10620    Atom property;
10621    Atom actual_return_type;
10622    int actual_format_return = 0;
10623    unsigned long nitems_return = 0;
10624    unsigned long bytes_after_return = 0;
10625    unsigned char *prop_return = 0;
10626    long long_length = 1024;
10627    size_t limit;
10628    char *result = 0;
10629
10630    TRACE(("getProperty %s(%s)\n", prop_name,
10631	   req_type ? TraceAtomName(dpy, req_type) : "?"));
10632    property = XInternAtom(dpy, prop_name, False);
10633
10634    if (!xtermGetWinProp(dpy,
10635			 w,
10636			 property,
10637			 0L,
10638			 long_length,
10639			 req_type,
10640			 &actual_return_type,
10641			 &actual_format_return,
10642			 &nitems_return,
10643			 &bytes_after_return,
10644			 &prop_return)) {
10645	TRACE((".. Cannot get %s property.\n", prop_name));
10646    } else if (prop_return != 0) {
10647
10648	if (nitems_return != 0 &&
10649	    actual_format_return != 0 &&
10650	    actual_return_type == req_type) {
10651	    /*
10652	     * Null-terminate the result to make string handling easier.
10653	     * The format==8 corresponds to strings, and the number of items
10654	     * is the number of characters.
10655	     */
10656	    if (actual_format_return == 8) {
10657		limit = nitems_return;
10658	    } else {
10659		/* manpage is misleading - X really uses 'long', not 32-bits */
10660		limit = sizeof(long) * nitems_return;
10661	    }
10662	    if ((result = malloc(limit + 1)) != 0) {
10663		memcpy(result, prop_return, limit);
10664		result[limit] = '\0';
10665	    }
10666	    TRACE(("... result %s\n", result ? ("ok") : "null"));
10667	}
10668	XFree(prop_return);
10669    } else {
10670	TRACE((".. no property returned\n"));
10671    }
10672    return (void *) result;
10673}
10674
10675/*
10676 * Active icons are supported by fvwm.  This feature is not supported by
10677 * metacity (gnome) or kwin (kde).  Both metacity and kwin support (in
10678 * incompatible ways, e.g., one uses the icon theme as a fallback for window
10679 * decorations but the other does not, etc, ...) an icon as part of the window
10680 * decoration (usually on the upper-left of the window).
10681 *
10682 * In either case, xterm's icon will only be shown in the window decorations if
10683 * xterm does not use the active icon feature.
10684 *
10685 * This function (tries to) determine the window manager's name, so that we can
10686 * provide a useful automatic default for active icons.  It is based on reading
10687 * wmctrl, which covers most of EWMH and ICCM.
10688 */
10689static char *
10690getWindowManagerName(XtermWidget xw)
10691{
10692    TScreen *screen = TScreenOf(xw);
10693    Display *dpy = screen->display;
10694    Window *sup_window = NULL;
10695    char *result = 0;
10696
10697    TRACE(("getWindowManagerName\n"));
10698#define getWinProp(type, name) \
10699    (Window *)getProperty(dpy, DefaultRootWindow(dpy), type, name)
10700    if ((sup_window = getWinProp(XA_WINDOW, "_NET_SUPPORTING_WM_CHECK")) == 0) {
10701	sup_window = getWinProp(XA_CARDINAL, "_WIN_SUPPORTING_WM_CHECK");
10702    }
10703
10704    /*
10705     * If we found the supporting window, get the property containing the
10706     * window manager's name.  EWMH defines _NET_WM_NAME, while ICCM defines
10707     * WM_CLASS.  There is no standard for the names stored there;
10708     * conventionally it is mixed case.  In practice, the former is more often
10709     * set; the latter is not given (or is a lowercased version of the former).
10710     */
10711    if (sup_window != 0) {
10712#define getStringProp(type,name) \
10713	(char *)getProperty(dpy, *sup_window, type, name)
10714	if ((result = getStringProp(XA_UTF8_STRING(dpy), "_NET_WM_NAME")) == 0
10715	    && (result = getStringProp(XA_STRING, "_NET_WM_NAME")) == 0
10716	    && (result = getStringProp(XA_STRING, "WM_CLASS")) == 0) {
10717	    TRACE(("... window manager does not tell its name\n"));
10718	}
10719	free(sup_window);
10720    } else {
10721	TRACE(("... Cannot get window manager info properties\n"));
10722    }
10723    if (result == 0)
10724	result = x_strdup("unknown");
10725    TRACE(("... window manager name is %s\n", result));
10726    return result;
10727}
10728
10729static Boolean
10730discount_frame_extents(XtermWidget xw, int *high, int *wide)
10731{
10732    TScreen *screen = TScreenOf(xw);
10733    Display *dpy = screen->display;
10734
10735    Atom atom_supported = XInternAtom(dpy, "_NET_FRAME_EXTENTS", False);
10736    Atom actual_type;
10737    int actual_format;
10738    long long_offset = 0;
10739    long long_length = 128;	/* number of items to ask for at a time */
10740    unsigned long nitems;
10741    unsigned long bytes_after;
10742    unsigned char *args;
10743    Boolean rc;
10744
10745    rc = xtermGetWinProp(dpy,
10746			 VShellWindow(xw),
10747			 atom_supported,
10748			 long_offset,
10749			 long_length,
10750			 XA_CARDINAL,	/* req_type */
10751			 &actual_type,	/* actual_type_return */
10752			 &actual_format,	/* actual_format_return */
10753			 &nitems,	/* nitems_return */
10754			 &bytes_after,	/* bytes_after_return */
10755			 &args	/* prop_return */
10756	);
10757
10758    if (rc && args && (nitems == 4) && (actual_format == 32)) {
10759	long *extents = (long *) (void *) args;
10760
10761	TRACE(("_NET_FRAME_EXTENTS:\n"));
10762	TRACE(("   left:   %ld\n", extents[0]));
10763	TRACE(("   right:  %ld\n", extents[1]));
10764	TRACE(("   top:    %ld\n", extents[2]));
10765	TRACE(("   bottom: %ld\n", extents[3]));
10766
10767	if (!x_strncasecmp(xw->work.wm_name, "gnome shell", 11)) {
10768	    *wide -= (int) (extents[0] + extents[1]);	/* -= (left+right) */
10769	    *high -= (int) (extents[2] + extents[3]);	/* -= (top+bottom) */
10770	    TRACE(("...applied extents %d,%d\n", *high, *wide));
10771	} else if (!x_strncasecmp(xw->work.wm_name, "compiz", 6)) {
10772	    /* Ubuntu 16.04 is really off-by-one */
10773	    *wide -= (int) (extents[0] + extents[1] - 1);
10774	    *high -= (int) (extents[2] + extents[3] - 1);
10775	    TRACE(("...applied extents %d,%d\n", *high, *wide));
10776	} else if (!x_strncasecmp(xw->work.wm_name, "fvwm", 4)) {
10777	    TRACE(("...skipping extents\n"));
10778	} else {
10779	    TRACE(("...ignoring extents\n"));
10780	    rc = False;
10781	}
10782    } else {
10783	rc = False;
10784    }
10785    return rc;
10786}
10787#endif /* !NO_ACTIVE_ICON */
10788
10789void
10790initBorderGC(XtermWidget xw, VTwin *win)
10791{
10792    TScreen *screen = TScreenOf(xw);
10793    Pixel filler;
10794
10795    TRACE(("initBorderGC(%s) core bg %#lx, bd %#lx text fg %#lx, bg %#lx %s\n",
10796	   (win == &(screen->fullVwin)) ? "full" : "icon",
10797	   xw->core.background_pixel,
10798	   xw->core.border_pixel,
10799	   T_COLOR(screen, TEXT_FG),
10800	   T_COLOR(screen, TEXT_BG),
10801	   xw->misc.re_verse ? "reverse" : "normal"));
10802    if (xw->misc.color_inner_border
10803	&& (xw->core.background_pixel != xw->core.border_pixel)) {
10804	/*
10805	 * By default, try to match the inner window's background.
10806	 */
10807	if ((xw->core.background_pixel == T_COLOR(screen, TEXT_BG)) &&
10808	    (xw->core.border_pixel == T_COLOR(screen, TEXT_FG))) {
10809	    filler = T_COLOR(screen, TEXT_BG);
10810	} else {
10811	    filler = xw->core.border_pixel;
10812	}
10813	TRACE((" border %#lx\n", filler));
10814	setCgsFore(xw, win, gcBorder, filler);
10815	setCgsBack(xw, win, gcBorder, filler);
10816	win->border_gc = getCgsGC(xw, win, gcBorder);
10817    }
10818#if USE_DOUBLE_BUFFER
10819    else if (resource.buffered) {
10820	filler = T_COLOR(screen, TEXT_BG);
10821	TRACE((" border %#lx (buffered)\n", filler));
10822	setCgsFore(xw, win, gcBorder, filler);
10823	setCgsBack(xw, win, gcBorder, filler);
10824	win->border_gc = getCgsGC(xw, win, gcBorder);
10825    }
10826#endif
10827    else {
10828	TRACE((" border unused\n"));
10829	win->border_gc = 0;
10830    }
10831
10832    /*
10833     * Initialize a GC for double-buffering, needed for XFillRectangle call
10834     * in xtermClear2().  When not double-buffering, the XClearArea call works,
10835     * without requiring a separate GC.
10836     */
10837#if USE_DOUBLE_BUFFER
10838    if (resource.buffered) {
10839	filler = (((xw->flags & BG_COLOR) && (xw->cur_background >= 0))
10840		  ? getXtermBG(xw, xw->flags, xw->cur_background)
10841		  : T_COLOR(screen, TEXT_BG));
10842
10843	TRACE((" filler %#lx %s\n",
10844	       filler,
10845	       xw->misc.re_verse ? "reverse" : "normal"));
10846
10847	setCgsFore(xw, win, gcFiller, filler);
10848	setCgsBack(xw, win, gcFiller, filler);
10849
10850	win->filler_gc = getCgsGC(xw, win, gcFiller);
10851    }
10852#endif
10853}
10854#if USE_DOUBLE_BUFFER
10855static Boolean
10856allocateDbe(XtermWidget xw, VTwin *target)
10857{
10858    TScreen *screen = TScreenOf(xw);
10859    Boolean result = False;
10860
10861    target->drawable = target->window;
10862
10863    if (resource.buffered) {
10864	Window win = target->window;
10865	Drawable d;
10866	int major, minor;
10867	if (XdbeQueryExtension(XtDisplay(xw), &major, &minor)) {
10868	    d = XdbeAllocateBackBufferName(XtDisplay(xw), win,
10869					   (XdbeSwapAction) XdbeCopied);
10870	    if (d == None) {
10871		fprintf(stderr, "Couldn't allocate a back buffer!\n");
10872		exit(3);
10873	    }
10874	    target->drawable = d;
10875	    screen->needSwap = 1;
10876	    TRACE(("initialized double-buffering\n"));
10877	    result = True;
10878	} else {
10879	    resource.buffered = False;
10880	}
10881    }
10882    return result;
10883}
10884#endif /* USE_DOUBLE_BUFFER */
10885
10886/*ARGSUSED*/
10887static void
10888VTRealize(Widget w,
10889	  XtValueMask * valuemask,
10890	  XSetWindowAttributes * values)
10891{
10892    XtermWidget xw = (XtermWidget) w;
10893    TScreen *screen = TScreenOf(xw);
10894
10895    const VTFontNames *myfont;
10896    struct Xinerama_geometry pos;
10897    int pr;
10898    Atom pid_atom;
10899    int i;
10900
10901    TRACE(("VTRealize " TRACE_L "\n"));
10902
10903    TabReset(xw->tabs);
10904
10905    if (screen->menu_font_number == fontMenu_default) {
10906	myfont = defaultVTFontNames(xw);
10907    } else {
10908	myfont = xtermFontName(screen->MenuFontName(screen->menu_font_number));
10909    }
10910    memset(screen->fnts, 0, sizeof(screen->fnts));
10911
10912    if (!xtermLoadFont(xw,
10913		       myfont,
10914		       False,
10915		       screen->menu_font_number)) {
10916	if (XmuCompareISOLatin1(myfont->f_n, DEFFONT) != 0) {
10917	    char *use_font = x_strdup(DEFFONT);
10918	    xtermWarning("unable to open font \"%s\", trying \"%s\"....\n",
10919			 myfont->f_n, use_font);
10920	    (void) xtermLoadFont(xw,
10921				 xtermFontName(use_font),
10922				 False,
10923				 screen->menu_font_number);
10924	    screen->MenuFontName(screen->menu_font_number) = use_font;
10925	}
10926    }
10927
10928    /* really screwed if we couldn't open default font */
10929    if (!GetNormalFont(screen, fNorm)->fs) {
10930	xtermWarning("unable to locate a suitable font\n");
10931	Exit(1);
10932    }
10933#if OPT_WIDE_CHARS
10934    if (screen->utf8_mode) {
10935	TRACE(("check if this is a wide font, if not try again\n"));
10936	if (xtermLoadWideFonts(xw, False)) {
10937	    SetVTFont(xw, screen->menu_font_number, True, NULL);
10938	    /* we will not be able to switch to ISO-8859-1 */
10939	    if (!screen->mergedVTFonts) {
10940		screen->utf8_fonts = uAlways;
10941		update_font_utf8_fonts();
10942	    }
10943	}
10944    }
10945#endif
10946
10947    xtermSetupPointer(xw, screen->pointer_shape);
10948
10949    /* set defaults */
10950    pos.x = 1;
10951    pos.y = 1;
10952    pos.w = 80;
10953    pos.h = 24;
10954
10955    TRACE(("parsing geo_metry %s\n", NonNull(xw->misc.geo_metry)));
10956    pr = XParseXineramaGeometry(screen->display, xw->misc.geo_metry, &pos);
10957    TRACE(("... position %d,%d size %dx%d\n", pos.y, pos.x, pos.h, pos.w));
10958
10959    set_max_col(screen, (int) (pos.w - 1));	/* units in character cells */
10960    set_max_row(screen, (int) (pos.h - 1));	/* units in character cells */
10961    xtermUpdateFontInfo(xw, False);
10962
10963    pos.w = screen->fullVwin.fullwidth;
10964    pos.h = screen->fullVwin.fullheight;
10965
10966    TRACE(("... BorderWidth: widget %d parent %d shell %d\n",
10967	   BorderWidth(xw),
10968	   BorderWidth(XtParent(xw)),
10969	   BorderWidth(SHELL_OF(xw))));
10970
10971    if ((pr & XValue) && (XNegative & pr)) {
10972	pos.x = (Position) (pos.x + (pos.scr_w
10973				     - (int) pos.w
10974				     - (BorderWidth(XtParent(xw)) * 2)));
10975    }
10976    if ((pr & YValue) && (YNegative & pr)) {
10977	pos.y = (Position) (pos.y + (pos.scr_h
10978				     - (int) pos.h
10979				     - (BorderWidth(XtParent(xw)) * 2)));
10980    }
10981    pos.x = (Position) (pos.x + pos.scr_x);
10982    pos.y = (Position) (pos.y + pos.scr_y);
10983
10984    /* set up size hints for window manager; min 1 char by 1 char */
10985    getXtermSizeHints(xw);
10986    xtermSizeHints(xw, (xw->misc.scrollbar
10987			? (screen->scrollWidget->core.width
10988			   + BorderWidth(screen->scrollWidget))
10989			: 0));
10990
10991    xw->hints.x = pos.x;
10992    xw->hints.y = pos.y;
10993#if OPT_MAXIMIZE
10994    /* assure single-increment resize for fullscreen */
10995    if (xw->work.ewmh[0].mode) {
10996	xw->hints.width_inc = 1;
10997	xw->hints.height_inc = 1;
10998    }
10999#endif
11000    if ((XValue & pr) || (YValue & pr)) {
11001	xw->hints.flags |= USSize | USPosition;
11002	xw->hints.flags |= PWinGravity;
11003	switch (pr & (XNegative | YNegative)) {
11004	case 0:
11005	    xw->hints.win_gravity = NorthWestGravity;
11006	    break;
11007	case XNegative:
11008	    xw->hints.win_gravity = NorthEastGravity;
11009	    break;
11010	case YNegative:
11011	    xw->hints.win_gravity = SouthWestGravity;
11012	    break;
11013	default:
11014	    xw->hints.win_gravity = SouthEastGravity;
11015	    break;
11016	}
11017    } else {
11018	/* set a default size, but do *not* set position */
11019	xw->hints.flags |= PSize;
11020    }
11021    xw->hints.height = xw->hints.base_height
11022	+ xw->hints.height_inc * MaxRows(screen);
11023    xw->hints.width = xw->hints.base_width
11024	+ xw->hints.width_inc * MaxCols(screen);
11025
11026    if ((WidthValue & pr) || (HeightValue & pr))
11027	xw->hints.flags |= USSize;
11028    else
11029	xw->hints.flags |= PSize;
11030
11031    /*
11032     * Note that the size-hints are for the shell, while the resize-request
11033     * is for the vt100 widget.  They are not the same size.
11034     */
11035    (void) REQ_RESIZE((Widget) xw,
11036		      (Dimension) pos.w, (Dimension) pos.h,
11037		      &xw->core.width, &xw->core.height);
11038
11039    /* XXX This is bogus.  We are parsing geometries too late.  This
11040     * is information that the shell widget ought to have before we get
11041     * realized, so that it can do the right thing.
11042     */
11043    if (xw->hints.flags & USPosition)
11044	XMoveWindow(XtDisplay(xw), VShellWindow(xw),
11045		    xw->hints.x, xw->hints.y);
11046
11047    TRACE(("%s@%d -- ", __FILE__, __LINE__));
11048    TRACE_HINTS(&xw->hints);
11049    XSetWMNormalHints(XtDisplay(xw), VShellWindow(xw), &xw->hints);
11050    TRACE(("%s@%d -- ", __FILE__, __LINE__));
11051    TRACE_WM_HINTS(xw);
11052
11053    if ((pid_atom = XInternAtom(XtDisplay(xw), "_NET_WM_PID", False)) != None) {
11054	/* XChangeProperty format 32 really is "long" */
11055	unsigned long pid_l = (unsigned long) getpid();
11056	TRACE(("Setting _NET_WM_PID property to %lu\n", pid_l));
11057	XChangeProperty(XtDisplay(xw), VShellWindow(xw),
11058			pid_atom, XA_CARDINAL, 32, PropModeReplace,
11059			(unsigned char *) &pid_l, 1);
11060    }
11061
11062    XFlush(XtDisplay(xw));	/* get it out to window manager */
11063
11064    /* use ForgetGravity instead of SouthWestGravity because translating
11065       the Expose events for ConfigureNotifys is too hard */
11066    values->bit_gravity = (GravityIsNorthWest(xw)
11067			   ? NorthWestGravity
11068			   : ForgetGravity);
11069    screen->fullVwin.window = XtWindow(xw) =
11070	XCreateWindow(XtDisplay(xw), XtWindow(XtParent(xw)),
11071		      xw->core.x, xw->core.y,
11072		      xw->core.width, xw->core.height, BorderWidth(xw),
11073		      (int) xw->core.depth,
11074		      InputOutput, CopyFromParent,
11075		      *valuemask | CWBitGravity, values);
11076#if USE_DOUBLE_BUFFER
11077    if (allocateDbe(xw, &(screen->fullVwin))) {
11078	screen->needSwap = 1;
11079	TRACE(("initialized full double-buffering\n"));
11080    } else {
11081	resource.buffered = False;
11082	screen->fullVwin.drawable = screen->fullVwin.window;
11083    }
11084#endif /* USE_DOUBLE_BUFFER */
11085    screen->event_mask = values->event_mask;
11086
11087#ifndef NO_ACTIVE_ICON
11088    /*
11089     * Normally, the font-number for icon fonts does not correspond with any of
11090     * the menu-selectable fonts.  If we cannot load the font given for the
11091     * iconFont resource, try with font1 aka "Unreadable".
11092     */
11093    screen->icon_fontnum = -1;
11094    if (getIconicFont(screen)->fs == 0) {
11095	getIconicFont(screen)->fs =
11096	    xtermLoadQueryFont(xw, screen->MenuFontName(fontMenu_font1));
11097	ReportIcons(("%susing font1 '%s' as iconFont\n",
11098		     (getIconicFont(screen)->fs
11099		      ? ""
11100		      : "NOT "),
11101		     screen->MenuFontName(fontMenu_font1)));
11102    }
11103#if OPT_RENDERFONT
11104    /*
11105     * If we still have no result from iconFont resource (perhaps because fonts
11106     * are missing) but are using Xft, try to use that instead.  We prefer
11107     * bitmap fonts in any case, since scaled fonts are usually less readable,
11108     * particularly at small sizes.
11109     */
11110    if (UsingRenderFont(xw)
11111	&& getIconicFont(screen)->fs == 0) {
11112	screen->icon_fontnum = fontMenu_default;
11113	getIconicFont(screen)->fs = GetNormalFont(screen, fNorm)->fs;	/* need for next-if */
11114	ReportIcons(("using TrueType font as iconFont\n"));
11115    }
11116#endif
11117    xw->work.wm_name = getWindowManagerName(xw);
11118    if ((xw->work.active_icon == eiDefault) && getIconicFont(screen)->fs) {
11119	ReportIcons(("window manager name is %s\n", xw->work.wm_name));
11120	if (x_strncasecmp(xw->work.wm_name, "fvwm", 4) &&
11121	    x_strncasecmp(xw->work.wm_name, "window maker", 12)) {
11122	    xw->work.active_icon = eiFalse;
11123	    TRACE(("... disable active_icon\n"));
11124	}
11125    }
11126    TRACE((".. if active_icon (%d), get its font\n", xw->work.active_icon));
11127    if (xw->work.active_icon && getIconicFont(screen)->fs) {
11128	int iconX = 0, iconY = 0;
11129	Widget shell = SHELL_OF(xw);
11130	VTwin *win = &(screen->iconVwin);
11131	int save_fontnum = screen->menu_font_number;
11132
11133	ReportIcons(("initializing active-icon %d\n", screen->icon_fontnum));
11134	screen->menu_font_number = screen->icon_fontnum;
11135	XtVaGetValues(shell,
11136		      XtNiconX, &iconX,
11137		      XtNiconY, &iconY,
11138		      (XtPointer) 0);
11139	xtermComputeFontInfo(xw, &(screen->iconVwin),
11140			     getIconicFont(screen)->fs, 0);
11141	screen->menu_font_number = save_fontnum;
11142
11143	/* since only one client is permitted to select for Button
11144	 * events, we have to let the window manager get 'em...
11145	 */
11146	values->event_mask &= ~(ButtonPressMask | ButtonReleaseMask);
11147	values->border_pixel = xw->misc.icon_border_pixel;
11148
11149	screen->iconVwin.window =
11150	    XCreateWindow(XtDisplay(xw),
11151			  RootWindowOfScreen(XtScreen(shell)),
11152			  iconX, iconY,
11153			  screen->iconVwin.fullwidth,
11154			  screen->iconVwin.fullheight,
11155			  xw->misc.icon_border_width,
11156			  (int) xw->core.depth,
11157			  InputOutput, CopyFromParent,
11158			  *valuemask | CWBitGravity | CWBorderPixel,
11159			  values);
11160#if USE_DOUBLE_BUFFER
11161	if (allocateDbe(xw, &(screen->iconVwin))) {
11162	    TRACE(("initialized icon double-buffering\n"));
11163	} else {
11164	    resource.buffered = False;
11165	    screen->iconVwin.drawable = screen->iconVwin.window;
11166	    screen->fullVwin.drawable = screen->fullVwin.window;
11167	}
11168#endif /* USE_DOUBLE_BUFFER */
11169	XtVaSetValues(shell,
11170		      XtNiconWindow, screen->iconVwin.window,
11171		      (XtPointer) 0);
11172	XtRegisterDrawable(XtDisplay(xw), screen->iconVwin.window, w);
11173
11174	setCgsFont(xw, win, gcNorm, getIconicFont(screen));
11175	setCgsFore(xw, win, gcNorm, T_COLOR(screen, TEXT_FG));
11176	setCgsBack(xw, win, gcNorm, T_COLOR(screen, TEXT_BG));
11177
11178	copyCgs(xw, win, gcBold, gcNorm);
11179
11180	setCgsFont(xw, win, gcNormReverse, getIconicFont(screen));
11181	setCgsFore(xw, win, gcNormReverse, T_COLOR(screen, TEXT_BG));
11182	setCgsBack(xw, win, gcNormReverse, T_COLOR(screen, TEXT_FG));
11183
11184	copyCgs(xw, win, gcBoldReverse, gcNormReverse);
11185
11186	initBorderGC(xw, win);
11187
11188#if OPT_TOOLBAR
11189	/*
11190	 * Toolbar is initialized before we get here.  Enable the menu item
11191	 * and set it properly.
11192	 */
11193	SetItemSensitivity(vtMenuEntries[vtMenu_activeicon].widget, True);
11194	update_activeicon();
11195#endif
11196    } else {
11197	ReportIcons(("disabled active-icon\n"));
11198	xw->work.active_icon = eiFalse;
11199    }
11200#endif /* NO_ACTIVE_ICON */
11201
11202#if OPT_INPUT_METHOD
11203    VTInitI18N(xw);
11204#endif
11205#if OPT_NUM_LOCK
11206    VTInitModifiers(xw);
11207#if OPT_EXTRA_PASTE
11208    if (xw->keyboard.extra_translations) {
11209	XtOverrideTranslations((Widget) xw,
11210			       XtParseTranslationTable(xw->keyboard.extra_translations));
11211    }
11212#endif
11213#endif
11214
11215    set_cursor_gcs(xw);
11216    initBorderGC(xw, &(screen->fullVwin));
11217
11218    /* Reset variables used by ANSI emulation. */
11219
11220    resetCharsets(screen);
11221
11222    XDefineCursor(screen->display, VShellWindow(xw), screen->pointer_cursor);
11223
11224    set_cur_col(screen, 0);
11225    set_cur_row(screen, 0);
11226    set_max_col(screen, Width(screen) / screen->fullVwin.f_width - 1);
11227    set_max_row(screen, Height(screen) / screen->fullVwin.f_height - 1);
11228    resetMargins(xw);
11229
11230    memset(screen->sc, 0, sizeof(screen->sc));
11231
11232    /* Mark screen buffer as unallocated.  We wait until the run loop so
11233       that the child process does not fork and exec with all the dynamic
11234       memory it will never use.  If we were to do it here, the
11235       swap space for new process would be huge for huge savelines. */
11236#if OPT_TEK4014
11237    if (!tekWidget)		/* if not called after fork */
11238#endif
11239    {
11240	screen->visbuf = NULL;
11241	screen->saveBuf_index = NULL;
11242    }
11243
11244    ResetWrap(screen);
11245    screen->scrolls = screen->incopy = 0;
11246    xtermSetCursorBox(screen);
11247
11248    screen->savedlines = 0;
11249
11250    for (i = 0; i < 2; ++i) {
11251	screen->whichBuf = !screen->whichBuf;
11252	CursorSave(xw);
11253    }
11254
11255#ifndef NO_ACTIVE_ICON
11256    if (!xw->work.active_icon)
11257#endif
11258	xtermLoadIcon(xw, resource.icon_hint);
11259
11260    /*
11261     * Do this last, since it may change the layout via a resize.
11262     */
11263    if (xw->misc.scrollbar) {
11264	screen->fullVwin.sb_info.width = 0;
11265	ScrollBarOn(xw, False);
11266    }
11267
11268    xtermSetWinSize(xw);
11269    TRACE(("" TRACE_R " VTRealize\n"));
11270}
11271
11272#if OPT_INPUT_METHOD
11273
11274/* limit this feature to recent XFree86 since X11R6.x core dumps */
11275#if defined(XtSpecificationRelease) && XtSpecificationRelease >= 6 && defined(X_HAVE_UTF8_STRING)
11276#define USE_XIM_INSTANTIATE_CB
11277
11278static void
11279xim_instantiate_cb(Display *display,
11280		   XPointer client_data GCC_UNUSED,
11281		   XPointer call_data GCC_UNUSED)
11282{
11283    XtermWidget xw = term;
11284
11285    TRACE(("xim_instantiate_cb client=%p, call=%p\n", client_data, call_data));
11286
11287    if (display == XtDisplay(xw)) {
11288	VTInitI18N(xw);
11289    }
11290}
11291
11292static void
11293xim_destroy_cb(XIM im GCC_UNUSED,
11294	       XPointer client_data GCC_UNUSED,
11295	       XPointer call_data GCC_UNUSED)
11296{
11297    XtermWidget xw = term;
11298    TInput *input = lookupTInput(xw, (Widget) xw);
11299
11300    TRACE(("xim_destroy_cb im=%lx, client=%p, call=%p\n",
11301	   (long) im, client_data, call_data));
11302    if (input)
11303	input->xic = NULL;
11304    XRegisterIMInstantiateCallback(XtDisplay(xw), NULL, NULL, NULL,
11305				   xim_instantiate_cb, NULL);
11306}
11307#endif /* X11R6+ */
11308
11309static Boolean
11310xim_create_fs(XtermWidget xw)
11311{
11312    XFontStruct **fonts;
11313    char **font_name_list;
11314    char **missing_charset_list;
11315    char *def_string;
11316    int missing_charset_count;
11317    unsigned i, j;
11318
11319    if (xw->work.xim_fs == 0) {
11320	xw->work.xim_fs = XCreateFontSet(XtDisplay(xw),
11321					 xw->misc.f_x,
11322					 &missing_charset_list,
11323					 &missing_charset_count,
11324					 &def_string);
11325	if (xw->work.xim_fs == NULL) {
11326	    xtermWarning("Preparation of font set "
11327			 "\"%s\" for XIM failed.\n", xw->misc.f_x);
11328	    xw->work.xim_fs = XCreateFontSet(XtDisplay(xw),
11329					     DEFXIMFONT,
11330					     &missing_charset_list,
11331					     &missing_charset_count,
11332					     &def_string);
11333	}
11334    }
11335    if (xw->work.xim_fs == NULL) {
11336	xtermWarning("Preparation of default font set "
11337		     "\"%s\" for XIM failed.\n", DEFXIMFONT);
11338	cleanupInputMethod(xw);
11339	xw->work.cannot_im = True;
11340    } else {
11341	(void) XExtentsOfFontSet(xw->work.xim_fs);
11342	j = (unsigned) XFontsOfFontSet(xw->work.xim_fs, &fonts, &font_name_list);
11343	for (i = 0, xw->work.xim_fs_ascent = 0; i < j; i++) {
11344	    if (xw->work.xim_fs_ascent < (*fonts)->ascent)
11345		xw->work.xim_fs_ascent = (*fonts)->ascent;
11346	}
11347    }
11348    return (Boolean) !(xw->work.cannot_im);
11349}
11350
11351static void
11352xim_create_xic(XtermWidget xw, Widget theInput)
11353{
11354    Display *myDisplay = XtDisplay(theInput);
11355    Window myWindow = XtWindow(theInput);
11356    unsigned i, j;
11357    char *p = NULL, *s, *t, *ns, *end, buf[32];
11358    XIMStyles *xim_styles;
11359    XIMStyle input_style = 0;
11360    Bool found;
11361    static struct {
11362	const char *name;
11363	unsigned long code;
11364    } known_style[] = {
11365	{
11366	    "OverTheSpot", (XIMPreeditPosition | XIMStatusNothing)
11367	},
11368	{
11369	    "OffTheSpot", (XIMPreeditArea | XIMStatusArea)
11370	},
11371	{
11372	    "Root", (XIMPreeditNothing | XIMStatusNothing)
11373	},
11374    };
11375    TInput *input = lookupTInput(xw, theInput);
11376
11377    if (xw->work.cannot_im) {
11378	return;
11379    }
11380
11381    if (input == 0) {
11382	for (i = 0; i < NINPUTWIDGETS; ++i) {
11383	    if (xw->work.inputs[i].w == 0) {
11384		input = xw->work.inputs + i;
11385		input->w = theInput;
11386		break;
11387	    }
11388	}
11389    }
11390
11391    if (input == 0) {
11392	xtermWarning("attempted to add too many input widgets\n");
11393	return;
11394    }
11395
11396    TRACE(("xim_real_init\n"));
11397
11398    if (IsEmpty(xw->misc.input_method)) {
11399	if ((p = XSetLocaleModifiers("")) != NULL && *p) {
11400	    input->xim = XOpenIM(myDisplay, NULL, NULL, NULL);
11401	}
11402    } else {
11403	s = xw->misc.input_method;
11404	i = 5 + (unsigned) strlen(s);
11405
11406	t = (char *) MyStackAlloc(i, buf);
11407	if (t == NULL) {
11408	    SysError(ERROR_VINIT);
11409	} else {
11410
11411	    for (ns = s; ns && *s;) {
11412		while (*s && isspace(CharOf(*s)))
11413		    s++;
11414		if (!*s)
11415		    break;
11416		if ((ns = end = strchr(s, ',')) == 0)
11417		    end = s + strlen(s);
11418		while ((end != s) && isspace(CharOf(end[-1])))
11419		    end--;
11420
11421		if (end != s) {
11422		    strcpy(t, "@im=");
11423		    strncat(t, s, (size_t) (end - s));
11424
11425		    if ((p = XSetLocaleModifiers(t)) != 0 && *p
11426			&& (input->xim = XOpenIM(myDisplay,
11427						 NULL,
11428						 NULL,
11429						 NULL)) != 0) {
11430			break;
11431		    }
11432
11433		}
11434		s = ns + 1;
11435	    }
11436	    MyStackFree(t, buf);
11437	}
11438    }
11439
11440    if (input->xim == NULL
11441	&& (p = XSetLocaleModifiers("@im=none")) != NULL
11442	&& *p) {
11443	input->xim = XOpenIM(myDisplay, NULL, NULL, NULL);
11444    }
11445
11446    if (!input->xim) {
11447	xtermWarning("Failed to open input method\n");
11448	return;
11449    }
11450    TRACE(("VTInitI18N opened input method:%s\n", NonNull(p)));
11451
11452    if (XGetIMValues(input->xim, XNQueryInputStyle, &xim_styles, (void *) 0)
11453	|| !xim_styles
11454	|| !xim_styles->count_styles) {
11455	xtermWarning("input method doesn't support any style\n");
11456	cleanupInputMethod(xw);
11457	xw->work.cannot_im = True;
11458	return;
11459    }
11460
11461    found = False;
11462    for (s = xw->misc.preedit_type; s && !found;) {
11463	while (*s && isspace(CharOf(*s)))
11464	    s++;
11465	if (!*s)
11466	    break;
11467	if ((ns = end = strchr(s, ',')) != 0)
11468	    ns++;
11469	else
11470	    end = s + strlen(s);
11471	while ((end != s) && isspace(CharOf(end[-1])))
11472	    end--;
11473
11474	if (end != s) {		/* just in case we have a spurious comma */
11475	    TRACE(("looking for style '%.*s'\n", (int) (end - s), s));
11476	    for (i = 0; i < XtNumber(known_style); i++) {
11477		if ((int) strlen(known_style[i].name) == (end - s)
11478		    && !strncmp(s, known_style[i].name, (size_t) (end - s))) {
11479		    input_style = known_style[i].code;
11480		    for (j = 0; j < xim_styles->count_styles; j++) {
11481			if (input_style == xim_styles->supported_styles[j]) {
11482			    found = True;
11483			    break;
11484			}
11485		    }
11486		    if (found)
11487			break;
11488		}
11489	    }
11490	}
11491
11492	s = ns;
11493    }
11494    XFree(xim_styles);
11495
11496    if (!found) {
11497	xtermWarning("input method doesn't support my preedit type (%s)\n",
11498		     xw->misc.preedit_type);
11499	cleanupInputMethod(xw);
11500	xw->work.cannot_im = True;
11501	return;
11502    }
11503
11504    /*
11505     * Check for styles we do not yet support.
11506     */
11507    TRACE(("input_style %#lx\n", input_style));
11508    if (input_style == (XIMPreeditArea | XIMStatusArea)) {
11509	xtermWarning("This program doesn't support the 'OffTheSpot' preedit type\n");
11510	cleanupInputMethod(xw);
11511	xw->work.cannot_im = True;
11512	return;
11513    }
11514
11515    /*
11516     * For XIMPreeditPosition (or OverTheSpot), XIM client has to
11517     * prepare a font.
11518     * The font has to be locale-dependent XFontSet, whereas
11519     * XTerm use Unicode font.  This leads a problem that the
11520     * same font cannot be used for XIM preedit.
11521     */
11522    if (input_style != (XIMPreeditNothing | XIMStatusNothing)) {
11523	XVaNestedList p_list;
11524	XPoint spot =
11525	{0, 0};
11526
11527	if (xim_create_fs(xw)) {
11528	    p_list = XVaCreateNestedList(0,
11529					 XNSpotLocation, &spot,
11530					 XNFontSet, xw->work.xim_fs,
11531					 (void *) 0);
11532	    input->xic = XCreateIC(input->xim,
11533				   XNInputStyle, input_style,
11534				   XNClientWindow, myWindow,
11535				   XNFocusWindow, myWindow,
11536				   XNPreeditAttributes, p_list,
11537				   (void *) 0);
11538	}
11539    } else {
11540	input->xic = XCreateIC(input->xim, XNInputStyle, input_style,
11541			       XNClientWindow, myWindow,
11542			       XNFocusWindow, myWindow,
11543			       (void *) 0);
11544    }
11545
11546    if (!input->xic) {
11547	xtermWarning("Failed to create input context\n");
11548	cleanupInputMethod(xw);
11549    }
11550#if defined(USE_XIM_INSTANTIATE_CB)
11551    else {
11552	XIMCallback destroy_cb;
11553
11554	destroy_cb.callback = xim_destroy_cb;
11555	destroy_cb.client_data = NULL;
11556	if (XSetIMValues(input->xim,
11557			 XNDestroyCallback,
11558			 &destroy_cb,
11559			 (void *) 0)) {
11560	    xtermWarning("Could not set destroy callback to IM\n");
11561	}
11562    }
11563#endif
11564
11565    return;
11566}
11567
11568static void
11569xim_real_init(XtermWidget xw)
11570{
11571    xim_create_xic(xw, (Widget) xw);
11572}
11573
11574static void
11575VTInitI18N(XtermWidget xw)
11576{
11577    if (xw->misc.open_im) {
11578	xim_real_init(xw);
11579
11580#if defined(USE_XIM_INSTANTIATE_CB)
11581	if (lookupTInput(xw, (Widget) xw) == NULL
11582	    && !xw->work.cannot_im
11583	    && xw->misc.retry_im-- > 0) {
11584	    sleep(3);
11585	    XRegisterIMInstantiateCallback(XtDisplay(xw), NULL, NULL, NULL,
11586					   xim_instantiate_cb, NULL);
11587	}
11588#endif
11589    }
11590}
11591
11592TInput *
11593lookupTInput(XtermWidget xw, Widget w)
11594{
11595    TInput *result = 0;
11596    unsigned n;
11597
11598    for (n = 0; n < NINPUTWIDGETS; ++n) {
11599	if (xw->work.inputs[n].w == w) {
11600	    result = xw->work.inputs + n;
11601	    break;
11602	}
11603    }
11604
11605    return result;
11606}
11607#endif /* OPT_INPUT_METHOD */
11608
11609static void
11610set_cursor_outline_gc(XtermWidget xw,
11611		      Bool filled,
11612		      Pixel fg,
11613		      Pixel bg,
11614		      Pixel cc)
11615{
11616    TScreen *screen = TScreenOf(xw);
11617    VTwin *win = WhichVWin(screen);
11618    CgsEnum cgsId = gcVTcursOutline;
11619
11620    if (cc == bg)
11621	cc = fg;
11622
11623    if (filled) {
11624	setCgsFore(xw, win, cgsId, bg);
11625	setCgsBack(xw, win, cgsId, cc);
11626    } else {
11627	setCgsFore(xw, win, cgsId, cc);
11628	setCgsBack(xw, win, cgsId, bg);
11629    }
11630}
11631
11632static Boolean
11633VTSetValues(Widget cur,
11634	    Widget request GCC_UNUSED,
11635	    Widget wnew,
11636	    ArgList args GCC_UNUSED,
11637	    Cardinal *num_args GCC_UNUSED)
11638{
11639    XtermWidget curvt = (XtermWidget) cur;
11640    XtermWidget newvt = (XtermWidget) wnew;
11641    Boolean refresh_needed = False;
11642    Boolean fonts_redone = False;
11643
11644    if ((T_COLOR(TScreenOf(curvt), TEXT_BG) !=
11645	 T_COLOR(TScreenOf(newvt), TEXT_BG)) ||
11646	(T_COLOR(TScreenOf(curvt), TEXT_FG) !=
11647	 T_COLOR(TScreenOf(newvt), TEXT_FG)) ||
11648	(TScreenOf(curvt)->MenuFontName(TScreenOf(curvt)->menu_font_number) !=
11649	 TScreenOf(newvt)->MenuFontName(TScreenOf(newvt)->menu_font_number)) ||
11650	strcmp(DefaultFontN(curvt), DefaultFontN(newvt))) {
11651	if (strcmp(DefaultFontN(curvt), DefaultFontN(newvt))) {
11652	    TScreenOf(newvt)->MenuFontName(fontMenu_default) = DefaultFontN(newvt);
11653	}
11654	if (xtermLoadFont(newvt,
11655			  xtermFontName(TScreenOf(newvt)->MenuFontName(TScreenOf(curvt)->menu_font_number)),
11656			  True, TScreenOf(newvt)->menu_font_number)) {
11657	    /* resizing does the redisplay, so don't ask for it here */
11658	    refresh_needed = True;
11659	    fonts_redone = True;
11660	} else if (strcmp(DefaultFontN(curvt), DefaultFontN(newvt))) {
11661	    TScreenOf(newvt)->MenuFontName(fontMenu_default) = DefaultFontN(curvt);
11662	}
11663    }
11664    if (!fonts_redone
11665	&& (T_COLOR(TScreenOf(curvt), TEXT_CURSOR) !=
11666	    T_COLOR(TScreenOf(newvt), TEXT_CURSOR))) {
11667	if (set_cursor_gcs(newvt))
11668	    refresh_needed = True;
11669    }
11670    if (curvt->misc.re_verse != newvt->misc.re_verse) {
11671	newvt->flags ^= REVERSE_VIDEO;
11672	ReverseVideo(newvt);
11673	/* ReverseVideo toggles */
11674	newvt->misc.re_verse = (Boolean) (!newvt->misc.re_verse);
11675	refresh_needed = True;
11676    }
11677    if ((T_COLOR(TScreenOf(curvt), MOUSE_FG) !=
11678	 T_COLOR(TScreenOf(newvt), MOUSE_FG)) ||
11679	(T_COLOR(TScreenOf(curvt), MOUSE_BG) !=
11680	 T_COLOR(TScreenOf(newvt), MOUSE_BG))) {
11681	recolor_cursor(TScreenOf(newvt),
11682		       TScreenOf(newvt)->pointer_cursor,
11683		       T_COLOR(TScreenOf(newvt), MOUSE_FG),
11684		       T_COLOR(TScreenOf(newvt), MOUSE_BG));
11685	refresh_needed = True;
11686    }
11687    if (curvt->misc.scrollbar != newvt->misc.scrollbar) {
11688	ToggleScrollBar(newvt);
11689    }
11690
11691    return refresh_needed;
11692}
11693
11694/*
11695 * Given a font-slot and information about selection/reverse, find the
11696 * corresponding cached-GC slot.
11697 */
11698#if OPT_WIDE_ATTRS
11699static int
11700reverseCgs(XtermWidget xw, unsigned attr_flags, Bool hilite, int font)
11701{
11702    TScreen *screen = TScreenOf(xw);
11703    CgsEnum result = gcMAX;
11704
11705    (void) screen;
11706    if (ReverseOrHilite(screen, attr_flags, hilite)) {
11707	switch (font) {
11708	case fNorm:
11709	    result = gcNormReverse;
11710	    break;
11711	case fBold:
11712	    result = gcBoldReverse;
11713	    break;
11714#if OPT_WIDE_ATTRS || OPT_RENDERWIDE
11715	case fItal:
11716	    result = gcNormReverse;	/* FIXME */
11717	    break;
11718#endif
11719#if OPT_WIDE_CHARS
11720	case fWide:
11721	    result = gcWideReverse;
11722	    break;
11723	case fWBold:
11724	    result = gcWBoldReverse;
11725	    break;
11726	case fWItal:
11727	    result = gcWideReverse;	/* FIXME */
11728	    break;
11729#endif
11730	}
11731    } else {
11732	switch (font) {
11733	case fNorm:
11734	    result = gcNorm;
11735	    break;
11736	case fBold:
11737	    result = gcBold;
11738	    break;
11739#if OPT_WIDE_ATTRS || OPT_RENDERWIDE
11740	case fItal:
11741	    result = gcNorm;	/* FIXME */
11742	    break;
11743#endif
11744#if OPT_WIDE_CHARS
11745	case fWide:
11746	    result = gcWide;
11747	    break;
11748	case fWBold:
11749	    result = gcWBold;
11750	    break;
11751	case fWItal:
11752	    result = gcWide;	/* FIXME */
11753	    break;
11754#endif
11755	}
11756    }
11757    return (int) result;
11758}
11759#endif
11760
11761#define setGC(code) set_at = __LINE__, currentCgs = code
11762
11763#define OutsideSelection(screen,srow,scol)  \
11764	 ((srow) > (screen)->endH.row || \
11765	  ((srow) == (screen)->endH.row && \
11766	   (scol) >= (screen)->endH.col) || \
11767	  (srow) < (screen)->startH.row || \
11768	  ((srow) == (screen)->startH.row && \
11769	   (scol) < (screen)->startH.col))
11770
11771/*
11772 * Shows cursor at new cursor position in screen.
11773 */
11774void
11775ShowCursor(XtermWidget xw)
11776{
11777    TScreen *screen = TScreenOf(xw);
11778    XTermDraw params;
11779    IChar base;
11780    unsigned flags;
11781    CellColor fg_bg = initCColor;
11782    GC currentGC;
11783    GC outlineGC;
11784    CgsEnum currentCgs = gcMAX;
11785    VTwin *currentWin = WhichVWin(screen);
11786    int set_at;
11787    Bool in_selection;
11788    Bool reversed;
11789    Bool filled;
11790    Pixel fg_pix;
11791    Pixel bg_pix;
11792    Pixel tmp;
11793#if OPT_HIGHLIGHT_COLOR
11794    Pixel selbg_pix = T_COLOR(screen, HIGHLIGHT_BG);
11795    Pixel selfg_pix = T_COLOR(screen, HIGHLIGHT_FG);
11796    Boolean use_selbg;
11797    Boolean use_selfg;
11798#endif
11799#if OPT_WIDE_CHARS
11800    int my_col = 0;
11801#endif
11802    int cursor_col;
11803    CLineData *ld = 0;
11804
11805    if (screen->cursor_state == BLINKED_OFF)
11806	return;
11807
11808    if (screen->eventMode != NORMAL)
11809	return;
11810
11811    if (INX2ROW(screen, screen->cur_row) > screen->max_row)
11812	return;
11813
11814    screen->cursorp.row = screen->cur_row;
11815    cursor_col = screen->cursorp.col = screen->cur_col;
11816    screen->cursor_moved = False;
11817
11818#ifndef NO_ACTIVE_ICON
11819    if (IsIcon(screen)) {
11820	screen->cursor_state = ON;
11821	return;
11822    }
11823#endif /* NO_ACTIVE_ICON */
11824
11825    ld = getLineData(screen, screen->cur_row);
11826
11827    base = ld->charData[cursor_col];
11828    flags = ld->attribs[cursor_col];
11829
11830    if_OPT_WIDE_CHARS(screen, {
11831	if (base == HIDDEN_CHAR && cursor_col > 0) {
11832	    /* if cursor points to non-initial part of wide character,
11833	     * back it up
11834	     */
11835	    --cursor_col;
11836	    base = ld->charData[cursor_col];
11837	}
11838	my_col = cursor_col;
11839	if (base == 0)
11840	    base = ' ';
11841	if (isWide((int) base))
11842	    my_col += 1;
11843    });
11844
11845    if (base == 0) {
11846	base = ' ';
11847    }
11848#if OPT_ISO_COLORS
11849#ifdef EXP_BOGUS_FG
11850    /*
11851     * If the cursor happens to be on blanks, and we have not set both
11852     * foreground and background color, do not treat it as a colored cell.
11853     */
11854    if (base == ' ') {
11855	if ((flags & (FG_COLOR | BG_COLOR)) == BG_COLOR) {
11856	    TRACE(("ShowCursor - do not treat as a colored cell\n"));
11857	    flags &= ~(FG_COLOR | BG_COLOR);
11858	} else if ((flags & (FG_COLOR | BG_COLOR)) == FG_COLOR) {
11859	    TRACE(("ShowCursor - should we treat as a colored cell?\n"));
11860	    if (!(xw->flags & FG_COLOR)) {
11861		if (CheckBogusForeground(screen, "ShowCursor")) {
11862		    flags &= ~(FG_COLOR | BG_COLOR);
11863		}
11864	    }
11865	}
11866    }
11867#else /* !EXP_BOGUS_FG */
11868    /*
11869     * If the cursor happens to be on blanks, and the foreground color is set
11870     * but not the background, do not treat it as a colored cell.
11871     */
11872    if ((flags & TERM_COLOR_FLAGS(xw)) == FG_COLOR
11873	&& base == ' ') {
11874	flags &= ~TERM_COLOR_FLAGS(xw);
11875    }
11876#endif
11877#endif
11878
11879    /*
11880     * Compare the current cell to the last set of colors used for the
11881     * cursor and update the GC's if needed.
11882     */
11883    (void) fg_bg;
11884    if_OPT_ISO_COLORS(screen, {
11885	fg_bg = ld->color[cursor_col];
11886    });
11887
11888    fg_pix = getXtermFG(xw, flags, (int) extract_fg(xw, fg_bg, flags));
11889    bg_pix = getXtermBG(xw, flags, (int) extract_bg(xw, fg_bg, flags));
11890
11891    /*
11892     * If we happen to have the same foreground/background colors, choose
11893     * a workable foreground color from which we can obtain a visible cursor.
11894     */
11895    if (fg_pix == bg_pix) {
11896	long bg_diff = (long) (bg_pix - T_COLOR(TScreenOf(xw), TEXT_BG));
11897	long fg_diff = (long) (bg_pix - T_COLOR(TScreenOf(xw), TEXT_FG));
11898	if (bg_diff < 0)
11899	    bg_diff = -bg_diff;
11900	if (fg_diff < 0)
11901	    fg_diff = -fg_diff;
11902	if (bg_diff < fg_diff) {
11903	    fg_pix = T_COLOR(TScreenOf(xw), TEXT_FG);
11904	} else {
11905	    fg_pix = T_COLOR(TScreenOf(xw), TEXT_BG);
11906	}
11907    }
11908
11909    if (OutsideSelection(screen, screen->cur_row, screen->cur_col))
11910	in_selection = False;
11911    else
11912	in_selection = True;
11913
11914    reversed = ReverseOrHilite(screen, flags, in_selection);
11915
11916    /* This is like updatedXtermGC(), except that we have to worry about
11917     * whether the window has focus, since in that case we want just an
11918     * outline for the cursor.
11919     */
11920    filled = (screen->select || screen->always_highlight) && isCursorBlock(screen);
11921#if OPT_HIGHLIGHT_COLOR
11922    use_selbg = isNotForeground(xw, fg_pix, bg_pix, selbg_pix);
11923    use_selfg = isNotBackground(xw, fg_pix, bg_pix, selfg_pix);
11924#endif
11925    if (filled) {
11926	if (reversed) {		/* text is reverse video */
11927	    if (getCgsGC(xw, currentWin, gcVTcursNormal)) {
11928		setGC(gcVTcursNormal);
11929	    } else {
11930		if (flags & BOLDATTR(screen)) {
11931		    setGC(gcBold);
11932		} else {
11933		    setGC(gcNorm);
11934		}
11935	    }
11936	    EXCHANGE(fg_pix, bg_pix, tmp);
11937#if OPT_HIGHLIGHT_COLOR
11938	    if (screen->hilite_reverse) {
11939		if (use_selbg && !use_selfg)
11940		    fg_pix = bg_pix;
11941		if (use_selfg && !use_selbg)
11942		    bg_pix = fg_pix;
11943		if (use_selbg)
11944		    bg_pix = selbg_pix;
11945		if (use_selfg)
11946		    fg_pix = selfg_pix;
11947	    }
11948#endif
11949	} else {		/* normal video */
11950	    if (getCgsGC(xw, currentWin, gcVTcursReverse)) {
11951		setGC(gcVTcursReverse);
11952	    } else {
11953		if (flags & BOLDATTR(screen)) {
11954		    setGC(gcBoldReverse);
11955		} else {
11956		    setGC(gcNormReverse);
11957		}
11958	    }
11959	}
11960
11961#define CUR_XX T_COLOR(screen, TEXT_CURSOR)
11962#define CGS_FG getCgsFore(xw, currentWin, getCgsGC(xw, currentWin, currentCgs))
11963#define CGS_BG getCgsBack(xw, currentWin, getCgsGC(xw, currentWin, currentCgs))
11964
11965#define FIX_311 (CUR_XX == (reversed ? xw->dft_background : xw->dft_foreground))
11966#define FIX_328 (CUR_XX == bg_pix)
11967#define FIX_330 (FIX_328 && reversed && in_selection)
11968
11969	if (FIX_330 || FIX_311) {
11970	    setCgsBack(xw, currentWin, currentCgs, fg_pix);
11971	}
11972	setCgsFore(xw, currentWin, currentCgs, bg_pix);
11973    } else {			/* not selected */
11974	if (reversed) {		/* text is reverse video */
11975	    EXCHANGE(fg_pix, bg_pix, tmp);
11976	    setGC(gcNormReverse);
11977	} else {		/* normal video */
11978	    setGC(gcNorm);
11979	}
11980#if OPT_HIGHLIGHT_COLOR
11981	if (screen->hilite_reverse) {
11982	    if (in_selection && !reversed) {
11983		/* EMPTY */
11984		/* really INVERSE ... */
11985		;
11986	    } else if (in_selection || reversed) {
11987		if (use_selbg) {
11988		    if (use_selfg) {
11989			bg_pix = fg_pix;
11990		    } else {
11991			fg_pix = bg_pix;
11992			bg_pix = selbg_pix;
11993		    }
11994		}
11995		if (use_selfg) {
11996		    fg_pix = selfg_pix;
11997		}
11998	    }
11999	} else {
12000	    if (in_selection) {
12001		if (use_selbg) {
12002		    bg_pix = selbg_pix;
12003		}
12004		if (use_selfg) {
12005		    fg_pix = selfg_pix;
12006		}
12007	    }
12008	}
12009#endif
12010	setCgsFore(xw, currentWin, currentCgs, fg_pix);
12011	setCgsBack(xw, currentWin, currentCgs, bg_pix);
12012    }
12013
12014    if (screen->cursor_busy == 0
12015	&& (screen->cursor_state != ON || screen->cursor_GC != set_at)) {
12016	int x, y;
12017
12018	screen->cursor_GC = set_at;
12019	TRACE(("ShowCursor calling drawXtermText cur(%d,%d) %s-%s, set_at %d\n",
12020	       screen->cur_row, screen->cur_col,
12021	       (filled ? "filled" : "outline"),
12022	       (isCursorBlock(screen) ? "box" :
12023		isCursorUnderline(screen) ? "underline" : "bar"),
12024	       set_at));
12025
12026	currentGC = getCgsGC(xw, currentWin, currentCgs);
12027	x = LineCursorX(screen, ld, cursor_col);
12028	y = CursorY(screen, screen->cur_row);
12029
12030	if (!isCursorBlock(screen)) {
12031	    /*
12032	     * Overriding the combination of filled, reversed, in_selection is
12033	     * too complicated since the underline or bar and the text-cell use
12034	     * different rules.  Just redraw the text-cell, and draw the
12035	     * underline or bar on top of it.
12036	     */
12037	    HideCursor(xw);
12038
12039	    /*
12040	     * Our current-GC is likely to have been modified in HideCursor().
12041	     * Set up a new request.
12042	     */
12043	    if (filled) {
12044		if (FIX_330 || FIX_311) {
12045		    setCgsBack(xw, currentWin, currentCgs, fg_pix);
12046		}
12047		setCgsFore(xw, currentWin, currentCgs, bg_pix);
12048	    } else {
12049		setCgsFore(xw, currentWin, currentCgs, fg_pix);
12050		setCgsBack(xw, currentWin, currentCgs, bg_pix);
12051	    }
12052	}
12053
12054	/*
12055	 * Update the outline-gc, to keep the cursor color distinct from the
12056	 * background color.
12057	 */
12058	set_cursor_outline_gc(xw,
12059			      filled,
12060			      fg_pix,
12061			      bg_pix,
12062			      T_COLOR(screen, TEXT_CURSOR));
12063
12064	outlineGC = getCgsGC(xw, currentWin, gcVTcursOutline);
12065	if (outlineGC == 0)
12066	    outlineGC = currentGC;
12067
12068	if (isCursorUnderline(screen)) {
12069
12070	    /*
12071	     * Finally, draw the underline.
12072	     */
12073	    screen->box->x = (short) x;
12074	    screen->box->y = (short) (y + FontHeight(screen) - 2);
12075	    XDrawLines(screen->display, VDrawable(screen), outlineGC,
12076		       screen->box, NBOX, CoordModePrevious);
12077	} else if (isCursorBar(screen)) {
12078
12079	    /*
12080	     * Or draw the bar.
12081	     */
12082	    screen->box->x = (short) x;
12083	    screen->box->y = (short) y;
12084	    XDrawLines(screen->display, VDrawable(screen), outlineGC,
12085		       screen->box, NBOX, CoordModePrevious);
12086	} else {
12087#if OPT_WIDE_ATTRS
12088	    int italics_on = ((ld->attribs[cursor_col] & ATR_ITALIC) != 0);
12089	    int italics_off = ((xw->flags & ATR_ITALIC) != 0);
12090	    int fix_italics = (italics_on != italics_off);
12091	    int which_font = ((xw->flags & BOLD) ? fBold : fNorm);
12092	    MyGetFont getter = italics_on ? getItalicFont : getNormalFont;
12093
12094	    if_OPT_WIDE_CHARS(screen, {
12095		if (isWide((int) base)) {
12096		    which_font = ((xw->flags & BOLD) ? fWBold : fWide);
12097		}
12098	    });
12099
12100	    if (fix_italics && UseItalicFont(screen)) {
12101		xtermLoadItalics(xw);
12102		setCgsFont(xw, currentWin, currentCgs,
12103			   getter(screen, which_font));
12104		getter = (((xw->flags & ATR_ITALIC) && UseItalicFont(screen))
12105			  ? getItalicFont
12106			  : getNormalFont);
12107	    }
12108	    currentGC = getCgsGC(xw, currentWin, currentCgs);
12109#endif /* OPT_WIDE_ATTRS */
12110
12111	    /* *INDENT-EQLS* */
12112	    params.xw          = xw;
12113	    params.attr_flags  = (flags & DRAWX_MASK);
12114	    params.draw_flags  = 0;
12115	    params.this_chrset = LineCharSet(screen, ld);
12116	    params.real_chrset = CSET_SWL;
12117	    params.on_wide     = 0;
12118
12119	    drawXtermText(&params,
12120			  currentGC, x, y,
12121			  &base, 1);
12122
12123#if OPT_WIDE_CHARS
12124	    if_OPT_WIDE_CHARS(screen, {
12125		size_t off;
12126
12127		/* *INDENT-EQLS* */
12128		params.draw_flags = NOBACKGROUND;
12129		params.on_wide    = isWide((int) base);
12130
12131		for_each_combData(off, ld) {
12132		    if (!(ld->combData[off][my_col]))
12133			break;
12134		    drawXtermText(&params,
12135				  currentGC, x, y,
12136				  ld->combData[off] + my_col, 1);
12137		}
12138	    });
12139#endif
12140
12141	    if (!filled) {
12142		screen->box->x = (short) x;
12143		screen->box->y = (short) y;
12144		XDrawLines(screen->display, VDrawable(screen), outlineGC,
12145			   screen->box, NBOX, CoordModePrevious);
12146	    }
12147#if OPT_WIDE_ATTRS
12148	    if (fix_italics && UseItalicFont(screen)) {
12149		setCgsFont(xw, currentWin, currentCgs,
12150			   getter(screen, which_font));
12151	    }
12152#endif
12153	}
12154    }
12155    screen->cursor_state = ON;
12156
12157    return;
12158}
12159
12160/*
12161 * hide cursor at previous cursor position in screen.
12162 */
12163void
12164HideCursor(XtermWidget xw)
12165{
12166    TScreen *screen = TScreenOf(xw);
12167    XTermDraw params;
12168    GC currentGC;
12169    int x, y;
12170    IChar base;
12171    unsigned flags;
12172    CellColor fg_bg = initCColor;
12173    Bool in_selection;
12174#if OPT_WIDE_CHARS
12175    int my_col = 0;
12176#endif
12177    int cursor_col;
12178    CLineData *ld = 0;
12179#if OPT_WIDE_ATTRS
12180    int which_Cgs = gcMAX;
12181    unsigned attr_flags;
12182    int which_font = fNorm;
12183    MyGetFont getter = getNormalFont;
12184#endif
12185
12186    if (screen->cursor_state == OFF)
12187	return;
12188    if (INX2ROW(screen, screen->cursorp.row) > screen->max_row)
12189	return;
12190
12191    cursor_col = screen->cursorp.col;
12192
12193#ifndef NO_ACTIVE_ICON
12194    if (IsIcon(screen)) {
12195	screen->cursor_state = OFF;
12196	return;
12197    }
12198#endif /* NO_ACTIVE_ICON */
12199
12200    ld = getLineData(screen, screen->cursorp.row);
12201
12202    base = ld->charData[cursor_col];
12203    flags = ld->attribs[cursor_col];
12204
12205    if_OPT_WIDE_CHARS(screen, {
12206	if (base == HIDDEN_CHAR && cursor_col > 0) {
12207	    /* if cursor points to non-initial part of wide character,
12208	     * back it up
12209	     */
12210	    --cursor_col;
12211	    base = ld->charData[cursor_col];
12212	}
12213	my_col = cursor_col;
12214	if (base == 0)
12215	    base = ' ';
12216	if (isWide((int) base))
12217	    my_col += 1;
12218    });
12219
12220    if (base == 0) {
12221	base = ' ';
12222    }
12223#ifdef EXP_BOGUS_FG
12224    /*
12225     * If the cursor happens to be on blanks, and we have not set both
12226     * foreground and background color, do not treat it as a colored cell.
12227     */
12228#if OPT_ISO_COLORS
12229    if (base == ' ') {
12230	if ((flags & (FG_COLOR | BG_COLOR)) == BG_COLOR) {
12231	    TRACE(("HideCursor - do not treat as a colored cell\n"));
12232	    flags &= ~(FG_COLOR | BG_COLOR);
12233	} else if ((flags & (FG_COLOR | BG_COLOR)) == FG_COLOR) {
12234	    TRACE(("HideCursor - should we treat as a colored cell?\n"));
12235	    if (!(xw->flags & FG_COLOR))
12236		if (CheckBogusForeground(screen, "HideCursor"))
12237		    flags &= ~(FG_COLOR | BG_COLOR);
12238	}
12239    }
12240#endif
12241#endif
12242
12243    /*
12244     * Compare the current cell to the last set of colors used for the
12245     * cursor and update the GC's if needed.
12246     */
12247    if_OPT_ISO_COLORS(screen, {
12248	fg_bg = ld->color[cursor_col];
12249    });
12250
12251    if (OutsideSelection(screen, screen->cursorp.row, screen->cursorp.col))
12252	in_selection = False;
12253    else
12254	in_selection = True;
12255
12256#if OPT_WIDE_ATTRS
12257    attr_flags = ld->attribs[cursor_col];
12258    if ((attr_flags & ATR_ITALIC) ^ (xw->flags & ATR_ITALIC)) {
12259	which_font = ((attr_flags & BOLD) ? fBold : fNorm);
12260	if ((attr_flags & ATR_ITALIC) && UseItalicFont(screen))
12261	    getter = getItalicFont;
12262
12263	if_OPT_WIDE_CHARS(screen, {
12264	    if (isWide((int) base)) {
12265		which_font = ((attr_flags & BOLD) ? fWBold : fWide);
12266	    }
12267	});
12268
12269	which_Cgs = reverseCgs(xw, attr_flags, in_selection, which_font);
12270	if (which_Cgs != gcMAX) {
12271	    setCgsFont(xw, WhichVWin(screen),
12272		       (CgsEnum) which_Cgs,
12273		       getter(screen, which_font));
12274	    getter = (((xw->flags & ATR_ITALIC) && UseItalicFont(screen))
12275		      ? getItalicFont
12276		      : getNormalFont);
12277	}
12278    }
12279#endif
12280
12281    currentGC = updatedXtermGC(xw, flags, fg_bg, in_selection);
12282
12283    TRACE(("HideCursor calling drawXtermText cur(%d,%d)\n",
12284	   screen->cursorp.row, screen->cursorp.col));
12285
12286    x = LineCursorX(screen, ld, cursor_col);
12287    y = CursorY(screen, screen->cursorp.row);
12288
12289    /* *INDENT-EQLS* */
12290    params.xw          = xw;
12291    params.attr_flags  = (flags & DRAWX_MASK);
12292    params.draw_flags  = 0;
12293    params.this_chrset = LineCharSet(screen, ld);
12294    params.real_chrset = CSET_SWL;
12295    params.on_wide     = 0;
12296
12297    drawXtermText(&params,
12298		  currentGC, x, y,
12299		  &base, 1);
12300
12301#if OPT_WIDE_CHARS
12302    if_OPT_WIDE_CHARS(screen, {
12303	size_t off;
12304
12305	/* *INDENT-EQLS* */
12306	params.draw_flags  = NOBACKGROUND;
12307	params.on_wide     = isWide((int) base);
12308
12309	for_each_combData(off, ld) {
12310	    if (!(ld->combData[off][my_col]))
12311		break;
12312	    drawXtermText(&params,
12313			  currentGC, x, y,
12314			  ld->combData[off] + my_col, 1);
12315	}
12316    });
12317#endif
12318    screen->cursor_state = OFF;
12319
12320#if OPT_WIDE_ATTRS
12321    if (which_Cgs != gcMAX) {
12322	setCgsFont(xw, WhichVWin(screen),
12323		   (CgsEnum) which_Cgs,
12324		   getter(screen, which_font));
12325    }
12326#endif
12327    resetXtermGC(xw, flags, in_selection);
12328
12329    refresh_displayed_graphics(xw,
12330			       screen->cursorp.col,
12331			       screen->cursorp.row,
12332			       1, 1);
12333
12334    return;
12335}
12336
12337#if OPT_BLINK_CURS || OPT_BLINK_TEXT
12338static void
12339StartBlinking(XtermWidget xw)
12340{
12341    TScreen *screen = TScreenOf(xw);
12342
12343    if (screen->blink_timer == 0) {
12344	unsigned long interval = (unsigned long) ((screen->cursor_state == ON)
12345						  ? screen->blink_on
12346						  : screen->blink_off);
12347	if (interval == 0)	/* wow! */
12348	    interval = 1;	/* let's humor him anyway */
12349	screen->blink_timer = XtAppAddTimeOut(app_con,
12350					      interval,
12351					      HandleBlinking,
12352					      xw);
12353    }
12354}
12355
12356static void
12357StopBlinking(XtermWidget xw)
12358{
12359    TScreen *screen = TScreenOf(xw);
12360
12361    if (screen->blink_timer) {
12362	XtRemoveTimeOut(screen->blink_timer);
12363	screen->blink_timer = 0;
12364	reallyStopBlinking(xw);
12365    } else {
12366	screen->blink_timer = 0;
12367    }
12368}
12369
12370#if OPT_BLINK_TEXT
12371Bool
12372LineHasBlinking(TScreen *screen, CLineData *ld)
12373{
12374    Bool result = False;
12375    if (ld != 0) {
12376	int col;
12377
12378	for (col = 0; col < MaxCols(screen); ++col) {
12379	    if (ld->attribs[col] & BLINK) {
12380		result = True;
12381		break;
12382	    }
12383	}
12384    }
12385    return result;
12386}
12387#endif
12388
12389/*
12390 * Blink the cursor by alternately showing/hiding cursor.  We leave the timer
12391 * running all the time (even though that's a little inefficient) to make the
12392 * logic simple.
12393 */
12394static void
12395HandleBlinking(XtPointer closure, XtIntervalId * id GCC_UNUSED)
12396{
12397    XtermWidget xw = (XtermWidget) closure;
12398    TScreen *screen = TScreenOf(xw);
12399    Bool resume = False;
12400
12401    screen->blink_timer = 0;
12402    screen->blink_state = !screen->blink_state;
12403
12404#if OPT_BLINK_CURS
12405    if (DoStartBlinking(screen)) {
12406	if (screen->cursor_state == ON) {
12407	    if (screen->select || screen->always_highlight) {
12408		HideCursor(xw);
12409		if (screen->cursor_state == OFF)
12410		    screen->cursor_state = BLINKED_OFF;
12411	    }
12412	} else if (screen->cursor_state == BLINKED_OFF) {
12413	    screen->cursor_state = OFF;
12414	    ShowCursor(xw);
12415	    if (screen->cursor_state == OFF)
12416		screen->cursor_state = BLINKED_OFF;
12417	}
12418	resume = True;
12419    }
12420#endif
12421
12422#if OPT_BLINK_TEXT
12423    /*
12424     * Inspect the lines on the current screen to see if any have the BLINK flag
12425     * associated with them.  Prune off any that have had the corresponding
12426     * cells reset.  If any are left, repaint those lines with ScrnRefresh().
12427     */
12428    if (!(screen->blink_as_bold)) {
12429	int row;
12430	int first_row = screen->max_row;
12431	int last_row = -1;
12432
12433	for (row = screen->max_row; row >= 0; row--) {
12434	    LineData *ld = getLineData(screen, ROW2INX(screen, row));
12435
12436	    if (ld != 0 && LineTstBlinked(ld)) {
12437		if (LineHasBlinking(screen, ld)) {
12438		    resume = True;
12439		    if (row > last_row)
12440			last_row = row;
12441		    if (row < first_row)
12442			first_row = row;
12443		} else {
12444		    LineClrBlinked(ld);
12445		}
12446	    }
12447	}
12448	/*
12449	 * FIXME: this could be a little more efficient, e.g,. by limiting the
12450	 * columns which are updated.
12451	 */
12452	if (first_row <= last_row) {
12453	    ScrnRefresh(xw,
12454			first_row,
12455			0,
12456			last_row + 1 - first_row,
12457			MaxCols(screen),
12458			True);
12459	}
12460    }
12461#endif
12462
12463    /*
12464     * If either the cursor or text is blinking, restart the timer.
12465     */
12466    if (resume)
12467	StartBlinking(xw);
12468}
12469#endif /* OPT_BLINK_CURS || OPT_BLINK_TEXT */
12470
12471void
12472RestartBlinking(XtermWidget xw)
12473{
12474#if OPT_BLINK_CURS || OPT_BLINK_TEXT
12475    TScreen *screen = TScreenOf(xw);
12476
12477    if (screen->blink_timer == 0) {
12478	Bool resume = False;
12479
12480#if OPT_BLINK_CURS
12481	if (DoStartBlinking(screen)) {
12482	    resume = True;
12483	}
12484#endif
12485#if OPT_BLINK_TEXT
12486	if (!resume) {
12487	    int row;
12488
12489	    for (row = screen->max_row; row >= 0; row--) {
12490		CLineData *ld = getLineData(screen, ROW2INX(screen, row));
12491
12492		if (ld != 0 && LineTstBlinked(ld)) {
12493		    if (LineHasBlinking(screen, ld)) {
12494			resume = True;
12495			break;
12496		    }
12497		}
12498	    }
12499	}
12500#endif
12501	if (resume)
12502	    StartBlinking(xw);
12503    }
12504#else
12505    (void) xw;
12506#endif
12507}
12508
12509/*
12510 * Implement soft or hard (full) reset of the VTxxx emulation.  There are a
12511 * couple of differences from real DEC VTxxx terminals (to avoid breaking
12512 * applications which have come to rely on xterm doing this):
12513 *
12514 *	+ autowrap mode should be reset (instead it's reset to the resource
12515 *	  default).
12516 *	+ the popup menu offers a choice of resetting the savedLines, or not.
12517 *	  (but the control sequence does this anyway).
12518 */
12519static void
12520ReallyReset(XtermWidget xw, Bool full, Bool saved)
12521{
12522    TScreen *screen = TScreenOf(xw);
12523    IFlags saveflags = xw->flags;
12524
12525    TRACE(("ReallyReset %s, %s\n",
12526	   full ? "hard" : "soft",
12527	   saved ? "clear savedLines" : "keep savedLines"));
12528
12529    if (!XtIsRealized((Widget) xw) || (CURRENT_EMU() != (Widget) xw)) {
12530	Bell(xw, XkbBI_MinorError, 0);
12531	return;
12532    }
12533
12534    if (saved) {
12535	screen->savedlines = 0;
12536	ScrollBarDrawThumb(xw, 0);
12537    }
12538
12539    /* make cursor visible */
12540    screen->cursor_set = ON;
12541    InitCursorShape(screen, screen);
12542#if OPT_BLINK_CURS
12543    screen->cursor_blink = screen->cursor_blink_i;
12544    screen->cursor_blink_esc = 0;
12545    TRACE(("cursor_shape:%d blinks:%d\n",
12546	   screen->cursor_shape,
12547	   screen->cursor_blink));
12548#endif
12549
12550    /* reset scrolling region */
12551    resetMargins(xw);
12552
12553    bitclr(&xw->flags, ORIGIN);
12554
12555    if_OPT_ISO_COLORS(screen, {
12556	static char empty[1];
12557	reset_SGR_Colors(xw);
12558	if (ResetAnsiColorRequest(xw, empty, 0))
12559	    xtermRepaint(xw);
12560    });
12561
12562    /* Reset character-sets to initial state */
12563    resetCharsets(screen);
12564
12565#if OPT_MOD_FKEYS
12566    /* Reset modifier-resources to initial state */
12567    xw->keyboard.modify_now = xw->keyboard.modify_1st;
12568#endif
12569#if OPT_DEC_RECTOPS
12570    screen->checksum_ext = screen->checksum_ext0;
12571#endif
12572
12573    /* Reset DECSCA */
12574    bitclr(&xw->flags, PROTECTED);
12575    screen->protected_mode = OFF_PROTECT;
12576
12577    if (full) {			/* RIS */
12578	if (screen->bellOnReset)
12579	    Bell(xw, XkbBI_TerminalBell, 0);
12580
12581	reset_displayed_graphics(screen);
12582
12583	/* reset the mouse mode */
12584	screen->send_mouse_pos = MOUSE_OFF;
12585	screen->send_focus_pos = OFF;
12586	screen->extend_coords = 0;
12587	screen->waitingForTrackInfo = False;
12588	screen->eventMode = NORMAL;
12589
12590	xtermShowPointer(xw, True);
12591
12592	TabReset(xw->tabs);
12593	xw->keyboard.flags = MODE_SRM;
12594
12595	guard_keyboard_type = False;
12596	screen->old_fkeys = screen->old_fkeys0;
12597	decode_keyboard_type(xw, &resource);
12598	update_keyboard_type();
12599
12600#if OPT_INITIAL_ERASE
12601	if (xw->keyboard.reset_DECBKM == 1)
12602	    xw->keyboard.flags |= MODE_DECBKM;
12603	else if (xw->keyboard.reset_DECBKM == 2)
12604#endif
12605	    if (TScreenOf(xw)->backarrow_key)
12606		xw->keyboard.flags |= MODE_DECBKM;
12607	TRACE(("full reset DECBKM %s\n",
12608	       BtoS(xw->keyboard.flags & MODE_DECBKM)));
12609
12610#if OPT_SCROLL_LOCK
12611	xtermClearLEDs(screen);
12612#endif
12613	screen->title_modes = screen->title_modes0;
12614	screen->pointer_mode = screen->pointer_mode0;
12615#if OPT_SIXEL_GRAPHICS
12616	if (TScreenOf(xw)->sixel_scrolling)
12617	    xw->keyboard.flags |= MODE_DECSDM;
12618	TRACE(("full reset DECSDM to %s (resource default is %s)\n",
12619	       BtoS(xw->keyboard.flags & MODE_DECSDM),
12620	       BtoS(TScreenOf(xw)->sixel_scrolling)));
12621#endif
12622
12623#if OPT_GRAPHICS
12624	screen->privatecolorregisters = TScreenOf(xw)->privatecolorregisters;
12625	TRACE(("full reset PRIVATE_COLOR_REGISTERS to %s (resource default is %s)\n",
12626	       BtoS(screen->privatecolorregisters),
12627	       BtoS(TScreenOf(xw)->privatecolorregisters)));
12628#endif
12629
12630#if OPT_SIXEL_GRAPHICS
12631	screen->sixel_scrolls_right = TScreenOf(xw)->sixel_scrolls_right;
12632	TRACE(("full reset SIXEL_SCROLLS_RIGHT to %s (resource default is %s)\n",
12633	       BtoS(screen->sixel_scrolls_right),
12634	       BtoS(TScreenOf(xw)->sixel_scrolls_right)));
12635#endif
12636
12637	update_appcursor();
12638	update_appkeypad();
12639	update_decbkm();
12640	update_decsdm();
12641	show_8bit_control(False);
12642	reset_decudk(xw);
12643
12644	FromAlternate(xw);
12645	ClearScreen(xw);
12646	screen->cursor_state = OFF;
12647
12648	if (xw->flags & REVERSE_VIDEO)
12649	    ReverseVideo(xw);
12650	ResetItalics(xw);
12651	xw->flags = xw->initflags;
12652
12653	update_reversevideo();
12654	update_autowrap();
12655	update_reversewrap();
12656	update_autolinefeed();
12657
12658	screen->jumpscroll = (Boolean) (!(xw->flags & SMOOTHSCROLL));
12659	update_jumpscroll();
12660
12661#if OPT_DEC_RECTOPS
12662	screen->cur_decsace = 0;
12663#endif
12664#if OPT_PASTE64 || OPT_READLINE
12665	screen->paste_brackets = OFF;
12666#endif
12667#if OPT_READLINE
12668	screen->click1_moves = OFF;
12669	screen->paste_moves = OFF;
12670	screen->dclick3_deletes = OFF;
12671	screen->paste_quotes = OFF;
12672	screen->paste_literal_nl = OFF;
12673#endif /* OPT_READLINE */
12674
12675	if (screen->c132 && (saveflags & IN132COLUMNS)) {
12676	    TRACE(("Making resize-request to restore 80-columns %dx%d\n",
12677		   MaxRows(screen), MaxCols(screen)));
12678	    RequestResize(xw, MaxRows(screen), 80, True);
12679	    repairSizeHints();
12680	    XSync(screen->display, False);	/* synchronize */
12681	    if (xtermAppPending())
12682		xevents(xw);
12683	}
12684
12685	CursorSet(screen, 0, 0, xw->flags);
12686	CursorSave(xw);
12687    } else {			/* DECSTR */
12688	/*
12689	 * There's a tiny difference, to accommodate usage of xterm.
12690	 * We reset autowrap to the resource values rather than turning
12691	 * it off.
12692	 */
12693	UIntClr(xw->keyboard.flags, (MODE_DECCKM | MODE_KAM | MODE_DECKPAM));
12694	bitcpy(&xw->flags, xw->initflags, WRAPAROUND | REVERSEWRAP);
12695	bitclr(&xw->flags, INSERT | INVERSE | BOLD | BLINK | UNDERLINE | INVISIBLE);
12696	ResetItalics(xw);
12697	if_OPT_ISO_COLORS(screen, {
12698	    reset_SGR_Colors(xw);
12699	});
12700	update_appcursor();
12701	update_autowrap();
12702	update_reversewrap();
12703
12704	CursorSave(xw);
12705	screen->sc[screen->whichBuf].row =
12706	    screen->sc[screen->whichBuf].col = 0;
12707    }
12708}
12709
12710void
12711VTReset(XtermWidget xw, Bool full, Bool saved)
12712{
12713    ReallyReset(xw, full, saved);
12714
12715    FreeAndNull(myState.string_area);
12716    FreeAndNull(myState.print_area);
12717
12718    longjmp(vtjmpbuf, 1);	/* force ground state in parser */
12719}
12720
12721typedef enum {
12722    ccLO,
12723    ccDASH,
12724    ccHI,
12725    ccCOLON,
12726    ccID,
12727    ccCOMMA
12728} CCLASS;
12729
12730/*
12731 * set_character_class - takes a string of the form
12732 *
12733 *   low[-high][:id][,low[-high][:id][...]]
12734 *
12735 * and sets the indicated ranges to the indicated values.
12736 */
12737static int
12738set_character_class(char *s)
12739{
12740#define FMT "%s in range string \"%s\" (position %d)\n"
12741
12742    TRACE(("set_character_class(%s) " TRACE_L "\n", NonNull(s)));
12743    if (IsEmpty(s)) {
12744	TRACE((TRACE_R " ERR set_character_class\n"));
12745	return -1;
12746    } else {
12747	CCLASS state = ccLO;
12748	int arg[3];
12749	int i;
12750	int len = (int) strlen(s);
12751
12752	arg[0] =
12753	    arg[1] =
12754	    arg[2] = -1;
12755
12756	for (i = 0; i < len; ++i) {
12757	    int ch = CharOf(s[i]);
12758	    char *t = 0;
12759	    long value = 0;
12760
12761	    if (isspace(ch))
12762		continue;
12763
12764	    switch (state) {
12765	    case ccLO:
12766	    case ccHI:
12767	    case ccID:
12768		if (!isdigit(ch)) {
12769		    xtermWarning(FMT, "missing number", s, i);
12770		    TRACE((TRACE_R " ERR set_character_class\n"));
12771		    return (-1);
12772		}
12773		value = strtol(s + i, &t, 0);
12774		i = (int) (t - s - 1);
12775		break;
12776	    case ccDASH:
12777	    case ccCOLON:
12778	    case ccCOMMA:
12779		break;
12780	    }
12781
12782	    switch (state) {
12783	    case ccLO:
12784		arg[0] =
12785		    arg[1] = (int) value;
12786		arg[2] = -1;
12787		state = ccDASH;
12788		break;
12789
12790	    case ccDASH:
12791		if (ch == '-') {
12792		    state = ccHI;
12793		} else {
12794		    goto parse_class;
12795		}
12796		break;
12797
12798	    case ccHI:
12799		arg[1] = (int) value;
12800		state = ccCOLON;
12801		break;
12802
12803	      parse_class:
12804	    case ccCOLON:
12805		if (ch == ':') {
12806		    state = ccID;
12807		} else if (ch == ',') {
12808		    goto apply_class;
12809		} else {
12810		    xtermWarning(FMT, "unexpected character", s, i);
12811		    TRACE((TRACE_R " ERR set_character_class\n"));
12812		    return (-1);
12813		}
12814		break;
12815
12816	    case ccID:
12817		arg[2] = (int) value;
12818		state = ccCOMMA;
12819		break;
12820
12821	      apply_class:
12822	    case ccCOMMA:
12823		if (SetCharacterClassRange(arg[0], arg[1], arg[2]) != 0) {
12824		    xtermWarning(FMT, "bad range", s, i);
12825		    TRACE((TRACE_R " ERR set_character_class\n"));
12826		    return -1;
12827		}
12828		state = ccLO;
12829		break;
12830	    }
12831	}
12832	if (state >= ccDASH) {
12833	    if (SetCharacterClassRange(arg[0], arg[1], arg[2]) != 0) {
12834		xtermWarning(FMT, "bad range", s, i);
12835		TRACE((TRACE_R " ERR set_character_class\n"));
12836		return -1;
12837	    }
12838	}
12839    }
12840
12841    TRACE((TRACE_R " OK set_character_class\n"));
12842    return (0);
12843#undef FMT
12844}
12845
12846void
12847getKeymapResources(Widget w,
12848		   const char *mapName,
12849		   const char *mapClass,
12850		   const char *type,
12851		   void *result,
12852		   size_t size)
12853{
12854    XtResource key_resources[1];
12855    key_resources[0].resource_name = XtNtranslations;
12856    key_resources[0].resource_class = XtCTranslations;
12857    key_resources[0].resource_type = (char *) type;
12858    key_resources[0].resource_size = (Cardinal) size;
12859    key_resources[0].resource_offset = 0;
12860    key_resources[0].default_type = key_resources[0].resource_type;
12861    key_resources[0].default_addr = 0;
12862    XtGetSubresources(w, (XtPointer) result, mapName, mapClass,
12863		      key_resources, (Cardinal) 1, NULL, (Cardinal) 0);
12864}
12865
12866/* ARGSUSED */
12867static void
12868HandleKeymapChange(Widget w,
12869		   XEvent *event GCC_UNUSED,
12870		   String *params,
12871		   Cardinal *param_count)
12872{
12873    static XtTranslations keymap, original;
12874
12875    TRACE(("HandleKeymapChange(%#lx, %s)\n",
12876	   (unsigned long) w,
12877	   (*param_count
12878	    ? params[0]
12879	    : "missing")));
12880
12881    if (*param_count != 1)
12882	return;
12883
12884    if (original == NULL) {
12885	TRACE(("...saving original keymap-translations\n"));
12886	original = w->core.tm.translations;
12887    }
12888
12889    if (strcmp(params[0], "None") == 0) {
12890	TRACE(("...restoring original keymap-translations\n"));
12891	XtOverrideTranslations(w, original);
12892    } else {
12893	char mapName[1000];
12894	char mapClass[1000];
12895	char *pmapName;
12896	char *pmapClass;
12897	size_t len;
12898
12899	len = strlen(params[0]) + 7;
12900
12901	pmapName = (char *) MyStackAlloc(len, mapName);
12902	pmapClass = (char *) MyStackAlloc(len, mapClass);
12903	if (pmapName == NULL
12904	    || pmapClass == NULL) {
12905	    SysError(ERROR_KMMALLOC1);
12906	} else {
12907
12908	    (void) sprintf(pmapName, "%sKeymap", params[0]);
12909	    (void) strcpy(pmapClass, pmapName);
12910	    if (islower(CharOf(pmapClass[0])))
12911		pmapClass[0] = x_toupper(pmapClass[0]);
12912	    getKeymapResources(w, pmapName, pmapClass, XtRTranslationTable,
12913			       &keymap, sizeof(keymap));
12914	    if (keymap != NULL) {
12915		TRACE(("...applying keymap \"%s\"\n", pmapName));
12916		XtOverrideTranslations(w, keymap);
12917	    } else {
12918		TRACE(("...found no match for keymap \"%s\"\n", pmapName));
12919	    }
12920
12921	    MyStackFree(pmapName, mapName);
12922	    MyStackFree(pmapClass, mapClass);
12923	}
12924    }
12925}
12926
12927/* ARGSUSED */
12928static void
12929HandleBell(Widget w GCC_UNUSED,
12930	   XEvent *event GCC_UNUSED,
12931	   String *params,	/* [0] = volume */
12932	   Cardinal *param_count)	/* 0 or 1 */
12933{
12934    int percent = (*param_count) ? atoi(params[0]) : 0;
12935
12936    Bell(term, XkbBI_TerminalBell, percent);
12937}
12938
12939/* ARGSUSED */
12940static void
12941HandleVisualBell(Widget w GCC_UNUSED,
12942		 XEvent *event GCC_UNUSED,
12943		 String *params GCC_UNUSED,
12944		 Cardinal *param_count GCC_UNUSED)
12945{
12946    VisualBell();
12947}
12948
12949/* ARGSUSED */
12950static void
12951HandleIgnore(Widget w,
12952	     XEvent *event,
12953	     String *params GCC_UNUSED,
12954	     Cardinal *param_count GCC_UNUSED)
12955{
12956    XtermWidget xw;
12957
12958    TRACE(("Handle ignore for %p %s\n",
12959	   (void *) w, visibleEventType(event->type)));
12960    if ((xw = getXtermWidget(w)) != 0) {
12961	/* do nothing, but check for funny escape sequences */
12962	switch (event->type) {
12963	case ButtonPress:
12964	case ButtonRelease:
12965	case MotionNotify:
12966	    (void) SendMousePosition(xw, event);
12967	    break;
12968	}
12969    }
12970}
12971
12972/* ARGSUSED */
12973static void
12974DoSetSelectedFont(Widget w,
12975		  XtPointer client_data GCC_UNUSED,
12976		  Atom *selection GCC_UNUSED,
12977		  Atom *type,
12978		  XtPointer value,
12979		  unsigned long *length,
12980		  int *format)
12981{
12982    XtermWidget xw = getXtermWidget(w);
12983
12984    if (xw == 0) {
12985	xtermWarning("unexpected widget in DoSetSelectedFont\n");
12986    } else if (*type != XA_STRING || *format != 8) {
12987	Bell(xw, XkbBI_MinorError, 0);
12988    } else {
12989	Boolean failed = False;
12990	int oldFont = TScreenOf(xw)->menu_font_number;
12991	char *save = TScreenOf(xw)->SelectFontName();
12992	char *val;
12993	char *test;
12994	unsigned len = (unsigned) *length;
12995	unsigned tst;
12996
12997	/*
12998	 * Some versions of X deliver null-terminated selections, some do not.
12999	 */
13000	for (tst = 0; tst < len; ++tst) {
13001	    if (((char *) value)[tst] == '\0') {
13002		len = tst;
13003		break;
13004	    }
13005	}
13006
13007	if (len > 0 && (val = TypeMallocN(char, len + 1)) != 0) {
13008	    char *used;
13009
13010	    memcpy(val, value, (size_t) len);
13011	    val[len] = '\0';
13012	    used = x_strtrim(val);
13013	    TRACE(("DoSetSelectedFont(%s)\n", used));
13014	    /* Do some sanity checking to avoid sending a long selection
13015	       back to the server in an OpenFont that is unlikely to succeed.
13016	       XLFD allows up to 255 characters and no control characters;
13017	       we are a little more liberal here. */
13018	    if (len < 1000
13019		&& used != 0
13020		&& !strchr(used, '\n')
13021		&& (test = x_strdup(used)) != 0) {
13022		TScreenOf(xw)->SelectFontName() = test;
13023		if (!xtermLoadFont(xw,
13024				   xtermFontName(used),
13025				   True,
13026				   fontMenu_fontsel)) {
13027		    failed = True;
13028		    free(test);
13029		    TScreenOf(xw)->SelectFontName() = save;
13030		}
13031	    } else {
13032		failed = True;
13033	    }
13034	    if (failed) {
13035		(void) xtermLoadFont(xw,
13036				     xtermFontName(TScreenOf(xw)->MenuFontName(oldFont)),
13037				     True,
13038				     oldFont);
13039		Bell(xw, XkbBI_MinorError, 0);
13040	    }
13041	    free(used);
13042	    free(val);
13043	}
13044    }
13045}
13046
13047void
13048FindFontSelection(XtermWidget xw, const char *atom_name, Bool justprobe)
13049{
13050    TScreen *screen = TScreenOf(xw);
13051    static AtomPtr *atoms;
13052    static unsigned int atomCount = 0;
13053    AtomPtr *pAtom;
13054    unsigned a;
13055    Atom target;
13056
13057    if (!atom_name)
13058	atom_name = ((screen->mappedSelect && atomCount)
13059		     ? screen->mappedSelect[0]
13060		     : "PRIMARY");
13061    TRACE(("FindFontSelection(%s)\n", atom_name));
13062
13063    for (pAtom = atoms, a = atomCount; a; a--, pAtom++) {
13064	if (strcmp(atom_name, XmuNameOfAtom(*pAtom)) == 0) {
13065	    TRACE(("...found atom %d:%s\n", a + 1, atom_name));
13066	    break;
13067	}
13068    }
13069    if (!a) {
13070	atoms = TypeXtReallocN(AtomPtr, atoms, atomCount + 1);
13071	*(pAtom = &atoms[atomCount]) = XmuMakeAtom(atom_name);
13072	++atomCount;
13073	TRACE(("...added atom %d:%s\n", atomCount, atom_name));
13074    }
13075
13076    target = XmuInternAtom(XtDisplay(xw), *pAtom);
13077    if (justprobe) {
13078	screen->SelectFontName() =
13079	    XGetSelectionOwner(XtDisplay(xw), target) ? _Font_Selected_ : 0;
13080	TRACE(("...selected fontname '%s'\n",
13081	       NonNull(screen->SelectFontName())));
13082    } else {
13083	XtGetSelectionValue((Widget) xw, target, XA_STRING,
13084			    DoSetSelectedFont, NULL,
13085			    XtLastTimestampProcessed(XtDisplay(xw)));
13086    }
13087    return;
13088}
13089
13090Bool
13091set_cursor_gcs(XtermWidget xw)
13092{
13093    TScreen *screen = TScreenOf(xw);
13094    VTwin *win = WhichVWin(screen);
13095
13096    Pixel cc = T_COLOR(screen, TEXT_CURSOR);
13097    Pixel fg = T_COLOR(screen, TEXT_FG);
13098    Pixel bg = T_COLOR(screen, TEXT_BG);
13099    Bool changed = False;
13100
13101    /*
13102     * Let's see, there are three things that have "color":
13103     *
13104     *     background
13105     *     text
13106     *     cursorblock
13107     *
13108     * And, there are four situations when drawing a cursor, if we decide
13109     * that we like have a solid block of cursor color with the letter
13110     * that it is highlighting shown in the background color to make it
13111     * stand out:
13112     *
13113     *     selected window, normal video - background on cursor
13114     *     selected window, reverse video - foreground on cursor
13115     *     unselected window, normal video - foreground on background
13116     *     unselected window, reverse video - background on foreground
13117     *
13118     * Since the last two are really just normalGC and reverseGC, we only
13119     * need two new GC's.  Under monochrome, we get the same effect as
13120     * above by setting cursor color to foreground.
13121     */
13122
13123    TRACE(("set_cursor_gcs cc=%#lx, fg=%#lx, bg=%#lx\n", cc, fg, bg));
13124    if (win != 0 && (cc != bg)) {
13125	Pixel xx = ((fg == cc) ? bg : cc);
13126
13127	/* set the fonts to the current one */
13128	setCgsFont(xw, win, gcVTcursNormal, 0);
13129	setCgsFont(xw, win, gcVTcursFilled, 0);
13130	setCgsFont(xw, win, gcVTcursReverse, 0);
13131	setCgsFont(xw, win, gcVTcursOutline, 0);
13132
13133	/* we have a colored cursor */
13134	setCgsFore(xw, win, gcVTcursNormal, fg);
13135	setCgsBack(xw, win, gcVTcursNormal, xx);
13136
13137	setCgsFore(xw, win, gcVTcursFilled, xx);
13138	setCgsBack(xw, win, gcVTcursFilled, fg);
13139
13140	if (screen->always_highlight) {
13141	    /* both GC's use the same color */
13142	    setCgsFore(xw, win, gcVTcursReverse, bg);
13143	    setCgsBack(xw, win, gcVTcursReverse, cc);
13144	} else {
13145	    setCgsFore(xw, win, gcVTcursReverse, bg);
13146	    setCgsBack(xw, win, gcVTcursReverse, cc);
13147	}
13148	set_cursor_outline_gc(xw, screen->always_highlight, fg, bg, cc);
13149	changed = True;
13150	FreeMarkGCs(xw);
13151    }
13152
13153    if (changed) {
13154	TRACE(("...set_cursor_gcs - done\n"));
13155    }
13156    return changed;
13157}
13158
13159/*
13160 * Build up the default translations string, allowing the user to suppress
13161 * some of the features.
13162 */
13163void
13164VTInitTranslations(void)
13165{
13166    /* *INDENT-OFF* */
13167    static struct {
13168	Boolean wanted;
13169	const char *name;
13170	const char *value;
13171    } table[] = {
13172#define DATA(name,value) { False, name, value }
13173	DATA("select",
13174"\
13175         Shift <KeyPress> Select:select-cursor-start() select-cursor-end(SELECT, CUT_BUFFER0) \n\
13176         Shift <KeyPress> Insert:insert-selection(SELECT, CUT_BUFFER0) \n\
13177"
13178	),
13179#if OPT_MAXIMIZE
13180	DATA("fullscreen",
13181"\
13182                 Alt <Key>Return:fullscreen() \n\
13183"
13184	),
13185#endif
13186#if OPT_SCROLL_LOCK
13187	DATA("scroll-lock",
13188"\
13189        <KeyRelease> Scroll_Lock:scroll-lock() \n\
13190"
13191	),
13192#endif
13193#if OPT_SHIFT_FONTS
13194	DATA("shift-fonts",
13195"\
13196    Shift~Ctrl <KeyPress> KP_Add:larger-vt-font() \n\
13197    Shift Ctrl <KeyPress> KP_Add:smaller-vt-font() \n\
13198    Shift <KeyPress> KP_Subtract:smaller-vt-font() \n\
13199"
13200	),
13201#endif
13202	DATA("paging",
13203"\
13204          Shift <KeyPress> Prior:scroll-back(1,halfpage) \n\
13205           Shift <KeyPress> Next:scroll-forw(1,halfpage) \n\
13206"
13207	),
13208	/* This must be the last set mentioning "KeyPress" */
13209	DATA("keypress",
13210"\
13211                ~Meta <KeyPress>:insert-seven-bit() \n\
13212                 Meta <KeyPress>:insert-eight-bit() \n\
13213"
13214	),
13215	DATA("popup-menu",
13216"\
13217                !Ctrl <Btn1Down>:popup-menu(mainMenu) \n\
13218           !Lock Ctrl <Btn1Down>:popup-menu(mainMenu) \n\
13219 !Lock Ctrl @Num_Lock <Btn1Down>:popup-menu(mainMenu) \n\
13220     ! @Num_Lock Ctrl <Btn1Down>:popup-menu(mainMenu) \n\
13221                !Ctrl <Btn2Down>:popup-menu(vtMenu) \n\
13222           !Lock Ctrl <Btn2Down>:popup-menu(vtMenu) \n\
13223 !Lock Ctrl @Num_Lock <Btn2Down>:popup-menu(vtMenu) \n\
13224     ! @Num_Lock Ctrl <Btn2Down>:popup-menu(vtMenu) \n\
13225                !Ctrl <Btn3Down>:popup-menu(fontMenu) \n\
13226           !Lock Ctrl <Btn3Down>:popup-menu(fontMenu) \n\
13227 !Lock Ctrl @Num_Lock <Btn3Down>:popup-menu(fontMenu) \n\
13228     ! @Num_Lock Ctrl <Btn3Down>:popup-menu(fontMenu) \n\
13229"
13230	),
13231	/* PROCURA added "Meta <Btn2Down>:clear-saved-lines()" */
13232	DATA("reset",
13233"\
13234                 Meta <Btn2Down>:clear-saved-lines() \n\
13235"
13236	),
13237	DATA("select",
13238"\
13239                ~Meta <Btn1Down>:select-start() \n\
13240              ~Meta <Btn1Motion>:select-extend() \n\
13241          ~Ctrl ~Meta <Btn2Down>:ignore() \n\
13242            ~Ctrl ~Meta <Btn2Up>:insert-selection(SELECT, CUT_BUFFER0) \n\
13243          ~Ctrl ~Meta <Btn3Down>:start-extend() \n\
13244              ~Meta <Btn3Motion>:select-extend() \n\
13245                         <BtnUp>:select-end(SELECT, CUT_BUFFER0) \n\
13246"
13247	),
13248	DATA("wheel-mouse",
13249"\
13250                 Ctrl <Btn4Down>:scroll-back(1,halfpage,m) \n\
13251            Lock Ctrl <Btn4Down>:scroll-back(1,halfpage,m) \n\
13252  Lock @Num_Lock Ctrl <Btn4Down>:scroll-back(1,halfpage,m) \n\
13253       @Num_Lock Ctrl <Btn4Down>:scroll-back(1,halfpage,m) \n\
13254                      <Btn4Down>:scroll-back(5,line,m)     \n\
13255                 Ctrl <Btn5Down>:scroll-forw(1,halfpage,m) \n\
13256            Lock Ctrl <Btn5Down>:scroll-forw(1,halfpage,m) \n\
13257  Lock @Num_Lock Ctrl <Btn5Down>:scroll-forw(1,halfpage,m) \n\
13258       @Num_Lock Ctrl <Btn5Down>:scroll-forw(1,halfpage,m) \n\
13259                      <Btn5Down>:scroll-forw(5,line,m)     \n\
13260"
13261	),
13262	DATA("pointer",
13263"\
13264                     <BtnMotion>:pointer-motion() \n\
13265                       <BtnDown>:pointer-button() \n\
13266                         <BtnUp>:pointer-button() \n\
13267"
13268	),
13269	DATA("default",
13270"\
13271                         <BtnUp>:ignore() \n\
13272"
13273	)
13274    };
13275#undef DATA
13276    /* *INDENT-ON* */
13277
13278    char *result = 0;
13279
13280    int pass;
13281    Cardinal item;
13282
13283    TRACE(("VTInitTranslations\n"));
13284    for (item = 0; item < XtNumber(table); ++item) {
13285	table[item].wanted = True;
13286    }
13287#if OPT_MAXIMIZE
13288    /*
13289     * As a special case, allow for disabling the alt-enter translation if
13290     * the resource settings prevent fullscreen from being used.  We would
13291     * do the same for scroll-lock and shift-fonts if they were application
13292     * resources too, rather than in the widget.
13293     */
13294    if (resource.fullscreen == esNever) {
13295	for (item = 0; item < XtNumber(table); ++item) {
13296	    if (!strcmp(table[item].name, "fullscreen")) {
13297		table[item].wanted = False;
13298		TRACE(("omit(%s):\n%s\n", table[item].name, table[item].value));
13299	    }
13300	}
13301    }
13302#endif
13303    if (!IsEmpty(resource.omitTranslation)) {
13304	char *value;
13305	const char *source = resource.omitTranslation;
13306
13307	while (*source != '\0' && (value = ParseList(&source)) != 0) {
13308	    size_t len = strlen(value);
13309
13310	    TRACE(("parsed:%s\n", value));
13311	    for (item = 0; item < XtNumber(table); ++item) {
13312		if (strlen(table[item].name) >= len
13313		    && x_strncasecmp(table[item].name,
13314				     value,
13315				     (unsigned) len) == 0) {
13316		    table[item].wanted = False;
13317		    TRACE(("omit(%s):\n%s\n", table[item].name, table[item].value));
13318		    /* continue: "select", for instance is two chunks */
13319		}
13320	    }
13321	    free(value);
13322	}
13323    }
13324
13325    for (pass = 0; pass < 2; ++pass) {
13326	size_t needed = 0;
13327	for (item = 0; item < XtNumber(table); ++item) {
13328	    if (table[item].wanted) {
13329		if (pass) {
13330		    strcat(result, table[item].value);
13331		} else {
13332		    needed += strlen(table[item].value) + 1;
13333		}
13334	    }
13335	}
13336	if (!pass) {
13337	    result = XtMalloc((Cardinal) needed);
13338	    *result = '\0';
13339	}
13340    }
13341
13342    TRACE(("result:\n%s\n", result));
13343
13344    defaultTranslations = result;
13345    free((void *) xtermClassRec.core_class.tm_table);
13346    xtermClassRec.core_class.tm_table = result;
13347}
13348
13349#ifdef NO_LEAKS
13350void
13351noleaks_charproc(void)
13352{
13353    free(v_buffer);
13354}
13355#endif
13356