1 /***********************************************************
3 Copyright 1987, 1988, 1994, 1998 The Open Group
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
26 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
30 Permission to use, copy, modify, and distribute this software and its
31 documentation for any purpose and without fee is hereby granted,
32 provided that the above copyright notice appear in all copies and that
33 both that copyright notice and this permission notice appear in
34 supporting documentation, and that the name of Digital not be
35 used in advertising or publicity pertaining to distribution of the
36 software without specific, written prior permission.
38 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
39 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
40 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
41 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
42 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
43 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
46 ******************************************************************/
49 * Copyright (c) 1998 by The XFree86 Project, Inc.
51 * Permission is hereby granted, free of charge, to any person obtaining a
52 * copy of this software and associated documentation files (the "Software"),
53 * to deal in the Software without restriction, including without limitation
54 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
55 * and/or sell copies of the Software, and to permit persons to whom the
56 * Software is furnished to do so, subject to the following conditions:
58 * The above copyright notice and this permission notice shall be included in
59 * all copies or substantial portions of the Software.
61 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
62 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
63 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
64 * THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
65 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
66 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
69 * Except as contained in this notice, the name of the XFree86 Project shall
70 * not be used in advertising or otherwise to promote the sale, use or other
71 * dealings in this Software without prior written authorization from the
79 #include <X11/IntrinsicP.h>
80 #include <X11/StringDefs.h>
81 #include <X11/Shell.h>
82 #include <X11/Xatom.h>
83 #include <X11/Xfuncs.h>
84 #include <X11/Xutil.h>
85 #include <X11/Xmu/Misc.h>
86 #include <X11/Xmu/SysUtil.h>
87 #include <X11/Xmu/Xmu.h>
88 #include <X11/Xaw/Cardinals.h>
89 #include <X11/Xaw/MultiSinkP.h>
90 #include <X11/Xaw/TextP.h>
91 #include <X11/Xaw/TextSrcP.h>
92 #include <X11/Xaw/TextSinkP.h>
93 #include <X11/Xaw/Scrollbar.h>
94 #include <X11/Xaw/XawImP.h>
95 #include <X11/Xaw/XawInit.h>
100 #define MAX_LEN_CT 6 /* for sequence: ESC $ ( A \xx \xx */
103 unsigned long FMT8BIT = 0L;
104 unsigned long XawFmt8Bit = 0L;
105 unsigned long XawFmtWide = 0L;
107 #define SinkClearToBG _XawTextSinkClearToBackground
109 #define SrcScan XawTextSourceScan
110 #define SrcRead XawTextSourceRead
111 #define SrcReplace XawTextSourceReplace
112 #define SrcSearch XawTextSourceSearch
113 #define SrcCvtSel XawTextSourceConvertSelection
114 #define SrcSetSelection XawTextSourceSetSelection
116 #define MULTI_CLICK_TIME 500L
118 #define SRC_CHANGE_NONE 0
119 #define SRC_CHANGE_AFTER 1
120 #define SRC_CHANGE_BEFORE 2
121 #define SRC_CHANGE_OVERLAP 3
123 #define Superclass (&simpleClassRec)
126 * Compute a the maximum length of a cut buffer that we can pass at any
127 * time. The 64 allows for the overhead of the Change Property request.
129 #define MAX_CUT_LEN(dpy) (XMaxRequestSize(dpy) - 64)
131 #define ClearWindow(ctx) \
132 _XawTextNeedsUpdating((ctx), \
133 (ctx)->text.lt.top, \
134 (ctx)->text.lt.info[ctx->text.lt.lines].position)
139 static void XawTextClassInitialize(void);
140 static void XawTextInitialize(Widget, Widget, ArgList, Cardinal*);
141 static void XawTextRealize(Widget, XtValueMask*, XSetWindowAttributes*);
142 static void XawTextDestroy(Widget);
143 static void XawTextResize(Widget);
144 static void XawTextExpose(Widget, XEvent*, Region);
145 static Boolean XawTextSetValues(Widget, Widget, Widget, ArgList, Cardinal*);
146 static void XawTextGetValuesHook(Widget, ArgList, Cardinal*);
147 static Bool XawTextChangeSensitive(Widget);
152 static XawTextPosition _BuildLineTable(TextWidget, XawTextPosition, int);
153 static void _CreateCutBuffers(Display*);
154 static Boolean TextConvertSelection(Widget, Atom*, Atom*, Atom*, XtPointer*,
155 unsigned long*, int*);
156 static int CountLines(TextWidget, XawTextPosition, XawTextPosition);
157 static void CreateHScrollBar(TextWidget);
158 static void CreateVScrollBar(TextWidget);
159 static void CvtStringToScrollMode(XrmValuePtr, Cardinal*,
160 XrmValuePtr, XrmValuePtr);
161 static Boolean CvtScrollModeToString(Display*, XrmValue*, Cardinal*,
162 XrmValue*, XrmValue*, XtPointer*);
163 static void CvtStringToWrapMode(XrmValuePtr, Cardinal*,
164 XrmValuePtr, XrmValuePtr);
165 static Boolean CvtWrapModeToString(Display*, XrmValue*, Cardinal*,
166 XrmValue*, XrmValue*, XtPointer*);
167 static Boolean CvtStringToJustifyMode(Display*, XrmValue*, Cardinal*,
168 XrmValue*, XrmValue*, XtPointer*);
169 static Boolean CvtJustifyModeToString(Display*, XrmValue*, Cardinal*,
170 XrmValue*, XrmValue*, XtPointer*);
171 static void DestroyHScrollBar(TextWidget);
172 static void DestroyVScrollBar(TextWidget);
174 static void DisplayText(Widget, XawTextPosition, XawTextPosition);
176 static void OldDisplayText(Widget, XawTextPosition, XawTextPosition);
177 static void DisplayTextWindow(Widget);
178 static void DoCopyArea(TextWidget, int, int, unsigned int, unsigned int,
180 static void DoSelection(TextWidget, XawTextPosition, Time, Bool);
181 static void ExtendSelection(TextWidget, XawTextPosition, Bool);
182 static XawTextPosition FindGoodPosition(TextWidget, XawTextPosition);
183 static void FlushUpdate(TextWidget);
184 static int GetCutBufferNumber(Atom);
185 static int GetMaxTextWidth(TextWidget);
186 static unsigned int GetWidestLine(TextWidget);
187 static void HScroll(Widget, XtPointer, XtPointer);
188 static void HJump(Widget, XtPointer, XtPointer);
189 static void InsertCursor(Widget, XawTextInsertState);
190 static Bool LineAndXYForPosition(TextWidget, XawTextPosition, int*,
192 static int LineForPosition(TextWidget, XawTextPosition);
193 static void TextLoseSelection(Widget, Atom*);
194 static Bool MatchSelection(Atom, XawTextSelection*);
195 static void ModifySelection(TextWidget, XawTextPosition, XawTextPosition);
196 static XawTextPosition PositionForXY(TextWidget, int, int);
197 static void PositionHScrollBar(TextWidget);
198 static void PositionVScrollBar(TextWidget);
200 static int ResolveColumnNumber(TextWidget);
201 static int ResolveLineNumber(TextWidget);
203 static void _SetSelection(TextWidget, XawTextPosition, XawTextPosition,
205 static void TextSinkResize(Widget);
206 static void UpdateTextInRectangle(TextWidget, XRectangle*);
207 static void UpdateTextInLine(TextWidget, int, int, int);
208 static void VScroll(Widget, XtPointer, XtPointer);
209 static void VJump(Widget, XtPointer, XtPointer);
214 void _XawTextAlterSelection(TextWidget,
215 XawTextSelectionMode, XawTextSelectionAction,
217 void _XawTextCheckResize(TextWidget);
218 void _XawTextClearAndCenterDisplay(TextWidget);
219 void _XawTextExecuteUpdate(TextWidget);
220 char *_XawTextGetText(TextWidget, XawTextPosition, XawTextPosition);
221 void _XawTextPrepareToUpdate(TextWidget);
222 int _XawTextReplace(TextWidget, XawTextPosition, XawTextPosition,
224 Atom *_XawTextSelectionList(TextWidget, String*, Cardinal);
225 void _XawTextSetScrollBars(TextWidget);
226 void _XawTextSetSelection(TextWidget, XawTextPosition, XawTextPosition,
228 void _XawTextVScroll(TextWidget, int);
229 void XawTextScroll(TextWidget, int, int);
230 void _XawTextSetSource(Widget, Widget, XawTextPosition, XawTextPosition);
232 void _XawTextSetLineAndColumnNumber(TextWidget, Bool);
234 void _XawTextSourceChanged(Widget, XawTextPosition, XawTextPosition,
237 /* Not used by other modules, but were extern on previous versions
240 void _XawTextShowPosition(TextWidget);
245 extern void _XawTextZapSelection(TextWidget, XEvent*, Bool);
250 void _XawSourceAddText(Widget, Widget);
251 void _XawSourceRemoveText(Widget, Widget, Bool);
252 Bool _XawTextSourceNewLineAtEOF(Widget);
257 void _XawTextSinkClearToBackground(Widget, int, int, unsigned, unsigned);
258 void _XawTextSinkDisplayText(Widget, int, int, XawTextPosition, XawTextPosition,
261 /****************************************************************
263 * Full class record constant
265 ****************************************************************/
269 static XawTextSelectType defaultSelectTypes[] = {
270 XawselectPosition, XawselectAlphaNumeric, XawselectWord, XawselectLine,
271 XawselectParagraph, XawselectAll, XawselectNull,
274 static XPointer defaultSelectTypesPtr = (XPointer)defaultSelectTypes;
275 static Dimension defWidth = 100;
276 static Dimension defHeight = DEFAULT_TEXT_HEIGHT;
278 #define offset(field) XtOffsetOf(TextRec, field)
279 static XtResource resources[] = {
294 offset(simple.cursor),
305 (XtPointer)&defHeight
311 sizeof(XawTextPosition),
320 sizeof(XawTextPosition),
321 offset(text.insertPos),
330 offset(text.r_margin.left),
339 offset(text.r_margin.right),
348 offset(text.r_margin.top),
357 offset(text.r_margin.bottom),
365 sizeof(XawTextSelectType*),
368 (XtPointer)&defaultSelectTypesPtr
393 offset(text.display_caret),
401 sizeof(XawTextScrollMode),
402 offset(text.scroll_vert),
410 sizeof(XawTextScrollMode),
411 offset(text.scroll_horiz),
419 sizeof(XawTextWrapMode),
422 (XtPointer)XawtextWrapNever
429 offset(text.auto_fill),
439 offset(text.position_callbacks),
448 offset(text.left_column),
457 offset(text.right_column),
465 sizeof(XawTextJustifyMode),
466 offset(text.justify),
468 (XtPointer)XawjustifyLeft
474 #define done(address, type) \
475 { toVal->size = sizeof(type); toVal->addr = (XPointer)address; }
477 static XrmQuark QWrapNever, QWrapLine, QWrapWord;
479 static XrmQuark QScrollNever, QScrollWhenNeeded, QScrollAlways;
481 static XrmQuark QJustifyLeft, QJustifyRight, QJustifyCenter, QJustifyFull;
485 CvtStringToScrollMode(XrmValuePtr args, Cardinal *num_args,
486 XrmValuePtr fromVal, XrmValuePtr toVal)
488 static XawTextScrollMode scrollMode = XawtextScrollNever;
492 XmuNCopyISOLatin1Lowered(name, (char *)fromVal->addr, sizeof(name));
493 q = XrmStringToQuark(name);
495 if (q == QScrollNever || q == QScrollWhenNeeded)
496 scrollMode = XawtextScrollNever;
497 else if (q == QScrollAlways)
498 scrollMode = XawtextScrollAlways;
499 else if (strcmp(name, "true") == 0 || strcmp(name, "1") == 0)
500 scrollMode = XawtextScrollAlways;
501 else if (strcmp(name, "false") == 0 || strcmp(name, "0") == 0)
502 scrollMode = XawtextScrollNever;
504 XtStringConversionWarning((char *)fromVal->addr, XtRScrollMode);
506 done(&scrollMode, XawTextScrollMode);
511 CvtScrollModeToString(Display *dpy, XrmValue *args, Cardinal *num_args,
512 XrmValue *fromVal, XrmValue *toVal, XtPointer *data)
517 switch (*(XawTextScrollMode *)fromVal->addr) {
518 case XawtextScrollNever:
519 case XawtextScrollWhenNeeded:
520 buffer = XtEtextScrollNever;
522 case XawtextScrollAlways:
523 buffer = XtEtextScrollAlways;
526 XawTypeToStringWarning(dpy, XtRScrollMode);
531 size = strlen(buffer) + 1;
532 if (toVal->addr != NULL) {
533 if (toVal->size < size) {
537 strcpy((char *)toVal->addr, buffer);
540 toVal->addr = (XPointer)buffer;
541 toVal->size = sizeof(String);
548 CvtStringToWrapMode(XrmValuePtr args, Cardinal *num_args,
549 XrmValuePtr fromVal, XrmValuePtr toVal)
551 static XawTextWrapMode wrapMode = XawtextWrapNever;
555 XmuNCopyISOLatin1Lowered(lowerName, (char *)fromVal->addr,
557 q = XrmStringToQuark(lowerName);
560 wrapMode = XawtextWrapNever;
561 else if (q == QWrapLine)
562 wrapMode = XawtextWrapLine;
563 else if (q == QWrapWord)
564 wrapMode = XawtextWrapWord;
566 XtStringConversionWarning((char *)fromVal->addr, XtRWrapMode);
568 done(&wrapMode, XawTextWrapMode);
573 CvtWrapModeToString(Display *dpy, XrmValue *args, Cardinal *num_args,
574 XrmValue *fromVal, XrmValue *toVal, XtPointer *data)
579 switch (*(XawTextWrapMode *)fromVal->addr) {
580 case XawtextWrapNever:
581 buffer = XtEtextWrapNever;
583 case XawtextWrapLine:
584 buffer = XtEtextWrapLine;
586 case XawtextWrapWord:
587 buffer = XtEtextWrapWord;
590 XawTypeToStringWarning(dpy, XtRWrapMode);
595 size = strlen(buffer) + 1;
596 if (toVal->addr != NULL) {
597 if (toVal->size < size) {
601 strcpy((char *)toVal->addr, buffer);
604 toVal->addr = (XPointer)buffer;
605 toVal->size = sizeof(String);
612 CvtStringToJustifyMode(Display *dpy, XrmValue *args, Cardinal *num_args,
613 XrmValue *fromVal, XrmValue *toVal, XtPointer *data)
615 XawTextJustifyMode justify;
619 XmuNCopyISOLatin1Lowered(lowerName, (char *)fromVal->addr,
621 q = XrmStringToQuark(lowerName);
623 if (q == QJustifyLeft)
624 justify = XawjustifyLeft;
625 else if (q == QJustifyRight)
626 justify = XawjustifyRight;
627 else if (q == QJustifyCenter)
628 justify = XawjustifyCenter;
629 else if(q == QJustifyFull)
630 justify = XawjustifyFull;
632 XtStringConversionWarning((char *)fromVal->addr, XtRJustifyMode);
636 toVal->size = sizeof(XawTextJustifyMode);
637 *(XawTextJustifyMode *)(toVal->addr) = justify;
645 CvtJustifyModeToString(Display *dpy, XrmValue *args, Cardinal *num_args,
646 XrmValue *fromVal, XrmValue *toVal, XtPointer *data)
651 switch (*(XawTextJustifyMode *)fromVal->addr) {
653 buffer = XtEtextJustifyLeft;
655 case XawjustifyRight:
656 buffer = XtEtextJustifyRight;
658 case XawjustifyCenter:
659 buffer = XtEtextJustifyCenter;
662 buffer = XtEtextJustifyFull;
665 XawTypeToStringWarning(dpy, XtRJustifyMode);
670 size = strlen(buffer) + 1;
671 if (toVal->addr != NULL) {
672 if (toVal->size < size) {
676 strcpy((char *)toVal->addr, buffer);
679 toVal->addr = (XPointer)buffer;
680 toVal->size = sizeof(String);
688 XawTextClassInitialize(void)
691 FMT8BIT = XawFmt8Bit = XrmPermStringToQuark("FMT8BIT");
693 XawFmtWide = XrmPermStringToQuark("FMTWIDE");
695 XawInitializeWidgetSet();
697 textClassRec.core_class.num_actions = _XawTextActionsTableCount;
699 QWrapNever = XrmPermStringToQuark(XtEtextWrapNever);
700 QWrapLine = XrmPermStringToQuark(XtEtextWrapLine);
701 QWrapWord = XrmPermStringToQuark(XtEtextWrapWord);
702 XtAddConverter(XtRString, XtRWrapMode, CvtStringToWrapMode, NULL, 0);
703 XtSetTypeConverter(XtRWrapMode, XtRString, CvtWrapModeToString,
704 NULL, 0, XtCacheNone, NULL);
705 QScrollNever = XrmPermStringToQuark(XtEtextScrollNever);
706 QScrollWhenNeeded = XrmPermStringToQuark(XtEtextScrollWhenNeeded);
707 QScrollAlways = XrmPermStringToQuark(XtEtextScrollAlways);
708 XtAddConverter(XtRString, XtRScrollMode, CvtStringToScrollMode,
710 XtSetTypeConverter(XtRScrollMode, XtRString, CvtScrollModeToString,
711 NULL, 0, XtCacheNone, NULL);
712 QJustifyLeft = XrmPermStringToQuark(XtEtextJustifyLeft);
713 QJustifyRight = XrmPermStringToQuark(XtEtextJustifyRight);
714 QJustifyCenter = XrmPermStringToQuark(XtEtextJustifyCenter);
715 QJustifyFull = XrmPermStringToQuark(XtEtextJustifyFull);
716 XtSetTypeConverter(XtRString, XtRJustifyMode, CvtStringToJustifyMode,
717 NULL, 0, XtCacheNone, NULL);
718 XtSetTypeConverter(XtRJustifyMode, XtRString, CvtJustifyModeToString,
719 NULL, 0, XtCacheNone, NULL);
730 * Positions the Horizontal scrollbar.
733 PositionHScrollBar(TextWidget ctx)
735 Widget hbar = ctx->text.hbar, vbar = ctx->text.vbar;
737 Dimension width, height;
739 if (ctx->text.hbar == NULL)
745 x = -XtBorderWidth(hbar);
746 y = XtHeight(ctx) - XtHeight(hbar) - XtBorderWidth(hbar);
748 width = XtWidth(ctx) - XtWidth(vbar) - XtBorderWidth(vbar);
749 if (width > XtWidth(ctx))
750 width = XtWidth(ctx);
753 width = XtWidth(ctx);
754 height = XtHeight(hbar);
756 XtConfigureWidget(hbar, x, y, width, height, XtBorderWidth(hbar));
767 * Positions the Vertical scrollbar.
770 PositionVScrollBar(TextWidget ctx)
772 Widget vbar = ctx->text.vbar;
774 Dimension width, height;
779 x = y = -XtBorderWidth(vbar);
780 height = XtHeight(ctx);
781 width = XtWidth(vbar);
783 XtConfigureWidget(vbar, x, y, width, height, XtBorderWidth(vbar));
787 CreateVScrollBar(TextWidget ctx)
791 if (ctx->text.vbar != NULL)
794 ctx->text.vbar = vbar =
795 XtCreateWidget("vScrollbar", scrollbarWidgetClass, (Widget)ctx, NULL, 0);
796 XtAddCallback(vbar, XtNscrollProc, VScroll, (XtPointer)ctx);
797 XtAddCallback(vbar, XtNjumpProc, VJump, (XtPointer)ctx);
799 ctx->text.r_margin.left += XtWidth(vbar) + XtBorderWidth(vbar);
800 ctx->text.left_margin = ctx->text.margin.left = ctx->text.r_margin.left;
802 PositionVScrollBar(ctx);
803 PositionHScrollBar(ctx);
804 TextSinkResize(ctx->text.sink);
806 if (XtIsRealized((Widget)ctx)) {
807 XtRealizeWidget(vbar);
810 XtSetKeyboardFocus(vbar, (Widget)ctx);
818 * ctx - parent text widget
821 * Removes vertical ScrollBar.
824 DestroyVScrollBar(TextWidget ctx)
826 Widget vbar = ctx->text.vbar;
831 ctx->text.r_margin.left -= XtWidth(vbar) + XtBorderWidth(vbar);
832 ctx->text.left_margin = ctx->text.margin.left = ctx->text.r_margin.left;
834 XtDestroyWidget(vbar);
835 ctx->text.vbar = NULL;
836 if (!ctx->core.being_destroyed) {
837 PositionHScrollBar(ctx);
838 TextSinkResize(ctx->text.sink);
843 CreateHScrollBar(TextWidget ctx)
849 if (ctx->text.hbar != NULL)
852 XtSetArg(args[0], XtNorientation, XtorientHorizontal);
853 ctx->text.hbar = hbar =
854 XtCreateWidget("hScrollbar", scrollbarWidgetClass, (Widget)ctx, args, 1);
855 XtAddCallback(hbar, XtNscrollProc, HScroll, (XtPointer)ctx);
856 XtAddCallback(hbar, XtNjumpProc, HJump, (XtPointer)ctx);
858 bottom = ctx->text.r_margin.bottom + XtHeight(hbar) + XtBorderWidth(hbar);
860 ctx->text.margin.bottom = ctx->text.r_margin.bottom = bottom;
862 PositionHScrollBar(ctx);
863 TextSinkResize(ctx->text.sink);
865 if (XtIsRealized((Widget)ctx)) {
866 XtRealizeWidget(hbar);
869 XtSetKeyboardFocus(hbar, (Widget)ctx);
877 * ctx - parent text widget
880 * Removes horizontal ScrollBar.
883 DestroyHScrollBar(TextWidget ctx)
885 Widget hbar = ctx->text.hbar;
890 ctx->text.r_margin.bottom -= XtHeight(hbar) + XtBorderWidth(hbar);
891 ctx->text.margin.bottom = ctx->text.r_margin.bottom;
893 XtDestroyWidget(hbar);
894 ctx->text.hbar = NULL;
895 if (!ctx->core.being_destroyed)
896 TextSinkResize(ctx->text.sink);
901 XawTextInitialize(Widget request, Widget cnew,
902 ArgList args, Cardinal *num_args)
904 TextWidget ctx = (TextWidget)cnew;
906 ctx->text.lt.lines = 0;
907 ctx->text.lt.info = (XawTextLineTableEntry *)
908 XtCalloc(1, sizeof(XawTextLineTableEntry));
910 ctx->text.lt.base_line = 1;
912 (void)bzero(&ctx->text.origSel, sizeof(XawTextSelection));
913 (void)bzero(&ctx->text.s, sizeof(XawTextSelection));
914 ctx->text.s.type = XawselectPosition;
915 ctx->text.salt = NULL;
916 ctx->text.hbar = ctx->text.vbar = NULL;
917 ctx->text.lasttime = 0;
919 ctx->text.showposition = True;
920 ctx->text.lastPos = ctx->text.source != NULL ?
921 XawTextGetLastPosition(ctx) : 0;
922 ctx->text.file_insert = NULL;
923 ctx->text.search = NULL;
924 ctx->text.update = XmuNewScanline(0, 0, 0);
925 ctx->text.gc = XtGetGC(cnew, 0, 0);
926 ctx->text.hasfocus = False;
927 ctx->text.margin = ctx->text.r_margin; /* Strucure copy */
928 ctx->text.left_margin = ctx->text.r_margin.left;
929 ctx->text.update_disabled = False;
930 ctx->text.clear_to_eol = True;
931 ctx->text.old_insert = -1;
933 ctx->text.salt2 = NULL;
934 ctx->text.from_left = -1;
937 ctx->text.numeric = False;
938 ctx->text.selection_state = False;
939 ctx->text.kill_ring = 0;
941 ctx->text.line_number = -1;
942 ctx->text.column_number = -1;
943 ctx->text.source_changed = SRC_CHANGE_NONE;
945 ctx->text.kill_ring_ptr = NULL;
946 ctx->text.overwrite = False;
949 if (XtHeight(ctx) == DEFAULT_TEXT_HEIGHT) {
950 XtHeight(ctx) = VMargins(ctx);
951 if (ctx->text.sink != NULL)
952 XtHeight(ctx) += XawTextSinkMaxHeight(ctx->text.sink, 1);
955 if (ctx->text.scroll_vert == XawtextScrollAlways)
956 CreateVScrollBar(ctx);
957 if (ctx->text.scroll_horiz == XawtextScrollAlways)
958 CreateHScrollBar(ctx);
961 if (ctx->text.left_column < 0)
962 ctx->text.left_column = 0;
963 if (ctx->text.right_column < 0)
964 ctx->text.right_column = 0;
969 XawTextRealize(Widget w, XtValueMask *mask, XSetWindowAttributes *attr)
971 TextWidget ctx = (TextWidget)w;
973 (*textClassRec.core_class.superclass->core_class.realize)(w, mask, attr);
975 if (ctx->text.hbar != NULL) {
976 XtRealizeWidget(ctx->text.hbar);
977 XtMapWidget(ctx->text.hbar);
980 if (ctx->text.vbar != NULL) {
981 XtRealizeWidget(ctx->text.vbar);
982 XtMapWidget(ctx->text.vbar);
985 _XawTextBuildLineTable(ctx, ctx->text.lt.top, True);
988 _XawTextSetLineAndColumnNumber(ctx, True);
992 /* Utility routines for support of Text */
994 _CreateCutBuffers(Display *d)
996 static struct _DisplayRec {
997 struct _DisplayRec *next;
1000 struct _DisplayRec *dpy_ptr;
1002 for (dpy_ptr = dpy_list; dpy_ptr != NULL; dpy_ptr = dpy_ptr->next)
1003 if (dpy_ptr->dpy == d)
1006 dpy_ptr = XtNew(struct _DisplayRec);
1007 dpy_ptr->next = dpy_list;
1011 #define Create(buffer) \
1012 XChangeProperty(d, RootWindow(d, 0), buffer, XA_STRING, 8, \
1013 PropModeAppend, NULL, 0);
1015 Create(XA_CUT_BUFFER0);
1016 Create(XA_CUT_BUFFER1);
1017 Create(XA_CUT_BUFFER2);
1018 Create(XA_CUT_BUFFER3);
1019 Create(XA_CUT_BUFFER4);
1020 Create(XA_CUT_BUFFER5);
1021 Create(XA_CUT_BUFFER6);
1022 Create(XA_CUT_BUFFER7);
1028 * Procedure to manage insert cursor visibility for editable text. It uses
1029 * the value of ctx->insertPos and an implicit argument. In the event that
1030 * position is immediately preceded by an eol graphic, then the insert cursor
1031 * is displayed at the beginning of the next line.
1034 InsertCursor(Widget w, XawTextInsertState state)
1036 TextWidget ctx = (TextWidget)w;
1040 if (ctx->text.lt.lines < 1)
1043 if (ctx->text.display_caret &&
1044 LineAndXYForPosition(ctx, ctx->text.insertPos, &line, &x, &y)) {
1045 if (line < ctx->text.lt.lines)
1046 y += (ctx->text.lt.info[line + 1].y - ctx->text.lt.info[line].y) + 1;
1048 y += (ctx->text.lt.info[line].y - ctx->text.lt.info[line - 1].y) + 1;
1050 XawTextSinkInsertCursor(ctx->text.sink, x, y, state);
1053 /* Keep Input Method up to speed */
1054 if (ctx->simple.international) {
1057 XtSetArg(list[0], XtNinsertPosition, ctx->text.insertPos);
1058 _XawImSetValues(w, list, 1);
1063 * Procedure to register a span of text that is no longer valid on the display
1064 * It is used to avoid a number of small, and potentially overlapping, screen
1068 _XawTextNeedsUpdating(TextWidget ctx,
1069 XawTextPosition left, XawTextPosition right)
1076 segment.x1 = (int)left;
1077 segment.x2 = (int)right;
1078 (void)XmuScanlineOrSegment(ctx->text.update, &segment);
1082 * Procedure to read a span of text in Ascii form. This is purely a hack and
1083 * we probably need to add a function to sources to provide this functionality.
1084 * [note: this is really a private procedure but is used in multiple modules].
1087 _XawTextGetText(TextWidget ctx, XawTextPosition left, XawTextPosition right)
1089 char *result, *tempResult;
1093 if (XawTextFormat(ctx, XawFmt8Bit))
1094 bytes = sizeof(unsigned char);
1095 else if (XawTextFormat(ctx, XawFmtWide))
1096 bytes = sizeof(wchar_t);
1097 else /* if there is another fomat, add here */
1100 /* leave space for ZERO */
1101 tempResult = result = XtMalloc((unsigned)(right - left + ONE) * bytes);
1103 while (left < right) {
1104 left = SrcRead(ctx->text.source, left, &text, (int)(right - left));
1107 memmove(tempResult, text.ptr, (unsigned)(text.length * bytes));
1108 tempResult += text.length * bytes;
1111 if (bytes == sizeof(wchar_t))
1112 *((wchar_t*)tempResult) = (wchar_t)0;
1119 /* Like _XawTextGetText, but enforces ICCCM STRING type encoding. This
1120 * routine is currently used to put just the ASCII chars in the selection
1121 * into a cut buffer.
1124 _XawTextGetSTRING(TextWidget ctx, XawTextPosition left, XawTextPosition right)
1131 /* allow ESC in accordance with ICCCM */
1132 if (XawTextFormat(ctx, XawFmtWide)) {
1133 MultiSinkObject sink = (MultiSinkObject)ctx->text.sink;
1134 ws = (wchar_t *)_XawTextGetText(ctx, left, right);
1136 for (j = 0, i = 0; j < n; j++) {
1138 if (XwcTextEscapement (sink->multi_sink.fontset, &wc, 1)
1139 || (wc == _Xaw_atowc(XawTAB)) || (wc == _Xaw_atowc(XawLF))
1140 || (wc == _Xaw_atowc(XawESC)))
1144 return ((char *)ws);
1147 s = (unsigned char *)_XawTextGetText(ctx, left, right);
1148 /* only HT and NL control chars are allowed, strip out others */
1149 n = strlen((char *)s);
1151 for (j = 0; j < n; j++) {
1153 if (((c >= 0x20) && c <= 0x7f)
1154 ||(c >= 0xa0) || (c == XawTAB) || (c == XawLF)
1167 * This routine maps an x and y position in a window that is displaying text
1168 * into the corresponding position in the source.
1170 static XawTextPosition
1171 PositionForXY(TextWidget ctx, int x, int y)
1173 int fromx, line, width, height;
1174 XawTextPosition position;
1176 if (ctx->text.lt.lines == 0)
1179 for (line = 0; line < ctx->text.lt.lines - 1; line++) {
1180 if (y <= ctx->text.lt.info[line + 1].y)
1183 position = ctx->text.lt.info[line].position;
1184 if (position >= ctx->text.lastPos)
1185 return (ctx->text.lastPos);
1186 fromx = ctx->text.left_margin;
1187 XawTextSinkFindPosition(ctx->text.sink, position, fromx, x - fromx,
1188 False, &position, &width, &height);
1190 if (position > ctx->text.lastPos)
1191 return (ctx->text.lastPos);
1193 if (position >= ctx->text.lt.info[line + 1].position)
1194 position = SrcScan(ctx->text.source, ctx->text.lt.info[line + 1].position,
1195 XawstPositions, XawsdLeft, 1, True);
1201 * This routine maps a source position in to the corresponding line number
1202 * of the text that is displayed in the window.
1205 LineForPosition(TextWidget ctx, XawTextPosition position)
1209 for (line = 0; line < ctx->text.lt.lines; line++)
1210 if (position < ctx->text.lt.info[line + 1].position)
1217 * This routine maps a source position into the corresponding line number
1218 * and the x, y coordinates of the text that is displayed in the window.
1221 LineAndXYForPosition(TextWidget ctx, XawTextPosition pos,
1222 int *line, int *x, int *y)
1224 XawTextPosition linePos, endPos;
1229 *x = ctx->text.left_margin;
1230 *y = ctx->text.margin.top + 1;
1231 if ((visible = IsPositionVisible(ctx, pos)) != False) {
1232 *line = LineForPosition(ctx, pos);
1233 *y = ctx->text.lt.info[*line].y;
1234 linePos = ctx->text.lt.info[*line].position;
1235 XawTextSinkFindDistance(ctx->text.sink, linePos,
1236 *x, pos, &realW, &endPos, &realH);
1244 * This routine builds a line table. It does this by starting at the
1245 * specified position and measuring text to determine the staring position
1246 * of each line to be displayed. It also determines and saves in the
1247 * linetable all the required metrics for displaying a given line (e.g.
1248 * x offset, y offset, line length, etc.).
1251 _XawTextBuildLineTable(TextWidget ctx, XawTextPosition position,
1252 _XtBoolean force_rebuild)
1254 Dimension height = 0;
1258 if ((int)XtHeight(ctx) > VMargins(ctx)) {
1259 height = XtHeight(ctx) - VMargins(ctx);
1260 lines = XawTextSinkMaxLines(ctx->text.sink, height);
1262 size = sizeof(XawTextLineTableEntry) * (lines + 1);
1264 if (lines != ctx->text.lt.lines || ctx->text.lt.info == NULL) {
1265 ctx->text.lt.info = (XawTextLineTableEntry *)
1266 XtRealloc((char *)ctx->text.lt.info, size);
1267 ctx->text.lt.lines = lines;
1268 force_rebuild = True;
1271 if (force_rebuild) {
1272 (void)bzero((char *)ctx->text.lt.info, size);
1273 /* force a text update in the first text line if it is visible */
1274 ctx->text.lt.info[0].position = (XawTextPosition)-1;
1276 if (position != ctx->text.lt.info[0].position) {
1277 (void)_BuildLineTable(ctx, position, 0);
1278 ctx->text.clear_to_eol = True;
1283 * We may need to resize the line table here, since there maybe lines with
1284 * different fonts (that can be shorter or taller than the default one)
1286 static XawTextPosition
1287 _BuildLineTable(TextWidget ctx, XawTextPosition position, int line)
1289 XawTextLineTableEntry *lt = ctx->text.lt.info + line;
1290 XawTextPosition end, update_from = -1;
1292 int wwidth, width, height;
1294 Widget src = ctx->text.source;
1296 int max_y = (int)XtHeight(ctx) - (int)ctx->text.margin.bottom;
1298 if (ctx->text.wrap == XawtextWrapNever)
1299 wwidth = 0x7fffffff;
1301 wwidth = GetMaxTextWidth(ctx);
1303 /* XXX y may change, due to font size changes. See later */
1304 y = line == 0 ? ctx->text.margin.top : lt->y;
1307 if (ctx->text.lt.base_line < 0) {
1309 ctx->text.lt.top = position;
1311 else if (line == 0) {
1312 XawTextPosition pos = ctx->text.lt.top;
1313 int base_line = ctx->text.lt.base_line;
1317 else if (ctx->text.lt.base_line == 0 ||
1318 ctx->text.source_changed == SRC_CHANGE_OVERLAP) {
1322 while (pos < position) {
1323 pos = SrcScan(src, pos, XawstEOL, XawsdRight, 1, True);
1324 if (pos <= position) {
1326 if (pos == ctx->text.lastPos) {
1327 base_line -= !_XawTextSourceNewLineAtEOF(src);
1333 else if (ctx->text.wrap == XawtextWrapNever
1334 && IsPositionVisible(ctx, position))
1335 base_line += LineForPosition(ctx, position);
1336 else if (pos < position) {
1337 while (pos < position) {
1338 pos = SrcScan(src, pos, XawstEOL, XawsdRight, 1, True);
1339 if (pos <= position) {
1341 if (pos == ctx->text.lastPos) {
1342 base_line -= !_XawTextSourceNewLineAtEOF(src);
1348 else if (pos > position) {
1349 while (pos > position) {
1350 pos = SrcScan(src, pos, XawstEOL, XawsdLeft, 1, False);
1351 if (--pos >= position)
1356 ctx->text.lt.top = position;
1357 ctx->text.lt.base_line = base_line;
1361 ctx->text.lt.top = position;
1366 XawTextSinkFindPosition(ctx->text.sink, position, ctx->text.left_margin,
1367 wwidth, ctx->text.wrap == XawtextWrapWord,
1368 &end, &width, &height);
1370 if (lt->position != position) {
1371 _XawTextNeedsUpdating(ctx, position,
1372 end <= position ? position + 1 : end);
1373 ctx->text.clear_to_eol = True;
1374 lt->position = position;
1377 if (update_from < 0)
1378 update_from = line == 0 ?
1379 ctx->text.lt.info[0].position :
1380 ctx->text.lt.info[line - 1].position;
1382 ctx->text.clear_to_eol = True;
1384 if (lt->textWidth != width) {
1385 if (lt->textWidth > width)
1386 ctx->text.clear_to_eol = True;
1387 lt->textWidth = width;
1391 if (end > ctx->text.lastPos) {
1393 ctx->text.clear_to_eol = True;
1394 _XawTextNeedsUpdating(ctx, end, end + ctx->text.lt.lines - line);
1395 while (line++ < ctx->text.lt.lines) {
1396 if (line > 1 && y > max_y) {
1397 ctx->text.lt.lines = line - 1;
1402 if (update_from < 0)
1403 update_from = line < 2 ?
1404 ctx->text.lt.info[0].position :
1405 ctx->text.lt.info[line - 2].position;
1408 lt->position = ++position;
1412 if (update_from >= 0)
1413 _XawTextNeedsUpdating(ctx, update_from,
1414 ctx->text.lt.info[ctx->text.lt.lines].position);
1415 _XawTextSetScrollBars(ctx);
1417 return (ctx->text.lastPos);
1420 if (line && y > max_y)
1421 /* will return in the next loop */
1422 ctx->text.lt.lines = line;
1424 if (++line > ctx->text.lt.lines && y < max_y) {
1425 /* grow the line table */
1426 ctx->text.lt.info = (XawTextLineTableEntry *)
1427 XtRealloc((char *)ctx->text.lt.info,
1428 sizeof(XawTextLineTableEntry) * (line + 1));
1429 lt = ctx->text.lt.info + line;
1430 bzero(lt, sizeof(XawTextLineTableEntry));
1431 ++ctx->text.lt.lines;
1435 if (position == end)
1440 if (line > ctx->text.lt.lines) {
1441 if (update_from >= 0)
1442 _XawTextNeedsUpdating(ctx, update_from,
1443 ctx->text.lt.info[ctx->text.lt.lines].position);
1444 _XawTextSetScrollBars(ctx);
1460 * Returns the width (in pixels) of the widest line that
1461 * is currently visable.
1464 * The width of the widest line
1467 GetWidestLine(TextWidget ctx)
1470 unsigned int widest;
1471 XawTextLineTablePtr lt = &(ctx->text.lt);
1473 for (i = 0, widest = 0; i < lt->lines; i++)
1474 if (widest < lt->info[i].textWidth)
1475 widest = lt->info[i].textWidth;
1481 * This routine is used by Text to notify an associated scrollbar of the
1482 * correct metrics (position and shown fraction) for the text being currently
1483 * displayed in the window.
1486 _XawTextSetScrollBars(TextWidget ctx)
1488 float first, last, denom, widest;
1490 if (ctx->text.scroll_vert == XawtextScrollAlways) {
1491 if (ctx->text.lastPos == 0)
1494 first = ctx->text.lt.top / (float)ctx->text.lastPos;
1496 if (ctx->text.lt.info[ctx->text.lt.lines].position < ctx->text.lastPos)
1497 last = ctx->text.lt.info[ctx->text.lt.lines].position /
1498 (float)ctx->text.lastPos;
1502 XawScrollbarSetThumb(ctx->text.vbar, first, last - first);
1505 if (ctx->text.scroll_horiz == XawtextScrollAlways) {
1506 denom = GetWidestLine(ctx);
1508 denom = (int)XtWidth(ctx) - RHMargins(ctx);
1511 widest = ((int)XtWidth(ctx) - RHMargins(ctx)) / denom;
1512 first = ctx->text.r_margin.left - ctx->text.left_margin;
1515 XawScrollbarSetThumb(ctx->text.hbar, first, widest);
1520 DoCopyArea(TextWidget ctx, int src_x, int src_y,
1521 unsigned int width, unsigned int height, int dst_x, int dst_y)
1525 x1 = ctx->text.r_margin.left;
1526 y1 = ctx->text.r_margin.top;
1527 x2 = XtWidth(ctx) - ctx->text.r_margin.right;
1528 y2 = XtHeight(ctx) - ctx->text.r_margin.bottom;
1530 if (x1 >= x2 || y1 >= y2)
1533 src_x = XawMax(x1, XawMin(src_x, x2));
1534 src_y = XawMax(y1, XawMin(src_y, y2));
1535 dst_x = XawMax(x1, XawMin(dst_x, x2));
1536 dst_y = XawMax(y1, XawMin(dst_y, y2));
1537 width = XawMax(0, XawMin(x2 - dst_x, (int)width));
1538 height = XawMax(0, XawMin(y2 - dst_y, (int)height));
1540 XCopyArea(XtDisplay(ctx), XtWindow(ctx), XtWindow(ctx), ctx->text.gc,
1541 src_x, src_y, width, height, dst_x, dst_y);
1550 * vlines - number of lines to scroll vertically
1551 * hpixels - number of pixels to scroll horizontally
1554 * Generic function for scrolling the text window.
1555 * Allows vertical and horizontal scroll at the same time.
1558 XawTextScroll(TextWidget ctx, int vlines, int hpixels)
1560 XawTextPosition top, tmp, update_from, update_to;
1561 XawTextLineTable *lt;
1563 int y0, y1, y2, count, dim, wwidth, lines = ctx->text.lt.lines;
1564 int vwidth, vheight; /* visible width and height */
1567 vwidth = (int)XtWidth(ctx) - RHMargins(ctx);
1568 vheight = (int)XtHeight(ctx) - RVMargins(ctx);
1571 if (!lt || vwidth <= 0 || vheight <= 0)
1574 if ((scroll = ctx->core.background_pixmap == XtUnspecifiedPixmap) == True) {
1575 dim = lt->info[1].y - lt->info[0].y;
1576 for (count = 1; count < lt->lines - 1; count++)
1577 if (lt->info[count + 1].y - lt->info[count].y != dim) {
1583 wwidth = GetMaxTextWidth(ctx);
1586 * Do the horizontall scrolling
1588 if (hpixels < 0 && ctx->text.left_margin - hpixels > ctx->text.r_margin.left)
1589 hpixels = ctx->text.left_margin - ctx->text.r_margin.left;
1590 ctx->text.left_margin -= hpixels;
1592 update_from = lt->top; /* remember the old value */
1594 * Checks the requested number of lines and calculates the top
1597 if (vlines < 0) { /* VScroll Up */
1598 if (IsPositionVisible(ctx, 0))
1600 else if (ctx->text.wrap != XawtextWrapNever) {
1601 XawTextPosition end;
1606 while (n_lines < count) {
1607 top = SrcScan(ctx->text.source, end, XawstEOL,
1608 XawsdLeft, 2, False);
1609 n_lines += CountLines(ctx, top, end);
1613 while (count++ < n_lines) {
1615 XawTextSinkFindPosition(ctx->text.sink, top,
1616 ctx->text.left_margin,
1617 wwidth,ctx->text.wrap == XawtextWrapWord,
1624 top = SrcScan(ctx->text.source, lt->top, XawstEOL,
1625 XawsdLeft, -vlines + 1, False);
1626 if (-vlines >= ctx->text.lt.lines)
1629 else if (vlines > 0) { /* VScroll Down */
1630 if (LineForPosition(ctx, ctx->text.lastPos) == 0)
1632 if (vlines < lt->lines)
1633 top = XawMin(lt->info[vlines].position, ctx->text.lastPos);
1634 else if (ctx->text.wrap == XawtextWrapNever)
1635 top = SrcScan(ctx->text.source,
1636 SrcScan(ctx->text.source, lt->top,
1637 XawstEOL, XawsdRight, vlines,
1639 XawstEOL, XawsdLeft, 1, False);
1643 while (count++ < vlines) {
1645 XawTextSinkFindPosition(ctx->text.sink, top,
1646 ctx->text.left_margin,
1647 wwidth, ctx->text.wrap == XawtextWrapWord,
1653 if (vlines >= ctx->text.lt.lines
1654 || lt->info[vlines].position >= ctx->text.lastPos)
1661 ctx->text.clear_to_eol = True;
1663 _XawTextSetScrollBars(ctx);
1667 /* Flushes any pending updates. Normally, there may be a call to
1668 * XawTextUnsetSelection not yet updated.
1670 if (!hpixels && scroll) {
1671 ctx->text.clear_to_eol = True;
1676 * Rebuild the line table, doing the vertical scroll
1678 (void)_BuildLineTable(ctx, top, 0);
1681 for (count = 0; count < lt->lines - 1; count++)
1682 if (lt->info[count + 1].y - lt->info[count].y != dim) {
1688 XtSetArg(arglist[0], XtNinsertPosition, lt->top + lt->lines);
1689 _XawImSetValues((Widget)ctx, arglist, 1);
1691 if (hpixels || !scroll || lines != lt->lines)
1694 /* _BuildLineTable updates everything if the top position changes.
1695 * It is not required here.
1697 (void)XmuScanlineXor(ctx->text.update, ctx->text.update);
1698 if (vlines < 0 && IsPositionVisible(ctx, 0))
1699 vlines = -LineForPosition(ctx, update_from);
1701 y0 = ctx->text.r_margin.top;
1703 update_from = lt->top;
1704 update_to = lt->info[-vlines + 1].position - 1;
1705 y1 = lt->info[lt->lines + vlines].y;
1706 y2 = lt->info[-vlines].y;
1707 DoCopyArea(ctx, ctx->text.r_margin.left, y0, vwidth,
1709 ctx->text.r_margin.left, y2);
1712 update_from = lt->info[lt->lines - vlines].position;
1713 update_to = lt->info[lt->lines].position;
1714 y1 = lt->info[lt->lines - vlines].y;
1715 y2 = lt->info[vlines].y;
1716 DoCopyArea(ctx, ctx->text.r_margin.left, y2,
1717 vwidth, lt->info[lt->lines].y - y2,
1718 ctx->text.r_margin.left, y0);
1720 _XawTextNeedsUpdating(ctx, update_from, update_to);
1721 ctx->text.clear_to_eol = True;
1725 * The routine will scroll the displayed text by lines. If the arg is
1726 * positive, move up; otherwise, move down. [note: this is really a private
1727 * procedure but is used in multiple modules].
1730 _XawTextVScroll(TextWidget ctx, int n)
1732 XawTextScroll(ctx, n, 0);
1737 HScroll(Widget w, XtPointer closure, XtPointer callData)
1739 TextWidget ctx = (TextWidget)closure;
1740 long pixels = (long)callData;
1745 max = (int)GetWidestLine(ctx) + ctx->text.left_margin -
1746 ctx->text.r_margin.left;
1747 max = XawMax(0, max);
1748 pixels = XawMin(pixels, max);
1752 _XawTextPrepareToUpdate(ctx);
1753 XawTextScroll(ctx, 0, pixels);
1754 _XawTextExecuteUpdate(ctx);
1760 HJump(Widget w, XtPointer closure, XtPointer callData)
1762 TextWidget ctx = (TextWidget)closure;
1763 float percent = *(float *)callData;
1766 pixels = ctx->text.left_margin -
1767 (ctx->text.r_margin.left - (int)(percent * GetWidestLine(ctx)));
1769 HScroll(w, (XtPointer)ctx, (XtPointer)pixels);
1778 * line - line to update
1783 * Updates the text in the given line and pixel interval
1786 UpdateTextInLine(TextWidget ctx, int line, int x1, int x2)
1788 XawTextLineTableEntry *lt = ctx->text.lt.info + line;
1789 XawTextPosition left, right;
1790 int from_x, width, height;
1792 if (lt->position >= ctx->text.lastPos
1793 || ctx->text.left_margin > x2
1794 || (int)lt->textWidth + ctx->text.left_margin < x1) {
1795 /* Mark line to be cleared */
1796 if (ctx->text.clear_to_eol)
1797 _XawTextNeedsUpdating(ctx, lt->position, lt->position + 1);
1801 from_x = ctx->text.left_margin;
1802 XawTextSinkFindPosition(ctx->text.sink, lt->position,
1803 from_x, x1 - from_x,
1804 False, &left, &width, &height);
1805 if (line == ctx->text.lt.lines)
1807 else if (x2 >= lt->textWidth - from_x)
1808 right = lt[1].position - 1;
1811 XawTextSinkFindPosition(ctx->text.sink, left,
1812 from_x, x2 - from_x,
1813 False, &right, &width, &height);
1816 if ((right < 0) || (right + 1 <= lt[1].position))
1819 /* Mark text interval to be repainted */
1820 _XawTextNeedsUpdating(ctx, left, right);
1824 * The routine will scroll the displayed text by pixels. If the calldata is
1825 * positive, move up; otherwise, move down.
1829 VScroll(Widget w, XtPointer closure, XtPointer callData)
1831 TextWidget ctx = (TextWidget)closure;
1832 long height, lines = (long)callData;
1834 height = XtHeight(ctx) - VMargins(ctx);
1837 lines = (lines * ctx->text.lt.lines) / height;
1838 _XawTextPrepareToUpdate(ctx);
1839 XawTextScroll(ctx, lines, 0);
1840 _XawTextExecuteUpdate(ctx);
1845 VJump(Widget w, XtPointer closure, XtPointer callData)
1847 float percent = *(float *)callData;
1848 TextWidget ctx = (TextWidget)closure;
1849 XawTextPosition top, last, position, tmp;
1850 XawTextLineTable *lt = &(ctx->text.lt);
1851 int dim, vlines = 0, wwidth = GetMaxTextWidth(ctx);
1854 position = percent * ctx->text.lastPos;
1857 if (!lt->lines || (position >= lt->top && position < lt->info[1].position)) {
1858 _XawTextSetScrollBars(ctx);
1863 ctx->text.lt.base_line = -1;
1866 if (position > lt->top) { /* VScroll Up */
1867 if (position > lt->top && position < lt->info[lt->lines].position)
1868 vlines = LineForPosition(ctx, position);
1871 top = SrcScan(ctx->text.source, position, XawstEOL,
1872 XawsdLeft, 1, False);
1873 if (ctx->text.wrap != XawtextWrapNever) {
1875 while (last < position) {
1877 XawTextSinkFindPosition(ctx->text.sink, last,
1878 ctx->text.left_margin, wwidth,
1879 ctx->text.wrap == XawtextWrapWord,
1883 if (last < position)
1889 else { /* VScroll Down */
1891 * Calculates the number of lines
1893 while (top > position) {
1895 top = SrcScan(ctx->text.source, top, XawstEOL,
1896 XawsdLeft, 2, False);
1897 vlines -= CountLines(ctx, top, last);
1898 if (-vlines >= ctx->text.lt.lines) {
1900 top = SrcScan(ctx->text.source, position, XawstEOL,
1901 XawsdLeft, 1, False);
1908 if (ctx->text.wrap != XawtextWrapNever) {
1910 while (last < position) {
1912 XawTextSinkFindPosition(ctx->text.sink, last,
1913 ctx->text.left_margin,
1915 ctx->text.wrap == XawtextWrapWord,
1919 if (last < position)
1926 if (vlines || !scroll) {
1927 _XawTextPrepareToUpdate(ctx);
1929 XawTextScroll(ctx, vlines, 0);
1931 _BuildLineTable(ctx, top, 0);
1932 _XawTextExecuteUpdate(ctx);
1937 MatchSelection(Atom selection, XawTextSelection *s)
1942 for (count = 0, match = s->selections; count < s->atom_count;
1944 if (*match == selection)
1951 TextConvertSelection(Widget w, Atom *selection, Atom *target, Atom *type,
1952 XtPointer *value, unsigned long *length, int *format)
1954 Display *d = XtDisplay(w);
1955 TextWidget ctx = (TextWidget)w;
1956 Widget src = ctx->text.source;
1957 XawTextEditType edit_mode;
1959 XawTextSelectionSalt *salt = NULL;
1960 XawTextSelection *s;
1962 if (*target == XA_TARGETS(d)) {
1963 Atom *targetP, *std_targets;
1964 unsigned long std_length;
1966 if (SrcCvtSel(src, selection, target, type, value, length, format))
1969 XtSetArg(args[0], XtNeditType, &edit_mode);
1970 XtGetValues(src, args, ONE);
1972 XmuConvertStandardSelection(w, ctx->text.time, selection,
1973 target, type, (XPointer*)&std_targets,
1974 &std_length, format);
1976 *length = 7 + (edit_mode == XawtextEdit) + std_length;
1977 *value = XtMalloc((unsigned)sizeof(Atom)*(*length));
1978 targetP = *(Atom**)value;
1979 *targetP++ = XA_STRING;
1980 *targetP++ = XA_TEXT(d);
1981 *targetP++ = XA_UTF8_STRING(d);
1982 *targetP++ = XA_COMPOUND_TEXT(d);
1983 *targetP++ = XA_LENGTH(d);
1984 *targetP++ = XA_LIST_LENGTH(d);
1985 *targetP++ = XA_CHARACTER_POSITION(d);
1986 if (edit_mode == XawtextEdit) {
1987 *targetP++ = XA_DELETE(d);
1989 (void)memmove((char*)targetP, (char*)std_targets,
1990 sizeof(Atom) * std_length);
1991 XtFree((char*)std_targets);
1997 if (SrcCvtSel(src, selection, target, type, value, length, format))
2000 if (MatchSelection(*selection, &ctx->text.s))
2003 for (salt = ctx->text.salt; salt; salt = salt->next)
2004 if (MatchSelection(*selection, &salt->s))
2010 if (*target == XA_STRING
2011 || *target == XA_TEXT(d)
2012 || *target == XA_UTF8_STRING(d)
2013 || *target == XA_COMPOUND_TEXT(d)) {
2014 if (*target == XA_TEXT(d)) {
2015 if (XawTextFormat(ctx, XawFmtWide))
2016 *type = XA_COMPOUND_TEXT(d);
2023 * If salt is True, the salt->contents stores CT string,
2024 * its length is measured in bytes.
2025 * Refer to _XawTextSaltAwaySelection().
2027 * by Li Yuhong, Mar. 20, 1991.
2030 *value = _XawTextGetSTRING(ctx, s->left, s->right);
2031 if (XawTextFormat(ctx, XawFmtWide)) {
2032 XTextProperty textprop;
2033 if (XwcTextListToTextProperty(d, (wchar_t **)value, 1,
2034 XCompoundTextStyle, &textprop)
2036 XtFree((char *)*value);
2039 XtFree((char *)*value);
2040 *value = (XtPointer)textprop.value;
2041 *length = textprop.nitems;
2044 *length = strlen((char *)*value);
2047 *value = XtMalloc((salt->length + 1) * sizeof(unsigned char));
2048 strcpy ((char *)*value, salt->contents);
2049 *length = salt->length;
2051 /* Got *value,*length, now in COMPOUND_TEXT format. */
2052 if (XawTextFormat(ctx, XawFmtWide) && *type == XA_STRING) {
2053 XTextProperty textprop;
2057 textprop.encoding = XA_COMPOUND_TEXT(d);
2058 textprop.value = (unsigned char *)*value;
2059 textprop.nitems = strlen(*value);
2060 textprop.format = 8;
2061 if (XwcTextPropertyToTextList(d, &textprop, &wlist, &count)
2064 XtFree((char *)*value);
2067 XtFree((char *)*value);
2068 if (XwcTextListToTextProperty(d, wlist, 1, XStringStyle, &textprop)
2070 XwcFreeStringList((wchar_t**) wlist);
2073 *value = (XtPointer)textprop.value;
2074 *length = textprop.nitems;
2075 XwcFreeStringList(wlist);
2076 } else if (*type == XA_UTF8_STRING(d)) {
2077 XTextProperty textprop;
2081 textprop.encoding = XA_COMPOUND_TEXT(d);
2082 textprop.value = (unsigned char *)*value;
2083 textprop.nitems = strlen(*value);
2084 textprop.format = 8;
2085 if (Xutf8TextPropertyToTextList(d, &textprop, &list, &count)
2088 XtFree((char *)*value);
2091 XtFree((char *)*value);
2093 *length = strlen(*list);
2100 if ((*target == XA_LIST_LENGTH(d)) || (*target == XA_LENGTH(d))) {
2103 temp = (long *)XtMalloc((unsigned)sizeof(long));
2104 if (*target == XA_LIST_LENGTH(d))
2106 else /* *target == XA_LENGTH(d) */
2107 *temp = (long) (s->right - s->left);
2109 *value = (XPointer)temp;
2116 if (*target == XA_CHARACTER_POSITION(d)) {
2119 temp = (long *)XtMalloc((unsigned)(2 * sizeof(long)));
2120 temp[0] = (long)(s->left + 1);
2122 *value = (XPointer)temp;
2129 if (*target == XA_DELETE(d)) {
2131 _XawTextZapSelection(ctx, NULL, True);
2139 if (XmuConvertStandardSelection(w, ctx->text.time, selection, target, type,
2140 (XPointer *)value, length, format))
2149 * GetCutBuffferNumber
2152 * atom - atom to check
2155 * Returns the number of the cut buffer.
2158 * The number of the cut buffer representing this atom or NOT_A_CUT_BUFFER
2160 #define NOT_A_CUT_BUFFER -1
2162 GetCutBufferNumber(Atom atom)
2164 if (atom == XA_CUT_BUFFER0) return (0);
2165 if (atom == XA_CUT_BUFFER1) return (1);
2166 if (atom == XA_CUT_BUFFER2) return (2);
2167 if (atom == XA_CUT_BUFFER3) return (3);
2168 if (atom == XA_CUT_BUFFER4) return (4);
2169 if (atom == XA_CUT_BUFFER5) return (5);
2170 if (atom == XA_CUT_BUFFER6) return (6);
2171 if (atom == XA_CUT_BUFFER7) return (7);
2172 return (NOT_A_CUT_BUFFER);
2176 TextLoseSelection(Widget w, Atom *selection)
2178 TextWidget ctx = (TextWidget)w;
2181 XawTextSelectionSalt*salt, *prevSalt, *nextSalt;
2183 atomP = ctx->text.s.selections;
2184 for (i = 0 ; i < ctx->text.s.atom_count; i++, atomP++)
2185 if ((*selection == *atomP)
2186 || (GetCutBufferNumber(*atomP) != NOT_A_CUT_BUFFER))
2189 while (ctx->text.s.atom_count
2190 && ctx->text.s.selections[ctx->text.s.atom_count - 1] == 0)
2191 ctx->text.s.atom_count--;
2194 * Must walk the selection list in opposite order from UnsetSelection
2196 atomP = ctx->text.s.selections;
2197 for (i = 0 ; i < ctx->text.s.atom_count; i++, atomP++)
2198 if (*atomP == (Atom)0) {
2199 *atomP = ctx->text.s.selections[--ctx->text.s.atom_count];
2200 while (ctx->text.s.atom_count
2201 && ctx->text.s.selections[ctx->text.s.atom_count-1] == 0)
2202 ctx->text.s.atom_count--;
2205 if (ctx->text.s.atom_count == 0)
2206 ModifySelection(ctx, ctx->text.insertPos, ctx->text.insertPos);
2209 for (salt = ctx->text.salt; salt; salt = nextSalt) {
2210 atomP = salt->s.selections;
2211 nextSalt = salt->next;
2212 for (i = 0 ; i < salt->s.atom_count; i++, atomP++)
2213 if (*selection == *atomP)
2216 while (salt->s.atom_count
2217 && salt->s.selections[salt->s.atom_count-1] == 0)
2218 salt->s.atom_count--;
2221 * Must walk the selection list in opposite order from UnsetSelection
2223 atomP = salt->s.selections;
2224 for (i = 0 ; i < salt->s.atom_count; i++, atomP++)
2225 if (*atomP == (Atom)0) {
2226 *atomP = salt->s.selections[--salt->s.atom_count];
2227 while (salt->s.atom_count
2228 && salt->s.selections[salt->s.atom_count-1] == 0)
2229 salt->s.atom_count--;
2232 if (salt->s.atom_count == 0) {
2233 XtFree ((char *) salt->s.selections);
2234 XtFree (salt->contents);
2236 prevSalt->next = nextSalt;
2238 ctx->text.salt = nextSalt;
2239 XtFree((char *)salt);
2247 _XawTextSaltAwaySelection(TextWidget ctx, Atom *selections, int num_atoms)
2249 XawTextSelectionSalt *salt;
2252 for (i = 0; i < num_atoms; i++)
2253 TextLoseSelection((Widget)ctx, selections + i);
2256 salt = (XawTextSelectionSalt *)
2257 XtMalloc((unsigned)sizeof(XawTextSelectionSalt));
2260 salt->s.selections = (Atom *)XtMalloc((unsigned)(num_atoms * sizeof(Atom)));
2261 if (!salt->s.selections) {
2262 XtFree((char *)salt);
2265 salt->s.left = ctx->text.s.left;
2266 salt->s.right = ctx->text.s.right;
2267 salt->s.type = ctx->text.s.type;
2268 salt->contents = _XawTextGetSTRING(ctx, ctx->text.s.left, ctx->text.s.right);
2269 if (XawTextFormat(ctx, XawFmtWide)) {
2270 XTextProperty textprop;
2271 if (XwcTextListToTextProperty(XtDisplay((Widget)ctx),
2272 (wchar_t**)(&(salt->contents)), 1,
2274 &textprop) < Success) {
2275 XtFree(salt->contents);
2279 XtFree(salt->contents);
2280 salt->contents = (char *)textprop.value;
2281 salt->length = textprop.nitems;
2284 salt->length = strlen (salt->contents);
2285 salt->next = ctx->text.salt;
2286 ctx->text.salt = salt;
2288 for (i = 0; i < num_atoms; i++) {
2289 if (GetCutBufferNumber (selections[i]) == NOT_A_CUT_BUFFER) {
2290 salt->s.selections[j++] = selections[i];
2291 XtOwnSelection((Widget)ctx, selections[i], ctx->text.time,
2292 TextConvertSelection, TextLoseSelection, NULL);
2295 salt->s.atom_count = j;
2299 _SetSelection(TextWidget ctx, XawTextPosition left, XawTextPosition right,
2300 Atom *selections, Cardinal count)
2304 XawTextPosition pos;
2305 TextSrcObject src = (TextSrcObject)ctx->text.source;
2307 for (i = 0; i < src->textSrc.num_text; i++) {
2308 TextWidget tw = (TextWidget)src->textSrc.text[i];
2309 Bool needs_updating = tw->text.old_insert < 0;
2310 Bool showposition = tw->text.showposition;
2312 if (needs_updating) {
2313 tw->text.showposition = False;
2314 _XawTextPrepareToUpdate(tw);
2317 TextWidget tw = ctx;
2318 XawTextPosition pos;
2321 if (left < tw->text.s.left) {
2322 pos = Min(right, tw->text.s.left);
2323 _XawTextNeedsUpdating(tw, left, pos);
2325 if (left > tw->text.s.left) {
2326 pos = Min(left, tw->text.s.right);
2327 _XawTextNeedsUpdating(tw, tw->text.s.left, pos);
2329 if (right < tw->text.s.right) {
2330 pos = Max(right, tw->text.s.left);
2331 _XawTextNeedsUpdating(tw, pos, tw->text.s.right);
2333 if (right > tw->text.s.right) {
2334 pos = Max(left, tw->text.s.right);
2335 _XawTextNeedsUpdating(tw, pos, right);
2338 tw->text.s.left = left;
2339 tw->text.s.right = right;
2342 if (needs_updating) {
2343 _XawTextExecuteUpdate(tw);
2344 tw->text.showposition = showposition;
2349 SrcSetSelection(ctx->text.source, left, right,
2350 (count == 0) ? None : selections[0]);
2353 Widget w = (Widget)ctx;
2357 Atom selection = selections[--count];
2360 * If this is a cut buffer
2362 if ((buffer = GetCutBufferNumber(selection)) != NOT_A_CUT_BUFFER) {
2363 unsigned char *ptr, *tptr;
2364 unsigned int amount, max_len = MAX_CUT_LEN(XtDisplay(w));
2367 tptr= ptr= (unsigned char *)_XawTextGetSTRING(ctx,
2370 if (XawTextFormat(ctx, XawFmtWide)) {
2372 * Only XA_STRING(Latin 1) is allowed in CUT_BUFFER,
2373 * so we get it from wchar string, then free the wchar string
2375 XTextProperty textprop;
2377 if (XwcTextListToTextProperty(XtDisplay(w), (wchar_t**)&ptr,
2378 1, XStringStyle, &textprop)
2380 XtFree((char *)ptr);
2383 XtFree((char *)ptr);
2384 tptr = ptr = textprop.value;
2387 _CreateCutBuffers(XtDisplay(w));
2388 XRotateBuffers(XtDisplay(w), 1);
2390 amount = Min ((len = strlen((char *)ptr)), max_len);
2391 XChangeProperty(XtDisplay(w), RootWindow(XtDisplay(w), 0),
2392 selection, XA_STRING, 8, PropModeReplace,
2395 while (len > max_len) {
2398 amount = Min (len, max_len);
2399 XChangeProperty(XtDisplay(w), RootWindow(XtDisplay(w), 0),
2400 selection, XA_STRING, 8, PropModeAppend,
2403 XtFree ((char *)ptr);
2405 else /* This is a real selection */
2406 XtOwnSelection(w, selection, ctx->text.time, TextConvertSelection,
2407 TextLoseSelection, NULL);
2411 XawTextUnsetSelection((Widget)ctx);
2416 _XawTextSetLineAndColumnNumber(TextWidget ctx, Bool force)
2418 int line_number, column_number;
2420 if (ctx->text.old_insert != ctx->text.insertPos &&
2421 ctx->text.lt.base_line < 0) {
2422 ctx->text.lt.base_line = 0;
2423 (void)_BuildLineTable(ctx, ctx->text.lt.top, 0);
2426 line_number = ResolveLineNumber(ctx);
2427 column_number = ResolveColumnNumber(ctx);
2429 if (force || (ctx->text.column_number != column_number
2430 || ctx->text.line_number != line_number)) {
2431 XawTextPositionInfo info;
2433 ctx->text.line_number = info.line_number = line_number;
2434 ctx->text.column_number = info.column_number = column_number;
2435 info.insert_position = ctx->text.insertPos;
2436 info.last_position = ctx->text.lastPos;
2437 info.overwrite_mode = ctx->text.overwrite;
2439 XtCallCallbacks((Widget)ctx, XtNpositionCallback, (XtPointer)&info);
2444 ResolveColumnNumber(TextWidget ctx)
2446 Widget src = ctx->text.source;
2447 short column_number = 0;
2448 XawTextPosition position;
2450 unsigned long format = _XawTextFormat(ctx);
2451 TextSinkObject sink = (TextSinkObject)ctx->text.sink;
2452 short *char_tabs = sink->text_sink.char_tabs;
2453 int tab_count = sink->text_sink.tab_count;
2454 int tab_index = 0, tab_column = 0, tab_base = 0;
2456 if (ctx->text.lt.base_line < 1)
2457 return (ctx->text.column_number);
2459 position = SrcScan(src, ctx->text.insertPos, XawstEOL, XawsdLeft, 1, False);
2460 XawTextSourceRead(src, position, &block, ctx->text.insertPos - position);
2462 for (; position < ctx->text.insertPos; position++) {
2463 if (position - block.firstPos >= block.length)
2464 XawTextSourceRead(src, position, &block, ctx->text.insertPos - position);
2465 if ((format == XawFmt8Bit && block.ptr[position - block.firstPos] == '\t') ||
2466 (format == XawFmtWide && ((wchar_t*)block.ptr)[position - block.firstPos] == _Xaw_atowc(XawTAB))) {
2467 while (tab_base + tab_column <= column_number) {
2469 for (; tab_index < tab_count; ++tab_index)
2470 if (tab_base + char_tabs[tab_index] > column_number) {
2471 tab_column = char_tabs[tab_index];
2474 if (tab_index >= tab_count) {
2475 tab_base += char_tabs[tab_count - 1];
2476 tab_column = tab_index = 0;
2480 tab_column += DEFAULT_TAB_SIZE;
2482 column_number = tab_base + tab_column;
2486 if (column_number >= 16384) {
2487 column_number = 16383;
2492 return (column_number);
2497 _XawTextSourceChanged(Widget w, XawTextPosition left, XawTextPosition right,
2498 XawTextBlock *block, int lines)
2500 TextWidget ctx = (TextWidget)w;
2501 Widget src = ctx->text.source;
2502 XawTextPosition update_from, update_to, top;
2503 Boolean update_disabled;
2504 int delta, line, line_from;
2506 if (left < ctx->text.old_insert) {
2507 XawTextPosition old_insert = ctx->text.old_insert;
2509 if (right < ctx->text.old_insert)
2510 old_insert -= right - left;
2514 ctx->text.insertPos = old_insert + block->length;
2517 if (left <= ctx->text.lt.top) {
2518 if (left + block->length - (right - left) < ctx->text.lt.top) {
2519 ctx->text.source_changed = SRC_CHANGE_BEFORE;
2520 ctx->text.lt.base_line += lines;
2523 ctx->text.source_changed = SRC_CHANGE_OVERLAP;
2526 ctx->text.source_changed = SRC_CHANGE_AFTER;
2530 update_to = left + block->length;
2531 update_to = SrcScan(src, update_to, XawstEOL, XawsdRight, 1, False);
2532 delta = block->length - (right - left);
2534 ctx->text.clear_to_eol = True;
2535 if (update_to == update_from)
2537 update_disabled = ctx->text.update_disabled;
2538 ctx->text.update_disabled = True;
2539 ctx->text.lastPos = XawTextGetLastPosition(ctx);
2540 top = ctx->text.lt.info[0].position;
2542 XawTextUnsetSelection((Widget)ctx);
2548 for (seg = ctx->text.update->segment; seg; seg = seg->next) {
2549 if (seg->x1 > (int)left)
2551 else if (seg->x2 > (int)left) {
2557 for (; seg; seg = seg->next) {
2561 XmuOptimizeScanline(ctx->text.update);
2563 for (i = 0; i <= ctx->text.lt.lines; i++)
2564 if (ctx->text.lt.info[i].position > left)
2566 for (; i <= ctx->text.lt.lines; i++)
2567 ctx->text.lt.info[i].position += delta;
2570 if (top != ctx->text.lt.info[0].position) {
2571 line_from = line = 0;
2572 ctx->text.lt.top = top = SrcScan(src, ctx->text.lt.info[0].position,
2573 XawstEOL, XawsdLeft, 1, False);
2577 line_from = line = LineForPosition(ctx, update_from + delta);
2578 top = ctx->text.lt.info[line].position;
2581 if (line > 0 && ctx->text.wrap == XawtextWrapWord) {
2583 top = ctx->text.lt.info[line].position;
2586 (void)_BuildLineTable(ctx, top, line);
2588 if (ctx->text.wrap == XawtextWrapWord) {
2589 if (line_from != LineForPosition(ctx, update_from)
2590 || line_from != LineForPosition(ctx, update_to)) {
2591 ctx->text.clear_to_eol = True;
2592 update_from = SrcScan(src, update_from,
2593 XawstWhiteSpace, XawsdLeft, 1, True);
2594 if (update_to >= ctx->text.lastPos)
2595 /* this is not an error, it just tells _BuildLineTable to
2596 * clear to the bottom of the window. The value of update_to
2597 * should not be > ctx->text.lastPos.
2602 else if (!ctx->text.clear_to_eol) {
2603 if (LineForPosition(ctx, update_from)
2604 != LineForPosition(ctx, update_to))
2605 ctx->text.clear_to_eol = True;
2608 _XawTextNeedsUpdating(ctx, update_from, update_to);
2609 ctx->text.update_disabled = update_disabled;
2618 * left - left offset
2619 * right - right offset
2620 * block - text block
2623 * Replaces the text between left and right by the text in block.
2624 * Does all the required calculations of offsets, and rebuild the
2625 * the line table, from the insertion point (or previous line, if
2626 * wrap mode is 'word').
2629 * XawEditDone - success
2630 * any other value - error code
2633 _XawTextReplace(TextWidget ctx, XawTextPosition left, XawTextPosition right,
2634 XawTextBlock *block)
2638 XawTextEditType edit_mode;
2640 if (left == right && block->length == 0)
2641 return (XawEditDone);
2643 src = ctx->text.source;
2644 XtSetArg(args[0], XtNeditType, &edit_mode);
2645 XtGetValues(src, args, 1);
2647 if (edit_mode == XawtextAppend) {
2648 if (block->length == 0)
2649 return (XawEditError);
2650 ctx->text.insertPos = ctx->text.lastPos;
2654 return (SrcReplace(src, left, right, block));
2656 if (SrcReplace(src, left, right, block) == XawEditDone) {
2657 _XawTextSourceChanged((Widget)ctx, left, right, block, 0);
2659 return (XawEditDone);
2662 return (XawEditError);
2667 * This routine will display text between two arbitrary source positions.
2668 * In the event that this span contains highlighted text for the selection,
2669 * only that portion will be displayed highlighted.
2672 OldDisplayText(Widget w, XawTextPosition left, XawTextPosition right)
2674 static XmuSegment segment;
2675 static XmuScanline next;
2676 static XmuScanline scanline = {0, &segment, &next};
2677 static XmuArea area = {&scanline};
2679 TextWidget ctx = (TextWidget)w;
2681 XawTextPosition start, end, last, final;
2684 XmuArea *clip = NULL;
2685 Bool cleol = ctx->text.clear_to_eol;
2686 Bool has_selection = ctx->text.s.right > ctx->text.s.left;
2688 left = left < ctx->text.lt.top ? ctx->text.lt.top : left;
2690 if (left > right || !LineAndXYForPosition(ctx, left, &line, &x, &y))
2693 last = XawTextGetLastPosition(ctx);
2694 segment.x2 = (int)XtWidth(ctx) - ctx->text.r_margin.right;
2697 clip = XmuCreateArea();
2699 for (start = left; start < right && line < ctx->text.lt.lines; line++) {
2700 if ((end = ctx->text.lt.info[line + 1].position) > right)
2709 || (start >= ctx->text.s.right || end <= ctx->text.s.left))
2710 _XawTextSinkDisplayText(ctx->text.sink, x, y, start, end, False);
2711 else if (start >= ctx->text.s.left && end <= ctx->text.s.right)
2712 _XawTextSinkDisplayText(ctx->text.sink, x, y, start, end, True);
2714 OldDisplayText(w, start, ctx->text.s.left);
2715 OldDisplayText(w, Max(start, ctx->text.s.left),
2716 Min(end, ctx->text.s.right));
2717 OldDisplayText(w, ctx->text.s.right, end);
2721 x = ctx->text.left_margin;
2723 segment.x1 = ctx->text.lt.info[line].textWidth + x;
2724 if (XmuValidSegment(&segment)) {
2726 next.y = ctx->text.lt.info[line + 1].y;
2727 XmuAreaOr(clip, &area);
2732 y = ctx->text.lt.info[line + 1].y;
2736 for (scan = clip->scanline; scan && scan->next; scan = scan->next)
2737 for (seg = scan->segment; seg; seg = seg->next)
2738 SinkClearToBG(ctx->text.sink,
2740 seg->x2 - seg->x1, scan->next->y - scan->y);
2741 XmuDestroyArea(clip);
2748 DisplayText(Widget w, XawTextPosition left, XawTextPosition right)
2750 static XmuSegment segment;
2751 static XmuScanline next;
2752 static XmuScanline scanline = {0, &segment, &next};
2753 static XmuArea area = {&scanline};
2755 TextWidget ctx = (TextWidget)w;
2757 XawTextPosition from, to, lastPos;
2758 Bool cleol = ctx->text.clear_to_eol;
2759 Bool has_selection = ctx->text.s.right > ctx->text.s.left;
2760 XawTextPaintList *paint_list;
2762 left = left < ctx->text.lt.top ? ctx->text.lt.top : left;
2764 if (left > right || !IsPositionVisible(ctx, left))
2767 line = LineForPosition(ctx, left);
2768 y = ctx->text.lt.info[line].y;
2769 segment.x2 = (int)XtWidth(ctx) - ctx->text.r_margin.right;
2770 lastPos = XawTextGetLastPosition(ctx);
2772 paint_list = ((TextSinkObject)ctx->text.sink)->text_sink.paint;
2774 for (from = left; from < right && line < ctx->text.lt.lines; line++) {
2775 if ((to = ctx->text.lt.info[line + 1].position) > right)
2783 || (from >= ctx->text.s.right || to <= ctx->text.s.left))
2784 XawTextSinkPreparePaint(ctx->text.sink, y, line, from, to, False);
2785 else if (from >= ctx->text.s.left && to <= ctx->text.s.right)
2786 XawTextSinkPreparePaint(ctx->text.sink, y, line, from, to, True);
2788 XawTextSinkPreparePaint(ctx->text.sink, y, line, from,
2789 ctx->text.s.left, False);
2790 XawTextSinkPreparePaint(ctx->text.sink, y, line,
2791 XawMax(from, ctx->text.s.left),
2792 XawMin(to, ctx->text.s.right), True);
2793 XawTextSinkPreparePaint(ctx->text.sink, y, line,
2794 ctx->text.s.right, to, False);
2799 segment.x1 = ctx->text.lt.info[line].textWidth + ctx->text.left_margin;
2800 if (XmuValidSegment(&segment)) {
2802 next.y = ctx->text.lt.info[line + 1].y;
2803 XmuAreaOr(paint_list->clip, &area);
2806 y = ctx->text.lt.info[line + 1].y;
2810 /* clear to the bottom of the window */
2811 if (cleol && line >= ctx->text.lt.lines) {
2812 segment.x1 = ctx->text.left_margin;
2813 if (XmuValidSegment(&segment)) {
2815 next.y = (int)XtHeight(ctx) - (int)ctx->text.margin.bottom;
2816 XmuAreaOr(paint_list->clip, &area);
2823 * This routine implements multi-click selection in a hardwired manner.
2824 * It supports multi-click entity cycling (char, word, line, file) and mouse
2825 * motion adjustment of the selected entitie (i.e. select a word then, with
2826 * button still down, adjust wich word you really meant by moving the mouse).
2827 * [NOTE: This routine is to be replaced by a set of procedures that
2828 * will allows clients to implements a wide class of draw through and
2829 * multi-click selection user interfaces.]
2832 DoSelection(TextWidget ctx, XawTextPosition pos, Time time, Bool motion)
2834 XawTextPosition newLeft, newRight;
2835 XawTextSelectType newType, *sarray;
2836 Widget src = ctx->text.source;
2839 newType = ctx->text.s.type;
2841 if ((abs((long) time - (long) ctx->text.lasttime) < MULTI_CLICK_TIME)
2842 && (pos >= ctx->text.s.left && pos <= ctx->text.s.right)) {
2843 sarray = ctx->text.sarray;
2844 for (; *sarray != XawselectNull && *sarray != ctx->text.s.type;
2847 if (*sarray == XawselectNull)
2848 newType = *(ctx->text.sarray);
2850 newType = *(sarray + 1);
2851 if (newType == XawselectNull)
2852 newType = *(ctx->text.sarray);
2855 else /* single-click event */
2856 newType = *(ctx->text.sarray);
2858 ctx->text.lasttime = time;
2861 case XawselectPosition:
2862 newLeft = newRight = pos;
2866 newRight = SrcScan(src, pos, XawstPositions, XawsdRight, 1, False);
2869 case XawselectParagraph:
2870 case XawselectAlphaNumeric: {
2871 XawTextScanType stype;
2873 if (newType == XawselectWord)
2874 stype = XawstWhiteSpace;
2875 else if (newType == XawselectParagraph)
2876 stype = XawstParagraph;
2878 stype = XawstAlphaNumeric;
2881 * Somewhat complicated, but basically I treat the space between
2882 * two objects as another object. The object that I am currently
2883 * in then becomes the end of the selection.
2885 * Chris Peterson - 4/19/90.
2887 newRight = SrcScan(ctx->text.source, pos, stype,
2888 XawsdRight, 1, False);
2889 newRight = SrcScan(ctx->text.source, newRight, stype,
2890 XawsdLeft, 1, False);
2892 if (pos != newRight)
2893 newLeft = SrcScan(ctx->text.source, pos, stype,
2894 XawsdLeft, 1, False);
2898 newLeft =SrcScan(ctx->text.source, newLeft, stype,
2899 XawsdRight, 1, False);
2901 if (newLeft > newRight) {
2902 XawTextPosition temp = newLeft;
2908 newLeft = SrcScan(src, pos, XawstEOL, XawsdLeft, 1, False);
2909 newRight = SrcScan(src, pos, XawstEOL, XawsdRight, 1, False);
2912 newLeft = SrcScan(src, pos, XawstAll, XawsdLeft, 1, False);
2913 newRight = SrcScan(src, pos, XawstAll, XawsdRight, 1, False);
2916 XtAppWarning(XtWidgetToApplicationContext((Widget) ctx),
2917 "Text Widget: empty selection array.");
2921 if (newLeft != ctx->text.s.left || newRight != ctx->text.s.right
2922 || newType != ctx->text.s.type) {
2923 ModifySelection(ctx, newLeft, newRight);
2924 if (pos - ctx->text.s.left < ctx->text.s.right - pos)
2925 ctx->text.insertPos = newLeft;
2927 ctx->text.insertPos = newRight;
2928 ctx->text.s.type = newType;
2930 if (!motion) { /* setup so we can freely mix select extend calls*/
2931 ctx->text.origSel.type = ctx->text.s.type;
2932 ctx->text.origSel.left = ctx->text.s.left;
2933 ctx->text.origSel.right = ctx->text.s.right;
2935 if (pos >= ctx->text.s.left + (ctx->text.s.right - ctx->text.s.left) / 2)
2936 ctx->text.extendDir = XawsdRight;
2938 ctx->text.extendDir = XawsdLeft;
2943 * This routine implements extension of the currently selected text in
2944 * the "current" mode (i.e. char word, line, etc.). It worries about
2945 * extending from either end of the selection and handles the case when you
2946 * cross through the "center" of the current selection (e.g. switch which
2947 * end you are extending!).
2950 ExtendSelection(TextWidget ctx, XawTextPosition pos, Bool motion)
2952 XawTextScanDirection dir;
2954 if (!motion) { /* setup for extending selection */
2955 if (ctx->text.s.left == ctx->text.s.right) /* no current selection. */
2956 ctx->text.s.left = ctx->text.s.right = ctx->text.insertPos;
2958 ctx->text.origSel.left = ctx->text.s.left;
2959 ctx->text.origSel.right = ctx->text.s.right;
2962 ctx->text.origSel.type = ctx->text.s.type;
2964 if (pos >= ctx->text.s.left + (ctx->text.s.right - ctx->text.s.left) / 2)
2965 ctx->text.extendDir = XawsdRight;
2967 ctx->text.extendDir = XawsdLeft;
2969 else /* check for change in extend direction */
2970 if ((ctx->text.extendDir == XawsdRight &&
2971 pos <= ctx->text.origSel.left) ||
2972 (ctx->text.extendDir == XawsdLeft &&
2973 pos >= ctx->text.origSel.right)) {
2974 ctx->text.extendDir = (ctx->text.extendDir == XawsdRight) ?
2975 XawsdLeft : XawsdRight;
2976 ModifySelection(ctx, ctx->text.origSel.left, ctx->text.origSel.right);
2979 dir = ctx->text.extendDir;
2980 switch (ctx->text.s.type) {
2982 case XawselectParagraph:
2983 case XawselectAlphaNumeric: {
2984 XawTextPosition left_pos, right_pos;
2985 XawTextScanType stype;
2987 if (ctx->text.s.type == XawselectWord)
2988 stype = XawstWhiteSpace;
2989 else if (ctx->text.s.type == XawselectParagraph)
2990 stype = XawstParagraph;
2992 stype = XawstAlphaNumeric;
2995 * Somewhat complicated, but basically I treat the space between
2996 * two objects as another object. The object that I am currently
2997 * in then becomes the end of the selection.
2999 * Chris Peterson - 4/19/90.
3001 right_pos = SrcScan(ctx->text.source, pos, stype,
3002 XawsdRight, 1, False);
3003 right_pos =SrcScan(ctx->text.source, right_pos, stype,
3004 XawsdLeft, 1, False);
3006 if (pos != right_pos)
3007 left_pos = SrcScan(ctx->text.source, pos, stype,
3008 XawsdLeft, 1, False);
3012 left_pos =SrcScan(ctx->text.source, left_pos, stype,
3013 XawsdRight, 1, False);
3015 if (dir == XawsdLeft)
3016 pos = Min(left_pos, right_pos);
3017 else /* dir == XawsdRight */
3018 pos = Max(left_pos, right_pos);
3021 pos = SrcScan(ctx->text.source, pos, XawstEOL,
3022 dir, 1, dir == XawsdRight);
3025 pos = ctx->text.insertPos;
3027 case XawselectPosition:
3032 if (dir == XawsdRight)
3033 ModifySelection(ctx, ctx->text.s.left, pos);
3035 ModifySelection(ctx, pos, ctx->text.s.right);
3037 ctx->text.insertPos = pos;
3042 * _XawTextClearAndCenterDisplay
3048 * Redraws the display with the cursor in insert point
3049 * centered vertically.
3052 _XawTextClearAndCenterDisplay(TextWidget ctx)
3054 int left_margin = ctx->text.left_margin;
3055 Bool visible = IsPositionVisible(ctx, ctx->text.insertPos);
3057 _XawTextShowPosition(ctx);
3059 if (XtIsRealized((Widget)ctx) && visible &&
3060 left_margin == ctx->text.left_margin) {
3061 int insert_line = LineForPosition(ctx, ctx->text.insertPos);
3062 int scroll_by = insert_line - (ctx->text.lt.lines >> 1);
3063 Boolean clear_to_eol = ctx->text.clear_to_eol;
3065 XawTextScroll(ctx, scroll_by, 0);
3066 SinkClearToBG(ctx->text.sink, 0, 0, XtWidth(ctx), XtHeight(ctx));
3068 clear_to_eol = ctx->text.clear_to_eol;
3069 ctx->text.clear_to_eol = False;
3071 ctx->text.clear_to_eol = clear_to_eol;
3076 * Internal redisplay entire window
3077 * Legal to call only if widget is realized
3080 DisplayTextWindow(Widget w)
3082 TextWidget ctx = (TextWidget)w;
3084 _XawTextBuildLineTable(ctx, ctx->text.lt.top, False);
3089 TextSinkResize(Widget w)
3091 if (w && XtClass(w)->core_class.resize)
3092 XtClass(w)->core_class.resize(w);
3097 _XawTextCheckResize(TextWidget ctx)
3103 * Converts (params, num_params) to a list of atoms & caches the
3104 * list in the TextWidget instance.
3107 _XawTextSelectionList(TextWidget ctx, String *list, Cardinal nelems)
3109 Atom *sel = ctx->text.s.selections;
3110 Display *dpy = XtDisplay((Widget)ctx);
3113 if (nelems > (Cardinal)ctx->text.s.array_size) {
3114 sel = (Atom *)XtRealloc((char *)sel, sizeof(Atom) * nelems);
3115 ctx->text.s.array_size = nelems;
3116 ctx->text.s.selections = sel;
3118 for (n = nelems; --n >= 0; sel++, list++)
3119 *sel = XInternAtom(dpy, *list, False);
3120 ctx->text.s.atom_count = nelems;
3122 return (ctx->text.s.selections);
3131 * defaultSel - default selection
3132 * l - left and right ends of the selection
3134 * list - the selection list (as strings).
3138 * Sets the current selection.
3141 * if (ctx->text.s.left >= ctx->text.s.right) then the selection is unset
3144 _XawTextSetSelection(TextWidget ctx, XawTextPosition l, XawTextPosition r,
3145 String *list, Cardinal nelems)
3147 if (nelems == 1 && !strcmp (list[0], "none"))
3150 String defaultSel = "PRIMARY";
3154 _SetSelection(ctx, l, r, _XawTextSelectionList(ctx, list, nelems), nelems);
3163 * left - left and right ends of the selection
3167 * Modifies the current selection.
3170 * if (ctx->text.s.left >= ctx->text.s.right) then the selection is unset
3173 ModifySelection(TextWidget ctx, XawTextPosition left, XawTextPosition right)
3176 ctx->text.insertPos = left;
3177 _SetSelection(ctx, left, right, NULL, 0);
3181 * This routine is used to perform various selection functions. The goal is
3182 * to be able to specify all the more popular forms of draw-through and
3183 * multi-click selection user interfaces from the outside.
3186 _XawTextAlterSelection(TextWidget ctx, XawTextSelectionMode mode,
3187 XawTextSelectionAction action, String *params,
3188 Cardinal *num_params)
3190 XawTextPosition position;
3194 * This flag is used by TextPop.c:DoReplace() to determine if the selection
3195 * is okay to use, or if it has been modified.
3197 if (ctx->text.search != NULL)
3198 ctx->text.search->selection_changed = True;
3200 position = PositionForXY(ctx, (int) ctx->text.ev_x, (int) ctx->text.ev_y);
3202 flag = (action != XawactionStart);
3203 if (mode == XawsmTextSelect)
3204 DoSelection(ctx, position, ctx->text.time, flag);
3205 else /* mode == XawsmTextExtend */
3206 ExtendSelection (ctx, position, flag);
3208 if (action == XawactionEnd)
3209 _XawTextSetSelection(ctx, ctx->text.s.left, ctx->text.s.right,
3210 params, *num_params);
3215 * UpdateTextInRectangle
3218 * ctx - the text widget
3222 * Updates the text in the given rectangle
3225 UpdateTextInRectangle(TextWidget ctx, XRectangle *rect)
3227 XawTextLineTable *lt;
3228 int line, y1, y2, x2;
3231 y2 = y1 + rect->height;
3232 x2 = rect->x + rect->width;
3234 for (line = 0, lt = &ctx->text.lt; line < lt->lines; line++)
3235 if (lt->info[line + 1].y > y1)
3237 for (; line <= lt->lines; line++) {
3238 if (lt->info[line].y > y2)
3240 UpdateTextInLine(ctx, line, rect->x, x2);
3245 * This routine processes all "expose region" XEvents. In general, its job
3246 * is to the best job at minimal re-paint of the text, displayed in the
3247 * window, that it can.
3251 XawTextExpose(Widget w, XEvent *event, Region region)
3253 TextWidget ctx = (TextWidget)w;
3254 Boolean clear_to_eol;
3257 if (event->type == Expose) {
3258 expose.x = event->xexpose.x;
3259 expose.y = event->xexpose.y;
3260 expose.width = event->xexpose.width;
3261 expose.height = event->xexpose.height;
3263 else if (event->type == GraphicsExpose) {
3264 expose.x = event->xgraphicsexpose.x;
3265 expose.y = event->xgraphicsexpose.y;
3266 expose.width = event->xgraphicsexpose.width;
3267 expose.height = event->xgraphicsexpose.height;
3272 _XawTextPrepareToUpdate(ctx);
3274 if (Superclass->core_class.expose)
3275 (*Superclass->core_class.expose)(w, event, region);
3277 clear_to_eol = ctx->text.clear_to_eol;
3278 ctx->text.clear_to_eol = False;
3280 UpdateTextInRectangle(ctx, &expose);
3281 XawTextSinkGetCursorBounds(ctx->text.sink, &expose);
3282 UpdateTextInRectangle(ctx, &expose);
3283 SinkClearToBG(ctx->text.sink, expose.x, expose.y,
3284 expose.width, expose.height);
3285 _XawTextExecuteUpdate(ctx);
3286 ctx->text.clear_to_eol = clear_to_eol;
3290 * This routine does all setup required to syncronize batched screen updates
3293 _XawTextPrepareToUpdate(TextWidget ctx)
3295 if (ctx->text.old_insert < 0) {
3296 InsertCursor((Widget)ctx, XawisOff);
3297 ctx->text.showposition = False;
3298 ctx->text.old_insert = ctx->text.insertPos;
3299 ctx->text.clear_to_eol = False;
3301 ctx->text.source_changed = SRC_CHANGE_NONE;
3307 * This is a private utility routine used by _XawTextExecuteUpdate. It
3308 * processes all the outstanding update requests and merges update
3309 * ranges where possible.
3312 FlushUpdate(TextWidget ctx)
3315 void (*display_text)(Widget, XawTextPosition, XawTextPosition);
3317 if (XtIsRealized((Widget)ctx)) {
3318 ctx->text.s.right = XawMin(ctx->text.s.right, ctx->text.lastPos);
3319 ctx->text.s.left = XawMin(ctx->text.s.left, ctx->text.s.right);
3322 if (XawTextSinkBeginPaint(ctx->text.sink) == False)
3324 display_text = OldDisplayText;
3327 display_text = DisplayText;
3329 for (seg = ctx->text.update->segment; seg; seg = seg->next)
3330 (*display_text)((Widget)ctx,
3331 (XawTextPosition)seg->x1,
3332 (XawTextPosition)seg->x2);
3334 if (display_text != OldDisplayText) {
3335 XawTextSinkDoPaint(ctx->text.sink);
3336 XawTextSinkEndPaint(ctx->text.sink);
3340 (void)XmuScanlineXor(ctx->text.update, ctx->text.update);
3344 CountLines(TextWidget ctx, XawTextPosition left, XawTextPosition right)
3346 if (ctx->text.wrap == XawtextWrapNever || left >= right)
3349 XawTextPosition tmp;
3350 int dim, lines = 0, wwidth = GetMaxTextWidth(ctx);
3352 while (left < right) {
3354 XawTextSinkFindPosition(ctx->text.sink, left,
3355 ctx->text.left_margin,
3356 wwidth, ctx->text.wrap == XawtextWrapWord,
3369 GetMaxTextWidth(TextWidget ctx)
3374 XawTextSinkGetCursorBounds(ctx->text.sink, &cursor);
3375 width = (int)XtWidth(ctx) - RHMargins(ctx) - cursor.width;
3377 return (XawMax(0, width));
3382 * _XawTextShowPosition
3385 * ctx - the text widget to show the position
3388 * Makes sure the text cursor visible, scrolling the text window
3392 _XawTextShowPosition(TextWidget ctx)
3395 * Variable scroll is used to avoid scanning large files to calculate
3398 int hpixels, vlines;
3399 XawTextPosition first, last, top, tmp;
3400 Bool visible, scroll;
3402 if (!XtIsRealized((Widget)ctx))
3406 * Checks if a horizontal scroll is required
3408 if (ctx->text.wrap == XawtextWrapNever) {
3409 int x, vwidth, distance, dim;
3412 vwidth = (int)XtWidth(ctx) - RHMargins(ctx);
3413 last = SrcScan(ctx->text.source, ctx->text.insertPos,
3414 XawstEOL, XawsdLeft, 1, False);
3415 XawTextSinkFindDistance(ctx->text.sink, last,
3416 ctx->text.left_margin,
3417 ctx->text.insertPos,
3418 &distance, &first, &dim);
3419 XawTextSinkGetCursorBounds(ctx->text.sink, &rect);
3420 x = ctx->text.left_margin - ctx->text.r_margin.left;
3422 if (x + distance + rect.width > vwidth)
3423 hpixels = x + distance + rect.width - vwidth + (vwidth >> 2);
3424 else if (x + distance < 0)
3425 hpixels = x + distance - (vwidth >> 2);
3432 visible = IsPositionVisible(ctx, ctx->text.insertPos);
3435 * If the cursor is already visible
3437 if (!hpixels && visible)
3440 scroll = ctx->core.background_pixmap == XtUnspecifiedPixmap && !hpixels;
3442 first = ctx->text.lt.top;
3445 * Needs to scroll the text window
3448 top = ctx->text.lt.top;
3450 top = SrcScan(ctx->text.source, ctx->text.insertPos,
3451 XawstEOL, XawsdLeft, 1, False);
3454 * Finds the nearest left position from ctx->text.insertPos
3456 if (ctx->text.wrap != XawtextWrapNever) {
3457 int dim, vwidth = GetMaxTextWidth(ctx);
3463 XawTextSinkFindPosition(ctx->text.sink, last,
3464 ctx->text.left_margin, vwidth,
3465 ctx->text.wrap == XawtextWrapWord,
3469 if (last <= ctx->text.insertPos)
3478 if (ctx->text.insertPos < first) { /* Scroll Down */
3479 while (first > top) {
3481 first = SrcScan(ctx->text.source, first,
3482 XawstEOL, XawsdLeft, 2, False);
3483 vlines -= CountLines(ctx, first, last);
3484 if (-vlines >= ctx->text.lt.lines) {
3490 else if (!visible) { /* Scroll Up */
3491 while (first < top) {
3493 first = SrcScan(ctx->text.source, first,
3494 XawstEOL, XawsdRight, 1, True);
3495 vlines += CountLines(ctx, last, first);
3496 if (vlines > ctx->text.lt.lines) {
3507 * If a portion of the text that will be scrolled is visible
3510 XawTextScroll(ctx, vlines ? vlines - (ctx->text.lt.lines >> 1) : 0, 0);
3512 * Else redraw the entire text window
3515 ctx->text.left_margin -= hpixels;
3516 if (ctx->text.left_margin > ctx->text.r_margin.left)
3517 ctx->text.left_margin = ctx->text.margin.left =
3518 ctx->text.r_margin.left;
3521 vlines = ctx->text.lt.lines >> 1;
3523 top = SrcScan(ctx->text.source, ctx->text.insertPos,
3524 XawstEOL, XawsdLeft, vlines + 1, False);
3526 if (ctx->text.wrap != XawtextWrapNever) {
3528 int n_lines = CountLines(ctx, top, ctx->text.insertPos);
3529 int vwidth = GetMaxTextWidth(ctx);
3531 while (n_lines-- > vlines) {
3533 XawTextSinkFindPosition(ctx->text.sink, top,
3534 ctx->text.left_margin,
3536 ctx->text.wrap == XawtextWrapWord,
3542 _XawTextBuildLineTable(ctx, top, True);
3547 ctx->text.clear_to_eol = True;
3552 ResolveLineNumber(TextWidget ctx)
3554 int line_number = ctx->text.lt.base_line;
3555 XawTextPosition position = ctx->text.lt.top;
3557 if (ctx->text.lt.base_line < 1)
3558 return (ctx->text.line_number);
3560 if (ctx->text.wrap == XawtextWrapNever
3561 && IsPositionVisible(ctx, ctx->text.insertPos))
3562 line_number += LineForPosition(ctx, ctx->text.insertPos);
3563 else if (position < ctx->text.insertPos) {
3564 while (position < ctx->text.insertPos) {
3565 position = SrcScan(ctx->text.source, position,
3566 XawstEOL, XawsdRight, 1, True);
3567 if (position <= ctx->text.insertPos) {
3569 if (position == ctx->text.lastPos) {
3570 line_number -= !_XawTextSourceNewLineAtEOF(ctx->text.source);
3576 else if (position > ctx->text.insertPos) {
3577 while (position > ctx->text.insertPos) {
3578 position = SrcScan(ctx->text.source, position,
3579 XawstEOL, XawsdLeft, 1, False);
3580 if (--position >= ctx->text.insertPos)
3585 return (line_number);
3590 * This routine causes all batched screen updates to be performed
3593 _XawTextExecuteUpdate(TextWidget ctx)
3595 if (ctx->text.update_disabled || ctx->text.old_insert < 0)
3598 if(ctx->text.old_insert != ctx->text.insertPos || ctx->text.showposition)
3599 _XawTextShowPosition(ctx);
3602 InsertCursor((Widget)ctx, XawisOn);
3603 ctx->text.old_insert = -1;
3605 _XawTextSetLineAndColumnNumber(ctx, False);
3610 XawTextDestroy(Widget w)
3612 TextWidget ctx = (TextWidget)w;
3614 DestroyHScrollBar(ctx);
3615 DestroyVScrollBar(ctx);
3617 XtFree((char *)ctx->text.s.selections);
3618 XtFree((char *)ctx->text.lt.info);
3619 XtFree((char *)ctx->text.search);
3620 XmuDestroyScanline(ctx->text.update);
3621 XtReleaseGC((Widget)ctx, ctx->text.gc);
3625 * by the time we are managed (and get this far) we had better
3626 * have both a source and a sink
3629 XawTextResize(Widget w)
3631 TextWidget ctx = (TextWidget)w;
3633 PositionVScrollBar(ctx);
3634 PositionHScrollBar(ctx);
3635 TextSinkResize(ctx->text.sink);
3637 ctx->text.showposition = True;
3638 _XawTextBuildLineTable(ctx, ctx->text.lt.top, True);
3642 * This routine allow the application program to Set attributes.
3646 XawTextSetValues(Widget current, Widget request, Widget cnew,
3647 ArgList args, Cardinal *num_args)
3649 TextWidget oldtw = (TextWidget)current;
3650 TextWidget newtw = (TextWidget)cnew;
3651 Boolean redisplay = False;
3652 Boolean display_caret = newtw->text.display_caret;
3654 Boolean show_lc = False;
3657 newtw->text.display_caret = oldtw->text.display_caret;
3658 _XawTextPrepareToUpdate(newtw);
3659 newtw->text.display_caret = display_caret;
3661 if (oldtw->text.r_margin.left != newtw->text.r_margin.left) {
3662 newtw->text.left_margin = newtw->text.margin.left =
3663 newtw->text.r_margin.left;
3664 if (newtw->text.vbar != NULL) {
3665 newtw->text.left_margin += XtWidth(newtw->text.vbar) +
3666 XtBorderWidth(newtw->text.vbar);
3671 if (oldtw->text.scroll_vert != newtw->text.scroll_vert) {
3672 if (newtw->text.scroll_vert == XawtextScrollAlways)
3673 CreateVScrollBar(newtw);
3675 DestroyVScrollBar(newtw);
3680 if (oldtw->text.r_margin.bottom != newtw->text.r_margin.bottom) {
3681 newtw->text.margin.bottom = newtw->text.r_margin.bottom;
3682 if (newtw->text.hbar != NULL)
3683 newtw->text.margin.bottom += newtw->text.hbar->core.height +
3684 newtw->text.hbar->core.border_width;
3688 if (oldtw->text.scroll_horiz != newtw->text.scroll_horiz) {
3689 if (newtw->text.scroll_horiz == XawtextScrollAlways)
3690 CreateHScrollBar(newtw);
3692 DestroyHScrollBar(newtw);
3697 if (oldtw->text.source != newtw->text.source) {
3700 _XawSourceRemoveText(oldtw->text.source, cnew,
3701 oldtw->text.source &&
3702 XtParent(oldtw->text.source) == cnew);
3703 _XawSourceAddText(newtw->text.source, cnew);
3705 _XawTextSetSource((Widget)newtw, newtw->text.source, newtw->text.lt.top,
3706 newtw->text.insertPos);
3709 newtw->text.redisplay_needed = False;
3710 XtSetValues((Widget)newtw->text.source, args, *num_args);
3711 XtSetValues((Widget)newtw->text.sink, args, *num_args);
3713 if (oldtw->text.wrap != newtw->text.wrap
3714 || oldtw->text.lt.top != newtw->text.lt.top
3715 || oldtw->text.insertPos != newtw->text.insertPos
3716 || oldtw->text.r_margin.right != newtw->text.r_margin.right
3717 || oldtw->text.r_margin.top != newtw->text.r_margin.top
3718 || oldtw->text.sink != newtw->text.sink
3719 || newtw->text.redisplay_needed) {
3720 if (oldtw->text.wrap != newtw->text.wrap) {
3721 newtw->text.left_margin = newtw->text.margin.left =
3722 newtw->text.r_margin.left;
3723 if (oldtw->text.lt.top == newtw->text.lt.top)
3724 newtw->text.lt.top = SrcScan(newtw->text.source, 0, XawstEOL,
3725 XawsdLeft, 1, False);
3727 newtw->text.showposition = True;
3730 newtw->text.source_changed = SRC_CHANGE_OVERLAP;
3732 _XawTextBuildLineTable(newtw, newtw->text.lt.top, True);
3737 if (newtw->text.left_column < 0)
3738 newtw->text.left_column = 0;
3739 if (newtw->text.right_column < 0)
3740 newtw->text.right_column = 0;
3743 _XawTextExecuteUpdate(newtw);
3747 _XawTextSetLineAndColumnNumber(newtw, True);
3751 _XawTextSetScrollBars(newtw);
3756 /* invoked by the Simple widget's SetValues */
3758 XawTextChangeSensitive(Widget w)
3761 TextWidget tw = (TextWidget)w;
3763 (*(&simpleClassRec)->simple_class.change_sensitive)(w);
3765 XtSetArg(args[0], XtNancestorSensitive,
3766 (tw->core.ancestor_sensitive && tw->core.sensitive));
3768 XtSetValues(tw->text.vbar, args, ONE);
3770 XtSetValues(tw->text.hbar, args, ONE);
3776 * XawTextGetValuesHook
3780 * args - argument list
3781 * num_args - number of args
3784 * This is a get values hook routine that gets the
3785 * values in the text source and sink.
3788 XawTextGetValuesHook(Widget w, ArgList args, Cardinal *num_args)
3790 XtGetValues(((TextWidget)w)->text.source, args, *num_args);
3791 XtGetValues(((TextWidget)w)->text.sink, args, *num_args);
3799 * pos - any position
3802 * Returns a valid position given any postition.
3805 * A position between (0 and lastPos)
3807 static XawTextPosition
3808 FindGoodPosition(TextWidget ctx, XawTextPosition pos)
3812 return (((pos > ctx->text.lastPos) ? ctx->text.lastPos : pos));
3815 /* Li wrote this so the IM can find a given text position's screen position */
3817 _XawTextPosToXY(Widget w, XawTextPosition pos, Position *x, Position *y)
3821 LineAndXYForPosition((TextWidget)w, pos, &line, &ix, &iy);
3826 /*******************************************************************
3827 The following routines provide procedural interfaces to Text window state
3828 setting and getting. They need to be redone so than the args code can use
3829 them. I suggest we create a complete set that takes the context as an
3830 argument and then have the public version lookup the context and call the
3831 internal one. The major value of this set is that they have actual application
3832 clients and therefore the functionality provided is required for any future
3834 ********************************************************************/
3836 XawTextDisplay(Widget w)
3838 TextWidget ctx = (TextWidget)w;
3840 if (!XtIsRealized(w))
3843 _XawTextPrepareToUpdate(ctx);
3844 ctx->text.clear_to_eol = True;
3845 DisplayTextWindow(w);
3846 _XawTextExecuteUpdate(ctx);
3850 XawTextSetSelectionArray(Widget w, XawTextSelectType *sarray)
3852 ((TextWidget)w)->text.sarray = sarray;
3856 XawTextGetSelectionPos(Widget w, XawTextPosition *left, XawTextPosition *right)
3858 *left = ((TextWidget)w)->text.s.left;
3859 *right = ((TextWidget)w)->text.s.right;
3863 _XawTextSetSource(Widget w, Widget source,
3864 XawTextPosition top, XawTextPosition startPos)
3866 TextWidget ctx = (TextWidget)w;
3868 Bool resolve = False;
3872 if (source != ctx->text.source)
3873 _XawSourceRemoveText(ctx->text.source, w, ctx->text.source &&
3874 XtParent(ctx->text.source) == w);
3875 _XawSourceAddText(source, w);
3877 if (source != ctx->text.source || ctx->text.insertPos != startPos)
3880 ctx->text.source_changed = SRC_CHANGE_OVERLAP;
3882 ctx->text.source = source;
3883 ctx->text.s.left = ctx->text.s.right = 0;
3884 ctx->text.lastPos = GETLASTPOS;
3885 top = FindGoodPosition(ctx, top);
3886 startPos = FindGoodPosition(ctx, startPos);
3887 ctx->text.insertPos = ctx->text.old_insert = startPos;
3888 _XawTextPrepareToUpdate(ctx);
3890 _XawTextBuildLineTable(ctx, top, True);
3892 _XawTextExecuteUpdate(ctx);
3895 _XawTextSetLineAndColumnNumber(ctx, True);
3900 XawTextSetSource(Widget w, Widget source, XawTextPosition top)
3902 _XawTextSetSource(w, source, top, top);
3906 * This public routine deletes the text from startPos to endPos in a source and
3907 * then inserts, at startPos, the text that was passed. As a side effect it
3908 * "invalidates" that portion of the displayed text (if any), so that things
3909 * will be repainted properly.
3912 XawTextReplace(Widget w, XawTextPosition startPos, XawTextPosition endPos,
3915 TextWidget ctx = (TextWidget)w;
3919 TextSrcObject src = (TextSrcObject)ctx->text.source;
3921 for (i = 0; i < src->textSrc.num_text; i++)
3922 _XawTextPrepareToUpdate((TextWidget)src->textSrc.text[i]);
3924 _XawTextPrepareToUpdate(ctx);
3927 endPos = FindGoodPosition(ctx, endPos);
3928 startPos = FindGoodPosition(ctx, startPos);
3929 result = _XawTextReplace(ctx, startPos, endPos, text);
3932 for (i = 0; i < src->textSrc.num_text; i++)
3933 _XawTextExecuteUpdate((TextWidget)src->textSrc.text[i]);
3935 _XawTextExecuteUpdate(ctx);
3942 XawTextTopPosition(Widget w)
3944 return (((TextWidget)w)->text.lt.top);
3948 XawTextLastPosition(Widget w)
3950 return (((TextWidget)w)->text.lastPos);
3954 XawTextSetInsertionPoint(Widget w, XawTextPosition position)
3956 TextWidget ctx = (TextWidget)w;
3958 _XawTextPrepareToUpdate(ctx);
3959 ctx->text.insertPos = FindGoodPosition(ctx, position);
3960 ctx->text.showposition = True;
3961 ctx->text.from_left = -1;
3963 _XawTextExecuteUpdate(ctx);
3965 _XawTextSetLineAndColumnNumber(ctx, False);
3970 XawTextGetInsertionPoint(Widget w)
3972 return (((TextWidget)w)->text.insertPos);
3976 * Note: Must walk the selection list in opposite order from TextLoseSelection
3979 XawTextUnsetSelection(Widget w)
3981 TextWidget ctx = (TextWidget)w;
3983 while (ctx->text.s.atom_count != 0) {
3984 Atom sel = ctx->text.s.selections[ctx->text.s.atom_count - 1];
3986 if (sel != (Atom) 0) {
3988 * As selections are lost the atom_count will decrement
3990 if (GetCutBufferNumber(sel) == NOT_A_CUT_BUFFER)
3991 XtDisownSelection(w, sel, ctx->text.time);
3992 TextLoseSelection(w, &sel); /* In case this is a cut buffer, or
3993 XtDisownSelection failed to call us */
3999 XawTextSetSelection(Widget w, XawTextPosition left, XawTextPosition right)
4001 TextWidget ctx = (TextWidget)w;
4003 _XawTextPrepareToUpdate(ctx);
4004 _XawTextSetSelection(ctx, FindGoodPosition(ctx, left),
4005 FindGoodPosition(ctx, right), NULL, 0);
4006 _XawTextExecuteUpdate(ctx);
4010 XawTextInvalidate(Widget w, XawTextPosition from, XawTextPosition to)
4012 TextWidget ctx = (TextWidget)w;
4014 from = FindGoodPosition(ctx, from);
4015 to = FindGoodPosition(ctx, to);
4016 ctx->text.lastPos = GETLASTPOS;
4017 _XawTextPrepareToUpdate(ctx);
4018 _XawTextNeedsUpdating(ctx, from, to);
4019 _XawTextExecuteUpdate(ctx);
4024 XawTextDisableRedisplay(Widget w)
4026 ((TextWidget)w)->text.update_disabled = True;
4027 _XawTextPrepareToUpdate((TextWidget)w);
4031 XawTextEnableRedisplay(Widget w)
4033 TextWidget ctx = (TextWidget)w;
4034 XawTextPosition lastPos;
4036 if (!ctx->text.update_disabled)
4039 ctx->text.update_disabled = False;
4040 lastPos = ctx->text.lastPos = GETLASTPOS;
4041 ctx->text.lt.top = FindGoodPosition(ctx, ctx->text.lt.top);
4042 ctx->text.insertPos = FindGoodPosition(ctx, ctx->text.insertPos);
4044 if (ctx->text.s.left > lastPos || ctx->text.s.right > lastPos)
4045 ctx->text.s.left = ctx->text.s.right = 0;
4047 _XawTextExecuteUpdate(ctx);
4051 XawTextGetSource(Widget w)
4053 return (((TextWidget)w)->text.source);
4057 XawTextGetSink(Widget w)
4059 return (((TextWidget)w)->text.sink);
4063 XawTextDisplayCaret(Widget w,
4064 #if NeedWidePrototypes
4067 Boolean display_caret
4071 TextWidget ctx = (TextWidget)w;
4073 if (XtIsRealized(w)) {
4074 _XawTextPrepareToUpdate(ctx);
4075 ctx->text.display_caret = display_caret;
4076 _XawTextExecuteUpdate(ctx);
4079 ctx->text.display_caret = display_caret;
4088 * dir - direction to search
4089 * text - text block containing info about the string to search for
4092 * Searches for the given text block.
4095 * The position of the text found, or XawTextSearchError on an error
4098 XawTextSearch(Widget w,
4099 #if NeedWidePrototypes
4102 XawTextScanDirection dir,
4106 TextWidget ctx = (TextWidget)w;
4108 return (SrcSearch(ctx->text.source, ctx->text.insertPos, dir, text));
4111 TextClassRec textClassRec = {
4114 (WidgetClass)&simpleClassRec, /* superclass */
4115 "Text", /* class_name */
4116 sizeof(TextRec), /* widget_size */
4117 XawTextClassInitialize, /* class_initialize */
4118 NULL, /* class_part_init */
4119 False, /* class_inited */
4120 XawTextInitialize, /* initialize */
4121 NULL, /* initialize_hook */
4122 XawTextRealize, /* realize */
4123 _XawTextActionsTable, /* actions */
4124 0, /* num_actions */
4125 resources, /* resources */
4126 XtNumber(resources), /* num_resource */
4127 NULLQUARK, /* xrm_class */
4128 True, /* compress_motion */
4129 XtExposeGraphicsExpose | /* compress_exposure */
4131 True, /* compress_enterleave */
4132 False, /* visible_interest */
4133 XawTextDestroy, /* destroy */
4134 XawTextResize, /* resize */
4135 XawTextExpose, /* expose */
4136 XawTextSetValues, /* set_values */
4137 NULL, /* set_values_hook */
4138 XtInheritSetValuesAlmost, /* set_values_almost */
4139 XawTextGetValuesHook, /* get_values_hook */
4140 NULL, /* accept_focus */
4141 XtVersion, /* version */
4142 NULL, /* callback_private */
4143 _XawDefaultTextTranslations, /* tm_table */
4144 XtInheritQueryGeometry, /* query_geometry */
4145 XtInheritDisplayAccelerator, /* display_accelerator */
4146 NULL, /* extension */
4150 XawTextChangeSensitive, /* change_sensitive */
4154 NULL, /* extension */
4158 WidgetClass textWidgetClass = (WidgetClass)&textClassRec;