#include <stdio.h>
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <X11/Xatom.h>
#include <X11/Xfuncs.h>
#include <X11/Xutil.h>
#include <X11/Xmu/Misc.h>
#include <X11/Xmu/SysUtil.h>
#include <X11/Xmu/Xmu.h>
#include <X11/Xaw/Cardinals.h>
#include <X11/Xaw/MultiSinkP.h>
#include <X11/Xaw/TextP.h>
#include <X11/Xaw/TextSrcP.h>
#include <X11/Xaw/TextSinkP.h>
#include <X11/Xaw/Scrollbar.h>
#include <X11/Xaw/XawImP.h>
#include <X11/Xaw/XawInit.h>
#include "Private.h"
#include "XawI18n.h"
#ifndef MAX_LEN_CT
#define MAX_LEN_CT 6
#endif
unsigned long FMT8BIT = 0L;
unsigned long XawFmt8Bit = 0L;
unsigned long XawFmtWide = 0L;
#define SinkClearToBG _XawTextSinkClearToBackground
#define SrcScan XawTextSourceScan
#define SrcRead XawTextSourceRead
#define SrcReplace XawTextSourceReplace
#define SrcSearch XawTextSourceSearch
#define SrcCvtSel XawTextSourceConvertSelection
#define SrcSetSelection XawTextSourceSetSelection
#define MULTI_CLICK_TIME 500L
#define SRC_CHANGE_NONE 0
#define SRC_CHANGE_AFTER 1
#define SRC_CHANGE_BEFORE 2
#define SRC_CHANGE_OVERLAP 3
#define Superclass (&simpleClassRec)
#define MAX_CUT_LEN(dpy) (XMaxRequestSize(dpy) - 64)
#define ClearWindow(ctx) \
_XawTextNeedsUpdating((ctx), \
(ctx)->text.lt.top, \
(ctx)->text.lt.info[ctx->text.lt.lines].position)
static void XawTextClassInitialize(void);
static void XawTextInitialize(Widget, Widget, ArgList, Cardinal*);
static void XawTextRealize(Widget, XtValueMask*, XSetWindowAttributes*);
static void XawTextDestroy(Widget);
static void XawTextResize(Widget);
static void XawTextExpose(Widget, XEvent*, Region);
static Boolean XawTextSetValues(Widget, Widget, Widget, ArgList, Cardinal*);
static void XawTextGetValuesHook(Widget, ArgList, Cardinal*);
static Bool XawTextChangeSensitive(Widget);
static XawTextPosition _BuildLineTable(TextWidget, XawTextPosition, int);
static void _CreateCutBuffers(Display*);
static Boolean TextConvertSelection(Widget, Atom*, Atom*, Atom*, XtPointer*,
unsigned long*, int*);
static int CountLines(TextWidget, XawTextPosition, XawTextPosition);
static void CreateHScrollBar(TextWidget);
static void CreateVScrollBar(TextWidget);
static void CvtStringToScrollMode(XrmValuePtr, Cardinal*,
XrmValuePtr, XrmValuePtr);
static Boolean CvtScrollModeToString(Display*, XrmValue*, Cardinal*,
XrmValue*, XrmValue*, XtPointer*);
static void CvtStringToWrapMode(XrmValuePtr, Cardinal*,
XrmValuePtr, XrmValuePtr);
static Boolean CvtWrapModeToString(Display*, XrmValue*, Cardinal*,
XrmValue*, XrmValue*, XtPointer*);
static Boolean CvtStringToJustifyMode(Display*, XrmValue*, Cardinal*,
XrmValue*, XrmValue*, XtPointer*);
static Boolean CvtJustifyModeToString(Display*, XrmValue*, Cardinal*,
XrmValue*, XrmValue*, XtPointer*);
static void DestroyHScrollBar(TextWidget);
static void DestroyVScrollBar(TextWidget);
#ifndef OLDXAW
static void DisplayText(Widget, XawTextPosition, XawTextPosition);
#endif
static void OldDisplayText(Widget, XawTextPosition, XawTextPosition);
static void DisplayTextWindow(Widget);
static void DoCopyArea(TextWidget, int, int, unsigned int, unsigned int,
int, int);
static void DoSelection(TextWidget, XawTextPosition, Time, Bool);
static void ExtendSelection(TextWidget, XawTextPosition, Bool);
static XawTextPosition FindGoodPosition(TextWidget, XawTextPosition);
static void FlushUpdate(TextWidget);
static int GetCutBufferNumber(Atom);
static int GetMaxTextWidth(TextWidget);
static unsigned int GetWidestLine(TextWidget);
static void HScroll(Widget, XtPointer, XtPointer);
static void HJump(Widget, XtPointer, XtPointer);
static void InsertCursor(Widget, XawTextInsertState);
static Bool LineAndXYForPosition(TextWidget, XawTextPosition, int*,
int*, int*);
static int LineForPosition(TextWidget, XawTextPosition);
static void TextLoseSelection(Widget, Atom*);
static Bool MatchSelection(Atom, XawTextSelection*);
static void ModifySelection(TextWidget, XawTextPosition, XawTextPosition);
static XawTextPosition PositionForXY(TextWidget, int, int);
static void PositionHScrollBar(TextWidget);
static void PositionVScrollBar(TextWidget);
#ifndef OLDXAW
static int ResolveColumnNumber(TextWidget);
static int ResolveLineNumber(TextWidget);
#endif
static void _SetSelection(TextWidget, XawTextPosition, XawTextPosition,
Atom*, Cardinal);
static void TextSinkResize(Widget);
static void UpdateTextInRectangle(TextWidget, XRectangle*);
static void UpdateTextInLine(TextWidget, int, int, int);
static void VScroll(Widget, XtPointer, XtPointer);
static void VJump(Widget, XtPointer, XtPointer);
void _XawTextAlterSelection(TextWidget,
XawTextSelectionMode, XawTextSelectionAction,
String*, Cardinal*);
void _XawTextCheckResize(TextWidget);
void _XawTextClearAndCenterDisplay(TextWidget);
void _XawTextExecuteUpdate(TextWidget);
char *_XawTextGetText(TextWidget, XawTextPosition, XawTextPosition);
void _XawTextPrepareToUpdate(TextWidget);
int _XawTextReplace(TextWidget, XawTextPosition, XawTextPosition,
XawTextBlock*);
Atom *_XawTextSelectionList(TextWidget, String*, Cardinal);
void _XawTextSetScrollBars(TextWidget);
void _XawTextSetSelection(TextWidget, XawTextPosition, XawTextPosition,
String*, Cardinal);
void _XawTextVScroll(TextWidget, int);
void XawTextScroll(TextWidget, int, int);
void _XawTextSetSource(Widget, Widget, XawTextPosition, XawTextPosition);
#ifndef OLDXAW
void _XawTextSetLineAndColumnNumber(TextWidget, Bool);
#endif
void _XawTextSourceChanged(Widget, XawTextPosition, XawTextPosition,
XawTextBlock*, int);
void _XawTextShowPosition(TextWidget);
extern void _XawTextZapSelection(TextWidget, XEvent*, Bool);
void _XawSourceAddText(Widget, Widget);
void _XawSourceRemoveText(Widget, Widget, Bool);
Bool _XawTextSourceNewLineAtEOF(Widget);
void _XawTextSinkClearToBackground(Widget, int, int, unsigned, unsigned);
void _XawTextSinkDisplayText(Widget, int, int, XawTextPosition, XawTextPosition,
Bool);
extern char _XawDefaultTextTranslations[];
static XawTextSelectType defaultSelectTypes[] = {
XawselectPosition, XawselectAlphaNumeric, XawselectWord, XawselectLine,
XawselectParagraph, XawselectAll, XawselectNull,
};
static XPointer defaultSelectTypesPtr = (XPointer)defaultSelectTypes;
static Dimension defWidth = 100;
static Dimension defHeight = DEFAULT_TEXT_HEIGHT;
#define offset(field) XtOffsetOf(TextRec, field)
static XtResource resources[] = {
{
XtNwidth,
XtCWidth,
XtRDimension,
sizeof(Dimension),
offset(core.width),
XtRDimension,
(XtPointer)&defWidth
},
{
XtNcursor,
XtCCursor,
XtRCursor,
sizeof(Cursor),
offset(simple.cursor),
XtRString,
"xterm"
},
{
XtNheight,
XtCHeight,
XtRDimension,
sizeof(Dimension),
offset(core.height),
XtRDimension,
(XtPointer)&defHeight
},
{
XtNdisplayPosition,
XtCTextPosition,
XtRInt,
sizeof(XawTextPosition),
offset(text.lt.top),
XtRImmediate,
(XtPointer)0
},
{
XtNinsertPosition,
XtCTextPosition,
XtRInt,
sizeof(XawTextPosition),
offset(text.insertPos),
XtRImmediate,
(XtPointer)0
},
{
XtNleftMargin,
XtCMargin,
XtRPosition,
sizeof(Position),
offset(text.r_margin.left),
XtRImmediate,
(XtPointer)2
},
{
XtNrightMargin,
XtCMargin,
XtRPosition,
sizeof(Position),
offset(text.r_margin.right),
XtRImmediate,
(XtPointer)4
},
{
XtNtopMargin,
XtCMargin,
XtRPosition,
sizeof(Position),
offset(text.r_margin.top),
XtRImmediate,
(XtPointer)2
},
{
XtNbottomMargin,
XtCMargin,
XtRPosition,
sizeof(Position),
offset(text.r_margin.bottom),
XtRImmediate,
(XtPointer)2
},
{
XtNselectTypes,
XtCSelectTypes,
XtRPointer,
sizeof(XawTextSelectType*),
offset(text.sarray),
XtRPointer,
(XtPointer)&defaultSelectTypesPtr
},
{
XtNtextSource,
XtCTextSource,
XtRWidget,
sizeof(Widget),
offset(text.source),
XtRImmediate,
NULL
},
{
XtNtextSink,
XtCTextSink,
XtRWidget,
sizeof(Widget),
offset(text.sink),
XtRImmediate,
NULL
},
{
XtNdisplayCaret,
XtCOutput,
XtRBoolean,
sizeof(Boolean),
offset(text.display_caret),
XtRImmediate,
(XtPointer)True
},
{
XtNscrollVertical,
XtCScroll,
XtRScrollMode,
sizeof(XawTextScrollMode),
offset(text.scroll_vert),
XtRImmediate,
(XtPointer)False
},
{
XtNscrollHorizontal,
XtCScroll,
XtRScrollMode,
sizeof(XawTextScrollMode),
offset(text.scroll_horiz),
XtRImmediate,
(XtPointer)False
},
{
XtNwrap,
XtCWrap,
XtRWrapMode,
sizeof(XawTextWrapMode),
offset(text.wrap),
XtRImmediate,
(XtPointer)XawtextWrapNever
},
{
XtNautoFill,
XtCAutoFill,
XtRBoolean,
sizeof(Boolean),
offset(text.auto_fill),
XtRImmediate,
(XtPointer)False
},
#ifndef OLDXAW
{
XtNpositionCallback,
XtCCallback,
XtRCallback,
sizeof(XtPointer),
offset(text.position_callbacks),
XtRCallback,
NULL
},
{
XtNleftColumn,
XtCColumn,
XtRShort,
sizeof(short),
offset(text.left_column),
XtRImmediate,
(XtPointer)0
},
{
XtNrightColumn,
XtCColumn,
XtRShort,
sizeof(short),
offset(text.right_column),
XtRImmediate,
(XtPointer)0
},
{
XtNjustifyMode,
XtCJustifyMode,
XtRJustifyMode,
sizeof(XawTextJustifyMode),
offset(text.justify),
XtRImmediate,
(XtPointer)XawjustifyLeft
},
#endif
};
#undef offset
#define done(address, type) \
{ toVal->size = sizeof(type); toVal->addr = (XPointer)address; }
static XrmQuark QWrapNever, QWrapLine, QWrapWord;
#ifndef notdef
static XrmQuark QScrollNever, QScrollWhenNeeded, QScrollAlways;
#endif
static XrmQuark QJustifyLeft, QJustifyRight, QJustifyCenter, QJustifyFull;
static void
CvtStringToScrollMode(XrmValuePtr args, Cardinal *num_args,
XrmValuePtr fromVal, XrmValuePtr toVal)
{
static XawTextScrollMode scrollMode = XawtextScrollNever;
XrmQuark q;
char name[32];
XmuNCopyISOLatin1Lowered(name, (char *)fromVal->addr, sizeof(name));
q = XrmStringToQuark(name);
if (q == QScrollNever || q == QScrollWhenNeeded)
scrollMode = XawtextScrollNever;
else if (q == QScrollAlways)
scrollMode = XawtextScrollAlways;
else if (strcmp(name, "true") == 0 || strcmp(name, "1") == 0)
scrollMode = XawtextScrollAlways;
else if (strcmp(name, "false") == 0 || strcmp(name, "0") == 0)
scrollMode = XawtextScrollNever;
else
XtStringConversionWarning((char *)fromVal->addr, XtRScrollMode);
done(&scrollMode, XawTextScrollMode);
}
static Boolean
CvtScrollModeToString(Display *dpy, XrmValue *args, Cardinal *num_args,
XrmValue *fromVal, XrmValue *toVal, XtPointer *data)
{
static char *buffer;
Cardinal size;
switch (*(XawTextScrollMode *)fromVal->addr) {
case XawtextScrollNever:
case XawtextScrollWhenNeeded:
buffer = XtEtextScrollNever;
break;
case XawtextScrollAlways:
buffer = XtEtextScrollAlways;
break;
default:
XawTypeToStringWarning(dpy, XtRScrollMode);
toVal->addr = NULL;
toVal->size = 0;
return (False);
}
size = strlen(buffer) + 1;
if (toVal->addr != NULL) {
if (toVal->size < size) {
toVal->size = size;
return (False);
}
strcpy((char *)toVal->addr, buffer);
}
else
toVal->addr = (XPointer)buffer;
toVal->size = sizeof(String);
return (True);
}
static void
CvtStringToWrapMode(XrmValuePtr args, Cardinal *num_args,
XrmValuePtr fromVal, XrmValuePtr toVal)
{
static XawTextWrapMode wrapMode = XawtextWrapNever;
XrmQuark q;
char lowerName[6];
XmuNCopyISOLatin1Lowered(lowerName, (char *)fromVal->addr,
sizeof(lowerName));
q = XrmStringToQuark(lowerName);
if (q == QWrapNever)
wrapMode = XawtextWrapNever;
else if (q == QWrapLine)
wrapMode = XawtextWrapLine;
else if (q == QWrapWord)
wrapMode = XawtextWrapWord;
else
XtStringConversionWarning((char *)fromVal->addr, XtRWrapMode);
done(&wrapMode, XawTextWrapMode);
}
static Boolean
CvtWrapModeToString(Display *dpy, XrmValue *args, Cardinal *num_args,
XrmValue *fromVal, XrmValue *toVal, XtPointer *data)
{
static char *buffer;
Cardinal size;
switch (*(XawTextWrapMode *)fromVal->addr) {
case XawtextWrapNever:
buffer = XtEtextWrapNever;
break;
case XawtextWrapLine:
buffer = XtEtextWrapLine;
break;
case XawtextWrapWord:
buffer = XtEtextWrapWord;
break;
default:
XawTypeToStringWarning(dpy, XtRWrapMode);
toVal->addr = NULL;
toVal->size = 0;
return (False);
}
size = strlen(buffer) + 1;
if (toVal->addr != NULL) {
if (toVal->size < size) {
toVal->size = size;
return (False);
}
strcpy((char *)toVal->addr, buffer);
}
else
toVal->addr = (XPointer)buffer;
toVal->size = sizeof(String);
return (True);
}
static Boolean
CvtStringToJustifyMode(Display *dpy, XrmValue *args, Cardinal *num_args,
XrmValue *fromVal, XrmValue *toVal, XtPointer *data)
{
XawTextJustifyMode justify;
XrmQuark q;
char lowerName[8];
XmuNCopyISOLatin1Lowered(lowerName, (char *)fromVal->addr,
sizeof(lowerName));
q = XrmStringToQuark(lowerName);
if (q == QJustifyLeft)
justify = XawjustifyLeft;
else if (q == QJustifyRight)
justify = XawjustifyRight;
else if (q == QJustifyCenter)
justify = XawjustifyCenter;
else if(q == QJustifyFull)
justify = XawjustifyFull;
else {
XtStringConversionWarning((char *)fromVal->addr, XtRJustifyMode);
return (False);
}
toVal->size = sizeof(XawTextJustifyMode);
*(XawTextJustifyMode *)(toVal->addr) = justify;
return (True);
}
static Boolean
CvtJustifyModeToString(Display *dpy, XrmValue *args, Cardinal *num_args,
XrmValue *fromVal, XrmValue *toVal, XtPointer *data)
{
static char *buffer;
Cardinal size;
switch (*(XawTextJustifyMode *)fromVal->addr) {
case XawjustifyLeft:
buffer = XtEtextJustifyLeft;
break;
case XawjustifyRight:
buffer = XtEtextJustifyRight;
break;
case XawjustifyCenter:
buffer = XtEtextJustifyCenter;
break;
case XawjustifyFull:
buffer = XtEtextJustifyFull;
break;
default:
XawTypeToStringWarning(dpy, XtRJustifyMode);
toVal->addr = NULL;
toVal->size = 0;
return (False);
}
size = strlen(buffer) + 1;
if (toVal->addr != NULL) {
if (toVal->size < size) {
toVal->size = size;
return (False);
}
strcpy((char *)toVal->addr, buffer);
}
else
toVal->addr = (XPointer)buffer;
toVal->size = sizeof(String);
return (True);
}
#undef done
static void
XawTextClassInitialize(void)
{
if (!XawFmt8Bit)
FMT8BIT = XawFmt8Bit = XrmPermStringToQuark("FMT8BIT");
if (!XawFmtWide)
XawFmtWide = XrmPermStringToQuark("FMTWIDE");
XawInitializeWidgetSet();
textClassRec.core_class.num_actions = _XawTextActionsTableCount;
QWrapNever = XrmPermStringToQuark(XtEtextWrapNever);
QWrapLine = XrmPermStringToQuark(XtEtextWrapLine);
QWrapWord = XrmPermStringToQuark(XtEtextWrapWord);
XtAddConverter(XtRString, XtRWrapMode, CvtStringToWrapMode, NULL, 0);
XtSetTypeConverter(XtRWrapMode, XtRString, CvtWrapModeToString,
NULL, 0, XtCacheNone, NULL);
QScrollNever = XrmPermStringToQuark(XtEtextScrollNever);
QScrollWhenNeeded = XrmPermStringToQuark(XtEtextScrollWhenNeeded);
QScrollAlways = XrmPermStringToQuark(XtEtextScrollAlways);
XtAddConverter(XtRString, XtRScrollMode, CvtStringToScrollMode,
NULL, 0);
XtSetTypeConverter(XtRScrollMode, XtRString, CvtScrollModeToString,
NULL, 0, XtCacheNone, NULL);
QJustifyLeft = XrmPermStringToQuark(XtEtextJustifyLeft);
QJustifyRight = XrmPermStringToQuark(XtEtextJustifyRight);
QJustifyCenter = XrmPermStringToQuark(XtEtextJustifyCenter);
QJustifyFull = XrmPermStringToQuark(XtEtextJustifyFull);
XtSetTypeConverter(XtRString, XtRJustifyMode, CvtStringToJustifyMode,
NULL, 0, XtCacheNone, NULL);
XtSetTypeConverter(XtRJustifyMode, XtRString, CvtJustifyModeToString,
NULL, 0, XtCacheNone, NULL);
}
static void
PositionHScrollBar(TextWidget ctx)
{
Widget hbar = ctx->text.hbar, vbar = ctx->text.vbar;
Position x, y;
Dimension width, height;
if (ctx->text.hbar == NULL)
return;
if (vbar != NULL)
x = XtWidth(vbar);
else
x = -XtBorderWidth(hbar);
y = XtHeight(ctx) - XtHeight(hbar) - XtBorderWidth(hbar);
if (vbar != NULL) {
width = XtWidth(ctx) - XtWidth(vbar) - XtBorderWidth(vbar);
if (width > XtWidth(ctx))
width = XtWidth(ctx);
}
else
width = XtWidth(ctx);
height = XtHeight(hbar);
XtConfigureWidget(hbar, x, y, width, height, XtBorderWidth(hbar));
}
static void
PositionVScrollBar(TextWidget ctx)
{
Widget vbar = ctx->text.vbar;
Position x, y;
Dimension width, height;
if (vbar == NULL)
return;
x = y = -XtBorderWidth(vbar);
height = XtHeight(ctx);
width = XtWidth(vbar);
XtConfigureWidget(vbar, x, y, width, height, XtBorderWidth(vbar));
}
static void
CreateVScrollBar(TextWidget ctx)
{
Widget vbar;
if (ctx->text.vbar != NULL)
return;
ctx->text.vbar = vbar =
XtCreateWidget("vScrollbar", scrollbarWidgetClass, (Widget)ctx, NULL, 0);
XtAddCallback(vbar, XtNscrollProc, VScroll, (XtPointer)ctx);
XtAddCallback(vbar, XtNjumpProc, VJump, (XtPointer)ctx);
ctx->text.r_margin.left += XtWidth(vbar) + XtBorderWidth(vbar);
ctx->text.left_margin = ctx->text.margin.left = ctx->text.r_margin.left;
PositionVScrollBar(ctx);
PositionHScrollBar(ctx);
TextSinkResize(ctx->text.sink);
if (XtIsRealized((Widget)ctx)) {
XtRealizeWidget(vbar);
XtMapWidget(vbar);
}
XtSetKeyboardFocus(vbar, (Widget)ctx);
}
static void
DestroyVScrollBar(TextWidget ctx)
{
Widget vbar = ctx->text.vbar;
if (vbar == NULL)
return;
ctx->text.r_margin.left -= XtWidth(vbar) + XtBorderWidth(vbar);
ctx->text.left_margin = ctx->text.margin.left = ctx->text.r_margin.left;
XtDestroyWidget(vbar);
ctx->text.vbar = NULL;
if (!ctx->core.being_destroyed) {
PositionHScrollBar(ctx);
TextSinkResize(ctx->text.sink);
}
}
static void
CreateHScrollBar(TextWidget ctx)
{
Arg args[1];
Widget hbar;
int bottom;
if (ctx->text.hbar != NULL)
return;
XtSetArg(args[0], XtNorientation, XtorientHorizontal);
ctx->text.hbar = hbar =
XtCreateWidget("hScrollbar", scrollbarWidgetClass, (Widget)ctx, args, 1);
XtAddCallback(hbar, XtNscrollProc, HScroll, (XtPointer)ctx);
XtAddCallback(hbar, XtNjumpProc, HJump, (XtPointer)ctx);
bottom = ctx->text.r_margin.bottom + XtHeight(hbar) + XtBorderWidth(hbar);
ctx->text.margin.bottom = ctx->text.r_margin.bottom = bottom;
PositionHScrollBar(ctx);
TextSinkResize(ctx->text.sink);
if (XtIsRealized((Widget)ctx)) {
XtRealizeWidget(hbar);
XtMapWidget(hbar);
}
XtSetKeyboardFocus(hbar, (Widget)ctx);
}
static void
DestroyHScrollBar(TextWidget ctx)
{
Widget hbar = ctx->text.hbar;
if (hbar == NULL)
return;
ctx->text.r_margin.bottom -= XtHeight(hbar) + XtBorderWidth(hbar);
ctx->text.margin.bottom = ctx->text.r_margin.bottom;
XtDestroyWidget(hbar);
ctx->text.hbar = NULL;
if (!ctx->core.being_destroyed)
TextSinkResize(ctx->text.sink);
}
static void
XawTextInitialize(Widget request, Widget cnew,
ArgList args, Cardinal *num_args)
{
TextWidget ctx = (TextWidget)cnew;
ctx->text.lt.lines = 0;
ctx->text.lt.info = (XawTextLineTableEntry *)
XtCalloc(1, sizeof(XawTextLineTableEntry));
#ifndef OLDXAW
ctx->text.lt.base_line = 1;
#endif
(void)bzero(&ctx->text.origSel, sizeof(XawTextSelection));
(void)bzero(&ctx->text.s, sizeof(XawTextSelection));
ctx->text.s.type = XawselectPosition;
ctx->text.salt = NULL;
ctx->text.hbar = ctx->text.vbar = NULL;
ctx->text.lasttime = 0;
ctx->text.time = 0;
ctx->text.showposition = True;
ctx->text.lastPos = ctx->text.source != NULL ?
XawTextGetLastPosition(ctx) : 0;
ctx->text.file_insert = NULL;
ctx->text.search = NULL;
ctx->text.update = XmuNewScanline(0, 0, 0);
ctx->text.gc = XtGetGC(cnew, 0, 0);
ctx->text.hasfocus = False;
ctx->text.margin = ctx->text.r_margin;
ctx->text.left_margin = ctx->text.r_margin.left;
ctx->text.update_disabled = False;
ctx->text.clear_to_eol = True;
ctx->text.old_insert = -1;
ctx->text.mult = 1;
ctx->text.salt2 = NULL;
ctx->text.from_left = -1;
#ifndef OLDXAW
ctx->text.numeric = False;
ctx->text.selection_state = False;
ctx->text.kill_ring = 0;
ctx->text.line_number = -1;
ctx->text.column_number = -1;
ctx->text.source_changed = SRC_CHANGE_NONE;
ctx->text.kill_ring_ptr = NULL;
ctx->text.overwrite = False;
#endif
if (XtHeight(ctx) == DEFAULT_TEXT_HEIGHT) {
XtHeight(ctx) = VMargins(ctx);
if (ctx->text.sink != NULL)
XtHeight(ctx) += XawTextSinkMaxHeight(ctx->text.sink, 1);
}
if (ctx->text.scroll_vert == XawtextScrollAlways)
CreateVScrollBar(ctx);
if (ctx->text.scroll_horiz == XawtextScrollAlways)
CreateHScrollBar(ctx);
#ifndef OLDXAW
if (ctx->text.left_column < 0)
ctx->text.left_column = 0;
if (ctx->text.right_column < 0)
ctx->text.right_column = 0;
#endif
}
static void
XawTextRealize(Widget w, XtValueMask *mask, XSetWindowAttributes *attr)
{
TextWidget ctx = (TextWidget)w;
(*textClassRec.core_class.superclass->core_class.realize)(w, mask, attr);
if (ctx->text.hbar != NULL) {
XtRealizeWidget(ctx->text.hbar);
XtMapWidget(ctx->text.hbar);
}
if (ctx->text.vbar != NULL) {
XtRealizeWidget(ctx->text.vbar);
XtMapWidget(ctx->text.vbar);
}
_XawTextBuildLineTable(ctx, ctx->text.lt.top, True);
#ifndef OLDXAW
_XawTextSetLineAndColumnNumber(ctx, True);
#endif
}
static void
_CreateCutBuffers(Display *d)
{
static struct _DisplayRec {
struct _DisplayRec *next;
Display *dpy;
} *dpy_list = NULL;
struct _DisplayRec *dpy_ptr;
for (dpy_ptr = dpy_list; dpy_ptr != NULL; dpy_ptr = dpy_ptr->next)
if (dpy_ptr->dpy == d)
return;
dpy_ptr = XtNew(struct _DisplayRec);
dpy_ptr->next = dpy_list;
dpy_ptr->dpy = d;
dpy_list = dpy_ptr;
#define Create(buffer) \
XChangeProperty(d, RootWindow(d, 0), buffer, XA_STRING, 8, \
PropModeAppend, NULL, 0);
Create(XA_CUT_BUFFER0);
Create(XA_CUT_BUFFER1);
Create(XA_CUT_BUFFER2);
Create(XA_CUT_BUFFER3);
Create(XA_CUT_BUFFER4);
Create(XA_CUT_BUFFER5);
Create(XA_CUT_BUFFER6);
Create(XA_CUT_BUFFER7);
#undef Create
}
static void
InsertCursor(Widget w, XawTextInsertState state)
{
TextWidget ctx = (TextWidget)w;
int x, y;
int line;
if (ctx->text.lt.lines < 1)
return;
if (ctx->text.display_caret &&
LineAndXYForPosition(ctx, ctx->text.insertPos, &line, &x, &y)) {
if (line < ctx->text.lt.lines)
y += (ctx->text.lt.info[line + 1].y - ctx->text.lt.info[line].y) + 1;
else
y += (ctx->text.lt.info[line].y - ctx->text.lt.info[line - 1].y) + 1;
XawTextSinkInsertCursor(ctx->text.sink, x, y, state);
}
if (ctx->simple.international) {
Arg list[1];
XtSetArg(list[0], XtNinsertPosition, ctx->text.insertPos);
_XawImSetValues(w, list, 1);
}
}
void
_XawTextNeedsUpdating(TextWidget ctx,
XawTextPosition left, XawTextPosition right)
{
XmuSegment segment;
if (left >= right)
return;
segment.x1 = (int)left;
segment.x2 = (int)right;
(void)XmuScanlineOrSegment(ctx->text.update, &segment);
}
char *
_XawTextGetText(TextWidget ctx, XawTextPosition left, XawTextPosition right)
{
char *result, *tempResult;
XawTextBlock text;
int bytes;
if (XawTextFormat(ctx, XawFmt8Bit))
bytes = sizeof(unsigned char);
else if (XawTextFormat(ctx, XawFmtWide))
bytes = sizeof(wchar_t);
else
bytes = 1;
tempResult = result = XtMalloc((unsigned)(right - left + ONE) * bytes);
while (left < right) {
left = SrcRead(ctx->text.source, left, &text, (int)(right - left));
if (!text.length)
break;
memmove(tempResult, text.ptr, (unsigned)(text.length * bytes));
tempResult += text.length * bytes;
}
if (bytes == sizeof(wchar_t))
*((wchar_t*)tempResult) = (wchar_t)0;
else
*tempResult = '\0';
return (result);
}
char *
_XawTextGetSTRING(TextWidget ctx, XawTextPosition left, XawTextPosition right)
{
unsigned char *s;
unsigned char c;
long i, j, n;
wchar_t *ws, wc;
if (XawTextFormat(ctx, XawFmtWide)) {
MultiSinkObject sink = (MultiSinkObject)ctx->text.sink;
ws = (wchar_t *)_XawTextGetText(ctx, left, right);
n = wcslen(ws);
for (j = 0, i = 0; j < n; j++) {
wc = ws[j];
if (XwcTextEscapement (sink->multi_sink.fontset, &wc, 1)
|| (wc == _Xaw_atowc(XawTAB)) || (wc == _Xaw_atowc(XawLF))
|| (wc == _Xaw_atowc(XawESC)))
ws[i++] = wc;
}
ws[i] = (wchar_t)0;
return ((char *)ws);
}
else {
s = (unsigned char *)_XawTextGetText(ctx, left, right);
n = strlen((char *)s);
i = 0;
for (j = 0; j < n; j++) {
c = s[j];
if (((c >= 0x20) && c <= 0x7f)
||(c >= 0xa0) || (c == XawTAB) || (c == XawLF)
|| (c == XawESC)) {
s[i] = c;
i++;
}
}
s[i] = 0;
return ((char *)s);
}
}
static XawTextPosition
PositionForXY(TextWidget ctx, int x, int y)
{
int fromx, line, width, height;
XawTextPosition position;
if (ctx->text.lt.lines == 0)
return (0);
for (line = 0; line < ctx->text.lt.lines - 1; line++) {
if (y <= ctx->text.lt.info[line + 1].y)
break;
}
position = ctx->text.lt.info[line].position;
if (position >= ctx->text.lastPos)
return (ctx->text.lastPos);
fromx = ctx->text.left_margin;
XawTextSinkFindPosition(ctx->text.sink, position, fromx, x - fromx,
False, &position, &width, &height);
if (position > ctx->text.lastPos)
return (ctx->text.lastPos);
if (position >= ctx->text.lt.info[line + 1].position)
position = SrcScan(ctx->text.source, ctx->text.lt.info[line + 1].position,
XawstPositions, XawsdLeft, 1, True);
return (position);
}
static int
LineForPosition(TextWidget ctx, XawTextPosition position)
{
int line;
for (line = 0; line < ctx->text.lt.lines; line++)
if (position < ctx->text.lt.info[line + 1].position)
break;
return (line);
}
static Bool
LineAndXYForPosition(TextWidget ctx, XawTextPosition pos,
int *line, int *x, int *y)
{
XawTextPosition linePos, endPos;
Boolean visible;
int realW, realH;
*line = 0;
*x = ctx->text.left_margin;
*y = ctx->text.margin.top + 1;
if ((visible = IsPositionVisible(ctx, pos)) != False) {
*line = LineForPosition(ctx, pos);
*y = ctx->text.lt.info[*line].y;
linePos = ctx->text.lt.info[*line].position;
XawTextSinkFindDistance(ctx->text.sink, linePos,
*x, pos, &realW, &endPos, &realH);
*x += realW;
}
return (visible);
}
void
_XawTextBuildLineTable(TextWidget ctx, XawTextPosition position,
_XtBoolean force_rebuild)
{
Dimension height = 0;
int lines = 0;
Cardinal size;
if ((int)XtHeight(ctx) > VMargins(ctx)) {
height = XtHeight(ctx) - VMargins(ctx);
lines = XawTextSinkMaxLines(ctx->text.sink, height);
}
size = sizeof(XawTextLineTableEntry) * (lines + 1);
if (lines != ctx->text.lt.lines || ctx->text.lt.info == NULL) {
ctx->text.lt.info = (XawTextLineTableEntry *)
XtRealloc((char *)ctx->text.lt.info, size);
ctx->text.lt.lines = lines;
force_rebuild = True;
}
if (force_rebuild) {
(void)bzero((char *)ctx->text.lt.info, size);
ctx->text.lt.info[0].position = (XawTextPosition)-1;
}
if (position != ctx->text.lt.info[0].position) {
(void)_BuildLineTable(ctx, position, 0);
ctx->text.clear_to_eol = True;
}
}
static XawTextPosition
_BuildLineTable(TextWidget ctx, XawTextPosition position, int line)
{
XawTextLineTableEntry *lt = ctx->text.lt.info + line;
XawTextPosition end, update_from = -1;
Position y;
int wwidth, width, height;
#ifndef OLDXAW
Widget src = ctx->text.source;
#endif
int max_y = (int)XtHeight(ctx) - (int)ctx->text.margin.bottom;
if (ctx->text.wrap == XawtextWrapNever)
wwidth = 0x7fffffff;
else
wwidth = GetMaxTextWidth(ctx);
y = line == 0 ? ctx->text.margin.top : lt->y;
#ifndef OLDXAW
if (ctx->text.lt.base_line < 0) {
if (line == 0)
ctx->text.lt.top = position;
}
else if (line == 0) {
XawTextPosition pos = ctx->text.lt.top;
int base_line = ctx->text.lt.base_line;
if (position == 0)
base_line = 1;
else if (ctx->text.lt.base_line == 0 ||
ctx->text.source_changed == SRC_CHANGE_OVERLAP) {
pos = 0;
base_line = 1;
while (pos < position) {
pos = SrcScan(src, pos, XawstEOL, XawsdRight, 1, True);
if (pos <= position) {
++base_line;
if (pos == ctx->text.lastPos) {
base_line -= !_XawTextSourceNewLineAtEOF(src);
break;
}
}
}
}
else if (ctx->text.wrap == XawtextWrapNever
&& IsPositionVisible(ctx, position))
base_line += LineForPosition(ctx, position);
else if (pos < position) {
while (pos < position) {
pos = SrcScan(src, pos, XawstEOL, XawsdRight, 1, True);
if (pos <= position) {
++base_line;
if (pos == ctx->text.lastPos) {
base_line -= !_XawTextSourceNewLineAtEOF(src);
break;
}
}
}
}
else if (pos > position) {
while (pos > position) {
pos = SrcScan(src, pos, XawstEOL, XawsdLeft, 1, False);
if (--pos >= position)
--base_line;
}
}
ctx->text.lt.top = position;
ctx->text.lt.base_line = base_line;
}
#else
if (line == 0)
ctx->text.lt.top = position;
#endif
while (True) {
XawTextSinkFindPosition(ctx->text.sink, position, ctx->text.left_margin,
wwidth, ctx->text.wrap == XawtextWrapWord,
&end, &width, &height);
if (lt->position != position) {
_XawTextNeedsUpdating(ctx, position,
end <= position ? position + 1 : end);
ctx->text.clear_to_eol = True;
lt->position = position;
}
if (lt->y != y) {
if (update_from < 0)
update_from = line == 0 ?
ctx->text.lt.info[0].position :
ctx->text.lt.info[line - 1].position;
lt->y = y;
ctx->text.clear_to_eol = True;
}
if (lt->textWidth != width) {
if (lt->textWidth > width)
ctx->text.clear_to_eol = True;
lt->textWidth = width;
}
y += height;
if (end > ctx->text.lastPos) {
position = end;
ctx->text.clear_to_eol = True;
_XawTextNeedsUpdating(ctx, end, end + ctx->text.lt.lines - line);
while (line++ < ctx->text.lt.lines) {
if (line > 1 && y > max_y) {
ctx->text.lt.lines = line - 1;
break;
}
++lt;
if (lt->y != y) {
if (update_from < 0)
update_from = line < 2 ?
ctx->text.lt.info[0].position :
ctx->text.lt.info[line - 2].position;
lt->y = y;
}
lt->position = ++position;
lt->textWidth = 0;
y += height;
}
if (update_from >= 0)
_XawTextNeedsUpdating(ctx, update_from,
ctx->text.lt.info[ctx->text.lt.lines].position);
_XawTextSetScrollBars(ctx);
return (ctx->text.lastPos);
}
if (line && y > max_y)
ctx->text.lt.lines = line;
if (++line > ctx->text.lt.lines && y < max_y) {
ctx->text.lt.info = (XawTextLineTableEntry *)
XtRealloc((char *)ctx->text.lt.info,
sizeof(XawTextLineTableEntry) * (line + 1));
lt = ctx->text.lt.info + line;
bzero(lt, sizeof(XawTextLineTableEntry));
++ctx->text.lt.lines;
}
else
++lt;
if (position == end)
++position;
else
position = end;
if (line > ctx->text.lt.lines) {
if (update_from >= 0)
_XawTextNeedsUpdating(ctx, update_from,
ctx->text.lt.info[ctx->text.lt.lines].position);
_XawTextSetScrollBars(ctx);
return (position);
}
}
}
static unsigned int
GetWidestLine(TextWidget ctx)
{
int i;
unsigned int widest;
XawTextLineTablePtr lt = &(ctx->text.lt);
for (i = 0, widest = 0; i < lt->lines; i++)
if (widest < lt->info[i].textWidth)
widest = lt->info[i].textWidth;
return (widest);
}
void
_XawTextSetScrollBars(TextWidget ctx)
{
float first, last, denom, widest;
if (ctx->text.scroll_vert == XawtextScrollAlways) {
if (ctx->text.lastPos == 0)
first = 0.0;
else
first = ctx->text.lt.top / (float)ctx->text.lastPos;
if (ctx->text.lt.info[ctx->text.lt.lines].position < ctx->text.lastPos)
last = ctx->text.lt.info[ctx->text.lt.lines].position /
(float)ctx->text.lastPos;
else
last = 1.0;
XawScrollbarSetThumb(ctx->text.vbar, first, last - first);
}
if (ctx->text.scroll_horiz == XawtextScrollAlways) {
denom = GetWidestLine(ctx);
if (denom <= 0)
denom = (int)XtWidth(ctx) - RHMargins(ctx);
if (denom <= 0)
denom = 1;
widest = ((int)XtWidth(ctx) - RHMargins(ctx)) / denom;
first = ctx->text.r_margin.left - ctx->text.left_margin;
first /= denom;
XawScrollbarSetThumb(ctx->text.hbar, first, widest);
}
}
static void
DoCopyArea(TextWidget ctx, int src_x, int src_y,
unsigned int width, unsigned int height, int dst_x, int dst_y)
{
int x1, y1, x2, y2;
x1 = ctx->text.r_margin.left;
y1 = ctx->text.r_margin.top;
x2 = XtWidth(ctx) - ctx->text.r_margin.right;
y2 = XtHeight(ctx) - ctx->text.r_margin.bottom;
if (x1 >= x2 || y1 >= y2)
return;
src_x = XawMax(x1, XawMin(src_x, x2));
src_y = XawMax(y1, XawMin(src_y, y2));
dst_x = XawMax(x1, XawMin(dst_x, x2));
dst_y = XawMax(y1, XawMin(dst_y, y2));
width = XawMax(0, XawMin(x2 - dst_x, (int)width));
height = XawMax(0, XawMin(y2 - dst_y, (int)height));
XCopyArea(XtDisplay(ctx), XtWindow(ctx), XtWindow(ctx), ctx->text.gc,
src_x, src_y, width, height, dst_x, dst_y);
}
void
XawTextScroll(TextWidget ctx, int vlines, int hpixels)
{
XawTextPosition top, tmp, update_from, update_to;
XawTextLineTable *lt;
Arg arglist[1];
int y0, y1, y2, count, dim, wwidth, lines = ctx->text.lt.lines;
int vwidth, vheight;
Bool scroll;
vwidth = (int)XtWidth(ctx) - RHMargins(ctx);
vheight = (int)XtHeight(ctx) - RVMargins(ctx);
lt = &ctx->text.lt;
if (!lt || vwidth <= 0 || vheight <= 0)
return;
if ((scroll = ctx->core.background_pixmap == XtUnspecifiedPixmap) == True) {
dim = lt->info[1].y - lt->info[0].y;
for (count = 1; count < lt->lines - 1; count++)
if (lt->info[count + 1].y - lt->info[count].y != dim) {
scroll = False;
break;
}
}
wwidth = GetMaxTextWidth(ctx);
if (hpixels < 0 && ctx->text.left_margin - hpixels > ctx->text.r_margin.left)
hpixels = ctx->text.left_margin - ctx->text.r_margin.left;
ctx->text.left_margin -= hpixels;
update_from = lt->top;
if (vlines < 0) {
if (IsPositionVisible(ctx, 0))
vlines = 0;
else if (ctx->text.wrap != XawtextWrapNever) {
XawTextPosition end;
int n_lines = 0;
count = -vlines;
end = lt->top;
while (n_lines < count) {
top = SrcScan(ctx->text.source, end, XawstEOL,
XawsdLeft, 2, False);
n_lines += CountLines(ctx, top, end);
end = top;
}
while (count++ < n_lines) {
tmp = top;
XawTextSinkFindPosition(ctx->text.sink, top,
ctx->text.left_margin,
wwidth,ctx->text.wrap == XawtextWrapWord,
&top, &dim, &dim);
if (tmp == top)
++top;
}
}
else
top = SrcScan(ctx->text.source, lt->top, XawstEOL,
XawsdLeft, -vlines + 1, False);
if (-vlines >= ctx->text.lt.lines)
scroll = False;
}
else if (vlines > 0) {
if (LineForPosition(ctx, ctx->text.lastPos) == 0)
vlines = 0;
if (vlines < lt->lines)
top = XawMin(lt->info[vlines].position, ctx->text.lastPos);
else if (ctx->text.wrap == XawtextWrapNever)
top = SrcScan(ctx->text.source,
SrcScan(ctx->text.source, lt->top,
XawstEOL, XawsdRight, vlines,
True),
XawstEOL, XawsdLeft, 1, False);
else {
top = lt->top;
count = 0;
while (count++ < vlines) {
tmp = top;
XawTextSinkFindPosition(ctx->text.sink, top,
ctx->text.left_margin,
wwidth, ctx->text.wrap == XawtextWrapWord,
&top, &dim, &dim);
if (tmp == top)
++top;
}
}
if (vlines >= ctx->text.lt.lines
|| lt->info[vlines].position >= ctx->text.lastPos)
scroll = False;
}
if (!vlines) {
if (hpixels) {
ClearWindow(ctx);
ctx->text.clear_to_eol = True;
}
_XawTextSetScrollBars(ctx);
return;
}
if (!hpixels && scroll) {
ctx->text.clear_to_eol = True;
FlushUpdate(ctx);
}
(void)_BuildLineTable(ctx, top, 0);
lt = &ctx->text.lt;
if (scroll) {
for (count = 0; count < lt->lines - 1; count++)
if (lt->info[count + 1].y - lt->info[count].y != dim) {
scroll = False;
break;
}
}
XtSetArg(arglist[0], XtNinsertPosition, lt->top + lt->lines);
_XawImSetValues((Widget)ctx, arglist, 1);
if (hpixels || !scroll || lines != lt->lines)
return;
(void)XmuScanlineXor(ctx->text.update, ctx->text.update);
if (vlines < 0 && IsPositionVisible(ctx, 0))
vlines = -LineForPosition(ctx, update_from);
y0 = ctx->text.r_margin.top;
if (vlines < 0) {
update_from = lt->top;
update_to = lt->info[-vlines + 1].position - 1;
y1 = lt->info[lt->lines + vlines].y;
y2 = lt->info[-vlines].y;
DoCopyArea(ctx, ctx->text.r_margin.left, y0, vwidth,
y1 - y0,
ctx->text.r_margin.left, y2);
}
else {
update_from = lt->info[lt->lines - vlines].position;
update_to = lt->info[lt->lines].position;
y1 = lt->info[lt->lines - vlines].y;
y2 = lt->info[vlines].y;
DoCopyArea(ctx, ctx->text.r_margin.left, y2,
vwidth, lt->info[lt->lines].y - y2,
ctx->text.r_margin.left, y0);
}
_XawTextNeedsUpdating(ctx, update_from, update_to);
ctx->text.clear_to_eol = True;
}
void
_XawTextVScroll(TextWidget ctx, int n)
{
XawTextScroll(ctx, n, 0);
}
static void
HScroll(Widget w, XtPointer closure, XtPointer callData)
{
TextWidget ctx = (TextWidget)closure;
long pixels = (long)callData;
if (pixels > 0) {
long max;
max = (int)GetWidestLine(ctx) + ctx->text.left_margin -
ctx->text.r_margin.left;
max = XawMax(0, max);
pixels = XawMin(pixels, max);
}
if (pixels) {
_XawTextPrepareToUpdate(ctx);
XawTextScroll(ctx, 0, pixels);
_XawTextExecuteUpdate(ctx);
}
}
static void
HJump(Widget w, XtPointer closure, XtPointer callData)
{
TextWidget ctx = (TextWidget)closure;
float percent = *(float *)callData;
long pixels;
pixels = ctx->text.left_margin -
(ctx->text.r_margin.left - (int)(percent * GetWidestLine(ctx)));
HScroll(w, (XtPointer)ctx, (XtPointer)pixels);
}
static void
UpdateTextInLine(TextWidget ctx, int line, int x1, int x2)
{
XawTextLineTableEntry *lt = ctx->text.lt.info + line;
XawTextPosition left, right;
int from_x, width, height;
if (lt->position >= ctx->text.lastPos
|| ctx->text.left_margin > x2
|| (int)lt->textWidth + ctx->text.left_margin < x1) {
if (ctx->text.clear_to_eol)
_XawTextNeedsUpdating(ctx, lt->position, lt->position + 1);
return;
}
from_x = ctx->text.left_margin;
XawTextSinkFindPosition(ctx->text.sink, lt->position,
from_x, x1 - from_x,
False, &left, &width, &height);
if (line == ctx->text.lt.lines)
right = -1;
else if (x2 >= lt->textWidth - from_x)
right = lt[1].position - 1;
else {
from_x += width;
XawTextSinkFindPosition(ctx->text.sink, left,
from_x, x2 - from_x,
False, &right, &width, &height);
}
if ((right < 0) || (right + 1 <= lt[1].position))
++right;
_XawTextNeedsUpdating(ctx, left, right);
}
static void
VScroll(Widget w, XtPointer closure, XtPointer callData)
{
TextWidget ctx = (TextWidget)closure;
long height, lines = (long)callData;
height = XtHeight(ctx) - VMargins(ctx);
if (height < 1)
height = 1;
lines = (lines * ctx->text.lt.lines) / height;
_XawTextPrepareToUpdate(ctx);
XawTextScroll(ctx, lines, 0);
_XawTextExecuteUpdate(ctx);
}
static void
VJump(Widget w, XtPointer closure, XtPointer callData)
{
float percent = *(float *)callData;
TextWidget ctx = (TextWidget)closure;
XawTextPosition top, last, position, tmp;
XawTextLineTable *lt = &(ctx->text.lt);
int dim, vlines = 0, wwidth = GetMaxTextWidth(ctx);
Bool scroll = True;
position = percent * ctx->text.lastPos;
top = lt->top;
if (!lt->lines || (position >= lt->top && position < lt->info[1].position)) {
_XawTextSetScrollBars(ctx);
return;
}
#ifndef OLDXAW
ctx->text.lt.base_line = -1;
#endif
if (position > lt->top) {
if (position > lt->top && position < lt->info[lt->lines].position)
vlines = LineForPosition(ctx, position);
else {
scroll = False;
top = SrcScan(ctx->text.source, position, XawstEOL,
XawsdLeft, 1, False);
if (ctx->text.wrap != XawtextWrapNever) {
last = top;
while (last < position) {
tmp = last;
XawTextSinkFindPosition(ctx->text.sink, last,
ctx->text.left_margin, wwidth,
ctx->text.wrap == XawtextWrapWord,
&last, &dim, &dim);
if (last == tmp)
++last;
if (last < position)
top = last;
}
}
}
}
else {
while (top > position) {
last = top;
top = SrcScan(ctx->text.source, top, XawstEOL,
XawsdLeft, 2, False);
vlines -= CountLines(ctx, top, last);
if (-vlines >= ctx->text.lt.lines) {
scroll = False;
top = SrcScan(ctx->text.source, position, XawstEOL,
XawsdLeft, 1, False);
break;
}
}
if (ctx->text.wrap != XawtextWrapNever) {
last = top;
while (last < position) {
tmp = last;
XawTextSinkFindPosition(ctx->text.sink, last,
ctx->text.left_margin,
wwidth,
ctx->text.wrap == XawtextWrapWord,
&last, &dim, &dim);
if (last == tmp)
++last;
if (last < position)
top = last;
++vlines;
}
}
}
if (vlines || !scroll) {
_XawTextPrepareToUpdate(ctx);
if (scroll)
XawTextScroll(ctx, vlines, 0);
else
_BuildLineTable(ctx, top, 0);
_XawTextExecuteUpdate(ctx);
}
}
static Bool
MatchSelection(Atom selection, XawTextSelection *s)
{
Atom *match;
int count;
for (count = 0, match = s->selections; count < s->atom_count;
match++, count++)
if (*match == selection)
return (True);
return (False);
}
static Boolean
TextConvertSelection(Widget w, Atom *selection, Atom *target, Atom *type,
XtPointer *value, unsigned long *length, int *format)
{
Display *d = XtDisplay(w);
TextWidget ctx = (TextWidget)w;
Widget src = ctx->text.source;
XawTextEditType edit_mode;
Arg args[1];
XawTextSelectionSalt *salt = NULL;
XawTextSelection *s;
if (*target == XA_TARGETS(d)) {
Atom *targetP, *std_targets;
unsigned long std_length;
if (SrcCvtSel(src, selection, target, type, value, length, format))
return (True);
XtSetArg(args[0], XtNeditType, &edit_mode);
XtGetValues(src, args, ONE);
XmuConvertStandardSelection(w, ctx->text.time, selection,
target, type, (XPointer*)&std_targets,
&std_length, format);
*length = 7 + (edit_mode == XawtextEdit) + std_length;
*value = XtMalloc((unsigned)sizeof(Atom)*(*length));
targetP = *(Atom**)value;
*targetP++ = XA_STRING;
*targetP++ = XA_TEXT(d);
*targetP++ = XA_UTF8_STRING(d);
*targetP++ = XA_COMPOUND_TEXT(d);
*targetP++ = XA_LENGTH(d);
*targetP++ = XA_LIST_LENGTH(d);
*targetP++ = XA_CHARACTER_POSITION(d);
if (edit_mode == XawtextEdit) {
*targetP++ = XA_DELETE(d);
}
(void)memmove((char*)targetP, (char*)std_targets,
sizeof(Atom) * std_length);
XtFree((char*)std_targets);
*type = XA_ATOM;
*format = 32;
return (True);
}
if (SrcCvtSel(src, selection, target, type, value, length, format))
return (True);
if (MatchSelection(*selection, &ctx->text.s))
s = &ctx->text.s;
else {
for (salt = ctx->text.salt; salt; salt = salt->next)
if (MatchSelection(*selection, &salt->s))
break;
if (!salt)
return (False);
s = &salt->s;
}
if (*target == XA_STRING
|| *target == XA_TEXT(d)
|| *target == XA_UTF8_STRING(d)
|| *target == XA_COMPOUND_TEXT(d)) {
if (*target == XA_TEXT(d)) {
if (XawTextFormat(ctx, XawFmtWide))
*type = XA_COMPOUND_TEXT(d);
else
*type = XA_STRING;
}
else
*type = *target;
if (!salt) {
*value = _XawTextGetSTRING(ctx, s->left, s->right);
if (XawTextFormat(ctx, XawFmtWide)) {
XTextProperty textprop;
if (XwcTextListToTextProperty(d, (wchar_t **)value, 1,
XCompoundTextStyle, &textprop)
< Success) {
XtFree((char *)*value);
return (False);
}
XtFree((char *)*value);
*value = (XtPointer)textprop.value;
*length = textprop.nitems;
}
else
*length = strlen((char *)*value);
}
else {
*value = XtMalloc((salt->length + 1) * sizeof(unsigned char));
strcpy ((char *)*value, salt->contents);
*length = salt->length;
}
if (XawTextFormat(ctx, XawFmtWide) && *type == XA_STRING) {
XTextProperty textprop;
wchar_t **wlist;
int count;
textprop.encoding = XA_COMPOUND_TEXT(d);
textprop.value = (unsigned char *)*value;
textprop.nitems = strlen(*value);
textprop.format = 8;
if (XwcTextPropertyToTextList(d, &textprop, &wlist, &count)
< Success
|| count < 1) {
XtFree((char *)*value);
return (False);
}
XtFree((char *)*value);
if (XwcTextListToTextProperty(d, wlist, 1, XStringStyle, &textprop)
< Success) {
XwcFreeStringList((wchar_t**) wlist);
return (False);
}
*value = (XtPointer)textprop.value;
*length = textprop.nitems;
XwcFreeStringList(wlist);
} else if (*type == XA_UTF8_STRING(d)) {
XTextProperty textprop;
char **list;
int count;
textprop.encoding = XA_COMPOUND_TEXT(d);
textprop.value = (unsigned char *)*value;
textprop.nitems = strlen(*value);
textprop.format = 8;
if (Xutf8TextPropertyToTextList(d, &textprop, &list, &count)
< Success
|| count < 1) {
XtFree((char *)*value);
return (False);
}
XtFree((char *)*value);
*value = *list;
*length = strlen(*list);
XFree(list);
}
*format = 8;
return (True);
}
if ((*target == XA_LIST_LENGTH(d)) || (*target == XA_LENGTH(d))) {
long * temp;
temp = (long *)XtMalloc((unsigned)sizeof(long));
if (*target == XA_LIST_LENGTH(d))
*temp = 1L;
else
*temp = (long) (s->right - s->left);
*value = (XPointer)temp;
*type = XA_INTEGER;
*length = 1L;
*format = 32;
return (True);
}
if (*target == XA_CHARACTER_POSITION(d)) {
long * temp;
temp = (long *)XtMalloc((unsigned)(2 * sizeof(long)));
temp[0] = (long)(s->left + 1);
temp[1] = s->right;
*value = (XPointer)temp;
*type = XA_SPAN(d);
*length = 2L;
*format = 32;
return (True);
}
if (*target == XA_DELETE(d)) {
if (!salt)
_XawTextZapSelection(ctx, NULL, True);
*value = NULL;
*type = XA_NULL(d);
*length = 0;
*format = 32;
return (True);
}
if (XmuConvertStandardSelection(w, ctx->text.time, selection, target, type,
(XPointer *)value, length, format))
return (True);
return (False);
}
#define NOT_A_CUT_BUFFER -1
static int
GetCutBufferNumber(Atom atom)
{
if (atom == XA_CUT_BUFFER0) return (0);
if (atom == XA_CUT_BUFFER1) return (1);
if (atom == XA_CUT_BUFFER2) return (2);
if (atom == XA_CUT_BUFFER3) return (3);
if (atom == XA_CUT_BUFFER4) return (4);
if (atom == XA_CUT_BUFFER5) return (5);
if (atom == XA_CUT_BUFFER6) return (6);
if (atom == XA_CUT_BUFFER7) return (7);
return (NOT_A_CUT_BUFFER);
}
static void
TextLoseSelection(Widget w, Atom *selection)
{
TextWidget ctx = (TextWidget)w;
Atom *atomP;
int i;
XawTextSelectionSalt*salt, *prevSalt, *nextSalt;
atomP = ctx->text.s.selections;
for (i = 0 ; i < ctx->text.s.atom_count; i++, atomP++)
if ((*selection == *atomP)
|| (GetCutBufferNumber(*atomP) != NOT_A_CUT_BUFFER))
*atomP = (Atom)0;
while (ctx->text.s.atom_count
&& ctx->text.s.selections[ctx->text.s.atom_count - 1] == 0)
ctx->text.s.atom_count--;
atomP = ctx->text.s.selections;
for (i = 0 ; i < ctx->text.s.atom_count; i++, atomP++)
if (*atomP == (Atom)0) {
*atomP = ctx->text.s.selections[--ctx->text.s.atom_count];
while (ctx->text.s.atom_count
&& ctx->text.s.selections[ctx->text.s.atom_count-1] == 0)
ctx->text.s.atom_count--;
}
if (ctx->text.s.atom_count == 0)
ModifySelection(ctx, ctx->text.insertPos, ctx->text.insertPos);
prevSalt = 0;
for (salt = ctx->text.salt; salt; salt = nextSalt) {
atomP = salt->s.selections;
nextSalt = salt->next;
for (i = 0 ; i < salt->s.atom_count; i++, atomP++)
if (*selection == *atomP)
*atomP = (Atom)0;
while (salt->s.atom_count
&& salt->s.selections[salt->s.atom_count-1] == 0)
salt->s.atom_count--;
atomP = salt->s.selections;
for (i = 0 ; i < salt->s.atom_count; i++, atomP++)
if (*atomP == (Atom)0) {
*atomP = salt->s.selections[--salt->s.atom_count];
while (salt->s.atom_count
&& salt->s.selections[salt->s.atom_count-1] == 0)
salt->s.atom_count--;
}
if (salt->s.atom_count == 0) {
XtFree ((char *) salt->s.selections);
XtFree (salt->contents);
if (prevSalt)
prevSalt->next = nextSalt;
else
ctx->text.salt = nextSalt;
XtFree((char *)salt);
}
else
prevSalt = salt;
}
}
void
_XawTextSaltAwaySelection(TextWidget ctx, Atom *selections, int num_atoms)
{
XawTextSelectionSalt *salt;
int i, j;
for (i = 0; i < num_atoms; i++)
TextLoseSelection((Widget)ctx, selections + i);
if (num_atoms == 0)
return;
salt = (XawTextSelectionSalt *)
XtMalloc((unsigned)sizeof(XawTextSelectionSalt));
if (!salt)
return;
salt->s.selections = (Atom *)XtMalloc((unsigned)(num_atoms * sizeof(Atom)));
if (!salt->s.selections) {
XtFree((char *)salt);
return;
}
salt->s.left = ctx->text.s.left;
salt->s.right = ctx->text.s.right;
salt->s.type = ctx->text.s.type;
salt->contents = _XawTextGetSTRING(ctx, ctx->text.s.left, ctx->text.s.right);
if (XawTextFormat(ctx, XawFmtWide)) {
XTextProperty textprop;
if (XwcTextListToTextProperty(XtDisplay((Widget)ctx),
(wchar_t**)(&(salt->contents)), 1,
XCompoundTextStyle,
&textprop) < Success) {
XtFree(salt->contents);
salt->length = 0;
return;
}
XtFree(salt->contents);
salt->contents = (char *)textprop.value;
salt->length = textprop.nitems;
}
else
salt->length = strlen (salt->contents);
salt->next = ctx->text.salt;
ctx->text.salt = salt;
j = 0;
for (i = 0; i < num_atoms; i++) {
if (GetCutBufferNumber (selections[i]) == NOT_A_CUT_BUFFER) {
salt->s.selections[j++] = selections[i];
XtOwnSelection((Widget)ctx, selections[i], ctx->text.time,
TextConvertSelection, TextLoseSelection, NULL);
}
}
salt->s.atom_count = j;
}
static void
_SetSelection(TextWidget ctx, XawTextPosition left, XawTextPosition right,
Atom *selections, Cardinal count)
{
#ifndef OLDXAW
Cardinal i;
XawTextPosition pos;
TextSrcObject src = (TextSrcObject)ctx->text.source;
for (i = 0; i < src->textSrc.num_text; i++) {
TextWidget tw = (TextWidget)src->textSrc.text[i];
Bool needs_updating = tw->text.old_insert < 0;
Bool showposition = tw->text.showposition;
if (needs_updating) {
tw->text.showposition = False;
_XawTextPrepareToUpdate(tw);
}
#else
TextWidget tw = ctx;
XawTextPosition pos;
#endif
if (left < tw->text.s.left) {
pos = Min(right, tw->text.s.left);
_XawTextNeedsUpdating(tw, left, pos);
}
if (left > tw->text.s.left) {
pos = Min(left, tw->text.s.right);
_XawTextNeedsUpdating(tw, tw->text.s.left, pos);
}
if (right < tw->text.s.right) {
pos = Max(right, tw->text.s.left);
_XawTextNeedsUpdating(tw, pos, tw->text.s.right);
}
if (right > tw->text.s.right) {
pos = Max(left, tw->text.s.right);
_XawTextNeedsUpdating(tw, pos, right);
}
tw->text.s.left = left;
tw->text.s.right = right;
#ifndef OLDXAW
if (needs_updating) {
_XawTextExecuteUpdate(tw);
tw->text.showposition = showposition;
}
}
#endif
SrcSetSelection(ctx->text.source, left, right,
(count == 0) ? None : selections[0]);
if (left < right) {
Widget w = (Widget)ctx;
int buffer;
while (count) {
Atom selection = selections[--count];
if ((buffer = GetCutBufferNumber(selection)) != NOT_A_CUT_BUFFER) {
unsigned char *ptr, *tptr;
unsigned int amount, max_len = MAX_CUT_LEN(XtDisplay(w));
unsigned long len;
tptr= ptr= (unsigned char *)_XawTextGetSTRING(ctx,
ctx->text.s.left,
ctx->text.s.right);
if (XawTextFormat(ctx, XawFmtWide)) {
XTextProperty textprop;
if (XwcTextListToTextProperty(XtDisplay(w), (wchar_t**)&ptr,
1, XStringStyle, &textprop)
< Success){
XtFree((char *)ptr);
return;
}
XtFree((char *)ptr);
tptr = ptr = textprop.value;
}
if (buffer == 0) {
_CreateCutBuffers(XtDisplay(w));
XRotateBuffers(XtDisplay(w), 1);
}
amount = Min ((len = strlen((char *)ptr)), max_len);
XChangeProperty(XtDisplay(w), RootWindow(XtDisplay(w), 0),
selection, XA_STRING, 8, PropModeReplace,
ptr, amount);
while (len > max_len) {
len -= max_len;
tptr += max_len;
amount = Min (len, max_len);
XChangeProperty(XtDisplay(w), RootWindow(XtDisplay(w), 0),
selection, XA_STRING, 8, PropModeAppend,
tptr, amount);
}
XtFree ((char *)ptr);
}
else
XtOwnSelection(w, selection, ctx->text.time, TextConvertSelection,
TextLoseSelection, NULL);
}
}
else
XawTextUnsetSelection((Widget)ctx);
}
#ifndef OLDXAW
void
_XawTextSetLineAndColumnNumber(TextWidget ctx, Bool force)
{
int line_number, column_number;
if (ctx->text.old_insert != ctx->text.insertPos &&
ctx->text.lt.base_line < 0) {
ctx->text.lt.base_line = 0;
(void)_BuildLineTable(ctx, ctx->text.lt.top, 0);
}
line_number = ResolveLineNumber(ctx);
column_number = ResolveColumnNumber(ctx);
if (force || (ctx->text.column_number != column_number
|| ctx->text.line_number != line_number)) {
XawTextPositionInfo info;
ctx->text.line_number = info.line_number = line_number;
ctx->text.column_number = info.column_number = column_number;
info.insert_position = ctx->text.insertPos;
info.last_position = ctx->text.lastPos;
info.overwrite_mode = ctx->text.overwrite;
XtCallCallbacks((Widget)ctx, XtNpositionCallback, (XtPointer)&info);
}
}
static int
ResolveColumnNumber(TextWidget ctx)
{
Widget src = ctx->text.source;
short column_number = 0;
XawTextPosition position;
XawTextBlock block;
unsigned long format = _XawTextFormat(ctx);
TextSinkObject sink = (TextSinkObject)ctx->text.sink;
short *char_tabs = sink->text_sink.char_tabs;
int tab_count = sink->text_sink.tab_count;
int tab_index = 0, tab_column = 0, tab_base = 0;
if (ctx->text.lt.base_line < 1)
return (ctx->text.column_number);
position = SrcScan(src, ctx->text.insertPos, XawstEOL, XawsdLeft, 1, False);
XawTextSourceRead(src, position, &block, ctx->text.insertPos - position);
for (; position < ctx->text.insertPos; position++) {
if (position - block.firstPos >= block.length)
XawTextSourceRead(src, position, &block, ctx->text.insertPos - position);
if ((format == XawFmt8Bit && block.ptr[position - block.firstPos] == '\t') ||
(format == XawFmtWide && ((wchar_t*)block.ptr)[position - block.firstPos] == _Xaw_atowc(XawTAB))) {
while (tab_base + tab_column <= column_number) {
if (tab_count) {
for (; tab_index < tab_count; ++tab_index)
if (tab_base + char_tabs[tab_index] > column_number) {
tab_column = char_tabs[tab_index];
break;
}
if (tab_index >= tab_count) {
tab_base += char_tabs[tab_count - 1];
tab_column = tab_index = 0;
}
}
else
tab_column += DEFAULT_TAB_SIZE;
}
column_number = tab_base + tab_column;
}
else
++column_number;
if (column_number >= 16384) {
column_number = 16383;
break;
}
}
return (column_number);
}
#endif
void
_XawTextSourceChanged(Widget w, XawTextPosition left, XawTextPosition right,
XawTextBlock *block, int lines)
{
TextWidget ctx = (TextWidget)w;
Widget src = ctx->text.source;
XawTextPosition update_from, update_to, top;
Boolean update_disabled;
int delta, line, line_from;
if (left < ctx->text.old_insert) {
XawTextPosition old_insert = ctx->text.old_insert;
if (right < ctx->text.old_insert)
old_insert -= right - left;
else
old_insert = left;
ctx->text.insertPos = old_insert + block->length;
}
#ifndef OLDXAW
if (left <= ctx->text.lt.top) {
if (left + block->length - (right - left) < ctx->text.lt.top) {
ctx->text.source_changed = SRC_CHANGE_BEFORE;
ctx->text.lt.base_line += lines;
}
else
ctx->text.source_changed = SRC_CHANGE_OVERLAP;
}
else
ctx->text.source_changed = SRC_CHANGE_AFTER;
#endif
update_from = left;
update_to = left + block->length;
update_to = SrcScan(src, update_to, XawstEOL, XawsdRight, 1, False);
delta = block->length - (right - left);
if (delta < 0)
ctx->text.clear_to_eol = True;
if (update_to == update_from)
++update_to;
update_disabled = ctx->text.update_disabled;
ctx->text.update_disabled = True;
ctx->text.lastPos = XawTextGetLastPosition(ctx);
top = ctx->text.lt.info[0].position;
XawTextUnsetSelection((Widget)ctx);
if (delta) {
int i;
XmuSegment *seg;
for (seg = ctx->text.update->segment; seg; seg = seg->next) {
if (seg->x1 > (int)left)
break;
else if (seg->x2 > (int)left) {
seg->x2 += delta;
seg = seg->next;
break;
}
}
for (; seg; seg = seg->next) {
seg->x1 += delta;
seg->x2 += delta;
}
XmuOptimizeScanline(ctx->text.update);
for (i = 0; i <= ctx->text.lt.lines; i++)
if (ctx->text.lt.info[i].position > left)
break;
for (; i <= ctx->text.lt.lines; i++)
ctx->text.lt.info[i].position += delta;
}
if (top != ctx->text.lt.info[0].position) {
line_from = line = 0;
ctx->text.lt.top = top = SrcScan(src, ctx->text.lt.info[0].position,
XawstEOL, XawsdLeft, 1, False);
update_from = top;
}
else {
line_from = line = LineForPosition(ctx, update_from + delta);
top = ctx->text.lt.info[line].position;
}
if (line > 0 && ctx->text.wrap == XawtextWrapWord) {
--line;
top = ctx->text.lt.info[line].position;
}
(void)_BuildLineTable(ctx, top, line);
if (ctx->text.wrap == XawtextWrapWord) {
if (line_from != LineForPosition(ctx, update_from)
|| line_from != LineForPosition(ctx, update_to)) {
ctx->text.clear_to_eol = True;
update_from = SrcScan(src, update_from,
XawstWhiteSpace, XawsdLeft, 1, True);
if (update_to >= ctx->text.lastPos)
++update_to;
}
}
else if (!ctx->text.clear_to_eol) {
if (LineForPosition(ctx, update_from)
!= LineForPosition(ctx, update_to))
ctx->text.clear_to_eol = True;
}
_XawTextNeedsUpdating(ctx, update_from, update_to);
ctx->text.update_disabled = update_disabled;
}
int
_XawTextReplace(TextWidget ctx, XawTextPosition left, XawTextPosition right,
XawTextBlock *block)
{
Arg args[1];
Widget src;
XawTextEditType edit_mode;
if (left == right && block->length == 0)
return (XawEditDone);
src = ctx->text.source;
XtSetArg(args[0], XtNeditType, &edit_mode);
XtGetValues(src, args, 1);
if (edit_mode == XawtextAppend) {
if (block->length == 0)
return (XawEditError);
ctx->text.insertPos = ctx->text.lastPos;
}
#ifndef OLDXAW
return (SrcReplace(src, left, right, block));
#else
if (SrcReplace(src, left, right, block) == XawEditDone) {
_XawTextSourceChanged((Widget)ctx, left, right, block, 0);
return (XawEditDone);
}
return (XawEditError);
#endif
}
static void
OldDisplayText(Widget w, XawTextPosition left, XawTextPosition right)
{
static XmuSegment segment;
static XmuScanline next;
static XmuScanline scanline = {0, &segment, &next};
static XmuArea area = {&scanline};
TextWidget ctx = (TextWidget)w;
int x, y, line;
XawTextPosition start, end, last, final;
XmuScanline *scan;
XmuSegment *seg;
XmuArea *clip = NULL;
Bool cleol = ctx->text.clear_to_eol;
Bool has_selection = ctx->text.s.right > ctx->text.s.left;
left = left < ctx->text.lt.top ? ctx->text.lt.top : left;
if (left > right || !LineAndXYForPosition(ctx, left, &line, &x, &y))
return;
last = XawTextGetLastPosition(ctx);
segment.x2 = (int)XtWidth(ctx) - ctx->text.r_margin.right;
if (cleol)
clip = XmuCreateArea();
for (start = left; start < right && line < ctx->text.lt.lines; line++) {
if ((end = ctx->text.lt.info[line + 1].position) > right)
end = right;
final = end;
if (end > last)
end = last;
if (end > start) {
if (!has_selection
|| (start >= ctx->text.s.right || end <= ctx->text.s.left))
_XawTextSinkDisplayText(ctx->text.sink, x, y, start, end, False);
else if (start >= ctx->text.s.left && end <= ctx->text.s.right)
_XawTextSinkDisplayText(ctx->text.sink, x, y, start, end, True);
else {
OldDisplayText(w, start, ctx->text.s.left);
OldDisplayText(w, Max(start, ctx->text.s.left),
Min(end, ctx->text.s.right));
OldDisplayText(w, ctx->text.s.right, end);
}
}
x = ctx->text.left_margin;
if (cleol) {
segment.x1 = ctx->text.lt.info[line].textWidth + x;
if (XmuValidSegment(&segment)) {
scanline.y = y;
next.y = ctx->text.lt.info[line + 1].y;
XmuAreaOr(clip, &area);
}
}
start = final;
y = ctx->text.lt.info[line + 1].y;
}
if (cleol) {
for (scan = clip->scanline; scan && scan->next; scan = scan->next)
for (seg = scan->segment; seg; seg = seg->next)
SinkClearToBG(ctx->text.sink,
seg->x1, scan->y,
seg->x2 - seg->x1, scan->next->y - scan->y);
XmuDestroyArea(clip);
}
}
#ifndef OLDXAW
static void
DisplayText(Widget w, XawTextPosition left, XawTextPosition right)
{
static XmuSegment segment;
static XmuScanline next;
static XmuScanline scanline = {0, &segment, &next};
static XmuArea area = {&scanline};
TextWidget ctx = (TextWidget)w;
int y, line;
XawTextPosition from, to, lastPos;
Bool cleol = ctx->text.clear_to_eol;
Bool has_selection = ctx->text.s.right > ctx->text.s.left;
XawTextPaintList *paint_list;
left = left < ctx->text.lt.top ? ctx->text.lt.top : left;
if (left > right || !IsPositionVisible(ctx, left))
return;
line = LineForPosition(ctx, left);
y = ctx->text.lt.info[line].y;
segment.x2 = (int)XtWidth(ctx) - ctx->text.r_margin.right;
lastPos = XawTextGetLastPosition(ctx);
paint_list = ((TextSinkObject)ctx->text.sink)->text_sink.paint;
for (from = left; from < right && line < ctx->text.lt.lines; line++) {
if ((to = ctx->text.lt.info[line + 1].position) > right)
to = right;
if (to > lastPos)
to = lastPos;
if (from < to) {
if (!has_selection
|| (from >= ctx->text.s.right || to <= ctx->text.s.left))
XawTextSinkPreparePaint(ctx->text.sink, y, line, from, to, False);
else if (from >= ctx->text.s.left && to <= ctx->text.s.right)
XawTextSinkPreparePaint(ctx->text.sink, y, line, from, to, True);
else {
XawTextSinkPreparePaint(ctx->text.sink, y, line, from,
ctx->text.s.left, False);
XawTextSinkPreparePaint(ctx->text.sink, y, line,
XawMax(from, ctx->text.s.left),
XawMin(to, ctx->text.s.right), True);
XawTextSinkPreparePaint(ctx->text.sink, y, line,
ctx->text.s.right, to, False);
}
}
if (cleol) {
segment.x1 = ctx->text.lt.info[line].textWidth + ctx->text.left_margin;
if (XmuValidSegment(&segment)) {
scanline.y = y;
next.y = ctx->text.lt.info[line + 1].y;
XmuAreaOr(paint_list->clip, &area);
}
}
y = ctx->text.lt.info[line + 1].y;
from = to;
}
if (cleol && line >= ctx->text.lt.lines) {
segment.x1 = ctx->text.left_margin;
if (XmuValidSegment(&segment)) {
scanline.y = y;
next.y = (int)XtHeight(ctx) - (int)ctx->text.margin.bottom;
XmuAreaOr(paint_list->clip, &area);
}
}
}
#endif
static void
DoSelection(TextWidget ctx, XawTextPosition pos, Time time, Bool motion)
{
XawTextPosition newLeft, newRight;
XawTextSelectType newType, *sarray;
Widget src = ctx->text.source;
if (motion)
newType = ctx->text.s.type;
else {
if ((abs((long) time - (long) ctx->text.lasttime) < MULTI_CLICK_TIME)
&& (pos >= ctx->text.s.left && pos <= ctx->text.s.right)) {
sarray = ctx->text.sarray;
for (; *sarray != XawselectNull && *sarray != ctx->text.s.type;
sarray++)
;
if (*sarray == XawselectNull)
newType = *(ctx->text.sarray);
else {
newType = *(sarray + 1);
if (newType == XawselectNull)
newType = *(ctx->text.sarray);
}
}
else
newType = *(ctx->text.sarray);
ctx->text.lasttime = time;
}
switch (newType) {
case XawselectPosition:
newLeft = newRight = pos;
break;
case XawselectChar:
newLeft = pos;
newRight = SrcScan(src, pos, XawstPositions, XawsdRight, 1, False);
break;
case XawselectWord:
case XawselectParagraph:
case XawselectAlphaNumeric: {
XawTextScanType stype;
if (newType == XawselectWord)
stype = XawstWhiteSpace;
else if (newType == XawselectParagraph)
stype = XawstParagraph;
else
stype = XawstAlphaNumeric;
newRight = SrcScan(ctx->text.source, pos, stype,
XawsdRight, 1, False);
newRight = SrcScan(ctx->text.source, newRight, stype,
XawsdLeft, 1, False);
if (pos != newRight)
newLeft = SrcScan(ctx->text.source, pos, stype,
XawsdLeft, 1, False);
else
newLeft = pos;
newLeft =SrcScan(ctx->text.source, newLeft, stype,
XawsdRight, 1, False);
if (newLeft > newRight) {
XawTextPosition temp = newLeft;
newLeft = newRight;
newRight = temp;
}
} break;
case XawselectLine:
newLeft = SrcScan(src, pos, XawstEOL, XawsdLeft, 1, False);
newRight = SrcScan(src, pos, XawstEOL, XawsdRight, 1, False);
break;
case XawselectAll:
newLeft = SrcScan(src, pos, XawstAll, XawsdLeft, 1, False);
newRight = SrcScan(src, pos, XawstAll, XawsdRight, 1, False);
break;
default:
XtAppWarning(XtWidgetToApplicationContext((Widget) ctx),
"Text Widget: empty selection array.");
return;
}
if (newLeft != ctx->text.s.left || newRight != ctx->text.s.right
|| newType != ctx->text.s.type) {
ModifySelection(ctx, newLeft, newRight);
if (pos - ctx->text.s.left < ctx->text.s.right - pos)
ctx->text.insertPos = newLeft;
else
ctx->text.insertPos = newRight;
ctx->text.s.type = newType;
}
if (!motion) {
ctx->text.origSel.type = ctx->text.s.type;
ctx->text.origSel.left = ctx->text.s.left;
ctx->text.origSel.right = ctx->text.s.right;
if (pos >= ctx->text.s.left + (ctx->text.s.right - ctx->text.s.left) / 2)
ctx->text.extendDir = XawsdRight;
else
ctx->text.extendDir = XawsdLeft;
}
}
static void
ExtendSelection(TextWidget ctx, XawTextPosition pos, Bool motion)
{
XawTextScanDirection dir;
if (!motion) {
if (ctx->text.s.left == ctx->text.s.right)
ctx->text.s.left = ctx->text.s.right = ctx->text.insertPos;
else {
ctx->text.origSel.left = ctx->text.s.left;
ctx->text.origSel.right = ctx->text.s.right;
}
ctx->text.origSel.type = ctx->text.s.type;
if (pos >= ctx->text.s.left + (ctx->text.s.right - ctx->text.s.left) / 2)
ctx->text.extendDir = XawsdRight;
else
ctx->text.extendDir = XawsdLeft;
}
else
if ((ctx->text.extendDir == XawsdRight &&
pos <= ctx->text.origSel.left) ||
(ctx->text.extendDir == XawsdLeft &&
pos >= ctx->text.origSel.right)) {
ctx->text.extendDir = (ctx->text.extendDir == XawsdRight) ?
XawsdLeft : XawsdRight;
ModifySelection(ctx, ctx->text.origSel.left, ctx->text.origSel.right);
}
dir = ctx->text.extendDir;
switch (ctx->text.s.type) {
case XawselectWord:
case XawselectParagraph:
case XawselectAlphaNumeric: {
XawTextPosition left_pos, right_pos;
XawTextScanType stype;
if (ctx->text.s.type == XawselectWord)
stype = XawstWhiteSpace;
else if (ctx->text.s.type == XawselectParagraph)
stype = XawstParagraph;
else
stype = XawstAlphaNumeric;
right_pos = SrcScan(ctx->text.source, pos, stype,
XawsdRight, 1, False);
right_pos =SrcScan(ctx->text.source, right_pos, stype,
XawsdLeft, 1, False);
if (pos != right_pos)
left_pos = SrcScan(ctx->text.source, pos, stype,
XawsdLeft, 1, False);
else
left_pos = pos;
left_pos =SrcScan(ctx->text.source, left_pos, stype,
XawsdRight, 1, False);
if (dir == XawsdLeft)
pos = Min(left_pos, right_pos);
else
pos = Max(left_pos, right_pos);
} break;
case XawselectLine:
pos = SrcScan(ctx->text.source, pos, XawstEOL,
dir, 1, dir == XawsdRight);
break;
case XawselectAll:
pos = ctx->text.insertPos;
case XawselectPosition:
default:
break;
}
if (dir == XawsdRight)
ModifySelection(ctx, ctx->text.s.left, pos);
else
ModifySelection(ctx, pos, ctx->text.s.right);
ctx->text.insertPos = pos;
}
void
_XawTextClearAndCenterDisplay(TextWidget ctx)
{
int left_margin = ctx->text.left_margin;
Bool visible = IsPositionVisible(ctx, ctx->text.insertPos);
_XawTextShowPosition(ctx);
if (XtIsRealized((Widget)ctx) && visible &&
left_margin == ctx->text.left_margin) {
int insert_line = LineForPosition(ctx, ctx->text.insertPos);
int scroll_by = insert_line - (ctx->text.lt.lines >> 1);
Boolean clear_to_eol = ctx->text.clear_to_eol;
XawTextScroll(ctx, scroll_by, 0);
SinkClearToBG(ctx->text.sink, 0, 0, XtWidth(ctx), XtHeight(ctx));
ClearWindow(ctx);
clear_to_eol = ctx->text.clear_to_eol;
ctx->text.clear_to_eol = False;
FlushUpdate(ctx);
ctx->text.clear_to_eol = clear_to_eol;
}
}
static void
DisplayTextWindow(Widget w)
{
TextWidget ctx = (TextWidget)w;
_XawTextBuildLineTable(ctx, ctx->text.lt.top, False);
ClearWindow(ctx);
}
static void
TextSinkResize(Widget w)
{
if (w && XtClass(w)->core_class.resize)
XtClass(w)->core_class.resize(w);
}
void
_XawTextCheckResize(TextWidget ctx)
{
return;
}
Atom *
_XawTextSelectionList(TextWidget ctx, String *list, Cardinal nelems)
{
Atom *sel = ctx->text.s.selections;
Display *dpy = XtDisplay((Widget)ctx);
int n;
if (nelems > (Cardinal)ctx->text.s.array_size) {
sel = (Atom *)XtRealloc((char *)sel, sizeof(Atom) * nelems);
ctx->text.s.array_size = nelems;
ctx->text.s.selections = sel;
}
for (n = nelems; --n >= 0; sel++, list++)
*sel = XInternAtom(dpy, *list, False);
ctx->text.s.atom_count = nelems;
return (ctx->text.s.selections);
}
void
_XawTextSetSelection(TextWidget ctx, XawTextPosition l, XawTextPosition r,
String *list, Cardinal nelems)
{
if (nelems == 1 && !strcmp (list[0], "none"))
return;
if (nelems == 0) {
String defaultSel = "PRIMARY";
list = &defaultSel;
nelems = 1;
}
_SetSelection(ctx, l, r, _XawTextSelectionList(ctx, list, nelems), nelems);
}
static void
ModifySelection(TextWidget ctx, XawTextPosition left, XawTextPosition right)
{
if (left == right)
ctx->text.insertPos = left;
_SetSelection(ctx, left, right, NULL, 0);
}
void
_XawTextAlterSelection(TextWidget ctx, XawTextSelectionMode mode,
XawTextSelectionAction action, String *params,
Cardinal *num_params)
{
XawTextPosition position;
Boolean flag;
if (ctx->text.search != NULL)
ctx->text.search->selection_changed = True;
position = PositionForXY(ctx, (int) ctx->text.ev_x, (int) ctx->text.ev_y);
flag = (action != XawactionStart);
if (mode == XawsmTextSelect)
DoSelection(ctx, position, ctx->text.time, flag);
else
ExtendSelection (ctx, position, flag);
if (action == XawactionEnd)
_XawTextSetSelection(ctx, ctx->text.s.left, ctx->text.s.right,
params, *num_params);
}
static void
UpdateTextInRectangle(TextWidget ctx, XRectangle *rect)
{
XawTextLineTable *lt;
int line, y1, y2, x2;
y1 = rect->y;
y2 = y1 + rect->height;
x2 = rect->x + rect->width;
for (line = 0, lt = &ctx->text.lt; line < lt->lines; line++)
if (lt->info[line + 1].y > y1)
break;
for (; line <= lt->lines; line++) {
if (lt->info[line].y > y2)
break;
UpdateTextInLine(ctx, line, rect->x, x2);
}
}
static void
XawTextExpose(Widget w, XEvent *event, Region region)
{
TextWidget ctx = (TextWidget)w;
Boolean clear_to_eol;
XRectangle expose;
if (event->type == Expose) {
expose.x = event->xexpose.x;
expose.y = event->xexpose.y;
expose.width = event->xexpose.width;
expose.height = event->xexpose.height;
}
else if (event->type == GraphicsExpose) {
expose.x = event->xgraphicsexpose.x;
expose.y = event->xgraphicsexpose.y;
expose.width = event->xgraphicsexpose.width;
expose.height = event->xgraphicsexpose.height;
}
else
return;
_XawTextPrepareToUpdate(ctx);
if (Superclass->core_class.expose)
(*Superclass->core_class.expose)(w, event, region);
clear_to_eol = ctx->text.clear_to_eol;
ctx->text.clear_to_eol = False;
UpdateTextInRectangle(ctx, &expose);
XawTextSinkGetCursorBounds(ctx->text.sink, &expose);
UpdateTextInRectangle(ctx, &expose);
SinkClearToBG(ctx->text.sink, expose.x, expose.y,
expose.width, expose.height);
_XawTextExecuteUpdate(ctx);
ctx->text.clear_to_eol = clear_to_eol;
}
void
_XawTextPrepareToUpdate(TextWidget ctx)
{
if (ctx->text.old_insert < 0) {
InsertCursor((Widget)ctx, XawisOff);
ctx->text.showposition = False;
ctx->text.old_insert = ctx->text.insertPos;
ctx->text.clear_to_eol = False;
#ifndef OLDXAW
ctx->text.source_changed = SRC_CHANGE_NONE;
#endif
}
}
static void
FlushUpdate(TextWidget ctx)
{
XmuSegment *seg;
void (*display_text)(Widget, XawTextPosition, XawTextPosition);
if (XtIsRealized((Widget)ctx)) {
ctx->text.s.right = XawMin(ctx->text.s.right, ctx->text.lastPos);
ctx->text.s.left = XawMin(ctx->text.s.left, ctx->text.s.right);
#ifndef OLDXAW
if (XawTextSinkBeginPaint(ctx->text.sink) == False)
#endif
display_text = OldDisplayText;
#ifndef OLDXAW
else
display_text = DisplayText;
#endif
for (seg = ctx->text.update->segment; seg; seg = seg->next)
(*display_text)((Widget)ctx,
(XawTextPosition)seg->x1,
(XawTextPosition)seg->x2);
#ifndef OLDXAW
if (display_text != OldDisplayText) {
XawTextSinkDoPaint(ctx->text.sink);
XawTextSinkEndPaint(ctx->text.sink);
}
#endif
}
(void)XmuScanlineXor(ctx->text.update, ctx->text.update);
}
static int
CountLines(TextWidget ctx, XawTextPosition left, XawTextPosition right)
{
if (ctx->text.wrap == XawtextWrapNever || left >= right)
return (1);
else {
XawTextPosition tmp;
int dim, lines = 0, wwidth = GetMaxTextWidth(ctx);
while (left < right) {
tmp = left;
XawTextSinkFindPosition(ctx->text.sink, left,
ctx->text.left_margin,
wwidth, ctx->text.wrap == XawtextWrapWord,
&left, &dim, &dim);
++lines;
if (tmp == left)
++left;
}
return (lines);
}
}
static int
GetMaxTextWidth(TextWidget ctx)
{
XRectangle cursor;
int width;
XawTextSinkGetCursorBounds(ctx->text.sink, &cursor);
width = (int)XtWidth(ctx) - RHMargins(ctx) - cursor.width;
return (XawMax(0, width));
}
void
_XawTextShowPosition(TextWidget ctx)
{
int hpixels, vlines;
XawTextPosition first, last, top, tmp;
Bool visible, scroll;
if (!XtIsRealized((Widget)ctx))
return;
if (ctx->text.wrap == XawtextWrapNever) {
int x, vwidth, distance, dim;
XRectangle rect;
vwidth = (int)XtWidth(ctx) - RHMargins(ctx);
last = SrcScan(ctx->text.source, ctx->text.insertPos,
XawstEOL, XawsdLeft, 1, False);
XawTextSinkFindDistance(ctx->text.sink, last,
ctx->text.left_margin,
ctx->text.insertPos,
&distance, &first, &dim);
XawTextSinkGetCursorBounds(ctx->text.sink, &rect);
x = ctx->text.left_margin - ctx->text.r_margin.left;
if (x + distance + rect.width > vwidth)
hpixels = x + distance + rect.width - vwidth + (vwidth >> 2);
else if (x + distance < 0)
hpixels = x + distance - (vwidth >> 2);
else
hpixels = 0;
}
else
hpixels = 0;
visible = IsPositionVisible(ctx, ctx->text.insertPos);
if (!hpixels && visible)
return;
scroll = ctx->core.background_pixmap == XtUnspecifiedPixmap && !hpixels;
vlines = 0;
first = ctx->text.lt.top;
if (visible)
top = ctx->text.lt.top;
else {
top = SrcScan(ctx->text.source, ctx->text.insertPos,
XawstEOL, XawsdLeft, 1, False);
if (ctx->text.wrap != XawtextWrapNever) {
int dim, vwidth = GetMaxTextWidth(ctx);
last = top;
while (1) {
tmp = last;
XawTextSinkFindPosition(ctx->text.sink, last,
ctx->text.left_margin, vwidth,
ctx->text.wrap == XawtextWrapWord,
&last, &dim, &dim);
if (last == tmp)
++last;
if (last <= ctx->text.insertPos)
top = last;
else
break;
}
}
}
if (scroll) {
if (ctx->text.insertPos < first) {
while (first > top) {
last = first;
first = SrcScan(ctx->text.source, first,
XawstEOL, XawsdLeft, 2, False);
vlines -= CountLines(ctx, first, last);
if (-vlines >= ctx->text.lt.lines) {
scroll = False;
break;
}
}
}
else if (!visible) {
while (first < top) {
last = first;
first = SrcScan(ctx->text.source, first,
XawstEOL, XawsdRight, 1, True);
vlines += CountLines(ctx, last, first);
if (vlines > ctx->text.lt.lines) {
scroll = False;
break;
}
}
}
else
scroll = False;
}
if (scroll)
XawTextScroll(ctx, vlines ? vlines - (ctx->text.lt.lines >> 1) : 0, 0);
else {
ctx->text.left_margin -= hpixels;
if (ctx->text.left_margin > ctx->text.r_margin.left)
ctx->text.left_margin = ctx->text.margin.left =
ctx->text.r_margin.left;
if (!visible) {
vlines = ctx->text.lt.lines >> 1;
if (vlines)
top = SrcScan(ctx->text.source, ctx->text.insertPos,
XawstEOL, XawsdLeft, vlines + 1, False);
if (ctx->text.wrap != XawtextWrapNever) {
int dim;
int n_lines = CountLines(ctx, top, ctx->text.insertPos);
int vwidth = GetMaxTextWidth(ctx);
while (n_lines-- > vlines) {
tmp = top;
XawTextSinkFindPosition(ctx->text.sink, top,
ctx->text.left_margin,
vwidth,
ctx->text.wrap == XawtextWrapWord,
&top, &dim, &dim);
if (tmp == top)
++top;
}
}
_XawTextBuildLineTable(ctx, top, True);
}
else
ClearWindow(ctx);
}
ctx->text.clear_to_eol = True;
}
#ifndef OLDXAW
static int
ResolveLineNumber(TextWidget ctx)
{
int line_number = ctx->text.lt.base_line;
XawTextPosition position = ctx->text.lt.top;
if (ctx->text.lt.base_line < 1)
return (ctx->text.line_number);
if (ctx->text.wrap == XawtextWrapNever
&& IsPositionVisible(ctx, ctx->text.insertPos))
line_number += LineForPosition(ctx, ctx->text.insertPos);
else if (position < ctx->text.insertPos) {
while (position < ctx->text.insertPos) {
position = SrcScan(ctx->text.source, position,
XawstEOL, XawsdRight, 1, True);
if (position <= ctx->text.insertPos) {
++line_number;
if (position == ctx->text.lastPos) {
line_number -= !_XawTextSourceNewLineAtEOF(ctx->text.source);
break;
}
}
}
}
else if (position > ctx->text.insertPos) {
while (position > ctx->text.insertPos) {
position = SrcScan(ctx->text.source, position,
XawstEOL, XawsdLeft, 1, False);
if (--position >= ctx->text.insertPos)
--line_number;
}
}
return (line_number);
}
#endif
void
_XawTextExecuteUpdate(TextWidget ctx)
{
if (ctx->text.update_disabled || ctx->text.old_insert < 0)
return;
if(ctx->text.old_insert != ctx->text.insertPos || ctx->text.showposition)
_XawTextShowPosition(ctx);
FlushUpdate(ctx);
InsertCursor((Widget)ctx, XawisOn);
ctx->text.old_insert = -1;
#ifndef OLDXAW
_XawTextSetLineAndColumnNumber(ctx, False);
#endif
}
static void
XawTextDestroy(Widget w)
{
TextWidget ctx = (TextWidget)w;
DestroyHScrollBar(ctx);
DestroyVScrollBar(ctx);
XtFree((char *)ctx->text.s.selections);
XtFree((char *)ctx->text.lt.info);
XtFree((char *)ctx->text.search);
XmuDestroyScanline(ctx->text.update);
XtReleaseGC((Widget)ctx, ctx->text.gc);
}
static void
XawTextResize(Widget w)
{
TextWidget ctx = (TextWidget)w;
PositionVScrollBar(ctx);
PositionHScrollBar(ctx);
TextSinkResize(ctx->text.sink);
ctx->text.showposition = True;
_XawTextBuildLineTable(ctx, ctx->text.lt.top, True);
}
static Boolean
XawTextSetValues(Widget current, Widget request, Widget cnew,
ArgList args, Cardinal *num_args)
{
TextWidget oldtw = (TextWidget)current;
TextWidget newtw = (TextWidget)cnew;
Boolean redisplay = False;
Boolean display_caret = newtw->text.display_caret;
#ifndef OLDXAW
Boolean show_lc = False;
#endif
newtw->text.display_caret = oldtw->text.display_caret;
_XawTextPrepareToUpdate(newtw);
newtw->text.display_caret = display_caret;
if (oldtw->text.r_margin.left != newtw->text.r_margin.left) {
newtw->text.left_margin = newtw->text.margin.left =
newtw->text.r_margin.left;
if (newtw->text.vbar != NULL) {
newtw->text.left_margin += XtWidth(newtw->text.vbar) +
XtBorderWidth(newtw->text.vbar);
}
redisplay = True;
}
if (oldtw->text.scroll_vert != newtw->text.scroll_vert) {
if (newtw->text.scroll_vert == XawtextScrollAlways)
CreateVScrollBar(newtw);
else
DestroyVScrollBar(newtw);
redisplay = True;
}
if (oldtw->text.r_margin.bottom != newtw->text.r_margin.bottom) {
newtw->text.margin.bottom = newtw->text.r_margin.bottom;
if (newtw->text.hbar != NULL)
newtw->text.margin.bottom += newtw->text.hbar->core.height +
newtw->text.hbar->core.border_width;
redisplay = True;
}
if (oldtw->text.scroll_horiz != newtw->text.scroll_horiz) {
if (newtw->text.scroll_horiz == XawtextScrollAlways)
CreateHScrollBar(newtw);
else
DestroyHScrollBar(newtw);
redisplay = True;
}
if (oldtw->text.source != newtw->text.source) {
#ifndef OLDXAW
show_lc = True;
_XawSourceRemoveText(oldtw->text.source, cnew,
oldtw->text.source &&
XtParent(oldtw->text.source) == cnew);
_XawSourceAddText(newtw->text.source, cnew);
#endif
_XawTextSetSource((Widget)newtw, newtw->text.source, newtw->text.lt.top,
newtw->text.insertPos);
}
newtw->text.redisplay_needed = False;
XtSetValues((Widget)newtw->text.source, args, *num_args);
XtSetValues((Widget)newtw->text.sink, args, *num_args);
if (oldtw->text.wrap != newtw->text.wrap
|| oldtw->text.lt.top != newtw->text.lt.top
|| oldtw->text.insertPos != newtw->text.insertPos
|| oldtw->text.r_margin.right != newtw->text.r_margin.right
|| oldtw->text.r_margin.top != newtw->text.r_margin.top
|| oldtw->text.sink != newtw->text.sink
|| newtw->text.redisplay_needed) {
if (oldtw->text.wrap != newtw->text.wrap) {
newtw->text.left_margin = newtw->text.margin.left =
newtw->text.r_margin.left;
if (oldtw->text.lt.top == newtw->text.lt.top)
newtw->text.lt.top = SrcScan(newtw->text.source, 0, XawstEOL,
XawsdLeft, 1, False);
}
newtw->text.showposition = True;
#ifndef OLDXAW
show_lc = True;
newtw->text.source_changed = SRC_CHANGE_OVERLAP;
#endif
_XawTextBuildLineTable(newtw, newtw->text.lt.top, True);
redisplay = True;
}
#ifndef OLDXAW
if (newtw->text.left_column < 0)
newtw->text.left_column = 0;
if (newtw->text.right_column < 0)
newtw->text.right_column = 0;
#endif
_XawTextExecuteUpdate(newtw);
#ifndef OLDXAW
if (show_lc)
_XawTextSetLineAndColumnNumber(newtw, True);
#endif
if (redisplay)
_XawTextSetScrollBars(newtw);
return (redisplay);
}
static Bool
XawTextChangeSensitive(Widget w)
{
Arg args[1];
TextWidget tw = (TextWidget)w;
(*(&simpleClassRec)->simple_class.change_sensitive)(w);
XtSetArg(args[0], XtNancestorSensitive,
(tw->core.ancestor_sensitive && tw->core.sensitive));
if (tw->text.vbar)
XtSetValues(tw->text.vbar, args, ONE);
if (tw->text.hbar)
XtSetValues(tw->text.hbar, args, ONE);
return (False);
}
static void
XawTextGetValuesHook(Widget w, ArgList args, Cardinal *num_args)
{
XtGetValues(((TextWidget)w)->text.source, args, *num_args);
XtGetValues(((TextWidget)w)->text.sink, args, *num_args);
}
static XawTextPosition
FindGoodPosition(TextWidget ctx, XawTextPosition pos)
{
if (pos < 0)
return (0);
return (((pos > ctx->text.lastPos) ? ctx->text.lastPos : pos));
}
void
_XawTextPosToXY(Widget w, XawTextPosition pos, Position *x, Position *y)
{
int line, ix, iy;
LineAndXYForPosition((TextWidget)w, pos, &line, &ix, &iy);
*x = ix;
*y = iy;
}
void
XawTextDisplay(Widget w)
{
TextWidget ctx = (TextWidget)w;
if (!XtIsRealized(w))
return;
_XawTextPrepareToUpdate(ctx);
ctx->text.clear_to_eol = True;
DisplayTextWindow(w);
_XawTextExecuteUpdate(ctx);
}
void
XawTextSetSelectionArray(Widget w, XawTextSelectType *sarray)
{
((TextWidget)w)->text.sarray = sarray;
}
void
XawTextGetSelectionPos(Widget w, XawTextPosition *left, XawTextPosition *right)
{
*left = ((TextWidget)w)->text.s.left;
*right = ((TextWidget)w)->text.s.right;
}
void
_XawTextSetSource(Widget w, Widget source,
XawTextPosition top, XawTextPosition startPos)
{
TextWidget ctx = (TextWidget)w;
#ifndef OLDXAW
Bool resolve = False;
#endif
#ifndef OLDXAW
if (source != ctx->text.source)
_XawSourceRemoveText(ctx->text.source, w, ctx->text.source &&
XtParent(ctx->text.source) == w);
_XawSourceAddText(source, w);
if (source != ctx->text.source || ctx->text.insertPos != startPos)
resolve = True;
ctx->text.source_changed = SRC_CHANGE_OVERLAP;
#endif
ctx->text.source = source;
ctx->text.s.left = ctx->text.s.right = 0;
ctx->text.lastPos = GETLASTPOS;
top = FindGoodPosition(ctx, top);
startPos = FindGoodPosition(ctx, startPos);
ctx->text.insertPos = ctx->text.old_insert = startPos;
_XawTextPrepareToUpdate(ctx);
_XawTextBuildLineTable(ctx, top, True);
_XawTextExecuteUpdate(ctx);
#ifndef OLDXAW
if (resolve)
_XawTextSetLineAndColumnNumber(ctx, True);
#endif
}
void
XawTextSetSource(Widget w, Widget source, XawTextPosition top)
{
_XawTextSetSource(w, source, top, top);
}
int
XawTextReplace(Widget w, XawTextPosition startPos, XawTextPosition endPos,
XawTextBlock *text)
{
TextWidget ctx = (TextWidget)w;
int result;
#ifndef OLDXAW
Cardinal i;
TextSrcObject src = (TextSrcObject)ctx->text.source;
for (i = 0; i < src->textSrc.num_text; i++)
_XawTextPrepareToUpdate((TextWidget)src->textSrc.text[i]);
#else
_XawTextPrepareToUpdate(ctx);
#endif
endPos = FindGoodPosition(ctx, endPos);
startPos = FindGoodPosition(ctx, startPos);
result = _XawTextReplace(ctx, startPos, endPos, text);
#ifndef OLDXAW
for (i = 0; i < src->textSrc.num_text; i++)
_XawTextExecuteUpdate((TextWidget)src->textSrc.text[i]);
#else
_XawTextExecuteUpdate(ctx);
#endif
return (result);
}
XawTextPosition
XawTextTopPosition(Widget w)
{
return (((TextWidget)w)->text.lt.top);
}
XawTextPosition
XawTextLastPosition(Widget w)
{
return (((TextWidget)w)->text.lastPos);
}
void
XawTextSetInsertionPoint(Widget w, XawTextPosition position)
{
TextWidget ctx = (TextWidget)w;
_XawTextPrepareToUpdate(ctx);
ctx->text.insertPos = FindGoodPosition(ctx, position);
ctx->text.showposition = True;
ctx->text.from_left = -1;
_XawTextExecuteUpdate(ctx);
#ifndef OLDXAW
_XawTextSetLineAndColumnNumber(ctx, False);
#endif
}
XawTextPosition
XawTextGetInsertionPoint(Widget w)
{
return (((TextWidget)w)->text.insertPos);
}
void
XawTextUnsetSelection(Widget w)
{
TextWidget ctx = (TextWidget)w;
while (ctx->text.s.atom_count != 0) {
Atom sel = ctx->text.s.selections[ctx->text.s.atom_count - 1];
if (sel != (Atom) 0) {
if (GetCutBufferNumber(sel) == NOT_A_CUT_BUFFER)
XtDisownSelection(w, sel, ctx->text.time);
TextLoseSelection(w, &sel);
}
}
}
void
XawTextSetSelection(Widget w, XawTextPosition left, XawTextPosition right)
{
TextWidget ctx = (TextWidget)w;
_XawTextPrepareToUpdate(ctx);
_XawTextSetSelection(ctx, FindGoodPosition(ctx, left),
FindGoodPosition(ctx, right), NULL, 0);
_XawTextExecuteUpdate(ctx);
}
void
XawTextInvalidate(Widget w, XawTextPosition from, XawTextPosition to)
{
TextWidget ctx = (TextWidget)w;
from = FindGoodPosition(ctx, from);
to = FindGoodPosition(ctx, to);
ctx->text.lastPos = GETLASTPOS;
_XawTextPrepareToUpdate(ctx);
_XawTextNeedsUpdating(ctx, from, to);
_XawTextExecuteUpdate(ctx);
}
void
XawTextDisableRedisplay(Widget w)
{
((TextWidget)w)->text.update_disabled = True;
_XawTextPrepareToUpdate((TextWidget)w);
}
void
XawTextEnableRedisplay(Widget w)
{
TextWidget ctx = (TextWidget)w;
XawTextPosition lastPos;
if (!ctx->text.update_disabled)
return;
ctx->text.update_disabled = False;
lastPos = ctx->text.lastPos = GETLASTPOS;
ctx->text.lt.top = FindGoodPosition(ctx, ctx->text.lt.top);
ctx->text.insertPos = FindGoodPosition(ctx, ctx->text.insertPos);
if (ctx->text.s.left > lastPos || ctx->text.s.right > lastPos)
ctx->text.s.left = ctx->text.s.right = 0;
_XawTextExecuteUpdate(ctx);
}
Widget
XawTextGetSource(Widget w)
{
return (((TextWidget)w)->text.source);
}
Widget
XawTextGetSink(Widget w)
{
return (((TextWidget)w)->text.sink);
}
void
XawTextDisplayCaret(Widget w,
#if NeedWidePrototypes
int display_caret
#else
Boolean display_caret
#endif
)
{
TextWidget ctx = (TextWidget)w;
if (XtIsRealized(w)) {
_XawTextPrepareToUpdate(ctx);
ctx->text.display_caret = display_caret;
_XawTextExecuteUpdate(ctx);
}
else
ctx->text.display_caret = display_caret;
}
XawTextPosition
XawTextSearch(Widget w,
#if NeedWidePrototypes
int dir,
#else
XawTextScanDirection dir,
#endif
XawTextBlock *text)
{
TextWidget ctx = (TextWidget)w;
return (SrcSearch(ctx->text.source, ctx->text.insertPos, dir, text));
}
TextClassRec textClassRec = {
{
(WidgetClass)&simpleClassRec,
"Text",
sizeof(TextRec),
XawTextClassInitialize,
NULL,
False,
XawTextInitialize,
NULL,
XawTextRealize,
_XawTextActionsTable,
0,
resources,
XtNumber(resources),
NULLQUARK,
True,
XtExposeGraphicsExpose |
XtExposeNoExpose,
True,
False,
XawTextDestroy,
XawTextResize,
XawTextExpose,
XawTextSetValues,
NULL,
XtInheritSetValuesAlmost,
XawTextGetValuesHook,
NULL,
XtVersion,
NULL,
_XawDefaultTextTranslations,
XtInheritQueryGeometry,
XtInheritDisplayAccelerator,
NULL,
},
{
XawTextChangeSensitive,
},
{
NULL,
}
};
WidgetClass textWidgetClass = (WidgetClass)&textClassRec;