charproc.c revision d522f475
1/* $XTermId: charproc.c,v 1.842 2008/04/20 22:08:42 tom Exp $ */
2
3/*
4
5Copyright 1999-2007,2008 by Thomas E. Dickey
6
7                        All Rights Reserved
8
9Permission is hereby granted, free of charge, to any person obtaining a
10copy of this software and associated documentation files (the
11"Software"), to deal in the Software without restriction, including
12without limitation the rights to use, copy, modify, merge, publish,
13distribute, sublicense, and/or sell copies of the Software, and to
14permit persons to whom the Software is furnished to do so, subject to
15the following conditions:
16
17The above copyright notice and this permission notice shall be included
18in all copies or substantial portions of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
24CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27
28Except as contained in this notice, the name(s) of the above copyright
29holders shall not be used in advertising or otherwise to promote the
30sale, use or other dealings in this Software without prior written
31authorization.
32
33Copyright 1988  The Open Group
34
35Permission to use, copy, modify, distribute, and sell this software and its
36documentation for any purpose is hereby granted without fee, provided that
37the above copyright notice appear in all copies and that both that
38copyright notice and this permission notice appear in supporting
39documentation.
40
41The above copyright notice and this permission notice shall be included in
42all copies or substantial portions of the Software.
43
44THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
45IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
46FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
47OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
48AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
49CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
50
51Except as contained in this notice, the name of The Open Group shall not be
52used in advertising or otherwise to promote the sale, use or other dealings
53in this Software without prior written authorization from The Open Group.
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/cursorfont.h>
87#include <X11/Xmu/Atoms.h>
88#include <X11/Xmu/CharSet.h>
89#include <X11/Xmu/Converters.h>
90
91#if OPT_INPUT_METHOD
92
93#if defined(HAVE_LIB_XAW)
94#include <X11/Xaw/XawImP.h>
95#elif defined(HAVE_LIB_XAW3D)
96#include <X11/Xaw3d/XawImP.h>
97#elif defined(HAVE_LIB_NEXTAW)
98#include <X11/neXtaw/XawImP.h>
99#elif defined(HAVE_LIB_XAWPLUS)
100#include <X11/XawPlus/XawImP.h>
101#endif
102
103#endif
104
105#if OPT_WIDE_CHARS
106#include <wcwidth.h>
107#include <precompose.h>
108#ifdef HAVE_LANGINFO_CODESET
109#include <langinfo.h>
110#endif
111#endif
112
113#if OPT_INPUT_METHOD
114#include <X11/Xlocale.h>
115#endif
116
117#include <stdio.h>
118#include <ctype.h>
119
120#if defined(HAVE_SCHED_YIELD)
121#include <sched.h>
122#endif
123
124#include <VTparse.h>
125#include <data.h>
126#include <error.h>
127#include <menu.h>
128#include <main.h>
129#include <fontutils.h>
130#include <xcharmouse.h>
131#include <charclass.h>
132#include <xstrings.h>
133
134static IChar doinput(void);
135static int set_character_class(char *s);
136static void FromAlternate(XtermWidget /* xw */ );
137static void RequestResize(XtermWidget termw, int rows, int cols, Bool text);
138static void SwitchBufs(XtermWidget xw);
139static void ToAlternate(XtermWidget /* xw */ );
140static void VTallocbuf(void);
141static void ansi_modes(XtermWidget termw,
142		       void (*func) (unsigned *p, unsigned mask));
143static void bitclr(unsigned *p, unsigned mask);
144static void bitcpy(unsigned *p, unsigned q, unsigned mask);
145static void bitset(unsigned *p, unsigned mask);
146static void dpmodes(XtermWidget termw, void (*func) (unsigned *p, unsigned mask));
147static void restoremodes(XtermWidget termw);
148static void savemodes(XtermWidget termw);
149static void window_ops(XtermWidget termw);
150
151#define DoStartBlinking(s) ((s)->cursor_blink ^ (s)->cursor_blink_esc)
152
153#if OPT_BLINK_CURS || OPT_BLINK_TEXT
154static void HandleBlinking(XtPointer closure, XtIntervalId * id);
155static void StartBlinking(TScreen * screen);
156static void StopBlinking(TScreen * screen);
157#else
158#define StartBlinking(screen)	/* nothing */
159#define StopBlinking(screen)	/* nothing */
160#endif
161
162#if OPT_INPUT_METHOD
163static void PreeditPosition(TScreen * screen);
164#endif
165
166#define	DEFAULT		-1
167#define BELLSUPPRESSMSEC 200
168
169static int nparam;
170static ANSI reply;
171static int param[NPARAM];
172
173static jmp_buf vtjmpbuf;
174
175/* event handlers */
176static void HandleBell PROTO_XT_ACTIONS_ARGS;
177static void HandleIgnore PROTO_XT_ACTIONS_ARGS;
178static void HandleKeymapChange PROTO_XT_ACTIONS_ARGS;
179static void HandleVisualBell PROTO_XT_ACTIONS_ARGS;
180#if HANDLE_STRUCT_NOTIFY
181static void HandleStructNotify PROTO_XT_EV_HANDLER_ARGS;
182#endif
183
184/*
185 * NOTE: VTInitialize zeros out the entire ".screen" component of the
186 * XtermWidget, so make sure to add an assignment statement in VTInitialize()
187 * for each new ".screen" field added to this resource list.
188 */
189
190/* Defaults */
191#if OPT_ISO_COLORS
192
193/*
194 * If we default to colorMode enabled, compile-in defaults for the ANSI colors.
195 */
196#if DFT_COLORMODE
197#define DFT_COLOR(name) name
198#else
199#define DFT_COLOR(name) XtDefaultForeground
200#endif
201#endif
202
203static char *_Font_Selected_ = "yes";	/* string is arbitrary */
204
205static char defaultTranslations[] =
206"\
207          Shift <KeyPress> Prior:scroll-back(1,halfpage) \n\
208           Shift <KeyPress> Next:scroll-forw(1,halfpage) \n\
209         Shift <KeyPress> Select:select-cursor-start() select-cursor-end(SELECT, CUT_BUFFER0) \n\
210         Shift <KeyPress> Insert:insert-selection(SELECT, CUT_BUFFER0) \n\
211"
212#if OPT_SHIFT_FONTS
213"\
214    Shift~Ctrl <KeyPress> KP_Add:larger-vt-font() \n\
215    Shift Ctrl <KeyPress> KP_Add:smaller-vt-font() \n\
216    Shift <KeyPress> KP_Subtract:smaller-vt-font() \n\
217"
218#endif
219"\
220                ~Meta <KeyPress>:insert-seven-bit() \n\
221                 Meta <KeyPress>:insert-eight-bit() \n\
222                !Ctrl <Btn1Down>:popup-menu(mainMenu) \n\
223           !Lock Ctrl <Btn1Down>:popup-menu(mainMenu) \n\
224 !Lock Ctrl @Num_Lock <Btn1Down>:popup-menu(mainMenu) \n\
225     ! @Num_Lock Ctrl <Btn1Down>:popup-menu(mainMenu) \n\
226                ~Meta <Btn1Down>:select-start() \n\
227              ~Meta <Btn1Motion>:select-extend() \n\
228                !Ctrl <Btn2Down>:popup-menu(vtMenu) \n\
229           !Lock Ctrl <Btn2Down>:popup-menu(vtMenu) \n\
230 !Lock Ctrl @Num_Lock <Btn2Down>:popup-menu(vtMenu) \n\
231     ! @Num_Lock Ctrl <Btn2Down>:popup-menu(vtMenu) \n\
232          ~Ctrl ~Meta <Btn2Down>:ignore() \n\
233                 Meta <Btn2Down>:clear-saved-lines() \n\
234            ~Ctrl ~Meta <Btn2Up>:insert-selection(SELECT, CUT_BUFFER0) \n\
235                !Ctrl <Btn3Down>:popup-menu(fontMenu) \n\
236           !Lock Ctrl <Btn3Down>:popup-menu(fontMenu) \n\
237 !Lock Ctrl @Num_Lock <Btn3Down>:popup-menu(fontMenu) \n\
238     ! @Num_Lock Ctrl <Btn3Down>:popup-menu(fontMenu) \n\
239          ~Ctrl ~Meta <Btn3Down>:start-extend() \n\
240              ~Meta <Btn3Motion>:select-extend() \n\
241                 Ctrl <Btn4Down>:scroll-back(1,halfpage,m) \n\
242            Lock Ctrl <Btn4Down>:scroll-back(1,halfpage,m) \n\
243  Lock @Num_Lock Ctrl <Btn4Down>:scroll-back(1,halfpage,m) \n\
244       @Num_Lock Ctrl <Btn4Down>:scroll-back(1,halfpage,m) \n\
245                      <Btn4Down>:scroll-back(5,line,m)     \n\
246                 Ctrl <Btn5Down>:scroll-forw(1,halfpage,m) \n\
247            Lock Ctrl <Btn5Down>:scroll-forw(1,halfpage,m) \n\
248  Lock @Num_Lock Ctrl <Btn5Down>:scroll-forw(1,halfpage,m) \n\
249       @Num_Lock Ctrl <Btn5Down>:scroll-forw(1,halfpage,m) \n\
250                      <Btn5Down>:scroll-forw(5,line,m)     \n\
251                         <BtnUp>:select-end(SELECT, CUT_BUFFER0) \n\
252                       <BtnDown>:ignore() \
253";				/* PROCURA added "Meta <Btn2Down>:clear-saved-lines()" */
254/* *INDENT-OFF* */
255static XtActionsRec actionsList[] = {
256    { "allow-send-events",	HandleAllowSends },
257    { "bell",			HandleBell },
258    { "clear-saved-lines",	HandleClearSavedLines },
259    { "create-menu",		HandleCreateMenu },
260    { "delete-is-del",		HandleDeleteIsDEL },
261    { "dired-button",		DiredButton },
262    { "hard-reset",		HandleHardReset },
263    { "ignore",			HandleIgnore },
264    { "insert",			HandleKeyPressed },  /* alias for insert-seven-bit */
265    { "insert-eight-bit",	HandleEightBitKeyPressed },
266    { "insert-selection",	HandleInsertSelection },
267    { "insert-seven-bit",	HandleKeyPressed },
268    { "interpret",		HandleInterpret },
269    { "keymap",			HandleKeymapChange },
270    { "popup-menu",		HandlePopupMenu },
271    { "print",			HandlePrintScreen },
272    { "print-redir",		HandlePrintControlMode },
273    { "quit",			HandleQuit },
274    { "redraw",			HandleRedraw },
275    { "scroll-back",		HandleScrollBack },
276    { "scroll-forw",		HandleScrollForward },
277    { "secure",			HandleSecure },
278    { "select-cursor-end",	HandleKeyboardSelectEnd },
279    { "select-cursor-extend",   HandleKeyboardSelectExtend },
280    { "select-cursor-start",	HandleKeyboardSelectStart },
281    { "select-end",		HandleSelectEnd },
282    { "select-extend",		HandleSelectExtend },
283    { "select-set",		HandleSelectSet },
284    { "select-start",		HandleSelectStart },
285    { "send-signal",		HandleSendSignal },
286    { "set-8-bit-control",	Handle8BitControl },
287    { "set-allow132",		HandleAllow132 },
288    { "set-altscreen",		HandleAltScreen },
289    { "set-appcursor",		HandleAppCursor },
290    { "set-appkeypad",		HandleAppKeypad },
291    { "set-autolinefeed",	HandleAutoLineFeed },
292    { "set-autowrap",		HandleAutoWrap },
293    { "set-backarrow",		HandleBackarrow },
294    { "set-bellIsUrgent",	HandleBellIsUrgent },
295    { "set-cursesemul",		HandleCursesEmul },
296    { "set-jumpscroll",		HandleJumpscroll },
297    { "set-keep-selection",	HandleKeepSelection },
298    { "set-marginbell",		HandleMarginBell },
299    { "set-old-function-keys",	HandleOldFunctionKeys },
300    { "set-pop-on-bell",	HandleSetPopOnBell },
301    { "set-reverse-video",	HandleReverseVideo },
302    { "set-reversewrap",	HandleReverseWrap },
303    { "set-scroll-on-key",	HandleScrollKey },
304    { "set-scroll-on-tty-output", HandleScrollTtyOutput },
305    { "set-scrollbar",		HandleScrollbar },
306    { "set-select",		HandleSetSelect },
307    { "set-sun-keyboard",	HandleSunKeyboard },
308    { "set-titeInhibit",	HandleTiteInhibit },
309    { "set-visual-bell",	HandleSetVisualBell },
310    { "set-vt-font",		HandleSetFont },
311    { "soft-reset",		HandleSoftReset },
312    { "start-cursor-extend",	HandleKeyboardStartExtend },
313    { "start-extend",		HandleStartExtend },
314    { "string",			HandleStringEvent },
315    { "vi-button",		ViButton },
316    { "visual-bell",		HandleVisualBell },
317#ifdef ALLOWLOGGING
318    { "set-logging",		HandleLogging },
319#endif
320#if OPT_BLINK_CURS
321    { "set-cursorblink",	HandleCursorBlink },
322#endif
323#if OPT_BOX_CHARS
324    { "set-font-linedrawing",	HandleFontBoxChars },
325#endif
326#if OPT_DABBREV
327    { "dabbrev-expand",		HandleDabbrevExpand },
328#endif
329#if OPT_DEC_CHRSET
330    { "set-font-doublesize",	HandleFontDoublesize },
331#endif
332#if OPT_DEC_SOFTFONT
333    { "set-font-loading",	HandleFontLoading },
334#endif
335#if OPT_EXEC_XTERM
336    { "spawn-new-terminal",	HandleSpawnTerminal },
337#endif
338#if OPT_HP_FUNC_KEYS
339    { "set-hp-function-keys",	HandleHpFunctionKeys },
340#endif
341#if OPT_LOAD_VTFONTS
342    { "load-vt-fonts",		HandleLoadVTFonts },
343#endif
344#if OPT_MAXIMIZE
345    { "deiconify",		HandleDeIconify },
346    { "iconify",		HandleIconify },
347    { "maximize",		HandleMaximize },
348    { "restore",		HandleRestoreSize },
349#endif
350#if OPT_NUM_LOCK
351    { "alt-sends-escape",	HandleAltEsc },
352    { "meta-sends-escape",	HandleMetaEsc },
353    { "set-num-lock",		HandleNumLock },
354#endif
355#if OPT_READLINE
356    { "readline-button",	ReadLineButton },
357#endif
358#if OPT_RENDERFONT
359    { "set-render-font",	HandleRenderFont },
360#endif
361#if OPT_SCO_FUNC_KEYS
362    { "set-sco-function-keys",	HandleScoFunctionKeys },
363#endif
364#if OPT_SHIFT_FONTS
365    { "larger-vt-font",		HandleLargerFont },
366    { "smaller-vt-font",	HandleSmallerFont },
367#endif
368#if OPT_SUN_FUNC_KEYS
369    { "set-sun-function-keys",	HandleSunFunctionKeys },
370#endif
371#if OPT_TEK4014
372    { "set-terminal-type",	HandleSetTerminalType },
373    { "set-visibility",		HandleVisibility },
374    { "set-tek-text",		HandleSetTekText },
375    { "tek-page",		HandleTekPage },
376    { "tek-reset",		HandleTekReset },
377    { "tek-copy",		HandleTekCopy },
378#endif
379#if OPT_TOOLBAR
380    { "set-toolbar",		HandleToolbar },
381#endif
382#if OPT_WIDE_CHARS
383    { "set-utf8-mode",		HandleUTF8Mode },
384    { "set-utf8-title",		HandleUTF8Title },
385#endif
386};
387/* *INDENT-ON* */
388
389static XtResource resources[] =
390{
391    Bres(XtNallowSendEvents, XtCAllowSendEvents, screen.allowSendEvent0, False),
392    Bres(XtNallowTitleOps, XtCAllowTitleOps, screen.allowTitleOp0, True),
393    Bres(XtNallowWindowOps, XtCAllowWindowOps, screen.allowWindowOp0, True),
394    Bres(XtNaltIsNotMeta, XtCAltIsNotMeta, screen.alt_is_not_meta, False),
395    Bres(XtNaltSendsEscape, XtCAltSendsEscape, screen.alt_sends_esc, False),
396    Bres(XtNalwaysBoldMode, XtCAlwaysBoldMode, screen.always_bold_mode, False),
397    Bres(XtNalwaysHighlight, XtCAlwaysHighlight, screen.always_highlight, False),
398    Bres(XtNappcursorDefault, XtCAppcursorDefault, misc.appcursorDefault, False),
399    Bres(XtNappkeypadDefault, XtCAppkeypadDefault, misc.appkeypadDefault, False),
400    Bres(XtNautoWrap, XtCAutoWrap, misc.autoWrap, True),
401    Bres(XtNawaitInput, XtCAwaitInput, screen.awaitInput, False),
402    Bres(XtNfreeBoldBox, XtCFreeBoldBox, screen.free_bold_box, False),
403    Bres(XtNbackarrowKey, XtCBackarrowKey, screen.backarrow_key, True),
404    Bres(XtNbellIsUrgent, XtCBellIsUrgent, screen.bellIsUrgent, False),
405    Bres(XtNbellOnReset, XtCBellOnReset, screen.bellOnReset, True),
406    Bres(XtNboldMode, XtCBoldMode, screen.bold_mode, True),
407    Bres(XtNbrokenSelections, XtCBrokenSelections, screen.brokenSelections, False),
408    Bres(XtNc132, XtCC132, screen.c132, False),
409    Bres(XtNcurses, XtCCurses, screen.curses, False),
410    Bres(XtNcutNewline, XtCCutNewline, screen.cutNewline, True),
411    Bres(XtNcutToBeginningOfLine, XtCCutToBeginningOfLine,
412	 screen.cutToBeginningOfLine, True),
413    Bres(XtNdeleteIsDEL, XtCDeleteIsDEL, screen.delete_is_del, DEFDELETE_DEL),
414    Bres(XtNdynamicColors, XtCDynamicColors, misc.dynamicColors, True),
415    Bres(XtNeightBitControl, XtCEightBitControl, screen.control_eight_bits, False),
416    Bres(XtNeightBitInput, XtCEightBitInput, screen.input_eight_bits, True),
417    Bres(XtNeightBitOutput, XtCEightBitOutput, screen.output_eight_bits, True),
418    Bres(XtNhighlightSelection, XtCHighlightSelection,
419	 screen.highlight_selection, False),
420    Bres(XtNhpLowerleftBugCompat, XtCHpLowerleftBugCompat, screen.hp_ll_bc, False),
421    Bres(XtNi18nSelections, XtCI18nSelections, screen.i18nSelections, True),
422    Bres(XtNjumpScroll, XtCJumpScroll, screen.jumpscroll, True),
423    Bres(XtNkeepSelection, XtCKeepSelection, screen.keepSelection, False),
424    Bres(XtNloginShell, XtCLoginShell, misc.login_shell, False),
425    Bres(XtNmarginBell, XtCMarginBell, screen.marginbell, False),
426    Bres(XtNmetaSendsEscape, XtCMetaSendsEscape, screen.meta_sends_esc, False),
427    Bres(XtNmultiScroll, XtCMultiScroll, screen.multiscroll, False),
428    Bres(XtNoldXtermFKeys, XtCOldXtermFKeys, screen.old_fkeys, False),
429    Bres(XtNpopOnBell, XtCPopOnBell, screen.poponbell, False),
430    Bres(XtNprinterAutoClose, XtCPrinterAutoClose, screen.printer_autoclose, False),
431    Bres(XtNprinterExtent, XtCPrinterExtent, screen.printer_extent, False),
432    Bres(XtNprinterFormFeed, XtCPrinterFormFeed, screen.printer_formfeed, False),
433    Bres(XtNquietGrab, XtCQuietGrab, screen.quiet_grab, False),
434    Bres(XtNreverseVideo, XtCReverseVideo, misc.re_verse, False),
435    Bres(XtNreverseWrap, XtCReverseWrap, misc.reverseWrap, False),
436    Bres(XtNscrollBar, XtCScrollBar, misc.scrollbar, False),
437    Bres(XtNscrollKey, XtCScrollCond, screen.scrollkey, False),
438    Bres(XtNscrollTtyOutput, XtCScrollCond, screen.scrollttyoutput, True),
439    Bres(XtNselectToClipboard, XtCSelectToClipboard,
440	 screen.selectToClipboard, False),
441    Bres(XtNsignalInhibit, XtCSignalInhibit, misc.signalInhibit, False),
442    Bres(XtNtiteInhibit, XtCTiteInhibit, misc.titeInhibit, False),
443    Bres(XtNtiXtraScroll, XtCTiXtraScroll, misc.tiXtraScroll, False),
444    Bres(XtNtrimSelection, XtCTrimSelection, screen.trim_selection, False),
445    Bres(XtNunderLine, XtCUnderLine, screen.underline, True),
446    Bres(XtNvisualBell, XtCVisualBell, screen.visualbell, False),
447
448    Ires(XtNbellSuppressTime, XtCBellSuppressTime, screen.bellSuppressTime, BELLSUPPRESSMSEC),
449    Ires(XtNinternalBorder, XtCBorderWidth, screen.border, DEFBORDER),
450    Ires(XtNlimitResize, XtCLimitResize, misc.limit_resize, 1),
451    Ires(XtNmultiClickTime, XtCMultiClickTime, screen.multiClickTime, MULTICLICKTIME),
452    Ires(XtNnMarginBell, XtCColumn, screen.nmarginbell, N_MARGINBELL),
453    Ires(XtNpointerMode, XtCPointerMode, screen.pointer_mode, DEF_POINTER_MODE),
454    Ires(XtNprinterControlMode, XtCPrinterControlMode,
455	 screen.printer_controlmode, 0),
456    Ires(XtNvisualBellDelay, XtCVisualBellDelay, screen.visualBellDelay, 100),
457    Ires(XtNsaveLines, XtCSaveLines, screen.savelines, SAVELINES),
458    Ires(XtNscrollBarBorder, XtCScrollBarBorder, screen.scrollBarBorder, 1),
459    Ires(XtNscrollLines, XtCScrollLines, screen.scrolllines, SCROLLLINES),
460
461    Sres(XtNinitialFont, XtCInitialFont, screen.initial_font, NULL),
462    Sres(XtNfont1, XtCFont1, screen.MenuFontName(fontMenu_font1), NULL),
463    Sres(XtNfont2, XtCFont2, screen.MenuFontName(fontMenu_font2), NULL),
464    Sres(XtNfont3, XtCFont3, screen.MenuFontName(fontMenu_font3), NULL),
465    Sres(XtNfont4, XtCFont4, screen.MenuFontName(fontMenu_font4), NULL),
466    Sres(XtNfont5, XtCFont5, screen.MenuFontName(fontMenu_font5), NULL),
467    Sres(XtNfont6, XtCFont6, screen.MenuFontName(fontMenu_font6), NULL),
468    Sres(XtNanswerbackString, XtCAnswerbackString, screen.answer_back, ""),
469    Sres(XtNboldFont, XtCBoldFont, misc.default_font.f_b, DEFBOLDFONT),
470    Sres(XtNcharClass, XtCCharClass, screen.charClass, NULL),
471    Sres(XtNdecTerminalID, XtCDecTerminalID, screen.term_id, DFT_DECID),
472    Sres(XtNfont, XtCFont, misc.default_font.f_n, DEFFONT),
473    Sres(XtNgeometry, XtCGeometry, misc.geo_metry, NULL),
474    Sres(XtNkeyboardDialect, XtCKeyboardDialect, screen.keyboard_dialect, DFT_KBD_DIALECT),
475    Sres(XtNprinterCommand, XtCPrinterCommand, screen.printer_command, ""),
476    Sres(XtNtekGeometry, XtCGeometry, misc.T_geometry, NULL),
477
478    Tres(XtNcursorColor, XtCCursorColor, TEXT_CURSOR, XtDefaultForeground),
479    Tres(XtNforeground, XtCForeground, TEXT_FG, XtDefaultForeground),
480    Tres(XtNpointerColor, XtCPointerColor, MOUSE_FG, XtDefaultForeground),
481    Tres(XtNbackground, XtCBackground, TEXT_BG, XtDefaultBackground),
482    Tres(XtNpointerColorBackground, XtCBackground, MOUSE_BG, XtDefaultBackground),
483
484    {XtNresizeGravity, XtCResizeGravity, XtRGravity, sizeof(XtGravity),
485     XtOffsetOf(XtermWidgetRec, misc.resizeGravity),
486     XtRImmediate, (XtPointer) SouthWestGravity},
487
488    {XtNpointerShape, XtCCursor, XtRCursor, sizeof(Cursor),
489     XtOffsetOf(XtermWidgetRec, screen.pointer_cursor),
490     XtRString, (XtPointer) "xterm"},
491
492#ifdef ALLOWLOGGING
493    Bres(XtNlogInhibit, XtCLogInhibit, misc.logInhibit, False),
494    Bres(XtNlogging, XtCLogging, misc.log_on, False),
495    Sres(XtNlogFile, XtCLogfile, screen.logfile, NULL),
496#endif
497
498#ifndef NO_ACTIVE_ICON
499    Bres("activeIcon", "ActiveIcon", misc.active_icon, False),
500    Ires("iconBorderWidth", XtCBorderWidth, misc.icon_border_width, 2),
501    Fres("iconFont", "IconFont", screen.fnt_icon.fs, XtDefaultFont),
502    Cres("iconBorderColor", XtCBorderColor, misc.icon_border_pixel, XtDefaultBackground),
503#endif				/* NO_ACTIVE_ICON */
504
505#if OPT_BLINK_CURS
506    Bres(XtNcursorBlink, XtCCursorBlink, screen.cursor_blink, False),
507#endif
508
509#if OPT_BLINK_TEXT
510    Bres(XtNshowBlinkAsBold, XtCCursorBlink, screen.blink_as_bold, DEFBLINKASBOLD),
511#endif
512
513#if OPT_BLINK_CURS || OPT_BLINK_TEXT
514    Ires(XtNcursorOnTime, XtCCursorOnTime, screen.blink_on, 600),
515    Ires(XtNcursorOffTime, XtCCursorOffTime, screen.blink_off, 300),
516#endif
517
518#if OPT_BOX_CHARS
519    Bres(XtNforceBoxChars, XtCForceBoxChars, screen.force_box_chars, False),
520    Bres(XtNshowMissingGlyphs, XtCShowMissingGlyphs, screen.force_all_chars, False),
521#endif
522
523#if OPT_BROKEN_OSC
524    Bres(XtNbrokenLinuxOSC, XtCBrokenLinuxOSC, screen.brokenLinuxOSC, True),
525#endif
526
527#if OPT_BROKEN_ST
528    Bres(XtNbrokenStringTerm, XtCBrokenStringTerm, screen.brokenStringTerm, True),
529#endif
530
531#if OPT_C1_PRINT
532    Bres(XtNallowC1Printable, XtCAllowC1Printable, screen.c1_printable, False),
533#endif
534
535#if OPT_CLIP_BOLD
536    Bres(XtNuseClipping, XtCUseClipping, screen.use_clipping, True),
537#endif
538
539#if OPT_DEC_CHRSET
540    Bres(XtNfontDoublesize, XtCFontDoublesize, screen.font_doublesize, True),
541    Ires(XtNcacheDoublesize, XtCCacheDoublesize, screen.cache_doublesize, NUM_CHRSET),
542#endif
543
544#if OPT_HIGHLIGHT_COLOR
545    Tres(XtNhighlightColor, XtCHighlightColor, HIGHLIGHT_BG, XtDefaultForeground),
546    Tres(XtNhighlightTextColor, XtCHighlightTextColor, HIGHLIGHT_FG, XtDefaultBackground),
547    Bres(XtNhighlightReverse, XtCHighlightReverse, screen.hilite_reverse, True),
548    Bres(XtNhighlightColorMode, XtCHighlightColorMode, screen.hilite_color, Maybe),
549#endif				/* OPT_HIGHLIGHT_COLOR */
550
551#if OPT_INPUT_METHOD
552    Bres(XtNopenIm, XtCOpenIm, misc.open_im, True),
553    Sres(XtNinputMethod, XtCInputMethod, misc.input_method, NULL),
554    Sres(XtNpreeditType, XtCPreeditType, misc.preedit_type,
555	 "OverTheSpot,Root"),
556#endif
557
558#if OPT_ISO_COLORS
559    Bres(XtNboldColors, XtCColorMode, screen.boldColors, True),
560    Ires(XtNveryBoldColors, XtCVeryBoldColors, screen.veryBoldColors, 0),
561    Bres(XtNcolorMode, XtCColorMode, screen.colorMode, DFT_COLORMODE),
562
563    Bres(XtNcolorAttrMode, XtCColorAttrMode, screen.colorAttrMode, False),
564    Bres(XtNcolorBDMode, XtCColorAttrMode, screen.colorBDMode, False),
565    Bres(XtNcolorBLMode, XtCColorAttrMode, screen.colorBLMode, False),
566    Bres(XtNcolorRVMode, XtCColorAttrMode, screen.colorRVMode, False),
567    Bres(XtNcolorULMode, XtCColorAttrMode, screen.colorULMode, False),
568    Bres(XtNitalicULMode, XtCColorAttrMode, screen.italicULMode, False),
569
570    COLOR_RES("0", screen.Acolors[COLOR_0], DFT_COLOR("black")),
571    COLOR_RES("1", screen.Acolors[COLOR_1], DFT_COLOR("red3")),
572    COLOR_RES("2", screen.Acolors[COLOR_2], DFT_COLOR("green3")),
573    COLOR_RES("3", screen.Acolors[COLOR_3], DFT_COLOR("yellow3")),
574    COLOR_RES("4", screen.Acolors[COLOR_4], DFT_COLOR(DEF_COLOR4)),
575    COLOR_RES("5", screen.Acolors[COLOR_5], DFT_COLOR("magenta3")),
576    COLOR_RES("6", screen.Acolors[COLOR_6], DFT_COLOR("cyan3")),
577    COLOR_RES("7", screen.Acolors[COLOR_7], DFT_COLOR("gray90")),
578    COLOR_RES("8", screen.Acolors[COLOR_8], DFT_COLOR("gray50")),
579    COLOR_RES("9", screen.Acolors[COLOR_9], DFT_COLOR("red")),
580    COLOR_RES("10", screen.Acolors[COLOR_10], DFT_COLOR("green")),
581    COLOR_RES("11", screen.Acolors[COLOR_11], DFT_COLOR("yellow")),
582    COLOR_RES("12", screen.Acolors[COLOR_12], DFT_COLOR(DEF_COLOR12)),
583    COLOR_RES("13", screen.Acolors[COLOR_13], DFT_COLOR("magenta")),
584    COLOR_RES("14", screen.Acolors[COLOR_14], DFT_COLOR("cyan")),
585    COLOR_RES("15", screen.Acolors[COLOR_15], DFT_COLOR("white")),
586    COLOR_RES("BD", screen.Acolors[COLOR_BD], DFT_COLOR(XtDefaultForeground)),
587    COLOR_RES("BL", screen.Acolors[COLOR_BL], DFT_COLOR(XtDefaultForeground)),
588    COLOR_RES("UL", screen.Acolors[COLOR_UL], DFT_COLOR(XtDefaultForeground)),
589    COLOR_RES("RV", screen.Acolors[COLOR_RV], DFT_COLOR(XtDefaultForeground)),
590
591    CLICK_RES("2", screen.onClick[1], "word"),
592    CLICK_RES("3", screen.onClick[2], "line"),
593    CLICK_RES("4", screen.onClick[3], 0),
594    CLICK_RES("5", screen.onClick[4], 0),
595
596#if !OPT_COLOR_RES2
597#if OPT_256_COLORS
598# include <256colres.h>
599#elif OPT_88_COLORS
600# include <88colres.h>
601#endif
602#endif				/* !OPT_COLOR_RES2 */
603
604#endif				/* OPT_ISO_COLORS */
605
606#if OPT_MOD_FKEYS
607    Ires(XtNmodifyCursorKeys, XtCModifyCursorKeys,
608	 keyboard.modify_1st.cursor_keys, 2),
609    Ires(XtNmodifyFunctionKeys, XtCModifyFunctionKeys,
610	 keyboard.modify_1st.function_keys, 2),
611    Ires(XtNmodifyKeypadKeys, XtCModifyKeypadKeys,
612	 keyboard.modify_1st.keypad_keys, 0),
613    Ires(XtNmodifyOtherKeys, XtCModifyOtherKeys,
614	 keyboard.modify_1st.other_keys, 0),
615    Ires(XtNmodifyStringKeys, XtCModifyStringKeys,
616	 keyboard.modify_1st.string_keys, 0),
617    Ires(XtNformatOtherKeys, XtCFormatOtherKeys,
618	 keyboard.format_keys, 0),
619#endif
620
621#if OPT_NUM_LOCK
622    Bres(XtNalwaysUseMods, XtCAlwaysUseMods, misc.alwaysUseMods, False),
623    Bres(XtNnumLock, XtCNumLock, misc.real_NumLock, True),
624#endif
625
626#if OPT_PRINT_COLORS
627    Ires(XtNprintAttributes, XtCPrintAttributes, screen.print_attributes, 1),
628#endif
629
630#if OPT_SHIFT_FONTS
631    Bres(XtNshiftFonts, XtCShiftFonts, misc.shift_fonts, True),
632#endif
633
634#if OPT_SUNPC_KBD
635    Ires(XtNctrlFKeys, XtCCtrlFKeys, misc.ctrl_fkeys, 10),
636#endif
637
638#if OPT_TEK4014
639    Bres(XtNtekInhibit, XtCTekInhibit, misc.tekInhibit, False),
640    Bres(XtNtekSmall, XtCTekSmall, misc.tekSmall, False),
641    Bres(XtNtekStartup, XtCTekStartup, misc.TekEmu, False),
642#endif
643
644#if OPT_TOOLBAR
645    Wres(XtNmenuBar, XtCMenuBar, VT100_TB_INFO(menu_bar), 0),
646    Ires(XtNmenuHeight, XtCMenuHeight, VT100_TB_INFO(menu_height), 25),
647#endif
648
649#if OPT_WIDE_CHARS
650    Bres(XtNcjkWidth, XtCCjkWidth, misc.cjk_width, False),
651    Bres(XtNmkWidth, XtCMkWidth, misc.mk_width, False),
652    Bres(XtNutf8Latin1, XtCUtf8Latin1, screen.utf8_latin1, False),
653    Bres(XtNutf8Title, XtCUtf8Title, screen.utf8_title, False),
654    Bres(XtNvt100Graphics, XtCVT100Graphics, screen.vt100_graphics, True),
655    Bres(XtNwideChars, XtCWideChars, screen.wide_chars, False),
656    Ires(XtNcombiningChars, XtCCombiningChars, screen.max_combining, 2),
657    Ires(XtNmkSamplePass, XtCMkSamplePass, misc.mk_samplepass, 256),
658    Ires(XtNmkSampleSize, XtCMkSampleSize, misc.mk_samplesize, 1024),
659    Ires(XtNutf8, XtCUtf8, screen.utf8_mode, uDefault),
660    Sres(XtNwideBoldFont, XtCWideBoldFont, misc.default_font.f_wb, DEFWIDEBOLDFONT),
661    Sres(XtNwideFont, XtCWideFont, misc.default_font.f_w, DEFWIDEFONT),
662#endif
663
664#if OPT_LUIT_PROG
665    Sres(XtNlocale, XtCLocale, misc.locale_str, "medium"),
666    Sres(XtNlocaleFilter, XtCLocaleFilter, misc.localefilter, DEFLOCALEFILTER),
667#endif
668
669#if OPT_INPUT_METHOD
670    Sres(XtNximFont, XtCXimFont, misc.f_x, DEFXIMFONT),
671#endif
672
673#if OPT_XMC_GLITCH
674    Bres(XtNxmcInline, XtCXmcInline, screen.xmc_inline, False),
675    Bres(XtNxmcMoveSGR, XtCXmcMoveSGR, screen.move_sgr_ok, True),
676    Ires(XtNxmcAttributes, XtCXmcAttributes, screen.xmc_attributes, 1),
677    Ires(XtNxmcGlitch, XtCXmcGlitch, screen.xmc_glitch, 0),
678#endif
679
680#ifdef SCROLLBAR_RIGHT
681    Bres(XtNrightScrollBar, XtCRightScrollBar, misc.useRight, False),
682#endif
683
684#if OPT_RENDERFONT
685#define RES_FACESIZE(n) Dres(XtNfaceSize #n, XtCFaceSize #n, misc.face_size[n], "0.0")
686    RES_FACESIZE(1),
687    RES_FACESIZE(2),
688    RES_FACESIZE(3),
689    RES_FACESIZE(4),
690    RES_FACESIZE(5),
691    RES_FACESIZE(6),
692    Dres(XtNfaceSize, XtCFaceSize, misc.face_size[0], DEFFACESIZE),
693    Sres(XtNfaceName, XtCFaceName, misc.face_name, DEFFACENAME),
694    Sres(XtNfaceNameDoublesize, XtCFaceNameDoublesize, misc.face_wide_name, DEFFACENAME),
695    Bres(XtNrenderFont, XtCRenderFont, misc.render_font, True),
696#endif
697};
698
699static Boolean VTSetValues(Widget cur, Widget request, Widget new_arg,
700			   ArgList args, Cardinal *num_args);
701static void VTClassInit(void);
702static void VTDestroy(Widget w);
703static void VTExpose(Widget w, XEvent * event, Region region);
704static void VTInitialize(Widget wrequest, Widget new_arg, ArgList args,
705			 Cardinal *num_args);
706static void VTRealize(Widget w, XtValueMask * valuemask,
707		      XSetWindowAttributes * values);
708static void VTResize(Widget w);
709
710#if OPT_I18N_SUPPORT && OPT_INPUT_METHOD
711static void VTInitI18N(void);
712#endif
713
714#ifdef VMS
715globaldef {
716    "xtermclassrec"
717} noshare
718
719#else
720static
721#endif				/* VMS */
722WidgetClassRec xtermClassRec =
723{
724    {
725/* core_class fields */
726	(WidgetClass) & widgetClassRec,		/* superclass     */
727	"VT100",		/* class_name                   */
728	sizeof(XtermWidgetRec),	/* widget_size                  */
729	VTClassInit,		/* class_initialize             */
730	NULL,			/* class_part_initialize        */
731	False,			/* class_inited                 */
732	VTInitialize,		/* initialize                   */
733	NULL,			/* initialize_hook              */
734	VTRealize,		/* realize                      */
735	actionsList,		/* actions                      */
736	XtNumber(actionsList),	/* num_actions                  */
737	resources,		/* resources                    */
738	XtNumber(resources),	/* num_resources                */
739	NULLQUARK,		/* xrm_class                    */
740	True,			/* compress_motion              */
741	False,			/* compress_exposure            */
742	True,			/* compress_enterleave          */
743	False,			/* visible_interest             */
744	VTDestroy,		/* destroy                      */
745	VTResize,		/* resize                       */
746	VTExpose,		/* expose                       */
747	VTSetValues,		/* set_values                   */
748	NULL,			/* set_values_hook              */
749	XtInheritSetValuesAlmost,	/* set_values_almost    */
750	NULL,			/* get_values_hook              */
751	NULL,			/* accept_focus                 */
752	XtVersion,		/* version                      */
753	NULL,			/* callback_offsets             */
754	defaultTranslations,	/* tm_table                     */
755	XtInheritQueryGeometry,	/* query_geometry               */
756	XtInheritDisplayAccelerator,	/* display_accelerator  */
757	NULL			/* extension                    */
758    }
759};
760
761#ifdef VMS
762globaldef {
763    "xtermwidgetclass"
764}
765noshare
766#endif /* VMS */
767WidgetClass xtermWidgetClass = (WidgetClass) & xtermClassRec;
768
769/*
770 * Add input-actions for widgets that are overlooked (scrollbar and toolbar):
771 *
772 *	a) Sometimes the scrollbar passes through translations, sometimes it
773 *	   doesn't.  We add the KeyPress translations here, just to be sure.
774 *	b) In the normal (non-toolbar) configuration, the xterm widget covers
775 *	   almost all of the window.  With a toolbar, there's a relatively
776 *	   large area that the user would expect to enter keystrokes since the
777 *	   program can get the focus.
778 */
779void
780xtermAddInput(Widget w)
781{
782#if OPT_TOOLBAR
783    /* *INDENT-OFF* */
784    XtActionsRec input_actions[] = {
785	{ "insert",		    HandleKeyPressed }, /* alias */
786	{ "insert-eight-bit",	    HandleEightBitKeyPressed },
787	{ "insert-seven-bit",	    HandleKeyPressed },
788	{ "secure",		    HandleSecure },
789	{ "string",		    HandleStringEvent },
790	{ "scroll-back",	    HandleScrollBack },
791	{ "scroll-forw",	    HandleScrollForward },
792	{ "select-cursor-end",	    HandleKeyboardSelectEnd },
793	{ "select-cursor-extend",   HandleKeyboardSelectExtend },
794	{ "select-cursor-start",    HandleKeyboardSelectStart },
795	{ "insert-selection",	    HandleInsertSelection },
796	{ "select-start",	    HandleSelectStart },
797	{ "select-extend",	    HandleSelectExtend },
798	{ "start-extend",	    HandleStartExtend },
799	{ "select-end",		    HandleSelectEnd },
800	{ "clear-saved-lines",	    HandleClearSavedLines },
801	{ "popup-menu",		    HandlePopupMenu },
802	{ "bell",		    HandleBell },
803	{ "ignore",		    HandleIgnore },
804#if OPT_DABBREV
805	{ "dabbrev-expand",	    HandleDabbrevExpand },
806#endif
807#if OPT_SHIFT_FONTS
808	{ "larger-vt-font",	    HandleLargerFont },
809	{ "smaller-vt-font",	    HandleSmallerFont },
810#endif
811    };
812    /* *INDENT-ON* */
813
814    XtAppAddActions(app_con, input_actions, XtNumber(input_actions));
815#endif
816    XtAugmentTranslations(w, XtParseTranslationTable(defaultTranslations));
817
818#if OPT_EXTRA_PASTE
819    if (term && term->keyboard.extra_translations)
820	XtOverrideTranslations((Widget) term, XtParseTranslationTable(term->keyboard.extra_translations));
821#endif
822}
823
824#if OPT_ISO_COLORS
825/*
826 * The terminal's foreground and background colors are set via two mechanisms:
827 *	text (cur_foreground, cur_background values that are passed down to
828 *		XDrawImageString and XDrawString)
829 *	area (X11 graphics context used in XClearArea and XFillRectangle)
830 */
831void
832SGR_Foreground(XtermWidget xw, int color)
833{
834    TScreen *screen = &xw->screen;
835    Pixel fg;
836
837    if (color >= 0) {
838	xw->flags |= FG_COLOR;
839    } else {
840	xw->flags &= ~FG_COLOR;
841    }
842    fg = getXtermForeground(xw, xw->flags, color);
843    xw->cur_foreground = color;
844
845    setCgsFore(xw, WhichVWin(screen), gcNorm, fg);
846    setCgsBack(xw, WhichVWin(screen), gcNormReverse, fg);
847
848    setCgsFore(xw, WhichVWin(screen), gcBold, fg);
849    setCgsBack(xw, WhichVWin(screen), gcBoldReverse, fg);
850}
851
852void
853SGR_Background(XtermWidget xw, int color)
854{
855    TScreen *screen = &xw->screen;
856    Pixel bg;
857
858    /*
859     * An indexing operation may have set screen->scroll_amt, which would
860     * normally result in calling FlushScroll() in WriteText().  However,
861     * if we're changing the background color now, then the new value
862     * should not apply to the pending blank lines.
863     */
864    if (screen->scroll_amt && (color != xw->cur_background))
865	FlushScroll(xw);
866
867    if (color >= 0) {
868	xw->flags |= BG_COLOR;
869    } else {
870	xw->flags &= ~BG_COLOR;
871    }
872    bg = getXtermBackground(xw, xw->flags, color);
873    xw->cur_background = color;
874
875    setCgsBack(xw, WhichVWin(screen), gcNorm, bg);
876    setCgsFore(xw, WhichVWin(screen), gcNormReverse, bg);
877
878    setCgsBack(xw, WhichVWin(screen), gcBold, bg);
879    setCgsFore(xw, WhichVWin(screen), gcBoldReverse, bg);
880}
881
882/* Invoked after updating bold/underline flags, computes the extended color
883 * index to use for foreground.  (See also 'extract_fg()').
884 */
885static void
886setExtendedFG(XtermWidget xw)
887{
888    int fg = xw->sgr_foreground;
889
890    if (xw->screen.colorAttrMode
891	|| (fg < 0)) {
892	if (xw->screen.colorULMode && (xw->flags & UNDERLINE))
893	    fg = COLOR_UL;
894	if (xw->screen.colorBDMode && (xw->flags & BOLD))
895	    fg = COLOR_BD;
896	if (xw->screen.colorBLMode && (xw->flags & BLINK))
897	    fg = COLOR_BL;
898    }
899
900    /* This implements the IBM PC-style convention of 8-colors, with one
901     * bit for bold, thus mapping the 0-7 codes to 8-15.  It won't make
902     * much sense for 16-color applications, but we keep it to retain
903     * compatiblity with ANSI-color applications.
904     */
905#if OPT_PC_COLORS		/* XXXJTL should be settable at runtime (resource or OSC?) */
906    if (xw->screen.boldColors
907	&& (!xw->sgr_extended)
908	&& (fg >= 0)
909	&& (fg < 8)
910	&& (xw->flags & BOLD))
911	fg |= 8;
912#endif
913
914    SGR_Foreground(xw, fg);
915}
916
917/* Invoked after updating inverse flag, computes the extended color
918 * index to use for background.  (See also 'extract_bg()').
919 */
920static void
921setExtendedBG(XtermWidget xw)
922{
923    int bg = xw->sgr_background;
924
925    if (xw->screen.colorAttrMode
926	|| (bg < 0)) {
927	if (xw->screen.colorRVMode && (xw->flags & INVERSE))
928	    bg = COLOR_RV;
929    }
930
931    SGR_Background(xw, bg);
932}
933
934static void
935reset_SGR_Foreground(XtermWidget xw)
936{
937    xw->sgr_foreground = -1;
938    xw->sgr_extended = False;
939    setExtendedFG(xw);
940}
941
942static void
943reset_SGR_Background(XtermWidget xw)
944{
945    xw->sgr_background = -1;
946    setExtendedBG(xw);
947}
948
949static void
950reset_SGR_Colors(XtermWidget xw)
951{
952    reset_SGR_Foreground(xw);
953    reset_SGR_Background(xw);
954}
955#endif /* OPT_ISO_COLORS */
956
957void
958resetCharsets(TScreen * screen)
959{
960    TRACE(("resetCharsets\n"));
961
962    screen->gsets[0] = 'B';	/* ASCII_G              */
963    screen->gsets[1] = 'B';	/* ASCII_G              */
964    screen->gsets[2] = 'B';	/* ASCII_G              */
965    screen->gsets[3] = 'B';	/* ASCII_G              */
966
967    screen->curgl = 0;		/* G0 => GL.            */
968    screen->curgr = 2;		/* G2 => GR.            */
969    screen->curss = 0;		/* No single shift.     */
970
971#if OPT_VT52_MODE
972    if (screen->vtXX_level == 0)
973	screen->gsets[1] = '0';	/* Graphics             */
974#endif
975}
976
977/*
978 * VT300 and up support three ANSI conformance levels, defined according to
979 * the dpANSI X3.134.1 standard.  DEC's manuals equate levels 1 and 2, and
980 * are unclear.  This code is written based on the manuals.
981 */
982static void
983set_ansi_conformance(TScreen * screen, int level)
984{
985    TRACE(("set_ansi_conformance(%d) terminal_id %d, ansi_level %d\n",
986	   level,
987	   screen->terminal_id,
988	   screen->ansi_level));
989    if (screen->vtXX_level >= 3) {
990	switch (screen->ansi_level = level) {
991	case 1:
992	    /* FALLTHRU */
993	case 2:
994	    screen->gsets[0] = 'B';	/* G0 is ASCII */
995	    screen->gsets[1] = 'B';	/* G1 is ISO Latin-1 (FIXME) */
996	    screen->curgl = 0;
997	    screen->curgr = 1;
998	    break;
999	case 3:
1000	    screen->gsets[0] = 'B';	/* G0 is ASCII */
1001	    screen->curgl = 0;
1002	    break;
1003	}
1004    }
1005}
1006
1007/*
1008 * Set scrolling margins.  VTxxx terminals require that the top/bottom are
1009 * different, so we have at least two lines in the scrolling region.
1010 */
1011void
1012set_tb_margins(TScreen * screen, int top, int bottom)
1013{
1014    TRACE(("set_tb_margins %d..%d, prior %d..%d\n",
1015	   top, bottom,
1016	   screen->top_marg,
1017	   screen->bot_marg));
1018    if (bottom > top) {
1019	screen->top_marg = top;
1020	screen->bot_marg = bottom;
1021    }
1022    if (screen->top_marg > screen->max_row)
1023	screen->top_marg = screen->max_row;
1024    if (screen->bot_marg > screen->max_row)
1025	screen->bot_marg = screen->max_row;
1026}
1027
1028void
1029set_max_col(TScreen * screen, int cols)
1030{
1031    TRACE(("set_max_col %d, prior %d\n", cols, screen->max_col));
1032    if (cols < 0)
1033	cols = 0;
1034    screen->max_col = cols;
1035}
1036
1037void
1038set_max_row(TScreen * screen, int rows)
1039{
1040    TRACE(("set_max_row %d, prior %d\n", rows, screen->max_row));
1041    if (rows < 0)
1042	rows = 0;
1043    screen->max_row = rows;
1044}
1045
1046#if OPT_MOD_FKEYS
1047static void
1048set_mod_fkeys(XtermWidget xw, int which, int what, Bool enabled)
1049{
1050#define SET_MOD_FKEYS(field) \
1051    xw->keyboard.modify_now.field = ((what == DEFAULT) && enabled) \
1052				     ? xw->keyboard.modify_1st.field \
1053				     : what; \
1054    TRACE(("set modify_now.%s to %d\n", #field, \
1055	   xw->keyboard.modify_now.field));
1056
1057    switch (which) {
1058    case 1:
1059	SET_MOD_FKEYS(cursor_keys);
1060	break;
1061    case 2:
1062	SET_MOD_FKEYS(function_keys);
1063	break;
1064    case 3:
1065	SET_MOD_FKEYS(keypad_keys);
1066	break;
1067    case 4:
1068	SET_MOD_FKEYS(other_keys);
1069	break;
1070    case 5:
1071	SET_MOD_FKEYS(string_keys);
1072	break;
1073    }
1074}
1075#endif /* OPT_MOD_FKEYS */
1076
1077#if OPT_TRACE
1078#define WHICH_TABLE(name) if (table == name) result = #name
1079static char *
1080which_table(Const PARSE_T * table)
1081{
1082    char *result = "?";
1083    /* *INDENT-OFF* */
1084    WHICH_TABLE (ansi_table);
1085    else WHICH_TABLE (csi_table);
1086    else WHICH_TABLE (csi2_table);
1087    else WHICH_TABLE (csi_ex_table);
1088    else WHICH_TABLE (csi_quo_table);
1089#if OPT_DEC_LOCATOR
1090    else WHICH_TABLE (csi_tick_table);
1091#endif
1092#if OPT_DEC_RECTOPS
1093    else WHICH_TABLE (csi_dollar_table);
1094    else WHICH_TABLE (csi_star_table);
1095#endif
1096    else WHICH_TABLE (dec_table);
1097    else WHICH_TABLE (dec2_table);
1098    else WHICH_TABLE (dec3_table);
1099    else WHICH_TABLE (cigtable);
1100    else WHICH_TABLE (eigtable);
1101    else WHICH_TABLE (esc_table);
1102    else WHICH_TABLE (esc_sp_table);
1103    else WHICH_TABLE (scrtable);
1104    else WHICH_TABLE (scstable);
1105    else WHICH_TABLE (sos_table);
1106#if OPT_WIDE_CHARS
1107    else WHICH_TABLE (esc_pct_table);
1108#endif
1109#if OPT_VT52_MODE
1110    else WHICH_TABLE (vt52_table);
1111    else WHICH_TABLE (vt52_esc_table);
1112    else WHICH_TABLE (vt52_ignore_table);
1113#endif
1114    /* *INDENT-ON* */
1115
1116    return result;
1117}
1118#endif
1119
1120	/* allocate larger buffer if needed/possible */
1121#define SafeAlloc(type, area, used, size) \
1122		type *new_string = area; \
1123		unsigned new_length = size; \
1124		if (new_length == 0) { \
1125		    new_length = 256; \
1126		    new_string = TypeMallocN(type, new_length); \
1127		} else if (used+1 >= new_length) { \
1128		    new_length = size * 2; \
1129		    new_string = TypeMallocN(type, new_length); \
1130		    if (new_string != 0 \
1131		     && area != 0 \
1132		     && used != 0) \
1133			memcpy(new_string, area, used * sizeof(type)); \
1134		}
1135
1136#define WriteNow() {						\
1137	    unsigned single = 0;				\
1138								\
1139	    if (screen->curss) {				\
1140		dotext(xw,					\
1141		       screen->gsets[(int) (screen->curss)],	\
1142		       print_area, 1);				\
1143		screen->curss = 0;				\
1144		single++;					\
1145	    }							\
1146	    if (print_used > single) {				\
1147		dotext(xw,					\
1148		       screen->gsets[(int) (screen->curgl)],	\
1149		       print_area + single,			\
1150		       print_used - single);			\
1151	    }							\
1152	    print_used = 0;					\
1153	}							\
1154
1155struct ParseState {
1156#if OPT_VT52_MODE
1157    Bool vt52_cup;
1158#endif
1159    Const PARSE_T *groundtable;
1160    Const PARSE_T *parsestate;
1161    int scstype;
1162    Bool private_function;	/* distinguish private-mode from standard */
1163    int string_mode;		/* nonzero iff we're processing a string */
1164    int lastchar;		/* positive iff we had a graphic character */
1165    int nextstate;
1166#if OPT_WIDE_CHARS
1167    int last_was_wide;
1168#endif
1169};
1170
1171static struct ParseState myState;
1172
1173static Boolean
1174doparsing(XtermWidget xw, unsigned c, struct ParseState *sp)
1175{
1176    /* Buffer for processing printable text */
1177    static IChar *print_area;
1178    static size_t print_size, print_used;
1179
1180    /* Buffer for processing strings (e.g., OSC ... ST) */
1181    static Char *string_area;
1182    static size_t string_size, string_used;
1183
1184    TScreen *screen = &xw->screen;
1185    int row;
1186    int col;
1187    int top;
1188    int bot;
1189    int count;
1190    int laststate;
1191    int thischar = -1;
1192    XTermRect myRect;
1193
1194    do {
1195#if OPT_WIDE_CHARS
1196
1197	/*
1198	 * Handle zero-width combining characters.  Make it faster by noting
1199	 * that according to the Unicode charts, the majority of Western
1200	 * character sets do not use this feature.  There are some unassigned
1201	 * codes at 0x242, but no zero-width characters until past 0x300.
1202	 */
1203	if (c >= 0x300 && screen->wide_chars
1204	    && my_wcwidth((int) c) == 0
1205	    && !isWideControl(c)) {
1206	    int prev, precomposed;
1207
1208	    WriteNow();
1209
1210	    prev = XTERM_CELL(screen->last_written_row,
1211			      screen->last_written_col);
1212	    precomposed = do_precomposition(prev, (int) c);
1213	    TRACE(("do_precomposition (U+%04X [%d], U+%04X [%d]) -> U+%04X [%d]\n",
1214		   prev, my_wcwidth(prev),
1215		   (int) c, my_wcwidth((int) c),
1216		   precomposed, my_wcwidth(precomposed)));
1217
1218	    /* substitute combined character with precomposed character
1219	     * only if it does not change the width of the base character
1220	     */
1221	    if (precomposed != -1 && my_wcwidth(precomposed) == my_wcwidth(prev)) {
1222		putXtermCell(screen,
1223			     screen->last_written_row,
1224			     screen->last_written_col, precomposed);
1225	    } else {
1226		addXtermCombining(screen,
1227				  screen->last_written_row,
1228				  screen->last_written_col, c);
1229	    }
1230
1231	    if (!screen->scroll_amt)
1232		ScrnUpdate(xw,
1233			   screen->last_written_row,
1234			   screen->last_written_col, 1, 1, 1);
1235	    continue;
1236	}
1237#endif
1238
1239	/* Intercept characters for printer controller mode */
1240	if (screen->printer_controlmode == 2) {
1241	    if ((c = xtermPrinterControl((int) c)) == 0)
1242		continue;
1243	}
1244
1245	/*
1246	 * VT52 is a little ugly in the one place it has a parameterized
1247	 * control sequence, since the parameter falls after the character
1248	 * that denotes the type of sequence.
1249	 */
1250#if OPT_VT52_MODE
1251	if (sp->vt52_cup) {
1252	    if (nparam < NPARAM)
1253		param[nparam++] = (c & 0x7f) - 32;
1254	    if (nparam < 2)
1255		continue;
1256	    sp->vt52_cup = False;
1257	    if ((row = param[0]) < 0)
1258		row = 0;
1259	    if ((col = param[1]) < 0)
1260		col = 0;
1261	    CursorSet(screen, row, col, xw->flags);
1262	    sp->parsestate = vt52_table;
1263	    param[0] = 0;
1264	    param[1] = 0;
1265	    continue;
1266	}
1267#endif
1268
1269	/*
1270	 * The parsing tables all have 256 entries.  If we're supporting
1271	 * wide characters, we handle them by treating them the same as
1272	 * printing characters.
1273	 */
1274	laststate = sp->nextstate;
1275#if OPT_WIDE_CHARS
1276	if (c > 255) {
1277	    if (sp->parsestate == sp->groundtable) {
1278		sp->nextstate = CASE_PRINT;
1279	    } else if (sp->parsestate == sos_table) {
1280		c &= 0xffff;
1281		if (c > 255) {
1282		    TRACE(("Found code > 255 while in SOS state: %04X\n", c));
1283		    c = '?';
1284		}
1285	    } else {
1286		sp->nextstate = CASE_GROUND_STATE;
1287	    }
1288	} else
1289#endif
1290	    sp->nextstate = sp->parsestate[E2A(c)];
1291
1292#if OPT_BROKEN_OSC
1293	/*
1294	 * Linux console palette escape sequences start with an OSC, but do
1295	 * not terminate correctly.  Some scripts do not check before writing
1296	 * them, making xterm appear to hang (it's awaiting a valid string
1297	 * terminator).  Just ignore these if we see them - there's no point
1298	 * in emulating bad code.
1299	 */
1300	if (screen->brokenLinuxOSC
1301	    && sp->parsestate == sos_table) {
1302	    if (string_used) {
1303		switch (string_area[0]) {
1304		case 'P':
1305		    if (string_used <= 7)
1306			break;
1307		    /* FALLTHRU */
1308		case 'R':
1309		    sp->parsestate = sp->groundtable;
1310		    sp->nextstate = sp->parsestate[E2A(c)];
1311		    TRACE(("Reset to ground state (brokenLinuxOSC)\n"));
1312		    break;
1313		}
1314	    }
1315	}
1316#endif
1317
1318#if OPT_BROKEN_ST
1319	/*
1320	 * Before patch #171, carriage control embedded within an OSC string
1321	 * would terminate it.  Some (buggy, of course) applications rely on
1322	 * this behavior.  Accommodate them by allowing one to compile xterm
1323	 * and emulate the old behavior.
1324	 */
1325	if (screen->brokenStringTerm
1326	    && sp->parsestate == sos_table
1327	    && c < 32) {
1328	    switch (c) {
1329	    case 5:		/* FALLTHRU */
1330	    case 8:		/* FALLTHRU */
1331	    case 9:		/* FALLTHRU */
1332	    case 10:		/* FALLTHRU */
1333	    case 11:		/* FALLTHRU */
1334	    case 12:		/* FALLTHRU */
1335	    case 13:		/* FALLTHRU */
1336	    case 14:		/* FALLTHRU */
1337	    case 15:		/* FALLTHRU */
1338	    case 24:
1339		sp->parsestate = sp->groundtable;
1340		sp->nextstate = sp->parsestate[E2A(c)];
1341		TRACE(("Reset to ground state (brokenStringTerm)\n"));
1342		break;
1343	    }
1344	}
1345#endif
1346
1347#if OPT_C1_PRINT
1348	/*
1349	 * This is not completely foolproof, but will allow an application
1350	 * with values in the C1 range to use them as printable characters,
1351	 * provided that they are not intermixed with an escape sequence.
1352	 */
1353	if (screen->c1_printable
1354	    && (c >= 128 && c < 160)) {
1355	    sp->nextstate = (sp->parsestate == esc_table
1356			     ? CASE_ESC_IGNORE
1357			     : sp->parsestate[E2A(160)]);
1358	}
1359#endif
1360
1361#if OPT_WIDE_CHARS
1362	/*
1363	 * If we have a C1 code and the c1_printable flag is not set, simply
1364	 * ignore it when it was translated from UTF-8.  That is because the
1365	 * value could not have been present as-is in the UTF-8.
1366	 *
1367	 * To see that CASE_IGNORE is a consistent value, note that it is
1368	 * always used for NUL and other uninteresting C0 controls.
1369	 */
1370#if OPT_C1_PRINT
1371	if (!screen->c1_printable)
1372#endif
1373	    if (screen->wide_chars
1374		&& (c >= 128 && c < 160)) {
1375		sp->nextstate = CASE_IGNORE;
1376	    }
1377
1378	/*
1379	 * If this character is a different width than the last one, put the
1380	 * previous text into the buffer and draw it now.
1381	 */
1382	if (iswide((int) c) != sp->last_was_wide) {
1383	    WriteNow();
1384	}
1385#endif
1386
1387	/*
1388	 * Accumulate string for printable text.  This may be 8/16-bit
1389	 * characters.
1390	 */
1391	if (sp->nextstate == CASE_PRINT) {
1392	    SafeAlloc(IChar, print_area, print_used, print_size);
1393	    if (new_string == 0) {
1394		fprintf(stderr,
1395			"Cannot allocate %u bytes for printable text\n",
1396			new_length);
1397		continue;
1398	    }
1399#if OPT_VT52_MODE
1400	    /*
1401	     * Strip output text to 7-bits for VT52.  We should do this for
1402	     * VT100 also (which is a 7-bit device), but xterm has been
1403	     * doing this for so long we shouldn't change this behavior.
1404	     */
1405	    if (screen->vtXX_level < 1)
1406		c &= 0x7f;
1407#endif
1408	    print_area = new_string;
1409	    print_size = new_length;
1410	    print_area[print_used++] = sp->lastchar = thischar = c;
1411#if OPT_WIDE_CHARS
1412	    sp->last_was_wide = iswide((int) c);
1413#endif
1414	    if (morePtyData(screen, VTbuffer)) {
1415		continue;
1416	    }
1417	}
1418
1419	if (sp->nextstate == CASE_PRINT
1420	    || (laststate == CASE_PRINT && print_used)) {
1421	    WriteNow();
1422	}
1423
1424	/*
1425	 * Accumulate string for APC, DCS, PM, OSC, SOS controls
1426	 * This should always be 8-bit characters.
1427	 */
1428	if (sp->parsestate == sos_table) {
1429	    SafeAlloc(Char, string_area, string_used, string_size);
1430	    if (new_string == 0) {
1431		fprintf(stderr,
1432			"Cannot allocate %u bytes for string mode %d\n",
1433			new_length, sp->string_mode);
1434		continue;
1435	    }
1436#if OPT_WIDE_CHARS
1437	    /*
1438	     * We cannot display codes above 255, but let's try to
1439	     * accommodate the application a little by not aborting the
1440	     * string.
1441	     */
1442	    if ((c & 0xffff) > 255) {
1443		sp->nextstate = CASE_PRINT;
1444		c = '?';
1445	    }
1446#endif
1447	    string_area = new_string;
1448	    string_size = new_length;
1449	    string_area[string_used++] = c;
1450	} else if (sp->parsestate != esc_table) {
1451	    /* if we were accumulating, we're not any more */
1452	    sp->string_mode = 0;
1453	    string_used = 0;
1454	}
1455
1456	TRACE(("parse %04X -> %d %s\n", c, sp->nextstate, which_table(sp->parsestate)));
1457
1458	switch (sp->nextstate) {
1459	case CASE_PRINT:
1460	    TRACE(("CASE_PRINT - printable characters\n"));
1461	    break;
1462
1463	case CASE_GROUND_STATE:
1464	    TRACE(("CASE_GROUND_STATE - exit ignore mode\n"));
1465	    sp->parsestate = sp->groundtable;
1466	    break;
1467
1468	case CASE_IGNORE:
1469	    TRACE(("CASE_IGNORE - Ignore character %02X\n", c));
1470	    break;
1471
1472	case CASE_ENQ:
1473	    TRACE(("CASE_ENQ - answerback\n"));
1474	    for (count = 0; screen->answer_back[count] != 0; count++)
1475		unparseputc(xw, screen->answer_back[count]);
1476	    unparse_end(xw);
1477	    break;
1478
1479	case CASE_BELL:
1480	    TRACE(("CASE_BELL - bell\n"));
1481	    if (sp->string_mode == ANSI_OSC) {
1482		if (string_used)
1483		    string_area[--string_used] = '\0';
1484		do_osc(xw, string_area, string_used, (int) c);
1485		sp->parsestate = sp->groundtable;
1486	    } else {
1487		/* bell */
1488		Bell(XkbBI_TerminalBell, 0);
1489	    }
1490	    break;
1491
1492	case CASE_BS:
1493	    TRACE(("CASE_BS - backspace\n"));
1494	    CursorBack(xw, 1);
1495	    break;
1496
1497	case CASE_CR:
1498	    /* CR */
1499	    CarriageReturn(screen);
1500	    break;
1501
1502	case CASE_ESC:
1503	    if_OPT_VT52_MODE(screen, {
1504		sp->parsestate = vt52_esc_table;
1505		break;
1506	    });
1507	    sp->parsestate = esc_table;
1508	    break;
1509
1510#if OPT_VT52_MODE
1511	case CASE_VT52_CUP:
1512	    TRACE(("CASE_VT52_CUP - VT52 cursor addressing\n"));
1513	    sp->vt52_cup = True;
1514	    nparam = 0;
1515	    break;
1516
1517	case CASE_VT52_IGNORE:
1518	    TRACE(("CASE_VT52_IGNORE - VT52 ignore-character\n"));
1519	    sp->parsestate = vt52_ignore_table;
1520	    break;
1521#endif
1522
1523	case CASE_VMOT:
1524	    /*
1525	     * form feed, line feed, vertical tab
1526	     */
1527	    xtermAutoPrint(c);
1528	    xtermIndex(xw, 1);
1529	    if (xw->flags & LINEFEED)
1530		CarriageReturn(screen);
1531	    else
1532		do_xevents();
1533	    break;
1534
1535	case CASE_CBT:
1536	    /* cursor backward tabulation */
1537	    if ((count = param[0]) == DEFAULT)
1538		count = 1;
1539	    while ((count-- > 0)
1540		   && (TabToPrevStop(xw))) ;
1541	    sp->parsestate = sp->groundtable;
1542	    break;
1543
1544	case CASE_CHT:
1545	    /* cursor forward tabulation */
1546	    if ((count = param[0]) == DEFAULT)
1547		count = 1;
1548	    while ((count-- > 0)
1549		   && (TabToNextStop(xw))) ;
1550	    sp->parsestate = sp->groundtable;
1551	    break;
1552
1553	case CASE_TAB:
1554	    /* tab */
1555	    TabToNextStop(xw);
1556	    break;
1557
1558	case CASE_SI:
1559	    screen->curgl = 0;
1560	    if_OPT_VT52_MODE(screen, {
1561		sp->parsestate = sp->groundtable;
1562	    });
1563	    break;
1564
1565	case CASE_SO:
1566	    screen->curgl = 1;
1567	    if_OPT_VT52_MODE(screen, {
1568		sp->parsestate = sp->groundtable;
1569	    });
1570	    break;
1571
1572	case CASE_DECDHL:
1573	    xterm_DECDHL(xw, c == '3');
1574	    sp->parsestate = sp->groundtable;
1575	    break;
1576
1577	case CASE_DECSWL:
1578	    xterm_DECSWL(xw);
1579	    sp->parsestate = sp->groundtable;
1580	    break;
1581
1582	case CASE_DECDWL:
1583	    xterm_DECDWL(xw);
1584	    sp->parsestate = sp->groundtable;
1585	    break;
1586
1587	case CASE_SCR_STATE:
1588	    /* enter scr state */
1589	    sp->parsestate = scrtable;
1590	    break;
1591
1592	case CASE_SCS0_STATE:
1593	    /* enter scs state 0 */
1594	    sp->scstype = 0;
1595	    sp->parsestate = scstable;
1596	    break;
1597
1598	case CASE_SCS1_STATE:
1599	    /* enter scs state 1 */
1600	    sp->scstype = 1;
1601	    sp->parsestate = scstable;
1602	    break;
1603
1604	case CASE_SCS2_STATE:
1605	    /* enter scs state 2 */
1606	    sp->scstype = 2;
1607	    sp->parsestate = scstable;
1608	    break;
1609
1610	case CASE_SCS3_STATE:
1611	    /* enter scs state 3 */
1612	    sp->scstype = 3;
1613	    sp->parsestate = scstable;
1614	    break;
1615
1616	case CASE_ESC_IGNORE:
1617	    /* unknown escape sequence */
1618	    sp->parsestate = eigtable;
1619	    break;
1620
1621	case CASE_ESC_DIGIT:
1622	    /* digit in csi or dec mode */
1623	    if ((row = param[nparam - 1]) == DEFAULT)
1624		row = 0;
1625	    param[nparam - 1] = 10 * row + (c - '0');
1626	    if (param[nparam - 1] > 65535)
1627		param[nparam - 1] = 65535;
1628	    if (sp->parsestate == csi_table)
1629		sp->parsestate = csi2_table;
1630	    break;
1631
1632	case CASE_ESC_SEMI:
1633	    /* semicolon in csi or dec mode */
1634	    if (nparam < NPARAM)
1635		param[nparam++] = DEFAULT;
1636	    if (sp->parsestate == csi_table)
1637		sp->parsestate = csi2_table;
1638	    break;
1639
1640	case CASE_DEC_STATE:
1641	    /* enter dec mode */
1642	    sp->parsestate = dec_table;
1643	    break;
1644
1645	case CASE_DEC2_STATE:
1646	    /* enter dec2 mode */
1647	    sp->parsestate = dec2_table;
1648	    break;
1649
1650	case CASE_DEC3_STATE:
1651	    /* enter dec3 mode */
1652	    sp->parsestate = dec3_table;
1653	    break;
1654
1655	case CASE_ICH:
1656	    TRACE(("CASE_ICH - insert char\n"));
1657	    if ((row = param[0]) < 1)
1658		row = 1;
1659	    InsertChar(xw, (unsigned) row);
1660	    sp->parsestate = sp->groundtable;
1661	    break;
1662
1663	case CASE_CUU:
1664	    TRACE(("CASE_CUU - cursor up\n"));
1665	    if ((row = param[0]) < 1)
1666		row = 1;
1667	    CursorUp(screen, row);
1668	    sp->parsestate = sp->groundtable;
1669	    break;
1670
1671	case CASE_CUD:
1672	    TRACE(("CASE_CUD - cursor down\n"));
1673	    if ((row = param[0]) < 1)
1674		row = 1;
1675	    CursorDown(screen, row);
1676	    sp->parsestate = sp->groundtable;
1677	    break;
1678
1679	case CASE_CUF:
1680	    TRACE(("CASE_CUF - cursor forward\n"));
1681	    if ((col = param[0]) < 1)
1682		col = 1;
1683	    CursorForward(screen, col);
1684	    sp->parsestate = sp->groundtable;
1685	    break;
1686
1687	case CASE_CUB:
1688	    TRACE(("CASE_CUB - cursor backward\n"));
1689	    if ((col = param[0]) < 1)
1690		col = 1;
1691	    CursorBack(xw, col);
1692	    sp->parsestate = sp->groundtable;
1693	    break;
1694
1695	case CASE_CUP:
1696	    TRACE(("CASE_CUP - cursor position\n"));
1697	    if_OPT_XMC_GLITCH(screen, {
1698		Jump_XMC(xw);
1699	    });
1700	    if ((row = param[0]) < 1)
1701		row = 1;
1702	    if (nparam < 2 || (col = param[1]) < 1)
1703		col = 1;
1704	    CursorSet(screen, row - 1, col - 1, xw->flags);
1705	    sp->parsestate = sp->groundtable;
1706	    break;
1707
1708	case CASE_VPA:
1709	    TRACE(("CASE_VPA - vertical position\n"));
1710	    if ((row = param[0]) < 1)
1711		row = 1;
1712	    CursorSet(screen, row - 1, screen->cur_col, xw->flags);
1713	    sp->parsestate = sp->groundtable;
1714	    break;
1715
1716	case CASE_HPA:
1717	    TRACE(("CASE_HPA - horizontal position\n"));
1718	    if ((col = param[0]) < 1)
1719		col = 1;
1720	    CursorSet(screen, screen->cur_row, col - 1, xw->flags);
1721	    sp->parsestate = sp->groundtable;
1722	    break;
1723
1724	case CASE_HP_BUGGY_LL:
1725	    TRACE(("CASE_HP_BUGGY_LL\n"));
1726	    /* Some HP-UX applications have the bug that they
1727	       assume ESC F goes to the lower left corner of
1728	       the screen, regardless of what terminfo says. */
1729	    if (screen->hp_ll_bc)
1730		CursorSet(screen, screen->max_row, 0, xw->flags);
1731	    sp->parsestate = sp->groundtable;
1732	    break;
1733
1734	case CASE_ED:
1735	    TRACE(("CASE_ED - erase display\n"));
1736	    do_erase_display(xw, param[0], OFF_PROTECT);
1737	    sp->parsestate = sp->groundtable;
1738	    break;
1739
1740	case CASE_EL:
1741	    TRACE(("CASE_EL - erase line\n"));
1742	    do_erase_line(xw, param[0], OFF_PROTECT);
1743	    sp->parsestate = sp->groundtable;
1744	    break;
1745
1746	case CASE_ECH:
1747	    TRACE(("CASE_ECH - erase char\n"));
1748	    /* ECH */
1749	    ClearRight(xw, param[0] < 1 ? 1 : param[0]);
1750	    sp->parsestate = sp->groundtable;
1751	    break;
1752
1753	case CASE_IL:
1754	    TRACE(("CASE_IL - insert line\n"));
1755	    if ((row = param[0]) < 1)
1756		row = 1;
1757	    InsertLine(xw, row);
1758	    sp->parsestate = sp->groundtable;
1759	    break;
1760
1761	case CASE_DL:
1762	    TRACE(("CASE_DL - delete line\n"));
1763	    if ((row = param[0]) < 1)
1764		row = 1;
1765	    DeleteLine(xw, row);
1766	    sp->parsestate = sp->groundtable;
1767	    break;
1768
1769	case CASE_DCH:
1770	    TRACE(("CASE_DCH - delete char\n"));
1771	    if ((row = param[0]) < 1)
1772		row = 1;
1773	    DeleteChar(xw, (unsigned) row);
1774	    sp->parsestate = sp->groundtable;
1775	    break;
1776
1777	case CASE_TRACK_MOUSE:
1778	    /*
1779	     * A single parameter other than zero is always scroll-down.
1780	     * A zero-parameter is used to reset the mouse mode, and is
1781	     * not useful for scrolling anyway.
1782	     */
1783	    if (nparam > 1 || param[0] == 0) {
1784		CELL start;
1785
1786		TRACE(("CASE_TRACK_MOUSE\n"));
1787		/* Track mouse as long as in window and between
1788		 * specified rows
1789		 */
1790		start.row = param[2] - 1;
1791		start.col = param[1] - 1;
1792		TrackMouse(xw,
1793			   param[0],
1794			   &start,
1795			   param[3] - 1, param[4] - 2);
1796	    } else {
1797		TRACE(("CASE_SD - scroll down\n"));
1798		/* SD */
1799		if ((count = param[0]) < 1)
1800		    count = 1;
1801		RevScroll(xw, count);
1802		do_xevents();
1803	    }
1804	    sp->parsestate = sp->groundtable;
1805	    break;
1806
1807	case CASE_DECID:
1808	    TRACE(("CASE_DECID\n"));
1809	    if_OPT_VT52_MODE(screen, {
1810		unparseputc(xw, ANSI_ESC);
1811		unparseputc(xw, '/');
1812		unparseputc(xw, 'Z');
1813		unparse_end(xw);
1814		sp->parsestate = sp->groundtable;
1815		break;
1816	    });
1817	    param[0] = DEFAULT;	/* Default ID parameter */
1818	    /* FALLTHRU */
1819	case CASE_DA1:
1820	    TRACE(("CASE_DA1\n"));
1821	    if (param[0] <= 0) {	/* less than means DEFAULT */
1822		count = 0;
1823		reply.a_type = ANSI_CSI;
1824		reply.a_pintro = '?';
1825
1826		/* The first param corresponds to the highest
1827		 * operating level (i.e., service level) of the
1828		 * emulation.  A DEC terminal can be setup to
1829		 * respond with a different DA response, but
1830		 * there's no control sequence that modifies this.
1831		 * We set it via a resource.
1832		 */
1833		if (screen->terminal_id < 200) {
1834		    switch (screen->terminal_id) {
1835		    case 102:
1836			reply.a_param[count++] = 6;	/* VT102 */
1837			break;
1838		    case 101:
1839			reply.a_param[count++] = 1;	/* VT101 */
1840			reply.a_param[count++] = 0;	/* no options */
1841			break;
1842		    default:	/* VT100 */
1843			reply.a_param[count++] = 1;	/* VT100 */
1844			reply.a_param[count++] = 2;	/* AVO */
1845			break;
1846		    }
1847		} else {
1848		    reply.a_param[count++] = 60 + screen->terminal_id / 100;
1849		    reply.a_param[count++] = 1;		/* 132-columns */
1850		    reply.a_param[count++] = 2;		/* printer */
1851		    reply.a_param[count++] = 6;		/* selective-erase */
1852#if OPT_SUNPC_KBD
1853		    if (xw->keyboard.type == keyboardIsVT220)
1854#endif
1855			reply.a_param[count++] = 8;	/* user-defined-keys */
1856		    reply.a_param[count++] = 9;		/* national replacement charsets */
1857		    reply.a_param[count++] = 15;	/* technical characters */
1858		    if_OPT_ISO_COLORS(screen, {
1859			reply.a_param[count++] = 22;	/* ANSI color, VT525 */
1860		    });
1861#if OPT_DEC_LOCATOR
1862		    reply.a_param[count++] = 29;	/* ANSI text locator */
1863#endif
1864		}
1865		reply.a_nparam = count;
1866		reply.a_inters = 0;
1867		reply.a_final = 'c';
1868		unparseseq(xw, &reply);
1869	    }
1870	    sp->parsestate = sp->groundtable;
1871	    break;
1872
1873	case CASE_DA2:
1874	    TRACE(("CASE_DA2\n"));
1875	    if (param[0] <= 0) {	/* less than means DEFAULT */
1876		count = 0;
1877		reply.a_type = ANSI_CSI;
1878		reply.a_pintro = '>';
1879
1880		if (screen->terminal_id >= 200)
1881		    reply.a_param[count++] = 1;		/* VT220 */
1882		else
1883		    reply.a_param[count++] = 0;		/* VT100 (nonstandard) */
1884		reply.a_param[count++] = XTERM_PATCH;	/* Version */
1885		reply.a_param[count++] = 0;	/* options (none) */
1886		reply.a_nparam = count;
1887		reply.a_inters = 0;
1888		reply.a_final = 'c';
1889		unparseseq(xw, &reply);
1890	    }
1891	    sp->parsestate = sp->groundtable;
1892	    break;
1893
1894	case CASE_DECRPTUI:
1895	    TRACE(("CASE_DECRPTUI\n"));
1896	    if ((screen->terminal_id >= 400)
1897		&& (param[0] <= 0)) {	/* less than means DEFAULT */
1898		unparseputc1(xw, ANSI_DCS);
1899		unparseputc(xw, '!');
1900		unparseputc(xw, '|');
1901		unparseputc(xw, '0');
1902		unparseputc1(xw, ANSI_ST);
1903		unparse_end(xw);
1904	    }
1905	    sp->parsestate = sp->groundtable;
1906	    break;
1907
1908	case CASE_TBC:
1909	    TRACE(("CASE_TBC - tab clear\n"));
1910	    if ((row = param[0]) <= 0)	/* less than means default */
1911		TabClear(xw->tabs, screen->cur_col);
1912	    else if (row == 3)
1913		TabZonk(xw->tabs);
1914	    sp->parsestate = sp->groundtable;
1915	    break;
1916
1917	case CASE_SET:
1918	    TRACE(("CASE_SET - set mode\n"));
1919	    ansi_modes(xw, bitset);
1920	    sp->parsestate = sp->groundtable;
1921	    break;
1922
1923	case CASE_RST:
1924	    TRACE(("CASE_RST - reset mode\n"));
1925	    ansi_modes(xw, bitclr);
1926	    sp->parsestate = sp->groundtable;
1927	    break;
1928
1929	case CASE_SGR:
1930	    for (row = 0; row < nparam; ++row) {
1931		if_OPT_XMC_GLITCH(screen, {
1932		    Mark_XMC(xw, param[row]);
1933		});
1934		TRACE(("CASE_SGR %d\n", param[row]));
1935		switch (param[row]) {
1936		case DEFAULT:
1937		case 0:
1938		    xw->flags &=
1939			~(INVERSE | BOLD | BLINK | UNDERLINE | INVISIBLE);
1940		    if_OPT_ISO_COLORS(screen, {
1941			reset_SGR_Colors(xw);
1942		    });
1943		    break;
1944		case 1:	/* Bold                 */
1945		    xw->flags |= BOLD;
1946		    if_OPT_ISO_COLORS(screen, {
1947			setExtendedFG(xw);
1948		    });
1949		    break;
1950		case 5:	/* Blink                */
1951		    xw->flags |= BLINK;
1952		    StartBlinking(screen);
1953		    if_OPT_ISO_COLORS(screen, {
1954			setExtendedFG(xw);
1955		    });
1956		    break;
1957		case 4:	/* Underscore           */
1958		    xw->flags |= UNDERLINE;
1959		    if_OPT_ISO_COLORS(screen, {
1960			setExtendedFG(xw);
1961		    });
1962		    break;
1963		case 7:
1964		    xw->flags |= INVERSE;
1965		    if_OPT_ISO_COLORS(screen, {
1966			setExtendedBG(xw);
1967		    });
1968		    break;
1969		case 8:
1970		    xw->flags |= INVISIBLE;
1971		    break;
1972		case 22:	/* reset 'bold' */
1973		    xw->flags &= ~BOLD;
1974		    if_OPT_ISO_COLORS(screen, {
1975			setExtendedFG(xw);
1976		    });
1977		    break;
1978		case 24:
1979		    xw->flags &= ~UNDERLINE;
1980		    if_OPT_ISO_COLORS(screen, {
1981			setExtendedFG(xw);
1982		    });
1983		    break;
1984		case 25:	/* reset 'blink' */
1985		    xw->flags &= ~BLINK;
1986		    if_OPT_ISO_COLORS(screen, {
1987			setExtendedFG(xw);
1988		    });
1989		    break;
1990		case 27:
1991		    xw->flags &= ~INVERSE;
1992		    if_OPT_ISO_COLORS(screen, {
1993			setExtendedBG(xw);
1994		    });
1995		    break;
1996		case 28:
1997		    xw->flags &= ~INVISIBLE;
1998		    break;
1999		case 30:
2000		case 31:
2001		case 32:
2002		case 33:
2003		case 34:
2004		case 35:
2005		case 36:
2006		case 37:
2007		    if_OPT_ISO_COLORS(screen, {
2008			xw->sgr_foreground = (param[row] - 30);
2009			xw->sgr_extended = False;
2010			setExtendedFG(xw);
2011		    });
2012		    break;
2013		case 38:
2014		    /* This is more complicated than I'd
2015		       like, but it should properly eat all
2016		       the parameters for unsupported modes
2017		     */
2018		    if_OPT_ISO_COLORS(screen, {
2019			row++;
2020			if (row < nparam) {
2021			    switch (param[row]) {
2022			    case 5:
2023				row++;
2024				if (row < nparam &&
2025				    param[row] < NUM_ANSI_COLORS) {
2026				    xw->sgr_foreground = param[row];
2027				    xw->sgr_extended = True;
2028				    setExtendedFG(xw);
2029				}
2030				break;
2031			    default:
2032				row += 7;
2033				break;
2034			    }
2035			}
2036		    });
2037		    break;
2038		case 39:
2039		    if_OPT_ISO_COLORS(screen, {
2040			reset_SGR_Foreground(xw);
2041		    });
2042		    break;
2043		case 40:
2044		case 41:
2045		case 42:
2046		case 43:
2047		case 44:
2048		case 45:
2049		case 46:
2050		case 47:
2051		    if_OPT_ISO_COLORS(screen, {
2052			xw->sgr_background = (param[row] - 40);
2053			setExtendedBG(xw);
2054		    });
2055		    break;
2056		case 48:
2057		    if_OPT_ISO_COLORS(screen, {
2058			row++;
2059			if (row < nparam) {
2060			    switch (param[row]) {
2061			    case 5:
2062				row++;
2063				if (row < nparam &&
2064				    param[row] < NUM_ANSI_COLORS) {
2065				    xw->sgr_background = param[row];
2066				    setExtendedBG(xw);
2067				}
2068				break;
2069			    default:
2070				row += 7;
2071				break;
2072			    }
2073			}
2074		    });
2075		    break;
2076		case 49:
2077		    if_OPT_ISO_COLORS(screen, {
2078			reset_SGR_Background(xw);
2079		    });
2080		    break;
2081		case 90:
2082		case 91:
2083		case 92:
2084		case 93:
2085		case 94:
2086		case 95:
2087		case 96:
2088		case 97:
2089		    if_OPT_AIX_COLORS(screen, {
2090			xw->sgr_foreground = (param[row] - 90 + 8);
2091			xw->sgr_extended = False;
2092			setExtendedFG(xw);
2093		    });
2094		    break;
2095		case 100:
2096#if !OPT_AIX_COLORS
2097		    if_OPT_ISO_COLORS(screen, {
2098			reset_SGR_Foreground(xw);
2099			reset_SGR_Background(xw);
2100		    });
2101		    break;
2102#endif
2103		case 101:
2104		case 102:
2105		case 103:
2106		case 104:
2107		case 105:
2108		case 106:
2109		case 107:
2110		    if_OPT_AIX_COLORS(screen, {
2111			xw->sgr_background = (param[row] - 100 + 8);
2112			setExtendedBG(xw);
2113		    });
2114		    break;
2115		}
2116	    }
2117	    sp->parsestate = sp->groundtable;
2118	    break;
2119
2120	    /* DSR (except for the '?') is a superset of CPR */
2121	case CASE_DSR:
2122	    sp->private_function = True;
2123
2124	    /* FALLTHRU */
2125	case CASE_CPR:
2126	    TRACE(("CASE_CPR - cursor position\n"));
2127	    count = 0;
2128	    reply.a_type = ANSI_CSI;
2129	    reply.a_pintro = sp->private_function ? '?' : 0;
2130	    reply.a_inters = 0;
2131	    reply.a_final = 'n';
2132
2133	    switch (param[0]) {
2134	    case 5:
2135		/* operating status */
2136		reply.a_param[count++] = 0;	/* (no malfunction ;-) */
2137		break;
2138	    case 6:
2139		/* CPR */
2140		/* DECXCPR (with page=0) */
2141		reply.a_param[count++] = screen->cur_row + 1;
2142		reply.a_param[count++] = screen->cur_col + 1;
2143		reply.a_final = 'R';
2144		break;
2145	    case 15:
2146		/* printer status */
2147		reply.a_param[count++] = 13;	/* implement printer */
2148		break;
2149	    case 25:
2150		/* UDK status */
2151		reply.a_param[count++] = 20;	/* UDK always unlocked */
2152		break;
2153	    case 26:
2154		/* keyboard status */
2155		reply.a_param[count++] = 27;
2156		reply.a_param[count++] = 1;	/* North American */
2157		if (screen->terminal_id >= 400) {
2158		    reply.a_param[count++] = 0;		/* ready */
2159		    reply.a_param[count++] = 0;		/* LK201 */
2160		}
2161		break;
2162	    case 53:
2163		/* Locator status */
2164#if OPT_DEC_LOCATOR
2165		reply.a_param[count++] = 50;	/* locator ready */
2166#else
2167		reply.a_param[count++] = 53;	/* no locator */
2168#endif
2169		break;
2170	    }
2171
2172	    if ((reply.a_nparam = count) != 0)
2173		unparseseq(xw, &reply);
2174
2175	    sp->parsestate = sp->groundtable;
2176	    sp->private_function = False;
2177	    break;
2178
2179	case CASE_MC:
2180	    TRACE(("CASE_MC - media control\n"));
2181	    xtermMediaControl(param[0], False);
2182	    sp->parsestate = sp->groundtable;
2183	    break;
2184
2185	case CASE_DEC_MC:
2186	    TRACE(("CASE_DEC_MC - DEC media control\n"));
2187	    xtermMediaControl(param[0], True);
2188	    sp->parsestate = sp->groundtable;
2189	    break;
2190
2191	case CASE_HP_MEM_LOCK:
2192	case CASE_HP_MEM_UNLOCK:
2193	    TRACE(("%s\n", ((sp->parsestate[c] == CASE_HP_MEM_LOCK)
2194			    ? "CASE_HP_MEM_LOCK"
2195			    : "CASE_HP_MEM_UNLOCK")));
2196	    if (screen->scroll_amt)
2197		FlushScroll(xw);
2198	    if (sp->parsestate[c] == CASE_HP_MEM_LOCK)
2199		set_tb_margins(screen, screen->cur_row, screen->bot_marg);
2200	    else
2201		set_tb_margins(screen, 0, screen->bot_marg);
2202	    sp->parsestate = sp->groundtable;
2203	    break;
2204
2205	case CASE_DECSTBM:
2206	    TRACE(("CASE_DECSTBM - set scrolling region\n"));
2207	    if ((top = param[0]) < 1)
2208		top = 1;
2209	    if (nparam < 2 || (bot = param[1]) == DEFAULT
2210		|| bot > MaxRows(screen)
2211		|| bot == 0)
2212		bot = MaxRows(screen);
2213	    if (bot > top) {
2214		if (screen->scroll_amt)
2215		    FlushScroll(xw);
2216		set_tb_margins(screen, top - 1, bot - 1);
2217		CursorSet(screen, 0, 0, xw->flags);
2218	    }
2219	    sp->parsestate = sp->groundtable;
2220	    break;
2221
2222	case CASE_DECREQTPARM:
2223	    TRACE(("CASE_DECREQTPARM\n"));
2224	    if (screen->terminal_id < 200) {	/* VT102 */
2225		if ((row = param[0]) == DEFAULT)
2226		    row = 0;
2227		if (row == 0 || row == 1) {
2228		    reply.a_type = ANSI_CSI;
2229		    reply.a_pintro = 0;
2230		    reply.a_nparam = 7;
2231		    reply.a_param[0] = row + 2;
2232		    reply.a_param[1] = 1;	/* no parity */
2233		    reply.a_param[2] = 1;	/* eight bits */
2234		    reply.a_param[3] = 128;	/* transmit 38.4k baud */
2235		    reply.a_param[4] = 128;	/* receive 38.4k baud */
2236		    reply.a_param[5] = 1;	/* clock multiplier ? */
2237		    reply.a_param[6] = 0;	/* STP flags ? */
2238		    reply.a_inters = 0;
2239		    reply.a_final = 'x';
2240		    unparseseq(xw, &reply);
2241		}
2242	    }
2243	    sp->parsestate = sp->groundtable;
2244	    break;
2245
2246	case CASE_DECSET:
2247	    /* DECSET */
2248#if OPT_VT52_MODE
2249	    if (screen->vtXX_level != 0)
2250#endif
2251		dpmodes(xw, bitset);
2252	    sp->parsestate = sp->groundtable;
2253#if OPT_TEK4014
2254	    if (TEK4014_ACTIVE(xw))
2255		return False;
2256#endif
2257	    break;
2258
2259	case CASE_DECRST:
2260	    /* DECRST */
2261	    dpmodes(xw, bitclr);
2262#if OPT_VT52_MODE
2263	    if (screen->vtXX_level == 0)
2264		sp->groundtable = vt52_table;
2265	    else if (screen->terminal_id >= 100)
2266		sp->groundtable = ansi_table;
2267#endif
2268	    sp->parsestate = sp->groundtable;
2269	    break;
2270
2271	case CASE_DECALN:
2272	    TRACE(("CASE_DECALN - alignment test\n"));
2273	    if (screen->cursor_state)
2274		HideCursor();
2275	    set_tb_margins(screen, 0, screen->max_row);
2276	    CursorSet(screen, 0, 0, xw->flags);
2277	    xtermParseRect(xw, 0, 0, &myRect);
2278	    ScrnFillRectangle(xw, &myRect, 'E', 0, False);
2279	    sp->parsestate = sp->groundtable;
2280	    break;
2281
2282	case CASE_GSETS:
2283	    TRACE(("CASE_GSETS(%d) = '%c'\n", sp->scstype, c));
2284	    if (screen->vtXX_level != 0)
2285		screen->gsets[sp->scstype] = c;
2286	    sp->parsestate = sp->groundtable;
2287	    break;
2288
2289	case CASE_DECSC:
2290	    TRACE(("CASE_DECSC - save cursor\n"));
2291	    CursorSave(xw);
2292	    sp->parsestate = sp->groundtable;
2293	    break;
2294
2295	case CASE_DECRC:
2296	    TRACE(("CASE_DECRC - restore cursor\n"));
2297	    CursorRestore(xw);
2298	    if_OPT_ISO_COLORS(screen, {
2299		setExtendedFG(xw);
2300	    });
2301	    sp->parsestate = sp->groundtable;
2302	    break;
2303
2304	case CASE_DECKPAM:
2305	    TRACE(("CASE_DECKPAM\n"));
2306	    xw->keyboard.flags |= MODE_DECKPAM;
2307	    update_appkeypad();
2308	    sp->parsestate = sp->groundtable;
2309	    break;
2310
2311	case CASE_DECKPNM:
2312	    TRACE(("CASE_DECKPNM\n"));
2313	    xw->keyboard.flags &= ~MODE_DECKPAM;
2314	    update_appkeypad();
2315	    sp->parsestate = sp->groundtable;
2316	    break;
2317
2318	case CASE_CSI_QUOTE_STATE:
2319	    sp->parsestate = csi_quo_table;
2320	    break;
2321
2322#if OPT_VT52_MODE
2323	case CASE_VT52_FINISH:
2324	    TRACE(("CASE_VT52_FINISH terminal_id %d, vtXX_level %d\n",
2325		   screen->terminal_id,
2326		   screen->vtXX_level));
2327	    if (screen->terminal_id >= 100
2328		&& screen->vtXX_level == 0) {
2329		sp->groundtable =
2330		    sp->parsestate = ansi_table;
2331		screen->vtXX_level = screen->vt52_save_level;
2332		screen->curgl = screen->vt52_save_curgl;
2333		screen->curgr = screen->vt52_save_curgr;
2334		screen->curss = screen->vt52_save_curss;
2335		memmove(screen->gsets, screen->vt52_save_gsets, sizeof(screen->gsets));
2336	    }
2337	    break;
2338#endif
2339
2340	case CASE_ANSI_LEVEL_1:
2341	    TRACE(("CASE_ANSI_LEVEL_1\n"));
2342	    set_ansi_conformance(screen, 1);
2343	    sp->parsestate = sp->groundtable;
2344	    break;
2345
2346	case CASE_ANSI_LEVEL_2:
2347	    TRACE(("CASE_ANSI_LEVEL_2\n"));
2348	    set_ansi_conformance(screen, 2);
2349	    sp->parsestate = sp->groundtable;
2350	    break;
2351
2352	case CASE_ANSI_LEVEL_3:
2353	    TRACE(("CASE_ANSI_LEVEL_3\n"));
2354	    set_ansi_conformance(screen, 3);
2355	    sp->parsestate = sp->groundtable;
2356	    break;
2357
2358	case CASE_DECSCL:
2359	    TRACE(("CASE_DECSCL(%d,%d)\n", param[0], param[1]));
2360	    if (param[0] >= 61 && param[0] <= 65) {
2361		/*
2362		 * VT300, VT420, VT520 manuals claim that DECSCL does a hard
2363		 * reset (RIS).  VT220 manual states that it is a soft reset.
2364		 * Perhaps both are right (unlikely).  Kermit says it's soft.
2365		 */
2366		VTReset(xw, False, False);
2367		screen->vtXX_level = param[0] - 60;
2368		if (param[0] > 61) {
2369		    if (param[1] == 1)
2370			show_8bit_control(False);
2371		    else if (param[1] == 0 || param[1] == 2)
2372			show_8bit_control(True);
2373		}
2374	    }
2375	    sp->parsestate = sp->groundtable;
2376	    break;
2377
2378	case CASE_DECSCA:
2379	    TRACE(("CASE_DECSCA\n"));
2380	    screen->protected_mode = DEC_PROTECT;
2381	    if (param[0] <= 0 || param[0] == 2)
2382		xw->flags &= ~PROTECTED;
2383	    else if (param[0] == 1)
2384		xw->flags |= PROTECTED;
2385	    sp->parsestate = sp->groundtable;
2386	    break;
2387
2388	case CASE_DECSED:
2389	    TRACE(("CASE_DECSED\n"));
2390	    do_erase_display(xw, param[0], DEC_PROTECT);
2391	    sp->parsestate = sp->groundtable;
2392	    break;
2393
2394	case CASE_DECSEL:
2395	    TRACE(("CASE_DECSEL\n"));
2396	    do_erase_line(xw, param[0], DEC_PROTECT);
2397	    sp->parsestate = sp->groundtable;
2398	    break;
2399
2400	case CASE_ST:
2401	    TRACE(("CASE_ST: End of String (%d bytes)\n", string_used));
2402	    sp->parsestate = sp->groundtable;
2403	    if (!string_used)
2404		break;
2405	    string_area[--string_used] = '\0';
2406	    switch (sp->string_mode) {
2407	    case ANSI_APC:
2408		/* ignored */
2409		break;
2410	    case ANSI_DCS:
2411		do_dcs(xw, string_area, string_used);
2412		break;
2413	    case ANSI_OSC:
2414		do_osc(xw, string_area, string_used, ANSI_ST);
2415		break;
2416	    case ANSI_PM:
2417		/* ignored */
2418		break;
2419	    case ANSI_SOS:
2420		/* ignored */
2421		break;
2422	    }
2423	    break;
2424
2425	case CASE_SOS:
2426	    TRACE(("CASE_SOS: Start of String\n"));
2427	    sp->string_mode = ANSI_SOS;
2428	    sp->parsestate = sos_table;
2429	    break;
2430
2431	case CASE_PM:
2432	    TRACE(("CASE_PM: Privacy Message\n"));
2433	    sp->string_mode = ANSI_PM;
2434	    sp->parsestate = sos_table;
2435	    break;
2436
2437	case CASE_DCS:
2438	    TRACE(("CASE_DCS: Device Control String\n"));
2439	    sp->string_mode = ANSI_DCS;
2440	    sp->parsestate = sos_table;
2441	    break;
2442
2443	case CASE_APC:
2444	    TRACE(("CASE_APC: Application Program Command\n"));
2445	    sp->string_mode = ANSI_APC;
2446	    sp->parsestate = sos_table;
2447	    break;
2448
2449	case CASE_SPA:
2450	    TRACE(("CASE_SPA - start protected area\n"));
2451	    screen->protected_mode = ISO_PROTECT;
2452	    xw->flags |= PROTECTED;
2453	    sp->parsestate = sp->groundtable;
2454	    break;
2455
2456	case CASE_EPA:
2457	    TRACE(("CASE_EPA - end protected area\n"));
2458	    xw->flags &= ~PROTECTED;
2459	    sp->parsestate = sp->groundtable;
2460	    break;
2461
2462	case CASE_SU:
2463	    TRACE(("CASE_SU - scroll up\n"));
2464	    if ((count = param[0]) < 1)
2465		count = 1;
2466	    xtermScroll(xw, count);
2467	    sp->parsestate = sp->groundtable;
2468	    break;
2469
2470	case CASE_IND:
2471	    TRACE(("CASE_IND - index\n"));
2472	    xtermIndex(xw, 1);
2473	    do_xevents();
2474	    sp->parsestate = sp->groundtable;
2475	    break;
2476
2477	case CASE_CPL:
2478	    TRACE(("CASE_CPL - cursor prev line\n"));
2479	    CursorPrevLine(screen, param[0]);
2480	    sp->parsestate = sp->groundtable;
2481	    break;
2482
2483	case CASE_CNL:
2484	    TRACE(("CASE_CNL - cursor next line\n"));
2485	    CursorNextLine(screen, param[0]);
2486	    sp->parsestate = sp->groundtable;
2487	    break;
2488
2489	case CASE_NEL:
2490	    TRACE(("CASE_NEL\n"));
2491	    xtermIndex(xw, 1);
2492	    CarriageReturn(screen);
2493	    sp->parsestate = sp->groundtable;
2494	    break;
2495
2496	case CASE_HTS:
2497	    TRACE(("CASE_HTS - horizontal tab set\n"));
2498	    TabSet(xw->tabs, screen->cur_col);
2499	    sp->parsestate = sp->groundtable;
2500	    break;
2501
2502	case CASE_RI:
2503	    TRACE(("CASE_RI - reverse index\n"));
2504	    RevIndex(xw, 1);
2505	    sp->parsestate = sp->groundtable;
2506	    break;
2507
2508	case CASE_SS2:
2509	    TRACE(("CASE_SS2\n"));
2510	    screen->curss = 2;
2511	    sp->parsestate = sp->groundtable;
2512	    break;
2513
2514	case CASE_SS3:
2515	    TRACE(("CASE_SS3\n"));
2516	    screen->curss = 3;
2517	    sp->parsestate = sp->groundtable;
2518	    break;
2519
2520	case CASE_CSI_STATE:
2521	    /* enter csi state */
2522	    nparam = 1;
2523	    param[0] = DEFAULT;
2524	    sp->parsestate = csi_table;
2525	    break;
2526
2527	case CASE_ESC_SP_STATE:
2528	    /* esc space */
2529	    sp->parsestate = esc_sp_table;
2530	    break;
2531
2532	case CASE_CSI_EX_STATE:
2533	    /* csi exclamation */
2534	    sp->parsestate = csi_ex_table;
2535	    break;
2536
2537#if OPT_DEC_LOCATOR
2538	case CASE_CSI_TICK_STATE:
2539	    /* csi tick (') */
2540	    sp->parsestate = csi_tick_table;
2541	    break;
2542
2543	case CASE_DECEFR:
2544	    TRACE(("CASE_DECEFR - Enable Filter Rectangle\n"));
2545	    if (screen->send_mouse_pos == DEC_LOCATOR) {
2546		MotionOff(screen, xw);
2547		if ((screen->loc_filter_top = param[0]) < 1)
2548		    screen->loc_filter_top = LOC_FILTER_POS;
2549		if (nparam < 2 || (screen->loc_filter_left = param[1]) < 1)
2550		    screen->loc_filter_left = LOC_FILTER_POS;
2551		if (nparam < 3 || (screen->loc_filter_bottom = param[2]) < 1)
2552		    screen->loc_filter_bottom = LOC_FILTER_POS;
2553		if (nparam < 4 || (screen->loc_filter_right = param[3]) < 1)
2554		    screen->loc_filter_right = LOC_FILTER_POS;
2555		InitLocatorFilter(xw);
2556	    }
2557	    sp->parsestate = sp->groundtable;
2558	    break;
2559
2560	case CASE_DECELR:
2561	    MotionOff(screen, xw);
2562	    if (param[0] <= 0 || param[0] > 2) {
2563		screen->send_mouse_pos = MOUSE_OFF;
2564		TRACE(("DECELR - Disable Locator Reports\n"));
2565	    } else {
2566		TRACE(("DECELR - Enable Locator Reports\n"));
2567		screen->send_mouse_pos = DEC_LOCATOR;
2568		xtermShowPointer(xw, True);
2569		if (param[0] == 2) {
2570		    screen->locator_reset = True;
2571		} else {
2572		    screen->locator_reset = False;
2573		}
2574		if (nparam < 2 || param[1] != 1) {
2575		    screen->locator_pixels = False;
2576		} else {
2577		    screen->locator_pixels = True;
2578		}
2579		screen->loc_filter = False;
2580	    }
2581	    sp->parsestate = sp->groundtable;
2582	    break;
2583
2584	case CASE_DECSLE:
2585	    TRACE(("DECSLE - Select Locator Events\n"));
2586	    for (count = 0; count < nparam; ++count) {
2587		switch (param[count]) {
2588		case DEFAULT:
2589		case 0:
2590		    MotionOff(screen, xw);
2591		    screen->loc_filter = False;
2592		    screen->locator_events = 0;
2593		    break;
2594		case 1:
2595		    screen->locator_events |= LOC_BTNS_DN;
2596		    break;
2597		case 2:
2598		    screen->locator_events &= ~LOC_BTNS_DN;
2599		    break;
2600		case 3:
2601		    screen->locator_events |= LOC_BTNS_UP;
2602		    break;
2603		case 4:
2604		    screen->locator_events &= ~LOC_BTNS_UP;
2605		    break;
2606		}
2607	    }
2608	    sp->parsestate = sp->groundtable;
2609	    break;
2610
2611	case CASE_DECRQLP:
2612	    TRACE(("DECRQLP - Request Locator Position\n"));
2613	    if (param[0] < 2) {
2614		/* Issue DECLRP Locator Position Report */
2615		GetLocatorPosition(xw);
2616	    }
2617	    sp->parsestate = sp->groundtable;
2618	    break;
2619#endif /* OPT_DEC_LOCATOR */
2620
2621#if OPT_DEC_RECTOPS
2622	case CASE_CSI_DOLLAR_STATE:
2623	    /* csi dollar ($) */
2624	    if (screen->vtXX_level >= 4)
2625		sp->parsestate = csi_dollar_table;
2626	    else
2627		sp->parsestate = eigtable;
2628	    break;
2629
2630	case CASE_CSI_STAR_STATE:
2631	    /* csi dollar (*) */
2632	    if (screen->vtXX_level >= 4)
2633		sp->parsestate = csi_star_table;
2634	    else
2635		sp->parsestate = eigtable;
2636	    break;
2637
2638	case CASE_DECCRA:
2639	    TRACE(("CASE_DECCRA - Copy rectangular area\n"));
2640	    xtermParseRect(xw, nparam, param, &myRect);
2641	    ScrnCopyRectangle(xw, &myRect, nparam - 5, param + 5);
2642	    sp->parsestate = sp->groundtable;
2643	    break;
2644
2645	case CASE_DECERA:
2646	    TRACE(("CASE_DECERA - Erase rectangular area\n"));
2647	    xtermParseRect(xw, nparam, param, &myRect);
2648	    ScrnFillRectangle(xw, &myRect, ' ', 0, True);
2649	    sp->parsestate = sp->groundtable;
2650	    break;
2651
2652	case CASE_DECFRA:
2653	    TRACE(("CASE_DECFRA - Fill rectangular area\n"));
2654	    if (nparam > 0
2655		&& ((param[0] >= 32 && param[0] <= 126)
2656		    || (param[0] >= 160 && param[0] <= 255))) {
2657		xtermParseRect(xw, nparam - 1, param + 1, &myRect);
2658		ScrnFillRectangle(xw, &myRect, param[0], xw->flags, True);
2659	    }
2660	    sp->parsestate = sp->groundtable;
2661	    break;
2662
2663	case CASE_DECSERA:
2664	    TRACE(("CASE_DECSERA - Selective erase rectangular area\n"));
2665	    xtermParseRect(xw, nparam > 4 ? 4 : nparam, param, &myRect);
2666	    ScrnWipeRectangle(xw, &myRect);
2667	    sp->parsestate = sp->groundtable;
2668	    break;
2669
2670	case CASE_DECSACE:
2671	    TRACE(("CASE_DECSACE - Select attribute change extent\n"));
2672	    screen->cur_decsace = param[0];
2673	    sp->parsestate = sp->groundtable;
2674	    break;
2675
2676	case CASE_DECCARA:
2677	    TRACE(("CASE_DECCARA - Change attributes in rectangular area\n"));
2678	    xtermParseRect(xw, nparam > 4 ? 4 : nparam, param, &myRect);
2679	    ScrnMarkRectangle(xw, &myRect, False, nparam - 4, param + 4);
2680	    sp->parsestate = sp->groundtable;
2681	    break;
2682
2683	case CASE_DECRARA:
2684	    TRACE(("CASE_DECRARA - Reverse attributes in rectangular area\n"));
2685	    xtermParseRect(xw, nparam > 4 ? 4 : nparam, param, &myRect);
2686	    ScrnMarkRectangle(xw, &myRect, True, nparam - 4, param + 4);
2687	    sp->parsestate = sp->groundtable;
2688	    break;
2689#else
2690	case CASE_CSI_DOLLAR_STATE:
2691	    /* csi dollar ($) */
2692	    sp->parsestate = eigtable;
2693	    break;
2694
2695	case CASE_CSI_STAR_STATE:
2696	    /* csi dollar (*) */
2697	    sp->parsestate = eigtable;
2698	    break;
2699#endif /* OPT_DEC_RECTOPS */
2700
2701	case CASE_S7C1T:
2702	    TRACE(("CASE_S7C1T\n"));
2703	    show_8bit_control(False);
2704	    sp->parsestate = sp->groundtable;
2705	    break;
2706
2707	case CASE_S8C1T:
2708	    TRACE(("CASE_S8C1T\n"));
2709#if OPT_VT52_MODE
2710	    if (screen->vtXX_level <= 1)
2711		break;
2712#endif
2713	    show_8bit_control(True);
2714	    sp->parsestate = sp->groundtable;
2715	    break;
2716
2717	case CASE_OSC:
2718	    TRACE(("CASE_OSC: Operating System Command\n"));
2719	    sp->parsestate = sos_table;
2720	    sp->string_mode = ANSI_OSC;
2721	    break;
2722
2723	case CASE_RIS:
2724	    TRACE(("CASE_RIS\n"));
2725	    VTReset(xw, True, True);
2726	    sp->parsestate = sp->groundtable;
2727	    break;
2728
2729	case CASE_DECSTR:
2730	    TRACE(("CASE_DECSTR\n"));
2731	    VTReset(xw, False, False);
2732	    sp->parsestate = sp->groundtable;
2733	    break;
2734
2735	case CASE_REP:
2736	    TRACE(("CASE_REP\n"));
2737	    if (sp->lastchar >= 0 &&
2738		sp->lastchar < 256 &&
2739		sp->groundtable[E2A(sp->lastchar)] == CASE_PRINT) {
2740		IChar repeated[2];
2741		count = (param[0] < 1) ? 1 : param[0];
2742		repeated[0] = sp->lastchar;
2743		while (count-- > 0) {
2744		    dotext(xw,
2745			   screen->gsets[(int) (screen->curgl)],
2746			   repeated, 1);
2747		}
2748	    }
2749	    sp->parsestate = sp->groundtable;
2750	    break;
2751
2752	case CASE_LS2:
2753	    TRACE(("CASE_LS2\n"));
2754	    screen->curgl = 2;
2755	    sp->parsestate = sp->groundtable;
2756	    break;
2757
2758	case CASE_LS3:
2759	    TRACE(("CASE_LS3\n"));
2760	    screen->curgl = 3;
2761	    sp->parsestate = sp->groundtable;
2762	    break;
2763
2764	case CASE_LS3R:
2765	    TRACE(("CASE_LS3R\n"));
2766	    screen->curgr = 3;
2767	    sp->parsestate = sp->groundtable;
2768	    break;
2769
2770	case CASE_LS2R:
2771	    TRACE(("CASE_LS2R\n"));
2772	    screen->curgr = 2;
2773	    sp->parsestate = sp->groundtable;
2774	    break;
2775
2776	case CASE_LS1R:
2777	    TRACE(("CASE_LS1R\n"));
2778	    screen->curgr = 1;
2779	    sp->parsestate = sp->groundtable;
2780	    break;
2781
2782	case CASE_XTERM_SAVE:
2783	    savemodes(xw);
2784	    sp->parsestate = sp->groundtable;
2785	    break;
2786
2787	case CASE_XTERM_RESTORE:
2788	    restoremodes(xw);
2789	    sp->parsestate = sp->groundtable;
2790	    break;
2791
2792	case CASE_XTERM_WINOPS:
2793	    TRACE(("CASE_XTERM_WINOPS\n"));
2794	    if (screen->allowWindowOps)
2795		window_ops(xw);
2796	    sp->parsestate = sp->groundtable;
2797	    break;
2798#if OPT_WIDE_CHARS
2799	case CASE_ESC_PERCENT:
2800	    sp->parsestate = esc_pct_table;
2801	    break;
2802
2803	case CASE_UTF8:
2804	    /* If we did not set UTF-8 mode from resource or the
2805	     * command-line, allow it to be enabled/disabled by
2806	     * control sequence.
2807	     */
2808	    if (!screen->wide_chars) {
2809		WriteNow();
2810		ChangeToWide(xw);
2811	    }
2812	    if (screen->wide_chars
2813		&& screen->utf8_mode != uAlways) {
2814		switchPtyData(screen, c == 'G');
2815		TRACE(("UTF8 mode %s\n",
2816		       BtoS(screen->utf8_mode)));
2817	    } else {
2818		TRACE(("UTF8 mode NOT turned %s (%s)\n",
2819		       BtoS(c == 'G'),
2820		       (screen->utf8_mode == uAlways)
2821		       ? "UTF-8 mode set from command-line"
2822		       : "wideChars resource was not set"));
2823	    }
2824	    sp->parsestate = sp->groundtable;
2825	    break;
2826#endif
2827#if OPT_MOD_FKEYS
2828	case CASE_SET_MOD_FKEYS:
2829	    TRACE(("CASE_SET_MOD_FKEYS\n"));
2830	    if (nparam >= 1) {
2831		set_mod_fkeys(xw, param[0], nparam > 1 ? param[1] : DEFAULT, True);
2832	    } else {
2833		for (row = 1; row <= 5; ++row)
2834		    set_mod_fkeys(xw, row, DEFAULT, True);
2835	    }
2836	    break;
2837	case CASE_SET_MOD_FKEYS0:
2838	    TRACE(("CASE_SET_MOD_FKEYS0\n"));
2839	    if (nparam >= 1 && param[0] != DEFAULT) {
2840		set_mod_fkeys(xw, param[0], -1, False);
2841	    } else {
2842		xw->keyboard.modify_now.function_keys = -1;
2843	    }
2844	    break;
2845#endif
2846	case CASE_HIDE_POINTER:
2847	    TRACE(("CASE_HIDE_POINTER\n"));
2848	    if (nparam >= 1 && param[0] != DEFAULT) {
2849		screen->pointer_mode = param[0];
2850	    } else {
2851		screen->pointer_mode = DEF_POINTER_MODE;
2852	    }
2853	    break;
2854
2855	case CASE_CSI_IGNORE:
2856	    sp->parsestate = cigtable;
2857	    break;
2858	}
2859	if (sp->parsestate == sp->groundtable)
2860	    sp->lastchar = thischar;
2861    } while (0);
2862
2863#if OPT_WIDE_CHARS
2864    screen->utf8_inparse = (screen->utf8_mode != uFalse
2865			    && sp->parsestate != sos_table);
2866#endif
2867
2868    return True;
2869}
2870
2871static void
2872VTparse(XtermWidget xw)
2873{
2874    TScreen *screen;
2875
2876    /* We longjmp back to this point in VTReset() */
2877    (void) setjmp(vtjmpbuf);
2878    screen = &xw->screen;
2879    memset(&myState, 0, sizeof(myState));
2880#if OPT_VT52_MODE
2881    myState.groundtable = screen->vtXX_level ? ansi_table : vt52_table;
2882#else
2883    myState.groundtable = ansi_table;
2884#endif
2885    myState.parsestate = myState.groundtable;
2886    myState.lastchar = -1;	/* not a legal IChar */
2887    myState.nextstate = -1;	/* not a legal state */
2888
2889    do {
2890    } while (doparsing(xw, doinput(), &myState));
2891}
2892
2893static Char *v_buffer;		/* pointer to physical buffer */
2894static Char *v_bufstr = NULL;	/* beginning of area to write */
2895static Char *v_bufptr;		/* end of area to write */
2896static Char *v_bufend;		/* end of physical buffer */
2897
2898/* Write data to the pty as typed by the user, pasted with the mouse,
2899   or generated by us in response to a query ESC sequence. */
2900
2901int
2902v_write(int f, Char * data, unsigned len)
2903{
2904    int riten;
2905    unsigned c = len;
2906
2907    if (v_bufstr == NULL && len > 0) {
2908	v_buffer = (Char *) XtMalloc(len);
2909	v_bufstr = v_buffer;
2910	v_bufptr = v_buffer;
2911	v_bufend = v_buffer + len;
2912    }
2913#ifdef DEBUG
2914    if (debug) {
2915	fprintf(stderr, "v_write called with %d bytes (%d left over)",
2916		len, v_bufptr - v_bufstr);
2917	if (len > 1 && len < 10)
2918	    fprintf(stderr, " \"%.*s\"", len, (char *) data);
2919	fprintf(stderr, "\n");
2920    }
2921#endif
2922
2923#ifdef VMS
2924    if ((1 << f) != pty_mask)
2925	return (tt_write((char *) data, len));
2926#else /* VMS */
2927    if (!FD_ISSET(f, &pty_mask))
2928	return (write(f, (char *) data, len));
2929#endif /* VMS */
2930
2931    /*
2932     * Append to the block we already have.
2933     * Always doing this simplifies the code, and
2934     * isn't too bad, either.  If this is a short
2935     * block, it isn't too expensive, and if this is
2936     * a long block, we won't be able to write it all
2937     * anyway.
2938     */
2939
2940    if (len > 0) {
2941#if OPT_DABBREV
2942	term->screen.dabbrev_working = 0;	/* break dabbrev sequence */
2943#endif
2944	if (v_bufend < v_bufptr + len) {	/* we've run out of room */
2945	    if (v_bufstr != v_buffer) {
2946		/* there is unused space, move everything down */
2947		/* possibly overlapping memmove here */
2948#ifdef DEBUG
2949		if (debug)
2950		    fprintf(stderr, "moving data down %d\n",
2951			    v_bufstr - v_buffer);
2952#endif
2953		memmove(v_buffer, v_bufstr, (unsigned) (v_bufptr - v_bufstr));
2954		v_bufptr -= v_bufstr - v_buffer;
2955		v_bufstr = v_buffer;
2956	    }
2957	    if (v_bufend < v_bufptr + len) {
2958		/* still won't fit: get more space */
2959		/* Don't use XtRealloc because an error is not fatal. */
2960		int size = v_bufptr - v_buffer;		/* save across realloc */
2961		v_buffer = TypeRealloc(Char, size + len, v_buffer);
2962		if (v_buffer) {
2963#ifdef DEBUG
2964		    if (debug)
2965			fprintf(stderr, "expanded buffer to %d\n",
2966				size + len);
2967#endif
2968		    v_bufstr = v_buffer;
2969		    v_bufptr = v_buffer + size;
2970		    v_bufend = v_bufptr + len;
2971		} else {
2972		    /* no memory: ignore entire write request */
2973		    fprintf(stderr, "%s: cannot allocate buffer space\n",
2974			    xterm_name);
2975		    v_buffer = v_bufstr;	/* restore clobbered pointer */
2976		    c = 0;
2977		}
2978	    }
2979	}
2980	if (v_bufend >= v_bufptr + len) {
2981	    /* new stuff will fit */
2982	    memmove(v_bufptr, data, len);
2983	    v_bufptr += len;
2984	}
2985    }
2986
2987    /*
2988     * Write out as much of the buffer as we can.
2989     * Be careful not to overflow the pty's input silo.
2990     * We are conservative here and only write
2991     * a small amount at a time.
2992     *
2993     * If we can't push all the data into the pty yet, we expect write
2994     * to return a non-negative number less than the length requested
2995     * (if some data written) or -1 and set errno to EAGAIN,
2996     * EWOULDBLOCK, or EINTR (if no data written).
2997     *
2998     * (Not all systems do this, sigh, so the code is actually
2999     * a little more forgiving.)
3000     */
3001
3002#define MAX_PTY_WRITE 128	/* 1/2 POSIX minimum MAX_INPUT */
3003
3004    if (v_bufptr > v_bufstr) {
3005#ifdef VMS
3006	riten = tt_write(v_bufstr,
3007			 ((v_bufptr - v_bufstr <= VMS_TERM_BUFFER_SIZE)
3008			  ? v_bufptr - v_bufstr
3009			  : VMS_TERM_BUFFER_SIZE));
3010	if (riten == 0)
3011	    return (riten);
3012#else /* VMS */
3013	riten = write(f, v_bufstr,
3014		      (size_t) ((v_bufptr - v_bufstr <= MAX_PTY_WRITE)
3015				? v_bufptr - v_bufstr
3016				: MAX_PTY_WRITE));
3017	if (riten < 0)
3018#endif /* VMS */
3019	{
3020#ifdef DEBUG
3021	    if (debug)
3022		perror("write");
3023#endif
3024	    riten = 0;
3025	}
3026#ifdef DEBUG
3027	if (debug)
3028	    fprintf(stderr, "write called with %d, wrote %d\n",
3029		    v_bufptr - v_bufstr <= MAX_PTY_WRITE ?
3030		    v_bufptr - v_bufstr : MAX_PTY_WRITE,
3031		    riten);
3032#endif
3033	v_bufstr += riten;
3034	if (v_bufstr >= v_bufptr)	/* we wrote it all */
3035	    v_bufstr = v_bufptr = v_buffer;
3036    }
3037
3038    /*
3039     * If we have lots of unused memory allocated, return it
3040     */
3041    if (v_bufend - v_bufptr > 1024) {	/* arbitrary hysteresis */
3042	/* save pointers across realloc */
3043	int start = v_bufstr - v_buffer;
3044	int size = v_bufptr - v_buffer;
3045	unsigned allocsize = (unsigned) (size ? size : 1);
3046
3047	v_buffer = TypeRealloc(Char, allocsize, v_buffer);
3048	if (v_buffer) {
3049	    v_bufstr = v_buffer + start;
3050	    v_bufptr = v_buffer + size;
3051	    v_bufend = v_buffer + allocsize;
3052#ifdef DEBUG
3053	    if (debug)
3054		fprintf(stderr, "shrunk buffer to %d\n", allocsize);
3055#endif
3056	} else {
3057	    /* should we print a warning if couldn't return memory? */
3058	    v_buffer = v_bufstr - start;	/* restore clobbered pointer */
3059	}
3060    }
3061    return (c);
3062}
3063
3064#ifdef VMS
3065#define	ptymask()	(v_bufptr > v_bufstr ? pty_mask : 0)
3066
3067static void
3068in_put(XtermWidget xw)
3069{
3070    static PtySelect select_mask;
3071    static PtySelect write_mask;
3072    int update = VTbuffer->update;
3073    int size;
3074
3075    int status;
3076    Dimension replyWidth, replyHeight;
3077    XtGeometryResult stat;
3078
3079    TScreen *screen = &xw->screen;
3080    char *cp;
3081    int i;
3082
3083    select_mask = pty_mask;	/* force initial read */
3084    for (;;) {
3085
3086	/* if the terminal changed size, resize the widget */
3087	if (tt_changed) {
3088	    tt_changed = False;
3089
3090	    stat = XtMakeResizeRequest((Widget) xw,
3091				       ((Dimension) FontWidth(screen)
3092					* (tt_width)
3093					+ 2 * screen->border
3094					+ screen->fullVwin.sb_info.width),
3095				       ((Dimension) FontHeight(screen)
3096					* (tt_length)
3097					+ 2 * screen->border),
3098				       &replyWidth, &replyHeight);
3099
3100	    if (stat == XtGeometryYes || stat == XtGeometryDone) {
3101		xw->core.width = replyWidth;
3102		xw->core.height = replyHeight;
3103
3104		ScreenResize(xw, replyWidth, replyHeight, &xw->flags);
3105	    }
3106	    repairSizeHints();
3107	}
3108
3109	if (screen->eventMode == NORMAL
3110	    && readPtyData(screen, &select_mask, VTbuffer)) {
3111	    if (screen->scrollWidget
3112		&& screen->scrollttyoutput
3113		&& screen->topline < 0)
3114		/* Scroll to bottom */
3115		WindowScroll(xw, 0);
3116	    break;
3117	}
3118	if (screen->scroll_amt)
3119	    FlushScroll(xw);
3120	if (screen->cursor_set && CursorMoved(screen)) {
3121	    if (screen->cursor_state)
3122		HideCursor();
3123	    ShowCursor();
3124#if OPT_INPUT_METHOD
3125	    PreeditPosition(screen);
3126#endif
3127	} else if (screen->cursor_set != screen->cursor_state) {
3128	    if (screen->cursor_set)
3129		ShowCursor();
3130	    else
3131		HideCursor();
3132	}
3133
3134	if (QLength(screen->display)) {
3135	    select_mask = X_mask;
3136	} else {
3137	    write_mask = ptymask();
3138	    XFlush(screen->display);
3139	    select_mask = Select_mask;
3140	    if (screen->eventMode != NORMAL)
3141		select_mask = X_mask;
3142	}
3143	if (write_mask & ptymask()) {
3144	    v_write(screen->respond, 0, 0);	/* flush buffer */
3145	}
3146
3147	if (select_mask & X_mask) {
3148	    xevents();
3149	    if (VTbuffer->update != update)
3150		break;
3151	}
3152    }
3153}
3154#else /* VMS */
3155
3156static void
3157in_put(XtermWidget xw)
3158{
3159    static PtySelect select_mask;
3160    static PtySelect write_mask;
3161
3162    TScreen *screen = &xw->screen;
3163    int i, time_select;
3164    int size;
3165    int update = VTbuffer->update;
3166
3167    static struct timeval select_timeout;
3168
3169#if OPT_BLINK_CURS
3170    /*
3171     * Compute the timeout for the blinking cursor to be much smaller than
3172     * the "on" or "off" interval.
3173     */
3174    int tick = ((screen->blink_on < screen->blink_off)
3175		? screen->blink_on
3176		: screen->blink_off);
3177    tick *= (1000 / 8);		/* 1000 for msec/usec, 8 for "much" smaller */
3178    if (tick < 1)
3179	tick = 1;
3180#endif
3181
3182    for (;;) {
3183	if (screen->eventMode == NORMAL
3184	    && (size = readPtyData(screen, &select_mask, VTbuffer)) != 0) {
3185	    if (screen->scrollWidget
3186		&& screen->scrollttyoutput
3187		&& screen->topline < 0)
3188		WindowScroll(xw, 0);	/* Scroll to bottom */
3189	    /* stop speed reading at some point to look for X stuff */
3190	    TRACE(("VTbuffer uses %d/%d\n",
3191		   VTbuffer->last - VTbuffer->buffer,
3192		   BUF_SIZE));
3193	    if ((VTbuffer->last - VTbuffer->buffer) > BUF_SIZE) {
3194		FD_CLR(screen->respond, &select_mask);
3195		break;
3196	    }
3197#if defined(HAVE_SCHED_YIELD)
3198	    /*
3199	     * If we've read a full (small/fragment) buffer, let the operating
3200	     * system have a turn, and we'll resume reading until we've either
3201	     * read only a fragment of the buffer, or we've filled the large
3202	     * buffer (see above).  Doing this helps keep up with large bursts
3203	     * of output.
3204	     */
3205	    if (size == FRG_SIZE) {
3206		select_timeout.tv_sec = 0;
3207		i = Select(max_plus1, &select_mask, &write_mask, 0,
3208			   &select_timeout);
3209		if (i > 0) {
3210		    sched_yield();
3211		} else
3212		    break;
3213	    } else {
3214		break;
3215	    }
3216#else
3217	    (void) size;	/* unused in this branch */
3218	    break;
3219#endif
3220	}
3221	/* update the screen */
3222	if (screen->scroll_amt)
3223	    FlushScroll(xw);
3224	if (screen->cursor_set && CursorMoved(screen)) {
3225	    if (screen->cursor_state)
3226		HideCursor();
3227	    ShowCursor();
3228#if OPT_INPUT_METHOD
3229	    PreeditPosition(screen);
3230#endif
3231	} else if (screen->cursor_set != screen->cursor_state) {
3232	    if (screen->cursor_set)
3233		ShowCursor();
3234	    else
3235		HideCursor();
3236	}
3237
3238	XFlush(screen->display);	/* always flush writes before waiting */
3239
3240	/* Update the masks and, unless X events are already in the queue,
3241	   wait for I/O to be possible. */
3242	XFD_COPYSET(&Select_mask, &select_mask);
3243	/* in selection mode xterm does not read pty */
3244	if (screen->eventMode != NORMAL)
3245	    FD_CLR(screen->respond, &select_mask);
3246
3247	if (v_bufptr > v_bufstr) {
3248	    XFD_COPYSET(&pty_mask, &write_mask);
3249	} else
3250	    FD_ZERO(&write_mask);
3251	select_timeout.tv_sec = 0;
3252	time_select = 0;
3253
3254	/*
3255	 * if there's either an XEvent or an XtTimeout pending, just take
3256	 * a quick peek, i.e. timeout from the select() immediately.  If
3257	 * there's nothing pending, let select() block a little while, but
3258	 * for a shorter interval than the arrow-style scrollbar timeout.
3259	 * The blocking is optional, because it tends to increase the load
3260	 * on the host.
3261	 */
3262	if (XtAppPending(app_con)) {
3263	    select_timeout.tv_usec = 0;
3264	    time_select = 1;
3265	} else if (screen->awaitInput) {
3266	    select_timeout.tv_usec = 50000;
3267	    time_select = 1;
3268#if OPT_BLINK_CURS
3269	} else if ((screen->blink_timer != 0 &&
3270		    ((screen->select & FOCUS) || screen->always_highlight)) ||
3271		   (screen->cursor_state == BLINKED_OFF)) {
3272	    select_timeout.tv_usec = tick;
3273	    while (select_timeout.tv_usec > 1000000) {
3274		select_timeout.tv_usec -= 1000000;
3275		select_timeout.tv_sec++;
3276	    }
3277	    time_select = 1;
3278#endif
3279#if OPT_SESSION_MGT
3280	} else if (resource.sessionMgt) {
3281	    if (ice_fd >= 0)
3282		FD_SET(ice_fd, &select_mask);
3283#endif
3284	}
3285	if (need_cleanup)
3286	    Cleanup(0);
3287	i = Select(max_plus1, &select_mask, &write_mask, 0,
3288		   (time_select ? &select_timeout : 0));
3289	if (i < 0) {
3290	    if (errno != EINTR)
3291		SysError(ERROR_SELECT);
3292	    continue;
3293	}
3294
3295	/* if there is room to write more data to the pty, go write more */
3296	if (FD_ISSET(screen->respond, &write_mask)) {
3297	    v_write(screen->respond, (Char *) 0, 0);	/* flush buffer */
3298	}
3299
3300	/* if there are X events already in our queue, it
3301	   counts as being readable */
3302	if (XtAppPending(app_con) ||
3303	    FD_ISSET(ConnectionNumber(screen->display), &select_mask)) {
3304	    xevents();
3305	    if (VTbuffer->update != update)	/* HandleInterpret */
3306		break;
3307	}
3308
3309    }
3310}
3311#endif /* VMS */
3312
3313static IChar
3314doinput(void)
3315{
3316    TScreen *screen = TScreenOf(term);
3317
3318    while (!morePtyData(screen, VTbuffer))
3319	in_put(term);
3320    return nextPtyData(screen, VTbuffer);
3321}
3322
3323#if OPT_INPUT_METHOD
3324/*
3325 *  For OverTheSpot, client has to inform the position for XIM preedit.
3326 */
3327static void
3328PreeditPosition(TScreen * screen)
3329{
3330    XPoint spot;
3331    XVaNestedList list;
3332
3333    if (!screen->xic)
3334	return;
3335    spot.x = CurCursorX(screen, screen->cur_row, screen->cur_col);
3336    spot.y = CursorY(screen, screen->cur_row) + screen->fs_ascent;
3337    list = XVaCreateNestedList(0,
3338			       XNSpotLocation, &spot,
3339			       XNForeground, T_COLOR(screen, TEXT_FG),
3340			       XNBackground, T_COLOR(screen, TEXT_BG),
3341			       NULL);
3342    XSetICValues(screen->xic, XNPreeditAttributes, list, NULL);
3343    XFree(list);
3344}
3345#endif
3346
3347static void
3348WrapLine(XtermWidget xw)
3349{
3350    TScreen *screen = &(xw->screen);
3351
3352    /* mark that we had to wrap this line */
3353    ScrnSetFlag(screen, screen->cur_row, LINEWRAPPED);
3354    xtermAutoPrint('\n');
3355    xtermIndex(xw, 1);
3356    set_cur_col(screen, 0);
3357}
3358
3359/*
3360 * process a string of characters according to the character set indicated
3361 * by charset.  worry about end of line conditions (wraparound if selected).
3362 */
3363void
3364dotext(XtermWidget xw,
3365       int charset,
3366       IChar * buf,		/* start of characters to process */
3367       Cardinal len)		/* end */
3368{
3369    TScreen *screen = &(xw->screen);
3370#if OPT_WIDE_CHARS
3371    Cardinal chars_chomped = 1;
3372    int next_col = screen->cur_col;
3373#else
3374    int next_col, last_col, this_col;	/* must be signed */
3375#endif
3376    Cardinal offset;
3377
3378#if OPT_WIDE_CHARS
3379    /* don't translate if we use UTF-8, and are not handling legacy support
3380     * for line-drawing characters.
3381     */
3382    if ((screen->utf8_mode == uFalse)
3383	|| (screen->vt100_graphics && charset == '0'))
3384#endif
3385
3386	if (!xtermCharSetOut(buf, buf + len, charset))
3387	    return;
3388
3389    if_OPT_XMC_GLITCH(screen, {
3390	Cardinal n;
3391	if (charset != '?') {
3392	    for (n = 0; n < len; n++) {
3393		if (buf[n] == XMC_GLITCH)
3394		    buf[n] = XMC_GLITCH + 1;
3395	    }
3396	}
3397    });
3398
3399#if OPT_WIDE_CHARS
3400    for (offset = 0;
3401	 offset < len && (chars_chomped > 0 || screen->do_wrap);
3402	 offset += chars_chomped) {
3403	int width_available = MaxCols(screen) - screen->cur_col;
3404	int width_here = 0;
3405	int need_wrap = 0;
3406	int last_chomp = 0;
3407	chars_chomped = 0;
3408
3409	if (screen->do_wrap) {
3410	    screen->do_wrap = 0;
3411	    if ((xw->flags & WRAPAROUND)) {
3412		WrapLine(xw);
3413		width_available = MaxCols(screen) - screen->cur_col;
3414		next_col = screen->cur_col;
3415	    }
3416	}
3417
3418	while (width_here <= width_available && chars_chomped < (len - offset)) {
3419	    if (!screen->utf8_mode
3420		|| (screen->vt100_graphics && charset == '0'))
3421		last_chomp = 1;
3422	    else
3423		last_chomp = my_wcwidth((int) buf[chars_chomped + offset]);
3424	    width_here += last_chomp;
3425	    chars_chomped++;
3426	}
3427
3428	if (width_here > width_available) {
3429	    if (last_chomp > MaxCols(screen))
3430		break;		/* give up - it is too big */
3431	    chars_chomped--;
3432	    width_here -= last_chomp;
3433	    if (chars_chomped > 0) {
3434		need_wrap = 1;
3435	    }
3436	} else if (width_here == width_available) {
3437	    need_wrap = 1;
3438	} else if (chars_chomped != (len - offset)) {
3439	    need_wrap = 1;
3440	}
3441
3442	/*
3443	 * Split the wide characters back into separate arrays of 8-bit
3444	 * characters so we can use the existing interface.
3445	 *
3446	 * FIXME:  If we rewrote this interface, it would involve
3447	 * rewriting all of the memory-management for the screen
3448	 * buffers (perhaps this is simpler).
3449	 */
3450	if (chars_chomped != 0 && next_col <= screen->max_col) {
3451	    static unsigned limit;
3452	    static Char *hibyte, *lobyte;
3453	    Bool both = False;
3454	    unsigned j, k;
3455
3456	    if (chars_chomped >= limit) {
3457		limit = (chars_chomped + 1) * 2;
3458		lobyte = (Char *) XtRealloc((char *) lobyte, limit);
3459		hibyte = (Char *) XtRealloc((char *) hibyte, limit);
3460	    }
3461	    for (j = offset, k = 0; j < offset + chars_chomped; j++) {
3462		if (buf[j] == HIDDEN_CHAR)
3463		    continue;
3464		lobyte[k] = LO_BYTE(buf[j]);
3465		if (buf[j] > 255) {
3466		    hibyte[k] = HI_BYTE(buf[j]);
3467		    both = True;
3468		} else {
3469		    hibyte[k] = 0;
3470		}
3471		++k;
3472	    }
3473
3474	    WriteText(xw, PAIRED_CHARS(lobyte,
3475				       (both ? hibyte : 0)),
3476		      k);
3477#ifdef NO_LEAKS
3478	    if (limit != 0) {
3479		limit = 0;
3480		XtFree((char *) lobyte);
3481		XtFree((char *) hibyte);
3482		lobyte = 0;
3483		hibyte = 0;
3484	    }
3485#endif
3486	}
3487	next_col += width_here;
3488	screen->do_wrap = need_wrap;
3489    }
3490#else /* ! OPT_WIDE_CHARS */
3491
3492    for (offset = 0; offset < len; offset += this_col) {
3493	last_col = CurMaxCol(screen, screen->cur_row);
3494	this_col = last_col - screen->cur_col + 1;
3495	if (this_col <= 1) {
3496	    if (screen->do_wrap) {
3497		screen->do_wrap = 0;
3498		if ((xw->flags & WRAPAROUND)) {
3499		    WrapLine(xw);
3500		}
3501	    }
3502	    this_col = 1;
3503	}
3504	if (offset + this_col > len) {
3505	    this_col = len - offset;
3506	}
3507	next_col = screen->cur_col + this_col;
3508
3509	WriteText(xw, PAIRED_CHARS(buf + offset,
3510				   buf2 ? buf2 + offset : 0),
3511		  (unsigned) this_col);
3512
3513	/*
3514	 * The call to WriteText updates screen->cur_col.
3515	 * If screen->cur_col is less than next_col, we must have
3516	 * hit the right margin - so set the do_wrap flag.
3517	 */
3518	screen->do_wrap = (screen->cur_col < next_col);
3519    }
3520
3521#endif /* OPT_WIDE_CHARS */
3522}
3523
3524#if OPT_WIDE_CHARS
3525unsigned
3526visual_width(PAIRED_CHARS(Char * str, Char * str2), Cardinal len)
3527{
3528    /* returns the visual width of a string (doublewide characters count
3529       as 2, normalwide characters count as 1) */
3530    int my_len = 0;
3531    while (len) {
3532	int ch = *str;
3533	if (str2)
3534	    ch |= *str2 << 8;
3535	if (str)
3536	    str++;
3537	if (str2)
3538	    str2++;
3539	if (iswide(ch))
3540	    my_len += 2;
3541	else
3542	    my_len++;
3543	len--;
3544    }
3545    return my_len;
3546}
3547#endif
3548
3549#if HANDLE_STRUCT_NOTIFY
3550/* Flag icon name with "***"  on window output when iconified.
3551 */
3552static void
3553HandleStructNotify(Widget w GCC_UNUSED,
3554		   XtPointer closure GCC_UNUSED,
3555		   XEvent * event,
3556		   Boolean * cont GCC_UNUSED)
3557{
3558    static char *icon_name;
3559    static Arg args[] =
3560    {
3561	{XtNiconName, (XtArgVal) & icon_name}
3562    };
3563    TScreen *screen = TScreenOf(term);
3564
3565    switch (event->type) {
3566    case MapNotify:
3567	TRACE(("HandleStructNotify(MapNotify)\n"));
3568#if OPT_ZICONBEEP
3569	if (screen->zIconBeep_flagged) {
3570	    screen->zIconBeep_flagged = False;
3571	    icon_name = NULL;
3572	    XtGetValues(toplevel, args, XtNumber(args));
3573	    if (icon_name != NULL) {
3574		char *buf = CastMallocN(char, strlen(icon_name));
3575		if (buf == NULL) {
3576		    screen->zIconBeep_flagged = True;
3577		    return;
3578		}
3579		strcpy(buf, icon_name + 4);
3580		ChangeIconName(buf);
3581		free(buf);
3582	    }
3583	}
3584#endif /* OPT_ZICONBEEP */
3585	mapstate = !IsUnmapped;
3586	break;
3587    case UnmapNotify:
3588	TRACE(("HandleStructNotify(UnmapNotify)\n"));
3589	mapstate = IsUnmapped;
3590	break;
3591    case ConfigureNotify:
3592	if (event->xconfigure.window == XtWindow(toplevel)) {
3593#if OPT_TOOLBAR
3594	    TRACE(("HandleStructNotify(ConfigureNotify)\n"));
3595	    /*
3596	     * The notification is for the top-level widget, but we care about
3597	     * vt100 (ignore the tek4014 window).
3598	     */
3599	    if (term->screen.Vshow) {
3600		VTwin *Vwin = WhichVWin(&(term->screen));
3601		TbInfo *info = &(Vwin->tb_info);
3602		TbInfo save = *info;
3603
3604		if (info->menu_bar) {
3605		    XtVaGetValues(info->menu_bar,
3606				  XtNheight, &info->menu_height,
3607				  XtNborderWidth, &info->menu_border,
3608				  (XtPointer) 0);
3609
3610		    if (save.menu_height != info->menu_height
3611			|| save.menu_border != info->menu_border) {
3612
3613			TRACE(("...menu_height %d\n", info->menu_height));
3614			TRACE(("...menu_border %d\n", info->menu_border));
3615			TRACE(("...had height  %d, border %d\n",
3616			       save.menu_height,
3617			       save.menu_border));
3618
3619			/*
3620			 * FIXME:  Window manager still may be using the old
3621			 * values.  Try to fool it.
3622			 */
3623			XtMakeResizeRequest((Widget) term,
3624					    screen->fullVwin.fullwidth,
3625					    info->menu_height
3626					    - save.menu_height
3627					    + screen->fullVwin.fullheight,
3628					    NULL, NULL);
3629			repairSizeHints();
3630		    }
3631		}
3632	    }
3633#else
3634	    int height, width;
3635
3636	    /*
3637	     * Some window managers modify the configuration during
3638	     * initialization.  Skip notification events that we know are
3639	     * obsolete because there is already another in the queue.
3640	     */
3641	    do {
3642		height = event->xconfigure.height;
3643		width = event->xconfigure.width;
3644		TRACE(("HandleStructNotify(ConfigureNotify) %dx%d\n",
3645		       event->xconfigure.height, event->xconfigure.width));
3646
3647	    } while (XCheckTypedWindowEvent(XtDisplay(term),
3648					    event->xconfigure.window,
3649					    ConfigureNotify, event));
3650
3651	    if (height != term->hints.height || width != term->hints.width)
3652		RequestResize(term, height, width, False);
3653#endif /* OPT_TOOLBAR */
3654	}
3655	break;
3656    case ReparentNotify:
3657	TRACE(("HandleStructNotify(ReparentNotify)\n"));
3658	break;
3659    default:
3660	TRACE(("HandleStructNotify(event %s)\n",
3661	       visibleEventType(event->type)));
3662	break;
3663    }
3664}
3665#endif /* HANDLE_STRUCT_NOTIFY */
3666
3667#if OPT_BLINK_CURS
3668static void
3669SetCursorBlink(TScreen * screen, int enable)
3670{
3671    screen->cursor_blink = enable;
3672    if (DoStartBlinking(screen)) {
3673	StartBlinking(screen);
3674    } else {
3675#if !OPT_BLINK_TEXT
3676	StopBlinking(screen);
3677#endif
3678    }
3679    update_cursorblink();
3680}
3681
3682void
3683ToggleCursorBlink(TScreen * screen)
3684{
3685    SetCursorBlink(screen, !(screen->cursor_blink));
3686}
3687#endif
3688
3689/*
3690 * process ANSI modes set, reset
3691 */
3692static void
3693ansi_modes(XtermWidget xw,
3694	   void (*func) (unsigned *p, unsigned mask))
3695{
3696    int i;
3697
3698    for (i = 0; i < nparam; ++i) {
3699	switch (param[i]) {
3700	case 2:		/* KAM (if set, keyboard locked */
3701	    (*func) (&xw->keyboard.flags, MODE_KAM);
3702	    break;
3703
3704	case 4:		/* IRM                          */
3705	    (*func) (&xw->flags, INSERT);
3706	    break;
3707
3708	case 12:		/* SRM (if set, local echo      */
3709	    (*func) (&xw->keyboard.flags, MODE_SRM);
3710	    break;
3711
3712	case 20:		/* LNM                          */
3713	    (*func) (&xw->flags, LINEFEED);
3714	    update_autolinefeed();
3715	    break;
3716	}
3717    }
3718}
3719
3720#define IsSM() (func == bitset)
3721
3722#define set_bool_mode(flag) \
3723	flag = (IsSM()) ? ON : OFF
3724
3725static void
3726really_set_mousemode(XtermWidget xw,
3727		     Bool enabled,
3728		     unsigned mode)
3729{
3730    xw->screen.send_mouse_pos = enabled ? mode : MOUSE_OFF;
3731    if (xw->screen.send_mouse_pos != MOUSE_OFF)
3732	xtermShowPointer(xw, True);
3733}
3734
3735#define set_mousemode(mode) really_set_mousemode(xw, IsSM(), mode)
3736
3737#if OPT_READLINE
3738#define set_mouseflag(f)		\
3739	(IsSM()				\
3740	 ? SCREEN_FLAG_set(screen, f)	\
3741	 : SCREEN_FLAG_unset(screen, f))
3742#endif
3743
3744/*
3745 * process DEC private modes set, reset
3746 */
3747static void
3748dpmodes(XtermWidget xw,
3749	void (*func) (unsigned *p, unsigned mask))
3750{
3751    TScreen *screen = &xw->screen;
3752    int i, j;
3753
3754    for (i = 0; i < nparam; ++i) {
3755	TRACE(("%s %d\n", IsSM()? "DECSET" : "DECRST", param[i]));
3756	switch (param[i]) {
3757	case 1:		/* DECCKM                       */
3758	    (*func) (&xw->keyboard.flags, MODE_DECCKM);
3759	    update_appcursor();
3760	    break;
3761	case 2:		/* DECANM - ANSI/VT52 mode      */
3762	    if (IsSM()) {	/* ANSI (VT100) */
3763		/*
3764		 * Setting DECANM should have no effect, since this function
3765		 * cannot be reached from vt52 mode.
3766		 */
3767		;
3768	    }
3769#if OPT_VT52_MODE
3770	    else if (screen->terminal_id >= 100) {	/* VT52 */
3771		TRACE(("DECANM terminal_id %d, vtXX_level %d\n",
3772		       screen->terminal_id,
3773		       screen->vtXX_level));
3774		screen->vt52_save_level = screen->vtXX_level;
3775		screen->vtXX_level = 0;
3776		screen->vt52_save_curgl = screen->curgl;
3777		screen->vt52_save_curgr = screen->curgr;
3778		screen->vt52_save_curss = screen->curss;
3779		memmove(screen->vt52_save_gsets, screen->gsets, sizeof(screen->gsets));
3780		resetCharsets(screen);
3781		nparam = 0;	/* ignore the remaining params, if any */
3782	    }
3783#endif
3784	    break;
3785	case 3:		/* DECCOLM                      */
3786	    if (screen->c132) {
3787		ClearScreen(xw);
3788		CursorSet(screen, 0, 0, xw->flags);
3789		if ((j = IsSM()? 132 : 80) !=
3790		    ((xw->flags & IN132COLUMNS) ? 132 : 80) ||
3791		    j != MaxCols(screen))
3792		    RequestResize(xw, -1, j, True);
3793		(*func) (&xw->flags, IN132COLUMNS);
3794	    }
3795	    break;
3796	case 4:		/* DECSCLM (slow scroll)        */
3797	    if (IsSM()) {
3798		screen->jumpscroll = 0;
3799		if (screen->scroll_amt)
3800		    FlushScroll(xw);
3801	    } else
3802		screen->jumpscroll = 1;
3803	    (*func) (&xw->flags, SMOOTHSCROLL);
3804	    update_jumpscroll();
3805	    break;
3806	case 5:		/* DECSCNM                      */
3807	    j = xw->flags;
3808	    (*func) (&xw->flags, REVERSE_VIDEO);
3809	    if ((xw->flags ^ j) & REVERSE_VIDEO)
3810		ReverseVideo(xw);
3811	    /* update_reversevideo done in RevVid */
3812	    break;
3813
3814	case 6:		/* DECOM                        */
3815	    (*func) (&xw->flags, ORIGIN);
3816	    CursorSet(screen, 0, 0, xw->flags);
3817	    break;
3818
3819	case 7:		/* DECAWM                       */
3820	    (*func) (&xw->flags, WRAPAROUND);
3821	    update_autowrap();
3822	    break;
3823	case 8:		/* DECARM                       */
3824	    /* ignore autorepeat
3825	     * XAutoRepeatOn() and XAutoRepeatOff() can do this, but only
3826	     * for the whole display - not limited to a given window.
3827	     */
3828	    break;
3829	case SET_X10_MOUSE:	/* MIT bogus sequence           */
3830	    MotionOff(screen, xw);
3831	    set_mousemode(X10_MOUSE);
3832	    break;
3833#if OPT_TOOLBAR
3834	case 10:		/* rxvt */
3835	    ShowToolbar(IsSM());
3836	    break;
3837#endif
3838#if OPT_BLINK_CURS
3839	case 12:		/* att610: Start/stop blinking cursor */
3840	    if (screen->cursor_blink_res) {
3841		set_bool_mode(screen->cursor_blink_esc);
3842		SetCursorBlink(screen, screen->cursor_blink);
3843	    }
3844	    break;
3845#endif
3846	case 18:		/* DECPFF: print form feed */
3847	    set_bool_mode(screen->printer_formfeed);
3848	    break;
3849	case 19:		/* DECPEX: print extent */
3850	    set_bool_mode(screen->printer_extent);
3851	    break;
3852	case 25:		/* DECTCEM: Show/hide cursor (VT200) */
3853	    set_bool_mode(screen->cursor_set);
3854	    break;
3855	case 30:		/* rxvt */
3856	    if (screen->fullVwin.sb_info.width != (IsSM()? ON : OFF))
3857		ToggleScrollBar(xw);
3858	    break;
3859#if OPT_SHIFT_FONTS
3860	case 35:		/* rxvt */
3861	    set_bool_mode(xw->misc.shift_fonts);
3862	    break;
3863#endif
3864	case 38:		/* DECTEK                       */
3865#if OPT_TEK4014
3866	    if (IsSM() && !(screen->inhibit & I_TEK)) {
3867		FlushLog(screen);
3868		TEK4014_ACTIVE(xw) = True;
3869	    }
3870#endif
3871	    break;
3872	case 40:		/* 132 column mode              */
3873	    set_bool_mode(screen->c132);
3874	    update_allow132();
3875	    break;
3876	case 41:		/* curses hack                  */
3877	    set_bool_mode(screen->curses);
3878	    update_cursesemul();
3879	    break;
3880	case 42:		/* DECNRCM national charset (VT220) */
3881	    (*func) (&xw->flags, NATIONAL);
3882	    break;
3883	case 44:		/* margin bell                  */
3884	    set_bool_mode(screen->marginbell);
3885	    if (!screen->marginbell)
3886		screen->bellarmed = -1;
3887	    update_marginbell();
3888	    break;
3889	case 45:		/* reverse wraparound   */
3890	    (*func) (&xw->flags, REVERSEWRAP);
3891	    update_reversewrap();
3892	    break;
3893#ifdef ALLOWLOGGING
3894	case 46:		/* logging              */
3895#ifdef ALLOWLOGFILEONOFF
3896	    /*
3897	     * if this feature is enabled, logging may be
3898	     * enabled and disabled via escape sequences.
3899	     */
3900	    if (IsSM())
3901		StartLog(screen);
3902	    else
3903		CloseLog(screen);
3904#else
3905	    Bell(XkbBI_Info, 0);
3906	    Bell(XkbBI_Info, 0);
3907#endif /* ALLOWLOGFILEONOFF */
3908	    break;
3909#endif
3910	case 1049:		/* alternate buffer & cursor */
3911	    if (!xw->misc.titeInhibit) {
3912		if (IsSM()) {
3913		    CursorSave(xw);
3914		    ToAlternate(xw);
3915		    ClearScreen(xw);
3916		} else {
3917		    FromAlternate(xw);
3918		    CursorRestore(xw);
3919		}
3920	    } else if (xw->misc.tiXtraScroll) {
3921		if (IsSM()) {
3922		    xtermScroll(xw, screen->max_row);
3923		}
3924	    }
3925	    break;
3926	case 1047:
3927	    /* FALLTHRU */
3928	case 47:		/* alternate buffer */
3929	    if (!xw->misc.titeInhibit) {
3930		if (IsSM()) {
3931		    ToAlternate(xw);
3932		} else {
3933		    if (screen->alternate
3934			&& (param[i] == 1047))
3935			ClearScreen(xw);
3936		    FromAlternate(xw);
3937		}
3938	    } else if (xw->misc.tiXtraScroll) {
3939		if (IsSM()) {
3940		    xtermScroll(xw, screen->max_row);
3941		}
3942	    }
3943	    break;
3944	case 66:		/* DECNKM */
3945	    (*func) (&xw->keyboard.flags, MODE_DECKPAM);
3946	    update_appkeypad();
3947	    break;
3948	case 67:		/* DECBKM */
3949	    /* back-arrow mapped to backspace or delete(D) */
3950	    (*func) (&xw->keyboard.flags, MODE_DECBKM);
3951	    TRACE(("DECSET DECBKM %s\n",
3952		   BtoS(xw->keyboard.flags & MODE_DECBKM)));
3953	    update_decbkm();
3954	    break;
3955	case SET_VT200_MOUSE:	/* xterm bogus sequence         */
3956	    MotionOff(screen, xw);
3957	    set_mousemode(VT200_MOUSE);
3958	    break;
3959	case SET_VT200_HIGHLIGHT_MOUSE:	/* xterm sequence w/hilite tracking */
3960	    MotionOff(screen, xw);
3961	    set_mousemode(VT200_HIGHLIGHT_MOUSE);
3962	    break;
3963	case SET_BTN_EVENT_MOUSE:
3964	    MotionOff(screen, xw);
3965	    set_mousemode(BTN_EVENT_MOUSE);
3966	    break;
3967	case SET_ANY_EVENT_MOUSE:
3968	    set_mousemode(ANY_EVENT_MOUSE);
3969	    if (screen->send_mouse_pos == MOUSE_OFF) {
3970		MotionOff(screen, xw);
3971	    } else {
3972		MotionOn(screen, xw);
3973	    }
3974	    break;
3975#if OPT_FOCUS_EVENT
3976	case SET_FOCUS_EVENT_MOUSE:
3977	    set_bool_mode(screen->send_focus_pos);
3978	    break;
3979#endif
3980	case 1010:		/* rxvt */
3981	    set_bool_mode(screen->scrollttyoutput);
3982	    update_scrollttyoutput();
3983	    break;
3984	case 1011:		/* rxvt */
3985	    set_bool_mode(screen->scrollkey);
3986	    update_scrollkey();
3987	    break;
3988	case 1034:
3989	    set_bool_mode(xw->screen.input_eight_bits);
3990	    update_alt_esc();
3991	    break;
3992#if OPT_NUM_LOCK
3993	case 1035:
3994	    set_bool_mode(xw->misc.real_NumLock);
3995	    update_num_lock();
3996	    break;
3997	case 1036:
3998	    set_bool_mode(screen->meta_sends_esc);
3999	    update_meta_esc();
4000	    break;
4001#endif
4002	case 1037:
4003	    set_bool_mode(screen->delete_is_del);
4004	    update_delete_del();
4005	    break;
4006#if OPT_NUM_LOCK
4007	case 1039:
4008	    set_bool_mode(screen->alt_sends_esc);
4009	    update_alt_esc();
4010	    break;
4011#endif
4012	case 1040:
4013	    set_bool_mode(screen->keepSelection);
4014	    update_keepSelection();
4015	    break;
4016	case 1041:
4017	    set_bool_mode(screen->selectToClipboard);
4018	    update_selectToClipboard();
4019	    break;
4020	case 1042:
4021	    set_bool_mode(screen->bellIsUrgent);
4022	    update_bellIsUrgent();
4023	    break;
4024	case 1043:
4025	    set_bool_mode(screen->poponbell);
4026	    update_poponbell();
4027	    break;
4028	case 1048:
4029	    if (!xw->misc.titeInhibit) {
4030		if (IsSM())
4031		    CursorSave(xw);
4032		else
4033		    CursorRestore(xw);
4034	    }
4035	    break;
4036#if OPT_TCAP_FKEYS
4037	case 1050:
4038	    set_keyboard_type(xw, keyboardIsTermcap, IsSM());
4039	    break;
4040#endif
4041#if OPT_SUN_FUNC_KEYS
4042	case 1051:
4043	    set_keyboard_type(xw, keyboardIsSun, IsSM());
4044	    break;
4045#endif
4046#if OPT_HP_FUNC_KEYS
4047	case 1052:
4048	    set_keyboard_type(xw, keyboardIsHP, IsSM());
4049	    break;
4050#endif
4051#if OPT_SCO_FUNC_KEYS
4052	case 1053:
4053	    set_keyboard_type(xw, keyboardIsSCO, IsSM());
4054	    break;
4055#endif
4056	case 1060:
4057	    set_keyboard_type(xw, keyboardIsLegacy, IsSM());
4058	    break;
4059#if OPT_SUNPC_KBD
4060	case 1061:
4061	    set_keyboard_type(xw, keyboardIsVT220, IsSM());
4062	    break;
4063#endif
4064#if OPT_READLINE
4065	case SET_BUTTON1_MOVE_POINT:
4066	    set_mouseflag(click1_moves);
4067	    break;
4068	case SET_BUTTON2_MOVE_POINT:
4069	    set_mouseflag(paste_moves);
4070	    break;
4071	case SET_DBUTTON3_DELETE:
4072	    set_mouseflag(dclick3_deletes);
4073	    break;
4074	case SET_PASTE_IN_BRACKET:
4075	    set_mouseflag(paste_brackets);
4076	    break;
4077	case SET_PASTE_QUOTE:
4078	    set_mouseflag(paste_quotes);
4079	    break;
4080	case SET_PASTE_LITERAL_NL:
4081	    set_mouseflag(paste_literal_nl);
4082	    break;
4083#endif /* OPT_READLINE */
4084	}
4085    }
4086}
4087
4088/*
4089 * process xterm private modes save
4090 */
4091static void
4092savemodes(XtermWidget xw)
4093{
4094    TScreen *screen = &xw->screen;
4095    int i;
4096
4097    for (i = 0; i < nparam; i++) {
4098	TRACE(("savemodes %d\n", param[i]));
4099	switch (param[i]) {
4100	case 1:		/* DECCKM                       */
4101	    DoSM(DP_DECCKM, xw->keyboard.flags & MODE_DECCKM);
4102	    break;
4103	case 3:		/* DECCOLM                      */
4104	    if (screen->c132)
4105		DoSM(DP_DECCOLM, xw->flags & IN132COLUMNS);
4106	    break;
4107	case 4:		/* DECSCLM (slow scroll)        */
4108	    DoSM(DP_DECSCLM, xw->flags & SMOOTHSCROLL);
4109	    break;
4110	case 5:		/* DECSCNM                      */
4111	    DoSM(DP_DECSCNM, xw->flags & REVERSE_VIDEO);
4112	    break;
4113	case 6:		/* DECOM                        */
4114	    DoSM(DP_DECOM, xw->flags & ORIGIN);
4115	    break;
4116	case 7:		/* DECAWM                       */
4117	    DoSM(DP_DECAWM, xw->flags & WRAPAROUND);
4118	    break;
4119	case 8:		/* DECARM                       */
4120	    /* ignore autorepeat */
4121	    break;
4122	case SET_X10_MOUSE:	/* mouse bogus sequence */
4123	    DoSM(DP_X_X10MSE, screen->send_mouse_pos);
4124	    break;
4125#if OPT_TOOLBAR
4126	case 10:		/* rxvt */
4127	    DoSM(DP_TOOLBAR, resource.toolBar);
4128	    break;
4129#endif
4130#if OPT_BLINK_CURS
4131	case 12:		/* att610: Start/stop blinking cursor */
4132	    if (screen->cursor_blink_res) {
4133		DoSM(DP_CRS_BLINK, screen->cursor_blink_esc);
4134	    }
4135	    break;
4136#endif
4137	case 18:		/* DECPFF: print form feed */
4138	    DoSM(DP_PRN_FORMFEED, screen->printer_formfeed);
4139	    break;
4140	case 19:		/* DECPEX: print extent */
4141	    DoSM(DP_PRN_EXTENT, screen->printer_extent);
4142	    break;
4143	case 25:		/* DECTCEM: Show/hide cursor (VT200) */
4144	    DoSM(DP_CRS_VISIBLE, screen->cursor_set);
4145	    break;
4146	case 40:		/* 132 column mode              */
4147	    DoSM(DP_X_DECCOLM, screen->c132);
4148	    break;
4149	case 41:		/* curses hack                  */
4150	    DoSM(DP_X_MORE, screen->curses);
4151	    break;
4152	case 42:		/* DECNRCM national charset (VT220) */
4153	    /* do nothing */
4154	    break;
4155	case 44:		/* margin bell                  */
4156	    DoSM(DP_X_MARGIN, screen->marginbell);
4157	    break;
4158	case 45:		/* reverse wraparound   */
4159	    DoSM(DP_X_REVWRAP, xw->flags & REVERSEWRAP);
4160	    break;
4161#ifdef ALLOWLOGGING
4162	case 46:		/* logging              */
4163	    DoSM(DP_X_LOGGING, screen->logging);
4164	    break;
4165#endif
4166	case 1047:		/* alternate buffer             */
4167	    /* FALLTHRU */
4168	case 47:		/* alternate buffer             */
4169	    DoSM(DP_X_ALTSCRN, screen->alternate);
4170	    break;
4171	case SET_VT200_MOUSE:	/* mouse bogus sequence         */
4172	case SET_VT200_HIGHLIGHT_MOUSE:
4173	case SET_BTN_EVENT_MOUSE:
4174	case SET_ANY_EVENT_MOUSE:
4175	    DoSM(DP_X_MOUSE, screen->send_mouse_pos);
4176	    break;
4177#if OPT_FOCUS_EVENT
4178	case SET_FOCUS_EVENT_MOUSE:
4179	    DoSM(DP_X_FOCUS, screen->send_focus_pos);
4180	    break;
4181#endif
4182	case 1048:
4183	    if (!xw->misc.titeInhibit) {
4184		CursorSave(xw);
4185	    }
4186	    break;
4187#if OPT_READLINE
4188	case SET_BUTTON1_MOVE_POINT:
4189	    SCREEN_FLAG_save(screen, click1_moves);
4190	    break;
4191	case SET_BUTTON2_MOVE_POINT:
4192	    SCREEN_FLAG_save(screen, paste_moves);
4193	    break;
4194	case SET_DBUTTON3_DELETE:
4195	    SCREEN_FLAG_save(screen, dclick3_deletes);
4196	    break;
4197	case SET_PASTE_IN_BRACKET:
4198	    SCREEN_FLAG_save(screen, paste_brackets);
4199	    break;
4200	case SET_PASTE_QUOTE:
4201	    SCREEN_FLAG_save(screen, paste_quotes);
4202	    break;
4203	case SET_PASTE_LITERAL_NL:
4204	    SCREEN_FLAG_save(screen, paste_literal_nl);
4205	    break;
4206#endif /* OPT_READLINE */
4207	}
4208    }
4209}
4210
4211/*
4212 * process xterm private modes restore
4213 */
4214static void
4215restoremodes(XtermWidget xw)
4216{
4217    TScreen *screen = &xw->screen;
4218    int i, j;
4219
4220    for (i = 0; i < nparam; i++) {
4221	TRACE(("restoremodes %d\n", param[i]));
4222	switch (param[i]) {
4223	case 1:		/* DECCKM                       */
4224	    bitcpy(&xw->keyboard.flags,
4225		   screen->save_modes[DP_DECCKM], MODE_DECCKM);
4226	    update_appcursor();
4227	    break;
4228	case 3:		/* DECCOLM                      */
4229	    if (screen->c132) {
4230		ClearScreen(xw);
4231		CursorSet(screen, 0, 0, xw->flags);
4232		if ((j = (screen->save_modes[DP_DECCOLM] & IN132COLUMNS)
4233		     ? 132 : 80) != ((xw->flags & IN132COLUMNS)
4234				     ? 132 : 80) || j != MaxCols(screen))
4235		    RequestResize(xw, -1, j, True);
4236		bitcpy(&xw->flags,
4237		       screen->save_modes[DP_DECCOLM],
4238		       IN132COLUMNS);
4239	    }
4240	    break;
4241	case 4:		/* DECSCLM (slow scroll)        */
4242	    if (screen->save_modes[DP_DECSCLM] & SMOOTHSCROLL) {
4243		screen->jumpscroll = 0;
4244		if (screen->scroll_amt)
4245		    FlushScroll(xw);
4246	    } else
4247		screen->jumpscroll = 1;
4248	    bitcpy(&xw->flags, screen->save_modes[DP_DECSCLM], SMOOTHSCROLL);
4249	    update_jumpscroll();
4250	    break;
4251	case 5:		/* DECSCNM                      */
4252	    if ((screen->save_modes[DP_DECSCNM] ^ xw->flags) & REVERSE_VIDEO) {
4253		bitcpy(&xw->flags, screen->save_modes[DP_DECSCNM], REVERSE_VIDEO);
4254		ReverseVideo(xw);
4255		/* update_reversevideo done in RevVid */
4256	    }
4257	    break;
4258	case 6:		/* DECOM                        */
4259	    bitcpy(&xw->flags, screen->save_modes[DP_DECOM], ORIGIN);
4260	    CursorSet(screen, 0, 0, xw->flags);
4261	    break;
4262
4263	case 7:		/* DECAWM                       */
4264	    bitcpy(&xw->flags, screen->save_modes[DP_DECAWM], WRAPAROUND);
4265	    update_autowrap();
4266	    break;
4267	case 8:		/* DECARM                       */
4268	    /* ignore autorepeat */
4269	    break;
4270	case SET_X10_MOUSE:	/* MIT bogus sequence           */
4271	    DoRM(DP_X_X10MSE, screen->send_mouse_pos);
4272	    break;
4273#if OPT_TOOLBAR
4274	case 10:		/* rxvt */
4275	    DoRM(DP_TOOLBAR, resource.toolBar);
4276	    ShowToolbar(resource.toolBar);
4277	    break;
4278#endif
4279#if OPT_BLINK_CURS
4280	case 12:		/* att610: Start/stop blinking cursor */
4281	    if (screen->cursor_blink_res) {
4282		DoRM(DP_CRS_BLINK, screen->cursor_blink_esc);
4283		SetCursorBlink(screen, screen->cursor_blink);
4284	    }
4285	    break;
4286#endif
4287	case 18:		/* DECPFF: print form feed */
4288	    DoRM(DP_PRN_FORMFEED, screen->printer_formfeed);
4289	    break;
4290	case 19:		/* DECPEX: print extent */
4291	    DoRM(DP_PRN_EXTENT, screen->printer_extent);
4292	    break;
4293	case 25:		/* DECTCEM: Show/hide cursor (VT200) */
4294	    DoRM(DP_CRS_VISIBLE, screen->cursor_set);
4295	    break;
4296	case 40:		/* 132 column mode              */
4297	    DoRM(DP_X_DECCOLM, screen->c132);
4298	    update_allow132();
4299	    break;
4300	case 41:		/* curses hack                  */
4301	    DoRM(DP_X_MORE, screen->curses);
4302	    update_cursesemul();
4303	    break;
4304	case 44:		/* margin bell                  */
4305	    if ((DoRM(DP_X_MARGIN, screen->marginbell)) == 0)
4306		screen->bellarmed = -1;
4307	    update_marginbell();
4308	    break;
4309	case 45:		/* reverse wraparound   */
4310	    bitcpy(&xw->flags, screen->save_modes[DP_X_REVWRAP], REVERSEWRAP);
4311	    update_reversewrap();
4312	    break;
4313#ifdef ALLOWLOGGING
4314	case 46:		/* logging              */
4315#ifdef ALLOWLOGFILEONOFF
4316	    if (screen->save_modes[DP_X_LOGGING])
4317		StartLog(screen);
4318	    else
4319		CloseLog(screen);
4320#endif /* ALLOWLOGFILEONOFF */
4321	    /* update_logging done by StartLog and CloseLog */
4322	    break;
4323#endif
4324	case 1047:		/* alternate buffer */
4325	    /* FALLTHRU */
4326	case 47:		/* alternate buffer */
4327	    if (!xw->misc.titeInhibit) {
4328		if (screen->save_modes[DP_X_ALTSCRN])
4329		    ToAlternate(xw);
4330		else
4331		    FromAlternate(xw);
4332		/* update_altscreen done by ToAlt and FromAlt */
4333	    } else if (xw->misc.tiXtraScroll) {
4334		if (screen->save_modes[DP_X_ALTSCRN]) {
4335		    xtermScroll(xw, screen->max_row);
4336		}
4337	    }
4338	    break;
4339	case SET_VT200_MOUSE:	/* mouse bogus sequence         */
4340	case SET_VT200_HIGHLIGHT_MOUSE:
4341	case SET_BTN_EVENT_MOUSE:
4342	case SET_ANY_EVENT_MOUSE:
4343	    DoRM(DP_X_MOUSE, screen->send_mouse_pos);
4344	    break;
4345#if OPT_FOCUS_EVENT
4346	case SET_FOCUS_EVENT_MOUSE:
4347	    DoRM(DP_X_FOCUS, screen->send_focus_pos);
4348	    break;
4349#endif
4350	case 1048:
4351	    if (!xw->misc.titeInhibit) {
4352		CursorRestore(xw);
4353	    }
4354	    break;
4355#if OPT_READLINE
4356	case SET_BUTTON1_MOVE_POINT:
4357	    SCREEN_FLAG_restore(screen, click1_moves);
4358	    break;
4359	case SET_BUTTON2_MOVE_POINT:
4360	    SCREEN_FLAG_restore(screen, paste_moves);
4361	    break;
4362	case SET_DBUTTON3_DELETE:
4363	    SCREEN_FLAG_restore(screen, dclick3_deletes);
4364	    break;
4365	case SET_PASTE_IN_BRACKET:
4366	    SCREEN_FLAG_restore(screen, paste_brackets);
4367	    break;
4368	case SET_PASTE_QUOTE:
4369	    SCREEN_FLAG_restore(screen, paste_quotes);
4370	    break;
4371	case SET_PASTE_LITERAL_NL:
4372	    SCREEN_FLAG_restore(screen, paste_literal_nl);
4373	    break;
4374#endif /* OPT_READLINE */
4375	}
4376    }
4377}
4378
4379/*
4380 * Report window label (icon or title) in dtterm protocol
4381 * ESC ] code label ESC backslash
4382 */
4383static void
4384report_win_label(XtermWidget xw,
4385		 int code,
4386		 XTextProperty * text,
4387		 Status ok)
4388{
4389    char **list;
4390    int length = 0;
4391
4392    reply.a_type = ANSI_ESC;
4393    unparseputc(xw, ANSI_ESC);
4394    unparseputc(xw, ']');
4395    unparseputc(xw, code);
4396
4397    if (ok) {
4398	if (XTextPropertyToStringList(text, &list, &length)) {
4399	    int n, c;
4400	    for (n = 0; n < length; n++) {
4401		char *s = list[n];
4402		while ((c = *s++) != '\0')
4403		    unparseputc(xw, c);
4404	    }
4405	    XFreeStringList(list);
4406	}
4407	if (text->value != 0)
4408	    XFree(text->value);
4409    }
4410
4411    unparseputc(xw, ANSI_ESC);
4412    unparseputc(xw, '\\');	/* should be ST */
4413    unparse_end(xw);
4414}
4415
4416/*
4417 * Window operations (from CDE dtterm description, as well as extensions).
4418 * See also "allowWindowOps" resource.
4419 */
4420static void
4421window_ops(XtermWidget xw)
4422{
4423    TScreen *screen = &xw->screen;
4424    XWindowChanges values;
4425    XWindowAttributes win_attrs;
4426    XTextProperty text;
4427    unsigned value_mask;
4428#if OPT_MAXIMIZE
4429    unsigned root_width;
4430    unsigned root_height;
4431#endif
4432
4433    TRACE(("window_ops %d\n", param[0]));
4434    switch (param[0]) {
4435    case 1:			/* Restore (de-iconify) window */
4436	XMapWindow(screen->display,
4437		   VShellWindow);
4438	break;
4439
4440    case 2:			/* Minimize (iconify) window */
4441	XIconifyWindow(screen->display,
4442		       VShellWindow,
4443		       DefaultScreen(screen->display));
4444	break;
4445
4446    case 3:			/* Move the window to the given position */
4447	values.x = param[1];
4448	values.y = param[2];
4449	value_mask = (CWX | CWY);
4450	XReconfigureWMWindow(screen->display,
4451			     VShellWindow,
4452			     DefaultScreen(screen->display),
4453			     value_mask,
4454			     &values);
4455	break;
4456
4457    case 4:			/* Resize the window to given size in pixels */
4458	RequestResize(xw, param[1], param[2], False);
4459	break;
4460
4461    case 5:			/* Raise the window to the front of the stack */
4462	XRaiseWindow(screen->display, VShellWindow);
4463	break;
4464
4465    case 6:			/* Lower the window to the bottom of the stack */
4466	XLowerWindow(screen->display, VShellWindow);
4467	break;
4468
4469    case 7:			/* Refresh the window */
4470	Redraw();
4471	break;
4472
4473    case 8:			/* Resize the text-area, in characters */
4474	RequestResize(xw, param[1], param[2], True);
4475	break;
4476
4477#if OPT_MAXIMIZE
4478    case 9:			/* Maximize or restore */
4479	RequestMaximize(xw, param[1]);
4480	break;
4481#endif
4482
4483    case 11:			/* Report the window's state */
4484	XGetWindowAttributes(screen->display,
4485			     VWindow(screen),
4486			     &win_attrs);
4487	reply.a_type = ANSI_CSI;
4488	reply.a_pintro = 0;
4489	reply.a_nparam = 1;
4490	reply.a_param[0] = (win_attrs.map_state == IsViewable) ? 1 : 2;
4491	reply.a_inters = 0;
4492	reply.a_final = 't';
4493	unparseseq(xw, &reply);
4494	break;
4495
4496    case 13:			/* Report the window's position */
4497	XGetWindowAttributes(screen->display,
4498			     WMFrameWindow(xw),
4499			     &win_attrs);
4500	reply.a_type = ANSI_CSI;
4501	reply.a_pintro = 0;
4502	reply.a_nparam = 3;
4503	reply.a_param[0] = 3;
4504	reply.a_param[1] = win_attrs.x;
4505	reply.a_param[2] = win_attrs.y;
4506	reply.a_inters = 0;
4507	reply.a_final = 't';
4508	unparseseq(xw, &reply);
4509	break;
4510
4511    case 14:			/* Report the window's size in pixels */
4512	XGetWindowAttributes(screen->display,
4513			     VWindow(screen),
4514			     &win_attrs);
4515	reply.a_type = ANSI_CSI;
4516	reply.a_pintro = 0;
4517	reply.a_nparam = 3;
4518	reply.a_param[0] = 4;
4519	/*FIXME: find if dtterm uses
4520	 *    win_attrs.height or Height
4521	 *      win_attrs.width  or Width
4522	 */
4523	reply.a_param[1] = Height(screen);
4524	reply.a_param[2] = Width(screen);
4525	reply.a_inters = 0;
4526	reply.a_final = 't';
4527	unparseseq(xw, &reply);
4528	break;
4529
4530    case 18:			/* Report the text's size in characters */
4531	reply.a_type = ANSI_CSI;
4532	reply.a_pintro = 0;
4533	reply.a_nparam = 3;
4534	reply.a_param[0] = 8;
4535	reply.a_param[1] = MaxRows(screen);
4536	reply.a_param[2] = MaxCols(screen);
4537	reply.a_inters = 0;
4538	reply.a_final = 't';
4539	unparseseq(xw, &reply);
4540	break;
4541
4542#if OPT_MAXIMIZE
4543    case 19:			/* Report the screen's size, in characters */
4544	if (!QueryMaximize(xw, &root_height, &root_width)) {
4545	    root_height = 0;
4546	    root_width = 0;
4547	}
4548	reply.a_type = ANSI_CSI;
4549	reply.a_pintro = 0;
4550	reply.a_nparam = 3;
4551	reply.a_param[0] = 9;
4552	reply.a_param[1] = root_height / FontHeight(screen);
4553	reply.a_param[2] = root_width / FontWidth(screen);
4554	reply.a_inters = 0;
4555	reply.a_final = 't';
4556	unparseseq(xw, &reply);
4557	break;
4558#endif
4559
4560    case 20:			/* Report the icon's label */
4561	report_win_label(xw, 'L', &text,
4562			 XGetWMIconName(screen->display, VShellWindow, &text));
4563	break;
4564
4565    case 21:			/* Report the window's title */
4566	report_win_label(xw, 'l', &text,
4567			 XGetWMName(screen->display, VShellWindow, &text));
4568	break;
4569
4570    default:			/* DECSLPP (24, 25, 36, 48, 72, 144) */
4571	if (param[0] >= 24)
4572	    RequestResize(xw, param[0], -1, True);
4573	break;
4574    }
4575}
4576
4577/*
4578 * set a bit in a word given a pointer to the word and a mask.
4579 */
4580static void
4581bitset(unsigned *p, unsigned mask)
4582{
4583    *p |= mask;
4584}
4585
4586/*
4587 * clear a bit in a word given a pointer to the word and a mask.
4588 */
4589static void
4590bitclr(unsigned *p, unsigned mask)
4591{
4592    *p &= ~mask;
4593}
4594
4595/*
4596 * Copy bits from one word to another, given a mask
4597 */
4598static void
4599bitcpy(unsigned *p, unsigned q, unsigned mask)
4600{
4601    bitclr(p, mask);
4602    bitset(p, q & mask);
4603}
4604
4605void
4606unparseputc1(XtermWidget xw, int c)
4607{
4608    if (c >= 0x80 && c <= 0x9F) {
4609	if (!xw->screen.control_eight_bits) {
4610	    unparseputc(xw, A2E(ANSI_ESC));
4611	    c = A2E(c - 0x40);
4612	}
4613    }
4614    unparseputc(xw, c);
4615}
4616
4617void
4618unparseseq(XtermWidget xw, ANSI * ap)
4619{
4620    int c;
4621    int i;
4622    int inters;
4623
4624    unparseputc1(xw, c = ap->a_type);
4625    if (c == ANSI_ESC
4626	|| c == ANSI_DCS
4627	|| c == ANSI_CSI
4628	|| c == ANSI_OSC
4629	|| c == ANSI_PM
4630	|| c == ANSI_APC
4631	|| c == ANSI_SS3) {
4632	if (ap->a_pintro != 0)
4633	    unparseputc(xw, ap->a_pintro);
4634	for (i = 0; i < ap->a_nparam; ++i) {
4635	    if (i != 0)
4636		unparseputc(xw, ';');
4637	    unparseputn(xw, (unsigned int) ap->a_param[i]);
4638	}
4639	if ((inters = ap->a_inters) != 0) {
4640	    for (i = 3; i >= 0; --i) {
4641		c = CharOf(inters >> (8 * i));
4642		if (c != 0)
4643		    unparseputc(xw, c);
4644	    }
4645	}
4646	unparseputc(xw, (char) ap->a_final);
4647    }
4648    unparse_end(xw);
4649}
4650
4651void
4652unparseputn(XtermWidget xw, unsigned int n)
4653{
4654    unsigned int q;
4655
4656    q = n / 10;
4657    if (q != 0)
4658	unparseputn(xw, q);
4659    unparseputc(xw, (char) ('0' + (n % 10)));
4660}
4661
4662void
4663unparseputs(XtermWidget xw, char *s)
4664{
4665    while (*s)
4666	unparseputc(xw, *s++);
4667}
4668
4669void
4670unparseputc(XtermWidget xw, int c)
4671{
4672    IChar *buf = xw->screen.unparse_bfr;
4673    unsigned len;
4674
4675    if ((xw->screen.unparse_len + 2) >= sizeof(xw->screen.unparse_bfr))
4676	unparse_end(xw);
4677
4678    len = xw->screen.unparse_len;
4679
4680#if OPT_TCAP_QUERY
4681    /*
4682     * If we're returning a termcap string, it has to be translated since
4683     * a DCS must not contain any characters except for the normal 7-bit
4684     * printable ASCII (counting tab, carriage return, etc).  For now,
4685     * just use hexadecimal for the whole thing.
4686     */
4687    if (xw->screen.tc_query_code >= 0) {
4688	char tmp[3];
4689	sprintf(tmp, "%02X", c & 0xFF);
4690	buf[len++] = tmp[0];
4691	buf[len++] = tmp[1];
4692    } else
4693#endif
4694    if ((buf[len++] = c) == '\r' && (xw->flags & LINEFEED)) {
4695	buf[len++] = '\n';
4696    }
4697
4698    xw->screen.unparse_len = len;
4699
4700    /* If send/receive mode is reset, we echo characters locally */
4701    if ((xw->keyboard.flags & MODE_SRM) == 0) {
4702	(void) doparsing(xw, (unsigned) c, &myState);
4703    }
4704}
4705
4706void
4707unparse_end(XtermWidget xw)
4708{
4709    if (xw->screen.unparse_len) {
4710#ifdef VMS
4711	tt_write(xw->screen.unparse_bfr, xw->screen.unparse_len);
4712#else /* VMS */
4713	writePtyData(xw->screen.respond, xw->screen.unparse_bfr, xw->screen.unparse_len);
4714#endif /* VMS */
4715	xw->screen.unparse_len = 0;
4716    }
4717}
4718
4719void
4720ToggleAlternate(XtermWidget xw)
4721{
4722    if (xw->screen.alternate)
4723	FromAlternate(xw);
4724    else
4725	ToAlternate(xw);
4726}
4727
4728static void
4729ToAlternate(XtermWidget xw)
4730{
4731    TScreen *screen = &(xw->screen);
4732
4733    if (!screen->alternate) {
4734	TRACE(("ToAlternate\n"));
4735	if (!screen->altbuf)
4736	    screen->altbuf = Allocate(MaxRows(screen), MaxCols(screen),
4737				      &screen->abuf_address);
4738	SwitchBufs(xw);
4739	screen->alternate = True;
4740	update_altscreen();
4741    }
4742}
4743
4744static void
4745FromAlternate(XtermWidget xw)
4746{
4747    TScreen *screen = &(xw->screen);
4748
4749    if (screen->alternate) {
4750	TRACE(("FromAlternate\n"));
4751	if (screen->scroll_amt)
4752	    FlushScroll(xw);
4753	screen->alternate = False;
4754	SwitchBufs(xw);
4755	update_altscreen();
4756    }
4757}
4758
4759static void
4760SwitchBufs(XtermWidget xw)
4761{
4762    TScreen *screen = &(xw->screen);
4763    int rows, top;
4764
4765    if (screen->cursor_state)
4766	HideCursor();
4767
4768    rows = MaxRows(screen);
4769    SwitchBufPtrs(screen);
4770
4771    if ((top = INX2ROW(screen, 0)) < rows) {
4772	if (screen->scroll_amt)
4773	    FlushScroll(xw);
4774	XClearArea(screen->display,
4775		   VWindow(screen),
4776		   (int) OriginX(screen),
4777		   (int) top * FontHeight(screen) + screen->border,
4778		   (unsigned) Width(screen),
4779		   (unsigned) (rows - top) * FontHeight(screen),
4780		   False);
4781    }
4782    ScrnUpdate(xw, 0, 0, rows, MaxCols(screen), False);
4783}
4784
4785Bool
4786CheckBufPtrs(TScreen * screen)
4787{
4788    return (screen->visbuf != 0
4789	    && screen->altbuf != 0);
4790}
4791
4792/*
4793 * Swap buffer line pointers between alternate and regular screens.
4794 * visbuf contains pointers from allbuf or altbuf for the visible screen,
4795 * and pointers from allbuf for the saved lines.  That makes it simple to
4796 * scroll back over the saved lines without juggling pointers for the
4797 * regular and alternate screens.
4798 */
4799void
4800SwitchBufPtrs(TScreen * screen)
4801{
4802    if (CheckBufPtrs(screen)) {
4803	size_t len = ScrnPointers(screen, (unsigned) MaxRows(screen));
4804
4805	memcpy((char *) screen->save_ptr, (char *) screen->visbuf, len);
4806	memcpy((char *) screen->visbuf, (char *) screen->altbuf, len);
4807	memcpy((char *) screen->altbuf, (char *) screen->save_ptr, len);
4808    }
4809}
4810
4811void
4812VTRun(void)
4813{
4814    TScreen *screen = TScreenOf(term);
4815
4816    TRACE(("VTRun ...\n"));
4817
4818    if (!screen->Vshow) {
4819	set_vt_visibility(True);
4820    }
4821    update_vttekmode();
4822    update_vtshow();
4823    update_tekshow();
4824    set_vthide_sensitivity();
4825
4826    if (screen->allbuf == NULL)
4827	VTallocbuf();
4828
4829    screen->cursor_state = OFF;
4830    screen->cursor_set = ON;
4831#if OPT_BLINK_CURS
4832    if (DoStartBlinking(screen))
4833	StartBlinking(screen);
4834#endif
4835
4836#if OPT_TEK4014
4837    if (Tpushb > Tpushback) {
4838	fillPtyData(screen, VTbuffer, (char *) Tpushback, Tpushb - Tpushback);
4839	Tpushb = Tpushback;
4840    }
4841#endif
4842    screen->is_running = True;
4843    if (!setjmp(VTend))
4844	VTparse(term);
4845    StopBlinking(screen);
4846    HideCursor();
4847    screen->cursor_set = OFF;
4848    TRACE(("... VTRun\n"));
4849}
4850
4851/*ARGSUSED*/
4852static void
4853VTExpose(Widget w GCC_UNUSED,
4854	 XEvent * event,
4855	 Region region GCC_UNUSED)
4856{
4857#ifdef DEBUG
4858    if (debug)
4859	fputs("Expose\n", stderr);
4860#endif /* DEBUG */
4861    if (event->type == Expose)
4862	HandleExposure(term, event);
4863}
4864
4865static void
4866VTGraphicsOrNoExpose(XEvent * event)
4867{
4868    TScreen *screen = TScreenOf(term);
4869    if (screen->incopy <= 0) {
4870	screen->incopy = 1;
4871	if (screen->scrolls > 0)
4872	    screen->scrolls--;
4873    }
4874    if (event->type == GraphicsExpose)
4875	if (HandleExposure(term, event))
4876	    screen->cursor_state = OFF;
4877    if ((event->type == NoExpose)
4878	|| ((XGraphicsExposeEvent *) event)->count == 0) {
4879	if (screen->incopy <= 0 && screen->scrolls > 0)
4880	    screen->scrolls--;
4881	if (screen->scrolls)
4882	    screen->incopy = -1;
4883	else
4884	    screen->incopy = 0;
4885    }
4886}
4887
4888/*ARGSUSED*/
4889static void
4890VTNonMaskableEvent(Widget w GCC_UNUSED,
4891		   XtPointer closure GCC_UNUSED,
4892		   XEvent * event,
4893		   Boolean * cont GCC_UNUSED)
4894{
4895    switch (event->type) {
4896    case GraphicsExpose:
4897    case NoExpose:
4898	VTGraphicsOrNoExpose(event);
4899	break;
4900    }
4901}
4902
4903static void
4904VTResize(Widget w)
4905{
4906    if (XtIsRealized(w)) {
4907	XtermWidget xw = (XtermWidget) w;
4908	ScreenResize(xw, xw->core.width, xw->core.height, &xw->flags);
4909    }
4910}
4911
4912#define okDimension(src,dst) ((src <= 32767) && ((dst = src) == src))
4913
4914static void
4915RequestResize(XtermWidget xw, int rows, int cols, Bool text)
4916{
4917    TScreen *screen = &xw->screen;
4918    unsigned long value;
4919    Dimension replyWidth, replyHeight;
4920    Dimension askedWidth, askedHeight;
4921    XtGeometryResult status;
4922    XWindowAttributes attrs;
4923
4924    TRACE(("RequestResize(rows=%d, cols=%d, text=%d)\n", rows, cols, text));
4925
4926    if ((askedWidth = cols) < cols
4927	|| (askedHeight = rows) < rows)
4928	return;
4929
4930    if (askedHeight == 0
4931	|| askedWidth == 0
4932	|| xw->misc.limit_resize > 0) {
4933	XGetWindowAttributes(XtDisplay(xw),
4934			     RootWindowOfScreen(XtScreen(xw)), &attrs);
4935    }
4936
4937    if (text) {
4938	if ((value = rows) != 0) {
4939	    if (rows < 0)
4940		value = MaxRows(screen);
4941	    value *= FontHeight(screen);
4942	    value += (2 * screen->border);
4943	    if (!okDimension(value, askedHeight))
4944		return;
4945	}
4946
4947	if ((value = cols) != 0) {
4948	    if (cols < 0)
4949		value = MaxCols(screen);
4950	    value *= FontWidth(screen);
4951	    value += (2 * screen->border) + ScrollbarWidth(screen);
4952	    if (!okDimension(value, askedWidth))
4953		return;
4954	}
4955
4956    } else {
4957	if (rows < 0)
4958	    askedHeight = FullHeight(screen);
4959	if (cols < 0)
4960	    askedWidth = FullWidth(screen);
4961    }
4962
4963    if (rows == 0)
4964	askedHeight = attrs.height;
4965    if (cols == 0)
4966	askedWidth = attrs.width;
4967
4968    if (xw->misc.limit_resize > 0) {
4969	Dimension high = xw->misc.limit_resize * attrs.height;
4970	Dimension wide = xw->misc.limit_resize * attrs.width;
4971	if (high < attrs.height)
4972	    high = attrs.height;
4973	if (askedHeight > high)
4974	    askedHeight = high;
4975	if (wide < attrs.width)
4976	    wide = attrs.width;
4977	if (askedWidth > wide)
4978	    askedWidth = wide;
4979    }
4980#ifndef nothack
4981    getXtermSizeHints(xw);
4982#endif
4983
4984    status = XtMakeResizeRequest((Widget) xw,
4985				 askedWidth, askedHeight,
4986				 &replyWidth, &replyHeight);
4987    TRACE(("...RequestResize XtMakeResizeRequest %dx%d -> %dx%d (status %d)\n",
4988	   askedHeight, askedWidth,
4989	   replyHeight, replyWidth,
4990	   status));
4991
4992    if (status == XtGeometryYes ||
4993	status == XtGeometryDone) {
4994	ScreenResize(xw, replyWidth, replyHeight, &xw->flags);
4995    }
4996#ifndef nothack
4997    /*
4998     * XtMakeResizeRequest() has the undesirable side-effect of clearing
4999     * the window manager's hints, even on a failed request.  This would
5000     * presumably be fixed if the shell did its own work.
5001     */
5002    if (xw->hints.flags
5003	&& replyHeight
5004	&& replyWidth) {
5005	xw->hints.height = replyHeight;
5006	xw->hints.width = replyWidth;
5007
5008	TRACE(("%s@%d -- ", __FILE__, __LINE__));
5009	TRACE_HINTS(&xw->hints);
5010	XSetWMNormalHints(screen->display, VShellWindow, &xw->hints);
5011	TRACE(("%s@%d -- ", __FILE__, __LINE__));
5012	TRACE_WM_HINTS(xw);
5013    }
5014#endif
5015
5016    XSync(screen->display, False);	/* synchronize */
5017    if (XtAppPending(app_con))
5018	xevents();
5019
5020    TRACE(("...RequestResize done\n"));
5021}
5022
5023static String xterm_trans =
5024"<ClientMessage>WM_PROTOCOLS: DeleteWindow()\n\
5025     <MappingNotify>: KeyboardMapping()\n";
5026
5027int
5028VTInit(void)
5029{
5030    TScreen *screen = TScreenOf(term);
5031    Widget vtparent = SHELL_OF(term);
5032
5033    TRACE(("VTInit {{\n"));
5034
5035    XtRealizeWidget(vtparent);
5036    XtOverrideTranslations(vtparent, XtParseTranslationTable(xterm_trans));
5037    (void) XSetWMProtocols(XtDisplay(vtparent), XtWindow(vtparent),
5038			   &wm_delete_window, 1);
5039    TRACE_TRANS("shell", vtparent);
5040    TRACE_TRANS("vt100", (Widget) (term));
5041
5042    if (screen->allbuf == NULL)
5043	VTallocbuf();
5044
5045    TRACE(("...}} VTInit\n"));
5046    return (1);
5047}
5048
5049static void
5050VTallocbuf(void)
5051{
5052    TScreen *screen = TScreenOf(term);
5053    int nrows = MaxRows(screen);
5054
5055    /* allocate screen buffer now, if necessary. */
5056    if (screen->scrollWidget)
5057	nrows += screen->savelines;
5058    screen->allbuf = Allocate(nrows, MaxCols(screen),
5059			      &screen->sbuf_address);
5060    if (screen->scrollWidget)
5061	screen->visbuf = &screen->allbuf[MAX_PTRS * screen->savelines];
5062    else
5063	screen->visbuf = screen->allbuf;
5064    return;
5065}
5066
5067static void
5068VTClassInit(void)
5069{
5070    XtAddConverter(XtRString, XtRGravity, XmuCvtStringToGravity,
5071		   (XtConvertArgList) NULL, (Cardinal) 0);
5072}
5073
5074/*
5075 * The whole wnew->screen struct is zeroed in VTInitialize.  Use these macros
5076 * where applicable for copying the pieces from the request widget into the
5077 * new widget.  We do not have to use them for wnew->misc, but the associated
5078 * traces are very useful for debugging.
5079 */
5080#if OPT_TRACE
5081#define init_Bres(name) \
5082	TRACE(("init " #name " = %s\n", \
5083		BtoS(wnew->name = request->name)))
5084#define init_Dres(name) \
5085	TRACE(("init " #name " = %f\n", \
5086		wnew->name = request->name))
5087#define init_Ires(name) \
5088	TRACE(("init " #name " = %d\n", \
5089		wnew->name = request->name))
5090#define init_Sres(name) \
5091	TRACE(("init " #name " = \"%s\"\n", \
5092		(wnew->name = x_strtrim(request->name)) != NULL \
5093			? wnew->name : "<null>"))
5094#define init_Tres(offset) \
5095	TRACE(("init screen.Tcolors[" #offset "] = %#lx\n", \
5096		fill_Tres(wnew, request, offset)))
5097#else
5098#define init_Bres(name) wnew->name = request->name
5099#define init_Dres(name) wnew->name = request->name
5100#define init_Ires(name) wnew->name = request->name
5101#define init_Sres(name) wnew->name = x_strtrim(request->name)
5102#define init_Tres(offset) fill_Tres(wnew, request, offset)
5103#endif
5104
5105#if OPT_COLOR_RES
5106/*
5107 * Override the use of XtDefaultForeground/XtDefaultBackground to make some
5108 * colors, such as cursor color, use the actual foreground/background value
5109 * if there is no explicit resource value used.
5110 */
5111static Pixel
5112fill_Tres(XtermWidget target, XtermWidget source, int offset)
5113{
5114    char *name;
5115    ScrnColors temp;
5116
5117    target->screen.Tcolors[offset] = source->screen.Tcolors[offset];
5118    target->screen.Tcolors[offset].mode = False;
5119
5120    if ((name = x_strtrim(target->screen.Tcolors[offset].resource)) != 0)
5121	target->screen.Tcolors[offset].resource = name;
5122
5123    if (name == 0) {
5124	target->screen.Tcolors[offset].value = target->dft_foreground;
5125    } else if (isDefaultForeground(name)) {
5126	target->screen.Tcolors[offset].value =
5127	    ((offset == TEXT_FG || offset == TEXT_BG)
5128	     ? target->dft_foreground
5129	     : target->screen.Tcolors[TEXT_FG].value);
5130    } else if (isDefaultBackground(name)) {
5131	target->screen.Tcolors[offset].value =
5132	    ((offset == TEXT_FG || offset == TEXT_BG)
5133	     ? target->dft_background
5134	     : target->screen.Tcolors[TEXT_BG].value);
5135    } else {
5136	memset(&temp, 0, sizeof(temp));
5137	if (AllocateTermColor(target, &temp, offset, name)) {
5138	    if (COLOR_DEFINED(&(temp), offset))
5139		free(temp.names[offset]);
5140	    target->screen.Tcolors[offset].value = temp.colors[offset];
5141	}
5142    }
5143    return target->screen.Tcolors[offset].value;
5144}
5145#else
5146#define fill_Tres(target, source, offset) \
5147	target->screen.Tcolors[offset] = source->screen.Tcolors[offset]
5148#endif
5149
5150#if OPT_WIDE_CHARS
5151static void
5152VTInitialize_locale(XtermWidget request)
5153{
5154    Bool is_utf8 = xtermEnvUTF8();
5155
5156    TRACE(("VTInitialize_locale\n"));
5157    TRACE(("... request screen.utf8_mode = %d\n", request->screen.utf8_mode));
5158
5159    if (request->screen.utf8_mode < 0)
5160	request->screen.utf8_mode = uFalse;
5161
5162    if (request->screen.utf8_mode > 3)
5163	request->screen.utf8_mode = uDefault;
5164
5165    request->screen.latin9_mode = 0;
5166    request->screen.unicode_font = 0;
5167#if OPT_LUIT_PROG
5168    request->misc.callfilter = 0;
5169    request->misc.use_encoding = 0;
5170
5171    TRACE(("... setup for luit:\n"));
5172    TRACE(("... request misc.locale_str = \"%s\"\n", request->misc.locale_str));
5173
5174    if (request->screen.utf8_mode == uFalse) {
5175	TRACE(("... command-line +u8 overrides\n"));
5176    } else
5177#if OPT_MINI_LUIT
5178    if (x_strcasecmp(request->misc.locale_str, "CHECKFONT") == 0) {
5179	int fl = (request->misc.default_font.f_n
5180		  ? strlen(request->misc.default_font.f_n)
5181		  : 0);
5182	if (fl > 11
5183	    && x_strcasecmp(request->misc.default_font.f_n + fl - 11,
5184			    "-ISO10646-1") == 0) {
5185	    request->screen.unicode_font = 1;
5186	    /* unicode font, use True */
5187#ifdef HAVE_LANGINFO_CODESET
5188	    if (!strcmp(xtermEnvEncoding(), "ANSI_X3.4-1968")
5189		|| !strcmp(xtermEnvEncoding(), "ISO-8859-1")) {
5190		if (request->screen.utf8_mode == uDefault)
5191		    request->screen.utf8_mode = uFalse;
5192	    } else if (!strcmp(xtermEnvEncoding(), "ISO-8859-15")) {
5193		if (request->screen.utf8_mode == uDefault)
5194		    request->screen.utf8_mode = uFalse;
5195		request->screen.latin9_mode = 1;
5196	    } else {
5197		request->misc.callfilter = is_utf8 ? 0 : 1;
5198		request->screen.utf8_mode = uAlways;
5199	    }
5200#else
5201	    request->misc.callfilter = is_utf8 ? 0 : 1;
5202	    request->screen.utf8_mode = uAlways;
5203#endif
5204	} else {
5205	    /* other encoding, use False */
5206	    if (request->screen.utf8_mode == uDefault) {
5207		request->screen.utf8_mode = is_utf8 ? uAlways : uFalse;
5208	    }
5209	}
5210    } else
5211#endif /* OPT_MINI_LUIT */
5212	if (x_strcasecmp(request->misc.locale_str, "TRUE") == 0 ||
5213	    x_strcasecmp(request->misc.locale_str, "ON") == 0 ||
5214	    x_strcasecmp(request->misc.locale_str, "YES") == 0 ||
5215	    x_strcasecmp(request->misc.locale_str, "AUTO") == 0 ||
5216	    strcmp(request->misc.locale_str, "1") == 0) {
5217	/* when true ... fully obeying LC_CTYPE locale */
5218	request->misc.callfilter = is_utf8 ? 0 : 1;
5219	request->screen.utf8_mode = uAlways;
5220    } else if (x_strcasecmp(request->misc.locale_str, "FALSE") == 0 ||
5221	       x_strcasecmp(request->misc.locale_str, "OFF") == 0 ||
5222	       x_strcasecmp(request->misc.locale_str, "NO") == 0 ||
5223	       strcmp(request->misc.locale_str, "0") == 0) {
5224	/* when false ... original value of utf8_mode is effective */
5225	if (request->screen.utf8_mode == uDefault) {
5226	    request->screen.utf8_mode = is_utf8 ? uAlways : uFalse;
5227	}
5228    } else if (x_strcasecmp(request->misc.locale_str, "MEDIUM") == 0 ||
5229	       x_strcasecmp(request->misc.locale_str, "SEMIAUTO") == 0) {
5230	/* when medium ... obeying locale only for UTF-8 and Asian */
5231	if (is_utf8) {
5232	    request->screen.utf8_mode = uAlways;
5233	} else if (
5234#ifdef MB_CUR_MAX
5235		      MB_CUR_MAX > 1 ||
5236#else
5237		      !strncmp(xtermEnvLocale(), "ja", 2) ||
5238		      !strncmp(xtermEnvLocale(), "ko", 2) ||
5239		      !strncmp(xtermEnvLocale(), "zh", 2) ||
5240#endif
5241		      !strncmp(xtermEnvLocale(), "th", 2) ||
5242		      !strncmp(xtermEnvLocale(), "vi", 2)) {
5243	    request->misc.callfilter = 1;
5244	    request->screen.utf8_mode = uAlways;
5245	} else {
5246	    request->screen.utf8_mode = uFalse;
5247	}
5248    } else if (x_strcasecmp(request->misc.locale_str, "UTF-8") == 0 ||
5249	       x_strcasecmp(request->misc.locale_str, "UTF8") == 0) {
5250	/* when UTF-8 ... UTF-8 mode */
5251	request->screen.utf8_mode = uAlways;
5252    } else {
5253	/* other words are regarded as encoding name passed to luit */
5254	request->misc.callfilter = 1;
5255	request->screen.utf8_mode = uAlways;
5256	request->misc.use_encoding = 1;
5257    }
5258    TRACE(("... updated misc.callfilter = %s\n", BtoS(request->misc.callfilter)));
5259    TRACE(("... updated misc.use_encoding = %s\n", BtoS(request->misc.use_encoding)));
5260#else
5261    if (request->screen.utf8_mode == uDefault) {
5262	request->screen.utf8_mode = is_utf8 ? uAlways : uFalse;
5263    }
5264#endif /* OPT_LUIT_PROG */
5265
5266    request->screen.utf8_inparse = (request->screen.utf8_mode != uFalse);
5267
5268    TRACE(("... updated screen.utf8_mode = %d\n", request->screen.utf8_mode));
5269    TRACE(("...VTInitialize_locale done\n"));
5270}
5271#endif
5272
5273static void
5274ParseOnClicks(XtermWidget wnew, XtermWidget wreq, Cardinal item)
5275{
5276    /* *INDENT-OFF* */
5277    static struct {
5278	const String	name;
5279	SelectUnit	code;
5280    } table[] = {
5281    	{ "char",	Select_CHAR },
5282    	{ "word",	Select_WORD },
5283    	{ "line",	Select_LINE },
5284    	{ "group",	Select_GROUP },
5285    	{ "page",	Select_PAGE },
5286    	{ "all",	Select_ALL },
5287#if OPT_SELECT_REGEX
5288    	{ "regex",	Select_REGEX },
5289#endif
5290    };
5291    /* *INDENT-ON* */
5292
5293    String res = wreq->screen.onClick[item];
5294    String next = x_skip_nonblanks(res);
5295    Cardinal n;
5296
5297    wnew->screen.selectMap[item] = NSELECTUNITS;
5298    for (n = 0; n < XtNumber(table); ++n) {
5299	if (!x_strncasecmp(table[n].name, res, (unsigned) (next - res))) {
5300	    wnew->screen.selectMap[item] = table[n].code;
5301#if OPT_SELECT_REGEX
5302	    if (table[n].code == Select_REGEX) {
5303		wnew->screen.selectExpr[item] = x_strtrim(next);
5304		TRACE(("Parsed regex \"%s\"\n", wnew->screen.selectExpr[item]));
5305	    }
5306#endif
5307	    break;
5308	}
5309    }
5310}
5311
5312/* ARGSUSED */
5313static void
5314VTInitialize(Widget wrequest,
5315	     Widget new_arg,
5316	     ArgList args GCC_UNUSED,
5317	     Cardinal *num_args GCC_UNUSED)
5318{
5319#define Kolor(name) wnew->screen.name.resource
5320#define TxtFg(name) !x_strcasecmp(Kolor(Tcolors[TEXT_FG]), Kolor(name))
5321#define TxtBg(name) !x_strcasecmp(Kolor(Tcolors[TEXT_BG]), Kolor(name))
5322#define DftFg(name) isDefaultForeground(Kolor(name))
5323#define DftBg(name) isDefaultBackground(Kolor(name))
5324
5325    XtermWidget request = (XtermWidget) wrequest;
5326    XtermWidget wnew = (XtermWidget) new_arg;
5327    Widget my_parent = SHELL_OF(wnew);
5328    int i;
5329    char *s;
5330
5331#if OPT_ISO_COLORS
5332    Bool color_ok;
5333#endif
5334
5335#if OPT_COLOR_RES2 && (MAXCOLORS > MIN_ANSI_COLORS)
5336    static XtResource fake_resources[] =
5337    {
5338#if OPT_256_COLORS
5339# include <256colres.h>
5340#elif OPT_88_COLORS
5341# include <88colres.h>
5342#endif
5343    };
5344#endif /* OPT_COLOR_RES2 */
5345
5346    TRACE(("VTInitialize\n"));
5347
5348    /* Zero out the entire "screen" component of "wnew" widget, then do
5349     * field-by-field assignment of "screen" fields that are named in the
5350     * resource list.
5351     */
5352    bzero((char *) &wnew->screen, sizeof(wnew->screen));
5353
5354    /* DESCO Sys#67660
5355     * Zero out the entire "keyboard" component of "wnew" widget.
5356     */
5357    bzero((char *) &wnew->keyboard, sizeof(wnew->keyboard));
5358
5359    /* dummy values so that we don't try to Realize the parent shell with height
5360     * or width of 0, which is illegal in X.  The real size is computed in the
5361     * xtermWidget's Realize proc, but the shell's Realize proc is called first,
5362     * and must see a valid size.
5363     */
5364    wnew->core.height = wnew->core.width = 1;
5365
5366    /*
5367     * The definition of -rv now is that it changes the definition of
5368     * XtDefaultForeground and XtDefaultBackground.  So, we no longer
5369     * need to do anything special.
5370     */
5371    wnew->screen.display = wnew->core.screen->display;
5372
5373    /*
5374     * We use the default foreground/background colors to compare/check if a
5375     * color-resource has been set.
5376     */
5377#define MyBlackPixel(dpy) BlackPixel(dpy,DefaultScreen(dpy))
5378#define MyWhitePixel(dpy) WhitePixel(dpy,DefaultScreen(dpy))
5379
5380    if (request->misc.re_verse) {
5381	wnew->dft_foreground = MyWhitePixel(wnew->screen.display);
5382	wnew->dft_background = MyBlackPixel(wnew->screen.display);
5383    } else {
5384	wnew->dft_foreground = MyBlackPixel(wnew->screen.display);
5385	wnew->dft_background = MyWhitePixel(wnew->screen.display);
5386    }
5387    init_Tres(TEXT_FG);
5388    init_Tres(TEXT_BG);
5389
5390    TRACE(("Color resource initialization:\n"));
5391    TRACE(("   Default foreground %#lx\n", wnew->dft_foreground));
5392    TRACE(("   Default background %#lx\n", wnew->dft_background));
5393    TRACE(("   Screen foreground  %#lx\n", T_COLOR(&(wnew->screen), TEXT_FG)));
5394    TRACE(("   Screen background  %#lx\n", T_COLOR(&(wnew->screen), TEXT_BG)));
5395
5396    wnew->screen.mouse_button = -1;
5397    wnew->screen.mouse_row = -1;
5398    wnew->screen.mouse_col = -1;
5399
5400#if OPT_BOX_CHARS
5401    init_Bres(screen.force_box_chars);
5402    init_Bres(screen.force_all_chars);
5403#endif
5404    init_Bres(screen.free_bold_box);
5405
5406    init_Bres(screen.c132);
5407    init_Bres(screen.curses);
5408    init_Bres(screen.hp_ll_bc);
5409#if OPT_XMC_GLITCH
5410    init_Ires(screen.xmc_glitch);
5411    init_Ires(screen.xmc_attributes);
5412    init_Bres(screen.xmc_inline);
5413    init_Bres(screen.move_sgr_ok);
5414#endif
5415#if OPT_BLINK_CURS
5416    init_Bres(screen.cursor_blink);
5417    init_Ires(screen.blink_on);
5418    init_Ires(screen.blink_off);
5419    wnew->screen.cursor_blink_res = wnew->screen.cursor_blink;
5420#endif
5421#if OPT_BLINK_TEXT
5422    init_Ires(screen.blink_as_bold);
5423#endif
5424    init_Ires(screen.border);
5425    init_Bres(screen.jumpscroll);
5426    init_Bres(screen.old_fkeys);
5427    init_Bres(screen.delete_is_del);
5428    wnew->keyboard.type = wnew->screen.old_fkeys
5429	? keyboardIsLegacy
5430	: keyboardIsDefault;
5431#ifdef ALLOWLOGGING
5432    init_Sres(screen.logfile);
5433#endif
5434    init_Bres(screen.bellIsUrgent);
5435    init_Bres(screen.bellOnReset);
5436    init_Bres(screen.marginbell);
5437    init_Bres(screen.multiscroll);
5438    init_Ires(screen.nmarginbell);
5439    init_Ires(screen.savelines);
5440    init_Ires(screen.scrollBarBorder);
5441    init_Ires(screen.scrolllines);
5442    init_Bres(screen.scrollttyoutput);
5443    init_Bres(screen.scrollkey);
5444
5445    init_Sres(screen.term_id);
5446    for (s = request->screen.term_id; *s; s++) {
5447	if (!isalpha(CharOf(*s)))
5448	    break;
5449    }
5450    wnew->screen.terminal_id = atoi(s);
5451    if (wnew->screen.terminal_id < MIN_DECID)
5452	wnew->screen.terminal_id = MIN_DECID;
5453    if (wnew->screen.terminal_id > MAX_DECID)
5454	wnew->screen.terminal_id = MAX_DECID;
5455    TRACE(("term_id '%s' -> terminal_id %d\n",
5456	   wnew->screen.term_id,
5457	   wnew->screen.terminal_id));
5458
5459    wnew->screen.vtXX_level = (wnew->screen.terminal_id / 100);
5460    init_Bres(screen.visualbell);
5461    init_Ires(screen.visualBellDelay);
5462    init_Bres(screen.poponbell);
5463    init_Ires(misc.limit_resize);
5464#if OPT_NUM_LOCK
5465    init_Bres(misc.real_NumLock);
5466    init_Bres(misc.alwaysUseMods);
5467    wnew->misc.num_lock = 0;
5468    wnew->misc.alt_mods = 0;
5469    wnew->misc.meta_mods = 0;
5470    wnew->misc.other_mods = 0;
5471#endif
5472#if OPT_SHIFT_FONTS
5473    init_Bres(misc.shift_fonts);
5474#endif
5475#if OPT_SUNPC_KBD
5476    init_Ires(misc.ctrl_fkeys);
5477#endif
5478#if OPT_TEK4014
5479    TEK4014_SHOWN(wnew) = False;	/* not a resource... */
5480    init_Bres(misc.tekInhibit);
5481    init_Bres(misc.tekSmall);
5482    init_Bres(misc.TekEmu);
5483#endif
5484#if OPT_TCAP_QUERY
5485    wnew->screen.tc_query_code = -1;
5486#endif
5487    wnew->misc.re_verse0 = request->misc.re_verse;
5488    init_Bres(misc.re_verse);
5489    init_Ires(screen.multiClickTime);
5490    init_Ires(screen.bellSuppressTime);
5491    init_Sres(screen.charClass);
5492
5493    init_Bres(screen.always_highlight);
5494    init_Bres(screen.brokenSelections);
5495    init_Bres(screen.cutNewline);
5496    init_Bres(screen.cutToBeginningOfLine);
5497    init_Bres(screen.highlight_selection);
5498    init_Bres(screen.i18nSelections);
5499    init_Bres(screen.keepSelection);
5500    init_Bres(screen.selectToClipboard);
5501    init_Bres(screen.trim_selection);
5502
5503    wnew->screen.pointer_cursor = request->screen.pointer_cursor;
5504    init_Ires(screen.pointer_mode);
5505
5506    init_Sres(screen.answer_back);
5507
5508    init_Sres(screen.printer_command);
5509    init_Bres(screen.printer_autoclose);
5510    init_Bres(screen.printer_extent);
5511    init_Bres(screen.printer_formfeed);
5512    init_Ires(screen.printer_controlmode);
5513#if OPT_PRINT_COLORS
5514    init_Ires(screen.print_attributes);
5515#endif
5516
5517    init_Sres(screen.keyboard_dialect);
5518
5519    init_Bres(screen.input_eight_bits);
5520    init_Bres(screen.output_eight_bits);
5521    init_Bres(screen.control_eight_bits);
5522    init_Bres(screen.backarrow_key);
5523    init_Bres(screen.alt_is_not_meta);
5524    init_Bres(screen.alt_sends_esc);
5525    init_Bres(screen.meta_sends_esc);
5526
5527    init_Bres(screen.allowSendEvent0);
5528    init_Bres(screen.allowTitleOp0);
5529    init_Bres(screen.allowWindowOp0);
5530
5531    /* make a copy so that editres cannot change the resource after startup */
5532    wnew->screen.allowSendEvents = wnew->screen.allowSendEvent0;
5533    wnew->screen.allowTitleOps = wnew->screen.allowTitleOp0;
5534    wnew->screen.allowWindowOps = wnew->screen.allowWindowOp0;
5535
5536    init_Bres(screen.quiet_grab);
5537
5538#ifndef NO_ACTIVE_ICON
5539    wnew->screen.fnt_icon.fs = request->screen.fnt_icon.fs;
5540    init_Bres(misc.active_icon);
5541    init_Ires(misc.icon_border_width);
5542    wnew->misc.icon_border_pixel = request->misc.icon_border_pixel;
5543#endif /* NO_ACTIVE_ICON */
5544    init_Bres(misc.titeInhibit);
5545    init_Bres(misc.tiXtraScroll);
5546    init_Bres(misc.dynamicColors);
5547    for (i = fontMenu_font1; i <= fontMenu_lastBuiltin; i++) {
5548	init_Sres(screen.MenuFontName(i));
5549    }
5550    wnew->screen.MenuFontName(fontMenu_default) = wnew->misc.default_font.f_n;
5551    wnew->screen.MenuFontName(fontMenu_fontescape) = NULL;
5552    wnew->screen.MenuFontName(fontMenu_fontsel) = NULL;
5553
5554    wnew->screen.menu_font_number = fontMenu_default;
5555    init_Sres(screen.initial_font);
5556    if (wnew->screen.initial_font != 0) {
5557	int result = xtermGetFont(wnew->screen.initial_font);
5558	if (result >= 0)
5559	    wnew->screen.menu_font_number = result;
5560    }
5561#if OPT_BROKEN_OSC
5562    init_Bres(screen.brokenLinuxOSC);
5563#endif
5564
5565#if OPT_BROKEN_ST
5566    init_Bres(screen.brokenStringTerm);
5567#endif
5568
5569#if OPT_C1_PRINT
5570    init_Bres(screen.c1_printable);
5571#endif
5572
5573#if OPT_CLIP_BOLD
5574    init_Bres(screen.use_clipping);
5575#endif
5576
5577#if OPT_DEC_CHRSET
5578    init_Bres(screen.font_doublesize);
5579    init_Ires(screen.cache_doublesize);
5580    if (wnew->screen.cache_doublesize > NUM_CHRSET)
5581	wnew->screen.cache_doublesize = NUM_CHRSET;
5582    if (wnew->screen.cache_doublesize == 0)
5583	wnew->screen.font_doublesize = False;
5584    TRACE(("Doublesize%s enabled, up to %d fonts\n",
5585	   wnew->screen.font_doublesize ? "" : " not",
5586	   wnew->screen.cache_doublesize));
5587#endif
5588
5589#if OPT_WIDE_CHARS
5590    wnew->num_ptrs = (OFF_CHARS + 1);	/* minimum needed for cell */
5591#endif
5592#if OPT_ISO_COLORS
5593    init_Ires(screen.veryBoldColors);
5594    init_Bres(screen.boldColors);
5595    init_Bres(screen.colorAttrMode);
5596    init_Bres(screen.colorBDMode);
5597    init_Bres(screen.colorBLMode);
5598    init_Bres(screen.colorMode);
5599    init_Bres(screen.colorULMode);
5600    init_Bres(screen.italicULMode);
5601    init_Bres(screen.colorRVMode);
5602
5603    for (i = 0, color_ok = False; i < MAXCOLORS; i++) {
5604
5605#if OPT_COLOR_RES2 && (MAXCOLORS > MIN_ANSI_COLORS)
5606	/*
5607	 * Xt has a hardcoded limit on the maximum number of resources that can
5608	 * be used in a widget.  If we configure both luit (which implies
5609	 * wide-characters) and 256-colors, it goes over that limit.  Most
5610	 * people would not need a resource-file with 256-colors; the default
5611	 * values in our table are sufficient.  In that case, fake the resource
5612	 * setting by copying the default value from the table.  The #define's
5613	 * can be overridden to make these true resources.
5614	 */
5615	if (i >= MIN_ANSI_COLORS && i < NUM_ANSI_COLORS) {
5616	    wnew->screen.Acolors[i].resource
5617		= ((char *) fake_resources[i - MIN_ANSI_COLORS].default_addr);
5618	    if (wnew->screen.Acolors[i].resource == 0)
5619		wnew->screen.Acolors[i].resource = XtDefaultForeground;
5620	} else
5621#endif /* OPT_COLOR_RES2 */
5622	    wnew->screen.Acolors[i] = request->screen.Acolors[i];
5623
5624#if OPT_COLOR_RES
5625	TRACE(("Acolors[%d] = %s\n", i, wnew->screen.Acolors[i].resource));
5626	wnew->screen.Acolors[i].mode = False;
5627	if (DftFg(Acolors[i])) {
5628	    wnew->screen.Acolors[i].value = T_COLOR(&(wnew->screen), TEXT_FG);
5629	    wnew->screen.Acolors[i].mode = True;
5630	} else if (DftBg(Acolors[i])) {
5631	    wnew->screen.Acolors[i].value = T_COLOR(&(wnew->screen), TEXT_BG);
5632	    wnew->screen.Acolors[i].mode = True;
5633	} else {
5634	    color_ok = True;
5635	}
5636#else
5637	TRACE(("Acolors[%d] = %#lx\n", i, request->screen.Acolors[i]));
5638	if (wnew->screen.Acolors[i] != wnew->dft_foreground &&
5639	    wnew->screen.Acolors[i] != T_COLOR(&(wnew->screen), TEXT_FG) &&
5640	    wnew->screen.Acolors[i] != T_COLOR(&(wnew->screen), TEXT_BG))
5641	    color_ok = True;
5642#endif
5643    }
5644
5645    /*
5646     * Check if we're trying to use color in a monochrome screen.  Disable
5647     * color in that case, since that would make ANSI colors unusable.  A 4-bit
5648     * or 8-bit display is usable, so we do not have to check for anything more
5649     * specific.
5650     */
5651    if (color_ok) {
5652	Display *display = wnew->screen.display;
5653	XVisualInfo myTemplate, *visInfoPtr;
5654	int numFound;
5655
5656	myTemplate.visualid = XVisualIDFromVisual(DefaultVisual(display,
5657								XDefaultScreen(display)));
5658	visInfoPtr = XGetVisualInfo(display, (long) VisualIDMask,
5659				    &myTemplate, &numFound);
5660	if (visInfoPtr == 0
5661	    || numFound == 0
5662	    || visInfoPtr->depth <= 1) {
5663	    TRACE(("disabling color since screen is monochrome\n"));
5664	    color_ok = False;
5665	} else {
5666	    XFree(visInfoPtr);
5667	}
5668    }
5669
5670    /* If none of the colors are anything other than the foreground or
5671     * background, we'll assume this isn't color, no matter what the colorMode
5672     * resource says.  (There doesn't seem to be any good way to determine if
5673     * the resource lookup failed versus the user having misconfigured this).
5674     */
5675    if (!color_ok) {
5676	wnew->screen.colorMode = False;
5677	TRACE(("All colors are foreground or background: disable colorMode\n"));
5678    }
5679    wnew->sgr_foreground = -1;
5680    wnew->sgr_background = -1;
5681    wnew->sgr_extended = False;
5682#endif /* OPT_ISO_COLORS */
5683
5684    /*
5685     * Decode the resources that control the behavior on multiple mouse clicks.
5686     * A single click is always bound to normal character selection, but the
5687     * other flavors can be changed.
5688     */
5689    for (i = 0; i < NSELECTUNITS; ++i) {
5690	int ck = (i + 1);
5691	wnew->screen.maxClicks = ck;
5692	if (i == Select_CHAR)
5693	    wnew->screen.selectMap[i] = Select_CHAR;
5694	else if (request->screen.onClick[i] != 0)
5695	    ParseOnClicks(wnew, request, (unsigned) i);
5696	else if (i <= Select_LINE)
5697	    wnew->screen.selectMap[i] = (SelectUnit) i;
5698	else
5699	    break;
5700	TRACE(("on%dClicks %s=%d\n", ck,
5701	       NonNull(request->screen.onClick[i]),
5702	       wnew->screen.selectMap[i]));
5703	if (wnew->screen.selectMap[i] == NSELECTUNITS)
5704	    break;
5705    }
5706    TRACE(("maxClicks %d\n", wnew->screen.maxClicks));
5707
5708    init_Tres(MOUSE_FG);
5709    init_Tres(MOUSE_BG);
5710    init_Tres(TEXT_CURSOR);
5711#if OPT_HIGHLIGHT_COLOR
5712    init_Tres(HIGHLIGHT_BG);
5713    init_Tres(HIGHLIGHT_FG);
5714    init_Bres(screen.hilite_reverse);
5715    init_Bres(screen.hilite_color);
5716    if (wnew->screen.hilite_color == Maybe) {
5717	wnew->screen.hilite_color = False;
5718#if OPT_COLOR_RES
5719	/*
5720	 * If the highlight text/background are both set, and if they are
5721	 * not equal to either the text/background or background/text, then
5722	 * set the highlightColorMode automatically.
5723	 */
5724	if (!DftFg(Tcolors[HIGHLIGHT_BG])
5725	    && !DftBg(Tcolors[HIGHLIGHT_FG])
5726	    && !TxtFg(Tcolors[HIGHLIGHT_BG])
5727	    && !TxtBg(Tcolors[HIGHLIGHT_FG])
5728	    && !TxtBg(Tcolors[HIGHLIGHT_BG])
5729	    && !TxtFg(Tcolors[HIGHLIGHT_FG])) {
5730	    TRACE(("...setting hilite_color automatically\n"));
5731	    wnew->screen.hilite_color = True;
5732	}
5733#endif
5734    }
5735#endif
5736
5737#if OPT_TEK4014
5738    /*
5739     * The Tek4014 window has no separate resources for foreground, background
5740     * and cursor color.  Since xterm always creates the vt100 widget first, we
5741     * can set the Tektronix colors here.  That lets us use escape sequences to
5742     * set its dynamic colors and get consistent behavior whether or not the
5743     * window is displayed.
5744     */
5745    T_COLOR(&(wnew->screen), TEK_BG) = T_COLOR(&(wnew->screen), TEXT_BG);
5746    T_COLOR(&(wnew->screen), TEK_FG) = T_COLOR(&(wnew->screen), TEXT_FG);
5747    T_COLOR(&(wnew->screen), TEK_CURSOR) = T_COLOR(&(wnew->screen), TEXT_CURSOR);
5748#endif
5749
5750#if OPT_WIDE_CHARS
5751    VTInitialize_locale(request);
5752    init_Bres(screen.utf8_latin1);
5753    init_Bres(screen.utf8_title);
5754
5755#if OPT_LUIT_PROG
5756    init_Bres(misc.callfilter);
5757    init_Bres(misc.use_encoding);
5758    init_Sres(misc.locale_str);
5759    init_Sres(misc.localefilter);
5760#endif
5761
5762#if OPT_RENDERFONT
5763    for (i = 0; i <= fontMenu_lastBuiltin; ++i) {
5764	init_Dres(misc.face_size[i]);
5765    }
5766    init_Sres(misc.face_name);
5767    init_Sres(misc.face_wide_name);
5768    init_Bres(misc.render_font);
5769    /* minor tweak to make debug traces consistent: */
5770    if (wnew->misc.render_font) {
5771	if (wnew->misc.face_name == 0) {
5772	    wnew->misc.render_font = False;
5773	    TRACE(("reset render_font since there is no face_name\n"));
5774	}
5775    }
5776#endif
5777
5778    init_Ires(screen.utf8_inparse);
5779    init_Ires(screen.utf8_mode);
5780    init_Ires(screen.max_combining);
5781
5782    if (wnew->screen.max_combining < 0) {
5783	wnew->screen.max_combining = 0;
5784    }
5785    if (wnew->screen.max_combining > 5) {
5786	wnew->screen.max_combining = 5;
5787    }
5788
5789    init_Bres(screen.vt100_graphics);
5790    init_Bres(screen.wide_chars);
5791    init_Bres(misc.mk_width);
5792    init_Bres(misc.cjk_width);
5793
5794    init_Ires(misc.mk_samplesize);
5795    init_Ires(misc.mk_samplepass);
5796
5797    if (wnew->misc.mk_samplesize > 0xffff)
5798	wnew->misc.mk_samplesize = 0xffff;
5799    if (wnew->misc.mk_samplesize < 0)
5800	wnew->misc.mk_samplesize = 0;
5801
5802    if (wnew->misc.mk_samplepass > wnew->misc.mk_samplesize)
5803	wnew->misc.mk_samplepass = wnew->misc.mk_samplesize;
5804    if (wnew->misc.mk_samplepass < 0)
5805	wnew->misc.mk_samplepass = 0;
5806
5807    if (request->screen.utf8_mode) {
5808	TRACE(("setting wide_chars on\n"));
5809	wnew->screen.wide_chars = True;
5810    } else {
5811	TRACE(("setting utf8_mode to 0\n"));
5812	wnew->screen.utf8_mode = uFalse;
5813    }
5814    TRACE(("initialized UTF-8 mode to %d\n", wnew->screen.utf8_mode));
5815
5816#if OPT_MINI_LUIT
5817    if (request->screen.latin9_mode) {
5818	wnew->screen.latin9_mode = True;
5819    }
5820    if (request->screen.unicode_font) {
5821	wnew->screen.unicode_font = True;
5822    }
5823    TRACE(("initialized Latin9 mode to %d\n", wnew->screen.latin9_mode));
5824    TRACE(("initialized unicode_font to %d\n", wnew->screen.unicode_font));
5825#endif
5826
5827    if (wnew->screen.wide_chars != False)
5828	wnew->num_ptrs = OFF_FINAL + (wnew->screen.max_combining * 2);
5829
5830    decode_wcwidth((wnew->misc.cjk_width ? 2 : 0)
5831		   + (wnew->misc.mk_width ? 1 : 0)
5832		   + 1,
5833		   wnew->misc.mk_samplesize,
5834		   wnew->misc.mk_samplepass);
5835#endif /* OPT_WIDE_CHARS */
5836
5837    init_Bres(screen.always_bold_mode);
5838    init_Bres(screen.bold_mode);
5839    init_Bres(screen.underline);
5840
5841    wnew->cur_foreground = 0;
5842    wnew->cur_background = 0;
5843
5844    wnew->keyboard.flags = MODE_SRM;
5845    if (wnew->screen.backarrow_key)
5846	wnew->keyboard.flags |= MODE_DECBKM;
5847    TRACE(("initialized DECBKM %s\n",
5848	   BtoS(wnew->keyboard.flags & MODE_DECBKM)));
5849
5850    /* look for focus related events on the shell, because we need
5851     * to care about the shell's border being part of our focus.
5852     */
5853    XtAddEventHandler(my_parent, EnterWindowMask, False,
5854		      HandleEnterWindow, (Opaque) NULL);
5855    XtAddEventHandler(my_parent, LeaveWindowMask, False,
5856		      HandleLeaveWindow, (Opaque) NULL);
5857    XtAddEventHandler(my_parent, FocusChangeMask, False,
5858		      HandleFocusChange, (Opaque) NULL);
5859    XtAddEventHandler((Widget) wnew, 0L, True,
5860		      VTNonMaskableEvent, (Opaque) NULL);
5861    XtAddEventHandler((Widget) wnew, PropertyChangeMask, False,
5862		      HandleBellPropertyChange, (Opaque) NULL);
5863
5864#if HANDLE_STRUCT_NOTIFY
5865#if OPT_TOOLBAR
5866    wnew->VT100_TB_INFO(menu_bar) = request->VT100_TB_INFO(menu_bar);
5867    init_Ires(VT100_TB_INFO(menu_height));
5868#else
5869    /* Flag icon name with "***"  on window output when iconified.
5870     * Put in a handler that will tell us when we get Map/Unmap events.
5871     */
5872    if (resource.zIconBeep)
5873#endif
5874	XtAddEventHandler(my_parent, StructureNotifyMask, False,
5875			  HandleStructNotify, (Opaque) 0);
5876#endif /* HANDLE_STRUCT_NOTIFY */
5877
5878    wnew->screen.bellInProgress = False;
5879
5880    set_character_class(wnew->screen.charClass);
5881
5882    /* create it, but don't realize it */
5883    ScrollBarOn(wnew, True, False);
5884
5885    /* make sure that the resize gravity acceptable */
5886    if (wnew->misc.resizeGravity != NorthWestGravity &&
5887	wnew->misc.resizeGravity != SouthWestGravity) {
5888	char value[80];
5889	char *temp[2];
5890	Cardinal nparams = 1;
5891
5892	sprintf(temp[0] = value, "%d", wnew->misc.resizeGravity);
5893	temp[1] = 0;
5894	XtAppWarningMsg(app_con, "rangeError", "resizeGravity", "XTermError",
5895			"unsupported resizeGravity resource value (%s)",
5896			temp, &nparams);
5897	wnew->misc.resizeGravity = SouthWestGravity;
5898    }
5899#ifndef NO_ACTIVE_ICON
5900    wnew->screen.whichVwin = &wnew->screen.fullVwin;
5901#endif /* NO_ACTIVE_ICON */
5902
5903    if (wnew->screen.savelines < 0)
5904	wnew->screen.savelines = 0;
5905
5906    init_Bres(screen.awaitInput);
5907
5908    wnew->flags = 0;
5909    if (!wnew->screen.jumpscroll)
5910	wnew->flags |= SMOOTHSCROLL;
5911    if (wnew->misc.reverseWrap)
5912	wnew->flags |= REVERSEWRAP;
5913    if (wnew->misc.autoWrap)
5914	wnew->flags |= WRAPAROUND;
5915    if (wnew->misc.re_verse != wnew->misc.re_verse0)
5916	wnew->flags |= REVERSE_VIDEO;
5917    if (wnew->screen.c132)
5918	wnew->flags |= IN132COLUMNS;
5919
5920    wnew->initflags = wnew->flags;
5921
5922#if OPT_MOD_FKEYS
5923    init_Ires(keyboard.modify_1st.cursor_keys);
5924    init_Ires(keyboard.modify_1st.function_keys);
5925    init_Ires(keyboard.modify_1st.keypad_keys);
5926    init_Ires(keyboard.modify_1st.other_keys);
5927    init_Ires(keyboard.modify_1st.string_keys);
5928    init_Ires(keyboard.format_keys);
5929    wnew->keyboard.modify_now = wnew->keyboard.modify_1st;
5930#endif
5931
5932    init_Ires(misc.appcursorDefault);
5933    if (wnew->misc.appcursorDefault)
5934	wnew->keyboard.flags |= MODE_DECCKM;
5935
5936    init_Ires(misc.appkeypadDefault);
5937    if (wnew->misc.appkeypadDefault)
5938	wnew->keyboard.flags |= MODE_DECKPAM;
5939
5940    return;
5941}
5942
5943void
5944releaseCursorGCs(XtermWidget xw)
5945{
5946    TScreen *screen = &xw->screen;
5947    VTwin *win = WhichVWin(screen);
5948    int n;
5949
5950    for_each_curs_gc(n) {
5951	freeCgs(xw, win, (CgsEnum) n);
5952    }
5953}
5954
5955void
5956releaseWindowGCs(XtermWidget xw, VTwin * win)
5957{
5958    int n;
5959
5960    for_each_text_gc(n) {
5961	freeCgs(xw, win, (CgsEnum) n);
5962    }
5963}
5964
5965#define TRACE_FREE_LEAK(name) \
5966	if (name) { \
5967	    free(name); \
5968	    name = 0; \
5969	    TRACE(("freed " #name "\n")); \
5970	}
5971
5972#define FREE_LEAK(name) \
5973	if (name) { \
5974	    free(name); \
5975	    name = 0; \
5976	}
5977
5978#ifdef NO_LEAKS
5979#if OPT_RENDERFONT
5980static void
5981xtermCloseXft(TScreen * screen, XftFont ** pub)
5982{
5983    if (*pub != 0) {
5984	XftFontClose(screen->display, *pub);
5985	*pub = 0;
5986    }
5987}
5988#endif
5989#endif
5990
5991static void
5992VTDestroy(Widget w GCC_UNUSED)
5993{
5994#ifdef NO_LEAKS
5995    XtermWidget xw = (XtermWidget) w;
5996    TScreen *screen = &xw->screen;
5997    Cardinal n;
5998
5999    StopBlinking(screen);
6000
6001    if (screen->scrollWidget)
6002	XtDestroyWidget(screen->scrollWidget);
6003
6004    TRACE_FREE_LEAK(screen->save_ptr);
6005    TRACE_FREE_LEAK(screen->sbuf_address);
6006    TRACE_FREE_LEAK(screen->allbuf);
6007    TRACE_FREE_LEAK(screen->abuf_address);
6008    TRACE_FREE_LEAK(screen->altbuf);
6009    TRACE_FREE_LEAK(screen->keyboard_dialect);
6010    TRACE_FREE_LEAK(screen->term_id);
6011#if OPT_WIDE_CHARS
6012    TRACE_FREE_LEAK(screen->draw_buf);
6013#if OPT_LUIT_PROG
6014    TRACE_FREE_LEAK(xw->misc.locale_str);
6015    TRACE_FREE_LEAK(xw->misc.localefilter);
6016#endif
6017#endif
6018#if OPT_INPUT_METHOD
6019    if (screen->xim) {
6020	XCloseIM(screen->xim);
6021	TRACE(("freed screen->xim\n"));
6022    }
6023#endif
6024    releaseCursorGCs(xw);
6025    releaseWindowGCs(xw, &(screen->fullVwin));
6026#ifndef NO_ACTIVE_ICON
6027    releaseWindowGCs(xw, &(screen->iconVwin));
6028#endif
6029
6030    if (screen->hidden_cursor)
6031	XFreeCursor(screen->display, screen->hidden_cursor);
6032
6033    xtermCloseFonts(xw, screen->fnts);
6034    noleaks_cachedCgs(xw);
6035
6036#if OPT_RENDERFONT
6037    for (n = 0; n < NMENUFONTS; ++n) {
6038	xtermCloseXft(screen, &(screen->renderFontNorm[n]));
6039	xtermCloseXft(screen, &(screen->renderFontBold[n]));
6040	xtermCloseXft(screen, &(screen->renderFontItal[n]));
6041	xtermCloseXft(screen, &(screen->renderWideNorm[n]));
6042	xtermCloseXft(screen, &(screen->renderWideBold[n]));
6043	xtermCloseXft(screen, &(screen->renderWideItal[n]));
6044    }
6045#endif
6046
6047#if 0				/* some strings may be owned by X libraries */
6048    for (n = 0; n <= fontMenu_lastBuiltin; ++n) {
6049	int k;
6050	for (k = 0; k < fMAX; ++k) {
6051	    char *s = screen->menu_font_names[n][k];
6052	    if (s != 0)
6053		free(s);
6054	}
6055    }
6056#endif
6057
6058#if OPT_COLOR_RES
6059    /* free local copies of resource strings */
6060    for (n = 0; n < NCOLORS; ++n) {
6061	FREE_LEAK(screen->Tcolors[n].resource);
6062    }
6063#endif
6064#if OPT_SELECT_REGEX
6065    for (n = 0; n < NSELECTUNITS; ++n) {
6066	FREE_LEAK(screen->selectExpr[n]);
6067    }
6068#endif
6069
6070    if (screen->selection_atoms)
6071	XtFree((char *) (screen->selection_atoms));
6072
6073    XtFree((char *) (screen->selection_data));
6074
6075    TRACE_FREE_LEAK(xw->keyboard.extra_translations);
6076    TRACE_FREE_LEAK(xw->keyboard.shell_translations);
6077    TRACE_FREE_LEAK(xw->keyboard.xterm_translations);
6078#endif /* defined(NO_LEAKS) */
6079}
6080
6081/*ARGSUSED*/
6082static void
6083VTRealize(Widget w,
6084	  XtValueMask * valuemask,
6085	  XSetWindowAttributes * values)
6086{
6087    XtermWidget xw = (XtermWidget) w;
6088    TScreen *screen = &xw->screen;
6089
6090    const VTFontNames *myfont;
6091    unsigned width, height;
6092    int xpos, ypos, pr;
6093    Atom pid_atom;
6094    int i;
6095
6096    TRACE(("VTRealize\n"));
6097
6098    TabReset(xw->tabs);
6099
6100    if (screen->menu_font_number == fontMenu_default) {
6101	myfont = &(xw->misc.default_font);
6102    } else {
6103	myfont = xtermFontName(screen->MenuFontName(screen->menu_font_number));
6104    }
6105    memset(screen->fnts, 0, sizeof(screen->fnts));
6106
6107    if (!xtermLoadFont(xw,
6108		       myfont,
6109		       False,
6110		       screen->menu_font_number)) {
6111	if (XmuCompareISOLatin1(myfont->f_n, DEFFONT) != 0) {
6112	    fprintf(stderr,
6113		    "%s:  unable to open font \"%s\", trying \"%s\"....\n",
6114		    xterm_name, myfont->f_n, DEFFONT);
6115	    (void) xtermLoadFont(xw,
6116				 xtermFontName(DEFFONT),
6117				 False,
6118				 screen->menu_font_number);
6119	    screen->MenuFontName(screen->menu_font_number) = DEFFONT;
6120	}
6121    }
6122
6123    /* really screwed if we couldn't open default font */
6124    if (!screen->fnts[fNorm].fs) {
6125	fprintf(stderr, "%s:  unable to locate a suitable font\n",
6126		xterm_name);
6127	Exit(1);
6128    }
6129#if OPT_WIDE_CHARS
6130    if (xw->screen.utf8_mode) {
6131	TRACE(("check if this is a wide font, if not try again\n"));
6132	if (xtermLoadWideFonts(xw, False))
6133	    SetVTFont(xw, screen->menu_font_number, True, NULL);
6134    }
6135#endif
6136
6137    /* making cursor */
6138    if (!screen->pointer_cursor) {
6139	screen->pointer_cursor =
6140	    make_colored_cursor(XC_xterm,
6141				T_COLOR(screen, MOUSE_FG),
6142				T_COLOR(screen, MOUSE_BG));
6143    } else {
6144	recolor_cursor(screen,
6145		       screen->pointer_cursor,
6146		       T_COLOR(screen, MOUSE_FG),
6147		       T_COLOR(screen, MOUSE_BG));
6148    }
6149
6150    /* set defaults */
6151    xpos = 1;
6152    ypos = 1;
6153    width = 80;
6154    height = 24;
6155
6156    TRACE(("parsing geo_metry %s\n", NonNull(xw->misc.geo_metry)));
6157    pr = XParseGeometry(xw->misc.geo_metry, &xpos, &ypos,
6158			&width, &height);
6159    TRACE(("... position %d,%d size %dx%d\n", ypos, xpos, height, width));
6160
6161    set_max_col(screen, (int) (width - 1));	/* units in character cells */
6162    set_max_row(screen, (int) (height - 1));	/* units in character cells */
6163    xtermUpdateFontInfo(xw, False);
6164
6165    width = screen->fullVwin.fullwidth;
6166    height = screen->fullVwin.fullheight;
6167
6168    TRACE(("... border widget %d parent %d shell %d\n",
6169	   BorderWidth(xw),
6170	   BorderWidth(XtParent(xw)),
6171	   BorderWidth(SHELL_OF(xw))));
6172
6173    if ((pr & XValue) && (XNegative & pr)) {
6174	xpos += DisplayWidth(screen->display, DefaultScreen(screen->display))
6175	    - width - (BorderWidth(XtParent(xw)) * 2);
6176    }
6177    if ((pr & YValue) && (YNegative & pr)) {
6178	ypos += DisplayHeight(screen->display, DefaultScreen(screen->display))
6179	    - height - (BorderWidth(XtParent(xw)) * 2);
6180    }
6181
6182    /* set up size hints for window manager; min 1 char by 1 char */
6183    getXtermSizeHints(xw);
6184    xtermSizeHints(xw, (xw->misc.scrollbar
6185			? (screen->scrollWidget->core.width
6186			   + BorderWidth(screen->scrollWidget))
6187			: 0));
6188
6189    xw->hints.x = xpos;
6190    xw->hints.y = ypos;
6191    if ((XValue & pr) || (YValue & pr)) {
6192	xw->hints.flags |= USSize | USPosition;
6193	xw->hints.flags |= PWinGravity;
6194	switch (pr & (XNegative | YNegative)) {
6195	case 0:
6196	    xw->hints.win_gravity = NorthWestGravity;
6197	    break;
6198	case XNegative:
6199	    xw->hints.win_gravity = NorthEastGravity;
6200	    break;
6201	case YNegative:
6202	    xw->hints.win_gravity = SouthWestGravity;
6203	    break;
6204	default:
6205	    xw->hints.win_gravity = SouthEastGravity;
6206	    break;
6207	}
6208    } else {
6209	/* set a default size, but do *not* set position */
6210	xw->hints.flags |= PSize;
6211    }
6212    xw->hints.height = xw->hints.base_height
6213	+ xw->hints.height_inc * MaxRows(screen);
6214    xw->hints.width = xw->hints.base_width
6215	+ xw->hints.width_inc * MaxCols(screen);
6216
6217    if ((WidthValue & pr) || (HeightValue & pr))
6218	xw->hints.flags |= USSize;
6219    else
6220	xw->hints.flags |= PSize;
6221
6222    /*
6223     * Note that the size-hints are for the shell, while the resize-request
6224     * is for the vt100 widget.  They are not the same size.
6225     */
6226    TRACE(("make resize request %dx%d\n", height, width));
6227    (void) XtMakeResizeRequest((Widget) xw,
6228			       (Dimension) width, (Dimension) height,
6229			       &xw->core.width, &xw->core.height);
6230    TRACE(("...made resize request %dx%d\n", xw->core.height, xw->core.width));
6231
6232    /* XXX This is bogus.  We are parsing geometries too late.  This
6233     * is information that the shell widget ought to have before we get
6234     * realized, so that it can do the right thing.
6235     */
6236    if (xw->hints.flags & USPosition)
6237	XMoveWindow(XtDisplay(xw), XtWindow(SHELL_OF(xw)),
6238		    xw->hints.x, xw->hints.y);
6239
6240    TRACE(("%s@%d -- ", __FILE__, __LINE__));
6241    TRACE_HINTS(&xw->hints);
6242    XSetWMNormalHints(XtDisplay(xw), XtWindow(SHELL_OF(xw)), &xw->hints);
6243    TRACE(("%s@%d -- ", __FILE__, __LINE__));
6244    TRACE_WM_HINTS(xw);
6245
6246    if ((pid_atom = XInternAtom(XtDisplay(xw), "_NET_WM_PID", False)) != None) {
6247	/* XChangeProperty format 32 really is "long" */
6248	unsigned long pid_l = (unsigned long) getpid();
6249	TRACE(("Setting _NET_WM_PID property to %lu\n", pid_l));
6250	XChangeProperty(XtDisplay(xw), VShellWindow,
6251			pid_atom, XA_CARDINAL, 32, PropModeReplace,
6252			(unsigned char *) &pid_l, 1);
6253    }
6254
6255    XFlush(XtDisplay(xw));	/* get it out to window manager */
6256
6257    /* use ForgetGravity instead of SouthWestGravity because translating
6258       the Expose events for ConfigureNotifys is too hard */
6259    values->bit_gravity = ((xw->misc.resizeGravity == NorthWestGravity)
6260			   ? NorthWestGravity
6261			   : ForgetGravity);
6262    xw->screen.fullVwin.window = XtWindow(xw) =
6263	XCreateWindow(XtDisplay(xw), XtWindow(XtParent(xw)),
6264		      xw->core.x, xw->core.y,
6265		      xw->core.width, xw->core.height, BorderWidth(xw),
6266		      (int) xw->core.depth,
6267		      InputOutput, CopyFromParent,
6268		      *valuemask | CWBitGravity, values);
6269    screen->event_mask = values->event_mask;
6270
6271#ifndef NO_ACTIVE_ICON
6272    if (xw->misc.active_icon && screen->fnt_icon.fs) {
6273	int iconX = 0, iconY = 0;
6274	Widget shell = SHELL_OF(xw);
6275	VTwin *win = &(screen->iconVwin);
6276
6277	TRACE(("Initializing active-icon\n"));
6278	XtVaGetValues(shell, XtNiconX, &iconX, XtNiconY, &iconY, (XtPointer) 0);
6279	xtermComputeFontInfo(xw, &(screen->iconVwin), screen->fnt_icon.fs, 0);
6280
6281	/* since only one client is permitted to select for Button
6282	 * events, we have to let the window manager get 'em...
6283	 */
6284	values->event_mask &= ~(ButtonPressMask | ButtonReleaseMask);
6285	values->border_pixel = xw->misc.icon_border_pixel;
6286
6287	screen->iconVwin.window =
6288	    XCreateWindow(XtDisplay(xw),
6289			  RootWindowOfScreen(XtScreen(shell)),
6290			  iconX, iconY,
6291			  screen->iconVwin.fullwidth,
6292			  screen->iconVwin.fullheight,
6293			  xw->misc.icon_border_width,
6294			  (int) xw->core.depth,
6295			  InputOutput, CopyFromParent,
6296			  *valuemask | CWBitGravity | CWBorderPixel,
6297			  values);
6298	XtVaSetValues(shell,
6299		      XtNiconWindow, screen->iconVwin.window,
6300		      (XtPointer) 0);
6301	XtRegisterDrawable(XtDisplay(xw), screen->iconVwin.window, w);
6302
6303	setCgsFont(xw, win, gcNorm, &(screen->fnt_icon));
6304	setCgsFore(xw, win, gcNorm, T_COLOR(screen, TEXT_FG));
6305	setCgsBack(xw, win, gcNorm, T_COLOR(screen, TEXT_BG));
6306
6307	copyCgs(xw, win, gcBold, gcNorm);
6308
6309	setCgsFont(xw, win, gcNormReverse, &(screen->fnt_icon));
6310	setCgsFore(xw, win, gcNormReverse, T_COLOR(screen, TEXT_BG));
6311	setCgsBack(xw, win, gcNormReverse, T_COLOR(screen, TEXT_FG));
6312
6313	copyCgs(xw, win, gcBoldReverse, gcNormReverse);
6314
6315#if OPT_TOOLBAR
6316	/*
6317	 * Toolbar is initialized before we get here.  Enable the menu item
6318	 * and set it properly.
6319	 */
6320	SetItemSensitivity(vtMenuEntries[vtMenu_activeicon].widget, True);
6321	update_activeicon();
6322#endif
6323    } else {
6324	TRACE(("Disabled active-icon\n"));
6325	xw->misc.active_icon = False;
6326    }
6327#endif /* NO_ACTIVE_ICON */
6328
6329#if OPT_I18N_SUPPORT && OPT_INPUT_METHOD
6330    VTInitI18N();
6331#else
6332    xw->screen.xic = NULL;
6333#endif
6334#if OPT_NUM_LOCK
6335    VTInitModifiers(xw);
6336#if OPT_EXTRA_PASTE
6337    if (xw->keyboard.extra_translations) {
6338	XtOverrideTranslations((Widget) xw,
6339			       XtParseTranslationTable(xw->keyboard.extra_translations));
6340    }
6341#endif
6342#endif
6343
6344    set_cursor_gcs(xw);
6345
6346    /* Reset variables used by ANSI emulation. */
6347
6348    resetCharsets(screen);
6349
6350    XDefineCursor(screen->display, VShellWindow, screen->pointer_cursor);
6351
6352    set_cur_col(screen, 0);
6353    set_cur_row(screen, 0);
6354    set_max_col(screen, Width(screen) / screen->fullVwin.f_width - 1);
6355    set_max_row(screen, Height(screen) / screen->fullVwin.f_height - 1);
6356    set_tb_margins(screen, 0, screen->max_row);
6357
6358    memset(screen->sc, 0, sizeof(screen->sc));
6359
6360    /* Mark screen buffer as unallocated.  We wait until the run loop so
6361       that the child process does not fork and exec with all the dynamic
6362       memory it will never use.  If we were to do it here, the
6363       swap space for new process would be huge for huge savelines. */
6364#if OPT_TEK4014
6365    if (!tekWidget)		/* if not called after fork */
6366#endif
6367	screen->visbuf = screen->allbuf = NULL;
6368
6369    screen->do_wrap = 0;
6370    screen->scrolls = screen->incopy = 0;
6371    xtermSetCursorBox(screen);
6372
6373    screen->savedlines = 0;
6374
6375    for (i = 0; i < 2; ++i) {
6376	screen->alternate = !screen->alternate;
6377	CursorSave(xw);
6378    }
6379
6380    /*
6381     * Do this last, since it may change the layout via a resize.
6382     */
6383    if (xw->misc.scrollbar) {
6384	screen->fullVwin.sb_info.width = 0;
6385	ScrollBarOn(xw, False, True);
6386    }
6387    return;
6388}
6389
6390#if OPT_I18N_SUPPORT && OPT_INPUT_METHOD
6391
6392/* limit this feature to recent XFree86 since X11R6.x core dumps */
6393#if defined(XtSpecificationRelease) && XtSpecificationRelease >= 6 && defined(X_HAVE_UTF8_STRING)
6394#define USE_XIM_INSTANTIATE_CB
6395
6396static void
6397xim_instantiate_cb(Display * display,
6398		   XPointer client_data GCC_UNUSED,
6399		   XPointer call_data GCC_UNUSED)
6400{
6401    if (display != XtDisplay(term))
6402	return;
6403
6404    VTInitI18N();
6405}
6406
6407static void
6408xim_destroy_cb(XIM im GCC_UNUSED,
6409	       XPointer client_data GCC_UNUSED,
6410	       XPointer call_data GCC_UNUSED)
6411{
6412    term->screen.xic = NULL;
6413
6414    XRegisterIMInstantiateCallback(XtDisplay(term), NULL, NULL, NULL,
6415				   xim_instantiate_cb, NULL);
6416}
6417#endif /* X11R6+ */
6418
6419static void
6420xim_real_init(void)
6421{
6422    unsigned i, j;
6423    char *p, *s, *t, *ns, *end, buf[32];
6424    XIMStyles *xim_styles;
6425    XIMStyle input_style = 0;
6426    Bool found;
6427    static struct {
6428	char *name;
6429	unsigned long code;
6430    } known_style[] = {
6431	{
6432	    "OverTheSpot", (XIMPreeditPosition | XIMStatusNothing)
6433	},
6434	{
6435	    "OffTheSpot", (XIMPreeditArea | XIMStatusArea)
6436	},
6437	{
6438	    "Root", (XIMPreeditNothing | XIMStatusNothing)
6439	},
6440    };
6441
6442    term->screen.xic = NULL;
6443
6444    if (term->misc.cannot_im) {
6445	return;
6446    }
6447
6448    if (!term->misc.input_method || !*term->misc.input_method) {
6449	if ((p = XSetLocaleModifiers("")) != NULL && *p)
6450	    term->screen.xim = XOpenIM(XtDisplay(term), NULL, NULL, NULL);
6451    } else {
6452	s = term->misc.input_method;
6453	i = 5 + strlen(s);
6454	t = (char *) MyStackAlloc(i, buf);
6455	if (t == NULL)
6456	    SysError(ERROR_VINIT);
6457
6458	for (ns = s; ns && *s;) {
6459	    while (*s && isspace(CharOf(*s)))
6460		s++;
6461	    if (!*s)
6462		break;
6463	    if ((ns = end = strchr(s, ',')) == 0)
6464		end = s + strlen(s);
6465	    while ((end != s) && isspace(CharOf(end[-1])))
6466		end--;
6467
6468	    if (end != s) {
6469		strcpy(t, "@im=");
6470		strncat(t, s, (unsigned) (end - s));
6471
6472		if ((p = XSetLocaleModifiers(t)) != 0 && *p
6473		    && (term->screen.xim = XOpenIM(XtDisplay(term),
6474						   NULL,
6475						   NULL,
6476						   NULL)) != 0)
6477		    break;
6478
6479	    }
6480	    s = ns + 1;
6481	}
6482	MyStackFree(t, buf);
6483    }
6484
6485    if (term->screen.xim == NULL
6486	&& (p = XSetLocaleModifiers("@im=none")) != NULL
6487	&& *p) {
6488	term->screen.xim = XOpenIM(XtDisplay(term), NULL, NULL, NULL);
6489    }
6490
6491    if (!term->screen.xim) {
6492	fprintf(stderr, "Failed to open input method\n");
6493	return;
6494    }
6495    TRACE(("VTInitI18N opened input method\n"));
6496
6497    if (XGetIMValues(term->screen.xim, XNQueryInputStyle, &xim_styles, NULL)
6498	|| !xim_styles
6499	|| !xim_styles->count_styles) {
6500	fprintf(stderr, "input method doesn't support any style\n");
6501	XCloseIM(term->screen.xim);
6502	term->misc.cannot_im = True;
6503	return;
6504    }
6505
6506    found = False;
6507    for (s = term->misc.preedit_type; s && !found;) {
6508	while (*s && isspace(CharOf(*s)))
6509	    s++;
6510	if (!*s)
6511	    break;
6512	if ((ns = end = strchr(s, ',')) != 0)
6513	    ns++;
6514	else
6515	    end = s + strlen(s);
6516	while ((end != s) && isspace(CharOf(end[-1])))
6517	    end--;
6518
6519	if (end != s) {		/* just in case we have a spurious comma */
6520	    TRACE(("looking for style '%.*s'\n", end - s, s));
6521	    for (i = 0; i < XtNumber(known_style); i++) {
6522		if ((int) strlen(known_style[i].name) == (end - s)
6523		    && !strncmp(s, known_style[i].name, (unsigned) (end - s))) {
6524		    input_style = known_style[i].code;
6525		    for (j = 0; j < xim_styles->count_styles; j++) {
6526			if (input_style == xim_styles->supported_styles[j]) {
6527			    found = True;
6528			    break;
6529			}
6530		    }
6531		    if (found)
6532			break;
6533		}
6534	    }
6535	}
6536
6537	s = ns;
6538    }
6539    XFree(xim_styles);
6540
6541    if (!found) {
6542	fprintf(stderr,
6543		"input method doesn't support my preedit type (%s)\n",
6544		term->misc.preedit_type);
6545	XCloseIM(term->screen.xim);
6546	term->misc.cannot_im = True;
6547	return;
6548    }
6549
6550    /*
6551     * Check for styles we do not yet support.
6552     */
6553    TRACE(("input_style %#lx\n", input_style));
6554    if (input_style == (XIMPreeditArea | XIMStatusArea)) {
6555	fprintf(stderr,
6556		"This program doesn't support the 'OffTheSpot' preedit type\n");
6557	XCloseIM(term->screen.xim);
6558	term->misc.cannot_im = True;
6559	return;
6560    }
6561
6562    /*
6563     * For XIMPreeditPosition (or OverTheSpot), XIM client has to
6564     * prepare a font.
6565     * The font has to be locale-dependent XFontSet, whereas
6566     * XTerm use Unicode font.  This leads a problem that the
6567     * same font cannot be used for XIM preedit.
6568     */
6569    if (input_style != (XIMPreeditNothing | XIMStatusNothing)) {
6570	char **missing_charset_list;
6571	int missing_charset_count;
6572	char *def_string;
6573	XVaNestedList p_list;
6574	XPoint spot =
6575	{0, 0};
6576	XFontStruct **fonts;
6577	char **font_name_list;
6578
6579	term->screen.fs = XCreateFontSet(XtDisplay(term),
6580					 term->misc.f_x,
6581					 &missing_charset_list,
6582					 &missing_charset_count,
6583					 &def_string);
6584	if (term->screen.fs == NULL) {
6585	    fprintf(stderr, "Preparation of font set "
6586		    "\"%s\" for XIM failed.\n", term->misc.f_x);
6587	    term->screen.fs = XCreateFontSet(XtDisplay(term),
6588					     DEFXIMFONT,
6589					     &missing_charset_list,
6590					     &missing_charset_count,
6591					     &def_string);
6592	}
6593	if (term->screen.fs == NULL) {
6594	    fprintf(stderr, "Preparation of default font set "
6595		    "\"%s\" for XIM failed.\n", DEFXIMFONT);
6596	    XCloseIM(term->screen.xim);
6597	    term->misc.cannot_im = True;
6598	    return;
6599	}
6600	(void) XExtentsOfFontSet(term->screen.fs);
6601	j = XFontsOfFontSet(term->screen.fs, &fonts, &font_name_list);
6602	for (i = 0, term->screen.fs_ascent = 0; i < j; i++) {
6603	    if (term->screen.fs_ascent < (*fonts)->ascent)
6604		term->screen.fs_ascent = (*fonts)->ascent;
6605	}
6606	p_list = XVaCreateNestedList(0,
6607				     XNSpotLocation, &spot,
6608				     XNFontSet, term->screen.fs,
6609				     NULL);
6610	term->screen.xic = XCreateIC(term->screen.xim,
6611				     XNInputStyle, input_style,
6612				     XNClientWindow, XtWindow(term),
6613				     XNFocusWindow, XtWindow(term),
6614				     XNPreeditAttributes, p_list,
6615				     NULL);
6616    } else {
6617	term->screen.xic = XCreateIC(term->screen.xim, XNInputStyle, input_style,
6618				     XNClientWindow, XtWindow(term),
6619				     XNFocusWindow, XtWindow(term),
6620				     NULL);
6621    }
6622
6623    if (!term->screen.xic) {
6624	fprintf(stderr, "Failed to create input context\n");
6625	XCloseIM(term->screen.xim);
6626    }
6627#if defined(USE_XIM_INSTANTIATE_CB)
6628    else {
6629	XIMCallback destroy_cb;
6630
6631	destroy_cb.callback = xim_destroy_cb;
6632	destroy_cb.client_data = NULL;
6633	if (XSetIMValues(term->screen.xim, XNDestroyCallback, &destroy_cb, NULL))
6634	    fprintf(stderr, "Could not set destroy callback to IM\n");
6635    }
6636#endif
6637
6638    return;
6639}
6640
6641static void
6642VTInitI18N(void)
6643{
6644    if (term->misc.open_im) {
6645	xim_real_init();
6646
6647#if defined(USE_XIM_INSTANTIATE_CB)
6648	if (term->screen.xic == NULL && !term->misc.cannot_im) {
6649	    sleep(3);
6650	    XRegisterIMInstantiateCallback(XtDisplay(term), NULL, NULL, NULL,
6651					   xim_instantiate_cb, NULL);
6652	}
6653#endif
6654    }
6655}
6656#endif /* OPT_I18N_SUPPORT && OPT_INPUT_METHOD */
6657
6658static Boolean
6659VTSetValues(Widget cur,
6660	    Widget request GCC_UNUSED,
6661	    Widget wnew,
6662	    ArgList args GCC_UNUSED,
6663	    Cardinal *num_args GCC_UNUSED)
6664{
6665    XtermWidget curvt = (XtermWidget) cur;
6666    XtermWidget newvt = (XtermWidget) wnew;
6667    Bool refresh_needed = False;
6668    Bool fonts_redone = False;
6669
6670    if ((T_COLOR(&(curvt->screen), TEXT_BG) !=
6671	 T_COLOR(&(newvt->screen), TEXT_BG)) ||
6672	(T_COLOR(&(curvt->screen), TEXT_FG) !=
6673	 T_COLOR(&(newvt->screen), TEXT_FG)) ||
6674	(curvt->screen.MenuFontName(curvt->screen.menu_font_number) !=
6675	 newvt->screen.MenuFontName(newvt->screen.menu_font_number)) ||
6676	(curvt->misc.default_font.f_n != newvt->misc.default_font.f_n)) {
6677	if (curvt->misc.default_font.f_n != newvt->misc.default_font.f_n)
6678	    newvt->screen.MenuFontName(fontMenu_default) = newvt->misc.default_font.f_n;
6679	if (xtermLoadFont(newvt,
6680			  xtermFontName(newvt->screen.MenuFontName(curvt->screen.menu_font_number)),
6681			  True, newvt->screen.menu_font_number)) {
6682	    /* resizing does the redisplay, so don't ask for it here */
6683	    refresh_needed = True;
6684	    fonts_redone = True;
6685	} else if (curvt->misc.default_font.f_n != newvt->misc.default_font.f_n)
6686	    newvt->screen.MenuFontName(fontMenu_default) = curvt->misc.default_font.f_n;
6687    }
6688    if (!fonts_redone
6689	&& (T_COLOR(&(curvt->screen), TEXT_CURSOR) !=
6690	    T_COLOR(&(newvt->screen), TEXT_CURSOR))) {
6691	set_cursor_gcs(newvt);
6692	refresh_needed = True;
6693    }
6694    if (curvt->misc.re_verse != newvt->misc.re_verse) {
6695	newvt->flags ^= REVERSE_VIDEO;
6696	ReverseVideo(newvt);
6697	newvt->misc.re_verse = !newvt->misc.re_verse;	/* ReverseVideo toggles */
6698	refresh_needed = True;
6699    }
6700    if ((T_COLOR(&(curvt->screen), MOUSE_FG) !=
6701	 T_COLOR(&(newvt->screen), MOUSE_FG)) ||
6702	(T_COLOR(&(curvt->screen), MOUSE_BG) !=
6703	 T_COLOR(&(newvt->screen), MOUSE_BG))) {
6704	recolor_cursor(&(newvt->screen),
6705		       newvt->screen.pointer_cursor,
6706		       T_COLOR(&(newvt->screen), MOUSE_FG),
6707		       T_COLOR(&(newvt->screen), MOUSE_BG));
6708	refresh_needed = True;
6709    }
6710    if (curvt->misc.scrollbar != newvt->misc.scrollbar) {
6711	ToggleScrollBar(newvt);
6712    }
6713
6714    return refresh_needed;
6715}
6716
6717#define setGC(code) set_at = __LINE__, currentCgs = code
6718
6719#define OutsideSelection(screen,srow,scol)  \
6720	 ((srow) > (screen)->endH.row || \
6721	  ((srow) == (screen)->endH.row && \
6722	   (scol) >= (screen)->endH.col) || \
6723	  (srow) < (screen)->startH.row || \
6724	  ((srow) == (screen)->startH.row && \
6725	   (scol) < (screen)->startH.col))
6726
6727/*
6728 * Shows cursor at new cursor position in screen.
6729 */
6730void
6731ShowCursor(void)
6732{
6733    XtermWidget xw = term;
6734    TScreen *screen = &xw->screen;
6735    int x, y;
6736    Char clo;
6737    unsigned flags;
6738    unsigned fg_bg = 0;
6739    GC currentGC;
6740    CgsEnum currentCgs = gcMAX;
6741    VTwin *currentWin = WhichVWin(screen);
6742    int set_at;
6743    Bool in_selection;
6744    Bool reversed;
6745    Bool filled;
6746    Pixel fg_pix;
6747    Pixel bg_pix;
6748    Pixel tmp;
6749#if OPT_HIGHLIGHT_COLOR
6750    Pixel selbg_pix = T_COLOR(screen, HIGHLIGHT_BG);
6751    Pixel selfg_pix = T_COLOR(screen, HIGHLIGHT_FG);
6752    Boolean use_selbg;
6753    Boolean use_selfg;
6754#endif
6755#if OPT_WIDE_CHARS
6756    Char chi = 0;
6757    int base;
6758    int off;
6759    int my_col = 0;
6760#endif
6761    int cursor_col;
6762
6763    if (screen->cursor_state == BLINKED_OFF)
6764	return;
6765
6766    if (screen->eventMode != NORMAL)
6767	return;
6768
6769    if (INX2ROW(screen, screen->cur_row) > screen->max_row)
6770	return;
6771
6772    screen->cursorp.row = screen->cur_row;
6773    cursor_col = screen->cursorp.col = screen->cur_col;
6774    screen->cursor_moved = False;
6775
6776#ifndef NO_ACTIVE_ICON
6777    if (IsIcon(screen)) {
6778	screen->cursor_state = ON;
6779	return;
6780    }
6781#endif /* NO_ACTIVE_ICON */
6782
6783#if OPT_WIDE_CHARS
6784    base =
6785#endif
6786	clo = SCRN_BUF_CHARS(screen, screen->cursorp.row)[cursor_col];
6787
6788    if_OPT_WIDE_CHARS(screen, {
6789	chi = SCRN_BUF_WIDEC(screen, screen->cursorp.row)[cursor_col];
6790	if (clo == HIDDEN_LO && chi == HIDDEN_HI && cursor_col > 0) {
6791	    /* if cursor points to non-initial part of wide character,
6792	     * back it up
6793	     */
6794	    --cursor_col;
6795	    clo = SCRN_BUF_CHARS(screen, screen->cursorp.row)[cursor_col];
6796	    chi = SCRN_BUF_WIDEC(screen, screen->cursorp.row)[cursor_col];
6797	}
6798	my_col = cursor_col;
6799	base = (chi << 8) | clo;
6800	if (iswide(base))
6801	    my_col += 1;
6802    });
6803
6804    flags = SCRN_BUF_ATTRS(screen, screen->cursorp.row)[cursor_col];
6805
6806    if (clo == 0
6807#if OPT_WIDE_CHARS
6808	&& chi == 0
6809#endif
6810	) {
6811	clo = ' ';
6812    }
6813
6814    /*
6815     * If the cursor happens to be on blanks, and the foreground color is set
6816     * but not the background, do not treat it as a colored cell.
6817     */
6818#if OPT_ISO_COLORS
6819    if ((flags & TERM_COLOR_FLAGS(xw)) == BG_COLOR
6820#if OPT_WIDE_CHARS
6821	&& chi == 0
6822#endif
6823	&& clo == ' ') {
6824	flags &= ~TERM_COLOR_FLAGS(xw);
6825    }
6826#endif
6827
6828    /*
6829     * Compare the current cell to the last set of colors used for the
6830     * cursor and update the GC's if needed.
6831     */
6832    (void) fg_bg;
6833    if_OPT_EXT_COLORS(screen, {
6834	fg_bg = (SCRN_BUF_FGRND(screen, screen->cursorp.row)[cursor_col] << 8)
6835	    | (SCRN_BUF_BGRND(screen, screen->cursorp.row)[cursor_col]);
6836    });
6837    if_OPT_ISO_TRADITIONAL_COLORS(screen, {
6838	fg_bg = SCRN_BUF_COLOR(screen, screen->cursorp.row)[cursor_col];
6839    });
6840    fg_pix = getXtermForeground(xw, flags, extract_fg(xw, fg_bg, flags));
6841    bg_pix = getXtermBackground(xw, flags, extract_bg(xw, fg_bg, flags));
6842
6843    if (OutsideSelection(screen, screen->cur_row, screen->cur_col))
6844	in_selection = False;
6845    else
6846	in_selection = True;
6847
6848    reversed = ReverseOrHilite(screen, flags, in_selection);
6849
6850    /* This is like updatedXtermGC(), except that we have to worry about
6851     * whether the window has focus, since in that case we want just an
6852     * outline for the cursor.
6853     */
6854    filled = (screen->select || screen->always_highlight);
6855#if OPT_HIGHLIGHT_COLOR
6856    use_selbg = isNotForeground(xw, fg_pix, bg_pix, selbg_pix);
6857    use_selfg = isNotBackground(xw, fg_pix, bg_pix, selfg_pix);
6858#endif
6859    if (filled) {
6860	if (reversed) {		/* text is reverse video */
6861	    if (getCgsGC(xw, currentWin, gcVTcursNormal)) {
6862		setGC(gcVTcursNormal);
6863	    } else {
6864		if (flags & BOLDATTR(screen)) {
6865		    setGC(gcBold);
6866		} else {
6867		    setGC(gcNorm);
6868		}
6869	    }
6870	    EXCHANGE(fg_pix, bg_pix, tmp);
6871#if OPT_HIGHLIGHT_COLOR
6872	    if (screen->hilite_reverse) {
6873		if (use_selbg && !use_selfg)
6874		    fg_pix = bg_pix;
6875		if (use_selfg && !use_selbg)
6876		    bg_pix = fg_pix;
6877		if (use_selbg)
6878		    bg_pix = selbg_pix;
6879		if (use_selfg)
6880		    fg_pix = selfg_pix;
6881	    }
6882#endif
6883	} else {		/* normal video */
6884	    if (getCgsGC(xw, currentWin, gcVTcursReverse)) {
6885		setGC(gcVTcursReverse);
6886	    } else {
6887		if (flags & BOLDATTR(screen)) {
6888		    setGC(gcBoldReverse);
6889		} else {
6890		    setGC(gcNormReverse);
6891		}
6892	    }
6893	}
6894	if (T_COLOR(screen, TEXT_CURSOR) == xw->dft_foreground) {
6895	    setCgsBack(xw, currentWin, currentCgs, fg_pix);
6896	}
6897	setCgsFore(xw, currentWin, currentCgs, bg_pix);
6898    } else {			/* not selected */
6899	if (reversed) {		/* text is reverse video */
6900	    EXCHANGE(fg_pix, bg_pix, tmp);
6901	    setGC(gcNormReverse);
6902	} else {		/* normal video */
6903	    setGC(gcNorm);
6904	}
6905#if OPT_HIGHLIGHT_COLOR
6906	if (screen->hilite_reverse) {
6907	    if (in_selection && !reversed) {
6908		;		/* really INVERSE ... */
6909	    } else if (in_selection || reversed) {
6910		if (use_selbg) {
6911		    if (use_selfg) {
6912			bg_pix = fg_pix;
6913		    } else {
6914			fg_pix = bg_pix;
6915		    }
6916		}
6917		if (use_selbg) {
6918		    bg_pix = selbg_pix;
6919		}
6920		if (use_selfg) {
6921		    fg_pix = selfg_pix;
6922		}
6923	    }
6924	} else {
6925	    if (in_selection) {
6926		if (use_selbg) {
6927		    bg_pix = selbg_pix;
6928		}
6929		if (use_selfg) {
6930		    fg_pix = selfg_pix;
6931		}
6932	    }
6933	}
6934#endif
6935	setCgsFore(xw, currentWin, currentCgs, fg_pix);
6936	setCgsBack(xw, currentWin, currentCgs, bg_pix);
6937    }
6938
6939    if (screen->cursor_busy == 0
6940	&& (screen->cursor_state != ON || screen->cursor_GC != set_at)) {
6941
6942	screen->cursor_GC = set_at;
6943	TRACE(("ShowCursor calling drawXtermText cur(%d,%d) %s\n",
6944	       screen->cur_row, screen->cur_col,
6945	       (filled ? "filled" : "outline")));
6946
6947	currentGC = getCgsGC(xw, currentWin, currentCgs);
6948	drawXtermText(xw, flags & DRAWX_MASK, currentGC,
6949		      x = CurCursorX(screen, screen->cur_row, cursor_col),
6950		      y = CursorY(screen, screen->cur_row),
6951		      curXtermChrSet(xw, screen->cur_row),
6952		      PAIRED_CHARS(&clo, &chi), 1, 0);
6953
6954#if OPT_WIDE_CHARS
6955	if_OPT_WIDE_CHARS(screen, {
6956	    for (off = OFF_FINAL; off < MAX_PTRS; off += 2) {
6957		clo = SCREEN_PTR(screen, screen->cursorp.row, off + 0)[my_col];
6958		chi = SCREEN_PTR(screen, screen->cursorp.row, off + 1)[my_col];
6959		if (!(clo || chi))
6960		    break;
6961		drawXtermText(xw, (flags & DRAWX_MASK) | NOBACKGROUND,
6962			      currentGC, x, y,
6963			      curXtermChrSet(xw, screen->cur_row),
6964			      PAIRED_CHARS(&clo, &chi), 1, iswide(base));
6965	    }
6966	});
6967#endif
6968
6969	if (!filled) {
6970	    GC outlineGC = getCgsGC(xw, currentWin, gcVTcursOutline);
6971	    if (outlineGC == 0)
6972		outlineGC = currentGC;
6973
6974	    screen->box->x = x;
6975	    screen->box->y = y;
6976	    XDrawLines(screen->display, VWindow(screen), outlineGC,
6977		       screen->box, NBOX, CoordModePrevious);
6978	}
6979    }
6980    screen->cursor_state = ON;
6981}
6982
6983/*
6984 * hide cursor at previous cursor position in screen.
6985 */
6986void
6987HideCursor(void)
6988{
6989    XtermWidget xw = term;
6990    TScreen *screen = &xw->screen;
6991    GC currentGC;
6992    unsigned flags;
6993    unsigned fg_bg = 0;
6994    int x, y;
6995    Char clo;
6996    Bool in_selection;
6997#if OPT_WIDE_CHARS
6998    Char chi = 0;
6999    int base;
7000    int off;
7001    int my_col = 0;
7002#endif
7003    int cursor_col;
7004
7005    if (screen->cursor_state == OFF)	/* FIXME */
7006	return;
7007    if (INX2ROW(screen, screen->cursorp.row) > screen->max_row)
7008	return;
7009
7010    cursor_col = screen->cursorp.col;
7011
7012#ifndef NO_ACTIVE_ICON
7013    if (IsIcon(screen)) {
7014	screen->cursor_state = OFF;
7015	return;
7016    }
7017#endif /* NO_ACTIVE_ICON */
7018
7019#if OPT_WIDE_CHARS
7020    base =
7021#endif
7022	clo = SCRN_BUF_CHARS(screen, screen->cursorp.row)[cursor_col];
7023    flags = SCRN_BUF_ATTRS(screen, screen->cursorp.row)[cursor_col];
7024
7025    if_OPT_WIDE_CHARS(screen, {
7026	chi = SCRN_BUF_WIDEC(screen, screen->cursorp.row)[cursor_col];
7027	if (clo == HIDDEN_LO && chi == HIDDEN_HI) {
7028	    /* if cursor points to non-initial part of wide character,
7029	     * back it up
7030	     */
7031	    --cursor_col;
7032	    clo = SCRN_BUF_CHARS(screen, screen->cursorp.row)[cursor_col];
7033	    chi = SCRN_BUF_WIDEC(screen, screen->cursorp.row)[cursor_col];
7034	}
7035	my_col = cursor_col;
7036	base = (chi << 8) | clo;
7037	if (iswide(base))
7038	    my_col += 1;
7039    });
7040
7041    if_OPT_EXT_COLORS(screen, {
7042	fg_bg = (SCRN_BUF_FGRND(screen, screen->cursorp.row)[cursor_col] << 8)
7043	    | (SCRN_BUF_BGRND(screen, screen->cursorp.row)[cursor_col]);
7044    });
7045    if_OPT_ISO_TRADITIONAL_COLORS(screen, {
7046	fg_bg = SCRN_BUF_COLOR(screen, screen->cursorp.row)[cursor_col];
7047    });
7048
7049    if (OutsideSelection(screen, screen->cursorp.row, screen->cursorp.col))
7050	in_selection = False;
7051    else
7052	in_selection = True;
7053
7054    currentGC = updatedXtermGC(xw, flags, fg_bg, in_selection);
7055
7056    if (clo == 0
7057#if OPT_WIDE_CHARS
7058	&& chi == 0
7059#endif
7060	) {
7061	clo = ' ';
7062    }
7063
7064    TRACE(("HideCursor calling drawXtermText cur(%d,%d)\n",
7065	   screen->cursorp.row, screen->cursorp.col));
7066    drawXtermText(xw, flags & DRAWX_MASK, currentGC,
7067		  x = CurCursorX(screen, screen->cursorp.row, cursor_col),
7068		  y = CursorY(screen, screen->cursorp.row),
7069		  curXtermChrSet(xw, screen->cursorp.row),
7070		  PAIRED_CHARS(&clo, &chi), 1, 0);
7071
7072#if OPT_WIDE_CHARS
7073    if_OPT_WIDE_CHARS(screen, {
7074	for (off = OFF_FINAL; off < MAX_PTRS; off += 2) {
7075	    clo = SCREEN_PTR(screen, screen->cursorp.row, off + 0)[my_col];
7076	    chi = SCREEN_PTR(screen, screen->cursorp.row, off + 1)[my_col];
7077	    if (!(clo || chi))
7078		break;
7079	    drawXtermText(xw, (flags & DRAWX_MASK) | NOBACKGROUND,
7080			  currentGC, x, y,
7081			  curXtermChrSet(xw, screen->cur_row),
7082			  PAIRED_CHARS(&clo, &chi), 1, iswide(base));
7083	}
7084    });
7085#endif
7086    screen->cursor_state = OFF;
7087    resetXtermGC(xw, flags, in_selection);
7088}
7089
7090#if OPT_BLINK_CURS || OPT_BLINK_TEXT
7091static void
7092StartBlinking(TScreen * screen)
7093{
7094    if (screen->blink_timer == 0) {
7095	unsigned long interval = (screen->cursor_state == ON ?
7096				  screen->blink_on : screen->blink_off);
7097	if (interval == 0)	/* wow! */
7098	    interval = 1;	/* let's humor him anyway */
7099	screen->blink_timer = XtAppAddTimeOut(app_con,
7100					      interval,
7101					      HandleBlinking,
7102					      screen);
7103    }
7104}
7105
7106static void
7107StopBlinking(TScreen * screen)
7108{
7109    if (screen->blink_timer)
7110	XtRemoveTimeOut(screen->blink_timer);
7111    screen->blink_timer = 0;
7112}
7113
7114#if OPT_BLINK_TEXT
7115static Bool
7116ScrnHasBlinking(TScreen * screen, int row)
7117{
7118    Char *attrs = SCRN_BUF_ATTRS(screen, row);
7119    int col;
7120    Bool result = False;
7121
7122    for (col = 0; col < MaxCols(screen); ++col) {
7123	if (attrs[col] & BLINK) {
7124	    result = True;
7125	    break;
7126	}
7127    }
7128    return result;
7129}
7130#endif
7131
7132/*
7133 * Blink the cursor by alternately showing/hiding cursor.  We leave the timer
7134 * running all the time (even though that's a little inefficient) to make the
7135 * logic simple.
7136 */
7137static void
7138HandleBlinking(XtPointer closure, XtIntervalId * id GCC_UNUSED)
7139{
7140    TScreen *screen = (TScreen *) closure;
7141    Bool resume = False;
7142
7143    screen->blink_timer = 0;
7144    screen->blink_state = !screen->blink_state;
7145
7146#if OPT_BLINK_CURS
7147    if (DoStartBlinking(screen)) {
7148	if (screen->cursor_state == ON) {
7149	    if (screen->select || screen->always_highlight) {
7150		HideCursor();
7151		if (screen->cursor_state == OFF)
7152		    screen->cursor_state = BLINKED_OFF;
7153	    }
7154	} else if (screen->cursor_state == BLINKED_OFF) {
7155	    screen->cursor_state = OFF;
7156	    ShowCursor();
7157	    if (screen->cursor_state == OFF)
7158		screen->cursor_state = BLINKED_OFF;
7159	}
7160	resume = True;
7161    }
7162#endif
7163
7164#if OPT_BLINK_TEXT
7165    /*
7166     * Inspect the line on the current screen to see if any have the BLINK flag
7167     * associated with them.  Prune off any that have had the corresponding
7168     * cells reset.  If any are left, repaint those lines with ScrnRefresh().
7169     */
7170    if (!(screen->blink_as_bold)) {
7171	int row;
7172	int first_row = screen->max_row;
7173	int last_row = -1;
7174
7175	for (row = screen->max_row; row >= 0; row--) {
7176	    if (ScrnTstBlinked(screen, row)) {
7177		if (ScrnHasBlinking(screen, row)) {
7178		    resume = True;
7179		    if (row > last_row)
7180			last_row = row;
7181		    if (row < first_row)
7182			first_row = row;
7183		} else {
7184		    ScrnClrBlinked(screen, row);
7185		}
7186	    }
7187	}
7188	/*
7189	 * FIXME: this could be a little more efficient, e.g,. by limiting the
7190	 * columns which are updated.
7191	 */
7192	if (first_row <= last_row) {
7193	    ScrnRefresh(term,
7194			first_row,
7195			0,
7196			last_row + 1 - first_row,
7197			MaxCols(screen),
7198			True);
7199	}
7200    }
7201#endif
7202
7203    /*
7204     * If either the cursor or text is blinking, restart the timer.
7205     */
7206    if (resume)
7207	StartBlinking(screen);
7208}
7209#endif /* OPT_BLINK_CURS || OPT_BLINK_TEXT */
7210
7211/*
7212 * Implement soft or hard (full) reset of the VTxxx emulation.  There are a
7213 * couple of differences from real DEC VTxxx terminals (to avoid breaking
7214 * applications which have come to rely on xterm doing this):
7215 *
7216 *	+ autowrap mode should be reset (instead it's reset to the resource
7217 *	  default).
7218 *	+ the popup menu offers a choice of resetting the savedLines, or not.
7219 *	  (but the control sequence does this anyway).
7220 */
7221void
7222VTReset(XtermWidget xw, Bool full, Bool saved)
7223{
7224    TScreen *screen = &xw->screen;
7225
7226    if (!XtIsRealized((Widget) xw) || (CURRENT_EMU() != (Widget) xw)) {
7227	Bell(XkbBI_MinorError, 0);
7228	return;
7229    }
7230
7231    if (saved) {
7232	screen->savedlines = 0;
7233	ScrollBarDrawThumb(screen->scrollWidget);
7234    }
7235
7236    /* make cursor visible */
7237    screen->cursor_set = ON;
7238
7239    /* reset scrolling region */
7240    set_tb_margins(screen, 0, screen->max_row);
7241
7242    bitclr(&xw->flags, ORIGIN);
7243
7244    if_OPT_ISO_COLORS(screen, {
7245	reset_SGR_Colors(xw);
7246    });
7247
7248    /* Reset character-sets to initial state */
7249    resetCharsets(screen);
7250
7251#if OPT_MOD_FKEYS
7252    /* Reset modifier-resources to initial state */
7253    xw->keyboard.modify_now = xw->keyboard.modify_1st;
7254#endif
7255
7256    /* Reset DECSCA */
7257    bitclr(&xw->flags, PROTECTED);
7258    screen->protected_mode = OFF_PROTECT;
7259
7260    if (full) {			/* RIS */
7261	if (screen->bellOnReset)
7262	    Bell(XkbBI_TerminalBell, 0);
7263
7264	/* reset the mouse mode */
7265	screen->send_mouse_pos = MOUSE_OFF;
7266	screen->send_focus_pos = OFF;
7267	screen->waitingForTrackInfo = False;
7268	screen->eventMode = NORMAL;
7269
7270	xtermShowPointer(xw, True);
7271
7272	TabReset(xw->tabs);
7273	xw->keyboard.flags = MODE_SRM;
7274#if OPT_INITIAL_ERASE
7275	if (xw->keyboard.reset_DECBKM == 1)
7276	    xw->keyboard.flags |= MODE_DECBKM;
7277	else if (xw->keyboard.reset_DECBKM == 2)
7278#endif
7279	    if (xw->screen.backarrow_key)
7280		xw->keyboard.flags |= MODE_DECBKM;
7281	TRACE(("full reset DECBKM %s\n",
7282	       BtoS(xw->keyboard.flags & MODE_DECBKM)));
7283	update_appcursor();
7284	update_appkeypad();
7285	update_decbkm();
7286	show_8bit_control(False);
7287	reset_decudk();
7288
7289	FromAlternate(xw);
7290	ClearScreen(xw);
7291	screen->cursor_state = OFF;
7292	if (xw->flags & REVERSE_VIDEO)
7293	    ReverseVideo(xw);
7294
7295	xw->flags = xw->initflags;
7296	update_reversevideo();
7297	update_autowrap();
7298	update_reversewrap();
7299	update_autolinefeed();
7300
7301	screen->jumpscroll = !(xw->flags & SMOOTHSCROLL);
7302	update_jumpscroll();
7303
7304	if (screen->c132 && (xw->flags & IN132COLUMNS)) {
7305	    Dimension reqWidth = (80 * FontWidth(screen)
7306				  + 2 * screen->border + ScrollbarWidth(screen));
7307	    Dimension reqHeight = (FontHeight(screen)
7308				   * MaxRows(screen) + 2 * screen->border);
7309	    Dimension replyWidth;
7310	    Dimension replyHeight;
7311
7312	    TRACE(("Making resize-request to restore 80-columns %dx%d\n",
7313		   reqHeight, reqWidth));
7314	    XtMakeResizeRequest((Widget) xw,
7315				reqWidth,
7316				reqHeight,
7317				&replyWidth, &replyHeight);
7318	    TRACE(("...result %dx%d\n", replyHeight, replyWidth));
7319	    repairSizeHints();
7320	    XSync(screen->display, False);	/* synchronize */
7321	    if (XtAppPending(app_con))
7322		xevents();
7323	}
7324
7325	CursorSet(screen, 0, 0, xw->flags);
7326	CursorSave(xw);
7327    } else {			/* DECSTR */
7328	/*
7329	 * There's a tiny difference, to accommodate usage of xterm.
7330	 * We reset autowrap to the resource values rather than turning
7331	 * it off.
7332	 */
7333	xw->keyboard.flags &= ~(MODE_DECCKM | MODE_KAM | MODE_DECKPAM);
7334	bitcpy(&xw->flags, xw->initflags, WRAPAROUND | REVERSEWRAP);
7335	bitclr(&xw->flags, INSERT | INVERSE | BOLD | BLINK | UNDERLINE | INVISIBLE);
7336	if_OPT_ISO_COLORS(screen, {
7337	    reset_SGR_Colors(xw);
7338	});
7339	update_appcursor();
7340	update_autowrap();
7341	update_reversewrap();
7342
7343	CursorSave(xw);
7344	screen->sc[screen->alternate != False].row =
7345	    screen->sc[screen->alternate != False].col = 0;
7346    }
7347    longjmp(vtjmpbuf, 1);	/* force ground state in parser */
7348}
7349
7350/*
7351 * set_character_class - takes a string of the form
7352 *
7353 *   low[-high]:val[,low[-high]:val[...]]
7354 *
7355 * and sets the indicated ranges to the indicated values.
7356 */
7357static int
7358set_character_class(char *s)
7359{
7360    int i;			/* iterator, index into s */
7361    int len;			/* length of s */
7362    int acc;			/* accumulator */
7363    int low, high;		/* bounds of range [0..127] */
7364    int base;			/* 8, 10, 16 (octal, decimal, hex) */
7365    int numbers;		/* count of numbers per range */
7366    int digits;			/* count of digits in a number */
7367    static char *errfmt = "%s:  %s in range string \"%s\" (position %d)\n";
7368
7369    if (!s || !s[0])
7370	return -1;
7371
7372    base = 10;			/* in case we ever add octal, hex */
7373    low = high = -1;		/* out of range */
7374
7375    for (i = 0, len = strlen(s), acc = 0, numbers = digits = 0;
7376	 i < len; i++) {
7377	Char c = s[i];
7378
7379	if (isspace(c)) {
7380	    continue;
7381	} else if (isdigit(c)) {
7382	    acc = acc * base + (c - '0');
7383	    digits++;
7384	    continue;
7385	} else if (c == '-') {
7386	    low = acc;
7387	    acc = 0;
7388	    if (digits == 0) {
7389		fprintf(stderr, errfmt, ProgramName, "missing number", s, i);
7390		return (-1);
7391	    }
7392	    digits = 0;
7393	    numbers++;
7394	    continue;
7395	} else if (c == ':') {
7396	    if (numbers == 0)
7397		low = acc;
7398	    else if (numbers == 1)
7399		high = acc;
7400	    else {
7401		fprintf(stderr, errfmt, ProgramName, "too many numbers",
7402			s, i);
7403		return (-1);
7404	    }
7405	    digits = 0;
7406	    numbers++;
7407	    acc = 0;
7408	    continue;
7409	} else if (c == ',') {
7410	    /*
7411	     * now, process it
7412	     */
7413
7414	    if (high < 0) {
7415		high = low;
7416		numbers++;
7417	    }
7418	    if (numbers != 2) {
7419		fprintf(stderr, errfmt, ProgramName, "bad value number",
7420			s, i);
7421	    } else if (SetCharacterClassRange(low, high, acc) != 0) {
7422		fprintf(stderr, errfmt, ProgramName, "bad range", s, i);
7423	    }
7424
7425	    low = high = -1;
7426	    acc = 0;
7427	    digits = 0;
7428	    numbers = 0;
7429	    continue;
7430	} else {
7431	    fprintf(stderr, errfmt, ProgramName, "bad character", s, i);
7432	    return (-1);
7433	}			/* end if else if ... else */
7434
7435    }
7436
7437    if (low < 0 && high < 0)
7438	return (0);
7439
7440    /*
7441     * now, process it
7442     */
7443
7444    if (high < 0)
7445	high = low;
7446    if (numbers < 1 || numbers > 2) {
7447	fprintf(stderr, errfmt, ProgramName, "bad value number", s, i);
7448    } else if (SetCharacterClassRange(low, high, acc) != 0) {
7449	fprintf(stderr, errfmt, ProgramName, "bad range", s, i);
7450    }
7451
7452    return (0);
7453}
7454
7455/* ARGSUSED */
7456static void
7457HandleKeymapChange(Widget w,
7458		   XEvent * event GCC_UNUSED,
7459		   String * params,
7460		   Cardinal *param_count)
7461{
7462    static XtTranslations keymap, original;
7463    static XtResource key_resources[] =
7464    {
7465	{XtNtranslations, XtCTranslations, XtRTranslationTable,
7466	 sizeof(XtTranslations), 0, XtRTranslationTable, (XtPointer) NULL}
7467    };
7468    char mapName[1000];
7469    char mapClass[1000];
7470    char *pmapName;
7471    char *pmapClass;
7472    size_t len;
7473
7474    if (*param_count != 1)
7475	return;
7476
7477    if (original == NULL)
7478	original = w->core.tm.translations;
7479
7480    if (strcmp(params[0], "None") == 0) {
7481	XtOverrideTranslations(w, original);
7482	return;
7483    }
7484
7485    len = strlen(params[0]) + 7;
7486
7487    pmapName = (char *) MyStackAlloc(len, mapName);
7488    pmapClass = (char *) MyStackAlloc(len, mapClass);
7489    if (pmapName == NULL
7490	|| pmapClass == NULL)
7491	SysError(ERROR_KMMALLOC1);
7492
7493    (void) sprintf(pmapName, "%sKeymap", params[0]);
7494    (void) strcpy(pmapClass, pmapName);
7495    if (islower(CharOf(pmapClass[0])))
7496	pmapClass[0] = toupper(CharOf(pmapClass[0]));
7497    XtGetSubresources(w, (XtPointer) &keymap, pmapName, pmapClass,
7498		      key_resources, (Cardinal) 1, NULL, (Cardinal) 0);
7499    if (keymap != NULL)
7500	XtOverrideTranslations(w, keymap);
7501
7502    MyStackFree(pmapName, mapName);
7503    MyStackFree(pmapClass, mapClass);
7504}
7505
7506/* ARGSUSED */
7507static void
7508HandleBell(Widget w GCC_UNUSED,
7509	   XEvent * event GCC_UNUSED,
7510	   String * params,	/* [0] = volume */
7511	   Cardinal *param_count)	/* 0 or 1 */
7512{
7513    int percent = (*param_count) ? atoi(params[0]) : 0;
7514
7515    Bell(XkbBI_TerminalBell, percent);
7516}
7517
7518/* ARGSUSED */
7519static void
7520HandleVisualBell(Widget w GCC_UNUSED,
7521		 XEvent * event GCC_UNUSED,
7522		 String * params GCC_UNUSED,
7523		 Cardinal *param_count GCC_UNUSED)
7524{
7525    VisualBell();
7526}
7527
7528/* ARGSUSED */
7529static void
7530HandleIgnore(Widget w,
7531	     XEvent * event,
7532	     String * params GCC_UNUSED,
7533	     Cardinal *param_count GCC_UNUSED)
7534{
7535    if (IsXtermWidget(w)) {
7536	/* do nothing, but check for funny escape sequences */
7537	(void) SendMousePosition((XtermWidget) w, event);
7538    }
7539}
7540
7541/* ARGSUSED */
7542static void
7543DoSetSelectedFont(Widget w,
7544		  XtPointer client_data GCC_UNUSED,
7545		  Atom * selection GCC_UNUSED,
7546		  Atom * type,
7547		  XtPointer value,
7548		  unsigned long *length,
7549		  int *format)
7550{
7551    if (!IsXtermWidget(w) || *type != XA_STRING || *format != 8) {
7552	Bell(XkbBI_MinorError, 0);
7553    } else {
7554	Boolean failed = False;
7555	XtermWidget xw = (XtermWidget) w;
7556	int oldFont = xw->screen.menu_font_number;
7557	char *save = xw->screen.MenuFontName(fontMenu_fontsel);
7558	char *val;
7559	char *test = 0;
7560	char *used = 0;
7561	unsigned len = *length;
7562	unsigned tst;
7563
7564	/*
7565	 * Some versions of X deliver null-terminated selections, some do not.
7566	 */
7567	for (tst = 0; tst < len; ++tst) {
7568	    if (((char *) value)[tst] == '\0') {
7569		len = tst;
7570		break;
7571	    }
7572	}
7573
7574	if (len > 0 && (val = TypeMallocN(char, len + 1)) != 0) {
7575	    memcpy(val, value, len);
7576	    val[len] = '\0';
7577	    used = x_strtrim(val);
7578	    TRACE(("DoSetSelectedFont(%s)\n", val));
7579	    /* Do some sanity checking to avoid sending a long selection
7580	       back to the server in an OpenFont that is unlikely to succeed.
7581	       XLFD allows up to 255 characters and no control characters;
7582	       we are a little more liberal here. */
7583	    if (len < 1000
7584		&& !strchr(val, '\n')
7585		&& (test = x_strdup(val)) != 0) {
7586		xw->screen.MenuFontName(fontMenu_fontsel) = test;
7587		if (!xtermLoadFont(term,
7588				   xtermFontName(val),
7589				   True,
7590				   fontMenu_fontsel)) {
7591		    failed = True;
7592		    free(test);
7593		    xw->screen.MenuFontName(fontMenu_fontsel) = save;
7594		}
7595	    } else {
7596		failed = True;
7597	    }
7598	    if (failed) {
7599		(void) xtermLoadFont(term,
7600				     xtermFontName(xw->screen.MenuFontName(oldFont)),
7601				     True,
7602				     oldFont);
7603		Bell(XkbBI_MinorError, 0);
7604	    }
7605	    if (used != val)
7606		free(used);
7607	    free(val);
7608	}
7609    }
7610}
7611
7612void
7613FindFontSelection(XtermWidget xw, const char *atom_name, Bool justprobe)
7614{
7615    static AtomPtr *atoms;
7616    static int atomCount = 0;
7617    AtomPtr *pAtom;
7618    int a;
7619    Atom target;
7620
7621    if (!atom_name)
7622	atom_name = (xw->screen.mappedSelect
7623		     ? xw->screen.mappedSelect[0]
7624		     : "PRIMARY");
7625    TRACE(("FindFontSelection(%s)\n", atom_name));
7626
7627    for (pAtom = atoms, a = atomCount; a; a--, pAtom++) {
7628	if (strcmp(atom_name, XmuNameOfAtom(*pAtom)) == 0)
7629	    break;
7630    }
7631    if (!a) {
7632	atoms = (AtomPtr *) XtRealloc((char *) atoms,
7633				      sizeof(AtomPtr) * (atomCount + 1));
7634	*(pAtom = &atoms[atomCount++]) = XmuMakeAtom(atom_name);
7635    }
7636
7637    target = XmuInternAtom(XtDisplay(xw), *pAtom);
7638    if (justprobe) {
7639	xw->screen.MenuFontName(fontMenu_fontsel) =
7640	    XGetSelectionOwner(XtDisplay(xw), target) ? _Font_Selected_ : 0;
7641    } else {
7642	XtGetSelectionValue((Widget) xw, target, XA_STRING,
7643			    DoSetSelectedFont, NULL,
7644			    XtLastTimestampProcessed(XtDisplay(xw)));
7645    }
7646    return;
7647}
7648
7649void
7650set_cursor_gcs(XtermWidget xw)
7651{
7652    TScreen *screen = &(xw->screen);
7653    VTwin *win = WhichVWin(screen);
7654
7655    Pixel cc = T_COLOR(screen, TEXT_CURSOR);
7656    Pixel fg = T_COLOR(screen, TEXT_FG);
7657    Pixel bg = T_COLOR(screen, TEXT_BG);
7658    Boolean changed = False;
7659
7660    /*
7661     * Let's see, there are three things that have "color":
7662     *
7663     *     background
7664     *     text
7665     *     cursorblock
7666     *
7667     * And, there are four situations when drawing a cursor, if we decide
7668     * that we like have a solid block of cursor color with the letter
7669     * that it is highlighting shown in the background color to make it
7670     * stand out:
7671     *
7672     *     selected window, normal video - background on cursor
7673     *     selected window, reverse video - foreground on cursor
7674     *     unselected window, normal video - foreground on background
7675     *     unselected window, reverse video - background on foreground
7676     *
7677     * Since the last two are really just normalGC and reverseGC, we only
7678     * need two new GC's.  Under monochrome, we get the same effect as
7679     * above by setting cursor color to foreground.
7680     */
7681
7682    TRACE(("set_cursor_gcs cc=%#lx, fg=%#lx, bg=%#lx\n", cc, fg, bg));
7683    if (win != 0 && (cc != bg)) {
7684	/* set the fonts to the current one */
7685	setCgsFont(xw, win, gcVTcursNormal, 0);
7686	setCgsFont(xw, win, gcVTcursFilled, 0);
7687	setCgsFont(xw, win, gcVTcursReverse, 0);
7688	setCgsFont(xw, win, gcVTcursOutline, 0);
7689
7690	/* we have a colored cursor */
7691	setCgsFore(xw, win, gcVTcursNormal, fg);
7692	setCgsBack(xw, win, gcVTcursNormal, cc);
7693
7694	setCgsFore(xw, win, gcVTcursFilled, cc);
7695	setCgsBack(xw, win, gcVTcursFilled, fg);
7696
7697	if (screen->always_highlight) {
7698	    /* both GC's use the same color */
7699	    setCgsFore(xw, win, gcVTcursReverse, bg);
7700	    setCgsBack(xw, win, gcVTcursReverse, cc);
7701
7702	    setCgsFore(xw, win, gcVTcursOutline, bg);
7703	    setCgsBack(xw, win, gcVTcursOutline, cc);
7704	} else {
7705	    setCgsFore(xw, win, gcVTcursReverse, bg);
7706	    setCgsBack(xw, win, gcVTcursReverse, cc);
7707
7708	    setCgsFore(xw, win, gcVTcursOutline, cc);
7709	    setCgsBack(xw, win, gcVTcursOutline, bg);
7710	}
7711	changed = True;
7712    }
7713
7714    if (changed) {
7715	TRACE(("...set_cursor_gcs - done\n"));
7716    }
7717}
7718
7719#ifdef NO_LEAKS
7720void
7721noleaks_charproc(void)
7722{
7723    if (v_buffer != 0)
7724	free(v_buffer);
7725}
7726#endif
7727