Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / lib / DtTerm / TermPrim / TermPrim.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 #ifndef lint
24 #ifdef  VERBOSE_REV_INFO
25 static char rcs_id[] = "$TOG: TermPrim.c /main/15 1999/10/14 16:35:04 mgreess $";
26 #endif  /* VERBOSE_REV_INFO */
27 #endif  /* lint */
28
29 /*                                                                      *
30  * (c) Copyright 1993, 1994, 1996 Hewlett-Packard Company               *
31  * (c) Copyright 1993, 1994, 1996 International Business Machines Corp. *
32  * (c) Copyright 1993, 1994, 1996 Sun Microsystems, Inc.                *
33  * (c) Copyright 1993, 1994, 1996 Novell, Inc.                          *
34  * (c) Copyright 1995, 1996 Digital Equipment Corporation.              *
35  * (c) Copyright 1996 FUJITSU LIMITED.                                  *
36  * (c) Copyright 1996 Hitachi.                                          *
37  */
38
39 extern char _DtTermPrimPullInTermWhatString[];
40 static char *termWhatString = _DtTermPrimPullInTermWhatString;
41 extern char * _DtTermPrimGetMessage( char *filename, int set, int n, char *s );
42
43 #include <stdio.h>
44 #include <unistd.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <X11/X.h>
48 #include <X11/keysym.h>
49 #include <Xm/MessageB.h>
50 #include <Xm/XmP.h>
51 #include <Xm/DisplayP.h>
52 #include <Xm/VirtKeys.h>
53 #include <Xm/MwmUtil.h>
54 #include "TermHeader.h"
55 #include "TermPrimOSDepI.h"             /* for SETENV_LINES_AND_COLS    */
56 #include "TermPrimI.h"
57 #include "TermPrimP.h"
58 #include "TermPrimBufferP.h"
59 #include "TermPrimAction.h"
60 #include "TermPrimParser.h"
61 #include "TermPrimParseTable.h"
62 #include "TermPrimPendingTextP.h"
63 #include "TermPrimRenderFont.h"
64 #include "TermPrimRenderFontSet.h"
65 #include "TermPrimSelectP.h"
66 #include "TermPrimSetUtmp.h"
67 #include "TermPrimUtil.h"     
68 #include "TermPrimDebug.h"
69 #include "TermPrimWMProtocols.h"
70 #include "TermPrimSetPty.h"
71 #include <Xm/RepType.h>
72 #include "TermPrimRepType.h"
73 #include "TermPrimMessageCatI.h"
74 #include <X11/CoreP.h>
75 #include <Xm/ManagerP.h>
76 #include <signal.h>
77 #include <ctype.h>
78 #include <nl_types.h>
79 #if defined(linux) || defined(hpV4)
80 # include <sys/types.h> /* For FD_* macros. */
81 # include <sys/time.h> /* For select() prototype. */
82 #else
83 # include <sys/select.h>
84 #endif
85
86 extern void TermReadKey(Widget w, XEvent *event, String *params,
87         Cardinal *num_params);
88 static void ClassInitialize(void);
89 static void ClassPartInitialize(WidgetClass wc);
90 static void initializeKeyboard(DtTermPrimData tpd);
91 static void initializeModes(DtTermPrimData tpd);
92 static void initializeStraps(DtTermPrimData tpd);
93 static void Initialize(Widget rw, Widget nw, Arg *args, Cardinal *num_args);
94 static void Resize(Widget w);
95 static void Redisplay(Widget w, XEvent *event, Region region);
96 static Boolean SetValues(Widget cw, Widget rw, Widget nw, ArgList args,
97         Cardinal *num_args);
98 static void Realize(Widget w, XtValueMask *p_valueMask,
99         XSetWindowAttributes *attributes);
100 static void Destroy(Widget w);
101 static void readPty(XtPointer client_data, int *source,
102         XtInputId *id);
103 static void handleKeyEvents(Widget w, XtPointer closure, XEvent *event,
104         Boolean *cont);
105 static void handleButtonEvents(Widget w, XtPointer closure, XEvent *event,
106         Boolean *cont);
107 static void handleNonMaskableEvents(Widget w, XtPointer eventData,
108         XEvent *event, Boolean *cont);
109 static void handlePropertyChangeEvents(Widget w, XtPointer eventData,
110         XEvent *event, Boolean *cont);
111 static void handleProcessStructureNotifyEvent(Widget w, XtPointer eventData,
112         XEvent *event, Boolean *cont);
113 static Boolean moreInput(int pty);
114 static void CapsLockUpdate(Widget w, Boolean capsLock);
115 static void InitializeVerticalScrollBar(Widget w, Boolean initCallbacks);
116 static void VerticalScrollBarCallback(Widget w, XtPointer client_data,
117         XtPointer call_data);
118 static void setThickness(Widget widget, int offset, XrmValue *value);
119
120 /*
121  * on the spot callbacks
122  */
123 static int PreeditStart(
124     XIC xic,
125     XPointer client_data,
126     XPointer call_data);
127
128 static void PreeditDone(
129     XIC xic,
130     XPointer client_data,
131     XPointer call_data);
132
133 static void PreeditDraw(
134     XIC xic,
135     XPointer client_data,
136     XIMPreeditDrawCallbackStruct *call_data);
137
138 static void PreeditCaret(
139     XIC xic,
140     XPointer client_data,
141     XIMPreeditCaretCallbackStruct *call_data);
142
143
144 /* action list for class: Term... */
145
146 static XtActionsRec actionsList[] = {
147     {"self-insert",             _DtTermPrimActionKeyInput},
148     {"insert",                  _DtTermPrimActionKeyInput},
149     {"key-release",             _DtTermPrimActionKeyRelease},
150     {"grab-focus",              _DtTermPrimSelectGrabFocus},
151     {"select-adjust",           _DtTermPrimSelectExtend},
152     {"extend-end",              _DtTermPrimSelectExtendEnd},
153     {"extend-start",            _DtTermPrimSelectExtendStart},
154     {"copy-to",                 _DtTermPrimSelectInsert},
155     {"copy-clipboard",          _DtTermPrimSelectCopyClipboardEventIF},
156     {"paste-clipboard",         _DtTermPrimSelectPasteClipboardEventIF},
157     {"process-bdrag",           _DtTermPrimSelectProcessBDrag},
158     {"leave",                   _DtTermPrimActionLeave},
159     {"enter",                   _DtTermPrimActionEnter},
160     {"focus-in",                _DtTermPrimActionFocusIn},
161     {"focus-out",               _DtTermPrimActionFocusOut},
162     {"keymap",                  _DtTermPrimActionKeymap},
163     {"redraw-display",          _DtTermPrimActionRedrawDisplay},
164     {"return",                  _DtTermPrimActionReturn},
165     {"stop",                    _DtTermPrimActionStop},
166     {"string",                  _DtTermPrimActionString},
167     {"tab",                     _DtTermPrimActionTab},
168     {"select-page",             _DtTermPrimSelectPage},
169     {"select-all",              _DtTermPrimSelectAll},
170     {"process-cancel",          _DtTermPrimSelectProcessCancel}
171 };
172
173 #define defaultColumns  80
174 #define defaultRows     24
175
176 /* the resource list for Term... */
177 static XtResource resources[] =
178 {
179     {
180         DtNcharCursorStyle, DtCCharCursorStyle, DtRDtTermCharCursorStyle,
181         sizeof(unsigned char),
182         XtOffsetOf(struct _DtTermPrimitiveRec, term.charCursorStyle),
183         XmRImmediate, (XtPointer) DtTERM_CHAR_CURSOR_BOX
184     },
185     {
186         DtNconsoleMode, DtCConsoleMode, XmRBoolean, sizeof(Boolean),
187         XtOffsetOf(struct _DtTermPrimitiveRec, term.consoleMode),
188         XmRImmediate, (XtPointer) False
189     },
190     {
191         DtNblinkRate, DtCBlinkRate, XmRInt, sizeof(int),
192         XtOffsetOf(struct _DtTermPrimitiveRec, term.blinkRate),
193         XmRImmediate, (XtPointer) 250
194     },
195     {
196         DtNbaseWidth, DtCBaseWidth, XmRInt, sizeof(int),
197         XtOffsetOf(struct _DtTermPrimitiveRec, term.baseWidth),
198         XmRImmediate, (XtPointer) 0
199     },
200     {
201         DtNbaseHeight, DtCBaseHeight, XmRInt, sizeof(int),
202         XtOffsetOf(struct _DtTermPrimitiveRec, term.baseHeight),
203         XmRImmediate, (XtPointer) 0
204     },
205     {
206         DtNwidthInc, DtCWidthInc, XmRInt, sizeof(int),
207         XtOffsetOf(struct _DtTermPrimitiveRec, term.widthInc),
208         XmRImmediate, (XtPointer) 0
209     },
210     {
211         DtNheightInc, DtCHeightInc, XmRInt, sizeof(int),
212         XtOffsetOf(struct _DtTermPrimitiveRec, term.heightInc),
213         XmRImmediate, (XtPointer) 0
214     },
215     {
216         DtNtermDevice, DtCTermDevice, XmRInt, sizeof(int),
217         XtOffsetOf(struct _DtTermPrimitiveRec, term.pty),
218         XmRImmediate, (XtPointer) -1
219     },
220     {
221         DtNtermDeviceAllocate, DtCTermDeviceAllocate, XmRBoolean,
222         sizeof(Boolean),
223         XtOffsetOf(struct _DtTermPrimitiveRec, term.ptyAllocate),
224         XmRImmediate, (XtPointer) True
225     },
226     {
227         DtNtermSlaveName, DtCTermSlaveName, XmRString, sizeof(char *),
228         XtOffsetOf(struct _DtTermPrimitiveRec, term.ptySlaveName),
229         XmRImmediate, (XtPointer) NULL
230     },
231     {
232         DtNsaveLines, DtCSaveLines, XmRString, sizeof(char *),
233         XtOffsetOf(struct _DtTermPrimitiveRec, term.saveLines),
234         XmRImmediate, (XtPointer) "4s"
235     },
236     {
237         DtNrows, DtCRows, XmRShort, sizeof(short),
238         XtOffsetOf(struct _DtTermPrimitiveRec, term.rows),
239         XmRImmediate, (XtPointer) defaultRows
240     },
241     {
242         DtNcolumns, DtCColumns, XmRShort, sizeof(short),
243         XtOffsetOf(struct _DtTermPrimitiveRec, term.columns),
244         XmRImmediate, (XtPointer) defaultColumns
245     },
246 #ifdef  HPVUE
247     {
248         DtNbackgroundIsSelect, DtCBackgroundIsSelect, XmRBoolean,
249         sizeof(Boolean),
250         XtOffsetOf(struct _DtTermPrimitiveRec, term.backgroundIsSelect),
251         XtRImmediate, (XtPointer) True
252     },
253 #else   /* HPVUE */
254     {
255         DtNbackgroundIsSelect, DtCBackgroundIsSelect, XmRBoolean,
256         sizeof(Boolean),
257         XtOffsetOf(struct _DtTermPrimitiveRec, term.backgroundIsSelect),
258         XtRImmediate, (XtPointer) False
259     },
260 #endif  /* HPVUE */
261     {
262         XmNtraversalOn, XmCTraversalOn, XmRBoolean, sizeof(Boolean),
263         XtOffsetOf(struct _DtTermPrimitiveRec, primitive.traversal_on),
264         XtRImmediate, (XtPointer) True
265     },
266     {
267         DtNshadowType, DtCShadowType, XmRShadowType, sizeof (unsigned char),
268         XtOffsetOf( struct _DtTermPrimitiveRec, term.shadowType),
269         XmRImmediate, (XtPointer) DtSHADOW_IN
270     },
271     {
272         XmNshadowThickness, XmCShadowThickness, XmRHorizontalDimension,
273         sizeof (Dimension),
274         XtOffsetOf( struct _DtTermPrimitiveRec, primitive.shadow_thickness),
275         XmRCallProc, (XtPointer) setThickness
276     },
277     {
278         DtNmarginWidth, DtCMarginWidth, XmRHorizontalDimension,
279         sizeof (Dimension),
280         XtOffsetOf( struct _DtTermPrimitiveRec, term.marginWidth),
281         XmRImmediate, (XtPointer) 2
282     },
283     {
284         DtNmarginHeight, DtCMarginHeight, XmRVerticalDimension,
285         sizeof (Dimension),
286         XtOffsetOf( struct _DtTermPrimitiveRec, term.marginHeight),
287         XmRImmediate, (XtPointer) 2
288     },
289     {
290         DtNuserBoldFont, DtCUserBoldFont, XmRFontList,
291         sizeof(XmFontList),
292         XtOffsetOf( struct _DtTermPrimitiveRec, term.boldFontList),
293         XmRImmediate, (XtPointer) NULL
294     },
295     {
296         DtNuserFont, DtCUserFont, XmRFontList,
297         sizeof(XmFontList),
298         XtOffsetOf( struct _DtTermPrimitiveRec, term.fontList),
299         XmRImmediate, (XtPointer) NULL
300     },
301     {
302         XmNhighlightThickness, XmCHighlightThickness, XmRHorizontalDimension,
303         sizeof (Dimension),
304         XtOffsetOf( struct _DtTermPrimitiveRec, primitive.highlight_thickness),
305         XmRCallProc, (XtPointer) setThickness
306     },
307     {
308         DtNvisualBell, DtCVisualBell, XmRBoolean, sizeof(Boolean),
309         XtOffsetOf( struct _DtTermPrimitiveRec, term.visualBell),
310         XtRImmediate, (XtPointer) False
311     },
312     {
313         DtNmarginBell, DtCMarginBell, XmRBoolean, sizeof(Boolean),
314         XtOffsetOf( struct _DtTermPrimitiveRec, term.marginBell),
315         XtRImmediate, (XtPointer) False
316     },
317     {
318         DtNnMarginBell, DtCNMarginBell, XmRInt, sizeof(int),
319         XtOffsetOf( struct _DtTermPrimitiveRec, term.nMarginBell),
320         XtRImmediate, (XtPointer) 8
321     },
322     {
323         DtNjumpScroll, DtCJumpScroll, XmRBoolean, sizeof(Boolean),
324         XtOffsetOf( struct _DtTermPrimitiveRec, term.jumpScroll),
325         XtRImmediate, (XtPointer) True
326     },
327     {
328         DtNsubprocessLoginShell, DtCSubprocessLoginShell, XmRBoolean,
329         sizeof(Boolean),
330         XtOffsetOf( struct _DtTermPrimitiveRec, term.subprocessLoginShell),
331         XtRImmediate, (XtPointer) False
332     },
333     {
334         DtNsubprocessTerminationCallback, DtCCallback, XmRCallback,
335         sizeof(XtCallbackList),
336         XtOffsetOf( struct _DtTermPrimitiveRec, term.subprocessTerminationCallback),
337         XmRPointer, (XtPointer) NULL
338     },
339     {
340         DtNstatusChangeCallback, DtCCallback, XmRCallback,
341         sizeof(XtCallbackList),
342         XtOffsetOf( struct _DtTermPrimitiveRec, term.statusChangeCallback),
343         XmRPointer, (XtPointer) NULL
344     },
345     {
346         DtNoutputLogCallback, DtCCallback, XmRCallback,
347         sizeof(XtCallbackList),
348         XtOffsetOf( struct _DtTermPrimitiveRec, term.outputLogCallback),
349         XmRPointer, (XtPointer) NULL
350     },
351     {
352         DtNinputVerifyCallback, DtCCallback, XmRCallback,
353         sizeof(XtCallbackList),
354         XtOffsetOf( struct _DtTermPrimitiveRec, term.inputVerifyCallback),
355         XmRPointer, (XtPointer) NULL
356     },
357     {
358         DtNverticalScrollBar, DtCVerticalScrollBar, XmRWidget, sizeof(Widget),
359         XtOffsetOf( struct _DtTermPrimitiveRec, term.verticalScrollBar),
360         XmRImmediate, (XtPointer) NULL
361     },
362     {
363         DtNsubprocessPid, DtCSubprocessPid, XmRInt, sizeof(int),
364         XtOffsetOf( struct _DtTermPrimitiveRec, term.subprocessPid),
365         XtRImmediate, (XtPointer) -1
366     },
367     {
368         DtNsubprocessExec, DtCSubprocessExec, XmRBoolean, sizeof(Boolean),
369         XtOffsetOf( struct _DtTermPrimitiveRec, term.subprocessExec),
370         XmRImmediate, (XtPointer) True
371     },
372     {
373         DtNsubprocessTerminationCatch, DtCSubprocessTerminationCatch,
374         XmRBoolean, sizeof(Boolean),
375         XtOffsetOf( struct _DtTermPrimitiveRec, term.subprocessTerminationCatch),
376         XmRImmediate, (XtPointer) True
377     },
378     {
379         DtNsubprocessCmd, DtCSubprocessCmd, XmRString, sizeof(char *),
380         XtOffsetOf( struct _DtTermPrimitiveRec, term.subprocessCmd),
381         XtRImmediate, (XtPointer) NULL
382     },
383     {
384         DtNsubprocessArgv, DtCSubprocessArgv, XtRStringArray, sizeof(String *),
385         XtOffsetOf( struct _DtTermPrimitiveRec, term.subprocessArgv),
386         XmRImmediate, (XtPointer) NULL
387     },
388     {
389         DtNemulationId, DtCEmulationId, XmRString, sizeof(char *),
390         XtOffsetOf( struct _DtTermPrimitiveRec, term.emulationId),
391         XtRImmediate, (XtPointer) "DtTermPrimitiveWidget"
392     },
393     {
394         DtNtermId, DtCTermId, XmRString, sizeof(char *),
395         XtOffsetOf( struct _DtTermPrimitiveRec, term.termId),
396         XtRImmediate, (XtPointer) "dumb"
397     },
398     {
399         DtNtermName, DtCTermName, XmRString, sizeof(char *),
400         XtOffsetOf( struct _DtTermPrimitiveRec, term.termName),
401         XtRImmediate, (XtPointer) "dumb"
402     },
403     {
404         DtNttyModes, DtCTtyModes, XmRString, sizeof(char *),
405         XtOffsetOf( struct _DtTermPrimitiveRec, term.ttyModes),
406         XtRImmediate, (XtPointer) NULL
407     },
408     {
409         DtNcsWidth, DtCCsWidth, XmRString, sizeof(char *),
410         XtOffsetOf( struct _DtTermPrimitiveRec, term.csWidth),
411         XtRImmediate, (XtPointer) NULL
412     },
413     {
414         DtNkshMode, DtCKshMode, XmRBoolean, sizeof(Boolean),
415         XtOffsetOf( struct _DtTermPrimitiveRec, term.kshMode),
416         XtRImmediate, (XtPointer) False
417     },
418     {
419         DtNpointerBlank, DtCPointerBlank, XmRBoolean, sizeof(Boolean),
420         XtOffsetOf( struct _DtTermPrimitiveRec, term.pointerBlank),
421         XtRImmediate, (XtPointer) False
422     },
423     {
424         DtNpointerBlankDelay, DtCPointerBlankDelay, XmRInt, sizeof(int),
425         XtOffsetOf( struct _DtTermPrimitiveRec, term.pointerBlankDelay),
426         XtRImmediate, (XtPointer) 2
427     },
428     {
429         DtNpointerShape, DtCCursor, XtRCursor, sizeof(Cursor),
430         XtOffsetOf( struct _DtTermPrimitiveRec, term.pointerShape),
431         XtRString,  (XtPointer) "xterm"
432     },
433     {
434         DtNpointerColor, DtCForeground, XtRPixel, sizeof(Pixel), 
435         XtOffsetOf( struct _DtTermPrimitiveRec, term.pointerColor),
436         XtRString,  (XtPointer) "XtDefaultForeground"
437     },
438     {
439         DtNpointerColorBackground, DtCBackground, XtRPixel, sizeof(Pixel),
440         XtOffsetOf( struct _DtTermPrimitiveRec, term.pointerColorBackground),
441         XtRString,  (XtPointer) "XtDefaultBackground"
442     },
443     {
444         DtNmapOnOutput, DtCMapOnOutput , XmRBoolean, sizeof(Boolean),
445         XtOffsetOf( struct _DtTermPrimitiveRec, term.mapOnOutput ),
446         XtRImmediate, (XtPointer) False
447     },
448     {
449         DtNmapOnOutputDelay, DtCMapOnOutputDelay, XmRInt, sizeof(int),       
450         XtOffsetOf( struct _DtTermPrimitiveRec, term.mapOnOutputDelay ),
451         XtRImmediate, (XtPointer) 0
452     },
453     {
454         DtNlogging, DtCLogging , XmRBoolean, sizeof(Boolean),
455         XtOffsetOf( struct _DtTermPrimitiveRec, term.logging ),
456         XtRImmediate, (XtPointer) False
457     },
458     {
459         DtNlogFile, DtCLogFile , XmRString, sizeof(char *),   
460         XtOffsetOf( struct _DtTermPrimitiveRec, term.logFile ),
461         XtRImmediate, (XtPointer) NULL
462     },
463     {
464         DtNlogInhibit, DtCLogInhibit , XmRBoolean, sizeof(Boolean), 
465         XtOffsetOf( struct _DtTermPrimitiveRec, term.logInhibit ),
466         XtRImmediate, (XtPointer) False
467     },
468     {
469         DtNreverseVideo, DtCReverseVideo, XmRBoolean, sizeof(Boolean),
470         XtOffsetOf( struct _DtTermPrimitiveRec, term.reverseVideo ),
471         XtRImmediate, (XtPointer) False
472     },
473     {
474         DtNallowSendEvents , DtCAllowSendEvents , XmRBoolean, sizeof(Boolean),
475         XtOffsetOf(struct _DtTermPrimitiveRec, term.allowSendEvents),
476         XtRImmediate, (XtPointer) False
477     }
478 };
479
480 /*
481  * Goofy debug'ed code by HP.
482  * IBM's JP kbd accepts Shift+KP_Multiply as a valid key sequence.
483  * I don't know why HP added non-exposed(internal) Xt's action ???
484  * Anyway, remove KP_Multiply entry from defaultTranslations[]
485  */
486 static char defaultTranslations[] = "\
487         Ctrl<Key>Cancel:        stop(long)\n\
488         ~Ctrl<Key>Cancel:       stop()\n\
489         <Key>Tab:               tab()\n\
490         <Key>KP_Tab:            tab()\n\
491         <KeyRelease>:           key-release()\n\
492         <KeyPress>:             insert()\n\
493         ~Shift~Ctrl<Btn1Down>:  grab-focus()\n\
494         Shift~Ctrl<Btn1Down>:   extend-start()\n\
495         ~Ctrl<Btn1Motion>:      select-adjust()\n\
496         ~Ctrl<Btn1Up>:          extend-end()\n\
497         ~Shift<Btn2Down>:       process-bdrag()\n\
498         ~Shift<Btn2Up>:         copy-to()\n\
499         <EnterWindow>:          enter()\n\
500         <LeaveWindow>:          leave()\n\
501         <FocusIn>:              focus-in()\n\
502         <FocusOut>:             focus-out()\n\
503         ";
504
505
506 /* global class record for instances of class: TermPrim
507  */
508
509 externaldef(termclassrec) DtTermPrimitiveClassRec dtTermPrimitiveClassRec =
510 {
511     /* core class record */
512     {
513         /* superclass           */      (WidgetClass) &xmPrimitiveClassRec,
514         /* class_name           */      "DtTermPrim",
515         /* widget_size          */      sizeof(DtTermPrimitiveRec),
516         /* class_initialize     */      ClassInitialize,
517         /* class_part_init      */      ClassPartInitialize,
518         /* class_inited         */      FALSE,
519         /* initialize           */      Initialize,
520         /* initialize_hook      */      (XtArgsProc) NULL,
521         /* realize              */      Realize,
522         /* actions              */      actionsList,
523         /* num_actions          */      XtNumber(actionsList),
524         /* resources            */      resources,
525         /* num_resources        */      XtNumber(resources),
526         /* xrm_class            */      NULLQUARK,
527         /* compress_motion      */      TRUE,
528         /* compress_exposure    */      FALSE,
529         /* compress_enterlv     */      TRUE,
530         /* visible_interest     */      TRUE,
531         /* destroy              */      Destroy,
532         /* resize               */      Resize,
533         /* expose               */      Redisplay,
534         /* set_values           */      SetValues,
535         /* set_values_hook      */      (XtArgsFunc) NULL,
536         /* set_values_almost    */      XtInheritSetValuesAlmost,
537         /* get_values_hook      */      (XtArgsProc) NULL,
538         /* accept_focus         */      (XtAcceptFocusProc) NULL,
539         /* version              */      XtVersion,
540         /* callback_private     */      (XtPointer) NULL,
541         /* tm_table             */      defaultTranslations,
542         /* query_geometry       */      (XtGeometryHandler) NULL,
543         /* display_accelerator  */      (XtStringProc) NULL,
544         /* extension            */      (XtPointer) NULL,
545     },
546
547     /* primitive class record */
548     {
549         /* Primitive border_highlight   */  XmInheritWidgetProc,
550         /* Primitive border_unhighlight */  XmInheritWidgetProc,
551         /* translations                 */  "" /*NULL*/ /*XtInheritTranslations*/,
552         /* arm_and_activate             */  NULL,
553         /* get resources                */  (XmSyntheticResource *) NULL,
554         /* num get_resources            */  0,
555         /* extension                    */  (XtPointer) NULL,
556     },
557
558     /* term class record */
559     {
560         /* parser_start_state           */  &_DtTermPrimStateStart,
561         /* use_history_buffer           */  False,
562         /* allow_scroll_below_buffer    */  False,
563         /* wrap_right_after_insert      */  False,
564         /* buffer_create_proc           */  _DtTermPrimBufferCreateBuffer,
565         /* buffer_free_proc             */  _DtTermPrimBufferFreeBuffer,
566         /* term_insert_proc             */  _DtTermPrimInsertText,
567         /* sizeOfBuffer                 */  (short) sizeof(TermBufferRec),
568         /* sizeOfLine                   */  (short) sizeof(TermLineRec),
569         /* sizeOfEnh                    */  (short) sizeof(TermEnhPart),
570     }
571 };
572
573 externaldef(termwidgetclass) WidgetClass dtTermPrimitiveWidgetClass =
574         (WidgetClass)&dtTermPrimitiveClassRec;
575
576 /* Class Initialize...
577  */
578 static void
579 ClassInitialize(void)
580 {
581     /* register our resource converters... */
582     (void) _DtTermPrimInitRepTypes();
583
584     return;
585 }
586
587 static void
588 ClassPartInitialize(WidgetClass w_class)
589 {
590     (void) DtTermInitialize();
591 }
592
593 static void
594 initializeKeyboard
595 (
596     DtTermPrimData tpd
597 )
598 {
599     /* 
600     ** Make sure the keyboard is unlocked...
601     */
602     tpd->keyboardLocked.escape      = False;
603     tpd->keyboardLocked.xferPending = False;
604     tpd->keyboardLocked.error       = False;
605     tpd->keyboardLocked.record      = False;
606
607     /* other keyboard modes...
608     */
609     tpd->autoLineFeed               = False;
610     tpd->halfDuplex                 = False;
611 }
612
613 /* 
614 ** initialize the term-generic straps...
615 */
616 static void
617 initializeStraps
618 (
619     DtTermPrimData tpd
620 )
621 {
622     tpd->transmitFunctions = False;
623     tpd->autoWrapRight     = True;
624 }
625
626 /* 
627 ** initialize the term-generic modes...
628 */
629 static void
630 initializeModes
631 (
632     DtTermPrimData tpd
633 )
634 {
635     tpd->scrollLockMode    = SCROLL_LOCKoff;
636 }
637
638 /*
639 ** initialize on the spot data...
640 */
641 static void
642 initializeOTS
643 (
644     DtTermPrimData tpd
645 )
646 {
647     tpd->onthespot = (OnTheSpotData)XtMalloc(sizeof(OnTheSpotDataRec));
648     tpd->onthespot->start = 0;
649     tpd->onthespot->end = 0;
650     tpd->onthespot->pre_len = 0;
651     tpd->onthespot->cursor = 0;
652     tpd->onthespot->under_preedit = False;
653 }
654
655
656 void
657 _DtTermPrimGetFontSet
658 (
659     Widget w,
660     XmFontList fontList,
661     XFontSet *fontSet,
662     XFontStruct **font
663 )
664 {
665     XmFontContext fontContext;
666     XmFontListEntry fontListEntry;
667     XmFontType fontType;
668     XtPointer pointer;
669
670     *fontSet = (XFontSet) 0;
671     *font = (XFontStruct *) 0;
672
673     if (!XmFontListInitFontContext(&fontContext, fontList)) {
674         (void) fprintf(stderr, "XmFontListInitFontContext() failed\n");
675         (void) exit(1);
676     }
677
678     /* suppress the CodeCenter warning:
679      * "Assignment in conditional 'while' expression."...
680      */
681     /*SUPPRESS 624*/
682     while (fontListEntry = XmFontListNextEntry(fontContext)) {
683         pointer = XmFontListEntryGetFont(fontListEntry, &fontType);
684         if (fontType == XmFONT_IS_FONTSET) {
685             int i;
686             int num_fonts;
687             XFontStruct **fonts;
688             char **fontNames;
689
690             Debug('f', fprintf(stderr, ">>fontType == XmFONT_IS_FONTSET\n"));
691             *fontSet = (XFontSet) pointer;
692             num_fonts = XFontsOfFontSet(*fontSet, &fonts, &fontNames);
693             for (i = 0; i < num_fonts; i++) {
694                 Debug('f', fprintf(stderr, ">>  font %d: %s\n", i + 1,
695                         fontNames[i]));
696             }
697         } else {
698             unsigned long ret;
699             Debug('f', fprintf(stderr, ">>fontType != XmFONT_IS_FONTSET\n"));
700             *font = (XFontStruct *) pointer;
701             if (XGetFontProperty(*font, XA_FONT, &ret)) {
702                 Debug('f', fprintf(stderr, ">>font: %s\n",
703                         XGetAtomName(XtDisplay(w), ret)));
704             }
705         }
706     }
707
708 #ifdef  NOTDEF
709     if (!*fontSet) {
710         unsigned long ret;
711         char *fontName;
712         char **missingCharsetList;
713         int missingCharsetCount;
714
715         /* build a fontSet from the font... */
716         if (XGetFontProperty(*font, XA_FONT, &ret)) {
717             fontName = XGetAtomName(XtDisplay(w), ret);
718         }
719         *fontSet = XCreateFontSet(XtDisplay(w),
720                 fontName,
721                 &missingCharsetList,
722                 &missingCharsetCount,
723                 (char **) 0);
724         if (missingCharsetCount > 0) {
725             int i;
726
727             for (i = 0; i < missingCharsetCount; i++)
728                 (void) fprintf(stderr, "missing charset in fontset \"%s\"\n",
729                         missingCharsetList[i]);
730         }
731     }
732 #endif  /* NOTDEF */
733
734     /* DKS: at some point, we may want to do something with the other
735      * fonts in the fontList as well...
736      */
737     /* free up malloc'ed memory... */
738     (void) XmFontListFreeFontContext(fontContext);
739 }
740
741 static TermFont
742 CreateRenderFont
743 (
744     Widget                w,
745     XmFontList            fontList,
746     XFontSet             *retFontSet,
747     XFontStruct         **retFont
748 )
749 {
750     TermFont              termFont;
751     XFontSet              fontSet = (XFontSet) 0;
752     XFontStruct          *font = (XFontStruct *) 0;
753
754     /* get our fontset from the fontlist...  */
755     (void) _DtTermPrimGetFontSet(w, fontList, &fontSet, &font);
756
757     /* generate a TermFont from either the fontset or the font... */
758     if (fontSet) {
759         termFont = _DtTermPrimRenderFontSetCreate(w, fontSet);
760     } else {
761         termFont = _DtTermPrimRenderFontCreate(w, font);
762     }
763
764     /* return the font and fontSet if requested... */
765     if (retFontSet)
766         *retFontSet = fontSet;
767     if (retFont)
768         *retFont = font;
769
770     /* return the generated font... */
771     return(termFont);
772 }
773
774 static void
775 AdjustWindowUnits
776 (
777     Widget                w
778 )
779 {
780     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
781
782     /* let's adjust the units by the base font size... */
783     if (tw->term.fontSet) {
784         XFontSetExtents *fontSetExtents;
785         int i;
786         int num_fonts;
787         XFontStruct **fonts;
788         char **fontNames;
789
790         num_fonts = XFontsOfFontSet(tw->term.fontSet, &fonts, &fontNames);
791         /* look for the single byte font that includes the normal
792          * ascii characters...
793          */
794         for (i = 0; i < num_fonts; i++) {
795             if ((fonts[i]->min_byte1 == 0) && (fonts[i]->max_byte1 == 0) &&
796                     (fonts[i]->min_char_or_byte2 <= 'A') &&
797                     (fonts[i]->max_char_or_byte2 >= 'Z')) {
798                 break;
799             }
800         }
801         if (i >= num_fonts) {
802             /* look for the multi-bypte font that includes the normal ascii
803              * characters...
804              */
805             for (i = 0; i < num_fonts; i++) {
806                 if (fonts[i]->min_byte1 == 0) {
807                     break;
808                 }
809             }
810         }
811         if (i >= num_fonts) {
812             /* as a last resort, just use the first font... */
813             i = 0;
814         }
815
816         fontSetExtents = XExtentsOfFontSet(tw->term.fontSet);
817
818         /* build termFont for this fontset... */
819         tw->term.widthInc = fonts[i]->max_bounds.width;
820         tw->term.heightInc = fontSetExtents->max_logical_extent.height;
821         /* why are there two "ascents"?  TMH */
822         tw->term.ascent = -fontSetExtents->max_logical_extent.y;
823         tw->term.tpd->ascent = tw->term.ascent;
824
825         tw->term.tpd->cellWidth = tw->term.widthInc;
826         tw->term.tpd->cellHeight = tw->term.heightInc;
827     } else {
828         tw->term.widthInc = tw->term.font->max_bounds.width;
829         tw->term.heightInc = tw->term.font->ascent + tw->term.font->descent;
830         /* why are there two "ascents"? TMH   */
831         tw->term.ascent = tw->term.font->ascent;
832         tw->term.tpd->ascent = tw->term.font->ascent;
833
834         tw->term.tpd->cellWidth = tw->term.widthInc;
835         tw->term.tpd->cellHeight = tw->term.heightInc;
836     }
837 }
838
839 static KeyCode *
840 GetCapsLockKeyCodes
841 (
842     XModifierKeymap              *modifierMapping,
843     short                        *numCapsLockKeyCodes
844 )
845 {
846     KeyCode                      *capsLockKeyCodes;
847     int                           i1;
848
849     /* initialize number of caps lock key codes... */
850     *numCapsLockKeyCodes = 0;
851
852     /* malloc storage for the keycodes (it will be less than or equal to
853      * the max)...
854      */
855     capsLockKeyCodes = (KeyCode *)
856             XtMalloc(modifierMapping->max_keypermod * sizeof(KeyCode));
857
858     /* copy them over...  */
859     for (i1 = 0; i1 < modifierMapping->max_keypermod; i1++) {
860         capsLockKeyCodes[*numCapsLockKeyCodes] =
861                 modifierMapping->modifiermap[LockMapIndex *
862                 modifierMapping->max_keypermod + i1];
863         /* only count non-zero keycodes... */
864         if (capsLockKeyCodes[*numCapsLockKeyCodes])
865             (*numCapsLockKeyCodes)++;
866     }
867
868     return(capsLockKeyCodes);
869 }
870
871 static unsigned int
872 GetMetaMask
873 (
874     XModifierKeymap              *modifierMapping,
875     KeySym                       *keyboardMapping,
876     int                           keysymsPerKeycode,
877     int                           minKeycodes,
878     int                           maxKeycodes
879 )
880 {
881     unsigned int                  i1;
882     unsigned int                  metaMask;
883     Boolean                       match;
884     int                           mapIndex;
885     KeyCode                       thisKeyCode;
886     KeySym                        thisKeySym;
887
888     /* figure out what modifier corresponds to the meta key.
889      * If there is none, return 0...
890      */
891     for (match = False, metaMask = Mod1Mask, mapIndex = Mod1MapIndex;
892             (mapIndex <= Mod5MapIndex) && !match;
893             metaMask <<= 1, mapIndex++) {
894         for (i1 = 0; i1 < modifierMapping->max_keypermod; i1++) {
895             thisKeyCode = modifierMapping->modifiermap[mapIndex *
896                     modifierMapping->max_keypermod + i1];
897             thisKeySym = keyboardMapping[(thisKeyCode - minKeycodes) *
898                     keysymsPerKeycode];
899             if ((thisKeySym == XK_Meta_L) || (thisKeySym == XK_Meta_R)) {
900                 /* we found either meta_l or meta_r... */
901                 match = True;
902                 break;
903             }
904         }
905
906         if (match) {
907             /* we found either meta_l or meta_r... */
908             break;
909         }
910     }
911
912     if (match) {
913         return(metaMask);
914     }
915
916     return(0);
917 }
918
919 /*ARGSUSED*/
920 static void
921 Initialize(Widget ref_w, Widget w, Arg *args, Cardinal *num_args)
922 {
923     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
924     DtTermPrimData tpd;
925     XmFontContext fontContext;
926     XmFontListEntry fontListEntry;
927     XmFontType fontType;
928     XModifierKeymap *modifierMapping;
929     KeySym *keyboardMapping;
930     int minKeycodes;
931     int maxKeycodes;
932     int keysymsPerKeycode;
933     XmRepTypeId shadowTypeID;
934     int i;
935
936     Debug('T', timeStamp("TermPrim Initialize() starting"));
937
938
939     /* initialize... */
940     /* we need to insure that everthing is initialized.  Let's do a
941      * checklist...
942      */
943     /* lower euid */
944     (void) _DtTermPrimToggleSuidRoot(False);
945
946     /* Widget verticalScrollBar         set via setvalues               */
947     /* short verticalScrollBarValue */
948     tw->term.verticalScrollBarValue = 0;
949
950     /* short verticalScrollBarMaximum */
951     tw->term.verticalScrollBarMaximum = 0;
952
953     /* short verticalScrollBarSliderSize */
954     tw->term.verticalScrollBarSliderSize = 0;
955
956     /* short verticalScrollBarPageIncrement */
957     tw->term.verticalScrollBarPageIncrement = 0;
958
959     /* unsigned char charCursorStyle    set via setvalues               */
960     /* int blinkRate                    set via setvalues               */
961     /* Boolean stickyPrevCursor         set via setvalues               */
962     /* Boolean stickyNextCursor         set via setvalues               */
963     /* Boolean backgroundIsSelect       set via setvalues               */
964     /* Boolean visualBell               set via setvalues               */
965     /* Boolean marginBell               set via setvalues               */
966     /* int nMarginBell                  set via setvalues               */
967     /* Boolean jumpScroll               set via setvalues               */
968     /* Boolean hasFocus */
969     tw->term.hasFocus = False;
970
971     /* char *termId                     set via setvalues               */
972     /* char *termName                   set via setvalues               */
973     /* char *ttyModes                   set via setvalues               */
974     /* unsigned char shadowType         set via setvalues               */
975     /* XmFontList fontList              set via setvalues               */
976     /* XFontStruct *font */
977     tw->term.font = (XFontStruct *) 0;
978     tw->term.boldFont = (XFontStruct *) 0;
979
980     /* XFontSet fontSet */
981     tw->term.fontSet = (XFontSet) 0;
982     tw->term.boldFontSet = (XFontSet) 0;
983
984     /* Boolean haveFontSet */
985     tw->term.haveFontSet = False;
986
987     /* char *saveLines                  set via setvalues               */
988     /* short rows                       set via setvalues               */
989     /* short columns                    set via setvalues               */
990     /* Dimension marginHeight           set via setvalues               */
991     /* Dimension marginWidth            set via setvalues               */
992     /* int baseWidth                    set via setvalues               */
993     /* int baseHeight                   set via setvalues               */
994     /* int widthInc                     set via setvalues               */
995     /* int heightInc                    set via setvalues               */
996     /* int ascent */
997     tw->term.ascent = 0;
998
999     /* int pty                          set via setvalues               */
1000     /* int ptyAllocate                  set via setvalues               */
1001     /* char *ptySlaveName               set via setvalues               */
1002     /* int subprocessPid                set via setvalues               */
1003     /* char *subprocessCWD */
1004     tw->term.subprocessCWD = (char *) 0;
1005
1006     /* char *subprocessCmd              set via setvalues               */
1007     /* char **subprocessArgv            set via setvalues               */
1008     /* Boolean subprocessLoginShell     set via setvalues               */
1009     /* Boolean subprocessTerminationCatch
1010                                         set via setvalues               */
1011     /* Boolean subprocessExec           set via setvalues               */
1012     /* _termSubprocId subprocessId */
1013     tw->term.subprocessId = (_termSubprocId) 0;
1014
1015     /* XtCallbackList statusChangeCallback
1016                                         set via setvalues               */
1017     /* XtCallbackList subprocessTerminationCallback
1018                                         set via setvalues               */
1019
1020     /* Boolean allowOsfKeysyms */
1021     tw->term.allowOsfKeysyms = False;
1022
1023     if (tw->term.backgroundIsSelect) {
1024         /* set the background pixel based on the select color... */
1025         (void) XmGetColors(XtScreen(w), w->core.colormap,
1026                 tw->core.background_pixel, NULL, NULL, NULL,
1027                 &tw->core.background_pixel);
1028     }
1029
1030     /* malloc terminalData dataspace... */
1031     tw->term.tpd = (DtTermPrimData) malloc(sizeof(DtTermPrimDataRec));
1032     tpd = tw->term.tpd;
1033
1034     /* clear malloc'ed memory... */
1035     (void) memset(tpd, '\0', sizeof(DtTermPrimDataRec));
1036
1037     /* initialize any of it...
1038      */
1039     tpd->cursorState = CURSORoff;
1040     tpd->cursorVisible = True;
1041     tpd->IMHasFocus = False;
1042     tpd->IMCursorRow = -1;
1043     tpd->IMCursorColumn = -1;
1044
1045     /* 
1046     ** Initialize the keyboard, straps, and modes...
1047     */
1048     initializeKeyboard(tpd);
1049     initializeModes(tpd);
1050     initializeStraps(tpd);
1051     initializeOTS(tpd);
1052
1053     /* initialize scroll variables...
1054      */
1055
1056     tpd->useHistoryBuffer = ((DtTermPrimitiveClassRec *) (tw->core.widget_class))->
1057             term_primitive_class.use_history_buffer;
1058     tpd->allowScrollBelowBuffer = ((DtTermPrimitiveClassRec *) (tw->core.widget_class))->
1059             term_primitive_class.allow_scroll_below_buffer;
1060     tpd->wrapRightAfterInsert = ((DtTermPrimitiveClassRec *) (tw->core.widget_class))->
1061             term_primitive_class.wrap_right_after_insert;
1062
1063     /* initialize pending text... */
1064     tpd->pendingRead = _DtTermPrimPendingTextCreate();
1065     tpd->pendingWrite = _DtTermPrimPendingTextCreate();
1066
1067     /*
1068     ** Initialize the utmp stuff...
1069     */
1070     _DtTermPrimUtmpInit(w);
1071     
1072     /* 
1073     ** Initialize the selection inforamtion
1074     */
1075     tpd->selectInfo = _DtTermPrimSelectCreate(w);
1076
1077     /* force unit type to pixels... */
1078     tw->primitive.unit_type = XmPIXELS;
1079
1080     /* we have a fontlist.  Get a fontset from it if we can, else get a
1081      * fontstruct and make a fontset if we can...
1082      */
1083     /* get the text default fontlist if we don't have one... */
1084     if (!tw->term.fontList) {
1085         tw->term.fontList = XmeGetDefaultRenderTable(w, XmTEXT_FONTLIST);
1086     }
1087
1088     tpd->termFont = CreateRenderFont(w, tw->term.fontList,
1089             &tw->term.fontSet, &tw->term.font);
1090
1091     if (tw->term.boldFontList) {
1092         tpd->boldTermFont = CreateRenderFont(w, tw->term.boldFontList,
1093                 &tw->term.boldFontSet, &tw->term.boldFont);
1094     } else {
1095         /* let's try and build a bold fontlist off of the base fontlist... */
1096         if (tw->term.fontSet) {
1097             int num_fonts;
1098             XFontStruct **fonts;
1099             char **fontNames;
1100             char boldFontNames[BUFSIZ];
1101             char *c1;
1102             char *c2;
1103             int i1;
1104             int i2;
1105             char **missingCharsetList;
1106             int missingCharsetCount;
1107
1108             Debug('f', fprintf(stderr, ">>generating bold fontset\n"));
1109             num_fonts = XFontsOfFontSet(tw->term.fontSet, &fonts, &fontNames);
1110             for (i1 = 0, c2 = boldFontNames; i1 < num_fonts; i1++) {
1111                 /* if this is not the first name we need a comma to
1112                  * separate the names...
1113                  */
1114                 if (i1 > 0) {
1115                     *c2++ = ',';
1116                     *c2++ = ' ';
1117                 }
1118
1119                 /* copy over the first 3 fields... */
1120                 for (c1 = fontNames[i1], i2 = 0; (i2 < 3) && *c1; i2++) {
1121                     while (*c1 && (*c1 != '-')) {
1122                         *c2++ = *c1++;
1123                     }
1124                     if (!*c1) {
1125                         break;
1126                     }
1127                     /* copy over the '-'... */
1128                     *c2++ = *c1++;
1129                 }
1130                 /* make boldFont bold by swapping the bold in for the
1131                  * weight...
1132                  */
1133                 (void) strcpy(c2, "bold");
1134                 c2 += strlen("bold");
1135
1136                 /* skip over the weight in the source... */
1137                 while (*c1 && (*c1 != '-')) {
1138                     c1++;
1139                 }
1140
1141                 /* copy over the rest of the fontname... */
1142                 while (*c1) {
1143                     *c2++ = *c1++;
1144                 }
1145             }
1146
1147             /* null term... */
1148             *c2 = '\0';
1149
1150             /* now create the fontset... */
1151             tw->term.boldFontSet = XCreateFontSet(XtDisplay(w),
1152                     boldFontNames,
1153                     &missingCharsetList,
1154                     &missingCharsetCount,
1155                     (char **) 0);
1156             if (missingCharsetCount > 0) {
1157                 int i;
1158
1159                 for (i = 0; i < missingCharsetCount; i++)
1160                     Debug('f', fprintf(stderr,
1161                             ">>missing charsets in boldfont \"%s\"\n",
1162                             missingCharsetList[i]));
1163                 (void) XFreeStringList(missingCharsetList);
1164                 if (tw->term.boldFontSet) {
1165                     (void) XFreeFontSet(XtDisplay(w), tw->term.boldFontSet);
1166                     tw->term.boldFontSet = (XFontSet) 0;
1167                 }
1168             }
1169
1170             /* create a bold render font... */
1171             if (tw->term.boldFontSet) {
1172                 tpd->boldTermFont =
1173                         _DtTermPrimRenderFontSetCreate(w, tw->term.boldFontSet);
1174             }
1175         } else if (tw->term.font) {
1176             unsigned long ret;
1177             char *fontName;
1178             char boldFontName[BUFSIZ];
1179             char *c1;
1180             char *c2;
1181             int i2;
1182
1183             /* get the fontname associated with the font... */
1184             if (XGetFontProperty(tw->term.font, XA_FONT, &ret)) {
1185                 fontName = XGetAtomName(XtDisplay(w), ret);
1186                 /* copy over the first 3 fields... */
1187                 for (c1 = fontName, c2 = boldFontName, i2 = 0;
1188                         (i2 < 3) && *c1; i2++) {
1189                     while (*c1 && (*c1 != '-')) {
1190                         *c2++ = *c1++;
1191                     }
1192                     if (!*c1) {
1193                         break;
1194                     }
1195                     /* copy over the '-'... */
1196                     *c2++ = *c1++;
1197                 }
1198                 /* make boldFont bold by swapping the bold in for the
1199                  * weight...
1200                  */
1201                 (void) strcpy(c2, "bold");
1202                 c2 += strlen("bold");
1203
1204                 /* skip over the weight in the source... */
1205                 while (*c1 && (*c1 != '-')) {
1206                     c1++;
1207                 }
1208
1209                 /* copy over the rest of the fontname... */
1210                 while (*c1) {
1211                     *c2++ = *c1++;
1212                 }
1213
1214                 /* null term the string... */
1215                 *c2 = '\0';
1216
1217                 tw->term.boldFont = XLoadQueryFont(XtDisplay(w), boldFontName);
1218                 /* create a bold render font... */
1219                 if (tw->term.boldFont) {
1220                     tpd->boldTermFont =
1221                             _DtTermPrimRenderFontCreate(w, tw->term.boldFont);
1222                 }
1223                 if (fontName) XFree(fontName) ;
1224             }
1225         }
1226     }
1227
1228     /* save away our original fonts as defaults... */
1229     tpd->defaultTermFont = tpd->termFont;
1230     tpd->defaultBoldTermFont = tpd->boldTermFont;
1231
1232     /* look through our XFontSet or XFontStruct and adjust our
1233      * width and height increments...
1234      */
1235     (void) AdjustWindowUnits(w);
1236
1237     /* initialize the base width/height... */
1238     tw->term.baseWidth = 2 * (tw->primitive.shadow_thickness +
1239             tw->primitive.highlight_thickness + tw->term.marginWidth);
1240     tw->term.baseHeight = 2 * (tw->primitive.shadow_thickness +
1241             tw->primitive.highlight_thickness + tw->term.marginHeight);
1242
1243     /* adjust width and height by rows/columns and the font size... */
1244     tw->core.width =
1245             tw->term.columns * tw->term.widthInc + tw->term.baseWidth;
1246     tw->core.height =
1247             tw->term.rows * tw->term.heightInc + tw->term.baseHeight;
1248     Debug('w', fprintf(stderr, ">>core.width=%u\n", tw->core.width));
1249     Debug('w', fprintf(stderr, ">>core.height=%u\n", tw->core.height));
1250
1251     /* set the termData fields... */
1252     (void) _DtTermPrimParserInitContext(w);
1253     tpd->parserNotInStartState = False;
1254     tpd->offsetX = tw->primitive.shadow_thickness +
1255             tw->primitive.highlight_thickness + tw->term.marginWidth;
1256     tpd->offsetY = tw->primitive.shadow_thickness +
1257             tw->primitive.highlight_thickness + tw->term.marginHeight;
1258     tpd->cellWidth = tw->term.widthInc;
1259     tpd->cellHeight = tw->term.heightInc;
1260     tpd->ascent = tw->term.ascent;
1261     tpd->windowMapped = False ;
1262     time( &tpd->creationTime) ;         
1263     if (tw->term.pointerBlank) tpd->pointerFirst = True ;
1264
1265     /* multi-byte specific fields...
1266      */
1267     tpd->mbCurMax = MB_CUR_MAX;
1268     /* use a debug flag to force ourselves into multi-byte
1269      * mode for single byte locales...
1270      */
1271     DebugF('m', 1, tpd->mbCurMax = MB_LEN_MAX);
1272     tpd->mbPartialCharLen = 0;  /* no pending partial multi-byte char */
1273
1274     /* check results of type converters... */
1275     shadowTypeID = XmRepTypeGetId(XmRShadowType);
1276     if (shadowTypeID != XmREP_TYPE_INVALID) {
1277         if (!XmRepTypeValidValue(shadowTypeID, tw->term.shadowType, w))
1278             tw->term.shadowType = DtSHADOW_IN;
1279     }
1280
1281     /* get the keyboard modifier mapping... */
1282     modifierMapping = XGetModifierMapping(XtDisplay(w));
1283     (void) XDisplayKeycodes(XtDisplay(w), &minKeycodes, &maxKeycodes);
1284     keyboardMapping = XGetKeyboardMapping(XtDisplay(w), minKeycodes,
1285             maxKeycodes - minKeycodes + 1, &keysymsPerKeycode);
1286
1287     /* get the caps lock keycodes... */
1288     tpd->capsLockKeyCodes = GetCapsLockKeyCodes(modifierMapping,
1289             &tpd->numCapsLockKeyCodes);
1290
1291     /* get the modifier bit that corresponds to meta.
1292      * If there is none, use mod1...
1293      */
1294     tpd->metaMask = GetMetaMask(modifierMapping, keyboardMapping,
1295             keysymsPerKeycode, minKeycodes, maxKeycodes);
1296     if (!tpd->metaMask) {
1297         /* default to mod1... */
1298         tpd->metaMask = Mod1Mask;
1299     }
1300             
1301     (void) XFree(keyboardMapping);
1302     (void) XFreeModifiermap(modifierMapping);
1303
1304     (void) XtAddEventHandler(w,
1305             (EventMask) KeyPressMask | KeyReleaseMask,
1306             False, handleKeyEvents, (Opaque) NULL);
1307     (void) XtAddEventHandler(w,
1308             (EventMask) ButtonPressMask | ButtonReleaseMask,
1309             False, handleButtonEvents, (Opaque) NULL);
1310     (void) XtAddEventHandler(w,
1311             (EventMask) 0,
1312             True, handleNonMaskableEvents, (Opaque) NULL);
1313     { 
1314         Widget sw ;
1315
1316         for (sw = w; !XtIsShell(sw); sw = XtParent(sw))
1317             ;
1318         (void) XtAddEventHandler(sw, (EventMask) StructureNotifyMask,
1319                 False, handleProcessStructureNotifyEvent, (Opaque) w);
1320         (void) XtAddEventHandler(sw, (EventMask) PropertyChangeMask,
1321                 False, handlePropertyChangeEvents, (Opaque) w);
1322     }
1323
1324     if (tw->term.verticalScrollBar) {
1325         /* set up the callbacks for the scrollbar... */
1326         (void) InitializeVerticalScrollBar(w, True);
1327     }
1328
1329     tw->term.log_on = False ;
1330     if (tw->term.logging) {
1331        _DtTermPrimStartLog(tw) ;
1332      }
1333
1334     Debug('T', timeStamp("TermPrim Initialize() finished"));
1335     return;
1336 }
1337
1338 static void
1339 InitializeVerticalScrollBar(Widget w, Boolean initCallbacks)
1340 {
1341     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
1342     DtTermPrimData tpd = tw->term.tpd;
1343     Arg arglist[20];
1344     int i;
1345     int value;
1346
1347     if (initCallbacks) {
1348         /* set up the scrollbar callbacks... */
1349 #ifdef  NOTDEF
1350         (void) XtAddCallback(tw->term.verticalScrollBar, XmNdecrementCallback,
1351                 VerticalScrollBarCallback, (XtPointer) w);
1352         (void) XtAddCallback(tw->term.verticalScrollBar, XmNincrementCallback,
1353                 VerticalScrollBarCallback, (XtPointer) w);
1354
1355         (void) XtAddCallback(tw->term.verticalScrollBar,
1356                 XmNpageDecrementCallback,
1357                 VerticalScrollBarCallback, (XtPointer) w);
1358         (void) XtAddCallback(tw->term.verticalScrollBar,
1359                 XmNpageIncrementCallback,
1360                 VerticalScrollBarCallback, (XtPointer) w);
1361
1362         (void) XtAddCallback(tw->term.verticalScrollBar,
1363                 XmNtoTopCallback, VerticalScrollBarCallback, (XtPointer) w);
1364         (void) XtAddCallback(tw->term.verticalScrollBar,
1365                 XmNtoBottomCallback, VerticalScrollBarCallback, (XtPointer) w);
1366 #endif  /* NOTDEF */
1367
1368         (void) XtAddCallback(tw->term.verticalScrollBar, XmNdragCallback,
1369                 VerticalScrollBarCallback, (XtPointer) w);
1370         (void) XtAddCallback(tw->term.verticalScrollBar,
1371                 XmNvalueChangedCallback, VerticalScrollBarCallback,
1372                 (XtPointer) w);
1373     }
1374
1375     if (!tpd->termBuffer) {
1376         /* no termBuffer yet, we set anything yet... */
1377         return;
1378     }
1379
1380     /* update the scrollbar... */
1381     if (tw->term.verticalScrollBar) {
1382         /* we can scroll the height of the history buffer and the
1383          * number of used rows less the protected areas...
1384          */
1385         if (tpd->useHistoryBuffer) {
1386 #define NO_SCROLL_REGION_HISTORY_SCROLL
1387 #ifdef  NO_SCROLL_REGION_HISTORY_SCROLL 
1388             tw->term.verticalScrollBarMaximum = tw->term.rows;
1389             if ((tpd->scrollLockTopRow <= 0) &&
1390                     (tpd->scrollLockBottomRow >= (tw->term.rows - 1))) {
1391                 tw->term.verticalScrollBarMaximum += tpd->lastUsedHistoryRow;
1392             }
1393 #else   /* NO_SCROLL_REGION_HISTORY_SCROLL */
1394             tw->term.verticalScrollBarMaximum = tw->term.rows +
1395                     tpd->lastUsedHistoryRow;
1396 #endif  /* NO_SCROLL_REGION_HISTORY_SCROLL */
1397         } else {
1398             tw->term.verticalScrollBarMaximum = tpd->lastUsedRow +
1399                     tpd->scrollLockTopRow -
1400                     (tw->term.rows - 1 - tpd->scrollLockBottomRow);
1401
1402             /* add in any non-existent rows below the last used row...
1403              */
1404             if (tpd->allowScrollBelowBuffer) {
1405                 /* add in a full screen (less one line and protected areas)
1406                  * below the last used row...
1407                  */
1408                 tw->term.verticalScrollBarMaximum += tw->term.rows - 1 -
1409                         tpd->scrollLockTopRow -
1410                         (tw->term.rows - 1 - tpd->scrollLockBottomRow);
1411             }
1412         }
1413
1414         if (tpd->useHistoryBuffer) {
1415             tw->term.verticalScrollBarSliderSize = tw->term.rows;
1416         } else {
1417             tw->term.verticalScrollBarSliderSize =
1418                     tw->term.rows - tpd->scrollLockTopRow -
1419                     (tw->term.rows - 1 - tpd->scrollLockBottomRow);
1420         }
1421
1422         tw->term.verticalScrollBarPageIncrement =
1423                 tw->term.verticalScrollBarSliderSize;
1424
1425 #ifdef  NO_SCROLL_REGION_HISTORY_SCROLL 
1426         tw->term.verticalScrollBarValue = tpd->topRow;
1427         if (tpd->useHistoryBuffer && (tpd->scrollLockTopRow <= 0) &&
1428                 (tpd->scrollLockBottomRow >= (tw->term.rows - 1))) {
1429             tw->term.verticalScrollBarValue += tpd->lastUsedHistoryRow;
1430         }
1431 #else   /* NO_SCROLL_REGION_HISTORY_SCROLL */
1432         tw->term.verticalScrollBarValue = tpd->topRow + tpd->lastUsedHistoryRow;
1433 #endif  /* NO_SCROLL_REGION_HISTORY_SCROLL */
1434
1435         i = 0;
1436         (void) XtSetArg(arglist[i], XmNincrement, 1); i++;
1437         (void) XtSetArg(arglist[i], XmNminimum, 0); i++;
1438         (void) XtSetArg(arglist[i], XmNmaximum,
1439                 tw->term.verticalScrollBarMaximum); i++;
1440         (void) XtSetArg(arglist[i], XmNpageIncrement,
1441                 tw->term.verticalScrollBarPageIncrement); i++;
1442         (void) XtSetArg(arglist[i], XmNsliderSize,
1443                 tw->term.verticalScrollBarSliderSize); i++;
1444         (void) XtSetArg(arglist[i], XmNvalue, tw->term.verticalScrollBarValue);
1445                 i++;
1446         (void) XtSetValues(tw->term.verticalScrollBar, arglist, i);
1447
1448         Debug('b', fprintf(stderr,
1449                 "InitializeVerticalScrollBar: sb size=%d  min=%d  max=%d  value=%d  pginc=%d\n",
1450                 tw->term.verticalScrollBarSliderSize,
1451                 0,
1452                 tw->term.verticalScrollBarMaximum,
1453                 tw->term.verticalScrollBarValue,
1454                 tw->term.verticalScrollBarPageIncrement));
1455     }
1456 }
1457
1458 static void
1459 InitOrResizeTermBuffer(Widget w)
1460 {
1461     DtTermPrimitiveWidget         tw = (DtTermPrimitiveWidget) w;
1462     DtTermPrimData                tpd = tw->term.tpd;
1463     DtTermPrimitiveClassPart     *termClassPart = &(((DtTermPrimitiveClassRec *)
1464             (tw->core.widget_class))->term_primitive_class);
1465     long                          lines;
1466     char                         *c;
1467     short                         newColumns;
1468     short                         newRows;
1469     short                         reqColumns;
1470     short                         reqRows;
1471     short                         newBufferRows = tpd->bufferRows;
1472     short                         newHistoryBufferRows = tpd->historyBufferRows;
1473     int                           linesNeeded;
1474     int                           historyLinesNeeded;
1475     int                           i1;
1476     Boolean                       resizeTermBuffer;
1477     Boolean                       updateWindowSize = False;
1478
1479     /* set rows and columns... */
1480     newColumns = MAX(1, ((int)(tw->core.width - (2 * (tw->primitive.shadow_thickness +
1481             tw->primitive.highlight_thickness + tw->term.marginWidth)))) /
1482             tw->term.widthInc);
1483     newRows = MAX(1, ((int)(tw->core.height - (2 * (tw->primitive.shadow_thickness +
1484             tw->primitive.highlight_thickness + tw->term.marginHeight)))) /
1485             tw->term.heightInc);
1486
1487     if ((newColumns == tw->term.columns) && (newRows == tw->term.rows) &&
1488             tpd->termBuffer) {
1489         /* we already have a buffer and the size didn't change so,
1490          * no change...
1491          */
1492         return;
1493     }
1494
1495     /* resize/create the term buffer... */
1496     if (tpd->termBuffer) {
1497         /* restore the buffer-to-window ratio of our off-window buffer
1498          * is less than 75% of the original off-window buffer...
1499          */
1500         if (tpd->useHistoryBuffer) {
1501             if ((100 * (tpd->bufferRows + tpd->historyBufferRows) /
1502                     newRows) < ((75 * tpd->bufferRowRatio) / 100)) {
1503                 newBufferRows = (tpd->bufferRowRatio * newRows) / 100;
1504                 newHistoryBufferRows = newBufferRows - newRows;
1505                 newBufferRows = newRows;
1506             } else {
1507                 /* the buffer needs to be the length of the window... */
1508                 newBufferRows = newRows;
1509             }
1510         } else {
1511             if ((100 * tpd->bufferRows / newRows) <
1512                     ((75 * tpd->bufferRowRatio) / 100)) {
1513                 newBufferRows = (tpd->bufferRowRatio * newRows) / 100;
1514             }
1515         }
1516
1517         /* it needs to be at least the size of the window...
1518          */
1519         if (newBufferRows < newRows) {
1520             newBufferRows = newRows;
1521         }
1522
1523         resizeTermBuffer = True;  /* until further notice */
1524
1525         if (tpd->useHistoryBuffer && tpd->historyBufferRows > 0 )
1526         {
1527             /*
1528             ** if we are using a history buffer and have scrolled
1529             ** into it, we need to snap back down before we do
1530             ** anything...
1531             */
1532             if (tpd->topRow < 0)
1533             {
1534                 (void) _DtTermPrimScrollTextTo((Widget) tw, 0);
1535             }
1536
1537             /* resize the history buffer first so that we can scroll
1538              * data from the active buffer into it (if necessary) without
1539              * loosing any data...
1540              */
1541             
1542             if ((newHistoryBufferRows > tpd->historyBufferRows) ||
1543                 (newColumns != tw->term.columns))
1544             {
1545                 reqRows    = newHistoryBufferRows;
1546                 reqColumns = newColumns;
1547             
1548                 _DtTermPrimBufferResizeBuffer(&tpd->historyBuffer, &reqRows,
1549                                               &reqColumns);
1550
1551                 if ((reqColumns < newColumns) || 
1552                     (reqRows < newHistoryBufferRows)) 
1553                 {
1554                     /*
1555                     ** we ran out of memory when we tried to resize the
1556                     ** history buffer, make the necessary adjustments
1557                     */
1558                     newColumns           = reqColumns;
1559                     newHistoryBufferRows = reqRows;
1560                     
1561                     /*
1562                     ** we ran out of memory, no need try and resize the
1563                     ** term buffer
1564                     */
1565                     resizeTermBuffer == False;
1566                 }
1567             }
1568
1569             if (resizeTermBuffer)
1570             {
1571                 if (newBufferRows < tpd->bufferRows)
1572                 {
1573                     /* we are shrinking the window.  The first choice is to
1574                      * move lines above the cursor into the history buffer so
1575                      * that we don't loose any lines in the window.  If there
1576                      * are not enough lines above the cursor, we will drop
1577                      * some of the lines off the bottom of the window...
1578                      */
1579                     linesNeeded = tpd->bufferRows - newBufferRows;
1580
1581                     /* clip this by the number of lines above the cursor... */
1582                     if (linesNeeded > tpd->cursorRow)
1583                     {
1584                         linesNeeded = tpd->cursorRow;
1585                     }
1586                     
1587                     historyLinesNeeded = linesNeeded - (newHistoryBufferRows -
1588                                                        tpd->lastUsedHistoryRow);
1589
1590                     if (historyLinesNeeded > 0) {
1591                         /* take them from the top of the history buffer... */
1592                         (void) _DtTermPrimBufferInsertLineFromTB(
1593                             tpd->historyBuffer, tpd->historyBufferRows - 1,
1594                             historyLinesNeeded, insertFromTop);
1595                         /* adjust everything... */
1596                         tpd->lastUsedHistoryRow -= historyLinesNeeded;
1597                     }
1598
1599                     /* copy the lines over... */
1600                     for (i1 = 0; i1 < linesNeeded; i1++) {
1601                         termChar *c1;
1602                         short length;
1603                         termChar *overflowChars;
1604                         short overflowCount;
1605                         
1606                         /* get the line from the active buffer... */
1607                         length = _DtTermPrimBufferGetLineLength(tpd->termBuffer,
1608                                                                 i1);
1609                         c1 = _DtTermPrimBufferGetCharacterPointer(tpd->termBuffer,
1610                                                                   i1, 0);
1611                         
1612                         /* stuff it into the history buffer... */
1613                         (void) _DtTermPrimBufferSetLineWidth(tpd->historyBuffer,
1614                                                              tpd->lastUsedHistoryRow,
1615                                                              0);
1616                         overflowChars = (termChar *) XtMalloc(BUFSIZ * sizeof (termChar));
1617                         (void) _DtTermPrimBufferInsert(tpd->historyBuffer,
1618                                                        tpd->lastUsedHistoryRow,
1619                                                        0, c1, length, False,
1620                                                        &overflowChars,
1621                                                        &overflowCount);
1622                         (void) tpd->lastUsedHistoryRow++;
1623                         (void) XtFree((char *) overflowChars);
1624                     }
1625                     
1626                     /* scroll up the active buffer... */
1627                     if (linesNeeded > 0) {
1628                         (void) _DtTermPrimBufferInsertLineFromTB(tpd->termBuffer,
1629                                                                  tpd->bufferRows - 1,
1630                                                                  linesNeeded,
1631                                                                  insertFromTop);
1632                         /* adjust everything... */
1633                         tpd->cursorRow -= linesNeeded;
1634                     }
1635                 }
1636
1637                 if ((newBufferRows != tpd->bufferRows) ||
1638                     (newColumns != tw->term.columns))
1639                 {
1640                     reqRows    = newBufferRows;
1641                     reqColumns = newColumns;
1642             
1643                     _DtTermPrimBufferResizeBuffer(&tpd->termBuffer, &reqRows,
1644                                                   &reqColumns);
1645                     if ((reqColumns < newColumns) || (reqRows < newBufferRows)) 
1646                     {
1647                         /*
1648                         ** we ran out of memory, resize the history buffer
1649                         ** to the same width as the terminal buffer,
1650                         ** and assume we will succeed...
1651                         */
1652                         newColumns = reqColumns;
1653                         reqRows    = newHistoryBufferRows;
1654                         
1655                         _DtTermPrimBufferResizeBuffer(&tpd->historyBuffer,
1656                                                       &reqRows, &reqColumns);
1657                         newBufferRows = reqRows;
1658                     }
1659                 }
1660             }
1661             tpd->historyBufferRows = newHistoryBufferRows;
1662             tpd->bufferRows        = newBufferRows;
1663         }
1664         else
1665         {
1666             /*
1667             ** no history buffer to worry about...
1668             */
1669             _DtTermPrimBufferResizeBuffer(&tpd->termBuffer, &newBufferRows,
1670                                           &newColumns);
1671             tpd->bufferRows = newBufferRows;
1672         }
1673
1674         /*
1675         ** on the slight chance that the buffer shrank...
1676         */
1677         newBufferRows = MIN(newBufferRows, newRows);
1678
1679         /*
1680         ** if we added rows, then malloc a new set of scrollRefreshRows...
1681         */
1682         if (newBufferRows > tw->term.rows)
1683         {
1684             (void) XtFree(tpd->scrollRefreshRows);
1685             tpd->scrollRefreshRows = (Boolean *) XtMalloc(newBufferRows *
1686                                                           sizeof(Boolean));
1687             (void) memset(tpd->scrollRefreshRows, '\0', newBufferRows *
1688                           sizeof(Boolean));
1689         }
1690         
1691         /* we got this far because we changed the buffer size.  We
1692          * will have to update the winsize structure...
1693          */
1694         updateWindowSize = True;
1695
1696         tw->term.rows    = newBufferRows;
1697         tw->term.columns = newColumns;
1698         if (tpd->lastUsedRow > newRows)
1699             tpd->lastUsedRow = newRows;
1700
1701         /* adjust the insert point if necessary... */
1702         if (tpd->cursorColumn > tw->term.columns - 1)
1703             tpd->cursorColumn = tw->term.columns - 1;
1704         if (tpd->cursorRow > tw->term.rows - 1)
1705             tpd->cursorRow = tw->term.rows - 1;
1706
1707     } else {
1708 #ifdef  SET_WINDOW_SIZE_ONLY_IF_CHANGED
1709         /* if our rows and columns changed, we will have to update
1710          * the winsize structure...
1711          */
1712         if ((tw->term.rows != newRows) || (tw->term.columns != newColumns)) {
1713             updateWindowSize = True;
1714         }
1715 #else   /* SET_WINDOW_SIZE_ONLY_IF_CHANGED */
1716         /* we always need to update the winsize structure since it will not
1717          * be done for us via $LINES and $COLUMNS...
1718          */
1719         updateWindowSize = True;
1720 #endif  /* SET_WINDOW_SIZE_ONLY_IF_CHANGED */
1721
1722         tw->term.rows    = newRows;
1723         tw->term.columns = newColumns;
1724
1725         /* this is the first time and we need to figure out our ratio for
1726          * future resizing...
1727          */
1728         if (tw->term.saveLines && *tw->term.saveLines) {
1729             lines = strtol(tw->term.saveLines, &c, 0);
1730             if (c && (*c == 's')) {
1731                 /* in terms of screens... */
1732                 tpd->bufferRows = (lines + 1) * tw->term.rows;
1733             } else {
1734                 tpd->bufferRows = (lines + tw->term.rows);
1735             }
1736         } else {
1737             tpd->bufferRows = 2 * tw->term.rows;
1738         }
1739
1740         /* calculate the buffer ratio from bufferRows and rows... */
1741         tpd->bufferRowRatio = (100 * tpd->bufferRows) / tw->term.rows;
1742             
1743         if (tpd->useHistoryBuffer) {
1744             /* split up the buffer between the active and history buffers...
1745              */
1746             tpd->historyBufferRows = tpd->bufferRows - tw->term.rows;
1747             tpd->bufferRows = tw->term.rows;
1748         }
1749
1750         /* allocate the two buffers... */
1751         tpd->termBuffer = (*(termClassPart->buffer_create_proc))(
1752                 w,
1753                 tpd->bufferRows,
1754                 tw->term.columns,
1755                 termClassPart->sizeOfBuffer,
1756                 termClassPart->sizeOfLine,
1757                 termClassPart->sizeOfEnh);
1758         if (tpd->useHistoryBuffer) {
1759             tpd->historyBuffer = (*(termClassPart->buffer_create_proc))(
1760                     w,
1761                     tpd->historyBufferRows,
1762                     tw->term.columns,
1763                     termClassPart->sizeOfBuffer,
1764                     termClassPart->sizeOfLine,
1765                     termClassPart->sizeOfEnh);
1766             (void) _DtTermPrimBufferSetLinks(tpd->termBuffer,
1767                     tpd->historyBuffer,
1768                     NULL);
1769             (void) _DtTermPrimBufferSetLinks(tpd->historyBuffer,
1770                     NULL,
1771                     tpd->termBuffer);
1772         }
1773
1774         /* check for error... */
1775         if (!tpd->termBuffer ||
1776                 (tpd->useHistoryBuffer && !tpd->historyBuffer)) {
1777             /*DKS: this needs to be cleaned up... */
1778             (void) fprintf(stderr, "unable to create termBuffer\n");
1779             (void) exit(1);
1780         }
1781
1782         /* malloc a set of scrollRefreshRows... */
1783         tpd->scrollRefreshRows = (Boolean *) XtMalloc(tw->term.rows *
1784                 sizeof(Boolean));
1785         (void) memset(tpd->scrollRefreshRows, '\0', tw->term.rows *
1786                 sizeof(Boolean));
1787
1788         /* now that we have a term buffer, we can set up our input selector
1789          * on our input source (pty or whatever)...
1790          */
1791         (void) _DtTermPrimStartOrStopPtyInput(w);
1792         /* initialize the insertion point... */
1793         tpd->cursorColumn = 0;
1794         tpd->cursorRow = 0;
1795         tpd->topRow  = 0;
1796         tpd->lastUsedRow = 1;
1797         tpd->lastUsedHistoryRow = 0;
1798     }
1799
1800     /*
1801     ** Resize (or creation) is complete, now update the relevant
1802     ** information.
1803     ** 
1804     ** reset scroll lock...
1805     */
1806     tpd->scrollLockMode = SCROLL_LOCKoff;
1807     tpd->scrollLockTopRow = 0;
1808     tpd->scrollLockBottomRow = newRows - 1;
1809
1810     /* set the rows and columns for the terminal... */
1811     if ((tw->term.pty >= 0) && (updateWindowSize)) {
1812         (void) _DtTermPrimPtySetWindowSize(tw->term.pty,
1813                    newColumns * tw->term.widthInc + 
1814                    (2 * (tw->primitive.shadow_thickness +
1815                          tw->primitive.highlight_thickness + 
1816                          tw->term.marginWidth)),
1817                    newRows * tw->term.heightInc +
1818                    (2 * (tw->primitive.shadow_thickness +
1819                          tw->primitive.highlight_thickness +
1820                          tw->term.marginHeight)),
1821                    newRows, newColumns);
1822     }
1823
1824     /* reset margins... */
1825     tpd->leftMargin = 0;
1826     tpd->rightMargin = newColumns - 1;
1827
1828     (void) InitializeVerticalScrollBar(w, False);
1829
1830     _DtTermPrimSelectResize(w) ;
1831 }
1832     
1833 static void
1834 Resize(Widget w)
1835 {
1836     DtTermPrimitiveWidget         tw = (DtTermPrimitiveWidget) w;
1837
1838     if (XtIsRealized(w)) {
1839         /* the first time through, if our size is changed during interactive
1840          * placement, we will be called before redisplay and we will be
1841          * initializing the buffer.  If we are sized to our requested size,
1842          * the resize function will not be called...
1843          */
1844         (void) InitOrResizeTermBuffer(w);
1845
1846     }
1847 }
1848
1849 /*ARGSUSED*/
1850 static void
1851 Redisplay(Widget w, XEvent *event, Region region)
1852 {
1853     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
1854     /* if this is the first time we are exposed, and we have never had our
1855      * size changed (i.e., no Resize() invoked), then we need to initialize
1856      * a few things, so let's force a resize...
1857      */
1858     if (XtIsRealized(w)) {
1859         if (!tw->term.tpd->termBuffer) {
1860             InitOrResizeTermBuffer(w);
1861         }
1862
1863         Debug('e', fprintf(stderr,
1864                 ">>Redisplay()  expose.x=%d  .y=%d  .width=%d  .height=%d\n",
1865                 event->xexpose.x, event->xexpose.y, event->xexpose.width,
1866                 event->xexpose.height));
1867
1868         (void) _DtTermPrimDrawShadow(w);
1869
1870         /* expose (refresh) the text... */
1871         _DtTermPrimCursorOff(w);
1872         (void) _DtTermPrimExposeText(w, event->xexpose.x, event->xexpose.y,
1873                 event->xexpose.width, event->xexpose.height, True);
1874         if (event->xexpose.count == 0)
1875             _DtTermPrimCursorOn(w);
1876
1877         /* Envelop our superclass expose method */
1878         (*(xmPrimitiveClassRec.core_class.expose)) (w, event, region);  
1879     }
1880 }
1881
1882 /*ARGSUSED*/
1883 static void
1884 handleNonMaskableEvents(Widget w, XtPointer eventData, XEvent *event,
1885         Boolean *cont)
1886 {
1887     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
1888     DtTermPrimData tpd = tw->term.tpd;
1889     unsigned char *buffer = (unsigned char *) 0;
1890     int fd = tw->term.pty;
1891
1892     switch (event->type) {
1893     case GraphicsExpose:
1894         /*DKS
1895         if (!tw->term.jumpScroll && tpd->scroll.nojump.scrollPending) {
1896         DKS*/
1897             (void) _DtTermPrimExposeText(w, event->xexpose.x, event->xexpose.y,
1898                     event->xexpose.width, event->xexpose.height, False);
1899         /*DKS
1900         }
1901         DKS*/
1902         if (event->xgraphicsexpose.count > 0)
1903             break;
1904         /* else fall through to noexpose... */
1905
1906     case NoExpose:
1907         /* clear the scroll flag... */
1908         tpd->scrollInProgress = False;
1909
1910         if (tpd->scroll.nojump.pendingScroll) {
1911             (void) _DtTermPrimScrollComplete(w, False);
1912         }
1913
1914         /* process any pending input... */
1915         if (TextIsPending(tpd->pendingRead)) {
1916             (void) readPty((XtPointer) w, &fd, &tpd->ptyInputId);
1917         }
1918
1919         /* reinstall the pty input select... */
1920         (void) _DtTermPrimStartOrStopPtyInput(w);
1921             
1922         /* free the old buffer... */
1923         if (buffer) {
1924             (void) XtFree((char *) buffer);
1925         }
1926
1927         if ((tpd->scroll.nojump.pendingScroll == 0) &&
1928                 !moreInput(tw->term.pty)) {
1929             /* turn the cursor back on... */
1930             (void) _DtTermPrimCursorOn(w);
1931         }
1932         break;
1933     }
1934 }
1935
1936 static void
1937 handleProcessStructureNotifyEvent(Widget w, XtPointer eventData, XEvent *event,
1938         Boolean *cont)
1939 {
1940     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) eventData;
1941     DtTermPrimData tpd = tw->term.tpd;
1942
1943     switch (event->type) {
1944     case MapNotify:
1945         tpd->windowMapped = True;
1946         if (tpd->mapWarningDialog && tpd->warningDialog) {
1947             (void) XtManageChild(tpd->warningDialog);
1948             tpd->warningDialogMapped = True;
1949             tpd->mapWarningDialog = False;
1950         }
1951         break;
1952
1953     case UnmapNotify:
1954         tpd->windowMapped = False;
1955         break;
1956     }
1957 }
1958
1959 /*ARGSUSED*/
1960 static void
1961 handlePropertyChangeEvents(Widget w, XtPointer eventData, XEvent *event,
1962         Boolean *cont)
1963 {
1964     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) eventData;
1965     static Boolean firstTime = True;
1966     static Atom xa_WM_STATE = None;
1967     struct _wmStateStruct {
1968         CARD32 state;
1969         Window icon;
1970     } *prop;
1971     Atom actualType;
1972     int actualFormat;
1973     unsigned long nItems;
1974     unsigned long bytesAfter;
1975
1976
1977     DebugF('p', 20,
1978             fprintf(stderr, "handlePropertyChangeEvents() starting\n"));
1979     /* initialize things... */
1980     _DtTermProcessLock();
1981     if (firstTime) {
1982         xa_WM_STATE = XInternAtom(XtDisplay(w), "WM_STATE", True);
1983         firstTime = False;
1984     }
1985     _DtTermProcessUnlock();
1986
1987     DebugF('p', 20,
1988             fprintf(stderr, "event == %s\n",
1989             XGetAtomName(((XPropertyEvent *) event)->display,
1990             ((XPropertyEvent *) event)->atom)));
1991     /* is this a WM_STATE property change?... */
1992     if (((XPropertyEvent *) event)->atom == xa_WM_STATE) {
1993         /* if we have not yet initialized the buffer (and started listening
1994          * to the pty), then let's see if we are iconfied and do so...
1995          */
1996         if (!tw->term.tpd->termBuffer) {
1997             if (Success == XGetWindowProperty(
1998                     ((XPropertyEvent *) event)->display,
1999                     ((XPropertyEvent *) event)->window,
2000                     xa_WM_STATE,
2001                     0,
2002                     (sizeof(struct _wmStateStruct) + 3) / 4,
2003                     False,
2004                     AnyPropertyType,
2005                     &actualType,
2006                     &actualFormat,
2007                     &nItems,
2008                     &bytesAfter,
2009                     (unsigned char **) &prop)) {
2010                 if ((int) prop->state == IconicState) {
2011                     DebugF('p', 20,
2012                             fprintf(stderr, "event == IconicState\n"));
2013                     InitOrResizeTermBuffer((Widget) tw);
2014                 }
2015                 (void) XFree(prop);
2016             }
2017         }
2018     }
2019     DebugF('p', 20,
2020             fprintf(stderr, "handlePropertyChangeEvents() finished\n"));
2021 }
2022
2023 /*ARGSUSED*/
2024 static void
2025 InvokeTerminationCallback(Widget w, pid_t pid, int *stat_loc)
2026 {
2027     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
2028     DtTermSubprocessTerminationCallbackStruct cb;
2029
2030     (void) memset(&cb, '\0', sizeof(cb));
2031     cb.reason = DtCR_TERM_SUBPROCESS_TERMINATION; 
2032     cb.event = (XEvent *) 0;
2033     cb.pid = pid;
2034     cb.status = *stat_loc;
2035
2036     if (tw->term.subprocessTerminationCallback) {
2037         (void) XtCallCallbackList(w,
2038                 tw->term.subprocessTerminationCallback, (XtPointer) &cb);
2039     }
2040 }
2041
2042 /* SetValues...
2043  */
2044 /*ARGSUSED*/
2045 static Boolean
2046 SetValues(Widget cur_w, Widget ref_w, Widget w, ArgList args,
2047         Cardinal *num_args)
2048 {
2049     DtTermPrimitiveWidget cur_tw = (DtTermPrimitiveWidget) cur_w;
2050     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
2051     Boolean flag = False;       /* return value... */
2052
2053     /* DKS: this needs to be done later...
2054      */
2055
2056     /* install/remove/modify the subprocess callback process... */
2057     if (cur_tw->term.subprocessPid != tw->term.subprocessPid) {
2058         /* if there was an old handler... */
2059         if (tw->term.subprocessId) {
2060             /* remove the old handler... */
2061             (void) _DtTermPrimSubprocRemoveSubproc(w, tw->term.subprocessId);
2062             tw->term.subprocessId = (_termSubprocId) 0;
2063         }
2064
2065         /* if there is a new handler... */
2066         if (tw->term.subprocessPid) {
2067             /* add it old handler... */
2068             tw->term.subprocessId = _DtTermPrimAddSubproc(w,
2069                     tw->term.subprocessPid, InvokeTerminationCallback, NULL);
2070
2071             /* now that we have a handler, we may need to invoke it... */
2072             if (tw->term.subprocessTerminationCatch) {
2073                 (void) _DtTermPrimSetChildSignalHandler();
2074             }
2075         }
2076     }
2077
2078     if (cur_tw->term.jumpScroll != tw->term.jumpScroll) {
2079         /* we need to sync up the scroll before we make the change... */
2080         Boolean newJumpScroll = tw->term.jumpScroll;
2081
2082         tw->term.jumpScroll = cur_tw->term.jumpScroll;
2083         (void) _DtTermPrimScrollComplete(w, True);
2084         tw->term.jumpScroll = newJumpScroll;
2085     }
2086
2087     if (cur_tw->term.verticalScrollBar != tw->term.verticalScrollBar) {
2088         if (tw->term.verticalScrollBar) {
2089             /* set up the scrollbar values and callbacks... */
2090             (void) InitializeVerticalScrollBar(w, True);
2091         }
2092     }
2093
2094     /* change in rows or columns... */
2095     if ((cur_tw->term.rows != tw->term.rows) ||
2096             (cur_tw->term.columns != tw->term.columns)) {
2097         XtWidgetGeometry request;
2098         XtWidgetGeometry reply;
2099
2100         request.request_mode = (XtGeometryMask) 0;
2101
2102         /* handle changes in rows... */
2103         if (cur_tw->term.rows != tw->term.rows) {
2104             request.height = tw->term.rows * tw->term.heightInc +
2105                     2 * (tw->primitive.shadow_thickness +
2106                     tw->primitive.highlight_thickness + tw->term.marginWidth);
2107             request.request_mode |= CWHeight;
2108         }
2109
2110         /* handle changes in columns... */
2111         if (cur_tw->term.columns != tw->term.columns) {
2112             request.width = tw->term.columns  * tw->term.widthInc +
2113                     2 * (tw->primitive.shadow_thickness +
2114                     tw->primitive.highlight_thickness + tw->term.marginHeight);
2115             request.request_mode |= CWWidth;
2116         }
2117
2118         /* ignore the return result.  The switch statement makes
2119          * it possible to debug the result...
2120          */
2121         switch(XtMakeGeometryRequest(w, &request, &reply)) {
2122         case XtGeometryAlmost:
2123             break;
2124
2125         case XtGeometryYes:
2126             break;
2127
2128         case XtGeometryNo:
2129             break;
2130         }
2131
2132         if (XtIsRealized(w)) {
2133             /* Let's set the columns and rows back at this point.  They will
2134              * be set for real when and if the XtMakeGeometryRequest is
2135              * honoured...
2136              */
2137             tw->term.columns = cur_tw->term.columns;
2138             tw->term.rows = cur_tw->term.rows;
2139         }
2140     }
2141
2142     if (cur_tw->term.fontList != tw->term.fontList) {
2143         XtWidgetGeometry request;
2144         XtWidgetGeometry reply;
2145
2146         /* reset the font in the GC's... */
2147         tw->term.tpd->renderGC.fid = (Font) 0;
2148         tw->term.tpd->renderReverseGC.fid = (Font) 0;
2149         tw->term.tpd->clearGC.fid = (Font) 0;
2150
2151         /* Our font list changed on us.  We need to resize ourself and
2152          * recompute our width and height increment values...
2153          */
2154         tw->term.tpd->termFont = CreateRenderFont(w, tw->term.fontList,
2155                 &tw->term.fontSet, &tw->term.font);
2156
2157         /* look through our XFontSet or XFontStruct and adjust our
2158          * width and height increments...
2159          */
2160         (void) AdjustWindowUnits(w);
2161         request.height = tw->term.rows * tw->term.heightInc +
2162                 2 * (tw->primitive.shadow_thickness +
2163                 tw->primitive.highlight_thickness + tw->term.marginWidth);
2164         request.width = tw->term.columns  * tw->term.widthInc +
2165                 2 * (tw->primitive.shadow_thickness +
2166                 tw->primitive.highlight_thickness + tw->term.marginHeight);
2167         request.request_mode = CWWidth | CWHeight;
2168
2169         /* ignore the return result... */
2170         (void) XtMakeGeometryRequest(w, &request, &reply);
2171         (void) XmImVaSetValues(w,
2172             XmNfontList, tw->term.fontList,
2173             NULL);
2174         /* clear the cursor position so that we will recalculate the
2175          * im spotLocation with the new font metrics...
2176          */
2177         tw->term.tpd->IMCursorRow = -1;
2178         tw->term.tpd->IMCursorColumn = -1;
2179     }
2180
2181     if (cur_tw->term.boldFontList != tw->term.boldFontList) {
2182         /* Our bold font has been changed... */
2183         tw->term.tpd->boldTermFont = CreateRenderFont(w, tw->term.boldFontList,
2184                 (XFontSet *) 0, (XFontStruct **) 0);
2185     }
2186
2187     if (cur_tw->term.charCursorStyle != tw->term.charCursorStyle) {
2188         /* we need to refresh so that we won't get caught in the cursor
2189          * transition...
2190          */
2191         flag = True;
2192     }
2193
2194     if (cur_tw->term.reverseVideo != tw->term.reverseVideo) {
2195         /* we need to refresh so that we will turn on or turn off
2196          * reverse video...
2197          */
2198         flag = True;
2199     }
2200
2201     return(flag);
2202 }
2203
2204 /*
2205 ** Input:
2206 **    oldEnv   - pointer to a null terminated list of env strings
2207 **    mergeEnv - pointer to a null terminated list of env strings to merge
2208 ** 
2209 ** Return:
2210 **    a pointer to a new list of environment strings
2211 ** 
2212 **    It is the calling function's responsibility to free the memory
2213 **    allocated for the new list of strings.
2214 **
2215 **    If one of the merge environment strings already exists in the old
2216 **    environment, then the new environment string replaces the old string,
2217 **    otherwise it is appended to the new list of strings.
2218 */
2219 static char **
2220 _mergeEnv
2221 (
2222     char **oldEnv,
2223     char **mergeEnv
2224 )
2225 {
2226     char **newEnv;
2227     char **ppChar;
2228
2229     int    i1;
2230     int    numOld;
2231     int    numMerge;
2232     int    numNew;
2233     int    numReplace;
2234     int   *mergeIdx;
2235     
2236     /*
2237     ** count the number of new environment strings
2238     */
2239     for (numMerge = 0; mergeEnv[numMerge]; numMerge++)
2240         ;
2241     
2242     /*
2243     ** create and initialize a list of indexs for each of the new strings
2244     ** (assume they will all be appended (idx == -1) and adjust later)...
2245     */
2246     mergeIdx = (int *) XtMalloc(numMerge * sizeof(int));
2247     for (i1 = 0; i1 < numMerge; i1++) 
2248     {
2249         mergeIdx[i1] = -1;
2250     }
2251     
2252     /*
2253     ** count the number of strings in old environment, and see how many
2254     ** of the merge strings match old strings
2255     */
2256     numReplace = 0;
2257     for (numOld = 0; oldEnv[numOld]; numOld++)
2258     {
2259         /*
2260         ** how many old strings have to be replaced?
2261         */
2262         if (numReplace < numMerge) 
2263         {
2264             for (i1 = 0; i1 < numMerge; i1++)
2265             {
2266                 if (mergeIdx[i1] == -1)
2267                 {
2268                     char *idx;
2269                     idx = strchr(mergeEnv[i1], '=');
2270                     
2271                     if (strncmp(mergeEnv[i1], oldEnv[numOld],
2272                                 idx - mergeEnv[i1] + 1) == 0)
2273                     {
2274                         /*
2275                         ** we have a match, remember the index of
2276                         ** this string for later...
2277                         */
2278                         mergeIdx[i1] = numOld;
2279                         numReplace++;
2280                         break;
2281                     }
2282                 }
2283             }
2284         }
2285     }
2286     numNew = numOld + numMerge - numReplace;
2287     
2288     /*
2289     ** make room for the appended strings...
2290     **
2291     ** NOTE:
2292     ** We use malloc here instead of XtMalloc to keep Sentinel from
2293     ** complaining if putenv reallocs this space.  (Sentinel prints a
2294     ** warning if memory allocation functions are not used symmetrically
2295     ** (i.e. memory that is XtMalloc'd should be either XtFree'd or
2296     ** XtRealloc'd, not free'd or realloc'd).)
2297     */
2298     newEnv = (char **) malloc((numNew + 1) * sizeof(char *));
2299     if (newEnv == NULL)
2300     {
2301         printf("L10n MALLOC ERROR\n");
2302     }
2303
2304     /*
2305     ** copy the old environment into the new one, and null terminate the
2306     ** newEnv list...
2307     */
2308     memcpy(newEnv, oldEnv, numOld * sizeof(char *));
2309     newEnv[numNew] = (char *) NULL;
2310     
2311     /*
2312     ** now merge in the merge strings, the merge string will either replace
2313     ** the existing string (mergeIdx >= 0) or be appended to the list
2314     ** (mergeIdx < 0)
2315     */
2316     ppChar = newEnv + numOld;
2317     for (i1 = 0; i1 < numMerge; i1++)
2318     {
2319         if (mergeIdx[i1] < 0)
2320         {
2321             /*
2322             ** append it to the list
2323             */
2324             *ppChar = mergeEnv[i1];
2325             ppChar++;
2326         }
2327         else
2328         {
2329             /*
2330             ** replace the existing string
2331             */
2332             newEnv[mergeIdx[i1]] = mergeEnv[i1];
2333         }
2334     }
2335     
2336     XtFree((char *)mergeIdx);
2337     
2338     return(newEnv);
2339 }
2340
2341 /* Realize...
2342  */
2343 static void
2344 Realize(Widget w, XtValueMask *p_valueMask, XSetWindowAttributes *attributes)
2345 {
2346     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
2347     DtTermPrimData tpd = tw->term.tpd;
2348     Mask valueMask = *p_valueMask;
2349     sigset_t sigNew;
2350     char buffer[BUFSIZ];
2351     char **newEnv = (char **) 0;
2352     char **oldEnv = (char **) 0;
2353     extern char **environ;
2354     char *newEnvStrings[4];
2355     int i1;
2356     char *ptyMasterName = (char *) 0;
2357     XPoint imPoint;
2358     Arg args[20];
2359     XIMCallback xim_cb[4];
2360     Cardinal n = 0;
2361
2362     Debug('T', timeStamp("TermPrim Realize() starting"));
2363
2364     /* adjust rows and columns to the window size...
2365      */
2366     tw->term.columns = ((int)(tw->core.width - (2 * (tw->primitive.shadow_thickness +
2367             tw->primitive.highlight_thickness + tw->term.marginWidth)))) /
2368             tw->term.widthInc;
2369     tw->term.rows = ((int)(tw->core.height - (2 * (tw->primitive.shadow_thickness +
2370             tw->primitive.highlight_thickness + tw->term.marginHeight)))) /
2371             tw->term.heightInc;
2372
2373     /*
2374     valueMask |= CWBitGravity | CWDontPropagate;
2375     attributes->bit_gravity = ForgetGravity;
2376     attributes->do_not_propagate_mask = ButtonPressMask |
2377             ButtonReleaseMask | KeyPressMask | KeyReleaseMask |
2378             PointerMotionMask;
2379             */
2380     (void) XtCreateWindow(w, InputOutput, CopyFromParent, valueMask,
2381             attributes);
2382
2383     /*
2384      * register input method, and set callbacks for on the spot
2385      * support.
2386      */
2387     (void) XmImRegister(w, (unsigned int) NULL);
2388     imPoint.x = 0;
2389     imPoint.y = 0;
2390
2391     n = 0;
2392     XtSetArg(args[n], XmNspotLocation, &imPoint); n++;
2393     XtSetArg(args[n], XmNfontList, tw->term.fontList); n++;
2394     XtSetArg(args[n], XmNbackground, tw->core.background_pixel); n++;
2395     XtSetArg(args[n], XmNforeground, tw->primitive.foreground); n++;
2396     XtSetArg(args[n], XmNbackgroundPixmap, tw->core.background_pixmap); n++;
2397     XtSetArg(args[n], XmNlineSpace, tw->term.heightInc); n++;
2398
2399     /*
2400      * Register on the spot callbacks.
2401      */
2402     xim_cb[0].client_data = (XPointer)w;
2403     xim_cb[0].callback = (XIMProc)PreeditStart;
2404     xim_cb[1].client_data = (XPointer)w;
2405     xim_cb[1].callback = (XIMProc)PreeditDone;
2406     xim_cb[2].client_data = (XPointer)tw;
2407     xim_cb[2].callback = (XIMProc)PreeditDraw;
2408     xim_cb[3].client_data = (XPointer)w;
2409     xim_cb[3].callback = (XIMProc)PreeditCaret;
2410     XtSetArg(args[n], XmNpreeditStartCallback, &xim_cb[0]); n++;
2411     XtSetArg(args[n], XmNpreeditDoneCallback, &xim_cb[1]); n++;
2412     XtSetArg(args[n], XmNpreeditDrawCallback, &xim_cb[2]); n++;
2413     XtSetArg(args[n], XmNpreeditCaretCallback, &xim_cb[3]); n++;
2414
2415     XmImSetValues(w, args, n);
2416
2417     /* block sigchld while we do this... */
2418     (void) sigemptyset(&sigNew);
2419     (void) sigaddset(&sigNew, SIGCHLD);
2420     (void) sigprocmask(SIG_BLOCK, &sigNew, (sigset_t *) 0);
2421
2422     /* get reference terminal modes before we open the pty (so we don't
2423      * inherit them from the pty), before we fork (so we only do this
2424      * once for however many instances we create), and before we break
2425      * our association from our controlling terminal (so we have something
2426      * to inherit from)...
2427      */
2428     (void) _DtTermPrimPtyGetDefaultModes();
2429
2430     /* allocate a pty if appropriate... */
2431     if (tw->term.ptyAllocate) {
2432         int mode;
2433
2434         /* turn on suid root...  */
2435         _DtTermPrimToggleSuidRoot(True);
2436         tw->term.pty = _DtTermPrimGetPty(&tw->term.ptySlaveName,
2437                 &ptyMasterName);
2438         /* turn off suid root...  */
2439         _DtTermPrimToggleSuidRoot(False);
2440
2441         if (tw->term.pty < 0) {
2442             XmeWarning(w, "unable to get pty");
2443
2444             /* popup a warning dialog... */
2445             (void) _DtTermPrimWarningDialog(w, "unable to get pty");
2446         }
2447
2448         /* this is the Spec1170 way to do this.  We probably could 
2449            consolidate the various _DtTermPrimGetPtys at this point,
2450            but that's Truth & Beauty. */
2451         if (fcntl(tw->term.pty, F_SETFL, O_NONBLOCK |
2452                   fcntl(tw->term.pty, F_GETFL, 0)) == -1)
2453         {
2454             XmeWarning(w, "unable to set non-blocking on pty");
2455
2456             /* popup a warning dialog... */
2457             (void) _DtTermPrimWarningDialog(w, 
2458                                        "unable to set non-blocking on pty");
2459         }
2460
2461
2462         if (ptyMasterName) {
2463             (void) free(ptyMasterName);
2464         }
2465     }
2466
2467     /* set the initial winsize structure before we kick off the
2468      * subprocess...
2469      */
2470     if (tw->term.pty >= 0) {
2471         (void) _DtTermPrimPtySetWindowSize(tw->term.pty,
2472                    tw->term.columns * tw->term.widthInc + 
2473                    (2 * (tw->primitive.shadow_thickness +
2474                          tw->primitive.highlight_thickness + 
2475                          tw->term.marginWidth)),
2476                    tw->term.rows * tw->term.heightInc +
2477                    (2 * (tw->primitive.shadow_thickness +
2478                          tw->primitive.highlight_thickness +
2479                          tw->term.marginHeight)),
2480                    tw->term.rows, tw->term.columns);
2481     }
2482
2483     /* get the utmp line name to use for searching later... */
2484     if (tw->term.pty >= 0) {
2485         tw->term.tpd->utmpId = _DtTermPrimUtmpGetUtLine(-1,
2486                 tw->term.ptySlaveName);
2487     }
2488
2489     /*
2490     ** If pointerBlank is true, then turn on the pointer with blanking,
2491     *  else turn it on to always stay on.
2492     */
2493     if (tw->term.pointerBlank) {(void) _DtTermPrimPointerOn((Widget)tw); }
2494     else   XDefineCursor(XtDisplay(tw), XtWindow(tw), tw->term.pointerShape);
2495     _DtTermPrimRecolorPointer((Widget)tw) ;
2496
2497     /* kick off a subprocess if appropriate.  Don't kick one off if
2498      * we didn't get a pty...
2499      */
2500     if (tw->term.subprocessExec && (tw->term.pty >= 0)) {
2501
2502         /* DKS: maybe we need to start passing the cmd earlier and not
2503          * fake it here...
2504          */
2505         if (!tw->term.subprocessCmd && tw->term.subprocessArgv) {
2506             tw->term.subprocessCmd = *tw->term.subprocessArgv;
2507         }
2508
2509         /* modify the environment for our child process...
2510          */
2511         /* set the environment variables for TERM, LINES, COLUMNS... */
2512         oldEnv = environ;
2513
2514         i1 = 0;
2515 #ifdef  SETENV_LINES_AND_COLS
2516         (void) sprintf(buffer, "LINES=%d", tw->term.rows);
2517         newEnvStrings[i1] = XtMalloc(strlen(buffer) + 1);
2518         (void) strcpy(newEnvStrings[i1++], buffer);
2519
2520         (void) sprintf(buffer, "COLUMNS=%d", tw->term.columns);
2521         newEnvStrings[i1] = XtMalloc(strlen(buffer) + 1);
2522         (void) strcpy(newEnvStrings[i1++], buffer);
2523 #endif  /* SETENV_LINES_AND_COLS */
2524
2525         if (tw->term.termName && *tw->term.termName)
2526         {
2527             char *fmt = "TERM=%s";
2528
2529             newEnvStrings[i1] =
2530               XtMalloc(strlen(tw->term.termName) + strlen(fmt) + 1);
2531             (void) sprintf(newEnvStrings[i1], fmt, tw->term.termName);
2532             i1++;
2533         }
2534         /* null term the list of new env strings... */
2535         newEnvStrings[i1] = (char *) 0;
2536         
2537         environ = _mergeEnv(oldEnv, newEnvStrings);
2538
2539         tw->term.subprocessPid = _DtTermPrimSubprocExec(w,
2540                 tw->term.ptySlaveName,
2541                 tw->term.consoleMode,
2542                 tw->term.subprocessCWD,
2543                 tw->term.subprocessCmd, tw->term.subprocessArgv,
2544                 tw->term.subprocessLoginShell);
2545
2546         /* free up the new environ... */
2547         for (i1 = 0; newEnvStrings[i1]; i1++)
2548         {
2549             (void) XtFree(newEnvStrings[i1]);
2550         }
2551
2552         if (environ) {
2553             /*
2554             ** free environ (rather than XtFree it) is since it was
2555             ** malloc'd (not XtMalloc'd) in _mergeEnv...
2556             */
2557             (void) free((char *) environ);
2558         }
2559         environ = oldEnv;
2560     }
2561
2562     /* set up a signal handler if appropriate... */
2563     if (tw->term.subprocessPid >= 0)
2564     {
2565         tw->term.subprocessId = _DtTermPrimAddSubproc(w,
2566                                     tw->term.subprocessPid,
2567                                     InvokeTerminationCallback, NULL);
2568         if (tw->term.subprocessTerminationCatch)
2569         {
2570             (void)_DtTermPrimSetChildSignalHandler();
2571         }
2572     }
2573
2574     /* unblock sigchld now that we are done... */
2575     (void) sigprocmask(SIG_UNBLOCK, &sigNew, (sigset_t *) 0);
2576     Debug('T', timeStamp("TermPrim Realize() finished"));
2577 }
2578
2579 /* Destroy...
2580  */
2581 static void
2582 Destroy(Widget w)
2583 {
2584     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
2585
2586     /* remove our handlers on our shell widget... */
2587     { 
2588         Widget sw ;
2589
2590         for (sw = w; !XtIsShell(sw); sw = XtParent(sw))
2591             ;
2592         (void) XtRemoveEventHandler(sw, (EventMask) StructureNotifyMask,
2593                 False, handleProcessStructureNotifyEvent, (Opaque) w);
2594         (void) XtRemoveEventHandler(sw, (EventMask) PropertyChangeMask,
2595                 False, handlePropertyChangeEvents, (Opaque) w);
2596     }
2597
2598     /*
2599     ** Unregister our input method (this fixes CMVC 8146).
2600     */
2601     XmImUnregister(w);
2602
2603     /* clean up pty specific stuff...
2604      */
2605     /* remove the pty input handler... */
2606     if (tw->term.tpd && tw->term.tpd->ptyInputId) {
2607         (void) XtRemoveInput(tw->term.tpd->ptyInputId);
2608         tw->term.tpd->ptyInputId = (XtInputId) 0;
2609     }
2610
2611     /* let's be proactive and send a SIGHUP to all the processes in this
2612      * instances process group.  For safety sake, let's not do anything
2613      * if the process id is not >1 (since use of 1 will send the signal
2614      * to all processes).
2615      */
2616     /* turn on suid root...
2617      */
2618     _DtTermPrimToggleSuidRoot(True);
2619     if (tw->term.subprocessPid > 1) {
2620         (void) kill(-tw->term.subprocessPid, SIGHUP);
2621     }
2622     /* turn off suid root...
2623      */
2624     _DtTermPrimToggleSuidRoot(False);
2625
2626     /* clean up our utmp entry... */
2627     if (tw->term.tpd && tw->term.tpd->utmpId && *tw->term.tpd->utmpId) {
2628         _DtTermPrimUtmpEntryDestroy(w, tw->term.tpd->utmpId);
2629         (void) XtFree(tw->term.tpd->utmpId);
2630         tw->term.tpd->utmpId = (char *) 0;
2631     }
2632
2633     /* close and release the...
2634      */
2635     if (tw->term.pty >= 0) {
2636         /* close the pty file descriptor so that:
2637          *          - the child will (passively) get SIGHUP'ed.
2638          *          - the child will get EOF on stdin.
2639          */
2640         (void) close(tw->term.pty);
2641       /* release the pty (restore owner, group, mode)... */
2642       if (tw->term.ptySlaveName) {
2643             (void) _DtTermPrimReleasePty(tw->term.ptySlaveName);
2644         }
2645     }
2646
2647     /* remove the subproc termination callback... */
2648     if (tw->term.subprocessId) {
2649         _DtTermPrimSubprocRemoveSubproc(w, tw->term.subprocessId);
2650         tw->term.subprocessId = (_termSubprocId) 0;
2651     }
2652
2653     /* free storage for current working directory name*/
2654     if ( tw->term.subprocessCWD) {
2655        XtFree(tw->term.subprocessCWD);
2656     }
2657
2658     /* flush the log file */
2659     if (tw->term.logging ) {
2660       _DtTermPrimCloseLog(tw) ;
2661      }
2662
2663     if (tw->term.boldFont) {
2664        (void) XFreeFont(XtDisplay(w), tw->term.boldFont);
2665      }
2666     if (tw->term.boldFontSet) {
2667        (void) XFreeFontSet(XtDisplay(w), tw->term.boldFontSet);
2668      }
2669
2670     /* remove the termData structure contents, followed by the structure...
2671      */
2672     if (tw->term.tpd) {
2673         /* remove the cursor timeout... */
2674         if (tw->term.tpd->cursorTimeoutId) {
2675             (void) XtRemoveTimeOut(tw->term.tpd->cursorTimeoutId);
2676             tw->term.tpd->cursorTimeoutId = (XtIntervalId) 0;
2677         }
2678
2679         /* free up all our GC's...
2680          */
2681         /* render GC... */
2682         if (tw->term.tpd->renderGC.gc) {
2683             (void) XFreeGC(XtDisplay(w), tw->term.tpd->renderGC.gc);
2684             tw->term.tpd->renderGC.gc = (GC) 0;
2685         }
2686         if (tw->term.tpd->renderReverseGC.gc) {
2687             (void) XFreeGC(XtDisplay(w), tw->term.tpd->renderReverseGC.gc);
2688             tw->term.tpd->renderReverseGC.gc = (GC) 0;
2689         }
2690         /* clear GC... */
2691         if (tw->term.tpd->clearGC.gc) {
2692             (void) XFreeGC(XtDisplay(w), tw->term.tpd->clearGC.gc);
2693             tw->term.tpd->clearGC.gc = (GC) 0;
2694         }
2695         /* cursor GC... */
2696         if (tw->term.tpd->cursorGC.gc) {
2697             (void) XFreeGC(XtDisplay(w), tw->term.tpd->cursorGC.gc);
2698             tw->term.tpd->cursorGC.gc = (GC) 0;
2699         }
2700
2701         /* free up our buffers... */
2702         if (tw->term.tpd->historyBuffer) {
2703             _DtTermPrimBufferFreeBuffer(tw->term.tpd->historyBuffer);
2704             tw->term.tpd->historyBuffer = NULL;
2705         }
2706
2707         if (tw->term.tpd->termBuffer) {
2708             _DtTermPrimBufferFreeBuffer(tw->term.tpd->termBuffer);
2709             tw->term.tpd->termBuffer = NULL;
2710         }
2711
2712         /* free up the scrollRefreshRows... */
2713         if (tw->term.tpd->scrollRefreshRows) {
2714             (void) XtFree((char *) tw->term.tpd->scrollRefreshRows);
2715             tw->term.tpd->scrollRefreshRows = (Boolean *) 0;
2716         }
2717
2718         /* free up the selection information */
2719         if (tw->term.tpd->selectInfo) {
2720             (void) _DtTermPrimSelectDestroy(w, tw->term.tpd->selectInfo);
2721             tw->term.tpd->selectInfo = (TermSelectInfo) 0;
2722         }
2723
2724         /* free up pending text... */
2725         if (tw->term.tpd->pendingRead) {
2726             (void) _DtTermPrimPendingTextDestroy(tw->term.tpd->pendingRead);
2727             tw->term.tpd->pendingRead = (PendingText) 0;
2728         }
2729         if (tw->term.tpd->pendingWrite) {
2730             (void) _DtTermPrimPendingTextDestroy(tw->term.tpd->pendingWrite);
2731             tw->term.tpd->pendingWrite = (PendingText) 0;
2732         }
2733
2734         if (tw->term.tpd->capsLockKeyCodes)
2735                  (void) XtFree((char *)tw->term.tpd->capsLockKeyCodes) ;
2736
2737         (void) _DtTermPrimDestroyFont(w,tw->term.tpd->boldTermFont) ;
2738         (void) _DtTermPrimDestroyFont(w,tw->term.tpd->termFont) ;
2739
2740         if (tw->term.ptyAllocate && tw->term.ptySlaveName)
2741                (void) XtFree((char *)tw->term.ptySlaveName);
2742          
2743
2744         if (tw->term.tpd->context)
2745                  (void) XtFree((char *)tw->term.tpd->context);
2746
2747         /* free up the termData structure... */
2748         (void) XtFree((char *) tw->term.tpd);
2749         tw->term.tpd = (DtTermPrimData) 0;
2750
2751     }
2752 }
2753
2754 /* _DtTermPrimActionEnter...
2755  */
2756 void
2757 _DtTermPrimActionEnter(Widget w, XEvent *event,
2758         String *params, Cardinal *num_params)
2759 {
2760     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
2761
2762     Debug('F', fprintf(stderr, ">>enterEvent starting\n"));
2763 #ifdef  NOTDEF
2764     Debug('F', fprintf(stderr,
2765             ">>  widget: name=\"%s\"  widget=0x%lx  window=0x%lx\n",
2766             tw->core.name, tw, XtWindow(w)));
2767     Debug('F', fprintf(stderr,
2768             ">>  event: window=0x%lx\n  mode=%d  detail=%d\n",
2769             event->xcrossing.window, event->xcrossing.mode,
2770             event->xcrossing.detail));
2771 #endif  /* NOTDEF */
2772     Debug('F', _DtTermPrimDebugDumpEvent(stderr, w, event));
2773
2774     if ((_XmGetFocusPolicy(w) != XmEXPLICIT) &&
2775             !(tw->term.hasFocus) &&
2776             event->xcrossing.focus &&
2777             (event->xcrossing.detail != NotifyInferior)) {
2778         tw->term.hasFocus = True;
2779         _DtTermPrimCursorChangeFocus(w);
2780     }
2781
2782     if ( tw->term.pointerBlank ) 
2783         _DtTermPrimPointerFreeze((Widget)tw, False);
2784
2785     /* update the caps lock flag... */
2786     (void) CapsLockUpdate(w,
2787             (event->xcrossing.state & LockMask) != 0);
2788
2789     _XmPrimitiveEnter(w, event, params, num_params);
2790 }
2791
2792
2793 /* _DtTermPrimActionLeave...
2794  */
2795 void
2796 _DtTermPrimActionLeave(Widget w, XEvent *event,
2797         String *params, Cardinal *num_params)
2798 {
2799     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
2800
2801     Debug('F', fprintf(stderr, ">>leaveEvent starting\n"));
2802 #ifdef  NOTDEF
2803     Debug('F', fprintf(stderr,
2804             ">>  widget: name=\"%s\"  widget=0x%lx  window=0x%lx\n",
2805             tw->core.name, tw, XtWindow(w)));
2806     Debug('F', fprintf(stderr,
2807             ">>  event: window=0x%lx\n  mode=%d  detail=%d\n",
2808             event->xcrossing.window, event->xcrossing.mode,
2809             event->xcrossing.detail));
2810 #endif  /* NOTDEF */
2811     Debug('F', _DtTermPrimDebugDumpEvent(stderr, w, event));
2812
2813     if ((_XmGetFocusPolicy(w) != XmEXPLICIT) &&
2814             tw->term.hasFocus &&
2815             event->xcrossing.focus &&
2816             (event->xcrossing.detail != NotifyInferior)) {
2817             tw->term.hasFocus = False;
2818         _DtTermPrimCursorChangeFocus(w);
2819     }
2820
2821     if ( tw->term.pointerBlank ) 
2822         _DtTermPrimPointerFreeze((Widget)tw, True);
2823
2824     /* update the caps lock flag... */
2825     (void) CapsLockUpdate(w,
2826             (event->xcrossing.state & LockMask) != 0);
2827
2828     _XmPrimitiveLeave(w, event, params, num_params);
2829 }
2830
2831 static Boolean
2832 moreInput(int pty)
2833 {
2834     fd_set readFD;
2835     struct timeval timeout;
2836
2837     /* do a non-blocking select to see if we have any more input.  If so,
2838      * we don't need to turn the cursor back on.
2839      */
2840     FD_ZERO(&readFD);
2841     FD_SET(pty, &readFD);
2842     timeout.tv_sec = 0;
2843     timeout.tv_usec = 0;
2844     if (!((select(pty + 1, &readFD, 0, 0, &timeout) > 0) &&
2845           (FD_ISSET(pty, &readFD))))
2846         return(False);
2847     return(True);
2848 }
2849
2850 /*ARGSUSED*/
2851 static void
2852 readPty(XtPointer client_data, int *source, XtInputId *id)
2853 {
2854     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) client_data;
2855     DtTermPrimData tpd = tw->term.tpd;
2856     unsigned char buffer[BUFSIZ];
2857     int len;
2858     unsigned char *dangleBuffer;
2859     int dangleBufferLen;
2860     int retLen;
2861     PendingTextChunk chunk = (PendingTextChunk) 0;
2862
2863     Debug('i', fprintf(stderr, ">>readPty() starting\n"));
2864     tpd->readInProgress = True;
2865     (void) _DtTermPrimCursorOff((Widget) tw);
2866     /* if we are using a history buffer and have scrolled into it, we
2867      * need to snap back down before we do anything...
2868      */
2869     if (tpd->useHistoryBuffer && (tpd->topRow < 0)) {
2870         (void) _DtTermPrimScrollTextTo((Widget) tw, 0);
2871         (void) _DtTermPrimScrollComplete((Widget) tw, True);
2872     }
2873
2874     if (TextIsPending(tpd->pendingRead)) {
2875         /* take text from the pendingRead buffer instead of doing a read...
2876          */
2877         chunk = _DtTermPrimPendingTextGetChunk(tpd->pendingRead);
2878         len = chunk->len;
2879         (void) memcpy(buffer, chunk->bufPtr, len);
2880     } else {
2881         len = read(*source, buffer, sizeof(buffer));
2882         Debug('i', fprintf(stderr, ">>readPty() read len=%d\n", len));
2883         if (isDebugFSet('i', 1)) {
2884 #ifdef  BBA
2885 #pragma BBA_IGNORE
2886 #endif  /*BBA*/
2887             int i1;
2888
2889             (void) fprintf(stderr,
2890                     ">>readPty() read %d bytes", len);
2891             if (len > 0) {
2892                 for (i1 = 0; i1 < len; i1++) {
2893                     if (!(i1 % 20))
2894                         fputs("\n    ", stderr);
2895                     (void) fprintf(stderr, " %02x", buffer[i1]);
2896                 }
2897                 (void) fprintf(stderr, "\n");
2898             }
2899         }
2900     }
2901         
2902     if (len > 0) {
2903         if (!tpd->windowMapped && tw->term.mapOnOutput) {
2904             /*
2905             ** map window unless it is too early...
2906             */
2907             if (tw->term.mapOnOutputDelay)
2908                 if ((time((time_t *) 0) - tpd->creationTime) >
2909                         tw->term.mapOnOutputDelay) {
2910                 /*
2911                 ** time is up
2912                 */
2913                 tw->term.mapOnOutputDelay = 0 ;
2914             }
2915
2916             if (!tw->term.mapOnOutputDelay) {
2917                 Widget sw;
2918
2919                 for (sw = (Widget)tw; !XtIsShell(sw); sw = XtParent(sw))
2920                     ;
2921                 XtMapWidget(sw);
2922             }
2923         }
2924  
2925         if (tw->term.log_on) {
2926             _DtTermPrimWriteLog(tw, buffer, len) ;
2927         }
2928
2929         if (tw->term.outputLogCallback) {
2930             DtTermOutputLogCallbackStruct cb;
2931
2932             cb.reason = DtCR_TERM_OUTPUT_LOG;
2933             cb.event = (XEvent *) 0;
2934             cb.text = buffer;
2935             cb.length = len;
2936
2937             (void) XtCallCallbackList((Widget) tw,
2938                     tw->term.outputLogCallback, &cb);
2939         }
2940
2941         if (!_DtTermPrimParseInput((Widget) tw, buffer, len,
2942                 &dangleBuffer, &dangleBufferLen)) {
2943             /* we were not able to write out everything and
2944              * we need to stuff away the pending text...
2945              */
2946             if (chunk) {
2947                 /* we didn't finish up the pending text chunk we were
2948                  * working on, so update the pointers and continue...
2949                  */
2950                 (void) _DtTermPrimPendingTextReplace(chunk, dangleBuffer,
2951                         dangleBufferLen);
2952             } else {
2953                 (void) _DtTermPrimPendingTextAppend(tpd->pendingRead,
2954                         dangleBuffer, dangleBufferLen);
2955             }
2956             (void) XtFree((char *) dangleBuffer);
2957         } else if (chunk) {
2958             /* we finished a pending chunk, so let's move on... */
2959             _DtTermPrimPendingTextRemoveChunk(tpd->pendingRead, chunk);
2960         }
2961         if (!tpd->ptyInputId) {
2962             /* we need to wait until we get a graphicsexpose (count==0)
2963              * or a noexpose...
2964              */
2965             /* we know we have more input, so we don't need to turn on
2966              * the cursor...
2967              */
2968             tpd->readInProgress = False;
2969             Debug('i', fprintf(stderr, ">>readPty() finished\n"));
2970             return;
2971         }
2972     }
2973
2974     if (!moreInput(tw->term.pty)) {
2975         /* we won't be getting an input select so we need to check on
2976          * pending text and force a read if we still have some...
2977          */
2978         if (TextIsPending(tpd->pendingRead)) {
2979             (void) XtAppAddTimeOut(XtWidgetToApplicationContext((Widget) tw),
2980                     0, _DtTermPrimForcePtyRead, (XtPointer) tw);
2981         } else {
2982             /* turn the cursor back on... */
2983             (void) _DtTermPrimCursorOn((Widget) tw);
2984         }
2985     }
2986     tpd->readInProgress = False;
2987     Debug('i', fprintf(stderr, ">>readPty() finished\n"));
2988 }
2989
2990 /*ARGSUSED*/
2991 void
2992 _DtTermPrimForcePtyRead(XtPointer client_data, XtIntervalId *id)
2993 {
2994     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) client_data;
2995     DtTermPrimData tpd = tw->term.tpd;
2996     int fd = tw->term.pty;
2997
2998     (void) _DtTermPrimStartOrStopPtyInput((Widget) tw);
2999
3000     if (TextIsPending(tpd->pendingRead)) {
3001         (void) readPty(client_data, &fd, &tpd->ptyInputId);
3002     }
3003 }
3004
3005 void
3006 _DtTermPrimLoopBackData(Widget w, char *data, int dataLength)
3007 {
3008     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
3009     DtTermPrimData tpd = tw->term.tpd;
3010     int fd = tw->term.pty;
3011
3012     /* queue up the pending text... */
3013     (void) _DtTermPrimPendingTextAppend(tpd->pendingRead, (unsigned char *) data,
3014             dataLength);
3015
3016     /* if we have a read in process, we can return now... */
3017     if (tpd->readInProgress) {
3018         return;
3019     }
3020
3021     /* if we are set up to select on pty input, then we can force a read
3022      * now...
3023      */
3024     if (tpd->ptyInputId) {
3025         (void) readPty((XtPointer) w, &fd, &tpd->ptyInputId);
3026     }
3027
3028     /* if not, we will force a read when we turn select on input back
3029      * on...
3030      */
3031 }
3032     
3033 void
3034 DtTermDisplaySend
3035 (
3036     Widget                w,
3037     unsigned char        *buffer,
3038     int                   length
3039 )
3040 {
3041     _DtTermWidgetToAppContext(w);
3042
3043     /* for now, it looks like _DtTermPrimLoopBackData will take care
3044      * of everything for us...
3045      */
3046     _DtTermAppLock(app);
3047     (void) _DtTermPrimLoopBackData(w, (char *) buffer, length);
3048     _DtTermAppUnlock(app);
3049 }
3050
3051 /*ARGSUSED*/
3052 static void
3053 writePty(XtPointer client_data, int *source, XtInputId *id)
3054 {
3055     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) client_data;
3056     DtTermPrimData tpd = tw->term.tpd;
3057
3058     Debug('o', fprintf(stderr, ">>writePty() starting\n"));
3059     
3060     /* 
3061     ** write some text from list of pending text chunks
3062     */
3063     _DtTermPrimPendingTextWrite(tpd->pendingWrite, tw->term.pty);
3064
3065     /* 
3066     ** turn off the write select as appropriate
3067     */
3068     _DtTermPrimStartOrStopPtyOutput((Widget)client_data);
3069     Debug('o', fprintf(stderr, ">>writePty() finished\n"));
3070 }
3071
3072 /*ARGSUSED*/
3073 void
3074 _DtTermPrimActionKeyRelease(Widget w, XEvent *event, String *params,
3075         Cardinal *num_params)
3076 {
3077     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
3078     DtTermPrimData tpd = tw->term.tpd;
3079     XKeyEvent *keyEvent = (XKeyEvent *) event;
3080     int i;
3081     
3082     Debug('i', fprintf(stderr, ">>_DtTermPrimActionKeyRelease() starting\n"));
3083     if (keyEvent->type != KeyRelease) {
3084         (void) fprintf(stderr,
3085                 "_DtTermPrimActionKeyRelease: incorrect event type %d\n",
3086                 keyEvent->type);
3087         return;
3088     }
3089
3090     /* check for caps lock... */
3091     for (i = 0; i < tpd->numCapsLockKeyCodes; i++) {
3092         if (tpd->capsLockKeyCodes[i] == keyEvent->keycode) {
3093             /* caps lock has toggled... */
3094             (void) CapsLockUpdate(w, !tpd->capsLock);
3095             break;
3096         }
3097     }
3098 }
3099
3100 /*ARGSUSED*/
3101 void
3102 _DtTermPrimActionKeyInput(Widget w, XEvent *event, String *params,
3103         Cardinal *num_params)
3104 {
3105     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
3106     DtTermPrimData tpd = tw->term.tpd;
3107     XKeyEvent *keyEvent = (XKeyEvent *) event;
3108     KeySym keysym;
3109     Status status;
3110     unsigned char string[BUFSIZ];
3111     int nbytes;
3112     int i;
3113     Boolean synEscape = False;  /* synthesize escape key from meta key */
3114                                 /* -kshMode                            */
3115
3116     Debug('i', fprintf(stderr, ">>_DtTermPrimActionKeyInput() starting\n"));
3117     if (keyEvent->type != KeyPress) {
3118         (void) fprintf(stderr, "_DtTermPrimActionKeyInput: incorrect event type %d\n",
3119                 keyEvent->type);
3120         return;
3121     }
3122     if (KEYBOARD_LOCKED(tpd->keyboardLocked)) {
3123         /* keyboard locked -- ring the bell...
3124          */
3125         (void) _DtTermPrimBell(w);
3126         return;
3127      }
3128
3129     if (tw->term.kshMode &&
3130             ((keyEvent->state & tpd->metaMask) == tpd->metaMask)) {
3131        keyEvent->state &= ~tpd->metaMask;
3132        synEscape = True ;
3133      }
3134        
3135     /* check for caps lock... */
3136     for (i = 0; i < tpd->numCapsLockKeyCodes; i++) {
3137         if (tpd->capsLockKeyCodes[i] == keyEvent->keycode) {
3138             /* caps lock has toggled... */
3139             (void) CapsLockUpdate(w, !tpd->capsLock);
3140             break;
3141         }
3142     }
3143
3144     /* I've pulled the following from hpterm2.0's input.c.  I don't
3145      * understand any of it, and we need to get some documentation on
3146      * it.
3147      */
3148
3149     nbytes = XmImMbLookupString(w, keyEvent, (char *) string, sizeof(string),
3150             &keysym, &status);
3151     if (XBufferOverflow == status) {
3152         nbytes = 0;
3153     }
3154
3155 #ifdef  XOR_CAPS_LOCK
3156     /* if lock and shift are both pressed, let's invert the case of all
3157      * upper and lower case characters...
3158      */
3159     if ((keyEvent->state & (LockMask | ShiftMask)) == (LockMask | ShiftMask)) {
3160         for (i = 0; i < nbytes; i++) {
3161             if (isupper(string[i])) {
3162                 string[i] = _tolower(string[i]);
3163             } else if (islower(string[i])) {
3164                 string[i] = _toupper(string[i]);
3165             }
3166         }
3167     }
3168 #endif  /* XOR_CAPS_LOCK */
3169
3170         
3171     if ((nbytes > 0) && (tw->term.inputVerifyCallback)) {
3172         DtTermInputVerifyCallbackStruct cb;
3173
3174         cb.reason = DtCR_TERM_INPUT_VERIFY;
3175         cb.event = event;
3176         cb.doit = True;
3177         cb.text = string;
3178         cb.length = nbytes;
3179
3180         /* invoke the callbacks... */
3181         (void) XtCallCallbackList(w, tw->term.inputVerifyCallback, &cb);
3182
3183         /* if doit was turned off, forget about the string... */
3184         if (!cb.doit) {
3185             nbytes = 0;
3186         }
3187     }
3188
3189     if (nbytes > 0) {
3190         unsigned char *start;
3191         unsigned char *end;
3192
3193         /* perform margin bell functionality if necessary... */
3194         if (tw->term.marginBell &&
3195                 ((tw->term.columns - tw->term.nMarginBell) ==
3196                     tpd->cursorColumn)) {
3197             _DtTermPrimBell(w);
3198         }
3199                 
3200         /* synthesize escape unless it was CR or Vertical Tab */
3201         if (synEscape && *string != '\r' && *string != 0x0B) 
3202             (void) _DtTermPrimSendInput(w, (unsigned char *) "\033", 1);
3203             
3204         /* for pointer blanking                               */
3205         if (tw->term.pointerBlank && *string != '\r' && *string != 0x0B) 
3206             _DtTermPrimPointerOff((Widget)tw,(XtIntervalId *)NULL) ;
3207
3208         for (end = string; nbytes > 0; )  {
3209             for (start = end; (nbytes > 0) && (*end != '\r'); nbytes--, end++)
3210                 ;
3211             if ((nbytes > 0) && (*end == '\r')) {
3212                 (void) end++;
3213                 (void) nbytes--;
3214             }
3215             (void) _DtTermPrimSendInput(w, start, end - start);
3216             if (tpd->autoLineFeed && (end[-1] == '\r')) {
3217                 (void) _DtTermPrimSendInput(w, (unsigned char *) "\n", 1);
3218             }
3219         }
3220     }
3221
3222     Debug('i', fprintf(stderr, ">>_DtTermPrimActionKeyInput() finished\n"));
3223 }
3224
3225 void
3226 _DtTermPrimSendInput
3227 (
3228     Widget                w,
3229     unsigned char        *buffer,
3230     int                   length
3231 )
3232 {
3233     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
3234     DtTermPrimData        tpd = tw->term.tpd;
3235
3236     if (length > 0) {
3237         (void) _DtTermPrimPendingTextAppend(tpd->pendingWrite, buffer, length);
3238         (void) _DtTermPrimStartOrStopPtyOutput(w);
3239
3240         if (tpd->halfDuplex) {
3241             DtTermDisplaySend(w, buffer, length);
3242         }
3243     }
3244 }
3245
3246 void
3247 DtTermSubprocSend
3248 (
3249     Widget                w,
3250     unsigned char        *buffer,
3251     int                   length
3252 )
3253 {
3254     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
3255     DtTermPrimData        tpd = tw->term.tpd;
3256     _DtTermWidgetToAppContext(w);
3257
3258     /* queue up all text send from outside the widget... */
3259     _DtTermAppLock(app);
3260     if (length > 0) {
3261         (void) _DtTermPrimPendingTextAppend(tpd->pendingWrite, buffer, length);
3262         (void) _DtTermPrimStartOrStopPtyOutput(w);
3263         if (tpd->halfDuplex) {
3264             DtTermDisplaySend(w, buffer, length);
3265         }
3266     }
3267     _DtTermAppUnlock(app);
3268 }
3269
3270 /*ARGSUSED*/
3271 void
3272 _DtTermPrimActionFocusIn(Widget w, XEvent *event, String *params,
3273         Cardinal *num_params)
3274 {
3275     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
3276
3277     Debug('F', fprintf(stderr, ">>focusIn starting\n"));
3278 #ifdef  NOTDEF
3279     Debug('F', fprintf(stderr,
3280             ">>  widget: name=\"%s\"  widget=0x%lx  window=0x%lx\n",
3281             tw->core.name, tw, XtWindow(w)));
3282     Debug('F', fprintf(stderr,
3283             ">>  event: window=0x%lx\n  mode=%d  detail=%d\n",
3284             event->xfocus.window, event->xfocus.mode, event->xfocus.detail));
3285 #endif  /* NOTDEF */
3286     Debug('F', _DtTermPrimDebugDumpEvent(stderr, w, event));
3287
3288     if (
3289 #ifdef  MOTIF_TEXT_BUG
3290             event->xfocus.send_event &&
3291 #endif  /* MOTIF_TEXT_BUG */
3292             !(tw->term.hasFocus)) {
3293         tw->term.hasFocus = True;
3294         _DtTermPrimCursorChangeFocus(w);
3295         if (_XmGetFocusPolicy(w) == XmEXPLICIT) {
3296             if (((XmPrimitiveWidgetClass) XtClass(w))
3297                     ->primitive_class.border_highlight) {
3298                 (void) (*((XmPrimitiveWidgetClass) XtClass(w))
3299                         ->primitive_class.border_highlight)(w);
3300             }
3301         }
3302     }
3303     (void) _XmPrimitiveFocusIn(w, event, params, num_params);
3304 }
3305
3306 /*ARGSUSED*/
3307 void
3308 _DtTermPrimActionFocusOut(Widget w, XEvent *event, String *params,
3309         Cardinal *num_params)
3310 {
3311     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
3312
3313     Debug('F', fprintf(stderr, ">>focusOut starting\n"));
3314 #ifdef  NOTDEF
3315     Debug('F', fprintf(stderr,
3316             ">>  widget: name=\"%s\"  widget=0x%lx  window=0x%lx\n",
3317             tw->core.name, tw, XtWindow(w)));
3318     Debug('F', fprintf(stderr,
3319             ">>  event: window=0x%lx\n  mode=%d  detail=%d\n",
3320             event->xfocus.window, event->xfocus.mode, event->xfocus.detail));
3321 #endif  /* NOTDEF */
3322     Debug('F', _DtTermPrimDebugDumpEvent(stderr, w, event));
3323
3324     if (
3325 #ifdef  MOTIF_TEXT_BUG
3326             event->xfocus.send_event &&
3327 #endif  /* MOTIF_TEXT_BUG */
3328             tw->term.hasFocus) {
3329         tw->term.hasFocus = False;
3330         _DtTermPrimCursorChangeFocus(w);
3331         if (_XmGetFocusPolicy(w) == XmEXPLICIT) {
3332             if (((XmPrimitiveWidgetClass) XtClass(w))
3333                     ->primitive_class.border_unhighlight) {
3334                 (void) (*((XmPrimitiveWidgetClass) XtClass(w))
3335                         ->primitive_class.border_unhighlight)(w);
3336             }
3337         }
3338     }
3339     (void) _XmPrimitiveFocusOut(w, event, params, num_params);
3340 }
3341
3342 static void
3343 KeyTranslator
3344 (
3345     Display              *display,
3346     KeyCode               keyCode,
3347     Modifiers             modifiers,
3348     Modifiers            *modifiersReturn,
3349     KeySym               *keysymReturn
3350 )
3351 {
3352     /* call the Xt translator to translate this event... */
3353     (void) XtTranslateKey(display, keyCode, modifiers, modifiersReturn,
3354             keysymReturn);
3355     /* and reinstall the Motif translator for the next widget/event... */
3356     (void) XtSetKeyTranslator(display, (XtKeyProc) XmTranslateKey);
3357 }
3358     
3359 /*ARGSUSED*/
3360 static void
3361 handleKeyEvents(Widget w, XtPointer closure, XEvent *event, Boolean *cont)
3362 {
3363     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
3364
3365     /* drop synthetic events... */
3366     if (!tw->term.allowSendEvents && event->xany.send_event) {
3367         *cont = False;
3368         return;
3369     }
3370
3371 #ifdef  KEY_TRANSLATE_HACK
3372     /* install our key translator... */
3373     (void) XtSetKeyTranslator(XtDisplay(w), (XtKeyProc) KeyTranslator);
3374 #endif  /* KEY_TRANSLATE_HACK */
3375     /* and return... */
3376 }
3377
3378 /*ARGSUSED*/
3379 static void
3380 handleButtonEvents(Widget w, XtPointer closure, XEvent *event, Boolean *cont)
3381 {
3382     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
3383
3384     /* drop synthetic events... */
3385     if (!tw->term.allowSendEvents && event->xany.send_event) {
3386         *cont = False;
3387         return;
3388     }
3389 }
3390
3391 static void
3392 CapsLockUpdate(Widget w, Boolean capsLock)
3393 {
3394     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
3395     DtTermPrimData tpd = tw->term.tpd;
3396
3397     if (tpd->capsLock != capsLock) {
3398         tpd->capsLock = capsLock;
3399
3400         /* invoke the caps lock callback... */
3401         if (tw->term.statusChangeCallback) {
3402             _DtTermPrimInvokeStatusChangeCallback(w);
3403         }
3404     }
3405 }
3406
3407 void
3408 _DtTermPrimInsertCharUpdate(Widget w, DtTermInsertCharMode insertCharMode)
3409 {
3410     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
3411     DtTermPrimData tpd = tw->term.tpd;
3412
3413     if (tpd->insertCharMode != insertCharMode) {
3414         tpd->insertCharMode = insertCharMode;
3415
3416         /* invoke the caps lock callback... */
3417         if (tw->term.statusChangeCallback) {
3418             _DtTermPrimInvokeStatusChangeCallback(w);
3419         }
3420     }
3421 }
3422
3423 /*ARGSUSED*/
3424 void
3425 _DtTermPrimActionStop(Widget w, XEvent *event, String *params, Cardinal *num_params)
3426 {
3427     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
3428     DtTermPrimData tpd = tw->term.tpd;
3429
3430     if (*num_params > 0) {
3431         if (!strcmp(params[0], "on")) {
3432             tpd->outputStopped = False;
3433         } else if (!strcmp(params[0], "off")) {
3434             tpd->outputStopped = True;
3435         } else {
3436             /* toggle the output... */
3437             tpd->outputStopped = !tpd->outputStopped;
3438         }
3439     } else {
3440         /* toggle the output... */
3441         tpd->outputStopped = !tpd->outputStopped;
3442     }
3443
3444     (void) _DtTermPrimStartOrStopPtyInput(w);
3445
3446     /* invoke the status update callback... */
3447     if (tw->term.statusChangeCallback) {
3448         _DtTermPrimInvokeStatusChangeCallback(w);
3449     }
3450 }
3451
3452 void
3453 _DtTermPrimInvokeStatusChangeCallback
3454 (
3455     Widget                        w
3456 )
3457 {
3458     DtTermPrimitiveWidget         tw = (DtTermPrimitiveWidget) w;
3459     DtTermPrimData                tpd = tw->term.tpd;
3460     DtTermStatusChangeCallbackStruct
3461                                   cb;
3462
3463     /* exit now if we don't need to do anything... */
3464     if (!tw->term.statusChangeCallback)
3465         return;
3466
3467     (void) memset(&cb, '\0', sizeof(cb));
3468     cb.reason = DtCR_TERM_STATUS_CHANGE;
3469     cb.event = (XEvent *) 0;
3470     cb.cursorX = tpd->cursorColumn + 1;
3471     cb.cursorY = tpd->topRow + tpd->cursorRow + 1;
3472     cb.capsLock = tpd->capsLock;
3473     cb.stop = tpd->outputStopped;
3474     cb.insertCharMode = tpd->insertCharMode;
3475     cb.locked = tpd->keyboardLocked.escape;
3476
3477     /* invoke them... */
3478     (void) XtCallCallbackList(w, tw->term.statusChangeCallback,
3479             (XtPointer) &cb);
3480 }
3481
3482 void
3483 _DtTermPrimDrawShadow(Widget w)
3484 {
3485     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
3486
3487     if (XtIsRealized(w)) {
3488         XmeDrawShadows(XtDisplay(w), XtWindow(w),
3489                 tw->primitive.top_shadow_GC,
3490                 tw->primitive.bottom_shadow_GC,
3491                 tw->primitive.highlight_thickness,
3492                 tw->primitive.highlight_thickness,
3493                 tw->core.width - 2 * tw->primitive.highlight_thickness,
3494                 tw->core.height - 2 * tw->primitive.highlight_thickness,
3495                 tw->primitive.shadow_thickness,
3496                 tw->term.shadowType);
3497     }
3498 }
3499
3500 Widget
3501 DtCreateTermPrimitive(Widget parent, char *name, ArgList arglist,
3502         Cardinal argcount)
3503 {
3504     Widget w;
3505     _DtTermWidgetToAppContext(parent);
3506
3507     _DtTermAppLock(app);
3508     Debug('T', timeStamp("DtCreateTermPrimitive() starting"));
3509     w = XtCreateWidget(name, dtTermPrimitiveWidgetClass, parent, arglist,
3510             argcount);
3511     Debug('T', timeStamp("DtCreateTermPrimitive() finished"));
3512     _DtTermAppUnlock(app);
3513     return(w);
3514 }
3515
3516 void
3517 _DtTermPrimStartOrStopPtyInput(Widget w)
3518 {
3519     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
3520     DtTermPrimData tpd = tw->term.tpd;
3521     Boolean inputOn = True;
3522
3523     /* This function will either turn on or turn off the pty input selector
3524      * depending on the status of:
3525      *
3526      *      - the outputStopped flag,
3527      *      - any pending scrolling operations.
3528      */
3529
3530     Debug('o', fprintf(stderr, ">>_StartOrStopPtyInput() starting\n"));
3531     /* turn off input if there is a non-jump scroll pending... */
3532     if (!tw->term.jumpScroll && tpd->scroll.nojump.pendingScroll)
3533         inputOn = False;
3534
3535     /* turn off input if we are stopped or paused... */
3536     if (tpd->outputStopped || tpd->oneSecondPause)
3537         inputOn = False;
3538
3539     if (inputOn && !tpd->ptyInputId && (tw->term.pty >= 0)) {
3540         /* turn it on... */
3541         tpd->ptyInputId = 
3542                 XtAppAddInput(XtWidgetToApplicationContext((Widget) tw),
3543                 tw->term.pty, (XtPointer) XtInputReadMask, readPty,
3544                 (Widget) tw);
3545         Debug('o', fprintf(stderr, "    adding pty read select\n"));
3546     } else if (!inputOn && tpd->ptyInputId) {
3547         /* turn it off... */
3548         (void) XtRemoveInput(tw->term.tpd->ptyInputId);
3549         tw->term.tpd->ptyInputId = (XtInputId) 0;
3550         Debug('o', fprintf(stderr, "    removing pty read select\n"));
3551     }
3552     Debug('o', fprintf(stderr, ">>_StartOrStopPtyInput() finished\n"));
3553 }
3554
3555 void
3556 _DtTermPrimStartOrStopPtyOutput(Widget w)
3557 {
3558     DtTermPrimitiveWidget          tw      = (DtTermPrimitiveWidget) w;
3559     DtTermPrimData              tpd      = tw->term.tpd;
3560
3561     Debug('o', fprintf(stderr, ">>_StartOrStopPtyOutput() starting\n"));
3562     /*
3563     ** This function will either turn on or turn off the 
3564     ** pty write selector depending whether any text is waiting
3565     ** to be written.
3566     */
3567     if (TextIsPending(tpd->pendingWrite))
3568     {   
3569         if (tpd->ptyOutputId == 0)
3570         {
3571             /*
3572             ** turn it on...
3573             */
3574             tpd->ptyOutputId = XtAppAddInput(XtWidgetToApplicationContext(w),
3575                                             tw->term.pty, 
3576                                             (XtPointer) XtInputWriteMask,
3577                                             writePty, w);
3578
3579             Debug('o', fprintf(stderr, "    adding pty write select\n"));
3580         }
3581     } 
3582     else if (tpd->ptyOutputId != 0)
3583     {
3584         /*
3585         ** turn it off...
3586         */
3587         (void) XtRemoveInput(tw->term.tpd->ptyOutputId);
3588         tw->term.tpd->ptyOutputId = (XtInputId) 0;
3589         Debug('o', fprintf(stderr, "    removing pty write select\n"));
3590     }
3591     Debug('o', fprintf(stderr, ">>_StartOrStopPtyOutput() finished\n"));
3592 }
3593
3594 /*ARGSUSED*/
3595 static void VerticalScrollBarCallback(Widget wid, XtPointer client_data,
3596         XtPointer call_data)
3597 {
3598     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) client_data;
3599     XmScrollBarCallbackStruct *cb = (XmScrollBarCallbackStruct *) call_data;
3600
3601     _DtTermPrimCursorOff((Widget) tw);
3602
3603     (void) _DtTermPrimScrollTextTo((Widget) tw, cb->value -
3604             (tw->term.tpd->useHistoryBuffer ?
3605             tw->term.tpd->lastUsedHistoryRow : 0));
3606     /* we need to complete the scroll or it won't happen... */
3607     (void) _DtTermPrimScrollComplete((Widget) tw, True);
3608     if (cb->reason != XmCR_DRAG) {
3609         _DtTermPrimCursorOn((Widget) tw);
3610     }
3611 }
3612
3613 /*ARGSUSED*/
3614 static void WarningDialogOkCallback(Widget wid, XtPointer client_data,
3615         XtPointer call_data)
3616 {
3617     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) client_data;
3618     DtTermPrimData tpd = tw->term.tpd;
3619
3620     tpd->warningDialogMapped = False;
3621 }
3622
3623 /*ARGSUSED*/
3624 static void WarningDialogWMDestroyCallback(Widget wid, XtPointer client_data,
3625         XtPointer call_data)
3626 {
3627     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) client_data;
3628     DtTermPrimData tpd = tw->term.tpd;
3629
3630     /* unmap the window (this is necessary for wm destroy callbacks)... */
3631     (void) XtUnmanageChild(tpd->warningDialog);
3632     /* call the OK callback... */
3633     (void) WarningDialogOkCallback(tpd->warningDialog, client_data,
3634             call_data);
3635 }
3636
3637 void _DtTermPrimWarningDialog(Widget w, char *msg)
3638 {
3639     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
3640     Widget parent;
3641     DtTermPrimData tpd = tw->term.tpd;
3642     XmString msgString;
3643     XmString titleString;
3644     Arg arglist[10];
3645     int i;
3646
3647     if (!tpd->warningDialog) {
3648         i = 0;
3649
3650         (void) XtSetArg(arglist[i], XmNdialogStyle,
3651                 XmDIALOG_PRIMARY_APPLICATION_MODAL); i++;
3652         titleString =
3653           XmStringGenerate(
3654                 GETMESSAGE(NL_SETN_Prim,2,"Terminal - Warning"),
3655                 XmFONTLIST_DEFAULT_TAG, XmCHARSET_TEXT, NULL);
3656         (void) XtSetArg(arglist[i], XmNdialogTitle, titleString); i++;
3657         tpd->warningDialog = XmCreateWarningDialog(w, "termWarning", arglist, i);
3658         (void) XmStringFree(titleString);
3659
3660         (void) XtAddCallback(tpd->warningDialog,
3661                 XmNokCallback, WarningDialogOkCallback, (XtPointer) w);
3662         /* find the shell widget so we can add a wmDestroy callback... */
3663         /*EMPTY*/
3664         for (parent = tpd->warningDialog; !XtIsShell(parent);
3665                 parent = XtParent(parent))
3666             ;
3667         (void) _DtTermPrimAddDeleteWindowCallback(parent,
3668                 WarningDialogWMDestroyCallback, (XtPointer) w);
3669     }
3670
3671     i = 0;
3672     msgString =
3673       XmStringGenerate(msg, XmFONTLIST_DEFAULT_TAG, XmCHARSET_TEXT, NULL);
3674     (void) XtSetArg(arglist[i], XmNmessageString, msgString); i++;
3675     (void) XtSetValues(tpd->warningDialog, arglist, i);
3676     (void) XmStringFree(msgString);
3677
3678     if (!XtIsRealized(tpd->warningDialog)) {
3679         (void) XtRealizeWidget(tpd->warningDialog);
3680         (void) XtUnmanageChild(XmMessageBoxGetChild(tpd->warningDialog,
3681                 XmDIALOG_CANCEL_BUTTON));
3682         (void) XtUnmanageChild(XmMessageBoxGetChild(tpd->warningDialog,
3683                 XmDIALOG_HELP_BUTTON));
3684     }
3685
3686     /* limit wm functions to move, decorations to menu, border and title...
3687      */
3688     i = 0;
3689     (void) XtSetArg(arglist[i], XmNmwmFunctions, MWM_FUNC_MOVE); i++;
3690     (void) XtSetArg(arglist[i], XmNmwmDecorations,
3691             MWM_DECOR_MENU | MWM_DECOR_BORDER | MWM_DECOR_TITLE); i++;
3692     (void) XtSetValues(XtParent(tpd->warningDialog), arglist, i);
3693
3694     if (tpd->windowMapped) {
3695         (void) XtManageChild(tpd->warningDialog);
3696         tpd->warningDialogMapped = True;
3697         tpd->mapWarningDialog = False;
3698     } else {
3699         tpd->mapWarningDialog = True;
3700     }
3701 }
3702
3703 typedef void _ManagerConstraintInitializeProc(Widget request, Widget new_w,
3704         ArgList args, Cardinal *num_args);
3705 static _ManagerConstraintInitializeProc *managerConstraintInitializeProc;
3706
3707 static void
3708 ManagerConstraintInitializePatch(Widget request, Widget new_w, ArgList args,
3709         Cardinal *num_args)
3710 {
3711     if (!XtIsSubclass(new_w, dtTermPrimitiveWidgetClass)) {
3712         (*managerConstraintInitializeProc)(request, new_w, args, num_args);
3713     }
3714 }
3715
3716 void
3717 DtTermInitialize()
3718 {
3719     XmManagerClassRec *mw = (XmManagerClassRec *) xmManagerWidgetClass;
3720     CoreClassRec *core = (CoreClassRec *) coreWidgetClass;
3721     static Boolean initted = False;
3722
3723     /* only do this once... */
3724     _DtTermProcessLock();
3725     if (initted) {
3726         _DtTermProcessUnlock();
3727         return;
3728     }
3729
3730     if (core->core_class.class_inited) {
3731         (void) XtWarning("DtTermInitialize was not called before toolkit initialization\n");
3732     }
3733     managerConstraintInitializeProc = mw->constraint_class.initialize;
3734     mw->constraint_class.initialize = ManagerConstraintInitializePatch;
3735     initted = True;
3736     _DtTermProcessUnlock();
3737 }
3738
3739 void
3740 _DtTermPrimPutEnv(char *c1, char *c2)
3741 {
3742     char buffer[BUFSIZ];
3743     char *c;
3744
3745     (void) strcpy(buffer, c1);
3746     (void) strcat(buffer, c2);
3747     c = XtMalloc(strlen(buffer) + 1);
3748     (void) strcpy(c, buffer);
3749     (void) putenv(c);
3750 }
3751
3752
3753 #if     !defined(NL_CAT_LOCALE)
3754 #define NL_CAT_LOCALE 0
3755 #endif  /* NL_CAT_LOCAL */
3756
3757 char *
3758 _DtTermPrimGetMessage(
3759         char *filename,
3760         int set,
3761         int n,
3762         char *s )
3763 {
3764         char *msg;
3765         char *lang;
3766         static int first = 1;
3767         static nl_catd nlmsg_fd;
3768
3769         _DtTermProcessLock();
3770         if ( first )
3771         {
3772                 first = 0;
3773
3774                 lang = (char *) getenv ("LANG");
3775
3776                 if (!lang || !(strcmp (lang, "C")))
3777                         /*
3778                          * If LANG is not set or if LANG=C, then there
3779                          * is no need to open the message catalog - just
3780                          * return the built-in string "s".
3781                          */
3782                         nlmsg_fd = (nl_catd) -1;
3783                 else
3784                         nlmsg_fd = catopen(filename, NL_CAT_LOCALE);
3785         }
3786         _DtTermProcessUnlock();
3787         msg=catgets(nlmsg_fd,set,n,s);
3788         return (msg);
3789 }
3790
3791
3792
3793 static int
3794 PreeditStart(
3795     XIC xic,
3796     XPointer client_data,
3797     XPointer call_data)
3798 {
3799     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) client_data;
3800
3801     PreLen(tw) = 0L;
3802     PreRow(tw) = tw->term.tpd->cursorRow;
3803     PreColumn(tw) = tw->term.tpd->cursorColumn;
3804
3805     /* vertical writing dependency here */
3806     PreStart(tw) = tw->term.tpd->cursorColumn;
3807     PreEnd(tw) = tw->term.tpd->cursorColumn;
3808
3809     PreUnder(tw) = True;
3810     return(-1);
3811 }
3812
3813
3814 static void
3815 PreeditDone(
3816     XIC xic,
3817     XPointer client_data,
3818     XPointer call_data)
3819 {
3820     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) client_data;
3821
3822     _DtTermPrimRefreshText((Widget)tw, PreColumn(tw), PreRow(tw),
3823                            tw->term.columns,
3824                            PreRow(tw));
3825     PreUnder(tw) = False;
3826     PreLen(tw) = 0L;
3827 }
3828
3829
3830 static void
3831 PreeditDelete(
3832     DtTermPrimitiveWidget tw,
3833     XIMPreeditDrawCallbackStruct *call_data)
3834 {
3835     short retcount, row, col, width;
3836     termChar *retchar;
3837
3838     /*
3839     ** chg_first to chg_length in the preedit call_data 
3840     ** structure indicates what should be deleted out of 
3841     ** the preedit buffer, but this is terms of characters 
3842     ** not bytes. We have stored the byte value in the 
3843     ** term data structure, so we use that instead.
3844     */
3845     if (call_data->chg_length && PreLen(tw)) {
3846         row = PreRow(tw);
3847         col = PreColumn(tw) + call_data->chg_first;
3848         width = call_data->chg_length;
3849         _DtTermPrimBufferDelete(tw->term.tpd->termBuffer, &row, &col,
3850                                 &width, &retchar, &retcount);
3851
3852         /*
3853          ** We may want to consider freeing retcount @ retchar
3854          */
3855         
3856         /*
3857          ** Refresh the text buffer -
3858          ** We must refresh to the rest of the line, because the
3859          ** preedit buffer may be in the middle of a line.
3860          */
3861         _DtTermPrimRefreshText((Widget)tw, PreColumn(tw), PreRow(tw),
3862                                tw->term.columns,
3863                                PreRow(tw));
3864     }
3865 }
3866
3867
3868 static void
3869 PreeditHighlight(
3870     DtTermPrimitiveWidget tw,
3871     XIMPreeditDrawCallbackStruct *call_data)
3872 {
3873     TermSelectInfo  selectInfo = tw->term.tpd->selectInfo;
3874
3875     /* check for null feedback */
3876     if (call_data->text->feedback) {
3877         switch (*call_data->text->feedback) {
3878           case XIMReverse:
3879           case XIMUnderline:
3880           case XIMHighlight:
3881           case XIMPrimary:
3882           case XIMSecondary:
3883           case XIMTertiary:
3884             /* clear any existing highlight first */
3885             selectInfo->ownPrimary = False;
3886             _DtTermPrimRenderRefreshTextLinear((Widget)tw, 
3887                                                selectInfo->begin,
3888                                                selectInfo->end - 1);
3889             selectInfo->ownPrimary =True;
3890             selectInfo->begin = rowColToPos(tw, PreRow(tw), PreColumn(tw));
3891             selectInfo->end = selectInfo->begin + PreLen(tw);
3892             _DtTermPrimRenderRefreshTextLinear((Widget)tw, 
3893                                                selectInfo->begin,
3894                                                selectInfo->end - 1);
3895             break;
3896           default:
3897             /* no highlight set, clear */
3898             selectInfo->ownPrimary = False;
3899             _DtTermPrimRenderRefreshTextLinear((Widget)tw, 
3900                                                selectInfo->begin,
3901                                                selectInfo->end - 1);
3902         }
3903     }
3904 }
3905
3906
3907 static void
3908 PreeditDraw(
3909     XIC xic,
3910     XPointer client_data,
3911     XIMPreeditDrawCallbackStruct *call_data)
3912 {
3913     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) client_data;
3914     DtTermInsertCharMode savmode;
3915     unsigned char *mb;
3916     wchar_t *wcs;
3917     size_t len;
3918
3919     /* are we under preedit? */
3920     if (!PreUnder(tw))
3921         return;
3922
3923     /*
3924     ** This indicates a preedit buffer deletion
3925     */
3926     if (!call_data->text) {
3927         PreeditHighlight(tw, call_data);
3928         PreeditDelete(tw, call_data);
3929
3930         /* reset row/column position to beginning */
3931         tw->term.tpd->cursorRow = PreRow(tw);
3932         tw->term.tpd->cursorColumn = PreColumn(tw);
3933         _DtTermPrimCursorUpdate((Widget)tw);
3934         _DtTermPrimCursorOn((Widget)tw);
3935         return;
3936     }
3937
3938     /*
3939     ** At this point, we know there is a string in the
3940     ** preedit buffer that we must render.
3941     */
3942
3943     /* get preedit string */
3944     if (call_data->text->encoding_is_wchar) {
3945
3946         /* preedit buffer is wchar, we must convert */
3947         wcs = call_data->text->string.wide_char;
3948         len = wcslen(wcs) * sizeof(wchar_t);
3949         mb = (unsigned char *)XtMalloc(len);
3950         
3951         /* check for invalid string */
3952         if (wcstombs((char *)mb, wcs, len) == -1)
3953             return;
3954     } else
3955         mb = (unsigned char *)call_data->text->string.multi_byte;
3956
3957
3958     /*
3959     ** First we must destroy the previous contents of
3960     ** the preedit buffer, if any, before we redraw 
3961     ** the new one.
3962     */
3963     PreeditDelete(tw, call_data);
3964
3965     /* set insertion point */
3966     tw->term.tpd->cursorRow = PreRow(tw);
3967     tw->term.tpd->cursorColumn = PreColumn(tw);
3968
3969     /* render buffer */
3970     savmode = tw->term.tpd->insertCharMode;
3971     tw->term.tpd->insertCharMode = DtTERM_INSERT_CHAR_ON;
3972     len = strlen((char *)mb);
3973     _DtTermPrimInsertText((Widget)tw, mb, len);
3974     PreLen(tw) = len;
3975     tw->term.tpd->insertCharMode = savmode;
3976
3977     /* check highlight */
3978     PreeditHighlight(tw, call_data);
3979
3980     /* update cursor */
3981     _DtTermPrimCursorUpdate((Widget)tw);
3982     _DtTermPrimCursorOn((Widget)tw);
3983 }
3984
3985
3986 static void
3987 PreeditCaret(
3988     XIC xic,
3989     XPointer client_data,
3990     XIMPreeditCaretCallbackStruct *call_data)
3991 {
3992     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) client_data;
3993     TermSelectInfo  selectInfo = tw->term.tpd->selectInfo;
3994     Boolean chgcursor = False;
3995     short newpos = 0;
3996
3997     switch (call_data->style) {
3998       case XIMIsInvisible:
3999         _DtTermPrimCursorOff((Widget)tw);
4000         break;
4001       case XIMIsPrimary:
4002       case XIMIsSecondary:
4003         _DtTermPrimCursorOn((Widget)tw);
4004         break;
4005       default:
4006         break;
4007     }
4008
4009     switch (call_data->direction) {
4010       case XIMForwardChar:
4011         newpos = tw->term.tpd->cursorColumn + 1;
4012         chgcursor = True;
4013         break;
4014       case XIMBackwardChar:
4015         newpos = tw->term.tpd->cursorColumn - 1;
4016         chgcursor = True;
4017         break;
4018       case XIMLineStart:
4019         newpos = PreStart(tw);
4020         chgcursor = True;
4021         break;
4022       case XIMLineEnd:
4023         newpos = PreEnd(tw);
4024         chgcursor = True;
4025         break;
4026       case XIMAbsolutePosition:
4027         newpos = PreColumn(tw) + call_data->position;
4028         chgcursor = True;
4029         break;
4030
4031       /* do nothing we these movements */
4032       case XIMForwardWord:
4033       case XIMBackwardWord:
4034       case XIMCaretUp:
4035       case XIMCaretDown:
4036       case XIMNextLine:
4037       case XIMPreviousLine:
4038       case XIMDontChange:
4039         break;
4040       default:
4041         break;  /* NOTREACHED */
4042     }
4043
4044     /*
4045      ** The input method shouldn't let us edit outside
4046      ** of the preedit buffer anyway, but we check just
4047      ** to be sure.
4048      */
4049     if (chgcursor && (newpos >= PreStart(tw)) && (newpos <= PreEnd(tw))) {
4050         tw->term.tpd->cursorColumn = newpos;
4051         _DtTermPrimCursorUpdate((Widget)tw);
4052         _DtTermPrimCursorOn((Widget)tw);
4053         /*
4054         ** refresh highlight (if any) because cursor 
4055         ** movement hoses it up
4056         */
4057         _DtTermPrimRenderRefreshTextLinear((Widget)tw, 
4058                                            selectInfo->begin,
4059                                            selectInfo->end - 1);
4060     }
4061 }
4062
4063 static void 
4064 setThickness(
4065         Widget widget,
4066         int offset,
4067         XrmValue *value )
4068 {
4069       XmDisplay        xmDisplay;
4070       static Dimension thickness;
4071
4072       xmDisplay = (XmDisplay)XmGetXmDisplay(XtDisplay(widget));
4073
4074       if (xmDisplay->display.enable_thin_thickness) {
4075               thickness = 1;
4076       }
4077       else {
4078               thickness = 2;
4079       }
4080
4081       value->addr = (XPointer)&thickness;
4082 }