4100 lines
117 KiB
C
4100 lines
117 KiB
C
/*
|
|
* CDE - Common Desktop Environment
|
|
*
|
|
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
|
|
*
|
|
* These libraries and programs are free software; you can
|
|
* redistribute them and/or modify them under the terms of the GNU
|
|
* Lesser General Public License as published by the Free Software
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* These libraries and programs are distributed in the hope that
|
|
* they will be useful, but WITHOUT ANY WARRANTY; without even the
|
|
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU Lesser General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with these libraries and programs; if not, write
|
|
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
|
* Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
/* *
|
|
* (c) Copyright 1993, 1994, 1996 Hewlett-Packard Company *
|
|
* (c) Copyright 1993, 1994, 1996 International Business Machines Corp. *
|
|
* (c) Copyright 1993, 1994, 1996 Sun Microsystems, Inc. *
|
|
* (c) Copyright 1993, 1994, 1996 Novell, Inc. *
|
|
* (c) Copyright 1995, 1996 Digital Equipment Corporation. *
|
|
* (c) Copyright 1996 FUJITSU LIMITED. *
|
|
* (c) Copyright 1996 Hitachi. *
|
|
*/
|
|
|
|
extern char _DtTermPrimPullInTermWhatString[];
|
|
static char *termWhatString = _DtTermPrimPullInTermWhatString;
|
|
extern char * _DtTermPrimGetMessage( char *filename, int set, int n, char *s );
|
|
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <X11/X.h>
|
|
#include <X11/keysym.h>
|
|
#include <Xm/MessageB.h>
|
|
#include <Xm/XmP.h>
|
|
#include <Xm/DisplayP.h>
|
|
#include <Xm/XmPrivate.h>
|
|
#include <Xm/VirtKeys.h>
|
|
#include <Xm/MwmUtil.h>
|
|
#include <Xm/DrawP.h>
|
|
#include "TermHeader.h"
|
|
#include "TermPrimOSDepI.h" /* for SETENV_LINES_AND_COLS */
|
|
#include "TermPrimI.h"
|
|
#include "TermPrimP.h"
|
|
#include "TermPrimBufferP.h"
|
|
#include "TermPrimAction.h"
|
|
#include "TermPrimGetPty.h"
|
|
#include "TermPrimParser.h"
|
|
#include "TermPrimParseTable.h"
|
|
#include "TermPrimPendingText.h"
|
|
#include "TermPrimPendingTextP.h"
|
|
#include "TermPrimRenderFont.h"
|
|
#include "TermPrimRenderFontSet.h"
|
|
#include "TermPrimSelectP.h"
|
|
#include "TermPrimSetUtmp.h"
|
|
#include "TermPrimUtil.h"
|
|
#include "TermPrimDebug.h"
|
|
#include "TermPrimWMProtocols.h"
|
|
#include "TermPrimSetPty.h"
|
|
#include <Xm/RepType.h>
|
|
#include "TermPrimRepType.h"
|
|
#include "TermPrimMessageCatI.h"
|
|
#include <X11/CoreP.h>
|
|
#include <Xm/ManagerP.h>
|
|
#include <signal.h>
|
|
#include <ctype.h>
|
|
#include <Dt/MsgCatP.h>
|
|
#include <wchar.h>
|
|
#if defined(__linux__)
|
|
# include <sys/types.h> /* For FD_* macros. */
|
|
# include <sys/time.h> /* For select() prototype. */
|
|
#else
|
|
# include <sys/select.h>
|
|
#endif
|
|
|
|
#ifdef HAS_UTEMPTER_LIBRARY
|
|
#include <utempter.h>
|
|
#endif
|
|
|
|
extern void TermReadKey(Widget w, XEvent *event, String *params,
|
|
Cardinal *num_params);
|
|
static void ClassInitialize(void);
|
|
static void ClassPartInitialize(WidgetClass wc);
|
|
static void initializeKeyboard(DtTermPrimData tpd);
|
|
static void initializeModes(DtTermPrimData tpd);
|
|
static void initializeStraps(DtTermPrimData tpd);
|
|
static void Initialize(Widget rw, Widget nw, Arg *args, Cardinal *num_args);
|
|
static void Resize(Widget w);
|
|
static void Redisplay(Widget w, XEvent *event, Region region);
|
|
static Boolean SetValues(Widget cw, Widget rw, Widget nw, ArgList args,
|
|
Cardinal *num_args);
|
|
static void Realize(Widget w, XtValueMask *p_valueMask,
|
|
XSetWindowAttributes *attributes);
|
|
static void Destroy(Widget w);
|
|
static void readPty(XtPointer client_data, int *source,
|
|
XtInputId *id);
|
|
static void handleKeyEvents(Widget w, XtPointer closure, XEvent *event,
|
|
Boolean *cont);
|
|
static void handleButtonEvents(Widget w, XtPointer closure, XEvent *event,
|
|
Boolean *cont);
|
|
static void handleNonMaskableEvents(Widget w, XtPointer eventData,
|
|
XEvent *event, Boolean *cont);
|
|
static void handlePropertyChangeEvents(Widget w, XtPointer eventData,
|
|
XEvent *event, Boolean *cont);
|
|
static void handleProcessStructureNotifyEvent(Widget w, XtPointer eventData,
|
|
XEvent *event, Boolean *cont);
|
|
static Boolean moreInput(int pty);
|
|
static void CapsLockUpdate(Widget w, Boolean capsLock);
|
|
static void InitializeVerticalScrollBar(Widget w, Boolean initCallbacks);
|
|
static void VerticalScrollBarCallback(Widget w, XtPointer client_data,
|
|
XtPointer call_data);
|
|
static void setThickness(Widget widget, int offset, XrmValue *value);
|
|
|
|
/*
|
|
* on the spot callbacks
|
|
*/
|
|
static int PreeditStart(
|
|
XIC xic,
|
|
XPointer client_data,
|
|
XPointer call_data);
|
|
|
|
static void PreeditDone(
|
|
XIC xic,
|
|
XPointer client_data,
|
|
XPointer call_data);
|
|
|
|
static void PreeditDraw(
|
|
XIC xic,
|
|
XPointer client_data,
|
|
XIMPreeditDrawCallbackStruct *call_data);
|
|
|
|
static void PreeditCaret(
|
|
XIC xic,
|
|
XPointer client_data,
|
|
XIMPreeditCaretCallbackStruct *call_data);
|
|
|
|
|
|
/* action list for class: Term... */
|
|
|
|
static XtActionsRec actionsList[] = {
|
|
{"self-insert", _DtTermPrimActionKeyInput},
|
|
{"insert", _DtTermPrimActionKeyInput},
|
|
{"key-release", _DtTermPrimActionKeyRelease},
|
|
{"grab-focus", _DtTermPrimSelectGrabFocus},
|
|
{"select-adjust", _DtTermPrimSelectExtend},
|
|
{"extend-end", _DtTermPrimSelectExtendEnd},
|
|
{"extend-start", _DtTermPrimSelectExtendStart},
|
|
{"copy-to", _DtTermPrimSelectInsert},
|
|
{"copy-clipboard", _DtTermPrimSelectCopyClipboardEventIF},
|
|
{"paste-clipboard", _DtTermPrimSelectPasteClipboardEventIF},
|
|
{"process-bdrag", _DtTermPrimSelectProcessBDrag},
|
|
{"leave", _DtTermPrimActionLeave},
|
|
{"enter", _DtTermPrimActionEnter},
|
|
{"focus-in", _DtTermPrimActionFocusIn},
|
|
{"focus-out", _DtTermPrimActionFocusOut},
|
|
{"keymap", _DtTermPrimActionKeymap},
|
|
{"redraw-display", _DtTermPrimActionRedrawDisplay},
|
|
{"return", _DtTermPrimActionReturn},
|
|
{"stop", _DtTermPrimActionStop},
|
|
{"string", _DtTermPrimActionString},
|
|
{"tab", _DtTermPrimActionTab},
|
|
{"select-page", _DtTermPrimSelectPage},
|
|
{"select-all", _DtTermPrimSelectAll},
|
|
{"process-cancel", _DtTermPrimSelectProcessCancel}
|
|
};
|
|
|
|
#define defaultColumns 80
|
|
#define defaultRows 24
|
|
|
|
/* the resource list for Term... */
|
|
static XtResource resources[] =
|
|
{
|
|
{
|
|
DtNcharCursorStyle, DtCCharCursorStyle, DtRDtTermCharCursorStyle,
|
|
sizeof(unsigned char),
|
|
XtOffsetOf(struct _DtTermPrimitiveRec, term.charCursorStyle),
|
|
XmRImmediate, (XtPointer) DtTERM_CHAR_CURSOR_BOX
|
|
},
|
|
{
|
|
DtNconsoleMode, DtCConsoleMode, XmRBoolean, sizeof(Boolean),
|
|
XtOffsetOf(struct _DtTermPrimitiveRec, term.consoleMode),
|
|
XmRImmediate, (XtPointer) False
|
|
},
|
|
{
|
|
DtNblinkRate, DtCBlinkRate, XmRInt, sizeof(int),
|
|
XtOffsetOf(struct _DtTermPrimitiveRec, term.blinkRate),
|
|
XmRImmediate, (XtPointer) 250
|
|
},
|
|
{
|
|
DtNbaseWidth, DtCBaseWidth, XmRInt, sizeof(int),
|
|
XtOffsetOf(struct _DtTermPrimitiveRec, term.baseWidth),
|
|
XmRImmediate, (XtPointer) 0
|
|
},
|
|
{
|
|
DtNbaseHeight, DtCBaseHeight, XmRInt, sizeof(int),
|
|
XtOffsetOf(struct _DtTermPrimitiveRec, term.baseHeight),
|
|
XmRImmediate, (XtPointer) 0
|
|
},
|
|
{
|
|
DtNwidthInc, DtCWidthInc, XmRInt, sizeof(int),
|
|
XtOffsetOf(struct _DtTermPrimitiveRec, term.widthInc),
|
|
XmRImmediate, (XtPointer) 0
|
|
},
|
|
{
|
|
DtNheightInc, DtCHeightInc, XmRInt, sizeof(int),
|
|
XtOffsetOf(struct _DtTermPrimitiveRec, term.heightInc),
|
|
XmRImmediate, (XtPointer) 0
|
|
},
|
|
{
|
|
DtNtermDevice, DtCTermDevice, XmRInt, sizeof(int),
|
|
XtOffsetOf(struct _DtTermPrimitiveRec, term.pty),
|
|
XmRImmediate, (XtPointer) -1
|
|
},
|
|
{
|
|
DtNtermDeviceAllocate, DtCTermDeviceAllocate, XmRBoolean,
|
|
sizeof(Boolean),
|
|
XtOffsetOf(struct _DtTermPrimitiveRec, term.ptyAllocate),
|
|
XmRImmediate, (XtPointer) True
|
|
},
|
|
{
|
|
DtNtermSlaveName, DtCTermSlaveName, XmRString, sizeof(char *),
|
|
XtOffsetOf(struct _DtTermPrimitiveRec, term.ptySlaveName),
|
|
XmRImmediate, (XtPointer) NULL
|
|
},
|
|
{
|
|
DtNsaveLines, DtCSaveLines, XmRString, sizeof(char *),
|
|
XtOffsetOf(struct _DtTermPrimitiveRec, term.saveLines),
|
|
XmRImmediate, (XtPointer) "4s"
|
|
},
|
|
{
|
|
DtNrows, DtCRows, XmRShort, sizeof(short),
|
|
XtOffsetOf(struct _DtTermPrimitiveRec, term.rows),
|
|
XmRImmediate, (XtPointer) defaultRows
|
|
},
|
|
{
|
|
DtNcolumns, DtCColumns, XmRShort, sizeof(short),
|
|
XtOffsetOf(struct _DtTermPrimitiveRec, term.columns),
|
|
XmRImmediate, (XtPointer) defaultColumns
|
|
},
|
|
{
|
|
DtNbackgroundIsSelect, DtCBackgroundIsSelect, XmRBoolean,
|
|
sizeof(Boolean),
|
|
XtOffsetOf(struct _DtTermPrimitiveRec, term.backgroundIsSelect),
|
|
XtRImmediate, (XtPointer) False
|
|
},
|
|
{
|
|
XmNtraversalOn, XmCTraversalOn, XmRBoolean, sizeof(Boolean),
|
|
XtOffsetOf(struct _DtTermPrimitiveRec, primitive.traversal_on),
|
|
XtRImmediate, (XtPointer) True
|
|
},
|
|
{
|
|
DtNshadowType, DtCShadowType, XmRShadowType, sizeof (unsigned char),
|
|
XtOffsetOf( struct _DtTermPrimitiveRec, term.shadowType),
|
|
XmRImmediate, (XtPointer) DtSHADOW_IN
|
|
},
|
|
{
|
|
XmNshadowThickness, XmCShadowThickness, XmRHorizontalDimension,
|
|
sizeof (Dimension),
|
|
XtOffsetOf( struct _DtTermPrimitiveRec, primitive.shadow_thickness),
|
|
XmRCallProc, (XtPointer) setThickness
|
|
},
|
|
{
|
|
DtNmarginWidth, DtCMarginWidth, XmRHorizontalDimension,
|
|
sizeof (Dimension),
|
|
XtOffsetOf( struct _DtTermPrimitiveRec, term.marginWidth),
|
|
XmRImmediate, (XtPointer) 2
|
|
},
|
|
{
|
|
DtNmarginHeight, DtCMarginHeight, XmRVerticalDimension,
|
|
sizeof (Dimension),
|
|
XtOffsetOf( struct _DtTermPrimitiveRec, term.marginHeight),
|
|
XmRImmediate, (XtPointer) 2
|
|
},
|
|
{
|
|
DtNuserBoldFont, DtCUserBoldFont, XmRFontList,
|
|
sizeof(XmFontList),
|
|
XtOffsetOf( struct _DtTermPrimitiveRec, term.boldFontList),
|
|
XmRImmediate, (XtPointer) NULL
|
|
},
|
|
{
|
|
DtNuserFont, DtCUserFont, XmRFontList,
|
|
sizeof(XmFontList),
|
|
XtOffsetOf( struct _DtTermPrimitiveRec, term.fontList),
|
|
XmRImmediate, (XtPointer) NULL
|
|
},
|
|
{
|
|
XmNhighlightThickness, XmCHighlightThickness, XmRHorizontalDimension,
|
|
sizeof (Dimension),
|
|
XtOffsetOf( struct _DtTermPrimitiveRec, primitive.highlight_thickness),
|
|
XmRCallProc, (XtPointer) setThickness
|
|
},
|
|
{
|
|
DtNvisualBell, DtCVisualBell, XmRBoolean, sizeof(Boolean),
|
|
XtOffsetOf( struct _DtTermPrimitiveRec, term.visualBell),
|
|
XtRImmediate, (XtPointer) False
|
|
},
|
|
{
|
|
DtNmarginBell, DtCMarginBell, XmRBoolean, sizeof(Boolean),
|
|
XtOffsetOf( struct _DtTermPrimitiveRec, term.marginBell),
|
|
XtRImmediate, (XtPointer) False
|
|
},
|
|
{
|
|
DtNnMarginBell, DtCNMarginBell, XmRInt, sizeof(int),
|
|
XtOffsetOf( struct _DtTermPrimitiveRec, term.nMarginBell),
|
|
XtRImmediate, (XtPointer) 8
|
|
},
|
|
{
|
|
DtNjumpScroll, DtCJumpScroll, XmRBoolean, sizeof(Boolean),
|
|
XtOffsetOf( struct _DtTermPrimitiveRec, term.jumpScroll),
|
|
XtRImmediate, (XtPointer) True
|
|
},
|
|
{
|
|
DtNsubprocessLoginShell, DtCSubprocessLoginShell, XmRBoolean,
|
|
sizeof(Boolean),
|
|
XtOffsetOf( struct _DtTermPrimitiveRec, term.subprocessLoginShell),
|
|
XtRImmediate, (XtPointer) False
|
|
},
|
|
{
|
|
DtNsubprocessTerminationCallback, DtCCallback, XmRCallback,
|
|
sizeof(XtCallbackList),
|
|
XtOffsetOf( struct _DtTermPrimitiveRec, term.subprocessTerminationCallback),
|
|
XmRPointer, (XtPointer) NULL
|
|
},
|
|
{
|
|
DtNstatusChangeCallback, DtCCallback, XmRCallback,
|
|
sizeof(XtCallbackList),
|
|
XtOffsetOf( struct _DtTermPrimitiveRec, term.statusChangeCallback),
|
|
XmRPointer, (XtPointer) NULL
|
|
},
|
|
{
|
|
DtNoutputLogCallback, DtCCallback, XmRCallback,
|
|
sizeof(XtCallbackList),
|
|
XtOffsetOf( struct _DtTermPrimitiveRec, term.outputLogCallback),
|
|
XmRPointer, (XtPointer) NULL
|
|
},
|
|
{
|
|
DtNinputVerifyCallback, DtCCallback, XmRCallback,
|
|
sizeof(XtCallbackList),
|
|
XtOffsetOf( struct _DtTermPrimitiveRec, term.inputVerifyCallback),
|
|
XmRPointer, (XtPointer) NULL
|
|
},
|
|
{
|
|
DtNverticalScrollBar, DtCVerticalScrollBar, XmRWidget, sizeof(Widget),
|
|
XtOffsetOf( struct _DtTermPrimitiveRec, term.verticalScrollBar),
|
|
XmRImmediate, (XtPointer) NULL
|
|
},
|
|
{
|
|
DtNsubprocessPid, DtCSubprocessPid, XmRInt, sizeof(int),
|
|
XtOffsetOf( struct _DtTermPrimitiveRec, term.subprocessPid),
|
|
XtRImmediate, (XtPointer) -1
|
|
},
|
|
{
|
|
DtNsubprocessExec, DtCSubprocessExec, XmRBoolean, sizeof(Boolean),
|
|
XtOffsetOf( struct _DtTermPrimitiveRec, term.subprocessExec),
|
|
XmRImmediate, (XtPointer) True
|
|
},
|
|
{
|
|
DtNsubprocessTerminationCatch, DtCSubprocessTerminationCatch,
|
|
XmRBoolean, sizeof(Boolean),
|
|
XtOffsetOf( struct _DtTermPrimitiveRec, term.subprocessTerminationCatch),
|
|
XmRImmediate, (XtPointer) True
|
|
},
|
|
{
|
|
DtNsubprocessCmd, DtCSubprocessCmd, XmRString, sizeof(char *),
|
|
XtOffsetOf( struct _DtTermPrimitiveRec, term.subprocessCmd),
|
|
XtRImmediate, (XtPointer) NULL
|
|
},
|
|
{
|
|
DtNsubprocessArgv, DtCSubprocessArgv, XtRStringArray, sizeof(String *),
|
|
XtOffsetOf( struct _DtTermPrimitiveRec, term.subprocessArgv),
|
|
XmRImmediate, (XtPointer) NULL
|
|
},
|
|
{
|
|
DtNemulationId, DtCEmulationId, XmRString, sizeof(char *),
|
|
XtOffsetOf( struct _DtTermPrimitiveRec, term.emulationId),
|
|
XtRImmediate, (XtPointer) "DtTermPrimitiveWidget"
|
|
},
|
|
{
|
|
DtNtermId, DtCTermId, XmRString, sizeof(char *),
|
|
XtOffsetOf( struct _DtTermPrimitiveRec, term.termId),
|
|
XtRImmediate, (XtPointer) "dumb"
|
|
},
|
|
{
|
|
DtNtermName, DtCTermName, XmRString, sizeof(char *),
|
|
XtOffsetOf( struct _DtTermPrimitiveRec, term.termName),
|
|
XtRImmediate, (XtPointer) "dumb"
|
|
},
|
|
{
|
|
DtNttyModes, DtCTtyModes, XmRString, sizeof(char *),
|
|
XtOffsetOf( struct _DtTermPrimitiveRec, term.ttyModes),
|
|
XtRImmediate, (XtPointer) NULL
|
|
},
|
|
{
|
|
DtNcsWidth, DtCCsWidth, XmRString, sizeof(char *),
|
|
XtOffsetOf( struct _DtTermPrimitiveRec, term.csWidth),
|
|
XtRImmediate, (XtPointer) NULL
|
|
},
|
|
{
|
|
DtNkshMode, DtCKshMode, XmRBoolean, sizeof(Boolean),
|
|
XtOffsetOf( struct _DtTermPrimitiveRec, term.kshMode),
|
|
XtRImmediate, (XtPointer) False
|
|
},
|
|
{
|
|
DtNpointerBlank, DtCPointerBlank, XmRBoolean, sizeof(Boolean),
|
|
XtOffsetOf( struct _DtTermPrimitiveRec, term.pointerBlank),
|
|
XtRImmediate, (XtPointer) False
|
|
},
|
|
{
|
|
DtNpointerBlankDelay, DtCPointerBlankDelay, XmRInt, sizeof(int),
|
|
XtOffsetOf( struct _DtTermPrimitiveRec, term.pointerBlankDelay),
|
|
XtRImmediate, (XtPointer) 2
|
|
},
|
|
{
|
|
DtNpointerShape, DtCCursor, XtRCursor, sizeof(Cursor),
|
|
XtOffsetOf( struct _DtTermPrimitiveRec, term.pointerShape),
|
|
XtRString, (XtPointer) "xterm"
|
|
},
|
|
{
|
|
DtNpointerColor, DtCForeground, XtRPixel, sizeof(Pixel),
|
|
XtOffsetOf( struct _DtTermPrimitiveRec, term.pointerColor),
|
|
XtRString, (XtPointer) "XtDefaultForeground"
|
|
},
|
|
{
|
|
DtNpointerColorBackground, DtCBackground, XtRPixel, sizeof(Pixel),
|
|
XtOffsetOf( struct _DtTermPrimitiveRec, term.pointerColorBackground),
|
|
XtRString, (XtPointer) "XtDefaultBackground"
|
|
},
|
|
{
|
|
DtNmapOnOutput, DtCMapOnOutput , XmRBoolean, sizeof(Boolean),
|
|
XtOffsetOf( struct _DtTermPrimitiveRec, term.mapOnOutput ),
|
|
XtRImmediate, (XtPointer) False
|
|
},
|
|
{
|
|
DtNmapOnOutputDelay, DtCMapOnOutputDelay, XmRInt, sizeof(int),
|
|
XtOffsetOf( struct _DtTermPrimitiveRec, term.mapOnOutputDelay ),
|
|
XtRImmediate, (XtPointer) 0
|
|
},
|
|
{
|
|
DtNlogging, DtCLogging , XmRBoolean, sizeof(Boolean),
|
|
XtOffsetOf( struct _DtTermPrimitiveRec, term.logging ),
|
|
XtRImmediate, (XtPointer) False
|
|
},
|
|
{
|
|
DtNlogFile, DtCLogFile , XmRString, sizeof(char *),
|
|
XtOffsetOf( struct _DtTermPrimitiveRec, term.logFile ),
|
|
XtRImmediate, (XtPointer) NULL
|
|
},
|
|
{
|
|
DtNlogInhibit, DtCLogInhibit , XmRBoolean, sizeof(Boolean),
|
|
XtOffsetOf( struct _DtTermPrimitiveRec, term.logInhibit ),
|
|
XtRImmediate, (XtPointer) False
|
|
},
|
|
{
|
|
DtNreverseVideo, DtCReverseVideo, XmRBoolean, sizeof(Boolean),
|
|
XtOffsetOf( struct _DtTermPrimitiveRec, term.reverseVideo ),
|
|
XtRImmediate, (XtPointer) False
|
|
},
|
|
{
|
|
DtNallowSendEvents , DtCAllowSendEvents , XmRBoolean, sizeof(Boolean),
|
|
XtOffsetOf(struct _DtTermPrimitiveRec, term.allowSendEvents),
|
|
XtRImmediate, (XtPointer) False
|
|
}
|
|
};
|
|
|
|
/*
|
|
* Goofy debug'ed code by HP.
|
|
* IBM's JP kbd accepts Shift+KP_Multiply as a valid key sequence.
|
|
* I don't know why HP added non-exposed(internal) Xt's action ???
|
|
* Anyway, remove KP_Multiply entry from defaultTranslations[]
|
|
*/
|
|
static char defaultTranslations[] = "\
|
|
Ctrl<Key>Cancel: stop(long)\n\
|
|
~Ctrl<Key>Cancel: stop()\n\
|
|
<Key>Tab: tab()\n\
|
|
<Key>KP_Tab: tab()\n\
|
|
<KeyRelease>: key-release()\n\
|
|
<KeyPress>: insert()\n\
|
|
~Shift~Ctrl<Btn1Down>: grab-focus()\n\
|
|
Shift~Ctrl<Btn1Down>: extend-start()\n\
|
|
~Ctrl<Btn1Motion>: select-adjust()\n\
|
|
~Ctrl<Btn1Up>: extend-end()\n\
|
|
~Shift<Btn2Down>: process-bdrag()\n\
|
|
~Shift<Btn2Up>: copy-to()\n\
|
|
<EnterWindow>: enter()\n\
|
|
<LeaveWindow>: leave()\n\
|
|
<FocusIn>: focus-in()\n\
|
|
<FocusOut>: focus-out()\n\
|
|
";
|
|
|
|
|
|
/* global class record for instances of class: TermPrim
|
|
*/
|
|
|
|
externaldef(termclassrec) DtTermPrimitiveClassRec dtTermPrimitiveClassRec =
|
|
{
|
|
/* core class record */
|
|
{
|
|
/* superclass */ (WidgetClass) &xmPrimitiveClassRec,
|
|
/* class_name */ "DtTermPrim",
|
|
/* widget_size */ sizeof(DtTermPrimitiveRec),
|
|
/* class_initialize */ ClassInitialize,
|
|
/* class_part_init */ ClassPartInitialize,
|
|
/* class_inited */ FALSE,
|
|
/* initialize */ Initialize,
|
|
/* initialize_hook */ (XtArgsProc) NULL,
|
|
/* realize */ Realize,
|
|
/* actions */ actionsList,
|
|
/* num_actions */ XtNumber(actionsList),
|
|
/* resources */ resources,
|
|
/* num_resources */ XtNumber(resources),
|
|
/* xrm_class */ NULLQUARK,
|
|
/* compress_motion */ TRUE,
|
|
/* compress_exposure */ FALSE,
|
|
/* compress_enterlv */ TRUE,
|
|
/* visible_interest */ TRUE,
|
|
/* destroy */ Destroy,
|
|
/* resize */ Resize,
|
|
/* expose */ Redisplay,
|
|
/* set_values */ SetValues,
|
|
/* set_values_hook */ (XtArgsFunc) NULL,
|
|
/* set_values_almost */ XtInheritSetValuesAlmost,
|
|
/* get_values_hook */ (XtArgsProc) NULL,
|
|
/* accept_focus */ (XtAcceptFocusProc) NULL,
|
|
/* version */ XtVersion,
|
|
/* callback_private */ (XtPointer) NULL,
|
|
/* tm_table */ defaultTranslations,
|
|
/* query_geometry */ (XtGeometryHandler) NULL,
|
|
/* display_accelerator */ (XtStringProc) NULL,
|
|
/* extension */ (XtPointer) NULL,
|
|
},
|
|
|
|
/* primitive class record */
|
|
{
|
|
/* Primitive border_highlight */ XmInheritWidgetProc,
|
|
/* Primitive border_unhighlight */ XmInheritWidgetProc,
|
|
/* translations */ "" /*NULL*/ /*XtInheritTranslations*/,
|
|
/* arm_and_activate */ NULL,
|
|
/* get resources */ (XmSyntheticResource *) NULL,
|
|
/* num get_resources */ 0,
|
|
/* extension */ (XtPointer) NULL,
|
|
},
|
|
|
|
/* term class record */
|
|
{
|
|
/* parser_start_state */ &_DtTermPrimStateStart,
|
|
/* use_history_buffer */ False,
|
|
/* allow_scroll_below_buffer */ False,
|
|
/* wrap_right_after_insert */ False,
|
|
/* buffer_create_proc */ _DtTermPrimBufferCreateBuffer,
|
|
/* buffer_free_proc */ _DtTermPrimBufferFreeBuffer,
|
|
/* term_insert_proc */ _DtTermPrimInsertText,
|
|
/* sizeOfBuffer */ (short) sizeof(TermBufferRec),
|
|
/* sizeOfLine */ (short) sizeof(TermLineRec),
|
|
/* sizeOfEnh */ (short) sizeof(TermEnhPart),
|
|
}
|
|
};
|
|
|
|
externaldef(termwidgetclass) WidgetClass dtTermPrimitiveWidgetClass =
|
|
(WidgetClass)&dtTermPrimitiveClassRec;
|
|
|
|
/* Class Initialize...
|
|
*/
|
|
static void
|
|
ClassInitialize(void)
|
|
{
|
|
/* register our resource converters... */
|
|
(void) _DtTermPrimInitRepTypes();
|
|
|
|
return;
|
|
}
|
|
|
|
static void
|
|
ClassPartInitialize(WidgetClass w_class)
|
|
{
|
|
(void) DtTermInitialize();
|
|
}
|
|
|
|
static void
|
|
initializeKeyboard
|
|
(
|
|
DtTermPrimData tpd
|
|
)
|
|
{
|
|
/*
|
|
** Make sure the keyboard is unlocked...
|
|
*/
|
|
tpd->keyboardLocked.escape = False;
|
|
tpd->keyboardLocked.xferPending = False;
|
|
tpd->keyboardLocked.error = False;
|
|
tpd->keyboardLocked.record = False;
|
|
|
|
/* other keyboard modes...
|
|
*/
|
|
tpd->autoLineFeed = False;
|
|
tpd->halfDuplex = False;
|
|
}
|
|
|
|
/*
|
|
** initialize the term-generic straps...
|
|
*/
|
|
static void
|
|
initializeStraps
|
|
(
|
|
DtTermPrimData tpd
|
|
)
|
|
{
|
|
tpd->transmitFunctions = False;
|
|
tpd->autoWrapRight = True;
|
|
}
|
|
|
|
/*
|
|
** initialize the term-generic modes...
|
|
*/
|
|
static void
|
|
initializeModes
|
|
(
|
|
DtTermPrimData tpd
|
|
)
|
|
{
|
|
tpd->scrollLockMode = SCROLL_LOCKoff;
|
|
}
|
|
|
|
/*
|
|
** initialize on the spot data...
|
|
*/
|
|
static void
|
|
initializeOTS
|
|
(
|
|
DtTermPrimData tpd
|
|
)
|
|
{
|
|
tpd->onthespot = (OnTheSpotData)XtMalloc(sizeof(OnTheSpotDataRec));
|
|
tpd->onthespot->start = 0;
|
|
tpd->onthespot->end = 0;
|
|
tpd->onthespot->pre_len = 0;
|
|
tpd->onthespot->cursor = 0;
|
|
tpd->onthespot->under_preedit = False;
|
|
}
|
|
|
|
|
|
void
|
|
_DtTermPrimGetFontSet
|
|
(
|
|
Widget w,
|
|
XmFontList fontList,
|
|
XFontSet *fontSet,
|
|
XFontStruct **font
|
|
)
|
|
{
|
|
XmFontContext fontContext;
|
|
XmFontListEntry fontListEntry;
|
|
XmFontType fontType;
|
|
XtPointer pointer;
|
|
|
|
*fontSet = (XFontSet) 0;
|
|
*font = (XFontStruct *) 0;
|
|
|
|
if (!XmFontListInitFontContext(&fontContext, fontList)) {
|
|
(void) fprintf(stderr, "XmFontListInitFontContext() failed\n");
|
|
(void) exit(1);
|
|
}
|
|
|
|
/* suppress the CodeCenter warning:
|
|
* "Assignment in conditional 'while' expression."...
|
|
*/
|
|
/*SUPPRESS 624*/
|
|
while ((fontListEntry = XmFontListNextEntry(fontContext))) {
|
|
pointer = XmFontListEntryGetFont(fontListEntry, &fontType);
|
|
if (fontType == XmFONT_IS_FONTSET) {
|
|
int i;
|
|
int num_fonts;
|
|
XFontStruct **fonts;
|
|
char **fontNames;
|
|
|
|
Debug('f', fprintf(stderr, ">>fontType == XmFONT_IS_FONTSET\n"));
|
|
*fontSet = (XFontSet) pointer;
|
|
num_fonts = XFontsOfFontSet(*fontSet, &fonts, &fontNames);
|
|
for (i = 0; i < num_fonts; i++) {
|
|
Debug('f', fprintf(stderr, ">> font %d: %s\n", i + 1,
|
|
fontNames[i]));
|
|
}
|
|
} else {
|
|
unsigned long ret;
|
|
Debug('f', fprintf(stderr, ">>fontType != XmFONT_IS_FONTSET\n"));
|
|
*font = (XFontStruct *) pointer;
|
|
if (XGetFontProperty(*font, XA_FONT, &ret)) {
|
|
Debug('f', fprintf(stderr, ">>font: %s\n",
|
|
XGetAtomName(XtDisplay(w), ret)));
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef NOTDEF
|
|
if (!*fontSet) {
|
|
unsigned long ret;
|
|
char *fontName;
|
|
char **missingCharsetList;
|
|
int missingCharsetCount;
|
|
|
|
/* build a fontSet from the font... */
|
|
if (XGetFontProperty(*font, XA_FONT, &ret)) {
|
|
fontName = XGetAtomName(XtDisplay(w), ret);
|
|
}
|
|
*fontSet = XCreateFontSet(XtDisplay(w),
|
|
fontName,
|
|
&missingCharsetList,
|
|
&missingCharsetCount,
|
|
(char **) 0);
|
|
if (missingCharsetCount > 0) {
|
|
int i;
|
|
|
|
for (i = 0; i < missingCharsetCount; i++)
|
|
(void) fprintf(stderr, "missing charset in fontset \"%s\"\n",
|
|
missingCharsetList[i]);
|
|
}
|
|
}
|
|
#endif /* NOTDEF */
|
|
|
|
/* DKS: at some point, we may want to do something with the other
|
|
* fonts in the fontList as well...
|
|
*/
|
|
/* free up malloc'ed memory... */
|
|
(void) XmFontListFreeFontContext(fontContext);
|
|
}
|
|
|
|
static TermFont
|
|
CreateRenderFont
|
|
(
|
|
Widget w,
|
|
XmFontList fontList,
|
|
XFontSet *retFontSet,
|
|
XFontStruct **retFont
|
|
)
|
|
{
|
|
TermFont termFont;
|
|
XFontSet fontSet = (XFontSet) 0;
|
|
XFontStruct *font = (XFontStruct *) 0;
|
|
|
|
/* get our fontset from the fontlist... */
|
|
(void) _DtTermPrimGetFontSet(w, fontList, &fontSet, &font);
|
|
|
|
/* generate a TermFont from either the fontset or the font... */
|
|
if (fontSet) {
|
|
termFont = _DtTermPrimRenderFontSetCreate(w, fontSet);
|
|
} else {
|
|
termFont = _DtTermPrimRenderFontCreate(w, font);
|
|
}
|
|
|
|
/* return the font and fontSet if requested... */
|
|
if (retFontSet)
|
|
*retFontSet = fontSet;
|
|
if (retFont)
|
|
*retFont = font;
|
|
|
|
/* return the generated font... */
|
|
return(termFont);
|
|
}
|
|
|
|
static void
|
|
AdjustWindowUnits
|
|
(
|
|
Widget w
|
|
)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
|
|
/* let's adjust the units by the base font size... */
|
|
if (tw->term.fontSet) {
|
|
XFontSetExtents *fontSetExtents;
|
|
int i;
|
|
int num_fonts;
|
|
XFontStruct **fonts;
|
|
char **fontNames;
|
|
|
|
num_fonts = XFontsOfFontSet(tw->term.fontSet, &fonts, &fontNames);
|
|
/* look for the single byte font that includes the normal
|
|
* ascii characters...
|
|
*/
|
|
for (i = 0; i < num_fonts; i++) {
|
|
if ((fonts[i]->min_byte1 == 0) && (fonts[i]->max_byte1 == 0) &&
|
|
(fonts[i]->min_char_or_byte2 <= 'A') &&
|
|
(fonts[i]->max_char_or_byte2 >= 'Z')) {
|
|
break;
|
|
}
|
|
}
|
|
if (i >= num_fonts) {
|
|
/* look for the multi-bypte font that includes the normal ascii
|
|
* characters...
|
|
*/
|
|
for (i = 0; i < num_fonts; i++) {
|
|
if (fonts[i]->min_byte1 == 0) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (i >= num_fonts) {
|
|
/* as a last resort, just use the first font... */
|
|
i = 0;
|
|
}
|
|
|
|
fontSetExtents = XExtentsOfFontSet(tw->term.fontSet);
|
|
|
|
/* build termFont for this fontset... */
|
|
tw->term.widthInc = fonts[i]->max_bounds.width;
|
|
tw->term.heightInc = fontSetExtents->max_logical_extent.height;
|
|
/* why are there two "ascents"? TMH */
|
|
tw->term.ascent = -fontSetExtents->max_logical_extent.y;
|
|
tw->term.tpd->ascent = tw->term.ascent;
|
|
|
|
tw->term.tpd->cellWidth = tw->term.widthInc;
|
|
tw->term.tpd->cellHeight = tw->term.heightInc;
|
|
} else {
|
|
tw->term.widthInc = tw->term.font->max_bounds.width;
|
|
tw->term.heightInc = tw->term.font->ascent + tw->term.font->descent;
|
|
/* why are there two "ascents"? TMH */
|
|
tw->term.ascent = tw->term.font->ascent;
|
|
tw->term.tpd->ascent = tw->term.font->ascent;
|
|
|
|
tw->term.tpd->cellWidth = tw->term.widthInc;
|
|
tw->term.tpd->cellHeight = tw->term.heightInc;
|
|
}
|
|
}
|
|
|
|
static KeyCode *
|
|
GetCapsLockKeyCodes
|
|
(
|
|
XModifierKeymap *modifierMapping,
|
|
short *numCapsLockKeyCodes
|
|
)
|
|
{
|
|
KeyCode *capsLockKeyCodes;
|
|
int i1;
|
|
|
|
/* initialize number of caps lock key codes... */
|
|
*numCapsLockKeyCodes = 0;
|
|
|
|
/* malloc storage for the keycodes (it will be less than or equal to
|
|
* the max)...
|
|
*/
|
|
capsLockKeyCodes = (KeyCode *)
|
|
XtMalloc(modifierMapping->max_keypermod * sizeof(KeyCode));
|
|
|
|
/* copy them over... */
|
|
for (i1 = 0; i1 < modifierMapping->max_keypermod; i1++) {
|
|
capsLockKeyCodes[*numCapsLockKeyCodes] =
|
|
modifierMapping->modifiermap[LockMapIndex *
|
|
modifierMapping->max_keypermod + i1];
|
|
/* only count non-zero keycodes... */
|
|
if (capsLockKeyCodes[*numCapsLockKeyCodes])
|
|
(*numCapsLockKeyCodes)++;
|
|
}
|
|
|
|
return(capsLockKeyCodes);
|
|
}
|
|
|
|
static unsigned int
|
|
GetMetaMask
|
|
(
|
|
XModifierKeymap *modifierMapping,
|
|
KeySym *keyboardMapping,
|
|
int keysymsPerKeycode,
|
|
int minKeycodes,
|
|
int maxKeycodes
|
|
)
|
|
{
|
|
unsigned int i1;
|
|
unsigned int metaMask;
|
|
Boolean match;
|
|
int mapIndex;
|
|
KeyCode thisKeyCode;
|
|
KeySym thisKeySym;
|
|
|
|
/* figure out what modifier corresponds to the meta key.
|
|
* If there is none, return 0...
|
|
*/
|
|
for (match = False, metaMask = Mod1Mask, mapIndex = Mod1MapIndex;
|
|
(mapIndex <= Mod5MapIndex) && !match;
|
|
metaMask <<= 1, mapIndex++) {
|
|
for (i1 = 0; i1 < modifierMapping->max_keypermod; i1++) {
|
|
thisKeyCode = modifierMapping->modifiermap[mapIndex *
|
|
modifierMapping->max_keypermod + i1];
|
|
if (thisKeyCode < minKeycodes)
|
|
break;
|
|
thisKeySym = keyboardMapping[(thisKeyCode - minKeycodes) *
|
|
keysymsPerKeycode];
|
|
if ((thisKeySym == XK_Meta_L) || (thisKeySym == XK_Meta_R)) {
|
|
/* we found either meta_l or meta_r... */
|
|
match = True;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (match) {
|
|
/* we found either meta_l or meta_r... */
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (match) {
|
|
return(metaMask);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static void
|
|
Initialize(Widget ref_w, Widget w, Arg *args, Cardinal *num_args)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
DtTermPrimData tpd;
|
|
XmFontContext fontContext;
|
|
XmFontListEntry fontListEntry;
|
|
XmFontType fontType;
|
|
XModifierKeymap *modifierMapping;
|
|
KeySym *keyboardMapping;
|
|
int minKeycodes;
|
|
int maxKeycodes;
|
|
int keysymsPerKeycode;
|
|
XmRepTypeId shadowTypeID;
|
|
int i;
|
|
|
|
Debug('T', timeStamp("TermPrim Initialize() starting"));
|
|
|
|
|
|
/* initialize... */
|
|
/* we need to insure that everything is initialized. Let's do a
|
|
* checklist...
|
|
*/
|
|
/* lower euid */
|
|
(void) _DtTermPrimToggleSuidRoot(False);
|
|
|
|
/* Widget verticalScrollBar set via setvalues */
|
|
/* short verticalScrollBarValue */
|
|
tw->term.verticalScrollBarValue = 0;
|
|
|
|
/* short verticalScrollBarMaximum */
|
|
tw->term.verticalScrollBarMaximum = 0;
|
|
|
|
/* short verticalScrollBarSliderSize */
|
|
tw->term.verticalScrollBarSliderSize = 0;
|
|
|
|
/* short verticalScrollBarPageIncrement */
|
|
tw->term.verticalScrollBarPageIncrement = 0;
|
|
|
|
/* unsigned char charCursorStyle set via setvalues */
|
|
/* int blinkRate set via setvalues */
|
|
/* Boolean stickyPrevCursor set via setvalues */
|
|
/* Boolean stickyNextCursor set via setvalues */
|
|
/* Boolean backgroundIsSelect set via setvalues */
|
|
/* Boolean visualBell set via setvalues */
|
|
/* Boolean marginBell set via setvalues */
|
|
/* int nMarginBell set via setvalues */
|
|
/* Boolean jumpScroll set via setvalues */
|
|
/* Boolean hasFocus */
|
|
tw->term.hasFocus = False;
|
|
|
|
/* char *termId set via setvalues */
|
|
/* char *termName set via setvalues */
|
|
/* char *ttyModes set via setvalues */
|
|
/* unsigned char shadowType set via setvalues */
|
|
/* XmFontList fontList set via setvalues */
|
|
/* XFontStruct *font */
|
|
tw->term.font = (XFontStruct *) 0;
|
|
tw->term.boldFont = (XFontStruct *) 0;
|
|
|
|
/* XFontSet fontSet */
|
|
tw->term.fontSet = (XFontSet) 0;
|
|
tw->term.boldFontSet = (XFontSet) 0;
|
|
|
|
/* Boolean haveFontSet */
|
|
tw->term.haveFontSet = False;
|
|
|
|
/* char *saveLines set via setvalues */
|
|
/* short rows set via setvalues */
|
|
/* short columns set via setvalues */
|
|
/* Dimension marginHeight set via setvalues */
|
|
/* Dimension marginWidth set via setvalues */
|
|
/* int baseWidth set via setvalues */
|
|
/* int baseHeight set via setvalues */
|
|
/* int widthInc set via setvalues */
|
|
/* int heightInc set via setvalues */
|
|
/* int ascent */
|
|
tw->term.ascent = 0;
|
|
|
|
/* int pty set via setvalues */
|
|
/* int ptyAllocate set via setvalues */
|
|
/* char *ptySlaveName set via setvalues */
|
|
/* int subprocessPid set via setvalues */
|
|
/* char *subprocessCWD */
|
|
tw->term.subprocessCWD = (char *) 0;
|
|
|
|
/* char *subprocessCmd set via setvalues */
|
|
/* char **subprocessArgv set via setvalues */
|
|
/* Boolean subprocessLoginShell set via setvalues */
|
|
/* Boolean subprocessTerminationCatch
|
|
set via setvalues */
|
|
/* Boolean subprocessExec set via setvalues */
|
|
/* _termSubprocId subprocessId */
|
|
tw->term.subprocessId = (_termSubprocId) 0;
|
|
|
|
/* XtCallbackList statusChangeCallback
|
|
set via setvalues */
|
|
/* XtCallbackList subprocessTerminationCallback
|
|
set via setvalues */
|
|
|
|
/* Boolean allowOsfKeysyms */
|
|
tw->term.allowOsfKeysyms = False;
|
|
|
|
if (tw->term.backgroundIsSelect) {
|
|
/* set the background pixel based on the select color... */
|
|
(void) XmGetColors(XtScreen(w), w->core.colormap,
|
|
tw->core.background_pixel, NULL, NULL, NULL,
|
|
&tw->core.background_pixel);
|
|
}
|
|
|
|
/* malloc terminalData dataspace... */
|
|
tw->term.tpd = (DtTermPrimData) malloc(sizeof(DtTermPrimDataRec));
|
|
tpd = tw->term.tpd;
|
|
|
|
/* clear malloc'ed memory... */
|
|
(void) memset(tpd, '\0', sizeof(DtTermPrimDataRec));
|
|
|
|
/* initialize any of it...
|
|
*/
|
|
tpd->cursorState = CURSORoff;
|
|
tpd->cursorVisible = True;
|
|
tpd->IMHasFocus = False;
|
|
tpd->IMCursorRow = -1;
|
|
tpd->IMCursorColumn = -1;
|
|
|
|
/*
|
|
** Initialize the keyboard, straps, and modes...
|
|
*/
|
|
initializeKeyboard(tpd);
|
|
initializeModes(tpd);
|
|
initializeStraps(tpd);
|
|
initializeOTS(tpd);
|
|
|
|
/* initialize scroll variables...
|
|
*/
|
|
|
|
tpd->useHistoryBuffer = ((DtTermPrimitiveClassRec *) (tw->core.widget_class))->
|
|
term_primitive_class.use_history_buffer;
|
|
tpd->allowScrollBelowBuffer = ((DtTermPrimitiveClassRec *) (tw->core.widget_class))->
|
|
term_primitive_class.allow_scroll_below_buffer;
|
|
tpd->wrapRightAfterInsert = ((DtTermPrimitiveClassRec *) (tw->core.widget_class))->
|
|
term_primitive_class.wrap_right_after_insert;
|
|
|
|
/* initialize pending text... */
|
|
tpd->pendingRead = _DtTermPrimPendingTextCreate();
|
|
tpd->pendingWrite = _DtTermPrimPendingTextCreate();
|
|
|
|
/*
|
|
** Initialize the utmp stuff...
|
|
*/
|
|
#ifndef HAS_UTEMPTER_LIBRARY
|
|
_DtTermPrimUtmpInit(w);
|
|
#endif
|
|
|
|
/*
|
|
** Initialize the selection inforamtion
|
|
*/
|
|
tpd->selectInfo = _DtTermPrimSelectCreate(w);
|
|
|
|
/* force unit type to pixels... */
|
|
tw->primitive.unit_type = XmPIXELS;
|
|
|
|
/* we have a fontlist. Get a fontset from it if we can, else get a
|
|
* fontstruct and make a fontset if we can...
|
|
*/
|
|
/* get the text default fontlist if we don't have one... */
|
|
if (!tw->term.fontList) {
|
|
tw->term.fontList = XmeGetDefaultRenderTable(w, XmTEXT_FONTLIST);
|
|
}
|
|
|
|
tpd->termFont = CreateRenderFont(w, tw->term.fontList,
|
|
&tw->term.fontSet, &tw->term.font);
|
|
|
|
if (tw->term.boldFontList) {
|
|
tpd->boldTermFont = CreateRenderFont(w, tw->term.boldFontList,
|
|
&tw->term.boldFontSet, &tw->term.boldFont);
|
|
} else {
|
|
/* let's try and build a bold fontlist off of the base fontlist... */
|
|
int num_fonts;
|
|
char **fontNames;
|
|
char *boldFontNames = NULL;
|
|
const char *bold = "bold";
|
|
size_t boldLen = strlen(bold);
|
|
|
|
if (tw->term.fontSet) {
|
|
int i;
|
|
XFontStruct **fonts;
|
|
size_t len = 1; /* 1: NUL */
|
|
|
|
Debug('f', fprintf(stderr, ">>generating bold fontset\n"));
|
|
num_fonts = XFontsOfFontSet(tw->term.fontSet, &fonts, &fontNames);
|
|
|
|
for (i = 0; i < num_fonts; ++i)
|
|
/* 2: COMMA and SPACE */
|
|
len += strlen(fontNames[i]) + boldLen + 2;
|
|
|
|
boldFontNames = malloc(len);
|
|
}
|
|
|
|
if (boldFontNames) {
|
|
char *c1;
|
|
char *c2;
|
|
int i1;
|
|
int i2;
|
|
char **missingCharsetList;
|
|
int missingCharsetCount;
|
|
|
|
for (i1 = 0, c2 = boldFontNames; i1 < num_fonts; i1++) {
|
|
/* if this is not the first name we need a comma to
|
|
* separate the names...
|
|
*/
|
|
if (i1 > 0) {
|
|
*c2++ = ',';
|
|
*c2++ = ' ';
|
|
}
|
|
|
|
/* copy over the first 3 fields... */
|
|
for (c1 = fontNames[i1], i2 = 0; (i2 < 3) && *c1; i2++) {
|
|
while (*c1 && (*c1 != '-')) {
|
|
*c2++ = *c1++;
|
|
}
|
|
if (!*c1) {
|
|
break;
|
|
}
|
|
/* copy over the '-'... */
|
|
*c2++ = *c1++;
|
|
}
|
|
/* make boldFont bold by swapping the bold in for the
|
|
* weight...
|
|
*/
|
|
(void) strcpy(c2, bold);
|
|
c2 += boldLen;
|
|
|
|
/* skip over the weight in the source... */
|
|
while (*c1 && (*c1 != '-')) {
|
|
c1++;
|
|
}
|
|
|
|
/* copy over the rest of the fontname... */
|
|
while (*c1) {
|
|
*c2++ = *c1++;
|
|
}
|
|
}
|
|
|
|
/* null term... */
|
|
*c2 = '\0';
|
|
|
|
/* now create the fontset... */
|
|
tw->term.boldFontSet = XCreateFontSet(XtDisplay(w),
|
|
boldFontNames,
|
|
&missingCharsetList,
|
|
&missingCharsetCount,
|
|
(char **) 0);
|
|
|
|
free(boldFontNames);
|
|
|
|
if (missingCharsetCount > 0) {
|
|
int i;
|
|
|
|
for (i = 0; i < missingCharsetCount; i++)
|
|
Debug('f', fprintf(stderr,
|
|
">>missing charsets in boldfont \"%s\"\n",
|
|
missingCharsetList[i]));
|
|
(void) XFreeStringList(missingCharsetList);
|
|
if (tw->term.boldFontSet) {
|
|
(void) XFreeFontSet(XtDisplay(w), tw->term.boldFontSet);
|
|
tw->term.boldFontSet = (XFontSet) 0;
|
|
}
|
|
}
|
|
|
|
/* create a bold render font... */
|
|
if (tw->term.boldFontSet) {
|
|
tpd->boldTermFont =
|
|
_DtTermPrimRenderFontSetCreate(w, tw->term.boldFontSet);
|
|
}
|
|
} else if (tw->term.font) {
|
|
unsigned long ret;
|
|
char *fontName;
|
|
char boldFontName[BUFSIZ];
|
|
char *c1;
|
|
char *c2;
|
|
int i2;
|
|
|
|
/* get the fontname associated with the font... */
|
|
if (XGetFontProperty(tw->term.font, XA_FONT, &ret)) {
|
|
fontName = XGetAtomName(XtDisplay(w), ret);
|
|
/* copy over the first 3 fields... */
|
|
for (c1 = fontName, c2 = boldFontName, i2 = 0;
|
|
(i2 < 3) && *c1; i2++) {
|
|
while (*c1 && (*c1 != '-')) {
|
|
*c2++ = *c1++;
|
|
}
|
|
if (!*c1) {
|
|
break;
|
|
}
|
|
/* copy over the '-'... */
|
|
*c2++ = *c1++;
|
|
}
|
|
/* make boldFont bold by swapping the bold in for the
|
|
* weight...
|
|
*/
|
|
(void) strcpy(c2, bold);
|
|
c2 += boldLen;
|
|
|
|
/* skip over the weight in the source... */
|
|
while (*c1 && (*c1 != '-')) {
|
|
c1++;
|
|
}
|
|
|
|
/* copy over the rest of the fontname... */
|
|
while (*c1) {
|
|
*c2++ = *c1++;
|
|
}
|
|
|
|
/* null term the string... */
|
|
*c2 = '\0';
|
|
|
|
tw->term.boldFont = XLoadQueryFont(XtDisplay(w), boldFontName);
|
|
/* create a bold render font... */
|
|
if (tw->term.boldFont) {
|
|
tpd->boldTermFont =
|
|
_DtTermPrimRenderFontCreate(w, tw->term.boldFont);
|
|
}
|
|
XFree(fontName) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* save away our original fonts as defaults... */
|
|
tpd->defaultTermFont = tpd->termFont;
|
|
tpd->defaultBoldTermFont = tpd->boldTermFont;
|
|
|
|
/* look through our XFontSet or XFontStruct and adjust our
|
|
* width and height increments...
|
|
*/
|
|
(void) AdjustWindowUnits(w);
|
|
|
|
/* initialize the base width/height... */
|
|
tw->term.baseWidth = 2 * (tw->primitive.shadow_thickness +
|
|
tw->primitive.highlight_thickness + tw->term.marginWidth);
|
|
tw->term.baseHeight = 2 * (tw->primitive.shadow_thickness +
|
|
tw->primitive.highlight_thickness + tw->term.marginHeight);
|
|
|
|
/* adjust width and height by rows/columns and the font size... */
|
|
tw->core.width =
|
|
tw->term.columns * tw->term.widthInc + tw->term.baseWidth;
|
|
tw->core.height =
|
|
tw->term.rows * tw->term.heightInc + tw->term.baseHeight;
|
|
Debug('w', fprintf(stderr, ">>core.width=%u\n", tw->core.width));
|
|
Debug('w', fprintf(stderr, ">>core.height=%u\n", tw->core.height));
|
|
|
|
/* set the termData fields... */
|
|
(void) _DtTermPrimParserInitContext(w);
|
|
tpd->parserNotInStartState = False;
|
|
tpd->offsetX = tw->primitive.shadow_thickness +
|
|
tw->primitive.highlight_thickness + tw->term.marginWidth;
|
|
tpd->offsetY = tw->primitive.shadow_thickness +
|
|
tw->primitive.highlight_thickness + tw->term.marginHeight;
|
|
tpd->cellWidth = tw->term.widthInc;
|
|
tpd->cellHeight = tw->term.heightInc;
|
|
tpd->ascent = tw->term.ascent;
|
|
tpd->windowMapped = False ;
|
|
time( &tpd->creationTime) ;
|
|
if (tw->term.pointerBlank) tpd->pointerFirst = True ;
|
|
|
|
/* multi-byte specific fields...
|
|
*/
|
|
tpd->mbCurMax = MB_CUR_MAX;
|
|
/* use a debug flag to force ourselves into multi-byte
|
|
* mode for single byte locales...
|
|
*/
|
|
DebugF('m', 1, tpd->mbCurMax = MB_LEN_MAX);
|
|
tpd->mbPartialCharLen = 0; /* no pending partial multi-byte char */
|
|
|
|
/* check results of type converters... */
|
|
shadowTypeID = XmRepTypeGetId(XmRShadowType);
|
|
if (shadowTypeID != XmREP_TYPE_INVALID) {
|
|
if (!XmRepTypeValidValue(shadowTypeID, tw->term.shadowType, w))
|
|
tw->term.shadowType = DtSHADOW_IN;
|
|
}
|
|
|
|
/* get the keyboard modifier mapping... */
|
|
modifierMapping = XGetModifierMapping(XtDisplay(w));
|
|
(void) XDisplayKeycodes(XtDisplay(w), &minKeycodes, &maxKeycodes);
|
|
keyboardMapping = XGetKeyboardMapping(XtDisplay(w), minKeycodes,
|
|
maxKeycodes - minKeycodes + 1, &keysymsPerKeycode);
|
|
|
|
/* get the caps lock keycodes... */
|
|
tpd->capsLockKeyCodes = GetCapsLockKeyCodes(modifierMapping,
|
|
&tpd->numCapsLockKeyCodes);
|
|
|
|
/* get the modifier bit that corresponds to meta.
|
|
* If there is none, use mod1...
|
|
*/
|
|
tpd->metaMask = GetMetaMask(modifierMapping, keyboardMapping,
|
|
keysymsPerKeycode, minKeycodes, maxKeycodes);
|
|
if (!tpd->metaMask) {
|
|
/* default to mod1... */
|
|
tpd->metaMask = Mod1Mask;
|
|
}
|
|
|
|
(void) XFree(keyboardMapping);
|
|
(void) XFreeModifiermap(modifierMapping);
|
|
|
|
(void) XtAddEventHandler(w,
|
|
(EventMask) KeyPressMask | KeyReleaseMask,
|
|
False, handleKeyEvents, (Opaque) NULL);
|
|
(void) XtAddEventHandler(w,
|
|
(EventMask) ButtonPressMask | ButtonReleaseMask,
|
|
False, handleButtonEvents, (Opaque) NULL);
|
|
(void) XtAddEventHandler(w,
|
|
(EventMask) 0,
|
|
True, handleNonMaskableEvents, (Opaque) NULL);
|
|
{
|
|
Widget sw ;
|
|
|
|
for (sw = w; !XtIsShell(sw); sw = XtParent(sw))
|
|
;
|
|
(void) XtAddEventHandler(sw, (EventMask) StructureNotifyMask,
|
|
False, handleProcessStructureNotifyEvent, (Opaque) w);
|
|
(void) XtAddEventHandler(sw, (EventMask) PropertyChangeMask,
|
|
False, handlePropertyChangeEvents, (Opaque) w);
|
|
}
|
|
|
|
if (tw->term.verticalScrollBar) {
|
|
/* set up the callbacks for the scrollbar... */
|
|
(void) InitializeVerticalScrollBar(w, True);
|
|
}
|
|
|
|
tw->term.log_on = False ;
|
|
if (tw->term.logging) {
|
|
_DtTermPrimStartLog((Widget) tw);
|
|
}
|
|
|
|
Debug('T', timeStamp("TermPrim Initialize() finished"));
|
|
return;
|
|
}
|
|
|
|
static void
|
|
InitializeVerticalScrollBar(Widget w, Boolean initCallbacks)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
Arg arglist[20];
|
|
int i;
|
|
int value;
|
|
|
|
if (initCallbacks) {
|
|
/* set up the scrollbar callbacks... */
|
|
#ifdef NOTDEF
|
|
(void) XtAddCallback(tw->term.verticalScrollBar, XmNdecrementCallback,
|
|
VerticalScrollBarCallback, (XtPointer) w);
|
|
(void) XtAddCallback(tw->term.verticalScrollBar, XmNincrementCallback,
|
|
VerticalScrollBarCallback, (XtPointer) w);
|
|
|
|
(void) XtAddCallback(tw->term.verticalScrollBar,
|
|
XmNpageDecrementCallback,
|
|
VerticalScrollBarCallback, (XtPointer) w);
|
|
(void) XtAddCallback(tw->term.verticalScrollBar,
|
|
XmNpageIncrementCallback,
|
|
VerticalScrollBarCallback, (XtPointer) w);
|
|
|
|
(void) XtAddCallback(tw->term.verticalScrollBar,
|
|
XmNtoTopCallback, VerticalScrollBarCallback, (XtPointer) w);
|
|
(void) XtAddCallback(tw->term.verticalScrollBar,
|
|
XmNtoBottomCallback, VerticalScrollBarCallback, (XtPointer) w);
|
|
#endif /* NOTDEF */
|
|
|
|
(void) XtAddCallback(tw->term.verticalScrollBar, XmNdragCallback,
|
|
VerticalScrollBarCallback, (XtPointer) w);
|
|
(void) XtAddCallback(tw->term.verticalScrollBar,
|
|
XmNvalueChangedCallback, VerticalScrollBarCallback,
|
|
(XtPointer) w);
|
|
}
|
|
|
|
if (!tpd->termBuffer) {
|
|
/* no termBuffer yet, we set anything yet... */
|
|
return;
|
|
}
|
|
|
|
/* update the scrollbar... */
|
|
if (tw->term.verticalScrollBar) {
|
|
/* we can scroll the height of the history buffer and the
|
|
* number of used rows less the protected areas...
|
|
*/
|
|
if (tpd->useHistoryBuffer) {
|
|
#define NO_SCROLL_REGION_HISTORY_SCROLL
|
|
#ifdef NO_SCROLL_REGION_HISTORY_SCROLL
|
|
tw->term.verticalScrollBarMaximum = tw->term.rows;
|
|
if ((tpd->scrollLockTopRow <= 0) &&
|
|
(tpd->scrollLockBottomRow >= (tw->term.rows - 1))) {
|
|
tw->term.verticalScrollBarMaximum += tpd->lastUsedHistoryRow;
|
|
}
|
|
#else /* NO_SCROLL_REGION_HISTORY_SCROLL */
|
|
tw->term.verticalScrollBarMaximum = tw->term.rows +
|
|
tpd->lastUsedHistoryRow;
|
|
#endif /* NO_SCROLL_REGION_HISTORY_SCROLL */
|
|
} else {
|
|
tw->term.verticalScrollBarMaximum = tpd->lastUsedRow +
|
|
tpd->scrollLockTopRow -
|
|
(tw->term.rows - 1 - tpd->scrollLockBottomRow);
|
|
|
|
/* add in any non-existent rows below the last used row...
|
|
*/
|
|
if (tpd->allowScrollBelowBuffer) {
|
|
/* add in a full screen (less one line and protected areas)
|
|
* below the last used row...
|
|
*/
|
|
tw->term.verticalScrollBarMaximum += tw->term.rows - 1 -
|
|
tpd->scrollLockTopRow -
|
|
(tw->term.rows - 1 - tpd->scrollLockBottomRow);
|
|
}
|
|
}
|
|
|
|
if (tpd->useHistoryBuffer) {
|
|
tw->term.verticalScrollBarSliderSize = tw->term.rows;
|
|
} else {
|
|
tw->term.verticalScrollBarSliderSize =
|
|
tw->term.rows - tpd->scrollLockTopRow -
|
|
(tw->term.rows - 1 - tpd->scrollLockBottomRow);
|
|
}
|
|
|
|
tw->term.verticalScrollBarPageIncrement =
|
|
tw->term.verticalScrollBarSliderSize;
|
|
|
|
#ifdef NO_SCROLL_REGION_HISTORY_SCROLL
|
|
tw->term.verticalScrollBarValue = tpd->topRow;
|
|
if (tpd->useHistoryBuffer && (tpd->scrollLockTopRow <= 0) &&
|
|
(tpd->scrollLockBottomRow >= (tw->term.rows - 1))) {
|
|
tw->term.verticalScrollBarValue += tpd->lastUsedHistoryRow;
|
|
}
|
|
#else /* NO_SCROLL_REGION_HISTORY_SCROLL */
|
|
tw->term.verticalScrollBarValue = tpd->topRow + tpd->lastUsedHistoryRow;
|
|
#endif /* NO_SCROLL_REGION_HISTORY_SCROLL */
|
|
|
|
i = 0;
|
|
(void) XtSetArg(arglist[i], XmNincrement, 1); i++;
|
|
(void) XtSetArg(arglist[i], XmNminimum, 0); i++;
|
|
(void) XtSetArg(arglist[i], XmNmaximum,
|
|
tw->term.verticalScrollBarMaximum); i++;
|
|
(void) XtSetArg(arglist[i], XmNpageIncrement,
|
|
tw->term.verticalScrollBarPageIncrement); i++;
|
|
(void) XtSetArg(arglist[i], XmNsliderSize,
|
|
tw->term.verticalScrollBarSliderSize); i++;
|
|
(void) XtSetArg(arglist[i], XmNvalue, tw->term.verticalScrollBarValue);
|
|
i++;
|
|
(void) XtSetValues(tw->term.verticalScrollBar, arglist, i);
|
|
|
|
Debug('b', fprintf(stderr,
|
|
"InitializeVerticalScrollBar: sb size=%d min=%d max=%d value=%d pginc=%d\n",
|
|
tw->term.verticalScrollBarSliderSize,
|
|
0,
|
|
tw->term.verticalScrollBarMaximum,
|
|
tw->term.verticalScrollBarValue,
|
|
tw->term.verticalScrollBarPageIncrement));
|
|
}
|
|
}
|
|
|
|
static void
|
|
InitOrResizeTermBuffer(Widget w)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
DtTermPrimitiveClassPart *termClassPart = &(((DtTermPrimitiveClassRec *)
|
|
(tw->core.widget_class))->term_primitive_class);
|
|
long lines;
|
|
char *c;
|
|
short newColumns;
|
|
short newRows;
|
|
short reqColumns;
|
|
short reqRows;
|
|
short newBufferRows = tpd->bufferRows;
|
|
short newHistoryBufferRows = tpd->historyBufferRows;
|
|
int linesNeeded;
|
|
int historyLinesNeeded;
|
|
int i1;
|
|
Boolean resizeTermBuffer;
|
|
Boolean updateWindowSize = False;
|
|
|
|
/* set rows and columns... */
|
|
newColumns = MAX(1, ((int)(tw->core.width - (2 * (tw->primitive.shadow_thickness +
|
|
tw->primitive.highlight_thickness + tw->term.marginWidth)))) /
|
|
tw->term.widthInc);
|
|
newRows = MAX(1, ((int)(tw->core.height - (2 * (tw->primitive.shadow_thickness +
|
|
tw->primitive.highlight_thickness + tw->term.marginHeight)))) /
|
|
tw->term.heightInc);
|
|
|
|
if ((newColumns == tw->term.columns) && (newRows == tw->term.rows) &&
|
|
tpd->termBuffer) {
|
|
/* we already have a buffer and the size didn't change so,
|
|
* no change...
|
|
*/
|
|
return;
|
|
}
|
|
|
|
/* resize/create the term buffer... */
|
|
if (tpd->termBuffer) {
|
|
/* restore the buffer-to-window ratio of our off-window buffer
|
|
* is less than 75% of the original off-window buffer...
|
|
*/
|
|
if (tpd->useHistoryBuffer) {
|
|
if ((100 * (tpd->bufferRows + tpd->historyBufferRows) /
|
|
newRows) < ((75 * tpd->bufferRowRatio) / 100)) {
|
|
newBufferRows = (tpd->bufferRowRatio * newRows) / 100;
|
|
newHistoryBufferRows = newBufferRows - newRows;
|
|
newBufferRows = newRows;
|
|
} else {
|
|
/* the buffer needs to be the length of the window... */
|
|
newBufferRows = newRows;
|
|
}
|
|
} else {
|
|
if ((100 * tpd->bufferRows / newRows) <
|
|
((75 * tpd->bufferRowRatio) / 100)) {
|
|
newBufferRows = (tpd->bufferRowRatio * newRows) / 100;
|
|
}
|
|
}
|
|
|
|
/* it needs to be at least the size of the window...
|
|
*/
|
|
if (newBufferRows < newRows) {
|
|
newBufferRows = newRows;
|
|
}
|
|
|
|
resizeTermBuffer = True; /* until further notice */
|
|
|
|
if (tpd->useHistoryBuffer && tpd->historyBufferRows > 0 )
|
|
{
|
|
/*
|
|
** if we are using a history buffer and have scrolled
|
|
** into it, we need to snap back down before we do
|
|
** anything...
|
|
*/
|
|
if (tpd->topRow < 0)
|
|
{
|
|
(void) _DtTermPrimScrollTextTo((Widget) tw, 0);
|
|
}
|
|
|
|
/* resize the history buffer first so that we can scroll
|
|
* data from the active buffer into it (if necessary) without
|
|
* loosing any data...
|
|
*/
|
|
|
|
if ((newHistoryBufferRows > tpd->historyBufferRows) ||
|
|
(newColumns != tw->term.columns))
|
|
{
|
|
reqRows = newHistoryBufferRows;
|
|
reqColumns = newColumns;
|
|
|
|
_DtTermPrimBufferResizeBuffer(&tpd->historyBuffer, &reqRows,
|
|
&reqColumns);
|
|
|
|
if ((reqColumns < newColumns) ||
|
|
(reqRows < newHistoryBufferRows))
|
|
{
|
|
/*
|
|
** we ran out of memory when we tried to resize the
|
|
** history buffer, make the necessary adjustments
|
|
*/
|
|
newColumns = reqColumns;
|
|
newHistoryBufferRows = reqRows;
|
|
|
|
/*
|
|
** we ran out of memory, no need try and resize the
|
|
** term buffer
|
|
*/
|
|
resizeTermBuffer = False;
|
|
}
|
|
}
|
|
|
|
if (resizeTermBuffer)
|
|
{
|
|
if (newBufferRows < tpd->bufferRows)
|
|
{
|
|
/* we are shrinking the window. The first choice is to
|
|
* move lines above the cursor into the history buffer so
|
|
* that we don't loose any lines in the window. If there
|
|
* are not enough lines above the cursor, we will drop
|
|
* some of the lines off the bottom of the window...
|
|
*/
|
|
linesNeeded = tpd->bufferRows - newBufferRows;
|
|
|
|
/* clip this by the number of lines above the cursor... */
|
|
if (linesNeeded > tpd->cursorRow)
|
|
{
|
|
linesNeeded = tpd->cursorRow;
|
|
}
|
|
|
|
historyLinesNeeded = linesNeeded - (newHistoryBufferRows -
|
|
tpd->lastUsedHistoryRow);
|
|
|
|
if (historyLinesNeeded > 0) {
|
|
/* take them from the top of the history buffer... */
|
|
(void) _DtTermPrimBufferInsertLineFromTB(
|
|
tpd->historyBuffer, tpd->historyBufferRows - 1,
|
|
historyLinesNeeded, insertFromTop);
|
|
/* adjust everything... */
|
|
tpd->lastUsedHistoryRow -= historyLinesNeeded;
|
|
}
|
|
|
|
/* copy the lines over... */
|
|
for (i1 = 0; i1 < linesNeeded; i1++) {
|
|
termChar *c1;
|
|
short length;
|
|
termChar *overflowChars;
|
|
short overflowCount;
|
|
|
|
/* get the line from the active buffer... */
|
|
length = _DtTermPrimBufferGetLineLength(tpd->termBuffer,
|
|
i1);
|
|
c1 = _DtTermPrimBufferGetCharacterPointer(tpd->termBuffer,
|
|
i1, 0);
|
|
|
|
/* stuff it into the history buffer... */
|
|
(void) _DtTermPrimBufferSetLineWidth(tpd->historyBuffer,
|
|
tpd->lastUsedHistoryRow,
|
|
0);
|
|
overflowChars = (termChar *) XtMalloc(BUFSIZ * sizeof (termChar));
|
|
(void) _DtTermPrimBufferInsert(tpd->historyBuffer,
|
|
tpd->lastUsedHistoryRow,
|
|
0, c1, length, False,
|
|
&overflowChars,
|
|
&overflowCount);
|
|
(void) tpd->lastUsedHistoryRow++;
|
|
(void) XtFree((char *) overflowChars);
|
|
}
|
|
|
|
/* scroll up the active buffer... */
|
|
if (linesNeeded > 0) {
|
|
(void) _DtTermPrimBufferInsertLineFromTB(tpd->termBuffer,
|
|
tpd->bufferRows - 1,
|
|
linesNeeded,
|
|
insertFromTop);
|
|
/* adjust everything... */
|
|
tpd->cursorRow -= linesNeeded;
|
|
}
|
|
}
|
|
|
|
if ((newBufferRows != tpd->bufferRows) ||
|
|
(newColumns != tw->term.columns))
|
|
{
|
|
reqRows = newBufferRows;
|
|
reqColumns = newColumns;
|
|
|
|
_DtTermPrimBufferResizeBuffer(&tpd->termBuffer, &reqRows,
|
|
&reqColumns);
|
|
if ((reqColumns < newColumns) || (reqRows < newBufferRows))
|
|
{
|
|
/*
|
|
** we ran out of memory, resize the history buffer
|
|
** to the same width as the terminal buffer,
|
|
** and assume we will succeed...
|
|
*/
|
|
newColumns = reqColumns;
|
|
reqRows = newHistoryBufferRows;
|
|
|
|
_DtTermPrimBufferResizeBuffer(&tpd->historyBuffer,
|
|
&reqRows, &reqColumns);
|
|
newBufferRows = reqRows;
|
|
}
|
|
}
|
|
}
|
|
tpd->historyBufferRows = newHistoryBufferRows;
|
|
tpd->bufferRows = newBufferRows;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
** no history buffer to worry about...
|
|
*/
|
|
_DtTermPrimBufferResizeBuffer(&tpd->termBuffer, &newBufferRows,
|
|
&newColumns);
|
|
tpd->bufferRows = newBufferRows;
|
|
}
|
|
|
|
/*
|
|
** on the slight chance that the buffer shrank...
|
|
*/
|
|
newBufferRows = MIN(newBufferRows, newRows);
|
|
|
|
/*
|
|
** if we added rows, then malloc a new set of scrollRefreshRows...
|
|
*/
|
|
if (newBufferRows > tw->term.rows)
|
|
{
|
|
(void) XtFree(tpd->scrollRefreshRows);
|
|
tpd->scrollRefreshRows = (Boolean *) XtMalloc(newBufferRows *
|
|
sizeof(Boolean));
|
|
(void) memset(tpd->scrollRefreshRows, '\0', newBufferRows *
|
|
sizeof(Boolean));
|
|
}
|
|
|
|
/* we got this far because we changed the buffer size. We
|
|
* will have to update the winsize structure...
|
|
*/
|
|
updateWindowSize = True;
|
|
|
|
tw->term.rows = newBufferRows;
|
|
tw->term.columns = newColumns;
|
|
if (tpd->lastUsedRow > newRows)
|
|
tpd->lastUsedRow = newRows;
|
|
|
|
/* adjust the insert point if necessary... */
|
|
if (tpd->cursorColumn > tw->term.columns - 1)
|
|
tpd->cursorColumn = tw->term.columns - 1;
|
|
if (tpd->cursorRow > tw->term.rows - 1)
|
|
tpd->cursorRow = tw->term.rows - 1;
|
|
|
|
} else {
|
|
#ifdef SET_WINDOW_SIZE_ONLY_IF_CHANGED
|
|
/* if our rows and columns changed, we will have to update
|
|
* the winsize structure...
|
|
*/
|
|
if ((tw->term.rows != newRows) || (tw->term.columns != newColumns)) {
|
|
updateWindowSize = True;
|
|
}
|
|
#else /* SET_WINDOW_SIZE_ONLY_IF_CHANGED */
|
|
/* we always need to update the winsize structure since it will not
|
|
* be done for us via $LINES and $COLUMNS...
|
|
*/
|
|
updateWindowSize = True;
|
|
#endif /* SET_WINDOW_SIZE_ONLY_IF_CHANGED */
|
|
|
|
tw->term.rows = newRows;
|
|
tw->term.columns = newColumns;
|
|
|
|
/* this is the first time and we need to figure out our ratio for
|
|
* future resizing...
|
|
*/
|
|
if (tw->term.saveLines && *tw->term.saveLines) {
|
|
lines = strtol(tw->term.saveLines, &c, 0);
|
|
if (c && (*c == 's')) {
|
|
/* in terms of screens... */
|
|
tpd->bufferRows = (lines + 1) * tw->term.rows;
|
|
} else {
|
|
tpd->bufferRows = (lines + tw->term.rows);
|
|
}
|
|
} else {
|
|
tpd->bufferRows = 2 * tw->term.rows;
|
|
}
|
|
|
|
/* calculate the buffer ratio from bufferRows and rows... */
|
|
tpd->bufferRowRatio = (100 * tpd->bufferRows) / tw->term.rows;
|
|
|
|
if (tpd->useHistoryBuffer) {
|
|
/* split up the buffer between the active and history buffers...
|
|
*/
|
|
tpd->historyBufferRows = tpd->bufferRows - tw->term.rows;
|
|
tpd->bufferRows = tw->term.rows;
|
|
}
|
|
|
|
/* allocate the two buffers... */
|
|
tpd->termBuffer = (*(termClassPart->buffer_create_proc))(
|
|
w,
|
|
tpd->bufferRows,
|
|
tw->term.columns,
|
|
termClassPart->sizeOfBuffer,
|
|
termClassPart->sizeOfLine,
|
|
termClassPart->sizeOfEnh);
|
|
if (tpd->useHistoryBuffer) {
|
|
tpd->historyBuffer = (*(termClassPart->buffer_create_proc))(
|
|
w,
|
|
tpd->historyBufferRows,
|
|
tw->term.columns,
|
|
termClassPart->sizeOfBuffer,
|
|
termClassPart->sizeOfLine,
|
|
termClassPart->sizeOfEnh);
|
|
(void) _DtTermPrimBufferSetLinks(tpd->termBuffer,
|
|
tpd->historyBuffer,
|
|
NULL);
|
|
(void) _DtTermPrimBufferSetLinks(tpd->historyBuffer,
|
|
NULL,
|
|
tpd->termBuffer);
|
|
}
|
|
|
|
/* check for error... */
|
|
if (!tpd->termBuffer ||
|
|
(tpd->useHistoryBuffer && !tpd->historyBuffer)) {
|
|
/*DKS: this needs to be cleaned up... */
|
|
(void) fprintf(stderr, "unable to create termBuffer\n");
|
|
(void) exit(1);
|
|
}
|
|
|
|
/* malloc a set of scrollRefreshRows... */
|
|
tpd->scrollRefreshRows = (Boolean *) XtMalloc(tw->term.rows *
|
|
sizeof(Boolean));
|
|
(void) memset(tpd->scrollRefreshRows, '\0', tw->term.rows *
|
|
sizeof(Boolean));
|
|
|
|
/* now that we have a term buffer, we can set up our input selector
|
|
* on our input source (pty or whatever)...
|
|
*/
|
|
(void) _DtTermPrimStartOrStopPtyInput(w);
|
|
/* initialize the insertion point... */
|
|
tpd->cursorColumn = 0;
|
|
tpd->cursorRow = 0;
|
|
tpd->topRow = 0;
|
|
tpd->lastUsedRow = 1;
|
|
tpd->lastUsedHistoryRow = 0;
|
|
}
|
|
|
|
/*
|
|
** Resize (or creation) is complete, now update the relevant
|
|
** information.
|
|
**
|
|
** reset scroll lock...
|
|
*/
|
|
tpd->scrollLockMode = SCROLL_LOCKoff;
|
|
tpd->scrollLockTopRow = 0;
|
|
tpd->scrollLockBottomRow = newRows - 1;
|
|
|
|
/* set the rows and columns for the terminal... */
|
|
if ((tw->term.pty >= 0) && (updateWindowSize)) {
|
|
(void) _DtTermPrimPtySetWindowSize(tw->term.pty,
|
|
newColumns * tw->term.widthInc +
|
|
(2 * (tw->primitive.shadow_thickness +
|
|
tw->primitive.highlight_thickness +
|
|
tw->term.marginWidth)),
|
|
newRows * tw->term.heightInc +
|
|
(2 * (tw->primitive.shadow_thickness +
|
|
tw->primitive.highlight_thickness +
|
|
tw->term.marginHeight)),
|
|
newRows, newColumns);
|
|
}
|
|
|
|
/* reset margins... */
|
|
tpd->leftMargin = 0;
|
|
tpd->rightMargin = newColumns - 1;
|
|
|
|
(void) InitializeVerticalScrollBar(w, False);
|
|
|
|
_DtTermPrimSelectResize(w) ;
|
|
}
|
|
|
|
static void
|
|
Resize(Widget w)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
|
|
if (XtIsRealized(w)) {
|
|
/* the first time through, if our size is changed during interactive
|
|
* placement, we will be called before redisplay and we will be
|
|
* initializing the buffer. If we are sized to our requested size,
|
|
* the resize function will not be called...
|
|
*/
|
|
(void) InitOrResizeTermBuffer(w);
|
|
|
|
}
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static void
|
|
Redisplay(Widget w, XEvent *event, Region region)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
/* if this is the first time we are exposed, and we have never had our
|
|
* size changed (i.e., no Resize() invoked), then we need to initialize
|
|
* a few things, so let's force a resize...
|
|
*/
|
|
if (XtIsRealized(w)) {
|
|
if (!tw->term.tpd->termBuffer) {
|
|
InitOrResizeTermBuffer(w);
|
|
}
|
|
|
|
Debug('e', fprintf(stderr,
|
|
">>Redisplay() expose.x=%d .y=%d .width=%d .height=%d\n",
|
|
event->xexpose.x, event->xexpose.y, event->xexpose.width,
|
|
event->xexpose.height));
|
|
|
|
(void) _DtTermPrimDrawShadow(w);
|
|
|
|
/* expose (refresh) the text... */
|
|
_DtTermPrimCursorOff(w);
|
|
(void) _DtTermPrimExposeText(w, event->xexpose.x, event->xexpose.y,
|
|
event->xexpose.width, event->xexpose.height, True);
|
|
if (event->xexpose.count == 0)
|
|
_DtTermPrimCursorOn(w);
|
|
|
|
/* Envelop our superclass expose method */
|
|
(*(xmPrimitiveClassRec.core_class.expose)) (w, event, region);
|
|
}
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static void
|
|
handleNonMaskableEvents(Widget w, XtPointer eventData, XEvent *event,
|
|
Boolean *cont)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
int fd = tw->term.pty;
|
|
|
|
switch (event->type) {
|
|
case GraphicsExpose:
|
|
/*DKS
|
|
if (!tw->term.jumpScroll && tpd->scroll.nojump.scrollPending) {
|
|
DKS*/
|
|
(void) _DtTermPrimExposeText(w, event->xexpose.x, event->xexpose.y,
|
|
event->xexpose.width, event->xexpose.height, False);
|
|
/*DKS
|
|
}
|
|
DKS*/
|
|
if (event->xgraphicsexpose.count > 0)
|
|
break;
|
|
/* else fall through to noexpose... */
|
|
|
|
case NoExpose:
|
|
/* clear the scroll flag... */
|
|
tpd->scrollInProgress = False;
|
|
|
|
if (tpd->scroll.nojump.pendingScroll) {
|
|
(void) _DtTermPrimScrollComplete(w, False);
|
|
}
|
|
|
|
/* process any pending input... */
|
|
if (TextIsPending(tpd->pendingRead)) {
|
|
(void) readPty((XtPointer) w, &fd, &tpd->ptyInputId);
|
|
}
|
|
|
|
/* reinstall the pty input select... */
|
|
(void) _DtTermPrimStartOrStopPtyInput(w);
|
|
|
|
if ((tpd->scroll.nojump.pendingScroll == 0) &&
|
|
!moreInput(tw->term.pty)) {
|
|
/* turn the cursor back on... */
|
|
(void) _DtTermPrimCursorOn(w);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
handleProcessStructureNotifyEvent(Widget w, XtPointer eventData, XEvent *event,
|
|
Boolean *cont)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) eventData;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
|
|
switch (event->type) {
|
|
case MapNotify:
|
|
tpd->windowMapped = True;
|
|
if (tpd->mapWarningDialog && tpd->warningDialog) {
|
|
(void) XtManageChild(tpd->warningDialog);
|
|
tpd->warningDialogMapped = True;
|
|
tpd->mapWarningDialog = False;
|
|
}
|
|
break;
|
|
|
|
case UnmapNotify:
|
|
tpd->windowMapped = False;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static void
|
|
handlePropertyChangeEvents(Widget w, XtPointer eventData, XEvent *event,
|
|
Boolean *cont)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) eventData;
|
|
static Boolean firstTime = True;
|
|
static Atom xa_WM_STATE = None;
|
|
struct _wmStateStruct {
|
|
CARD32 state;
|
|
Window icon;
|
|
} *prop;
|
|
Atom actualType;
|
|
int actualFormat;
|
|
unsigned long nItems;
|
|
unsigned long bytesAfter;
|
|
|
|
|
|
DebugF('p', 20,
|
|
fprintf(stderr, "handlePropertyChangeEvents() starting\n"));
|
|
/* initialize things... */
|
|
_DtTermProcessLock();
|
|
if (firstTime) {
|
|
xa_WM_STATE = XInternAtom(XtDisplay(w), "WM_STATE", True);
|
|
firstTime = False;
|
|
}
|
|
_DtTermProcessUnlock();
|
|
|
|
DebugF('p', 20,
|
|
fprintf(stderr, "event == %s\n",
|
|
XGetAtomName(((XPropertyEvent *) event)->display,
|
|
((XPropertyEvent *) event)->atom)));
|
|
/* is this a WM_STATE property change?... */
|
|
if (((XPropertyEvent *) event)->atom == xa_WM_STATE) {
|
|
/* if we have not yet initialized the buffer (and started listening
|
|
* to the pty), then let's see if we are iconfied and do so...
|
|
*/
|
|
if (!tw->term.tpd->termBuffer) {
|
|
if (Success == XGetWindowProperty(
|
|
((XPropertyEvent *) event)->display,
|
|
((XPropertyEvent *) event)->window,
|
|
xa_WM_STATE,
|
|
0,
|
|
(sizeof(struct _wmStateStruct) + 3) / 4,
|
|
False,
|
|
AnyPropertyType,
|
|
&actualType,
|
|
&actualFormat,
|
|
&nItems,
|
|
&bytesAfter,
|
|
(unsigned char **) &prop)) {
|
|
if ((int) prop->state == IconicState) {
|
|
DebugF('p', 20,
|
|
fprintf(stderr, "event == IconicState\n"));
|
|
InitOrResizeTermBuffer((Widget) tw);
|
|
}
|
|
(void) XFree(prop);
|
|
}
|
|
}
|
|
}
|
|
DebugF('p', 20,
|
|
fprintf(stderr, "handlePropertyChangeEvents() finished\n"));
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static void
|
|
InvokeTerminationCallback(Widget w, pid_t pid, int *stat_loc)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
DtTermSubprocessTerminationCallbackStruct cb;
|
|
|
|
(void) memset(&cb, '\0', sizeof(cb));
|
|
cb.reason = DtCR_TERM_SUBPROCESS_TERMINATION;
|
|
cb.event = (XEvent *) 0;
|
|
cb.pid = pid;
|
|
cb.status = *stat_loc;
|
|
|
|
if (tw->term.subprocessTerminationCallback) {
|
|
(void) XtCallCallbackList(w,
|
|
tw->term.subprocessTerminationCallback, (XtPointer) &cb);
|
|
}
|
|
}
|
|
|
|
/* SetValues...
|
|
*/
|
|
/*ARGSUSED*/
|
|
static Boolean
|
|
SetValues(Widget cur_w, Widget ref_w, Widget w, ArgList args,
|
|
Cardinal *num_args)
|
|
{
|
|
DtTermPrimitiveWidget cur_tw = (DtTermPrimitiveWidget) cur_w;
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
Boolean flag = False; /* return value... */
|
|
|
|
/* DKS: this needs to be done later...
|
|
*/
|
|
|
|
/* install/remove/modify the subprocess callback process... */
|
|
if (cur_tw->term.subprocessPid != tw->term.subprocessPid) {
|
|
/* if there was an old handler... */
|
|
if (tw->term.subprocessId) {
|
|
/* remove the old handler... */
|
|
(void) _DtTermPrimSubprocRemoveSubproc(w, tw->term.subprocessId);
|
|
tw->term.subprocessId = (_termSubprocId) 0;
|
|
}
|
|
|
|
/* if there is a new handler... */
|
|
if (tw->term.subprocessPid) {
|
|
/* add it old handler... */
|
|
tw->term.subprocessId = _DtTermPrimAddSubproc(w,
|
|
tw->term.subprocessPid, InvokeTerminationCallback, NULL);
|
|
|
|
/* now that we have a handler, we may need to invoke it... */
|
|
if (tw->term.subprocessTerminationCatch) {
|
|
(void) _DtTermPrimSetChildSignalHandler();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (cur_tw->term.jumpScroll != tw->term.jumpScroll) {
|
|
/* we need to sync up the scroll before we make the change... */
|
|
Boolean newJumpScroll = tw->term.jumpScroll;
|
|
|
|
tw->term.jumpScroll = cur_tw->term.jumpScroll;
|
|
(void) _DtTermPrimScrollComplete(w, True);
|
|
tw->term.jumpScroll = newJumpScroll;
|
|
}
|
|
|
|
if (cur_tw->term.verticalScrollBar != tw->term.verticalScrollBar) {
|
|
if (tw->term.verticalScrollBar) {
|
|
/* set up the scrollbar values and callbacks... */
|
|
(void) InitializeVerticalScrollBar(w, True);
|
|
}
|
|
}
|
|
|
|
/* change in rows or columns... */
|
|
if ((cur_tw->term.rows != tw->term.rows) ||
|
|
(cur_tw->term.columns != tw->term.columns)) {
|
|
XtWidgetGeometry request;
|
|
XtWidgetGeometry reply;
|
|
|
|
request.request_mode = (XtGeometryMask) 0;
|
|
|
|
/* handle changes in rows... */
|
|
if (cur_tw->term.rows != tw->term.rows) {
|
|
request.height = tw->term.rows * tw->term.heightInc +
|
|
2 * (tw->primitive.shadow_thickness +
|
|
tw->primitive.highlight_thickness + tw->term.marginWidth);
|
|
request.request_mode |= CWHeight;
|
|
}
|
|
|
|
/* handle changes in columns... */
|
|
if (cur_tw->term.columns != tw->term.columns) {
|
|
request.width = tw->term.columns * tw->term.widthInc +
|
|
2 * (tw->primitive.shadow_thickness +
|
|
tw->primitive.highlight_thickness + tw->term.marginHeight);
|
|
request.request_mode |= CWWidth;
|
|
}
|
|
|
|
/* ignore the return result. The switch statement makes
|
|
* it possible to debug the result...
|
|
*/
|
|
switch(XtMakeGeometryRequest(w, &request, &reply)) {
|
|
case XtGeometryAlmost:
|
|
break;
|
|
|
|
case XtGeometryYes:
|
|
break;
|
|
|
|
case XtGeometryNo:
|
|
break;
|
|
}
|
|
|
|
if (XtIsRealized(w)) {
|
|
/* Let's set the columns and rows back at this point. They will
|
|
* be set for real when and if the XtMakeGeometryRequest is
|
|
* honoured...
|
|
*/
|
|
tw->term.columns = cur_tw->term.columns;
|
|
tw->term.rows = cur_tw->term.rows;
|
|
}
|
|
}
|
|
|
|
if (cur_tw->term.fontList != tw->term.fontList) {
|
|
XtWidgetGeometry request;
|
|
XtWidgetGeometry reply;
|
|
|
|
/* reset the font in the GC's... */
|
|
tw->term.tpd->renderGC.fid = (Font) 0;
|
|
tw->term.tpd->renderReverseGC.fid = (Font) 0;
|
|
tw->term.tpd->clearGC.fid = (Font) 0;
|
|
|
|
/* Our font list changed on us. We need to resize ourself and
|
|
* recompute our width and height increment values...
|
|
*/
|
|
tw->term.tpd->termFont = CreateRenderFont(w, tw->term.fontList,
|
|
&tw->term.fontSet, &tw->term.font);
|
|
|
|
/* look through our XFontSet or XFontStruct and adjust our
|
|
* width and height increments...
|
|
*/
|
|
(void) AdjustWindowUnits(w);
|
|
request.height = tw->term.rows * tw->term.heightInc +
|
|
2 * (tw->primitive.shadow_thickness +
|
|
tw->primitive.highlight_thickness + tw->term.marginWidth);
|
|
request.width = tw->term.columns * tw->term.widthInc +
|
|
2 * (tw->primitive.shadow_thickness +
|
|
tw->primitive.highlight_thickness + tw->term.marginHeight);
|
|
request.request_mode = CWWidth | CWHeight;
|
|
|
|
/* ignore the return result... */
|
|
(void) XtMakeGeometryRequest(w, &request, &reply);
|
|
(void) XmImVaSetValues(w,
|
|
XmNfontList, tw->term.fontList,
|
|
NULL);
|
|
/* clear the cursor position so that we will recalculate the
|
|
* im spotLocation with the new font metrics...
|
|
*/
|
|
tw->term.tpd->IMCursorRow = -1;
|
|
tw->term.tpd->IMCursorColumn = -1;
|
|
}
|
|
|
|
if (cur_tw->term.boldFontList != tw->term.boldFontList) {
|
|
/* Our bold font has been changed... */
|
|
tw->term.tpd->boldTermFont = CreateRenderFont(w, tw->term.boldFontList,
|
|
(XFontSet *) 0, (XFontStruct **) 0);
|
|
}
|
|
|
|
if (cur_tw->term.charCursorStyle != tw->term.charCursorStyle) {
|
|
/* we need to refresh so that we won't get caught in the cursor
|
|
* transition...
|
|
*/
|
|
flag = True;
|
|
}
|
|
|
|
if (cur_tw->term.reverseVideo != tw->term.reverseVideo) {
|
|
/* we need to refresh so that we will turn on or turn off
|
|
* reverse video...
|
|
*/
|
|
flag = True;
|
|
}
|
|
|
|
return(flag);
|
|
}
|
|
|
|
/*
|
|
** Input:
|
|
** oldEnv - pointer to a null terminated list of env strings
|
|
** mergeEnv - pointer to a null terminated list of env strings to merge
|
|
**
|
|
** Return:
|
|
** a pointer to a new list of environment strings
|
|
**
|
|
** It is the calling function's responsibility to free the memory
|
|
** allocated for the new list of strings.
|
|
**
|
|
** If one of the merge environment strings already exists in the old
|
|
** environment, then the new environment string replaces the old string,
|
|
** otherwise it is appended to the new list of strings.
|
|
*/
|
|
static char **
|
|
_mergeEnv
|
|
(
|
|
char **oldEnv,
|
|
char **mergeEnv
|
|
)
|
|
{
|
|
char **newEnv;
|
|
char **ppChar;
|
|
|
|
int i1;
|
|
int numOld;
|
|
int numMerge;
|
|
int numNew;
|
|
int numReplace;
|
|
int *mergeIdx;
|
|
|
|
/*
|
|
** count the number of new environment strings
|
|
*/
|
|
for (numMerge = 0; mergeEnv[numMerge]; numMerge++)
|
|
;
|
|
|
|
/*
|
|
** create and initialize a list of indexs for each of the new strings
|
|
** (assume they will all be appended (idx == -1) and adjust later)...
|
|
*/
|
|
mergeIdx = (int *) XtMalloc(numMerge * sizeof(int));
|
|
for (i1 = 0; i1 < numMerge; i1++)
|
|
{
|
|
mergeIdx[i1] = -1;
|
|
}
|
|
|
|
/*
|
|
** count the number of strings in old environment, and see how many
|
|
** of the merge strings match old strings
|
|
*/
|
|
numReplace = 0;
|
|
for (numOld = 0; oldEnv[numOld]; numOld++)
|
|
{
|
|
/*
|
|
** how many old strings have to be replaced?
|
|
*/
|
|
if (numReplace < numMerge)
|
|
{
|
|
for (i1 = 0; i1 < numMerge; i1++)
|
|
{
|
|
if (mergeIdx[i1] == -1)
|
|
{
|
|
char *idx;
|
|
idx = strchr(mergeEnv[i1], '=');
|
|
|
|
if (strncmp(mergeEnv[i1], oldEnv[numOld],
|
|
idx - mergeEnv[i1] + 1) == 0)
|
|
{
|
|
/*
|
|
** we have a match, remember the index of
|
|
** this string for later...
|
|
*/
|
|
mergeIdx[i1] = numOld;
|
|
numReplace++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
numNew = numOld + numMerge - numReplace;
|
|
|
|
/*
|
|
** make room for the appended strings...
|
|
**
|
|
** NOTE:
|
|
** We use malloc here instead of XtMalloc to keep Sentinel from
|
|
** complaining if putenv reallocs this space. (Sentinel prints a
|
|
** warning if memory allocation functions are not used symmetrically
|
|
** (i.e. memory that is XtMalloc'd should be either XtFree'd or
|
|
** XtRealloc'd, not free'd or realloc'd).)
|
|
*/
|
|
newEnv = (char **) malloc((numNew + 1) * sizeof(char *));
|
|
if (newEnv == NULL)
|
|
{
|
|
printf("L10n MALLOC ERROR\n");
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
** copy the old environment into the new one, and null terminate the
|
|
** newEnv list...
|
|
*/
|
|
memcpy(newEnv, oldEnv, numOld * sizeof(char *));
|
|
newEnv[numNew] = (char *) NULL;
|
|
|
|
/*
|
|
** now merge in the merge strings, the merge string will either replace
|
|
** the existing string (mergeIdx >= 0) or be appended to the list
|
|
** (mergeIdx < 0)
|
|
*/
|
|
ppChar = newEnv + numOld;
|
|
for (i1 = 0; i1 < numMerge; i1++)
|
|
{
|
|
if (mergeIdx[i1] < 0)
|
|
{
|
|
/*
|
|
** append it to the list
|
|
*/
|
|
*ppChar = mergeEnv[i1];
|
|
ppChar++;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
** replace the existing string
|
|
*/
|
|
newEnv[mergeIdx[i1]] = mergeEnv[i1];
|
|
}
|
|
}
|
|
|
|
XtFree((char *)mergeIdx);
|
|
|
|
return(newEnv);
|
|
}
|
|
|
|
/* Realize...
|
|
*/
|
|
static void
|
|
Realize(Widget w, XtValueMask *p_valueMask, XSetWindowAttributes *attributes)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
Mask valueMask = *p_valueMask;
|
|
sigset_t sigNew;
|
|
char buffer[BUFSIZ];
|
|
char **newEnv = (char **) 0;
|
|
char **oldEnv = (char **) 0;
|
|
extern char **environ;
|
|
char *newEnvStrings[4];
|
|
int i1;
|
|
char *ptyMasterName = (char *) 0;
|
|
XPoint imPoint;
|
|
Arg args[20];
|
|
XIMCallback xim_cb[4];
|
|
Cardinal n = 0;
|
|
|
|
Debug('T', timeStamp("TermPrim Realize() starting"));
|
|
|
|
/* adjust rows and columns to the window size...
|
|
*/
|
|
tw->term.columns = ((int)(tw->core.width - (2 * (tw->primitive.shadow_thickness +
|
|
tw->primitive.highlight_thickness + tw->term.marginWidth)))) /
|
|
tw->term.widthInc;
|
|
tw->term.rows = ((int)(tw->core.height - (2 * (tw->primitive.shadow_thickness +
|
|
tw->primitive.highlight_thickness + tw->term.marginHeight)))) /
|
|
tw->term.heightInc;
|
|
|
|
/*
|
|
valueMask |= CWBitGravity | CWDontPropagate;
|
|
attributes->bit_gravity = ForgetGravity;
|
|
attributes->do_not_propagate_mask = ButtonPressMask |
|
|
ButtonReleaseMask | KeyPressMask | KeyReleaseMask |
|
|
PointerMotionMask;
|
|
*/
|
|
(void) XtCreateWindow(w, InputOutput, CopyFromParent, valueMask,
|
|
attributes);
|
|
|
|
/*
|
|
* register input method, and set callbacks for on the spot
|
|
* support.
|
|
*/
|
|
(void) XmImRegister(w, 0);
|
|
imPoint.x = 0;
|
|
imPoint.y = 0;
|
|
|
|
n = 0;
|
|
XtSetArg(args[n], XmNspotLocation, &imPoint); n++;
|
|
XtSetArg(args[n], XmNfontList, tw->term.fontList); n++;
|
|
XtSetArg(args[n], XmNbackground, tw->core.background_pixel); n++;
|
|
XtSetArg(args[n], XmNforeground, tw->primitive.foreground); n++;
|
|
XtSetArg(args[n], XmNbackgroundPixmap, tw->core.background_pixmap); n++;
|
|
XtSetArg(args[n], XmNlineSpace, tw->term.heightInc); n++;
|
|
|
|
/*
|
|
* Register on the spot callbacks.
|
|
*/
|
|
xim_cb[0].client_data = (XPointer)w;
|
|
xim_cb[0].callback = (XIMProc)PreeditStart;
|
|
xim_cb[1].client_data = (XPointer)w;
|
|
xim_cb[1].callback = (XIMProc)PreeditDone;
|
|
xim_cb[2].client_data = (XPointer)tw;
|
|
xim_cb[2].callback = (XIMProc)PreeditDraw;
|
|
xim_cb[3].client_data = (XPointer)w;
|
|
xim_cb[3].callback = (XIMProc)PreeditCaret;
|
|
XtSetArg(args[n], XmNpreeditStartCallback, &xim_cb[0]); n++;
|
|
XtSetArg(args[n], XmNpreeditDoneCallback, &xim_cb[1]); n++;
|
|
XtSetArg(args[n], XmNpreeditDrawCallback, &xim_cb[2]); n++;
|
|
XtSetArg(args[n], XmNpreeditCaretCallback, &xim_cb[3]); n++;
|
|
|
|
XmImSetValues(w, args, n);
|
|
|
|
/* block sigchld while we do this... */
|
|
(void) sigemptyset(&sigNew);
|
|
(void) sigaddset(&sigNew, SIGCHLD);
|
|
(void) sigprocmask(SIG_BLOCK, &sigNew, (sigset_t *) 0);
|
|
|
|
/* get reference terminal modes before we open the pty (so we don't
|
|
* inherit them from the pty), before we fork (so we only do this
|
|
* once for however many instances we create), and before we break
|
|
* our association from our controlling terminal (so we have something
|
|
* to inherit from)...
|
|
*/
|
|
(void) _DtTermPrimPtyGetDefaultModes();
|
|
|
|
/* allocate a pty if appropriate... */
|
|
if (tw->term.ptyAllocate) {
|
|
int mode;
|
|
|
|
/* turn on suid root... */
|
|
_DtTermPrimToggleSuidRoot(True);
|
|
tw->term.pty = _DtTermPrimGetPty(&tw->term.ptySlaveName,
|
|
&ptyMasterName);
|
|
/* turn off suid root... */
|
|
_DtTermPrimToggleSuidRoot(False);
|
|
|
|
if (tw->term.pty < 0) {
|
|
XmeWarning(w, "unable to get pty");
|
|
|
|
/* popup a warning dialog... */
|
|
(void) _DtTermPrimWarningDialog(w, "unable to get pty");
|
|
}
|
|
|
|
/* this is the Spec1170 way to do this. We probably could
|
|
consolidate the various _DtTermPrimGetPtys at this point,
|
|
but that's Truth & Beauty. */
|
|
if (fcntl(tw->term.pty, F_SETFL, O_NONBLOCK |
|
|
fcntl(tw->term.pty, F_GETFL, 0)) == -1)
|
|
{
|
|
XmeWarning(w, "unable to set non-blocking on pty");
|
|
|
|
/* popup a warning dialog... */
|
|
(void) _DtTermPrimWarningDialog(w,
|
|
"unable to set non-blocking on pty");
|
|
}
|
|
|
|
|
|
if (ptyMasterName) {
|
|
(void) free(ptyMasterName);
|
|
}
|
|
}
|
|
|
|
/* set the initial winsize structure before we kick off the
|
|
* subprocess...
|
|
*/
|
|
if (tw->term.pty >= 0) {
|
|
(void) _DtTermPrimPtySetWindowSize(tw->term.pty,
|
|
tw->term.columns * tw->term.widthInc +
|
|
(2 * (tw->primitive.shadow_thickness +
|
|
tw->primitive.highlight_thickness +
|
|
tw->term.marginWidth)),
|
|
tw->term.rows * tw->term.heightInc +
|
|
(2 * (tw->primitive.shadow_thickness +
|
|
tw->primitive.highlight_thickness +
|
|
tw->term.marginHeight)),
|
|
tw->term.rows, tw->term.columns);
|
|
}
|
|
|
|
/* get the utmp line name to use for searching later... */
|
|
if (tw->term.pty >= 0) {
|
|
#ifdef HAS_UTEMPTER_LIBRARY
|
|
utempter_add_record(tw->term.pty, DisplayString(XtDisplay(w)));
|
|
#else
|
|
tw->term.tpd->utmpId = _DtTermPrimUtmpGetUtLine(-1,
|
|
tw->term.ptySlaveName);
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
** If pointerBlank is true, then turn on the pointer with blanking,
|
|
* else turn it on to always stay on.
|
|
*/
|
|
if (tw->term.pointerBlank) {(void) _DtTermPrimPointerOn((Widget)tw); }
|
|
else XDefineCursor(XtDisplay(tw), XtWindow(tw), tw->term.pointerShape);
|
|
_DtTermPrimRecolorPointer((Widget)tw) ;
|
|
|
|
/* kick off a subprocess if appropriate. Don't kick one off if
|
|
* we didn't get a pty...
|
|
*/
|
|
if (tw->term.subprocessExec && (tw->term.pty >= 0)) {
|
|
|
|
/* DKS: maybe we need to start passing the cmd earlier and not
|
|
* fake it here...
|
|
*/
|
|
if (!tw->term.subprocessCmd && tw->term.subprocessArgv) {
|
|
tw->term.subprocessCmd = *tw->term.subprocessArgv;
|
|
}
|
|
|
|
/* modify the environment for our child process...
|
|
*/
|
|
/* set the environment variables for TERM, LINES, COLUMNS... */
|
|
oldEnv = environ;
|
|
|
|
i1 = 0;
|
|
#ifdef SETENV_LINES_AND_COLS
|
|
(void) sprintf(buffer, "LINES=%d", tw->term.rows);
|
|
newEnvStrings[i1] = XtMalloc(strlen(buffer) + 1);
|
|
(void) strcpy(newEnvStrings[i1++], buffer);
|
|
|
|
(void) sprintf(buffer, "COLUMNS=%d", tw->term.columns);
|
|
newEnvStrings[i1] = XtMalloc(strlen(buffer) + 1);
|
|
(void) strcpy(newEnvStrings[i1++], buffer);
|
|
#endif /* SETENV_LINES_AND_COLS */
|
|
|
|
if (tw->term.termName && *tw->term.termName)
|
|
{
|
|
char *fmt = "TERM=%s";
|
|
|
|
newEnvStrings[i1] =
|
|
XtMalloc(strlen(tw->term.termName) + strlen(fmt) + 1);
|
|
(void) sprintf(newEnvStrings[i1], fmt, tw->term.termName);
|
|
i1++;
|
|
}
|
|
/* null term the list of new env strings... */
|
|
newEnvStrings[i1] = (char *) 0;
|
|
|
|
environ = _mergeEnv(oldEnv, newEnvStrings);
|
|
|
|
tw->term.subprocessPid = _DtTermPrimSubprocExec(w,
|
|
tw->term.ptySlaveName,
|
|
tw->term.consoleMode,
|
|
tw->term.subprocessCWD,
|
|
tw->term.subprocessCmd, tw->term.subprocessArgv,
|
|
tw->term.subprocessLoginShell);
|
|
|
|
/* free up the new environ... */
|
|
for (i1 = 0; newEnvStrings[i1]; i1++)
|
|
{
|
|
(void) XtFree(newEnvStrings[i1]);
|
|
}
|
|
|
|
if (environ) {
|
|
/*
|
|
** free environ (rather than XtFree it) is since it was
|
|
** malloc'd (not XtMalloc'd) in _mergeEnv...
|
|
*/
|
|
(void) free((char *) environ);
|
|
}
|
|
environ = oldEnv;
|
|
}
|
|
|
|
/* set up a signal handler if appropriate... */
|
|
if (tw->term.subprocessPid >= 0)
|
|
{
|
|
tw->term.subprocessId = _DtTermPrimAddSubproc(w,
|
|
tw->term.subprocessPid,
|
|
InvokeTerminationCallback, NULL);
|
|
if (tw->term.subprocessTerminationCatch)
|
|
{
|
|
(void)_DtTermPrimSetChildSignalHandler();
|
|
}
|
|
}
|
|
|
|
/* unblock sigchld now that we are done... */
|
|
(void) sigprocmask(SIG_UNBLOCK, &sigNew, (sigset_t *) 0);
|
|
Debug('T', timeStamp("TermPrim Realize() finished"));
|
|
}
|
|
|
|
/* Destroy...
|
|
*/
|
|
static void
|
|
Destroy(Widget w)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
|
|
/* remove our handlers on our shell widget... */
|
|
{
|
|
Widget sw ;
|
|
|
|
for (sw = w; !XtIsShell(sw); sw = XtParent(sw))
|
|
;
|
|
(void) XtRemoveEventHandler(sw, (EventMask) StructureNotifyMask,
|
|
False, handleProcessStructureNotifyEvent, (Opaque) w);
|
|
(void) XtRemoveEventHandler(sw, (EventMask) PropertyChangeMask,
|
|
False, handlePropertyChangeEvents, (Opaque) w);
|
|
}
|
|
|
|
/*
|
|
** Unregister our input method (this fixes CMVC 8146).
|
|
*/
|
|
XmImUnregister(w);
|
|
|
|
/* clean up pty specific stuff...
|
|
*/
|
|
/* remove the pty input handler... */
|
|
if (tw->term.tpd && tw->term.tpd->ptyInputId) {
|
|
(void) XtRemoveInput(tw->term.tpd->ptyInputId);
|
|
tw->term.tpd->ptyInputId = (XtInputId) 0;
|
|
}
|
|
|
|
/* let's be proactive and send a SIGHUP to all the processes in this
|
|
* instances process group. For safety sake, let's not do anything
|
|
* if the process id is not >1 (since use of 1 will send the signal
|
|
* to all processes).
|
|
*/
|
|
/* turn on suid root...
|
|
*/
|
|
_DtTermPrimToggleSuidRoot(True);
|
|
if (tw->term.subprocessPid > 1) {
|
|
(void) kill(-tw->term.subprocessPid, SIGHUP);
|
|
}
|
|
/* turn off suid root...
|
|
*/
|
|
_DtTermPrimToggleSuidRoot(False);
|
|
|
|
/* clean up our utmp entry... */
|
|
#ifdef HAS_UTEMPTER_LIBRARY
|
|
utempter_remove_added_record();
|
|
#else
|
|
if (tw->term.tpd && tw->term.tpd->utmpId && *tw->term.tpd->utmpId) {
|
|
_DtTermPrimUtmpEntryDestroy(w, tw->term.tpd->utmpId);
|
|
(void) XtFree(tw->term.tpd->utmpId);
|
|
tw->term.tpd->utmpId = (char *) 0;
|
|
}
|
|
#endif
|
|
|
|
/* close and release the...
|
|
*/
|
|
if (tw->term.pty >= 0) {
|
|
/* close the pty file descriptor so that:
|
|
* - the child will (passively) get SIGHUP'ed.
|
|
* - the child will get EOF on stdin.
|
|
*/
|
|
(void) close(tw->term.pty);
|
|
/* release the pty (restore owner, group, mode)... */
|
|
if (tw->term.ptySlaveName) {
|
|
(void) _DtTermPrimReleasePty(tw->term.ptySlaveName);
|
|
}
|
|
}
|
|
|
|
/* remove the subproc termination callback... */
|
|
if (tw->term.subprocessId) {
|
|
_DtTermPrimSubprocRemoveSubproc(w, tw->term.subprocessId);
|
|
tw->term.subprocessId = (_termSubprocId) 0;
|
|
}
|
|
|
|
/* free storage for current working directory name*/
|
|
if ( tw->term.subprocessCWD) {
|
|
XtFree(tw->term.subprocessCWD);
|
|
}
|
|
|
|
/* flush the log file */
|
|
if (tw->term.logging ) {
|
|
_DtTermPrimCloseLog((Widget) tw);
|
|
}
|
|
|
|
if (tw->term.boldFont) {
|
|
(void) XFreeFont(XtDisplay(w), tw->term.boldFont);
|
|
}
|
|
if (tw->term.boldFontSet) {
|
|
(void) XFreeFontSet(XtDisplay(w), tw->term.boldFontSet);
|
|
}
|
|
|
|
/* remove the termData structure contents, followed by the structure...
|
|
*/
|
|
if (tw->term.tpd) {
|
|
/* remove the cursor timeout... */
|
|
if (tw->term.tpd->cursorTimeoutId) {
|
|
(void) XtRemoveTimeOut(tw->term.tpd->cursorTimeoutId);
|
|
tw->term.tpd->cursorTimeoutId = (XtIntervalId) 0;
|
|
}
|
|
|
|
/* free up all our GC's...
|
|
*/
|
|
/* render GC... */
|
|
if (tw->term.tpd->renderGC.gc) {
|
|
(void) XFreeGC(XtDisplay(w), tw->term.tpd->renderGC.gc);
|
|
tw->term.tpd->renderGC.gc = (GC) 0;
|
|
}
|
|
if (tw->term.tpd->renderReverseGC.gc) {
|
|
(void) XFreeGC(XtDisplay(w), tw->term.tpd->renderReverseGC.gc);
|
|
tw->term.tpd->renderReverseGC.gc = (GC) 0;
|
|
}
|
|
/* clear GC... */
|
|
if (tw->term.tpd->clearGC.gc) {
|
|
(void) XFreeGC(XtDisplay(w), tw->term.tpd->clearGC.gc);
|
|
tw->term.tpd->clearGC.gc = (GC) 0;
|
|
}
|
|
/* cursor GC... */
|
|
if (tw->term.tpd->cursorGC.gc) {
|
|
(void) XFreeGC(XtDisplay(w), tw->term.tpd->cursorGC.gc);
|
|
tw->term.tpd->cursorGC.gc = (GC) 0;
|
|
}
|
|
|
|
/* free up our buffers... */
|
|
if (tw->term.tpd->historyBuffer) {
|
|
_DtTermPrimBufferFreeBuffer(tw->term.tpd->historyBuffer);
|
|
tw->term.tpd->historyBuffer = NULL;
|
|
}
|
|
|
|
if (tw->term.tpd->termBuffer) {
|
|
_DtTermPrimBufferFreeBuffer(tw->term.tpd->termBuffer);
|
|
tw->term.tpd->termBuffer = NULL;
|
|
}
|
|
|
|
/* free up the scrollRefreshRows... */
|
|
if (tw->term.tpd->scrollRefreshRows) {
|
|
(void) XtFree((char *) tw->term.tpd->scrollRefreshRows);
|
|
tw->term.tpd->scrollRefreshRows = (Boolean *) 0;
|
|
}
|
|
|
|
/* free up the selection information */
|
|
if (tw->term.tpd->selectInfo) {
|
|
(void) _DtTermPrimSelectDestroy(w, tw->term.tpd->selectInfo);
|
|
tw->term.tpd->selectInfo = (TermSelectInfo) 0;
|
|
}
|
|
|
|
/* free up pending text... */
|
|
if (tw->term.tpd->pendingRead) {
|
|
(void) _DtTermPrimPendingTextDestroy(tw->term.tpd->pendingRead);
|
|
tw->term.tpd->pendingRead = (PendingText) 0;
|
|
}
|
|
if (tw->term.tpd->pendingWrite) {
|
|
(void) _DtTermPrimPendingTextDestroy(tw->term.tpd->pendingWrite);
|
|
tw->term.tpd->pendingWrite = (PendingText) 0;
|
|
}
|
|
|
|
if (tw->term.tpd->capsLockKeyCodes)
|
|
(void) XtFree((char *)tw->term.tpd->capsLockKeyCodes) ;
|
|
|
|
(void) _DtTermPrimDestroyFont(w,tw->term.tpd->boldTermFont) ;
|
|
(void) _DtTermPrimDestroyFont(w,tw->term.tpd->termFont) ;
|
|
|
|
if (tw->term.ptyAllocate && tw->term.ptySlaveName)
|
|
(void) XtFree((char *)tw->term.ptySlaveName);
|
|
|
|
|
|
if (tw->term.tpd->context)
|
|
(void) XtFree((char *)tw->term.tpd->context);
|
|
|
|
/* free up the termData structure... */
|
|
(void) XtFree((char *) tw->term.tpd);
|
|
tw->term.tpd = (DtTermPrimData) 0;
|
|
|
|
}
|
|
}
|
|
|
|
/* _DtTermPrimActionEnter...
|
|
*/
|
|
void
|
|
_DtTermPrimActionEnter(Widget w, XEvent *event,
|
|
String *params, Cardinal *num_params)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
|
|
Debug('F', fprintf(stderr, ">>enterEvent starting\n"));
|
|
#ifdef NOTDEF
|
|
Debug('F', fprintf(stderr,
|
|
">> widget: name=\"%s\" widget=0x%lx window=0x%lx\n",
|
|
tw->core.name, tw, XtWindow(w)));
|
|
Debug('F', fprintf(stderr,
|
|
">> event: window=0x%lx\n mode=%d detail=%d\n",
|
|
event->xcrossing.window, event->xcrossing.mode,
|
|
event->xcrossing.detail));
|
|
#endif /* NOTDEF */
|
|
Debug('F', _DtTermPrimDebugDumpEvent(stderr, w, event));
|
|
|
|
if ((_XmGetFocusPolicy(w) != XmEXPLICIT) &&
|
|
!(tw->term.hasFocus) &&
|
|
event->xcrossing.focus &&
|
|
(event->xcrossing.detail != NotifyInferior)) {
|
|
tw->term.hasFocus = True;
|
|
_DtTermPrimCursorChangeFocus(w);
|
|
}
|
|
|
|
if ( tw->term.pointerBlank )
|
|
_DtTermPrimPointerFreeze((Widget)tw, False);
|
|
|
|
/* update the caps lock flag... */
|
|
(void) CapsLockUpdate(w,
|
|
(event->xcrossing.state & LockMask) != 0);
|
|
|
|
_XmPrimitiveEnter(w, event, params, num_params);
|
|
}
|
|
|
|
|
|
/* _DtTermPrimActionLeave...
|
|
*/
|
|
void
|
|
_DtTermPrimActionLeave(Widget w, XEvent *event,
|
|
String *params, Cardinal *num_params)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
|
|
Debug('F', fprintf(stderr, ">>leaveEvent starting\n"));
|
|
#ifdef NOTDEF
|
|
Debug('F', fprintf(stderr,
|
|
">> widget: name=\"%s\" widget=0x%lx window=0x%lx\n",
|
|
tw->core.name, tw, XtWindow(w)));
|
|
Debug('F', fprintf(stderr,
|
|
">> event: window=0x%lx\n mode=%d detail=%d\n",
|
|
event->xcrossing.window, event->xcrossing.mode,
|
|
event->xcrossing.detail));
|
|
#endif /* NOTDEF */
|
|
Debug('F', _DtTermPrimDebugDumpEvent(stderr, w, event));
|
|
|
|
if ((_XmGetFocusPolicy(w) != XmEXPLICIT) &&
|
|
tw->term.hasFocus &&
|
|
event->xcrossing.focus &&
|
|
(event->xcrossing.detail != NotifyInferior)) {
|
|
tw->term.hasFocus = False;
|
|
_DtTermPrimCursorChangeFocus(w);
|
|
}
|
|
|
|
if ( tw->term.pointerBlank )
|
|
_DtTermPrimPointerFreeze((Widget)tw, True);
|
|
|
|
/* update the caps lock flag... */
|
|
(void) CapsLockUpdate(w,
|
|
(event->xcrossing.state & LockMask) != 0);
|
|
|
|
_XmPrimitiveLeave(w, event, params, num_params);
|
|
}
|
|
|
|
static Boolean
|
|
moreInput(int pty)
|
|
{
|
|
fd_set readFD;
|
|
struct timeval timeout;
|
|
|
|
/* do a non-blocking select to see if we have any more input. If so,
|
|
* we don't need to turn the cursor back on.
|
|
*/
|
|
FD_ZERO(&readFD);
|
|
FD_SET(pty, &readFD);
|
|
timeout.tv_sec = 0;
|
|
timeout.tv_usec = 0;
|
|
if (!((select(pty + 1, &readFD, 0, 0, &timeout) > 0) &&
|
|
(FD_ISSET(pty, &readFD))))
|
|
return(False);
|
|
return(True);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static void
|
|
readPty(XtPointer client_data, int *source, XtInputId *id)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) client_data;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
unsigned char buffer[BUFSIZ];
|
|
int len;
|
|
unsigned char *dangleBuffer;
|
|
int dangleBufferLen;
|
|
int retLen;
|
|
PendingTextChunk chunk = (PendingTextChunk) 0;
|
|
|
|
Debug('i', fprintf(stderr, ">>readPty() starting\n"));
|
|
tpd->readInProgress = True;
|
|
(void) _DtTermPrimCursorOff((Widget) tw);
|
|
/* if we are using a history buffer and have scrolled into it, we
|
|
* need to snap back down before we do anything...
|
|
*/
|
|
if (tpd->useHistoryBuffer && (tpd->topRow < 0)) {
|
|
(void) _DtTermPrimScrollTextTo((Widget) tw, 0);
|
|
(void) _DtTermPrimScrollComplete((Widget) tw, True);
|
|
}
|
|
|
|
if (TextIsPending(tpd->pendingRead)) {
|
|
/* take text from the pendingRead buffer instead of doing a read...
|
|
*/
|
|
chunk = _DtTermPrimPendingTextGetChunk(tpd->pendingRead);
|
|
len = chunk->len;
|
|
(void) memcpy(buffer, chunk->bufPtr, len);
|
|
} else {
|
|
len = read(*source, buffer, sizeof(buffer));
|
|
Debug('i', fprintf(stderr, ">>readPty() read len=%d\n", len));
|
|
if (isDebugFSet('i', 1)) {
|
|
#ifdef BBA
|
|
#pragma BBA_IGNORE
|
|
#endif /*BBA*/
|
|
int i1;
|
|
|
|
(void) fprintf(stderr,
|
|
">>readPty() read %d bytes", len);
|
|
if (len > 0) {
|
|
for (i1 = 0; i1 < len; i1++) {
|
|
if (!(i1 % 20))
|
|
fputs("\n ", stderr);
|
|
(void) fprintf(stderr, " %02x", buffer[i1]);
|
|
}
|
|
(void) fprintf(stderr, "\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
if (len > 0) {
|
|
if (!tpd->windowMapped && tw->term.mapOnOutput) {
|
|
/*
|
|
** map window unless it is too early...
|
|
*/
|
|
if (tw->term.mapOnOutputDelay)
|
|
if ((time((time_t *) 0) - tpd->creationTime) >
|
|
tw->term.mapOnOutputDelay) {
|
|
/*
|
|
** time is up
|
|
*/
|
|
tw->term.mapOnOutputDelay = 0 ;
|
|
}
|
|
|
|
if (!tw->term.mapOnOutputDelay) {
|
|
Widget sw;
|
|
|
|
for (sw = (Widget)tw; !XtIsShell(sw); sw = XtParent(sw))
|
|
;
|
|
XtMapWidget(sw);
|
|
}
|
|
}
|
|
|
|
if (tw->term.log_on) {
|
|
_DtTermPrimWriteLog(tw, buffer, len) ;
|
|
}
|
|
|
|
if (tw->term.outputLogCallback) {
|
|
DtTermOutputLogCallbackStruct cb;
|
|
|
|
cb.reason = DtCR_TERM_OUTPUT_LOG;
|
|
cb.event = (XEvent *) 0;
|
|
cb.text = buffer;
|
|
cb.length = len;
|
|
|
|
(void) XtCallCallbackList((Widget) tw,
|
|
tw->term.outputLogCallback, &cb);
|
|
}
|
|
|
|
if (!_DtTermPrimParseInput((Widget) tw, buffer, len,
|
|
&dangleBuffer, &dangleBufferLen)) {
|
|
/* we were not able to write out everything and
|
|
* we need to stuff away the pending text...
|
|
*/
|
|
if (chunk) {
|
|
/* we didn't finish up the pending text chunk we were
|
|
* working on, so update the pointers and continue...
|
|
*/
|
|
(void) _DtTermPrimPendingTextReplace(chunk, dangleBuffer,
|
|
dangleBufferLen);
|
|
} else {
|
|
(void) _DtTermPrimPendingTextAppend(tpd->pendingRead,
|
|
dangleBuffer, dangleBufferLen);
|
|
}
|
|
(void) XtFree((char *) dangleBuffer);
|
|
} else if (chunk) {
|
|
/* we finished a pending chunk, so let's move on... */
|
|
_DtTermPrimPendingTextRemoveChunk(tpd->pendingRead, chunk);
|
|
}
|
|
if (!tpd->ptyInputId) {
|
|
/* we need to wait until we get a graphicsexpose (count==0)
|
|
* or a noexpose...
|
|
*/
|
|
/* we know we have more input, so we don't need to turn on
|
|
* the cursor...
|
|
*/
|
|
tpd->readInProgress = False;
|
|
Debug('i', fprintf(stderr, ">>readPty() finished\n"));
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!moreInput(tw->term.pty)) {
|
|
/* we won't be getting an input select so we need to check on
|
|
* pending text and force a read if we still have some...
|
|
*/
|
|
if (TextIsPending(tpd->pendingRead)) {
|
|
(void) XtAppAddTimeOut(XtWidgetToApplicationContext((Widget) tw),
|
|
0, _DtTermPrimForcePtyRead, (XtPointer) tw);
|
|
} else {
|
|
/* turn the cursor back on... */
|
|
(void) _DtTermPrimCursorOn((Widget) tw);
|
|
}
|
|
}
|
|
tpd->readInProgress = False;
|
|
Debug('i', fprintf(stderr, ">>readPty() finished\n"));
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
_DtTermPrimForcePtyRead(XtPointer client_data, XtIntervalId *id)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) client_data;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
int fd = tw->term.pty;
|
|
|
|
(void) _DtTermPrimStartOrStopPtyInput((Widget) tw);
|
|
|
|
if (TextIsPending(tpd->pendingRead)) {
|
|
(void) readPty(client_data, &fd, &tpd->ptyInputId);
|
|
}
|
|
}
|
|
|
|
void
|
|
_DtTermPrimLoopBackData(Widget w, char *data, int dataLength)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
int fd = tw->term.pty;
|
|
|
|
/* queue up the pending text... */
|
|
(void) _DtTermPrimPendingTextAppend(tpd->pendingRead, (unsigned char *) data,
|
|
dataLength);
|
|
|
|
/* if we have a read in process, we can return now... */
|
|
if (tpd->readInProgress) {
|
|
return;
|
|
}
|
|
|
|
/* if we are set up to select on pty input, then we can force a read
|
|
* now...
|
|
*/
|
|
if (tpd->ptyInputId) {
|
|
(void) readPty((XtPointer) w, &fd, &tpd->ptyInputId);
|
|
}
|
|
|
|
/* if not, we will force a read when we turn select on input back
|
|
* on...
|
|
*/
|
|
}
|
|
|
|
void
|
|
DtTermDisplaySend
|
|
(
|
|
Widget w,
|
|
unsigned char *buffer,
|
|
int length
|
|
)
|
|
{
|
|
_DtTermWidgetToAppContext(w);
|
|
|
|
/* for now, it looks like _DtTermPrimLoopBackData will take care
|
|
* of everything for us...
|
|
*/
|
|
_DtTermAppLock(app);
|
|
(void) _DtTermPrimLoopBackData(w, (char *) buffer, length);
|
|
_DtTermAppUnlock(app);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static void
|
|
writePty(XtPointer client_data, int *source, XtInputId *id)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) client_data;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
|
|
Debug('o', fprintf(stderr, ">>writePty() starting\n"));
|
|
|
|
/*
|
|
** write some text from list of pending text chunks
|
|
*/
|
|
_DtTermPrimPendingTextWrite(tpd->pendingWrite, tw->term.pty);
|
|
|
|
/*
|
|
** turn off the write select as appropriate
|
|
*/
|
|
_DtTermPrimStartOrStopPtyOutput((Widget)client_data);
|
|
Debug('o', fprintf(stderr, ">>writePty() finished\n"));
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
_DtTermPrimActionKeyRelease(Widget w, XEvent *event, String *params,
|
|
Cardinal *num_params)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
XKeyEvent *keyEvent = (XKeyEvent *) event;
|
|
int i;
|
|
|
|
Debug('i', fprintf(stderr, ">>_DtTermPrimActionKeyRelease() starting\n"));
|
|
if (keyEvent->type != KeyRelease) {
|
|
(void) fprintf(stderr,
|
|
"_DtTermPrimActionKeyRelease: incorrect event type %d\n",
|
|
keyEvent->type);
|
|
return;
|
|
}
|
|
|
|
/* check for caps lock... */
|
|
for (i = 0; i < tpd->numCapsLockKeyCodes; i++) {
|
|
if (tpd->capsLockKeyCodes[i] == keyEvent->keycode) {
|
|
/* caps lock has toggled... */
|
|
(void) CapsLockUpdate(w, !tpd->capsLock);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
_DtTermPrimActionKeyInput(Widget w, XEvent *event, String *params,
|
|
Cardinal *num_params)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
XKeyEvent *keyEvent = (XKeyEvent *) event;
|
|
KeySym keysym;
|
|
Status status;
|
|
unsigned char string[BUFSIZ];
|
|
int nbytes;
|
|
int i;
|
|
Boolean synEscape = False; /* synthesize escape key from meta key */
|
|
/* -kshMode */
|
|
|
|
Debug('i', fprintf(stderr, ">>_DtTermPrimActionKeyInput() starting\n"));
|
|
if (keyEvent->type != KeyPress) {
|
|
(void) fprintf(stderr, "_DtTermPrimActionKeyInput: incorrect event type %d\n",
|
|
keyEvent->type);
|
|
return;
|
|
}
|
|
if (KEYBOARD_LOCKED(tpd->keyboardLocked)) {
|
|
/* keyboard locked -- ring the bell...
|
|
*/
|
|
(void) _DtTermPrimBell(w);
|
|
return;
|
|
}
|
|
|
|
if (tw->term.kshMode &&
|
|
((keyEvent->state & tpd->metaMask) == tpd->metaMask)) {
|
|
keyEvent->state &= ~tpd->metaMask;
|
|
synEscape = True ;
|
|
}
|
|
|
|
/* check for caps lock... */
|
|
for (i = 0; i < tpd->numCapsLockKeyCodes; i++) {
|
|
if (tpd->capsLockKeyCodes[i] == keyEvent->keycode) {
|
|
/* caps lock has toggled... */
|
|
(void) CapsLockUpdate(w, !tpd->capsLock);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* I've pulled the following from hpterm2.0's input.c. I don't
|
|
* understand any of it, and we need to get some documentation on
|
|
* it.
|
|
*/
|
|
|
|
nbytes = XmImMbLookupString(w, keyEvent, (char *) string, sizeof(string),
|
|
&keysym, &status);
|
|
if (XBufferOverflow == status) {
|
|
nbytes = 0;
|
|
}
|
|
|
|
#ifdef XOR_CAPS_LOCK
|
|
/* if lock and shift are both pressed, let's invert the case of all
|
|
* upper and lower case characters...
|
|
*/
|
|
if ((keyEvent->state & (LockMask | ShiftMask)) == (LockMask | ShiftMask)) {
|
|
for (i = 0; i < nbytes; i++) {
|
|
if (isupper(string[i])) {
|
|
string[i] = _tolower(string[i]);
|
|
} else if (islower(string[i])) {
|
|
string[i] = _toupper(string[i]);
|
|
}
|
|
}
|
|
}
|
|
#endif /* XOR_CAPS_LOCK */
|
|
|
|
|
|
if ((nbytes > 0) && (tw->term.inputVerifyCallback)) {
|
|
DtTermInputVerifyCallbackStruct cb;
|
|
|
|
cb.reason = DtCR_TERM_INPUT_VERIFY;
|
|
cb.event = event;
|
|
cb.doit = True;
|
|
cb.text = string;
|
|
cb.length = nbytes;
|
|
|
|
/* invoke the callbacks... */
|
|
(void) XtCallCallbackList(w, tw->term.inputVerifyCallback, &cb);
|
|
|
|
/* if doit was turned off, forget about the string... */
|
|
if (!cb.doit) {
|
|
nbytes = 0;
|
|
}
|
|
}
|
|
|
|
if (nbytes > 0) {
|
|
unsigned char *start;
|
|
unsigned char *end;
|
|
|
|
/* perform margin bell functionality if necessary... */
|
|
if (tw->term.marginBell &&
|
|
((tw->term.columns - tw->term.nMarginBell) ==
|
|
tpd->cursorColumn)) {
|
|
_DtTermPrimBell(w);
|
|
}
|
|
|
|
/* synthesize escape unless it was CR or Vertical Tab */
|
|
if (synEscape && *string != '\r' && *string != 0x0B)
|
|
(void) _DtTermPrimSendInput(w, (unsigned char *) "\033", 1);
|
|
|
|
/* for pointer blanking */
|
|
if (tw->term.pointerBlank && *string != '\r' && *string != 0x0B)
|
|
_DtTermPrimPointerOff((Widget)tw,(XtIntervalId *)NULL) ;
|
|
|
|
for (end = string; nbytes > 0; ) {
|
|
for (start = end; (nbytes > 0) && (*end != '\r'); nbytes--, end++)
|
|
;
|
|
if ((nbytes > 0) && (*end == '\r')) {
|
|
(void) end++;
|
|
(void) nbytes--;
|
|
}
|
|
(void) _DtTermPrimSendInput(w, start, end - start);
|
|
if (tpd->autoLineFeed && (end[-1] == '\r')) {
|
|
(void) _DtTermPrimSendInput(w, (unsigned char *) "\n", 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
Debug('i', fprintf(stderr, ">>_DtTermPrimActionKeyInput() finished\n"));
|
|
}
|
|
|
|
void
|
|
_DtTermPrimSendInput
|
|
(
|
|
Widget w,
|
|
unsigned char *buffer,
|
|
int length
|
|
)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
|
|
if (length > 0) {
|
|
(void) _DtTermPrimPendingTextAppend(tpd->pendingWrite, buffer, length);
|
|
(void) _DtTermPrimStartOrStopPtyOutput(w);
|
|
|
|
if (tpd->halfDuplex) {
|
|
DtTermDisplaySend(w, buffer, length);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
DtTermSubprocSend
|
|
(
|
|
Widget w,
|
|
unsigned char *buffer,
|
|
int length
|
|
)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
_DtTermWidgetToAppContext(w);
|
|
|
|
/* queue up all text send from outside the widget... */
|
|
_DtTermAppLock(app);
|
|
if (length > 0) {
|
|
(void) _DtTermPrimPendingTextAppend(tpd->pendingWrite, buffer, length);
|
|
(void) _DtTermPrimStartOrStopPtyOutput(w);
|
|
if (tpd->halfDuplex) {
|
|
DtTermDisplaySend(w, buffer, length);
|
|
}
|
|
}
|
|
_DtTermAppUnlock(app);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
_DtTermPrimActionFocusIn(Widget w, XEvent *event, String *params,
|
|
Cardinal *num_params)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
|
|
Debug('F', fprintf(stderr, ">>focusIn starting\n"));
|
|
#ifdef NOTDEF
|
|
Debug('F', fprintf(stderr,
|
|
">> widget: name=\"%s\" widget=0x%lx window=0x%lx\n",
|
|
tw->core.name, tw, XtWindow(w)));
|
|
Debug('F', fprintf(stderr,
|
|
">> event: window=0x%lx\n mode=%d detail=%d\n",
|
|
event->xfocus.window, event->xfocus.mode, event->xfocus.detail));
|
|
#endif /* NOTDEF */
|
|
Debug('F', _DtTermPrimDebugDumpEvent(stderr, w, event));
|
|
|
|
if (
|
|
#ifdef MOTIF_TEXT_BUG
|
|
event->xfocus.send_event &&
|
|
#endif /* MOTIF_TEXT_BUG */
|
|
!(tw->term.hasFocus)) {
|
|
tw->term.hasFocus = True;
|
|
_DtTermPrimCursorChangeFocus(w);
|
|
if (_XmGetFocusPolicy(w) == XmEXPLICIT) {
|
|
if (((XmPrimitiveWidgetClass) XtClass(w))
|
|
->primitive_class.border_highlight) {
|
|
(void) (*((XmPrimitiveWidgetClass) XtClass(w))
|
|
->primitive_class.border_highlight)(w);
|
|
}
|
|
}
|
|
}
|
|
(void) _XmPrimitiveFocusIn(w, event, params, num_params);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
_DtTermPrimActionFocusOut(Widget w, XEvent *event, String *params,
|
|
Cardinal *num_params)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
|
|
Debug('F', fprintf(stderr, ">>focusOut starting\n"));
|
|
#ifdef NOTDEF
|
|
Debug('F', fprintf(stderr,
|
|
">> widget: name=\"%s\" widget=0x%lx window=0x%lx\n",
|
|
tw->core.name, tw, XtWindow(w)));
|
|
Debug('F', fprintf(stderr,
|
|
">> event: window=0x%lx\n mode=%d detail=%d\n",
|
|
event->xfocus.window, event->xfocus.mode, event->xfocus.detail));
|
|
#endif /* NOTDEF */
|
|
Debug('F', _DtTermPrimDebugDumpEvent(stderr, w, event));
|
|
|
|
if (
|
|
#ifdef MOTIF_TEXT_BUG
|
|
event->xfocus.send_event &&
|
|
#endif /* MOTIF_TEXT_BUG */
|
|
tw->term.hasFocus) {
|
|
tw->term.hasFocus = False;
|
|
_DtTermPrimCursorChangeFocus(w);
|
|
if (_XmGetFocusPolicy(w) == XmEXPLICIT) {
|
|
if (((XmPrimitiveWidgetClass) XtClass(w))
|
|
->primitive_class.border_unhighlight) {
|
|
(void) (*((XmPrimitiveWidgetClass) XtClass(w))
|
|
->primitive_class.border_unhighlight)(w);
|
|
}
|
|
}
|
|
}
|
|
(void) _XmPrimitiveFocusOut(w, event, params, num_params);
|
|
}
|
|
|
|
static void
|
|
KeyTranslator
|
|
(
|
|
Display *display,
|
|
KeyCode keyCode,
|
|
Modifiers modifiers,
|
|
Modifiers *modifiersReturn,
|
|
KeySym *keysymReturn
|
|
)
|
|
{
|
|
/* call the Xt translator to translate this event... */
|
|
(void) XtTranslateKey(display, keyCode, modifiers, modifiersReturn,
|
|
keysymReturn);
|
|
/* and reinstall the Motif translator for the next widget/event... */
|
|
(void) XtSetKeyTranslator(display, (XtKeyProc) XmTranslateKey);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static void
|
|
handleKeyEvents(Widget w, XtPointer closure, XEvent *event, Boolean *cont)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
|
|
/* drop synthetic events... */
|
|
if (!tw->term.allowSendEvents && event->xany.send_event) {
|
|
*cont = False;
|
|
return;
|
|
}
|
|
|
|
#ifdef KEY_TRANSLATE_HACK
|
|
/* install our key translator... */
|
|
(void) XtSetKeyTranslator(XtDisplay(w), (XtKeyProc) KeyTranslator);
|
|
#endif /* KEY_TRANSLATE_HACK */
|
|
/* and return... */
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static void
|
|
handleButtonEvents(Widget w, XtPointer closure, XEvent *event, Boolean *cont)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
|
|
/* drop synthetic events... */
|
|
if (!tw->term.allowSendEvents && event->xany.send_event) {
|
|
*cont = False;
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void
|
|
CapsLockUpdate(Widget w, Boolean capsLock)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
|
|
if (tpd->capsLock != capsLock) {
|
|
tpd->capsLock = capsLock;
|
|
|
|
/* invoke the caps lock callback... */
|
|
if (tw->term.statusChangeCallback) {
|
|
_DtTermPrimInvokeStatusChangeCallback(w);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
_DtTermPrimInsertCharUpdate(Widget w, DtTermInsertCharMode insertCharMode)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
|
|
if (tpd->insertCharMode != insertCharMode) {
|
|
tpd->insertCharMode = insertCharMode;
|
|
|
|
/* invoke the caps lock callback... */
|
|
if (tw->term.statusChangeCallback) {
|
|
_DtTermPrimInvokeStatusChangeCallback(w);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
_DtTermPrimActionStop(Widget w, XEvent *event, String *params, Cardinal *num_params)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
|
|
if (*num_params > 0) {
|
|
if (!strcmp(params[0], "on")) {
|
|
tpd->outputStopped = False;
|
|
} else if (!strcmp(params[0], "off")) {
|
|
tpd->outputStopped = True;
|
|
} else {
|
|
/* toggle the output... */
|
|
tpd->outputStopped = !tpd->outputStopped;
|
|
}
|
|
} else {
|
|
/* toggle the output... */
|
|
tpd->outputStopped = !tpd->outputStopped;
|
|
}
|
|
|
|
(void) _DtTermPrimStartOrStopPtyInput(w);
|
|
|
|
/* invoke the status update callback... */
|
|
if (tw->term.statusChangeCallback) {
|
|
_DtTermPrimInvokeStatusChangeCallback(w);
|
|
}
|
|
}
|
|
|
|
void
|
|
_DtTermPrimInvokeStatusChangeCallback
|
|
(
|
|
Widget w
|
|
)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
DtTermStatusChangeCallbackStruct
|
|
cb;
|
|
|
|
/* exit now if we don't need to do anything... */
|
|
if (!tw->term.statusChangeCallback)
|
|
return;
|
|
|
|
(void) memset(&cb, '\0', sizeof(cb));
|
|
cb.reason = DtCR_TERM_STATUS_CHANGE;
|
|
cb.event = (XEvent *) 0;
|
|
cb.cursorX = tpd->cursorColumn + 1;
|
|
cb.cursorY = tpd->topRow + tpd->cursorRow + 1;
|
|
cb.capsLock = tpd->capsLock;
|
|
cb.stop = tpd->outputStopped;
|
|
cb.insertCharMode = tpd->insertCharMode;
|
|
cb.locked = tpd->keyboardLocked.escape;
|
|
|
|
/* invoke them... */
|
|
(void) XtCallCallbackList(w, tw->term.statusChangeCallback,
|
|
(XtPointer) &cb);
|
|
}
|
|
|
|
void
|
|
_DtTermPrimDrawShadow(Widget w)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
|
|
if (XtIsRealized(w)) {
|
|
XmeDrawShadows(XtDisplay(w), XtWindow(w),
|
|
tw->primitive.top_shadow_GC,
|
|
tw->primitive.bottom_shadow_GC,
|
|
tw->primitive.highlight_thickness,
|
|
tw->primitive.highlight_thickness,
|
|
tw->core.width - 2 * tw->primitive.highlight_thickness,
|
|
tw->core.height - 2 * tw->primitive.highlight_thickness,
|
|
tw->primitive.shadow_thickness,
|
|
tw->term.shadowType);
|
|
}
|
|
}
|
|
|
|
Widget
|
|
DtCreateTermPrimitive(Widget parent, char *name, ArgList arglist,
|
|
Cardinal argcount)
|
|
{
|
|
Widget w;
|
|
_DtTermWidgetToAppContext(parent);
|
|
|
|
_DtTermAppLock(app);
|
|
Debug('T', timeStamp("DtCreateTermPrimitive() starting"));
|
|
w = XtCreateWidget(name, dtTermPrimitiveWidgetClass, parent, arglist,
|
|
argcount);
|
|
Debug('T', timeStamp("DtCreateTermPrimitive() finished"));
|
|
_DtTermAppUnlock(app);
|
|
return(w);
|
|
}
|
|
|
|
void
|
|
_DtTermPrimStartOrStopPtyInput(Widget w)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
Boolean inputOn = True;
|
|
|
|
/* This function will either turn on or turn off the pty input selector
|
|
* depending on the status of:
|
|
*
|
|
* - the outputStopped flag,
|
|
* - any pending scrolling operations.
|
|
*/
|
|
|
|
Debug('o', fprintf(stderr, ">>_StartOrStopPtyInput() starting\n"));
|
|
/* turn off input if there is a non-jump scroll pending... */
|
|
if (!tw->term.jumpScroll && tpd->scroll.nojump.pendingScroll)
|
|
inputOn = False;
|
|
|
|
/* turn off input if we are stopped or paused... */
|
|
if (tpd->outputStopped || tpd->oneSecondPause)
|
|
inputOn = False;
|
|
|
|
if (inputOn && !tpd->ptyInputId && (tw->term.pty >= 0)) {
|
|
/* turn it on... */
|
|
tpd->ptyInputId =
|
|
XtAppAddInput(XtWidgetToApplicationContext((Widget) tw),
|
|
tw->term.pty, (XtPointer) XtInputReadMask, readPty,
|
|
(Widget) tw);
|
|
Debug('o', fprintf(stderr, " adding pty read select\n"));
|
|
} else if (!inputOn && tpd->ptyInputId) {
|
|
/* turn it off... */
|
|
(void) XtRemoveInput(tw->term.tpd->ptyInputId);
|
|
tw->term.tpd->ptyInputId = (XtInputId) 0;
|
|
Debug('o', fprintf(stderr, " removing pty read select\n"));
|
|
}
|
|
Debug('o', fprintf(stderr, ">>_StartOrStopPtyInput() finished\n"));
|
|
}
|
|
|
|
void
|
|
_DtTermPrimStartOrStopPtyOutput(Widget w)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
|
|
Debug('o', fprintf(stderr, ">>_StartOrStopPtyOutput() starting\n"));
|
|
/*
|
|
** This function will either turn on or turn off the
|
|
** pty write selector depending whether any text is waiting
|
|
** to be written.
|
|
*/
|
|
if (TextIsPending(tpd->pendingWrite))
|
|
{
|
|
if (tpd->ptyOutputId == 0)
|
|
{
|
|
/*
|
|
** turn it on...
|
|
*/
|
|
tpd->ptyOutputId = XtAppAddInput(XtWidgetToApplicationContext(w),
|
|
tw->term.pty,
|
|
(XtPointer) XtInputWriteMask,
|
|
writePty, w);
|
|
|
|
Debug('o', fprintf(stderr, " adding pty write select\n"));
|
|
}
|
|
}
|
|
else if (tpd->ptyOutputId != 0)
|
|
{
|
|
/*
|
|
** turn it off...
|
|
*/
|
|
(void) XtRemoveInput(tw->term.tpd->ptyOutputId);
|
|
tw->term.tpd->ptyOutputId = (XtInputId) 0;
|
|
Debug('o', fprintf(stderr, " removing pty write select\n"));
|
|
}
|
|
Debug('o', fprintf(stderr, ">>_StartOrStopPtyOutput() finished\n"));
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static void VerticalScrollBarCallback(Widget wid, XtPointer client_data,
|
|
XtPointer call_data)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) client_data;
|
|
XmScrollBarCallbackStruct *cb = (XmScrollBarCallbackStruct *) call_data;
|
|
|
|
_DtTermPrimCursorOff((Widget) tw);
|
|
|
|
(void) _DtTermPrimScrollTextTo((Widget) tw, cb->value -
|
|
(tw->term.tpd->useHistoryBuffer ?
|
|
tw->term.tpd->lastUsedHistoryRow : 0));
|
|
/* we need to complete the scroll or it won't happen... */
|
|
(void) _DtTermPrimScrollComplete((Widget) tw, True);
|
|
if (cb->reason != XmCR_DRAG) {
|
|
_DtTermPrimCursorOn((Widget) tw);
|
|
}
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static void WarningDialogOkCallback(Widget wid, XtPointer client_data,
|
|
XtPointer call_data)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) client_data;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
|
|
tpd->warningDialogMapped = False;
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static void WarningDialogWMDestroyCallback(Widget wid, XtPointer client_data,
|
|
XtPointer call_data)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) client_data;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
|
|
/* unmap the window (this is necessary for wm destroy callbacks)... */
|
|
(void) XtUnmanageChild(tpd->warningDialog);
|
|
/* call the OK callback... */
|
|
(void) WarningDialogOkCallback(tpd->warningDialog, client_data,
|
|
call_data);
|
|
}
|
|
|
|
void _DtTermPrimWarningDialog(Widget w, char *msg)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
Widget parent;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
XmString msgString;
|
|
XmString titleString;
|
|
Arg arglist[10];
|
|
int i;
|
|
|
|
if (!tpd->warningDialog) {
|
|
i = 0;
|
|
|
|
(void) XtSetArg(arglist[i], XmNdialogStyle,
|
|
XmDIALOG_PRIMARY_APPLICATION_MODAL); i++;
|
|
titleString =
|
|
XmStringGenerate(
|
|
GETMESSAGE(NL_SETN_Prim,2,"Terminal - Warning"),
|
|
XmFONTLIST_DEFAULT_TAG, XmCHARSET_TEXT, NULL);
|
|
(void) XtSetArg(arglist[i], XmNdialogTitle, titleString); i++;
|
|
tpd->warningDialog = XmCreateWarningDialog(w, "termWarning", arglist, i);
|
|
(void) XmStringFree(titleString);
|
|
|
|
(void) XtAddCallback(tpd->warningDialog,
|
|
XmNokCallback, WarningDialogOkCallback, (XtPointer) w);
|
|
/* find the shell widget so we can add a wmDestroy callback... */
|
|
/*EMPTY*/
|
|
for (parent = tpd->warningDialog; !XtIsShell(parent);
|
|
parent = XtParent(parent))
|
|
;
|
|
(void) _DtTermPrimAddDeleteWindowCallback(parent,
|
|
WarningDialogWMDestroyCallback, (XtPointer) w);
|
|
}
|
|
|
|
i = 0;
|
|
msgString =
|
|
XmStringGenerate(msg, XmFONTLIST_DEFAULT_TAG, XmCHARSET_TEXT, NULL);
|
|
(void) XtSetArg(arglist[i], XmNmessageString, msgString); i++;
|
|
(void) XtSetValues(tpd->warningDialog, arglist, i);
|
|
(void) XmStringFree(msgString);
|
|
|
|
if (!XtIsRealized(tpd->warningDialog)) {
|
|
(void) XtRealizeWidget(tpd->warningDialog);
|
|
(void) XtUnmanageChild(XmMessageBoxGetChild(tpd->warningDialog,
|
|
XmDIALOG_CANCEL_BUTTON));
|
|
(void) XtUnmanageChild(XmMessageBoxGetChild(tpd->warningDialog,
|
|
XmDIALOG_HELP_BUTTON));
|
|
}
|
|
|
|
/* limit wm functions to move, decorations to menu, border and title...
|
|
*/
|
|
i = 0;
|
|
(void) XtSetArg(arglist[i], XmNmwmFunctions, MWM_FUNC_MOVE); i++;
|
|
(void) XtSetArg(arglist[i], XmNmwmDecorations,
|
|
MWM_DECOR_MENU | MWM_DECOR_BORDER | MWM_DECOR_TITLE); i++;
|
|
(void) XtSetValues(XtParent(tpd->warningDialog), arglist, i);
|
|
|
|
if (tpd->windowMapped) {
|
|
(void) XtManageChild(tpd->warningDialog);
|
|
tpd->warningDialogMapped = True;
|
|
tpd->mapWarningDialog = False;
|
|
} else {
|
|
tpd->mapWarningDialog = True;
|
|
}
|
|
}
|
|
|
|
typedef void _ManagerConstraintInitializeProc(Widget request, Widget new_w,
|
|
ArgList args, Cardinal *num_args);
|
|
static _ManagerConstraintInitializeProc *managerConstraintInitializeProc;
|
|
|
|
static void
|
|
ManagerConstraintInitializePatch(Widget request, Widget new_w, ArgList args,
|
|
Cardinal *num_args)
|
|
{
|
|
if (!XtIsSubclass(new_w, dtTermPrimitiveWidgetClass)) {
|
|
(*managerConstraintInitializeProc)(request, new_w, args, num_args);
|
|
}
|
|
}
|
|
|
|
void
|
|
DtTermInitialize(void)
|
|
{
|
|
XmManagerClassRec *mw = (XmManagerClassRec *) xmManagerWidgetClass;
|
|
CoreClassRec *core = (CoreClassRec *) coreWidgetClass;
|
|
static Boolean initted = False;
|
|
|
|
/* only do this once... */
|
|
_DtTermProcessLock();
|
|
if (initted) {
|
|
_DtTermProcessUnlock();
|
|
return;
|
|
}
|
|
|
|
if (core->core_class.class_inited) {
|
|
(void) XtWarning("DtTermInitialize was not called before toolkit initialization\n");
|
|
}
|
|
managerConstraintInitializeProc = mw->constraint_class.initialize;
|
|
mw->constraint_class.initialize = ManagerConstraintInitializePatch;
|
|
initted = True;
|
|
_DtTermProcessUnlock();
|
|
}
|
|
|
|
void
|
|
_DtTermPrimPutEnv(char *c1, char *c2)
|
|
{
|
|
char buffer[BUFSIZ];
|
|
char *c;
|
|
|
|
snprintf(buffer, sizeof(buffer), "%s%s", c1, c2);
|
|
c = XtMalloc(strlen(buffer) + 1);
|
|
(void) strcpy(c, buffer);
|
|
(void) putenv(c);
|
|
}
|
|
|
|
|
|
#if !defined(NL_CAT_LOCALE)
|
|
#define NL_CAT_LOCALE 0
|
|
#endif /* NL_CAT_LOCAL */
|
|
|
|
char *
|
|
_DtTermPrimGetMessage(
|
|
char *filename,
|
|
int set,
|
|
int n,
|
|
char *s )
|
|
{
|
|
char *msg;
|
|
char *lang;
|
|
static int first = 1;
|
|
static nl_catd nlmsg_fd;
|
|
|
|
_DtTermProcessLock();
|
|
if ( first )
|
|
{
|
|
first = 0;
|
|
|
|
lang = (char *) getenv ("LANG");
|
|
|
|
if (!lang || !(strcmp (lang, "C")))
|
|
/*
|
|
* If LANG is not set or if LANG=C, then there
|
|
* is no need to open the message catalog - just
|
|
* return the built-in string "s".
|
|
*/
|
|
nlmsg_fd = (nl_catd) -1;
|
|
else
|
|
nlmsg_fd = CATOPEN(filename, NL_CAT_LOCALE);
|
|
}
|
|
_DtTermProcessUnlock();
|
|
msg=CATGETS(nlmsg_fd,set,n,s);
|
|
return (msg);
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
PreeditStart(
|
|
XIC xic,
|
|
XPointer client_data,
|
|
XPointer call_data)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) client_data;
|
|
|
|
PreLen(tw) = 0L;
|
|
PreRow(tw) = tw->term.tpd->cursorRow;
|
|
PreColumn(tw) = tw->term.tpd->cursorColumn;
|
|
|
|
/* vertical writing dependency here */
|
|
PreStart(tw) = tw->term.tpd->cursorColumn;
|
|
PreEnd(tw) = tw->term.tpd->cursorColumn;
|
|
|
|
PreUnder(tw) = True;
|
|
return(-1);
|
|
}
|
|
|
|
|
|
static void
|
|
PreeditDone(
|
|
XIC xic,
|
|
XPointer client_data,
|
|
XPointer call_data)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) client_data;
|
|
|
|
_DtTermPrimRefreshText((Widget)tw, PreColumn(tw), PreRow(tw),
|
|
tw->term.columns,
|
|
PreRow(tw));
|
|
PreUnder(tw) = False;
|
|
PreLen(tw) = 0L;
|
|
}
|
|
|
|
|
|
static void
|
|
PreeditDelete(
|
|
DtTermPrimitiveWidget tw,
|
|
XIMPreeditDrawCallbackStruct *call_data)
|
|
{
|
|
short retcount, row, col, width;
|
|
termChar *retchar;
|
|
|
|
/*
|
|
** chg_first to chg_length in the preedit call_data
|
|
** structure indicates what should be deleted out of
|
|
** the preedit buffer, but this is terms of characters
|
|
** not bytes. We have stored the byte value in the
|
|
** term data structure, so we use that instead.
|
|
*/
|
|
if (call_data->chg_length && PreLen(tw)) {
|
|
row = PreRow(tw);
|
|
col = PreColumn(tw) + call_data->chg_first;
|
|
width = call_data->chg_length;
|
|
_DtTermPrimBufferDelete(tw->term.tpd->termBuffer, &row, &col,
|
|
&width, &retchar, &retcount);
|
|
|
|
/*
|
|
** We may want to consider freeing retcount @ retchar
|
|
*/
|
|
|
|
/*
|
|
** Refresh the text buffer -
|
|
** We must refresh to the rest of the line, because the
|
|
** preedit buffer may be in the middle of a line.
|
|
*/
|
|
_DtTermPrimRefreshText((Widget)tw, PreColumn(tw), PreRow(tw),
|
|
tw->term.columns,
|
|
PreRow(tw));
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
PreeditHighlight(
|
|
DtTermPrimitiveWidget tw,
|
|
XIMPreeditDrawCallbackStruct *call_data)
|
|
{
|
|
TermSelectInfo selectInfo = tw->term.tpd->selectInfo;
|
|
|
|
/* check for null feedback */
|
|
if (call_data && call_data->text && call_data->text->feedback) {
|
|
switch (*call_data->text->feedback) {
|
|
case XIMReverse:
|
|
case XIMUnderline:
|
|
case XIMHighlight:
|
|
case XIMPrimary:
|
|
case XIMSecondary:
|
|
case XIMTertiary:
|
|
/* clear any existing highlight first */
|
|
selectInfo->ownPrimary = False;
|
|
_DtTermPrimRenderRefreshTextLinear((Widget)tw,
|
|
selectInfo->begin,
|
|
selectInfo->end - 1);
|
|
selectInfo->ownPrimary =True;
|
|
selectInfo->begin = rowColToPos(tw, PreRow(tw), PreColumn(tw));
|
|
selectInfo->end = selectInfo->begin + PreLen(tw);
|
|
_DtTermPrimRenderRefreshTextLinear((Widget)tw,
|
|
selectInfo->begin,
|
|
selectInfo->end - 1);
|
|
break;
|
|
default:
|
|
/* no highlight set, clear */
|
|
selectInfo->ownPrimary = False;
|
|
_DtTermPrimRenderRefreshTextLinear((Widget)tw,
|
|
selectInfo->begin,
|
|
selectInfo->end - 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
PreeditDraw(
|
|
XIC xic,
|
|
XPointer client_data,
|
|
XIMPreeditDrawCallbackStruct *call_data)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) client_data;
|
|
DtTermInsertCharMode savmode;
|
|
unsigned char *mb;
|
|
wchar_t *wcs;
|
|
size_t len;
|
|
|
|
/* are we under preedit? */
|
|
if (!PreUnder(tw))
|
|
return;
|
|
|
|
/*
|
|
** This indicates a preedit buffer deletion
|
|
*/
|
|
if (!call_data->text) {
|
|
PreeditHighlight(tw, call_data);
|
|
PreeditDelete(tw, call_data);
|
|
|
|
/* reset row/column position to beginning */
|
|
tw->term.tpd->cursorRow = PreRow(tw);
|
|
tw->term.tpd->cursorColumn = PreColumn(tw);
|
|
_DtTermPrimCursorUpdate((Widget)tw);
|
|
_DtTermPrimCursorOn((Widget)tw);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
** At this point, we know there is a string in the
|
|
** preedit buffer that we must render.
|
|
*/
|
|
|
|
/* get preedit string */
|
|
if (call_data->text->encoding_is_wchar) {
|
|
|
|
/* preedit buffer is wchar, we must convert */
|
|
wcs = call_data->text->string.wide_char;
|
|
len = wcslen(wcs) * sizeof(wchar_t);
|
|
mb = (unsigned char *)XtMalloc(len);
|
|
|
|
/* check for invalid string */
|
|
if (wcstombs((char *)mb, wcs, len) == -1)
|
|
return;
|
|
} else
|
|
mb = (unsigned char *)call_data->text->string.multi_byte;
|
|
|
|
|
|
/*
|
|
** First we must destroy the previous contents of
|
|
** the preedit buffer, if any, before we redraw
|
|
** the new one.
|
|
*/
|
|
PreeditDelete(tw, call_data);
|
|
|
|
/* set insertion point */
|
|
tw->term.tpd->cursorRow = PreRow(tw);
|
|
tw->term.tpd->cursorColumn = PreColumn(tw);
|
|
|
|
/* render buffer */
|
|
savmode = tw->term.tpd->insertCharMode;
|
|
tw->term.tpd->insertCharMode = DtTERM_INSERT_CHAR_ON;
|
|
len = strlen((char *)mb);
|
|
_DtTermPrimInsertText((Widget)tw, mb, len);
|
|
PreLen(tw) = len;
|
|
tw->term.tpd->insertCharMode = savmode;
|
|
|
|
/* check highlight */
|
|
PreeditHighlight(tw, call_data);
|
|
|
|
/* update cursor */
|
|
_DtTermPrimCursorUpdate((Widget)tw);
|
|
_DtTermPrimCursorOn((Widget)tw);
|
|
}
|
|
|
|
|
|
static void
|
|
PreeditCaret(
|
|
XIC xic,
|
|
XPointer client_data,
|
|
XIMPreeditCaretCallbackStruct *call_data)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) client_data;
|
|
TermSelectInfo selectInfo = tw->term.tpd->selectInfo;
|
|
Boolean chgcursor = False;
|
|
short newpos = 0;
|
|
|
|
switch (call_data->style) {
|
|
case XIMIsInvisible:
|
|
_DtTermPrimCursorOff((Widget)tw);
|
|
break;
|
|
case XIMIsPrimary:
|
|
case XIMIsSecondary:
|
|
_DtTermPrimCursorOn((Widget)tw);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch (call_data->direction) {
|
|
case XIMForwardChar:
|
|
newpos = tw->term.tpd->cursorColumn + 1;
|
|
chgcursor = True;
|
|
break;
|
|
case XIMBackwardChar:
|
|
newpos = tw->term.tpd->cursorColumn - 1;
|
|
chgcursor = True;
|
|
break;
|
|
case XIMLineStart:
|
|
newpos = PreStart(tw);
|
|
chgcursor = True;
|
|
break;
|
|
case XIMLineEnd:
|
|
newpos = PreEnd(tw);
|
|
chgcursor = True;
|
|
break;
|
|
case XIMAbsolutePosition:
|
|
newpos = PreColumn(tw) + call_data->position;
|
|
chgcursor = True;
|
|
break;
|
|
|
|
/* do nothing we these movements */
|
|
case XIMForwardWord:
|
|
case XIMBackwardWord:
|
|
case XIMCaretUp:
|
|
case XIMCaretDown:
|
|
case XIMNextLine:
|
|
case XIMPreviousLine:
|
|
case XIMDontChange:
|
|
break;
|
|
default:
|
|
break; /* NOTREACHED */
|
|
}
|
|
|
|
/*
|
|
** The input method shouldn't let us edit outside
|
|
** of the preedit buffer anyway, but we check just
|
|
** to be sure.
|
|
*/
|
|
if (chgcursor && (newpos >= PreStart(tw)) && (newpos <= PreEnd(tw))) {
|
|
tw->term.tpd->cursorColumn = newpos;
|
|
_DtTermPrimCursorUpdate((Widget)tw);
|
|
_DtTermPrimCursorOn((Widget)tw);
|
|
/*
|
|
** refresh highlight (if any) because cursor
|
|
** movement hoses it up
|
|
*/
|
|
_DtTermPrimRenderRefreshTextLinear((Widget)tw,
|
|
selectInfo->begin,
|
|
selectInfo->end - 1);
|
|
}
|
|
}
|
|
|
|
static void
|
|
setThickness(
|
|
Widget widget,
|
|
int offset,
|
|
XrmValue *value )
|
|
{
|
|
XmDisplay xmDisplay;
|
|
static Dimension thickness;
|
|
|
|
xmDisplay = (XmDisplay)XmGetXmDisplay(XtDisplay(widget));
|
|
|
|
if (xmDisplay->display.enable_thin_thickness) {
|
|
thickness = 1;
|
|
}
|
|
else {
|
|
thickness = 2;
|
|
}
|
|
|
|
value->addr = (XPointer)&thickness;
|
|
}
|