3 Copyright 1989, 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.
32 #include <X11/Xos.h> /* for select() and struct timeval */
34 #include <X11/IntrinsicP.h>
35 #include <X11/StringDefs.h>
36 #include <X11/Xatom.h>
37 #include <X11/Xfuncs.h>
38 #include <X11/Xutil.h>
39 #include <X11/Xmu/Atoms.h>
40 #include <X11/Xmu/Misc.h>
41 #include <X11/Xmu/StdSel.h>
42 #include <X11/Xaw/MultiSinkP.h>
43 #include <X11/Xaw/MultiSrcP.h>
44 #include <X11/Xaw/TextP.h>
45 #include <X11/Xaw/TextSrcP.h>
46 #include <X11/Xaw/XawImP.h>
50 #define SrcScan XawTextSourceScan
51 #define FindDist XawTextSinkFindDistance
52 #define FindPos XawTextSinkFindPosition
53 #define MULT(w) (w->text.mult == 0 ? 4 : \
54 w->text.mult == 32767 ? -4 : w->text.mult)
56 #define KILL_RING_APPEND 2
57 #define KILL_RING_BEGIN 3
58 #define KILL_RING_YANK 100
59 #define KILL_RING_YANK_DONE 98
61 #define XawTextActionMaxHexChars 100
66 static void _DeleteOrKill(TextWidget, XawTextPosition, XawTextPosition, Bool);
67 static void _SelectionReceived(Widget, XtPointer, Atom*, Atom*, XtPointer,
68 unsigned long*, int*);
69 static void _LoseSelection(Widget, Atom*, char**, int*);
70 static void AutoFill(TextWidget);
71 static Boolean ConvertSelection(Widget, Atom*, Atom*, Atom*, XtPointer*,
72 unsigned long*, int*);
73 static void DeleteOrKill(TextWidget, XEvent*, XawTextScanDirection,
74 XawTextScanType, Bool, Bool);
75 static void EndAction(TextWidget);
77 static Bool BlankLine(Widget, XawTextPosition, int*);
78 static int DoFormatText(TextWidget, XawTextPosition, Bool, int,
79 XawTextBlock*, XawTextPosition*, int, Bool);
80 static int FormatText(TextWidget, XawTextPosition, Bool,
81 XawTextPosition*, int);
82 static Bool GetBlockBoundaries(TextWidget, XawTextPosition*, XawTextPosition*);
84 static int FormRegion(TextWidget, XawTextPosition, XawTextPosition,
85 XawTextPosition*, int);
86 static void GetSelection(Widget, Time, String*, Cardinal);
87 static char *IfHexConvertHexElseReturnParam(char*, int*);
88 static void InsertNewCRs(TextWidget, XawTextPosition, XawTextPosition,
89 XawTextPosition*, int);
90 static int InsertNewLineAndBackupInternal(TextWidget);
91 static int LocalInsertNewLine(TextWidget, XEvent*);
92 static void LoseSelection(Widget, Atom*);
93 static void ParameterError(Widget, String);
94 static Bool MatchSelection(Atom, XawTextSelection*);
95 static void ModifySelection(TextWidget, XEvent*, XawTextSelectionMode,
96 XawTextSelectionAction, String*, Cardinal*);
97 static void Move(TextWidget, XEvent*, XawTextScanDirection, XawTextScanType,
99 static void NotePosition(TextWidget, XEvent*);
100 static void StartAction(TextWidget, XEvent*);
101 static XawTextPosition StripOutOldCRs(TextWidget, XawTextPosition,
102 XawTextPosition, XawTextPosition*, int);
104 static Bool StripSpaces(TextWidget, XawTextPosition, XawTextPosition,
105 XawTextPosition*, int, XawTextBlock*);
106 static Bool Tabify(TextWidget, XawTextPosition, XawTextPosition,
107 XawTextPosition*, int, XawTextBlock*);
108 static Bool Untabify(TextWidget, XawTextPosition, XawTextPosition,
109 XawTextPosition*, int, XawTextBlock*);
115 static void CapitalizeWord(Widget, XEvent*, String*, Cardinal*);
116 static void DisplayCaret(Widget, XEvent*, String*, Cardinal*);
117 static void Delete(Widget, XEvent*, String*, Cardinal*);
118 static void DeleteBackwardChar(Widget, XEvent*, String*, Cardinal*);
119 static void DeleteBackwardWord(Widget, XEvent*, String*, Cardinal*);
120 static void DeleteCurrentSelection(Widget, XEvent*, String*, Cardinal*);
121 static void DeleteForwardChar(Widget, XEvent*, String*, Cardinal*);
122 static void DeleteForwardWord(Widget, XEvent*, String*, Cardinal*);
123 static void DowncaseWord(Widget, XEvent*, String*, Cardinal*);
124 static void ExtendAdjust(Widget, XEvent*, String*, Cardinal*);
125 static void ExtendEnd(Widget, XEvent*, String*, Cardinal*);
126 static void ExtendStart(Widget, XEvent*, String*, Cardinal*);
127 static void FormParagraph(Widget, XEvent*, String*, Cardinal*);
129 static void Indent(Widget, XEvent*, String*, Cardinal*);
131 static void InsertChar(Widget, XEvent*, String*, Cardinal*);
132 static void InsertNewLine(Widget, XEvent*, String*, Cardinal*);
133 static void InsertNewLineAndBackup(Widget, XEvent*, String*, Cardinal*);
134 static void InsertNewLineAndIndent(Widget, XEvent*, String*, Cardinal*);
135 static void InsertSelection(Widget, XEvent*, String*, Cardinal*);
136 static void InsertString(Widget, XEvent*, String*, Cardinal*);
138 static void KeyboardReset(Widget, XEvent*, String*, Cardinal*);
140 static void KillBackwardWord(Widget, XEvent*, String*, Cardinal*);
141 static void KillCurrentSelection(Widget, XEvent*, String*, Cardinal*);
142 static void KillForwardWord(Widget, XEvent*, String*, Cardinal*);
144 static void KillRingYank(Widget, XEvent*, String*, Cardinal*);
146 static void KillToEndOfLine(Widget, XEvent*, String*, Cardinal*);
147 static void KillToEndOfParagraph(Widget, XEvent*, String*, Cardinal*);
148 static void MoveBackwardChar(Widget, XEvent*, String*, Cardinal*);
149 static void MoveBackwardWord(Widget, XEvent*, String*, Cardinal*);
150 static void MoveBackwardParagraph(Widget, XEvent*, String*, Cardinal*);
151 static void MoveBeginningOfFile(Widget, XEvent*, String*, Cardinal*);
152 static void MoveEndOfFile(Widget, XEvent*, String*, Cardinal*);
153 static void MoveForwardChar(Widget, XEvent*, String*, Cardinal*);
154 static void MoveForwardWord(Widget, XEvent*, String*, Cardinal*);
155 static void MoveForwardParagraph(Widget, XEvent*, String*, Cardinal*);
156 static void MoveNextLine(Widget, XEvent*, String*, Cardinal*);
157 static void MoveNextPage(Widget, XEvent*, String*, Cardinal*);
158 static void MovePage(TextWidget, XEvent*, XawTextScanDirection);
159 static void MovePreviousLine(Widget, XEvent*, String*, Cardinal*);
160 static void MovePreviousPage(Widget, XEvent*, String*, Cardinal*);
161 static void MoveLine(TextWidget, XEvent*, XawTextScanDirection);
162 static void MoveToLineEnd(Widget, XEvent*, String*, Cardinal*);
163 static void MoveToLineStart(Widget, XEvent*, String*, Cardinal*);
164 static void Multiply(Widget, XEvent*, String*, Cardinal*);
165 static void NoOp(Widget, XEvent*, String*, Cardinal*);
167 static void Numeric(Widget, XEvent*, String*, Cardinal*);
169 static void Reconnect(Widget, XEvent*, String*, Cardinal*);
170 static void RedrawDisplay(Widget, XEvent*, String*, Cardinal*);
171 static void Scroll(TextWidget, XEvent*, XawTextScanDirection);
172 static void ScrollOneLineDown(Widget, XEvent*, String*, Cardinal*);
173 static void ScrollOneLineUp(Widget, XEvent*, String*, Cardinal*);
174 static void SelectAdjust(Widget, XEvent*, String*, Cardinal*);
175 static void SelectAll(Widget, XEvent*, String*, Cardinal*);
176 static void SelectEnd(Widget, XEvent*, String*, Cardinal*);
177 static void SelectSave(Widget, XEvent*, String*, Cardinal*);
178 static void SelectStart(Widget, XEvent*, String*, Cardinal*);
179 static void SelectWord(Widget, XEvent*, String*, Cardinal*);
180 static void SetKeyboardFocus(Widget, XEvent*, String*, Cardinal*);
181 static void TextEnterWindow(Widget, XEvent*, String*, Cardinal*);
182 static void TextFocusIn(Widget, XEvent*, String*, Cardinal*);
183 static void TextFocusOut(Widget, XEvent*, String*, Cardinal*);
184 static void TextLeaveWindow(Widget, XEvent*, String*, Cardinal*);
185 static void TransposeCharacters(Widget, XEvent*, String*, Cardinal*);
187 static void ToggleOverwrite(Widget, XEvent*, String*, Cardinal*);
188 static void Undo(Widget, XEvent*, String*, Cardinal*);
190 static void UpcaseWord(Widget, XEvent*, String*, Cardinal*);
191 static void DestroyFocusCallback(Widget, XtPointer, XtPointer);
196 void _XawTextZapSelection(TextWidget, XEvent*, Bool);
199 * Defined in TextPop.c
201 void _XawTextInsertFileAction(Widget, XEvent*, String*, Cardinal*);
202 void _XawTextInsertFile(Widget, XEvent*, String*, Cardinal*);
203 void _XawTextSearch(Widget, XEvent*, String*, Cardinal*);
204 void _XawTextDoSearchAction(Widget, XEvent*, String*, Cardinal*);
205 void _XawTextDoReplaceAction(Widget, XEvent*, String*, Cardinal*);
206 void _XawTextSetField(Widget, XEvent*, String*, Cardinal*);
207 void _XawTextPopdownSearchAction(Widget, XEvent*, String*, Cardinal*);
210 * These are defined in Text.c
212 void _XawTextAlterSelection(TextWidget, XawTextSelectionMode,
213 XawTextSelectionAction, String*, Cardinal*);
214 void _XawTextClearAndCenterDisplay(TextWidget);
215 void _XawTextExecuteUpdate(TextWidget);
216 char *_XawTextGetText(TextWidget, XawTextPosition, XawTextPosition);
217 void _XawTextPrepareToUpdate(TextWidget);
218 int _XawTextReplace(TextWidget, XawTextPosition, XawTextPosition,
220 Atom *_XawTextSelectionList(TextWidget, String*, Cardinal);
221 void _XawTextSetSelection(TextWidget, XawTextPosition, XawTextPosition,
223 void _XawTextVScroll(TextWidget, int);
224 void XawTextScroll(TextWidget, int, int);
225 void _XawTextSetLineAndColumnNumber(TextWidget, Bool);
229 * Defined in TextSrc.c
231 Bool _XawTextSrcUndo(TextSrcObject, XawTextPosition*);
232 Bool _XawTextSrcToggleUndo(TextSrcObject);
233 void _XawSourceSetUndoErase(TextSrcObject, int);
234 void _XawSourceSetUndoMerge(TextSrcObject, Bool);
241 #define MAX_KILL_RINGS 1024
242 XawTextKillRing *xaw_text_kill_ring;
243 static XawTextKillRing kill_ring_prev, kill_ring_null = { &kill_ring_prev, };
244 static unsigned num_kill_rings;
251 ParameterError(Widget w, String param)
254 Cardinal num_params = 2;
255 params[0] = XtName(w);
258 XtAppWarningMsg(XtWidgetToApplicationContext(w),
259 "parameterError", "textAction", "XawError",
260 "Widget: %s Parameter: %s",
261 params, &num_params);
262 XBell(XtDisplay(w), 50);
266 StartAction(TextWidget ctx, XEvent *event)
270 TextSrcObject src = (TextSrcObject)ctx->text.source;
272 for (i = 0; i < src->textSrc.num_text; i++)
273 _XawTextPrepareToUpdate((TextWidget)src->textSrc.text[i]);
274 _XawSourceSetUndoMerge(src, False);
276 _XawTextPrepareToUpdate(ctx);
280 switch (event->type) {
283 ctx->text.time = event->xbutton.time;
287 ctx->text.time = event->xkey.time;
290 ctx->text.time = event->xmotion.time;
294 ctx->text.time = event->xcrossing.time;
300 NotePosition(TextWidget ctx, XEvent *event)
302 switch (event->type) {
305 ctx->text.ev_x = event->xbutton.x;
306 ctx->text.ev_y = event->xbutton.y;
311 XawTextSinkGetCursorBounds(ctx->text.sink, &cursor);
312 ctx->text.ev_x = cursor.x + cursor.width / 2;
313 ctx->text.ev_y = cursor.y + cursor.height / 2;
316 ctx->text.ev_x = event->xmotion.x;
317 ctx->text.ev_y = event->xmotion.y;
321 ctx->text.ev_x = event->xcrossing.x;
322 ctx->text.ev_y = event->xcrossing.y;
327 EndAction(TextWidget ctx)
331 TextSrcObject src = (TextSrcObject)ctx->text.source;
333 for (i = 0; i < src->textSrc.num_text; i++)
334 _XawTextExecuteUpdate((TextWidget)src->textSrc.text[i]);
337 ctx->text.numeric = False;
338 if (ctx->text.kill_ring) {
339 if (--ctx->text.kill_ring == KILL_RING_YANK_DONE) {
340 if (ctx->text.kill_ring_ptr) {
341 --ctx->text.kill_ring_ptr->refcount;
342 ctx->text.kill_ring_ptr = NULL;
348 _XawTextExecuteUpdate(ctx);
352 struct _SelectionList {
356 int asked; /* which selection currently has been asked for:
357 0 = UTF8_STRING, 1 = COMPOUND_TEXT, 2 = STRING */
358 Atom selection; /* selection atom (normally XA_PRIMARY) */
363 _SelectionReceived(Widget w, XtPointer client_data, Atom *selection,
364 Atom *type, XtPointer value, unsigned long *length,
367 Display *d = XtDisplay(w);
368 TextWidget ctx = (TextWidget)w;
371 if (*type == 0 /*XT_CONVERT_FAIL*/ || *length == 0) {
372 struct _SelectionList* list = (struct _SelectionList*)client_data;
375 if (list->asked == 0) {
376 /* If we just asked for XA_UTF8_STRING and got no response,
377 we'll ask again, this time for XA_COMPOUND_TEXT. */
379 XtGetSelectionValue(w, list->selection, XA_COMPOUND_TEXT(d),
381 (XtPointer)list, list->time);
382 } else if (list->asked == 1) {
383 /* If we just asked for XA_COMPOUND_TEXT and got no response,
384 we'll ask again, this time for XA_STRING. */
386 XtGetSelectionValue(w, list->selection, XA_STRING,
388 (XtPointer)list, list->time);
390 /* We tried all possible text targets in this param.
391 Recurse on the tail of the params list. */
392 GetSelection(w, list->time, list->params, list->count);
399 StartAction(ctx, NULL);
400 if (XawTextFormat(ctx, XawFmtWide)) {
401 XTextProperty textprop;
405 textprop.encoding = *type;
406 textprop.value = (unsigned char *)value;
407 textprop.nitems = strlen(value);
410 if (XwcTextPropertyToTextList(d, &textprop, &wlist, &count)
413 XwcFreeStringList(wlist);
415 /* Notify the user on strerr and in the insertion :) */
416 fprintf(stderr, "Xaw Text Widget: An attempt was made to insert "
417 "an illegal selection.\n");
419 textprop.value = (unsigned char *)" >> ILLEGAL SELECTION << ";
420 textprop.nitems = strlen((char *) textprop.value);
421 if (XwcTextPropertyToTextList(d, &textprop, &wlist, &count)
428 value = (XPointer)wlist[0];
430 *length = wcslen(wlist[0]);
431 XtFree((XtPointer)wlist);
432 text.format = XawFmtWide;
434 text.ptr = (char*)value;
436 text.length = *length;
437 if (_XawTextReplace(ctx, ctx->text.insertPos, ctx->text.insertPos, &text)) {
438 XBell(XtDisplay(ctx), 0);
443 ctx->text.from_left = -1;
444 ctx->text.insertPos = SrcScan(ctx->text.source, ctx->text.old_insert,
445 XawstPositions, XawsdRight, text.length, True);
449 XFree(value); /* the selection value should be freed with XFree */
453 GetSelection(Widget w, Time timev, String *params, Cardinal num_params)
455 Display *d = XtDisplay(w);
456 TextWidget ctx = (TextWidget)w;
460 selection = XInternAtom(XtDisplay(w), *params, False);
462 case XA_CUT_BUFFER0: buffer = 0; break;
463 case XA_CUT_BUFFER1: buffer = 1; break;
464 case XA_CUT_BUFFER2: buffer = 2; break;
465 case XA_CUT_BUFFER3: buffer = 3; break;
466 case XA_CUT_BUFFER4: buffer = 4; break;
467 case XA_CUT_BUFFER5: buffer = 5; break;
468 case XA_CUT_BUFFER6: buffer = 6; break;
469 case XA_CUT_BUFFER7: buffer = 7; break;
470 default: buffer = -1;
474 unsigned long length;
476 Atom type = XA_STRING;
477 char *line = XFetchBuffer(XtDisplay(w), &nbytes, buffer);
479 if ((length = nbytes) != 0L)
480 _SelectionReceived(w, NULL, &selection, &type, line, &length, &fmt8);
481 else if (num_params > 1)
482 GetSelection(w, timev, params+1, num_params-1);
485 struct _SelectionList* list;
488 list = XtNew(struct _SelectionList);
489 list->params = params + 1;
490 list->count = num_params;
493 list->selection = selection;
497 XtGetSelectionValue(w, selection, XawTextFormat(ctx, XawFmtWide) ?
498 XA_UTF8_STRING(d) : XA_TEXT(d),
499 _SelectionReceived, (XtPointer)list, timev);
504 InsertSelection(Widget w, XEvent *event, String *params, Cardinal *num_params)
506 StartAction((TextWidget)w, event); /* Get Time. */
507 GetSelection(w, ((TextWidget)w)->text.time, params, *num_params);
508 EndAction((TextWidget)w);
512 * Routines for Moving Around
515 Move(TextWidget ctx, XEvent *event, XawTextScanDirection dir,
516 XawTextScanType type, Bool include)
518 XawTextPosition insertPos;
519 short mult = MULT(ctx);
523 dir = dir == XawsdLeft ? XawsdRight : XawsdLeft;
526 insertPos = SrcScan(ctx->text.source, ctx->text.insertPos,
527 type, dir, mult, include);
529 StartAction(ctx, event);
531 if (ctx->text.s.left != ctx->text.s.right)
532 XawTextUnsetSelection((Widget)ctx);
535 ctx->text.numeric = False;
538 ctx->text.showposition = True;
539 ctx->text.from_left = -1;
540 ctx->text.insertPos = insertPos;
546 MoveForwardChar(Widget w, XEvent *event, String *p, Cardinal *n)
548 Move((TextWidget)w, event, XawsdRight, XawstPositions, True);
553 MoveBackwardChar(Widget w, XEvent *event, String *p, Cardinal *n)
555 Move((TextWidget)w, event, XawsdLeft, XawstPositions, True);
559 MoveForwardWord(Widget w, XEvent *event, String *p, Cardinal *n)
561 if (*n && (p[0][0] == 'A' || p[0][0] == 'a'))
562 Move((TextWidget)w, event, XawsdRight, XawstAlphaNumeric, False);
564 Move((TextWidget)w, event, XawsdRight, XawstWhiteSpace, False);
568 MoveBackwardWord(Widget w, XEvent *event, String *p, Cardinal *n)
570 if (*n && (p[0][0] == 'A' || p[0][0] == 'a'))
571 Move((TextWidget)w, event, XawsdLeft, XawstAlphaNumeric, False);
573 Move((TextWidget)w, event, XawsdLeft, XawstWhiteSpace, False);
577 MoveForwardParagraph(Widget w, XEvent *event, String *p, Cardinal *n)
579 TextWidget ctx = (TextWidget)w;
580 XawTextPosition position = ctx->text.insertPos;
581 short mult = MULT(ctx);
584 ctx->text.mult = -mult;
585 MoveBackwardParagraph(w, event, p, n);
590 position = SrcScan(ctx->text.source, position,
591 XawstEOL, XawsdRight, 1, False) - 1;
593 while (position == SrcScan(ctx->text.source, position,
594 XawstEOL, XawsdRight, 1, False))
595 if (++position > ctx->text.lastPos) {
600 position = SrcScan(ctx->text.source, position,
601 XawstParagraph, XawsdRight, 1, True);
602 if (position != ctx->text.lastPos)
603 position = SrcScan(ctx->text.source, position - 1,
604 XawstEOL, XawsdLeft, 1, False);
609 if (position != ctx->text.insertPos) {
610 XawTextUnsetSelection(w);
611 StartAction(ctx, event);
612 ctx->text.showposition = True;
613 ctx->text.from_left = -1;
614 ctx->text.insertPos = position;
623 MoveBackwardParagraph(Widget w, XEvent *event, String *p, Cardinal *n)
625 TextWidget ctx = (TextWidget)w;
626 XawTextPosition position = ctx->text.insertPos;
627 short mult = MULT(ctx);
630 ctx->text.mult = -mult;
631 MoveForwardParagraph(w, event, p, n);
636 position = SrcScan(ctx->text.source, position,
637 XawstEOL, XawsdLeft, 1, False) + 1;
639 while (position == SrcScan(ctx->text.source, position,
640 XawstEOL, XawsdLeft, 1, False))
641 if (--position < 0) {
646 position = SrcScan(ctx->text.source, position,
647 XawstParagraph, XawsdLeft, 1, True);
648 if (position > 0 && position < ctx->text.lastPos)
654 if (position != ctx->text.insertPos) {
655 XawTextUnsetSelection(w);
656 StartAction(ctx, event);
657 ctx->text.showposition = True;
658 ctx->text.from_left = -1;
659 ctx->text.insertPos = position;
668 MoveToLineEnd(Widget w, XEvent *event, String *p, Cardinal *n)
670 Move((TextWidget)w, event, XawsdRight, XawstEOL, False);
675 MoveToLineStart(Widget w, XEvent *event, String *p, Cardinal *n)
677 Move((TextWidget)w, event, XawsdLeft, XawstEOL, False);
681 MoveLine(TextWidget ctx, XEvent *event, XawTextScanDirection dir)
683 XawTextPosition cnew, next_line, ltemp;
684 int itemp, from_left;
685 short mult = MULT(ctx);
687 StartAction(ctx, event);
689 XawTextUnsetSelection((Widget)ctx);
691 if (dir == XawsdLeft)
692 mult = mult == 0 ? 5 : mult + 1;
694 cnew = SrcScan(ctx->text.source, ctx->text.insertPos,
695 XawstEOL, XawsdLeft, 1, False);
697 if (ctx->text.from_left < 0)
698 FindDist(ctx->text.sink, cnew, ctx->text.left_margin, ctx->text.insertPos,
699 &ctx->text.from_left, <emp, &itemp);
701 cnew = SrcScan(ctx->text.source, ctx->text.insertPos, XawstEOL, dir,
702 mult, (dir == XawsdRight));
704 next_line = SrcScan(ctx->text.source, cnew, XawstEOL, XawsdRight, 1, False);
706 FindPos(ctx->text.sink, cnew, ctx->text.left_margin, ctx->text.from_left,
707 False, &ctx->text.insertPos, &from_left, &itemp);
709 if (from_left < ctx->text.from_left) {
712 XawTextSourceRead(ctx->text.source, ctx->text.insertPos, &block, 1);
714 if (XawTextFormat(ctx, XawFmtWide)) {
715 if (*(wchar_t *)block.ptr == _Xaw_atowc(XawTAB))
716 ++ctx->text.insertPos;
718 else if (block.ptr[0] == XawTAB)
719 ++ctx->text.insertPos;
723 if (ctx->text.insertPos > next_line)
724 ctx->text.insertPos = next_line;
730 MoveNextLine(Widget w, XEvent *event, String *p, Cardinal *n)
732 TextWidget ctx = (TextWidget)w;
733 short mult = MULT(ctx);
736 ctx->text.mult = -mult;
737 MovePreviousLine(w, event, p, n);
741 if (ctx->text.insertPos < ctx->text.lastPos)
742 MoveLine(ctx, event, XawsdRight);
748 MovePreviousLine(Widget w, XEvent *event, String *p, Cardinal *n)
750 TextWidget ctx = (TextWidget)w;
751 short mult = MULT(ctx);
754 ctx->text.mult = -mult;
755 MoveNextLine(w, event, p, n);
759 if (ctx->text.lt.top != 0 || (ctx->text.lt.lines > 1 &&
760 ctx->text.insertPos >= ctx->text.lt.info[1].position))
761 MoveLine(ctx, event, XawsdLeft);
768 MoveBeginningOfFile(Widget w, XEvent *event, String *p, Cardinal *n)
770 Move((TextWidget)w, event, XawsdLeft, XawstAll, True);
775 MoveEndOfFile(Widget w, XEvent *event, String *p, Cardinal *n)
777 Move((TextWidget)w, event, XawsdRight, XawstAll, True);
781 Scroll(TextWidget ctx, XEvent *event, XawTextScanDirection dir)
783 short mult = MULT(ctx);
787 dir = dir == XawsdLeft ? XawsdRight : XawsdLeft;
790 if (ctx->text.lt.lines > 1
791 && (dir == XawsdRight
792 || ctx->text.lastPos >= ctx->text.lt.info[1].position)) {
793 StartAction(ctx, event);
795 if (dir == XawsdLeft)
796 _XawTextVScroll(ctx, mult);
798 _XawTextVScroll(ctx, -mult);
805 ctx->text.numeric = False;
812 ScrollOneLineUp(Widget w, XEvent *event, String *p, Cardinal *n)
814 Scroll((TextWidget)w, event, XawsdLeft);
819 ScrollOneLineDown(Widget w, XEvent *event, String *p, Cardinal *n)
821 Scroll((TextWidget)w, event, XawsdRight);
825 MovePage(TextWidget ctx, XEvent *event, XawTextScanDirection dir)
828 XawTextPosition old_pos;
830 ctx->text.from_left = -1;
833 if (ctx->text.lt.top != 0)
834 scroll_val = -Max(1, ctx->text.lt.lines - 1);
837 if (!IsPositionVisible(ctx, Max(0, ctx->text.lastPos)))
838 scroll_val = Max(1, ctx->text.lt.lines - 1);
843 XawTextScroll(ctx, scroll_val,
844 ctx->text.left_margin - ctx->text.r_margin.left);
846 old_pos = ctx->text.insertPos;
849 if (IsPositionVisible(ctx, Max(0, ctx->text.lastPos)))
850 ctx->text.insertPos = Max(0, ctx->text.lastPos);
852 ctx->text.insertPos = ctx->text.lt.top;
853 if (ctx->text.insertPos < old_pos)
854 ctx->text.insertPos = SrcScan(ctx->text.source, old_pos,
855 XawstEOL, XawsdLeft, 1, False);
858 if (IsPositionVisible(ctx, 0))
859 ctx->text.insertPos = 0;
860 else if (ctx->text.lt.lines)
861 ctx->text.insertPos =
862 ctx->text.lt.info[ctx->text.lt.lines - 1].position;
864 ctx->text.insertPos = ctx->text.lt.top;
865 if (ctx->text.insertPos > old_pos)
866 ctx->text.insertPos = SrcScan(ctx->text.source, old_pos,
867 XawstEOL, XawsdLeft, 1, False);
873 MoveNextPage(Widget w, XEvent *event, String *p, Cardinal *n)
875 TextWidget ctx = (TextWidget)w;
876 short mult = MULT(ctx);
879 ctx->text.mult = -mult;
880 MovePreviousPage(w, event, p, n);
884 if (ctx->text.insertPos < ctx->text.lastPos) {
885 XawTextUnsetSelection(w);
886 StartAction(ctx, event);
887 ctx->text.clear_to_eol = True;
888 while (mult-- && ctx->text.insertPos < ctx->text.lastPos)
889 MovePage(ctx, event, XawsdRight);
898 MovePreviousPage(Widget w, XEvent *event, String *p, Cardinal *n)
900 TextWidget ctx = (TextWidget)w;
901 short mult = MULT(ctx);
904 ctx->text.mult = -mult;
905 MoveNextPage(w, event, p, n);
909 if (ctx->text.insertPos > 0) {
910 XawTextUnsetSelection(w);
911 StartAction(ctx, event);
912 ctx->text.clear_to_eol = True;
913 while (mult-- && ctx->text.insertPos > 0)
914 MovePage(ctx, event, XawsdLeft);
925 MatchSelection(Atom selection, XawTextSelection *s)
930 for (count = 0, match = s->selections; count < s->atom_count;
932 if (*match == selection)
938 #define SrcCvtSel XawTextSourceConvertSelection
941 ConvertSelection(Widget w, Atom *selection, Atom *target, Atom *type,
942 XtPointer *value, unsigned long *length, int *format)
944 Display *d = XtDisplay(w);
945 TextWidget ctx = (TextWidget)w;
946 Widget src = ctx->text.source;
947 XawTextEditType edit_mode;
949 XawTextSelectionSalt *salt = NULL;
952 if (*target == XA_TARGETS(d)) {
953 Atom *targetP, *std_targets;
954 unsigned long std_length;
956 if (SrcCvtSel(src, selection, target, type, value, length, format))
959 XtSetArg(args[0], XtNeditType,&edit_mode);
960 XtGetValues(src, args, 1);
962 XmuConvertStandardSelection(w, ctx->text.time, selection,
963 target, type, (XPointer *)&std_targets,
964 &std_length, format);
966 *length = 7 + (edit_mode == XawtextEdit) + std_length;
967 *value = XtMalloc((unsigned)sizeof(Atom)*(*length));
968 targetP = *(Atom**)value;
969 *targetP++ = XA_STRING;
970 *targetP++ = XA_TEXT(d);
971 *targetP++ = XA_UTF8_STRING(d);
972 *targetP++ = XA_COMPOUND_TEXT(d);
973 *targetP++ = XA_LENGTH(d);
974 *targetP++ = XA_LIST_LENGTH(d);
975 *targetP++ = XA_CHARACTER_POSITION(d);
976 if (edit_mode == XawtextEdit) {
977 *targetP++ = XA_DELETE(d);
979 memcpy((char*)targetP, (char*)std_targets, sizeof(Atom)*std_length);
980 XtFree((char*)std_targets);
986 if (SrcCvtSel(src, selection, target, type, value, length, format))
989 for (salt = ctx->text.salt2; salt; salt = salt->next)
990 if (MatchSelection (*selection, &salt->s))
995 if (*target == XA_STRING
996 || *target == XA_TEXT(d)
997 || *target == XA_UTF8_STRING(d)
998 || *target == XA_COMPOUND_TEXT(d)) {
999 if (*target == XA_TEXT(d)) {
1000 if (XawTextFormat(ctx, XawFmtWide))
1001 *type = XA_COMPOUND_TEXT(d);
1009 * If salt is True, the salt->contents stores CT string,
1010 * its length is measured in bytes.
1011 * Refer to _XawTextSaltAwaySelection()
1013 * by Li Yuhong, Mar. 20, 1991.
1016 *value = (char *)_XawTextGetSTRING(ctx, s->left, s->right);
1017 if (XawTextFormat(ctx, XawFmtWide)) {
1018 XTextProperty textprop;
1019 if (XwcTextListToTextProperty(d, (wchar_t**)value, 1,
1020 XCompoundTextStyle, &textprop)
1026 *value = (XtPointer)textprop.value;
1027 *length = textprop.nitems;
1030 *length = strlen(*value);
1033 *value = XtMalloc((salt->length + 1) * sizeof(unsigned char));
1034 strcpy (*value, salt->contents);
1035 *length = salt->length;
1037 /* Got *value,*length, now in COMPOUND_TEXT format. */
1038 if (XawTextFormat(ctx, XawFmtWide)) {
1039 if (*type == XA_STRING) {
1040 XTextProperty textprop;
1044 textprop.encoding = XA_COMPOUND_TEXT(d);
1045 textprop.value = (unsigned char *)*value;
1046 textprop.nitems = strlen(*value);
1047 textprop.format = 8;
1048 if (XwcTextPropertyToTextList(d, &textprop, &wlist, &count)
1055 if (XwcTextListToTextProperty(d, wlist, 1, XStringStyle, &textprop)
1057 XwcFreeStringList((wchar_t**)wlist);
1060 *value = (XtPointer)textprop.value;
1061 *length = textprop.nitems;
1062 XwcFreeStringList((wchar_t**) wlist);
1064 else if (*type == XA_UTF8_STRING(d)) {
1065 XTextProperty textprop;
1069 textprop.encoding = XA_COMPOUND_TEXT(d);
1070 textprop.value = (unsigned char *)*value;
1071 textprop.nitems = strlen(*value);
1072 textprop.format = 8;
1073 if (Xutf8TextPropertyToTextList(d, &textprop, &list, &count)
1081 *length = strlen(*list);
1089 if (*target == XA_LIST_LENGTH(d) || *target == XA_LENGTH(d)) {
1092 temp = (long *)XtMalloc(sizeof(long));
1093 if (*target == XA_LIST_LENGTH(d))
1095 else /* *target == XA_LENGTH(d) */
1096 *temp = (long)(s->right - s->left);
1098 *value = (XPointer)temp;
1105 if (*target == XA_CHARACTER_POSITION(d)) {
1108 temp = (long *) XtMalloc(2 * sizeof(long));
1109 temp[0] = (long)(s->left + 1);
1111 *value = (XPointer)temp;
1118 if (*target == XA_DELETE(d)) {
1120 _XawTextZapSelection(ctx, NULL, True);
1128 if (XmuConvertStandardSelection(w, ctx->text.time, selection, target, type,
1129 (XPointer *)value, length, format))
1136 LoseSelection(Widget w, Atom *selection)
1138 _LoseSelection(w, selection, NULL, NULL);
1142 _LoseSelection(Widget w, Atom *selection, char **contents, int *length)
1144 TextWidget ctx = (TextWidget)w;
1147 XawTextSelectionSalt *salt, *prevSalt, *nextSalt;
1150 for (salt = ctx->text.salt2; salt; salt = nextSalt) {
1151 atomP = salt->s.selections;
1152 nextSalt = salt->next;
1153 for (i = 0 ; i < salt->s.atom_count; i++, atomP++)
1154 if (*selection == *atomP)
1157 while (salt->s.atom_count
1158 && salt->s.selections[salt->s.atom_count-1] == 0)
1159 salt->s.atom_count--;
1162 * Must walk the selection list in opposite order from UnsetSelection.
1164 atomP = salt->s.selections;
1165 for (i = 0 ; i < salt->s.atom_count; i++, atomP++)
1166 if (*atomP == (Atom)0) {
1167 *atomP = salt->s.selections[--salt->s.atom_count];
1169 while (salt->s.atom_count
1170 && salt->s.selections[salt->s.atom_count-1] == 0)
1171 salt->s.atom_count--;
1173 if (salt->s.atom_count == 0) {
1175 if (contents == NULL) {
1176 XawTextKillRing *kill_ring = XtNew(XawTextKillRing);
1178 kill_ring->next = xaw_text_kill_ring;
1179 kill_ring->contents = salt->contents;
1180 kill_ring->length = salt->length;
1181 kill_ring->format = XawFmt8Bit;
1182 xaw_text_kill_ring = kill_ring;
1183 kill_ring_prev.next = xaw_text_kill_ring;
1185 if (++num_kill_rings > MAX_KILL_RINGS) {
1186 XawTextKillRing *tail = NULL;
1188 while (kill_ring->next) {
1190 kill_ring = kill_ring->next;
1192 if (kill_ring->refcount == 0) {
1195 XtFree(kill_ring->contents);
1196 XtFree((char*)kill_ring);
1201 *contents = salt->contents;
1202 *length = salt->length;
1206 prevSalt->next = nextSalt;
1208 ctx->text.salt2 = nextSalt;
1210 XtFree((char *)salt->s.selections);
1211 XtFree((char *)salt);
1219 _DeleteOrKill(TextWidget ctx, XawTextPosition from, XawTextPosition to,
1225 if (ctx->text.kill_ring_ptr) {
1226 --ctx->text.kill_ring_ptr->refcount;
1227 ctx->text.kill_ring_ptr = NULL;
1230 if (kill && from < to) {
1232 Bool append = False;
1234 XawTextPosition old_from = from;
1237 int size = 0, length;
1238 XawTextSelectionSalt *salt;
1239 Atom selection = XInternAtom(XtDisplay(ctx), "SECONDARY", False);
1242 if (ctx->text.kill_ring == KILL_RING_APPEND) {
1243 old_from = ctx->text.salt2->s.left;
1247 ctx->text.kill_ring = KILL_RING_BEGIN;
1250 _LoseSelection((Widget)ctx, &selection, &ring, &size);
1253 LoseSelection((Widget)ctx, &selection);
1255 salt = (XawTextSelectionSalt*)XtMalloc(sizeof(XawTextSelectionSalt));
1256 salt->s.selections = (Atom *)XtMalloc(sizeof(Atom));
1257 salt->s.left = from;
1260 string = (char *)_XawTextGetSTRING(ctx, from, to);
1262 if (XawTextFormat(ctx, XawFmtWide)) {
1263 XTextProperty textprop;
1265 if (XwcTextListToTextProperty(XtDisplay((Widget)ctx),
1266 (wchar_t**)(&string),
1267 1, XCompoundTextStyle,
1268 &textprop) < Success) {
1270 XtFree((char*)salt->s.selections);
1271 XtFree((char*)salt);
1275 string = (char *)textprop.value;
1276 length = textprop.nitems;
1279 length = strlen(string);
1281 salt->length = length + size;
1285 salt->contents = string;
1287 salt->contents = XtMalloc(length + size + 1);
1288 if (from >= old_from) {
1289 strncpy(salt->contents, ring, size);
1290 salt->contents[size] = '\0';
1291 strncat(salt->contents, string, length);
1294 strncpy(salt->contents, string, length);
1295 salt->contents[length] = '\0';
1296 strncat(salt->contents, ring, size);
1298 salt->contents[length + size] = '\0';
1303 kill_ring_prev.contents = salt->contents;
1304 kill_ring_prev.length = salt->length;
1305 kill_ring_prev.format = XawFmt8Bit;
1307 salt->contents = string;
1310 salt->next = ctx->text.salt2;
1311 ctx->text.salt2 = salt;
1315 ctx->text.kill_ring = KILL_RING_BEGIN;
1318 salt->s.selections[0] = selection;
1320 XtOwnSelection((Widget)ctx, selection, ctx->text.time,
1321 ConvertSelection, LoseSelection, NULL);
1322 salt->s.atom_count = 1;
1327 text.format = _XawTextFormat(ctx);
1330 if (_XawTextReplace(ctx, from, to, &text)) {
1331 XBell(XtDisplay(ctx), 50);
1334 ctx->text.from_left = -1;
1335 ctx->text.insertPos = from;
1336 ctx->text.showposition = TRUE;
1340 DeleteOrKill(TextWidget ctx, XEvent *event, XawTextScanDirection dir,
1341 XawTextScanType type, Bool include, Bool kill)
1343 XawTextPosition from, to;
1344 short mult = MULT(ctx);
1348 dir = dir == XawsdLeft ? XawsdRight : XawsdLeft;
1351 StartAction(ctx, event);
1354 _XawSourceSetUndoMerge((TextSrcObject)ctx->text.source, True);
1356 to = SrcScan(ctx->text.source, ctx->text.insertPos,
1357 type, dir, mult, include);
1360 * If no movement actually happened, then bump the count and try again.
1361 * This causes the character position at the very beginning and end of
1362 * a boundary to act correctly
1364 if (to == ctx->text.insertPos)
1365 to = SrcScan(ctx->text.source, ctx->text.insertPos,
1366 type, dir, mult + 1, include);
1368 if (dir == XawsdLeft) {
1370 to = ctx->text.insertPos;
1373 from = ctx->text.insertPos;
1375 _DeleteOrKill(ctx, from, to, kill);
1380 Delete(Widget w, XEvent *event, String *p, Cardinal *n)
1382 TextWidget ctx = (TextWidget)w;
1384 if (ctx->text.s.left != ctx->text.s.right)
1385 DeleteCurrentSelection(w, event, p, n);
1387 DeleteBackwardChar(w, event, p, n);
1391 DeleteChar(Widget w, XEvent *event, XawTextScanDirection dir)
1393 TextWidget ctx = (TextWidget)w;
1394 short mul = MULT(ctx);
1397 ctx->text.mult = mul = -mul;
1398 dir = dir == XawsdLeft ? XawsdRight : XawsdLeft;
1400 DeleteOrKill(ctx, event, dir, XawstPositions, True, False);
1403 _XawSourceSetUndoErase((TextSrcObject)ctx->text.source,
1404 dir == XawsdLeft ? -1 : 1);
1410 DeleteForwardChar(Widget w, XEvent *event, String *p, Cardinal *n)
1412 DeleteChar(w, event, XawsdRight);
1417 DeleteBackwardChar(Widget w, XEvent *event, String *p, Cardinal *n)
1419 DeleteChar(w, event, XawsdLeft);
1423 DeleteForwardWord(Widget w, XEvent *event, String *params, Cardinal *num_params)
1425 XawTextScanType type;
1427 if (*num_params && (*params[0] == 'A' || *params[0] == 'a'))
1428 type = XawstAlphaNumeric;
1430 type = XawstWhiteSpace;
1432 DeleteOrKill((TextWidget)w, event, XawsdRight, type, False, False);
1436 DeleteBackwardWord(Widget w, XEvent *event, String *params, Cardinal *num_params)
1438 XawTextScanType type;
1440 if (*num_params && (*params[0] == 'A' || *params[0] == 'a'))
1441 type = XawstAlphaNumeric;
1443 type = XawstWhiteSpace;
1445 DeleteOrKill((TextWidget)w, event, XawsdLeft, type, False, False);
1449 KillForwardWord(Widget w, XEvent *event, String *params, Cardinal *num_params)
1451 XawTextScanType type;
1453 if (*num_params && (*params[0] == 'A' || *params[0] == 'a'))
1454 type = XawstAlphaNumeric;
1456 type = XawstWhiteSpace;
1458 DeleteOrKill((TextWidget)w, event, XawsdRight, type, False, True);
1462 KillBackwardWord(Widget w, XEvent *event, String *params, Cardinal *num_params)
1464 XawTextScanType type;
1466 if (*num_params && (*params[0] == 'A' || *params[0] == 'a'))
1467 type = XawstAlphaNumeric;
1469 type = XawstWhiteSpace;
1471 DeleteOrKill((TextWidget) w, event, XawsdLeft, type, False, True);
1476 KillToEndOfLine(Widget w, XEvent *event, String *p, Cardinal *n)
1478 TextWidget ctx = (TextWidget)w;
1479 XawTextPosition end_of_line;
1480 XawTextScanDirection dir = XawsdRight;
1481 short mult = MULT(ctx);
1488 StartAction(ctx, event);
1489 end_of_line = SrcScan(ctx->text.source, ctx->text.insertPos, XawstEOL,
1491 if (end_of_line == ctx->text.insertPos)
1492 end_of_line = SrcScan(ctx->text.source, ctx->text.insertPos, XawstEOL,
1495 if (dir == XawsdRight)
1496 _DeleteOrKill(ctx, ctx->text.insertPos, end_of_line, True);
1498 _DeleteOrKill(ctx, end_of_line, ctx->text.insertPos, True);
1504 KillToEndOfParagraph(Widget w, XEvent *event, String *p, Cardinal *n)
1506 DeleteOrKill((TextWidget)w, event, XawsdRight, XawstParagraph, False, True);
1510 _XawTextZapSelection(TextWidget ctx, XEvent *event, Bool kill)
1512 StartAction(ctx, event);
1513 _DeleteOrKill(ctx, ctx->text.s.left, ctx->text.s.right, kill);
1519 KillCurrentSelection(Widget w, XEvent *event, String *p, Cardinal *n)
1521 _XawTextZapSelection((TextWidget) w, event, True);
1527 KillRingYank(Widget w, XEvent *event, String *params, Cardinal *num_params)
1529 TextWidget ctx = (TextWidget)w;
1530 XawTextPosition insertPos = ctx->text.insertPos;
1531 Bool first_yank = False;
1533 if (ctx->text.s.left != ctx->text.s.right)
1534 XawTextUnsetSelection((Widget)ctx);
1536 StartAction(ctx, event);
1538 if (ctx->text.kill_ring_ptr == NULL) {
1539 ctx->text.kill_ring_ptr = &kill_ring_prev;
1540 ++ctx->text.kill_ring_ptr->refcount;
1541 ctx->text.s.left = ctx->text.s.right = insertPos;
1544 if (ctx->text.kill_ring_ptr) {
1545 int mul = MULT(ctx);
1551 --ctx->text.kill_ring_ptr->refcount;
1553 if ((ctx->text.kill_ring_ptr = ctx->text.kill_ring_ptr->next) == NULL)
1554 ctx->text.kill_ring_ptr = &kill_ring_null;
1556 ++ctx->text.kill_ring_ptr->refcount;
1559 text.length = ctx->text.kill_ring_ptr->length;
1560 text.ptr = ctx->text.kill_ring_ptr->contents;
1561 text.format = ctx->text.kill_ring_ptr->format;
1563 if (_XawTextReplace(ctx, ctx->text.s.left, insertPos, &text) == XawEditDone) {
1564 ctx->text.kill_ring = KILL_RING_YANK;
1565 ctx->text.insertPos = ctx->text.s.left + text.length;
1569 XBell(XtDisplay(w), 0);
1577 DeleteCurrentSelection(Widget w, XEvent *event, String *p, Cardinal *n)
1579 _XawTextZapSelection((TextWidget)w, event, False);
1583 #define CHECK_SAVE() \
1584 if (save && !save->ptr) \
1585 save->ptr = _XawTextGetText(ctx, save->firstPos, \
1586 save->firstPos + save->length)
1588 StripSpaces(TextWidget ctx, XawTextPosition left, XawTextPosition right,
1589 XawTextPosition *pos, int num_pos, XawTextBlock *save)
1592 int i, cpos, count = 0;
1593 XawTextBlock block, text;
1594 XawTextPosition ipos, position = left, tmp = left;
1597 text.format = XawFmt8Bit;
1601 position = XawTextSourceRead(ctx->text.source, position,
1602 &block, right - left);
1605 /* convert tabs and returns to spaces */
1607 if (XawTextFormat(ctx, XawFmt8Bit)) {
1608 for (i = 0; i < block.length; i++)
1609 if (block.ptr[i] == '\t' || block.ptr[i] == '\n') {
1615 wchar_t *wptr = (wchar_t*)block.ptr;
1616 for (i = 0; i < block.length; i++)
1617 if (wptr[i] == _Xaw_atowc('\t') || wptr[i] == _Xaw_atowc('\n')) {
1624 if (_XawTextReplace(ctx, tmp + i, tmp + i + 1, &text))
1629 position = XawTextSourceRead(ctx->text.source, tmp,
1630 &block, right - tmp);
1631 if (block.length == 0 || tmp == position || tmp >= right)
1637 position = tmp = left;
1638 position = XawTextSourceRead(ctx->text.source, position,
1639 &block, right - left);
1640 ipos = ctx->text.insertPos;
1643 if (XawTextFormat(ctx, XawFmt8Bit)) {
1644 for (i = 0; i < block.length; i++)
1645 if (block.ptr[i] == ' ')
1647 else if (count == 1)
1653 wchar_t *wptr = (wchar_t*)block.ptr;
1654 for (i = 0; i < block.length; i++)
1655 if (wptr[i] == _Xaw_atowc(' '))
1657 else if (count == 1)
1664 if (_XawTextReplace(ctx, tmp + i - count, tmp + i, &text))
1668 for (cpos = 0; cpos < num_pos; cpos++) {
1669 if (tmp + i - count < pos[cpos]) {
1670 if (tmp + i < pos[cpos])
1673 pos[cpos] = tmp + i - count;
1678 if (tmp + i - count < ipos) {
1682 ipos = tmp + i - count;
1690 position = XawTextSourceRead(ctx->text.source, tmp,
1691 &block, right - tmp);
1692 if (block.length == 0 || tmp == position || tmp >= right)
1696 ctx->text.insertPos = ipos;
1702 Tabify(TextWidget ctx, XawTextPosition left, XawTextPosition right,
1703 XawTextPosition *pos, int num_pos, XawTextBlock *save)
1706 int i, cpos, count = 0, column = 0, offset = 0;
1707 XawTextBlock text, block;
1708 XawTextPosition ipos, position = left, tmp = left;
1709 TextSinkObject sink = (TextSinkObject)ctx->text.sink;
1710 short *char_tabs = sink->text_sink.char_tabs;
1711 int tab_count = sink->text_sink.tab_count;
1712 int tab_index = 0, tab_column = 0, TAB_SIZE = DEFAULT_TAB_SIZE;
1716 text.format = XawFmt8Bit;
1719 position = XawTextSourceRead(ctx->text.source, position,
1720 &block, right - left);
1721 ipos = ctx->text.insertPos;
1722 done = zero = False;
1724 TAB_SIZE = *char_tabs;
1726 if (XawTextFormat(ctx, XawFmt8Bit)) {
1727 for (i = 0; i < block.length; i++) {
1731 if (column > tab_column + char_tabs[tab_index]) {
1732 TAB_SIZE = tab_index < tab_count - 1 ? char_tabs[tab_index + 1] - char_tabs[tab_index] : *char_tabs;
1733 if (++tab_index >= tab_count) {
1734 tab_column += char_tabs[tab_count - 1];
1739 if (block.ptr[i] == ' ') {
1740 if (++count > TAB_SIZE)
1742 if ((tab_count && column == tab_column + char_tabs[tab_index]) ||
1743 (!tab_count && column % TAB_SIZE == 0)) {
1744 if (count % (TAB_SIZE + 1) > 1)
1751 if (block.ptr[i] == '\n') {
1760 wchar_t *wptr = (wchar_t*)block.ptr;
1761 for (i = 0; i < block.length; i++) {
1765 if (column > tab_column + char_tabs[tab_index]) {
1766 TAB_SIZE = tab_index < tab_count - 1 ? char_tabs[tab_index + 1] - char_tabs[tab_index] : *char_tabs;
1767 if (++tab_index >= tab_count) {
1768 tab_column += char_tabs[tab_count - 1];
1773 if (wptr[i] == _Xaw_atowc(' ')) {
1774 if (++count > TAB_SIZE)
1776 if ((tab_count && column == tab_column + char_tabs[tab_index]) ||
1777 (!tab_count && column % TAB_SIZE == 0)) {
1778 if (count % (TAB_SIZE + 1) > 1)
1785 if (wptr[i] == _Xaw_atowc('\n')) {
1793 count %= TAB_SIZE + 1;
1794 if (!zero && count > 1 && i < block.length) {
1796 if (_XawTextReplace(ctx, tmp + i - count + 1, tmp + i + 1, &text))
1799 offset -= count - 1;
1801 for (cpos = 0; cpos < num_pos; cpos++) {
1802 if (tmp + i - count + 1 < pos[cpos]) {
1803 if (tmp + i + 1 < pos[cpos])
1806 pos[cpos] = tmp + i - count + 1;
1812 if (tmp + i - count + 1 < ipos) {
1813 if (tmp + i + 1 < ipos)
1816 ipos = tmp + i - count + 1;
1827 tab_column = tab_index = 0;
1828 TAB_SIZE = *char_tabs;
1831 else if (i < block.length)
1833 tmp = left + offset;
1834 position = XawTextSourceRead(ctx->text.source, tmp,
1835 &block, right - tmp);
1836 if (tmp == position || tmp >= right)
1840 ctx->text.insertPos = ipos;
1846 Untabify(TextWidget ctx, XawTextPosition left, XawTextPosition right,
1847 XawTextPosition *pos, int num_pos, XawTextBlock *save)
1850 int i, cpos, count = 0, diff = 0;
1851 XawTextBlock block, text;
1852 XawTextPosition ipos, position = left, tmp = left;
1853 TextSinkObject sink = (TextSinkObject)ctx->text.sink;
1854 short *char_tabs = sink->text_sink.char_tabs;
1855 int tab_count = sink->text_sink.tab_count;
1856 int tab_index = 0, tab_column = 0, tab_base = 0;
1857 static char *tabs = " ";
1860 text.format = XawFmt8Bit;
1863 position = XawTextSourceRead(ctx->text.source, position,
1864 &block, right - left);
1865 ipos = ctx->text.insertPos;
1869 if (XawTextFormat(ctx, XawFmt8Bit))
1870 for (i = 0; i < block.length; i++) {
1871 if (block.ptr[i] != '\t') {
1873 if (block.ptr[i] == '\n') {
1882 wchar_t *wptr = (wchar_t*)block.ptr;
1883 for (i = 0; i < block.length; i++)
1884 if (wptr[i] != _Xaw_atowc('\t')) {
1886 if (wptr[i] != _Xaw_atowc('\n')) {
1894 if (!zero && i < block.length) {
1896 while (tab_base + tab_column <= count) {
1897 for (; tab_index < tab_count; ++tab_index)
1898 if (tab_base + char_tabs[tab_index] > count) {
1899 tab_column = char_tabs[tab_index];
1902 if (tab_index >= tab_count) {
1903 tab_base += char_tabs[tab_count - 1];
1904 tab_column = tab_index = 0;
1907 text.length = (tab_base + tab_column) - count;
1908 if (text.length > 8) {
1911 text.ptr = XtMalloc(text.length);
1912 for (j = 0; j < text.length; j++)
1919 text.length = DEFAULT_TAB_SIZE - (count % DEFAULT_TAB_SIZE);
1921 if (_XawTextReplace(ctx, tmp + i, tmp + i + 1, &text)) {
1922 if (tab_count && text.length > 8)
1926 if (tab_count && text.length > 8)
1928 count += text.length;
1929 right += text.length - 1;
1931 for (cpos = 0; cpos < num_pos; cpos++) {
1932 if (tmp + i < pos[cpos]) {
1933 if (tmp + i + 1 < pos[cpos])
1936 pos[cpos] = tmp + i;
1937 pos[cpos] += text.length;
1942 if (tmp + i < ipos) {
1943 if (tmp + i + 1 < ipos)
1947 ipos += text.length;
1951 tmp = left + count + diff;
1957 tab_base = tab_column = tab_index = 0;
1959 position = XawTextSourceRead(ctx->text.source, tmp,
1960 &block, right - tmp);
1961 if (tmp == position || tmp >= right)
1965 ctx->text.insertPos = ipos;
1971 FormatText(TextWidget ctx, XawTextPosition left, Bool force,
1972 XawTextPosition *pos, int num_pos)
1975 Bool freepos = False, undo, paragraph = pos != NULL;
1977 XawTextBlock block, *text;
1978 XawTextPosition end = ctx->text.lastPos, buf[32];
1979 TextSrcObject src = (TextSrcObject)ctx->text.source;
1980 XawTextPosition right = SrcScan(ctx->text.source, left, XawstEOL,
1981 XawsdRight, 1, False);
1983 undo = src->textSrc.enable_undo && src->textSrc.undo_state == False;
1986 num_pos = src->textSrc.num_text;
1987 pos = XawStackAlloc(sizeof(XawTextPosition) * num_pos, buf);
1988 for (i = 0; i < num_pos; i++)
1989 pos[i] = ((TextWidget)src->textSrc.text[i])->text.insertPos;
1994 src->textSrc.undo_state = True;
1996 block.firstPos = left;
1997 block.length = right - left;
2003 result = DoFormatText(ctx, left, force, 1, text, pos, num_pos, paragraph);
2004 if (undo && result == XawEditDone && block.ptr) {
2006 unsigned llen, rlen, size;
2008 ptr = lbuf = block.ptr;
2009 llen = block.length;
2010 rlen = llen + (ctx->text.lastPos - end);
2013 block.format = _XawTextFormat(ctx);
2015 rbuf = _XawTextGetText(ctx, left, left + rlen);
2017 size = XawTextFormat(ctx, XawFmtWide) ? sizeof(wchar_t) : sizeof(char);
2018 if (llen != rlen || memcmp(lbuf, rbuf, llen * size)) {
2020 block.length = llen;
2021 _XawTextReplace(ctx, left, left + rlen, &block);
2023 src->textSrc.undo_state = False;
2025 block.length = rlen;
2026 _XawTextReplace(ctx, left, left + llen, &block);
2029 src->textSrc.undo_state = False;
2033 src->textSrc.undo_state = False;
2035 for (i = 0; i < num_pos; i++) {
2036 TextWidget tw = (TextWidget)src->textSrc.text[i];
2037 tw->text.insertPos = XawMin(XawMax(0, pos[i]), tw->text.lastPos);
2039 XawStackFree(pos, buf);
2049 DoFormatText(TextWidget ctx, XawTextPosition left, Bool force, int level,
2050 XawTextBlock *save, XawTextPosition *pos, int num_pos,
2053 XawTextPosition right = SrcScan(ctx->text.source, left, XawstEOL,
2054 XawsdRight, 1, False);
2055 XawTextPosition position, tmp, ipos;
2056 XawTextBlock block, text;
2060 Bool done, force2 = force, recurse = False;
2062 position = XawTextSourceRead(ctx->text.source, left, &block, right - left);
2063 if (block.length == 0 || left >= right ||
2064 (level == 1 && ((XawTextFormat(ctx, XawFmt8Bit) &&
2065 block.ptr[0] != ' ' &&
2066 block.ptr[0] != '\t' &&
2067 !isalnum(*(unsigned char*)block.ptr)) ||
2068 (XawTextFormat(ctx, XawFmtWide) &&
2069 _Xaw_atowc(XawSP) != *(wchar_t*)block.ptr &&
2070 _Xaw_atowc(XawTAB) != *(wchar_t*)block.ptr &&
2071 !iswalnum(*(wchar_t*)block.ptr)))))
2072 return (XawEditDone);
2074 if (level == 1 && !paragraph) {
2075 tmp = ctx->text.lastPos;
2076 if (Untabify(ctx, left, right, pos, num_pos, save) == False)
2077 return (XawEditError);
2078 right += ctx->text.lastPos - tmp;
2079 position = XawTextSourceRead(ctx->text.source, left, &block,
2084 text.format = XawFmt8Bit;
2086 ipos = ctx->text.insertPos;
2090 if (XawTextFormat(ctx, XawFmt8Bit)) {
2091 for (i = 0; i < block.length; i++)
2092 if (block.ptr[i] == ' ')
2100 wptr = (wchar_t*)block.ptr;
2101 for (i = 0; i < block.length; i++)
2102 if (wptr[i] == _Xaw_atowc(' '))
2110 position = XawTextSourceRead(ctx->text.source, position,
2111 &block, right - position);
2112 if (tmp == position)
2115 position = left + count;
2116 if (count < ctx->text.left_column) {
2117 int bytes = ctx->text.left_column - count;
2119 text.ptr = XawStackAlloc(bytes, buf);
2120 text.length = bytes;
2121 for (i = 0; i < bytes; i++)
2124 if (_XawTextReplace(ctx, left, left, &text)) {
2125 XawStackFree(text.ptr, buf);
2126 return (XawEditError);
2128 XawStackFree(text.ptr, buf);
2131 for (cpos = 0; cpos < num_pos; cpos++)
2132 if (pos[cpos] >= left)
2141 if (!paragraph && level == 1
2142 && ipos <= right && ipos - left > ctx->text.right_column) {
2143 XawTextPosition len = ctx->text.lastPos;
2144 int skip = ctx->text.justify == XawjustifyRight
2145 || ctx->text.justify == XawjustifyCenter ?
2146 ctx->text.left_column : count;
2149 for (i = 0; i < num_pos; i++)
2153 StripSpaces(ctx, left + skip, right, pos, num_pos, save);
2154 right += ctx->text.lastPos - len;
2155 if (pos && i < num_pos)
2158 ipos = ctx->text.insertPos;
2159 done = ipos - left > ctx->text.right_column;
2160 count = skip + (count == skip + 1);
2162 if ((paragraph || done) && right - left > ctx->text.right_column) {
2163 position = tmp = right;
2164 XawTextSourceRead(ctx->text.source, position - 1, &block, 1);
2166 ((XawTextFormat(ctx, XawFmt8Bit) &&
2167 block.ptr[0] == ' ') ||
2168 (XawTextFormat(ctx, XawFmtWide) &&
2169 _Xaw_atowc(XawSP) == *(wchar_t*)block.ptr)))
2171 while (position - left > ctx->text.right_column) {
2173 position = SrcScan(ctx->text.source, position,
2174 XawstWhiteSpace, XawsdLeft, 1, True);
2176 if (position <= left + ctx->text.left_column)
2178 if (position > left && position - left > ctx->text.left_column
2179 && position != right) {
2183 if (_XawTextReplace(ctx, position, position + 1, &text))
2184 return (XawEditError);
2192 if (ctx->text.justify == XawjustifyCenter)
2193 count = ctx->text.right_column - (count - ctx->text.left_column);
2195 count = ctx->text.right_column;
2196 if (count > right - left)
2197 count -= right - left;
2204 switch (ctx->text.justify) {
2205 case XawjustifyLeft:
2207 case XawjustifyRight:
2208 case XawjustifyCenter:
2209 if (ctx->text.justify == XawjustifyCenter) {
2213 XawTextSourceRead(ctx->text.source, right, &block, 1);
2214 if ((XawTextFormat(ctx, XawFmt8Bit)
2215 && isalnum(*(unsigned char*)block.ptr)) ||
2216 (XawTextFormat(ctx, XawFmtWide)
2217 && iswalnum(*(wchar_t*)block.ptr)))
2220 count = (count + alnum) >> 1;
2222 text.ptr = XawStackAlloc(count, buf);
2223 text.length = count;
2224 for (i = 0; i < count; i++)
2227 if (_XawTextReplace(ctx, left, left, &text)) {
2228 XawStackFree(text.ptr, buf);
2229 return (XawEditError);
2231 XawStackFree(text.ptr, buf);
2235 for (cpos = 0; cpos < num_pos; cpos++)
2236 if (pos[cpos] > left)
2239 else if (ipos > left)
2242 case XawjustifyFull:
2247 tmp = SrcScan(ctx->text.source, tmp, XawstWhiteSpace,
2248 XawsdRight, 1, True);
2259 inc = ii = (count + .5) / (double)i;
2262 text.ptr = XawStackAlloc(steps, buf);
2263 for (i = 0; i < steps; i++)
2269 while (inc + ii < 1) {
2273 tmp = SrcScan(ctx->text.source, tmp, XawstWhiteSpace,
2274 XawsdRight, steps, True);
2276 text.length = (int)inc;
2278 text.length = bytes;
2279 bytes -= text.length;
2280 if (_XawTextReplace(ctx, tmp, tmp, &text)) {
2281 XawStackFree(text.ptr, buf);
2282 return (XawEditError);
2285 for (cpos = 0; cpos < num_pos; cpos++)
2286 if (tmp <= pos[cpos])
2287 pos[cpos] += text.length;
2289 else if (tmp <= ipos)
2290 ipos += text.length;
2296 XawStackFree(text.ptr, buf);
2303 ctx->text.insertPos = XawMin(ipos, ctx->text.lastPos);
2305 return (recurse ? DoFormatText(ctx, position + 1,
2306 ctx->text.justify != XawjustifyFull
2307 && (force2 || paragraph),
2308 ++level, save, pos, num_pos, paragraph)
2315 Indent(Widget w, XEvent *event, String *params, Cardinal *num_params)
2317 TextWidget ctx = (TextWidget)w;
2318 TextSrcObject src = (TextSrcObject)ctx->text.source;
2319 XawTextPosition from, to, tmp, end = 0, *pos, *posbuf[32];
2322 int i, spaces = MULT(ctx);
2323 char *lbuf = NULL, *rbuf;
2324 unsigned llen = 0, rlen, size;
2325 Bool undo = src->textSrc.enable_undo && src->textSrc.undo_state == False;
2326 Bool format = ctx->text.auto_fill
2327 && ctx->text.left_column < ctx->text.right_column;
2330 text.format = XawFmt8Bit;
2333 StartAction(ctx, event);
2335 pos = XawStackAlloc(sizeof(XawTextPosition) * src->textSrc.num_text, posbuf);
2336 for (i = 0; i < src->textSrc.num_text; i++)
2337 pos[i] = ((TextWidget)src->textSrc.text[i])->text.insertPos;
2339 if (!GetBlockBoundaries(ctx, &from, &to)) {
2341 XawStackFree(pos, posbuf);
2347 end = ctx->text.lastPos;
2348 lbuf = _XawTextGetText(ctx, from, to);
2349 src->textSrc.undo_state = True;
2352 tmp = ctx->text.lastPos;
2353 if (!Untabify(ctx, from, to, pos, src->textSrc.num_text, NULL)) {
2354 XBell(XtDisplay(ctx), 0);
2356 XawStackFree(pos, posbuf);
2358 src->textSrc.undo_state = True;
2363 to += ctx->text.lastPos - tmp;
2368 text.ptr = XawStackAlloc(spaces, buf);
2369 for (i = 0; i < spaces; i++)
2372 text.length = spaces;
2374 _XawTextReplace(ctx, tmp, tmp, &text);
2376 for (i = 0; i < src->textSrc.num_text; i++)
2381 tmp = SrcScan(ctx->text.source, tmp, XawstEOL, XawsdRight, 1, True);
2383 XawStackFree(text.ptr, buf);
2391 /* find the amount of spaces to cut */
2393 (void)BlankLine(w, tmp, &i);
2396 tmp = SrcScan(ctx->text.source, tmp, XawstEOL, XawsdRight, 1, True);
2398 spaces = XawMin(-spaces, min);
2400 /* cut the spaces */
2403 _XawTextReplace(ctx, tmp, tmp + spaces, &text);
2405 for (i = 0; i < src->textSrc.num_text; i++)
2407 if (tmp + spaces < pos[i])
2414 tmp = SrcScan(ctx->text.source, tmp, XawstEOL, XawsdRight, 1, True);
2419 Tabify(ctx, from, to, pos, src->textSrc.num_text, NULL);
2422 rlen = llen + (ctx->text.lastPos - end);
2423 rbuf = _XawTextGetText(ctx, from, from + rlen);
2425 text.format = _XawTextFormat(ctx);
2426 size = XawTextFormat(ctx, XawFmtWide) ? sizeof(wchar_t) : sizeof(char);
2427 if (llen != rlen || memcmp(lbuf, rbuf, llen * size)) {
2430 _XawTextReplace(ctx, from, from + rlen, &text);
2432 src->textSrc.undo_state = False;
2435 _XawTextReplace(ctx, from, from + llen, &text);
2438 src->textSrc.undo_state = False;
2443 for (i = 0; i < src->textSrc.num_text; i++) {
2444 TextWidget tw = (TextWidget)src->textSrc.text[i];
2446 tw->text.insertPos = XawMin(XawMax(0, pos[i]), tw->text.lastPos);
2448 XawStackFree(pos, posbuf);
2449 ctx->text.showposition = True;
2456 ToggleOverwrite(Widget w, XEvent *event, String *params, Cardinal *num_params)
2458 TextWidget ctx = (TextWidget)w;
2460 ctx->text.overwrite = !ctx->text.overwrite;
2462 /* call information callback */
2463 _XawTextSetLineAndColumnNumber(ctx, True);
2468 * Insertion Routines
2471 InsertNewLineAndBackupInternal(TextWidget ctx)
2473 int count, error = XawEditDone, mult = MULT(ctx);
2475 XawTextPosition position;
2482 return (XawEditError);
2485 text.format = _XawTextFormat(ctx);
2489 if (text.format == XawFmtWide) {
2492 text.ptr = XawStackAlloc(sizeof(wchar_t) * mult, buf);
2493 wptr = (wchar_t *)text.ptr;
2494 for (count = 0; count < mult; count++)
2495 wptr[count] = _Xaw_atowc(XawLF);
2498 text.ptr = XawStackAlloc(sizeof(char) * mult, buf);
2499 for (count = 0; count < mult; count++)
2500 text.ptr[count] = XawLF;
2504 position = SrcScan(ctx->text.source, ctx->text.insertPos,
2505 XawstEOL, XawsdLeft, 1, False);
2507 if (_XawTextReplace(ctx, ctx->text.insertPos, ctx->text.insertPos, &text)) {
2508 XBell( XtDisplay(ctx), 50);
2509 error = XawEditError;
2512 ctx->text.showposition = TRUE;
2513 ctx->text.insertPos += text.length;
2516 XawStackFree(text.ptr, buf);
2519 if (ctx->text.auto_fill && error == XawEditDone)
2520 (void)FormatText(ctx, position, ctx->text.justify != XawjustifyFull,
2529 InsertNewLineAndBackup(Widget w, XEvent *event, String *p, Cardinal *n)
2531 TextWidget ctx = (TextWidget)w;
2532 XawTextPosition insertPos = ctx->text.insertPos;
2534 StartAction((TextWidget)w, event);
2535 (void)InsertNewLineAndBackupInternal(ctx);
2536 ctx->text.insertPos = SrcScan(ctx->text.source, insertPos, XawstEOL,
2537 XawsdRight, 1, False);
2538 EndAction((TextWidget)w);
2542 LocalInsertNewLine(TextWidget ctx, XEvent *event)
2546 StartAction(ctx, event);
2547 error = InsertNewLineAndBackupInternal(ctx);
2548 ctx->text.from_left = -1;
2556 InsertNewLine(Widget w, XEvent *event, String *p, Cardinal *n)
2558 (void)LocalInsertNewLine((TextWidget)w, event);
2563 InsertNewLineAndIndent(Widget w, XEvent *event, String *p, Cardinal *n)
2566 XawTextPosition pos1;
2568 TextWidget ctx = (TextWidget)w;
2571 StartAction(ctx, event);
2572 pos1 = SrcScan(ctx->text.source, ctx->text.insertPos,
2573 XawstEOL, XawsdLeft, 1, False);
2575 line_to_ip = _XawTextGetText(ctx, pos1, ctx->text.insertPos);
2577 text.format = _XawTextFormat(ctx);
2580 if (text.format == XawFmtWide) {
2583 text.ptr = XtMalloc((2 + wcslen((wchar_t*)line_to_ip))
2585 ptr = (wchar_t*)text.ptr;
2586 ptr[0] = _Xaw_atowc(XawLF);
2587 wcscpy((wchar_t*)++ptr, (wchar_t*)line_to_ip);
2589 length = wcslen((wchar_t*)text.ptr);
2590 while (length && (iswspace(*ptr) || *ptr == _Xaw_atowc(XawTAB)))
2593 text.length = wcslen((wchar_t*)text.ptr);
2598 length = strlen(line_to_ip);
2599 text.ptr = XtMalloc((2 + length) * sizeof(char));
2602 strcpy(++ptr, line_to_ip);
2605 while (length && (isspace(*ptr) || (*ptr == XawTAB)))
2608 text.length = strlen(text.ptr);
2612 if (_XawTextReplace(ctx,ctx->text.insertPos, ctx->text.insertPos, &text)) {
2613 XBell(XtDisplay(ctx), 50);
2620 ctx->text.from_left = -1;
2621 ctx->text.insertPos = SrcScan(ctx->text.source, ctx->text.old_insert,
2622 XawstPositions, XawsdRight, text.length, True);
2627 * Selection Routines
2630 SelectWord(Widget w, XEvent *event, String *params, Cardinal *num_params)
2632 TextWidget ctx = (TextWidget)w;
2633 XawTextPosition l, r;
2635 StartAction(ctx, event);
2636 l = SrcScan(ctx->text.source, ctx->text.insertPos,
2637 XawstWhiteSpace, XawsdLeft, 1, False);
2638 r = SrcScan(ctx->text.source, l, XawstWhiteSpace, XawsdRight, 1, False);
2639 _XawTextSetSelection(ctx, l, r, params, *num_params);
2644 SelectAll(Widget w, XEvent *event, String *params, Cardinal *num_params)
2646 TextWidget ctx = (TextWidget)w;
2648 StartAction(ctx, event);
2649 _XawTextSetSelection(ctx,zeroPosition,ctx->text.lastPos,params,*num_params);
2654 ModifySelection(TextWidget ctx, XEvent *event,
2655 XawTextSelectionMode mode,
2656 XawTextSelectionAction action,
2657 String *params, Cardinal *num_params)
2660 int old_y = ctx->text.ev_y;
2663 StartAction(ctx, event);
2664 NotePosition(ctx, event);
2667 if (event->type == MotionNotify) {
2668 if (ctx->text.ev_y <= ctx->text.margin.top) {
2669 if (old_y >= ctx->text.ev_y)
2670 XawTextScroll(ctx, -1, 0);
2672 else if (ctx->text.ev_y >= XtHeight(ctx) - ctx->text.margin.bottom) {
2673 if (old_y <= ctx->text.ev_y
2674 && !IsPositionVisible(ctx, ctx->text.lastPos))
2675 XawTextScroll(ctx, 1, 0);
2679 ctx->text.from_left = -1;
2680 _XawTextAlterSelection(ctx, mode, action, params, num_params);
2686 SelectStart(Widget w, XEvent *event, String *params, Cardinal *num_params)
2688 TextWidget ctx = (TextWidget)w;
2691 if (!ctx->text.selection_state) {
2692 ctx->text.selection_state = True;
2694 ModifySelection(ctx, event,
2695 XawsmTextSelect, XawactionStart, params, num_params);
2702 SelectAdjust(Widget w, XEvent *event, String *params, Cardinal *num_params)
2704 TextWidget ctx = (TextWidget)w;
2707 if (ctx->text.selection_state)
2709 ModifySelection(ctx, event,
2710 XawsmTextSelect, XawactionAdjust, params, num_params);
2714 SelectEnd(Widget w, XEvent *event, String *params, Cardinal *num_params)
2716 TextWidget ctx = (TextWidget)w;
2719 if (ctx->text.selection_state) {
2720 ctx->text.selection_state = False;
2722 ModifySelection(ctx, event,
2723 XawsmTextSelect, XawactionEnd, params, num_params);
2730 ExtendStart(Widget w, XEvent *event, String *params, Cardinal *num_params)
2732 TextWidget ctx = (TextWidget)w;
2735 if (!ctx->text.selection_state) {
2736 ctx->text.selection_state = True;
2738 ModifySelection(ctx, event,
2739 XawsmTextExtend, XawactionStart, params, num_params);
2746 ExtendAdjust(Widget w, XEvent *event, String *params, Cardinal *num_params)
2748 TextWidget ctx = (TextWidget)w;
2751 if (ctx->text.selection_state)
2753 ModifySelection(ctx, event,
2754 XawsmTextExtend, XawactionAdjust, params, num_params);
2758 ExtendEnd(Widget w, XEvent *event, String *params, Cardinal *num_params)
2760 TextWidget ctx = (TextWidget)w;
2763 if (ctx->text.selection_state) {
2764 ctx->text.selection_state = False;
2766 ModifySelection(ctx, event,
2767 XawsmTextExtend, XawactionEnd, params, num_params);
2774 SelectSave(Widget w, XEvent *event, String *params, Cardinal *num_params)
2778 Display *dpy = XtDisplay(w);
2779 Atom selections[256];
2781 StartAction((TextWidget)w, event);
2782 num_atoms = *num_params;
2783 if (num_atoms > 256)
2785 for (sel=selections; --num_atoms >= 0; sel++, params++)
2786 *sel = XInternAtom(dpy, *params, False);
2787 num_atoms = *num_params;
2788 _XawTextSaltAwaySelection((TextWidget)w, selections, num_atoms);
2789 EndAction((TextWidget)w);
2797 SetKeyboardFocus(Widget w, XEvent *event, String *params, Cardinal *num_params)
2799 Widget shell, parent;
2803 if (XtIsShell(shell = parent))
2805 parent = XtParent(parent);
2807 XtSetKeyboardFocus(shell, w);
2812 RedrawDisplay(Widget w, XEvent *event, String *p, Cardinal *n)
2814 StartAction((TextWidget)w, event);
2815 _XawTextClearAndCenterDisplay((TextWidget)w);
2816 EndAction((TextWidget)w);
2819 /* This is kind of a hack, but, only one text widget can have focus at
2820 * a time on one display. There is a problem in the implementation of the
2821 * text widget, the scrollbars can not be adressed via editres, since they
2822 * are not children of a subclass of composite.
2823 * The focus variable is required to make sure only one text window will
2824 * show a block cursor at one time.
2826 struct _focus { Display *display; Widget widget; };
2827 static struct _focus *focus;
2828 static Cardinal num_focus;
2832 DestroyFocusCallback(Widget w, XtPointer user_data, XtPointer call_data)
2834 struct _focus *f = (struct _focus*)(user_data);
2842 TextFocusIn(Widget w, XEvent *event, String *p, Cardinal *n)
2844 TextWidget ctx = (TextWidget)w;
2845 Bool display_caret = ctx->text.display_caret;
2848 if (event->xfocus.detail == NotifyPointer)
2851 if (event->xfocus.send_event) {
2853 int rootx, rooty, x, y;
2856 if (ctx->text.hasfocus)
2859 if (XQueryPointer(XtDisplay(w), XtWindow(w), &root, &child,
2860 &rootx, &rooty, &x, &y, &mask)) {
2866 /* Let the input method know focus has arrived. */
2867 _XawImSetFocusValues(w, NULL, 0);
2870 StartAction(ctx, event);
2871 ctx->text.hasfocus = TRUE;
2875 for (i = 0; i < num_focus; i++)
2876 if (focus[i].display == XtDisplay(w))
2878 if (i >= num_focus) {
2879 focus = (struct _focus*)
2880 XtRealloc((XtPointer)focus, sizeof(struct _focus) * (num_focus + 1));
2882 focus[i].widget = NULL;
2883 focus[i].display = XtDisplay(w);
2886 if (focus[i].widget != w) {
2887 Widget old = focus[i].widget;
2889 focus[i].widget = w;
2891 TextFocusOut(old, event, p, n);
2892 /* TextFocusOut may set it to NULL */
2893 focus[i].widget = w;
2895 XtAddCallback(w, XtNdestroyCallback,
2896 DestroyFocusCallback, (XtPointer)&focus[i]);
2902 TextFocusOut(Widget w, XEvent *event, String *p, Cardinal *n)
2904 TextWidget ctx = (TextWidget)w;
2905 Bool display_caret = ctx->text.display_caret;
2912 if (XtIsShell(shell))
2914 shell = XtParent(shell);
2917 for (i = 0; i < num_focus; i++)
2918 if (focus[i].display == XtDisplay(w))
2920 XGetInputFocus(XtDisplay(w), &window, &revert);
2921 if ((XtWindow(shell) == window &&
2922 (i < num_focus && focus[i].widget == w))
2923 || event->xfocus.detail == NotifyPointer)
2926 if (i < num_focus && focus[i].widget) {
2927 XtRemoveCallback(focus[i].widget, XtNdestroyCallback,
2928 DestroyFocusCallback, (XtPointer)&focus[i]);
2929 focus[i].widget = NULL;
2932 /* Let the input method know focus has left.*/
2933 _XawImUnsetFocus(w);
2936 StartAction(ctx, event);
2937 ctx->text.hasfocus = FALSE;
2944 TextEnterWindow(Widget w, XEvent *event, String *params, Cardinal *num_params)
2946 TextWidget ctx = (TextWidget)w;
2948 if ((event->xcrossing.detail != NotifyInferior) && event->xcrossing.focus
2949 && !ctx->text.hasfocus)
2950 _XawImSetFocusValues(w, NULL, 0);
2955 TextLeaveWindow(Widget w, XEvent *event, String *params, Cardinal *num_params)
2957 TextWidget ctx = (TextWidget)w;
2959 if ((event->xcrossing.detail != NotifyInferior) && event->xcrossing.focus
2960 && !ctx->text.hasfocus)
2961 _XawImUnsetFocus(w);
2967 * Arguments: ctx - The text widget.
2970 * Breaks the line at the previous word boundry when
2971 * called inside InsertChar.
2974 AutoFill(TextWidget ctx)
2976 int width, height, x, line_num, max_width;
2977 XawTextPosition ret_pos;
2982 for (line_num = 0; line_num < ctx->text.lt.lines ; line_num++)
2983 if (ctx->text.lt.info[line_num].position >= ctx->text.insertPos)
2986 line_num--; /* backup a line. */
2988 XawTextSinkGetCursorBounds(ctx->text.sink, &cursor);
2989 max_width = Max(0, (int)XtWidth(ctx) - RHMargins(ctx) - cursor.width);
2991 x = ctx->text.r_margin.left;
2992 XawTextSinkFindPosition(ctx->text.sink, ctx->text.lt.info[line_num].position,
2993 x, max_width, True, &ret_pos,
2996 if (ret_pos <= ctx->text.lt.info[line_num].position
2997 || ret_pos >= ctx->text.insertPos || ret_pos < 1)
3000 XawTextSourceRead(ctx->text.source, ret_pos - 1, &text, 1);
3002 if (XawTextFormat(ctx, XawFmtWide)) {
3003 wc_buf[0] = *(wchar_t *)text.ptr;
3004 if (wc_buf[0] != _Xaw_atowc(XawSP) && wc_buf[0] != _Xaw_atowc(XawTAB))
3005 /* Only eats white spaces */
3008 text.format = XawFmtWide;
3009 text.ptr = (char *)wc_buf;
3010 wc_buf[0] = _Xaw_atowc(XawLF);
3014 if (text.ptr[0] != XawSP && text.ptr[0] != XawTAB)
3015 /* Only eats white spaces */
3018 text.format = XawFmt8Bit;
3024 if (_XawTextReplace(ctx, ret_pos - 1, ret_pos, &text))
3025 XBell(XtDisplay((Widget)ctx), 0);
3027 if (++ctx->text.insertPos > ctx->text.lastPos)
3028 ctx->text.insertPos = ctx->text.lastPos;
3033 InsertChar(Widget w, XEvent *event, String *p, Cardinal *n)
3035 TextWidget ctx = (TextWidget)w;
3036 char *ptr, strbuf[128], ptrbuf[512];
3037 int count, error, mult = MULT(ctx);
3041 Bool format = False;
3043 XawTextPosition from, to;
3045 if (XtIsSubclass (ctx->text.source, (WidgetClass) multiSrcObjectClass))
3046 text.length = _XawImWcLookupString(w, &event->xkey, (wchar_t*)strbuf,
3047 sizeof(strbuf), &keysym);
3049 text.length = _XawLookupString(w, (XKeyEvent*)event, strbuf,
3050 sizeof(strbuf), &keysym);
3052 if (text.length == 0)
3060 text.format = _XawTextFormat(ctx);
3061 if (text.format == XawFmtWide) {
3062 text.ptr = ptr = XawStackAlloc(sizeof(wchar_t) * text.length
3064 for (count = 0; count < mult; count++) {
3065 memcpy((char*)ptr, (char *)strbuf, sizeof(wchar_t) * text.length);
3066 ptr += sizeof(wchar_t) * text.length;
3070 format = ctx->text.left_column < ctx->text.right_column;
3073 else { /* == XawFmt8Bit */
3074 text.ptr = ptr = XawStackAlloc(text.length * mult, ptrbuf);
3075 for (count = 0; count < mult; count++) {
3076 strncpy(ptr, strbuf, text.length);
3081 format = ctx->text.left_column < ctx->text.right_column;
3085 text.length = text.length * mult;
3088 StartAction(ctx, event);
3091 _XawSourceSetUndoMerge((TextSrcObject)ctx->text.source, True);
3094 from = ctx->text.insertPos;
3096 if (ctx->text.overwrite) {
3097 XawTextPosition tmp;
3100 tmp = SrcScan(ctx->text.source, from, XawstEOL, XawsdRight, 1, False);
3108 error = _XawTextReplace(ctx, from , to, &text);
3110 if (error == XawEditDone) {
3111 ctx->text.from_left = -1;
3112 ctx->text.insertPos = SrcScan(ctx->text.source, ctx->text.old_insert,
3113 XawstPositions, XawsdRight,
3115 if (ctx->text.auto_fill) {
3118 (void)FormatText(ctx, SrcScan(ctx->text.source,
3119 ctx->text.insertPos, XawstEOL,
3120 XawsdLeft, 1, False), False,
3128 XBell(XtDisplay(ctx), 50);
3130 XawStackFree(text.ptr, ptrbuf);
3133 if (error == XawEditDone && text.format == XawFmt8Bit && text.length == 1
3134 && (text.ptr[0] == ')' || text.ptr[0] == ']' || text.ptr[0] == '}')
3135 && ctx->text.display_caret) {
3136 static struct timeval tmval = {0, 500000};
3138 Widget source = ctx->text.source;
3139 XawTextPosition insertPos = ctx->text.insertPos, pos, tmp, last;
3140 char left, right = text.ptr[0];
3142 XtAppContext app_context = XtWidgetToApplicationContext(w);
3144 left = right == ')' ? '(' : right == ']' ? '[' : '{';
3146 last = insertPos - 1;
3149 pos = XawTextSourceSearch(source, last, XawsdLeft, &text);
3150 if (pos == XawTextSearchError || !IsPositionVisible(ctx, pos))
3152 text.ptr[0] = right;
3155 tmp = XawTextSourceSearch(source, tmp, XawsdRight, &text);
3156 if (tmp == XawTextSearchError)
3160 } while (++tmp <= last);
3165 StartAction(ctx, NULL);
3167 _XawSourceSetUndoMerge((TextSrcObject)ctx->text.source, True);
3169 ctx->text.insertPos = pos;
3172 XSync(XtDisplay(w), False);
3173 while (XtAppPending(app_context) & XtIMXEvent) {
3175 if (! XtAppPeekEvent(app_context, &ev))
3177 if (ev.type == KeyPress || ev.type == ButtonPress)
3179 XtAppProcessEvent(app_context, XtIMXEvent);
3182 FD_SET(ConnectionNumber(XtDisplay(w)), &fds);
3183 (void)select(FD_SETSIZE, &fds, NULL, NULL, &tmval);
3184 if (tmval.tv_usec != 500000)
3187 StartAction(ctx, NULL);
3189 _XawSourceSetUndoMerge((TextSrcObject)ctx->text.source, True);
3191 ctx->text.insertPos = insertPos;
3196 /* IfHexConvertHexElseReturnParam() - called by InsertString
3198 * i18n requires the ability to specify multiple characters in a hexa-
3199 * decimal string at once. Since Insert was already too long, I made
3200 * this a seperate routine.
3202 * A legal hex string in MBNF: '0' 'x' ( HEX-DIGIT HEX-DIGIT )+ '\0'
3204 * WHEN: the passed param is a legal hex string
3205 * RETURNS: a pointer to that converted, null terminated hex string;
3206 * len_return holds the character count of conversion result
3208 * WHEN: the passed param is not a legal hex string:
3209 * RETURNS: the parameter passed;
3210 * len_return holds the char count of param.
3212 * NOTE: In neither case will there be strings to free. */
3214 IfHexConvertHexElseReturnParam(char *param, int *len_return)
3216 char *p; /* steps through param char by char */
3217 char c; /* holds the character pointed to by p */
3218 int ind; /* steps through hexval buffer char by char */
3219 static char hexval[XawTextActionMaxHexChars];
3220 Boolean first_digit;
3222 /* reject if it doesn't begin with 0x and at least one more character. */
3223 if ((param[0] != '0') || (param[1] != 'x') || (param[2] == '\0')) {
3224 *len_return = strlen(param);
3228 /* Skip the 0x; go character by character shifting and adding. */
3233 for (p = param+2; (c = *p) != '\0'; p++) {
3235 if (c >= '0' && c <= '9')
3236 hexval[ind] += c - '0';
3237 else if (c >= 'a' && c <= 'f')
3238 hexval[ind] += c - 'a' + 10;
3239 else if (c >= 'A' && c <= 'F')
3240 hexval[ind] += c - 'A' + 10;
3244 /* If we didn't break in preceding line, it was a good hex char. */
3246 first_digit = False;
3249 if (++ind < XawTextActionMaxHexChars)
3252 *len_return = strlen(param);
3258 /* We quit the above loop becasue we hit a non hex. If that char is \0... */
3259 if ((c == '\0') && first_digit) {
3260 *len_return = strlen(hexval);
3261 return (hexval); /* ...it was a legal hex string, so return it */
3264 /* Else, there were non-hex chars or odd digit count, so... */
3266 *len_return = strlen(param);
3267 return (param); /* ...return the verbatim string. */
3270 /* InsertString() - action
3272 * Mostly rewritten for R6 i18n.
3274 * Each parameter, in turn, will be insert at the inputPos
3275 * and the inputPos advances to the insertion's end.
3277 * The exception is that parameters composed of the two
3278 * characters 0x, followed only by an even number of
3279 * hexadecimal digits will be converted to characters */
3282 InsertString(Widget w, XEvent *event, String *params, Cardinal *num_params)
3284 TextWidget ctx = (TextWidget)w;
3285 XtAppContext app_con = XtWidgetToApplicationContext(w);
3290 text.format = _XawTextFormat(ctx);
3292 StartAction(ctx, event);
3293 for (i = *num_params; i; i--, params++) { /* DO FOR EACH PARAMETER */
3294 text.ptr = IfHexConvertHexElseReturnParam(*params, &text.length);
3296 if (text.length == 0)
3299 if (XawTextFormat(ctx, XawFmtWide)) { /* convert to WC */
3302 text.ptr = (char*)_XawTextMBToWC(XtDisplay(w), text.ptr,
3305 if (text.ptr == NULL) { /* conversion error */
3306 XtAppWarningMsg(app_con,
3307 "insertString", "textAction", "XawError",
3308 "insert-string()'s parameter contents "
3309 "not legal in this locale.",
3311 ParameterError(w, *params);
3315 /* Double check that the new input is legal: try to convert to MB. */
3317 temp_len = text.length; /* _XawTextWCToMB's 3rd arg is in_out */
3318 if (_XawTextWCToMB(XtDisplay(w), (wchar_t*)text.ptr, &temp_len)
3320 XtAppWarningMsg( app_con,
3321 "insertString", "textAction", "XawError",
3322 "insert-string()'s parameter contents "
3323 "not legal in this locale.",
3325 ParameterError(w, *params);
3328 } /* convert to WC */
3330 if (_XawTextReplace(ctx, ctx->text.insertPos,
3331 ctx->text.insertPos, &text)) {
3332 XBell(XtDisplay(ctx), 50);
3337 ctx->text.from_left = -1;
3338 /* Advance insertPos to the end of the string we just inserted. */
3339 ctx->text.insertPos = SrcScan(ctx->text.source, ctx->text.old_insert,
3340 XawstPositions, XawsdRight, text.length,
3343 } /* DO FOR EACH PARAMETER */
3348 /* DisplayCaret() - action
3350 * The parameter list should contain one boolean value. If the
3351 * argument is true, the cursor will be displayed. If false, not.
3353 * The exception is that EnterNotify and LeaveNotify events may
3354 * have a second argument, "always". If they do not, the cursor
3355 * is only affected if the focus member of the event is true. */
3357 DisplayCaret(Widget w, XEvent *event, String *params, Cardinal *num_params)
3359 TextWidget ctx = (TextWidget)w;
3360 Bool display_caret = True;
3362 if ((event->type == EnterNotify || event->type == LeaveNotify)
3363 && ((*num_params >= 2) && (strcmp(params[1], "always") == 0))
3364 && (!event->xcrossing.focus))
3367 if (*num_params > 0) { /* default arg is "True" */
3369 from.size = strlen(from.addr = params[0]);
3370 XtConvert(w, XtRString, &from, XtRBoolean, &to);
3372 if (to.addr != NULL)
3373 display_caret = *(Boolean*)to.addr;
3374 if (ctx->text.display_caret == display_caret)
3377 StartAction(ctx, event);
3378 ctx->text.display_caret = display_caret;
3384 Numeric(Widget w, XEvent *event, String *params, Cardinal *num_params)
3386 TextWidget ctx = (TextWidget)w;
3388 if (ctx->text.numeric) {
3389 long mult = ctx->text.mult;
3391 if (*num_params != 1 || strlen(params[0]) != 1
3392 || (!isdigit(params[0][0])
3393 && (params[0][0] != '-' || mult != 0))) {
3396 if (event && (event->type == KeyPress || event->type == KeyRelease)
3397 && params[0][0] == '-') {
3398 InsertChar(w, event, params, num_params);
3401 snprintf(err_buf, sizeof(err_buf),
3402 "numeric: Invalid argument%s'%s'",
3403 *num_params ? ", " : "",
3404 *num_params ? params[0] : "");
3405 XtAppWarning(XtWidgetToApplicationContext(w), err_buf);
3406 ctx->text.numeric = False;
3410 if (params[0][0] == '-') {
3411 ctx->text.mult = 32767;
3414 else if (mult == 32767) {
3415 mult = ctx->text.mult = - (params[0][0] - '0');
3419 mult = mult * 10 + (params[0][0] - '0') * (mult < 0 ? -1 : 1);
3420 ctx->text.mult = ctx->text.mult * 10 + (params[0][0] - '0') *
3421 (mult < 0 ? -1 : 1);
3423 if (mult != ctx->text.mult || mult >= 32767) { /* checks for overflow */
3424 XBell(XtDisplay(w), 0);
3426 ctx->text.numeric = False;
3431 InsertChar(w, event, params, num_params);
3436 KeyboardReset(Widget w, XEvent *event, String *params, Cardinal *num_params)
3438 TextWidget ctx = (TextWidget)w;
3440 ctx->text.numeric = False;
3443 (void)_XawTextSrcToggleUndo((TextSrcObject)ctx->text.source);
3445 if (ctx->text.kill_ring_ptr) {
3446 --ctx->text.kill_ring_ptr->refcount;
3447 ctx->text.kill_ring_ptr = NULL;
3449 ctx->text.kill_ring = 0;
3451 XBell(XtDisplay(w), 0);
3455 /* Multiply() - action
3457 * The parameter list may contain either a number or the string 'Reset'.
3459 * A number will multiply the current multiplication factor by that number.
3460 * Many of the text widget actions will will perform n actions, where n is
3461 * the multiplication factor.
3463 * The string reset will reset the mutiplication factor to 1. */
3466 Multiply(Widget w, XEvent *event, String *params, Cardinal *num_params)
3468 TextWidget ctx = (TextWidget)w;
3471 if (*num_params != 1) {
3472 XtAppError(XtWidgetToApplicationContext(w),
3473 "Xaw Text Widget: multiply() takes exactly one argument.");
3474 XBell(XtDisplay(w), 0);
3478 if ((params[0][0] == 'r') || (params[0][0] == 'R')) {
3479 XBell(XtDisplay(w), 0);
3481 ctx->text.numeric = False;
3488 if (params[0][0] == 's' || params[0][0] == 'S') {
3489 ctx->text.numeric = True;
3495 if ((mult = atoi(params[0])) == 0) {
3498 snprintf(buf, sizeof(buf),
3499 "Xaw Text Widget: multiply() argument "
3500 "must be a number greater than zero, or 'Reset'.");
3501 XtAppError(XtWidgetToApplicationContext(w), buf);
3502 XBell(XtDisplay(w), 50);
3506 ctx->text.mult *= mult;
3509 /* StripOutOldCRs() - called from FormRegion
3511 * removes CRs in widget ctx, from from to to.
3513 * RETURNS: the new ending location (we may add some characters),
3514 * or XawReplaceError if the widget can't be written to. */
3515 static XawTextPosition
3516 StripOutOldCRs(TextWidget ctx, XawTextPosition from, XawTextPosition to,
3517 XawTextPosition *pos, int num_pos)
3519 XawTextPosition startPos, endPos, eop_begin, eop_end, temp;
3520 Widget src = ctx->text.source;
3523 static wchar_t wc_two_spaces[3];
3526 /* Initialize our TextBlock with two spaces. */
3528 text.format = _XawTextFormat(ctx);
3529 if (text.format == XawFmt8Bit)
3532 wc_two_spaces[0] = _Xaw_atowc(XawSP);
3533 wc_two_spaces[1] = _Xaw_atowc(XawSP);
3534 wc_two_spaces[2] = 0;
3535 text.ptr = (char*)wc_two_spaces;
3538 /* Strip out CR's. */
3539 eop_begin = eop_end = startPos = endPos = from;
3543 endPos=SrcScan(src, startPos, XawstEOL, XawsdRight, 1, False);
3545 temp = SrcScan(src, endPos, XawstWhiteSpace, XawsdLeft, 1, False);
3546 temp = SrcScan(src, temp, XawstWhiteSpace, XawsdRight,1, False);
3548 if (temp > startPos)
3554 if (endPos >= eop_begin) {
3556 eop_begin=SrcScan(src, startPos, XawstParagraph,
3557 XawsdRight, 1,False);
3558 eop_end = SrcScan(src, startPos, XawstParagraph,
3559 XawsdRight, 1, True);
3562 XawTextPosition periodPos, next_word;
3565 periodPos = SrcScan(src, endPos, XawstPositions,
3566 XawsdLeft, 1, True);
3567 next_word = SrcScan(src, endPos, XawstWhiteSpace,
3568 XawsdRight, 1, False);
3570 len = next_word - periodPos;
3573 buf = _XawTextGetText(ctx, periodPos, next_word);
3574 if (text.format == XawFmtWide) {
3575 if (periodPos < endPos && ((wchar_t*)buf)[0] == _Xaw_atowc('.'))
3579 if (periodPos < endPos && buf[0] == '.')
3580 text.length++; /* Put in two spaces. */
3583 * Remove all extra spaces.
3585 for (i = 1 ; i < len; i++)
3586 if (text.format == XawFmtWide) {
3587 if (!iswspace(((wchar_t*)buf)[i]) || ((periodPos + i) >= to))
3590 else if (!isspace(buf[i]) || (periodPos + i) >= to)
3595 to -= (i - text.length - 1);
3596 startPos = SrcScan(src, periodPos, XawstPositions,
3597 XawsdRight, i, True);
3598 if (_XawTextReplace(ctx, endPos, startPos, &text) != XawEditDone)
3599 return (XawReplaceError);
3601 for (idx = 0; idx < num_pos; idx++) {
3602 if (endPos < pos[idx]) {
3603 if (startPos < pos[idx])
3604 pos[idx] -= startPos - endPos;
3607 pos[idx] += text.length;
3611 startPos -= i - text.length;
3618 /* InsertNewCRs() - called from FormRegion
3620 * inserts new CRs for FormRegion, thus for FormParagraph action */
3622 InsertNewCRs(TextWidget ctx, XawTextPosition from, XawTextPosition to,
3623 XawTextPosition *pos, int num_pos)
3625 XawTextPosition startPos, endPos, space, eol;
3627 int i, width, height, len, wwidth, idx;
3629 static wchar_t wide_CR[2];
3633 text.format = _XawTextFormat(ctx);
3635 if (text.format == XawFmt8Bit)
3638 wide_CR[0] = _Xaw_atowc(XawLF);
3640 text.ptr = (char*)wide_CR;
3645 wwidth = (int)XtWidth(ctx) - (int)HMargins(ctx);
3646 if (ctx->text.wrap != XawtextWrapNever) {
3649 XawTextSinkGetCursorBounds(ctx->text.sink, &cursor);
3650 wwidth -= (int)cursor.width;
3652 wwidth = XawMax(0, wwidth);
3656 XawTextSinkFindPosition(ctx->text.sink, startPos,
3657 (int)ctx->text.r_margin.left, wwidth,
3658 True, &eol, &width, &height);
3659 if (eol == startPos)
3664 eol = SrcScan(ctx->text.source, eol, XawstPositions,
3665 XawsdLeft, 1, True);
3666 space = SrcScan(ctx->text.source, eol, XawstWhiteSpace,
3667 XawsdRight,1, True);
3669 startPos = endPos = eol;
3673 len = (int)(space - eol);
3674 buf = _XawTextGetText(ctx, eol, space);
3675 for (i = 0 ; i < len ; i++)
3676 if (text.format == XawFmtWide) {
3677 if (!iswspace(((wchar_t*)buf)[i]))
3680 else if (!isspace(buf[i]))
3684 endPos = SrcScan(ctx->text.source, endPos,
3685 XawstPositions, XawsdRight, i, True);
3688 if (_XawTextReplace(ctx, startPos, endPos, &text))
3691 for (idx = 0; idx < num_pos; idx++) {
3692 if (startPos < pos[idx]) {
3693 if (endPos < pos[idx])
3694 pos[idx] -= endPos - startPos;
3696 pos[idx] = startPos;
3697 pos[idx] += text.length;
3701 startPos = SrcScan(ctx->text.source, startPos,
3702 XawstPositions, XawsdRight, 1, True);
3706 /* FormRegion() - called by FormParagraph
3708 * oversees the work of paragraph-forming a region
3711 * XawEditDone if successful, or XawReplaceError
3714 FormRegion(TextWidget ctx, XawTextPosition from, XawTextPosition to,
3715 XawTextPosition *pos, int num_pos)
3718 Bool format = ctx->text.auto_fill
3719 && ctx->text.left_column < ctx->text.right_column;
3723 return (XawEditDone);
3727 XawTextPosition len = ctx->text.lastPos;
3730 if (ctx->text.justify == XawjustifyLeft ||
3731 ctx->text.justify == XawjustifyFull) {
3732 Untabify(ctx, from, to, pos, num_pos, NULL);
3733 to += ctx->text.lastPos - len;
3734 len = ctx->text.insertPos;
3735 (void)BlankLine((Widget)ctx, from, &inc);
3736 if (from + inc >= to)
3737 return (XawEditDone);
3739 if (!StripSpaces(ctx, from + inc, to, pos, num_pos, NULL))
3740 return (XawReplaceError);
3741 to += ctx->text.lastPos - len;
3743 FormatText(ctx, from, ctx->text.justify != XawjustifyFull, pos, num_pos);
3747 if ((to = StripOutOldCRs(ctx, from, to, pos, num_pos)) == XawReplaceError)
3748 return (XawReplaceError);
3749 InsertNewCRs(ctx, from, to, pos, num_pos);
3753 ctx->text.from_left = -1;
3755 return (XawEditDone);
3760 BlankLine(Widget w, XawTextPosition pos, int *blanks_return)
3764 Widget src = XawTextGetSource(w);
3765 XawTextPosition l = SrcScan(src, pos, XawstEOL, XawsdLeft, 1, False);
3766 XawTextPosition r = SrcScan(src, pos, XawstEOL, XawsdRight, 1, False);
3769 l = XawTextSourceRead(src, l, &block, r - l);
3770 if (block.length == 0) {
3772 *blanks_return = blanks;
3775 if (XawTextFormat((TextWidget)w, XawFmt8Bit)) {
3776 for (i = 0; i < block.length; i++, blanks++)
3777 if (block.ptr[i] != ' ' &&
3778 block.ptr[i] != '\t') {
3780 *blanks_return = blanks;
3781 return (block.ptr[i] == '\n');
3784 else if (XawTextFormat((TextWidget)w, XawFmtWide)) {
3785 for (i = 0; i < block.length; i++, blanks++)
3786 if (_Xaw_atowc(XawSP) != ((wchar_t*)block.ptr)[i] &&
3787 _Xaw_atowc(XawTAB) != ((wchar_t*)block.ptr)[i]) {
3789 *blanks_return = blanks;
3790 return (_Xaw_atowc(XawLF) == ((wchar_t*)block.ptr)[i]);
3799 GetBlockBoundaries(TextWidget ctx,
3800 XawTextPosition *from_return, XawTextPosition *to_return)
3802 XawTextPosition from, to;
3804 if (ctx->text.auto_fill && ctx->text.left_column < ctx->text.right_column) {
3805 if (ctx->text.s.left != ctx->text.s.right) {
3806 from = SrcScan(ctx->text.source,
3807 XawMin(ctx->text.s.left, ctx->text.s.right),
3808 XawstEOL, XawsdLeft, 1, False);
3809 to = SrcScan(ctx->text.source,
3810 XawMax(ctx->text.s.right, ctx->text.s.right),
3811 XawstEOL, XawsdRight, 1, False);
3815 XawTextPosition tmp;
3818 from = to = ctx->text.insertPos;
3820 /* find from position */
3824 from = SrcScan(ctx->text.source, from, XawstEOL, XawsdLeft,
3826 XawTextSourceRead(ctx->text.source, from, &block, 1);
3827 if (block.length == 0 ||
3828 (XawTextFormat(ctx, XawFmt8Bit) &&
3829 block.ptr[0] != ' ' &&
3830 block.ptr[0] != '\t' &&
3831 !isalnum(*(unsigned char*)block.ptr)) ||
3832 (XawTextFormat(ctx, XawFmtWide) &&
3833 _Xaw_atowc(XawSP) != *(wchar_t*)block.ptr &&
3834 _Xaw_atowc(XawTAB) != *(wchar_t*)block.ptr &&
3835 !iswalnum(*(wchar_t*)block.ptr)) ||
3836 BlankLine((Widget)ctx, from, NULL)) {
3840 if (from == tmp && !first)
3847 /* find to position */
3851 to = SrcScan(ctx->text.source, to, XawstEOL, XawsdRight,
3853 XawTextSourceRead(ctx->text.source, to + (to < ctx->text.lastPos),
3855 if (block.length == 0 ||
3856 (XawTextFormat(ctx, XawFmt8Bit) &&
3857 block.ptr[0] != ' ' &&
3858 block.ptr[0] != '\t' &&
3859 !isalnum(*(unsigned char*)block.ptr)) ||
3860 (XawTextFormat(ctx, XawFmtWide) &&
3861 _Xaw_atowc(XawSP) != *(wchar_t*)block.ptr &&
3862 _Xaw_atowc(XawTAB) != *(wchar_t*)block.ptr &&
3863 !iswalnum(*(wchar_t*)block.ptr)) ||
3864 BlankLine((Widget)ctx, to, NULL))
3866 if (to == tmp && !first)
3873 from = SrcScan(ctx->text.source, ctx->text.insertPos, XawstEOL,
3874 XawsdLeft, 1, False);
3875 if (BlankLine((Widget)ctx, from, NULL))
3877 from = SrcScan(ctx->text.source, from, XawstParagraph,
3878 XawsdLeft, 1, False);
3879 if (BlankLine((Widget)ctx, from, NULL))
3880 from = SrcScan(ctx->text.source, from, XawstEOL,
3881 XawsdRight, 1, True);
3882 to = SrcScan(ctx->text.source, from, XawstParagraph,
3883 XawsdRight, 1, False);
3887 *from_return = from;
3896 /* FormParagraph() - action
3898 * removes and reinserts CRs to maximize line length without clipping */
3901 FormParagraph(Widget w, XEvent *event, String *params, Cardinal *num_params)
3903 TextWidget ctx = (TextWidget)w;
3904 XawTextPosition from, to, buf[32], *pos;
3906 XawTextPosition endPos = 0;
3907 char *lbuf = NULL, *rbuf;
3908 TextSrcObject src = (TextSrcObject)ctx->text.source;
3910 Bool undo = src->textSrc.enable_undo && src->textSrc.undo_state == False;
3913 StartAction(ctx, event);
3916 pos = XawStackAlloc(sizeof(XawTextPosition) * src->textSrc.num_text, buf);
3917 for (i = 0; i < src->textSrc.num_text; i++)
3918 pos[i] = ((TextWidget)src->textSrc.text[i])->text.old_insert;
3921 *pos = ctx->text.old_insert;
3925 if (!GetBlockBoundaries(ctx, &from, &to)) {
3927 XawStackFree(pos, buf);
3932 src->textSrc.undo_state = True;
3933 lbuf = _XawTextGetText(ctx, from, to);
3934 endPos = ctx->text.lastPos;
3937 if (FormRegion(ctx, from, to, pos, src->textSrc.num_text) == XawReplaceError) {
3938 XawStackFree(pos, buf);
3941 from = SrcScan(ctx->text.source, ctx->text.insertPos,
3942 XawstParagraph, XawsdLeft, 1, False);
3943 to = SrcScan(ctx->text.source, from,
3944 XawstParagraph, XawsdRight, 1, False);
3946 if (FormRegion(ctx, from, to, pos, 1) == XawReplaceError) {
3948 XBell(XtDisplay(w), 0);
3951 src->textSrc.undo_state = False;
3958 /* makes the form-paragraph only one undo/redo step */
3959 unsigned llen, rlen, size;
3963 rlen = llen + (ctx->text.lastPos - endPos);
3966 block.format = _XawTextFormat(ctx);
3968 rbuf = _XawTextGetText(ctx, from, from + rlen);
3970 size = XawTextFormat(ctx, XawFmtWide) ? sizeof(wchar_t) : sizeof(char);
3971 if (llen != rlen || memcmp(lbuf, rbuf, llen * size)) {
3973 block.length = llen;
3974 _XawTextReplace(ctx, from, from + rlen, &block);
3976 src->textSrc.undo_state = False;
3978 block.length = rlen;
3979 _XawTextReplace(ctx, from, from + llen, &block);
3982 src->textSrc.undo_state = False;
3987 for (i = 0; i < src->textSrc.num_text; i++) {
3988 TextWidget tw = (TextWidget)src->textSrc.text[i];
3990 tw->text.old_insert = tw->text.insertPos = pos[i];
3991 _XawTextBuildLineTable(tw, SrcScan((Widget)src, tw->text.lt.top, XawstEOL,
3992 XawsdLeft, 1, False), False);
3993 tw->text.clear_to_eol = True;
3995 XawStackFree(pos, buf);
3997 ctx->text.old_insert = ctx->text.insertPos = *pos;
3998 _XawTextBuildLineTable(ctx, SrcScan(ctx->text.source, ctx->text.lt.top,
3999 XawstEOL, XawsdLeft, 1, False), False);
4000 ctx->text.clear_to_eol = True;
4002 ctx->text.showposition = True;
4007 /* TransposeCharacters() - action
4009 * Swaps the character to the left of the mark
4010 * with the character to the right of the mark */
4013 TransposeCharacters(Widget w, XEvent *event,
4014 String *params, Cardinal *num_params)
4016 TextWidget ctx = (TextWidget)w;
4017 XawTextPosition start, end;
4020 int i, mult = MULT(ctx);
4027 StartAction(ctx, event);
4031 start = SrcScan(ctx->text.source, ctx->text.insertPos, XawstPositions,
4032 XawsdLeft, 1, True);
4033 end = SrcScan(ctx->text.source, ctx->text.insertPos, XawstPositions,
4034 XawsdRight, mult, True);
4036 /* Make sure we aren't at the very beginning or end of the buffer. */
4038 if (start == ctx->text.insertPos || end == ctx->text.insertPos) {
4039 XBell(XtDisplay(w), 0); /* complain. */
4044 ctx->text.from_left = -1;
4045 ctx->text.insertPos = end;
4048 text.format = _XawTextFormat(ctx);
4050 /* Retrieve text and swap the characters. */
4051 if (text.format == XawFmtWide) {
4055 wbuf = (wchar_t*)_XawTextGetText(ctx, start, end);
4056 text.length = wcslen(wbuf);
4058 for (i = 1; i < text.length; i++)
4059 wbuf[i - 1] = wbuf[i];
4061 buf = (char*)wbuf; /* so that it gets assigned and freed */
4063 else { /* thus text.format == XawFmt8Bit */
4066 buf = _XawTextGetText(ctx, start, end);
4067 text.length = strlen(buf);
4069 for (i = 1; i < text.length; i++)
4070 buf[i - 1] = buf[i];
4076 /* Store new text in source. */
4078 if (_XawTextReplace (ctx, start, end, &text))
4079 XBell(XtDisplay(w), 0);
4080 XtFree((char *)buf);
4087 Undo(Widget w, XEvent *event, String *params, Cardinal *num_params)
4089 TextWidget ctx = (TextWidget)w;
4090 int mul = MULT(ctx);
4091 Bool toggle = False;
4095 _XawTextSrcToggleUndo((TextSrcObject)ctx->text.source);
4096 ctx->text.mult = mul = -mul;
4099 StartAction(ctx, event);
4101 if (!_XawTextSrcUndo((TextSrcObject)ctx->text.source, &ctx->text.insertPos))
4103 ctx->text.showposition = True;
4106 _XawTextSrcToggleUndo((TextSrcObject)ctx->text.source);
4112 * This action performs no action, and allows the user or
4113 * application programmer to unbind a translation.
4115 * Note: If the parameter list contains the string "RingBell" then
4116 * this action will ring the bell.
4120 NoOp(Widget w, XEvent *event, String *params, Cardinal *num_params)
4122 if (*num_params != 1)
4125 switch(params[0][0]) {
4128 XBell(XtDisplay(w), 0);
4135 /* Reconnect() - action
4136 * This reconnects to the input method. The user will typically call
4137 * this action if/when connection has been severed, or when the app
4138 * was started up before an IM was started up
4142 Reconnect(Widget w, XEvent *event, String *params, Cardinal *num_params)
4147 #define CAPITALIZE 1
4158 XmuNCopyISOLatin1Lowered(buf, buf, sizeof(buf));
4169 XmuNCopyISOLatin1Uppered(buf, buf, sizeof(buf));
4177 return ((ch >= '0' && ch <= '9') || ToUpper(ch) != ch || ToLower(ch) != ch);
4186 *upbuf = *lobuf = ch;
4187 XmuNCopyISOLatin1Lowered(lobuf, lobuf, sizeof(lobuf));
4188 XmuNCopyISOLatin1Uppered(upbuf, upbuf, sizeof(upbuf));
4190 return (*lobuf != *upbuf && ch == *lobuf);
4199 *upbuf = *lobuf = ch;
4200 XmuNCopyISOLatin1Lowered(lobuf, lobuf, sizeof(lobuf));
4201 XmuNCopyISOLatin1Uppered(upbuf, upbuf, sizeof(upbuf));
4203 return (*lobuf != *upbuf && ch == *upbuf);
4206 #define ToLower tolower
4207 #define ToUpper toupper
4208 #define IsAlnum isalnum
4209 #define IsLower islower
4210 #define IsUpper isupper
4214 CaseProc(Widget w, XEvent *event, int cmd)
4216 TextWidget ctx = (TextWidget)w;
4217 short mul = MULT(ctx);
4218 XawTextPosition left, right;
4220 Bool changed = False;
4221 unsigned char ch, mb[sizeof(wchar_t)];
4225 right = SrcScan(ctx->text.source, left = ctx->text.insertPos,
4226 XawstAlphaNumeric, XawsdRight, mul, False);
4228 left = SrcScan(ctx->text.source, right = ctx->text.insertPos,
4229 XawstAlphaNumeric, XawsdLeft, 1 + -mul, False);
4231 block.format = _XawTextFormat(ctx);
4232 block.length = right - left;
4233 block.ptr = _XawTextGetText(ctx, left, right);
4236 if (block.format == XawFmt8Bit)
4237 for (i = 0; i < block.length; i++) {
4238 if (!IsAlnum(*mb = (unsigned char)block.ptr[i]))
4240 else if (++count == 1 || cmd != CAPITALIZE) {
4241 ch = cmd == DOWNCASE ? ToLower(*mb) : ToUpper(*mb);
4247 else if (cmd == CAPITALIZE) {
4248 if ((ch = ToLower(*mb)) != *mb) {
4255 for (i = 0; i < block.length; i++) {
4256 wctomb((char*)mb, ((wchar_t*)block.ptr)[i]);
4259 else if (++count == 1 || cmd != CAPITALIZE) {
4260 ch = cmd == DOWNCASE ? ToLower(*mb) : ToUpper(*mb);
4263 ((wchar_t*)block.ptr)[i] = _Xaw_atowc(ch);
4266 else if (cmd == CAPITALIZE) {
4267 if ((ch = ToLower(*mb)) != *mb) {
4269 ((wchar_t*)block.ptr)[i] = _Xaw_atowc(ch);
4274 StartAction(ctx, event);
4275 if (changed && _XawTextReplace(ctx, left, right, &block) != XawEditDone)
4276 XBell(XtDisplay(ctx), 0);
4277 ctx->text.insertPos = right;
4285 CapitalizeWord(Widget w, XEvent *event, String *params, Cardinal *num_params)
4287 CaseProc(w, event, CAPITALIZE);
4292 DowncaseWord(Widget w, XEvent *event, String *params, Cardinal *num_params)
4294 CaseProc(w, event, DOWNCASE);
4299 UpcaseWord(Widget w, XEvent *event, String *params, Cardinal *num_params)
4301 CaseProc(w, event, UPCASE);
4307 XtActionsRec _XawTextActionsTable[] = {
4309 {"forward-character", MoveForwardChar},
4310 {"backward-character", MoveBackwardChar},
4311 {"forward-word", MoveForwardWord},
4312 {"backward-word", MoveBackwardWord},
4313 {"forward-paragraph", MoveForwardParagraph},
4314 {"backward-paragraph", MoveBackwardParagraph},
4315 {"beginning-of-line", MoveToLineStart},
4316 {"end-of-line", MoveToLineEnd},
4317 {"next-line", MoveNextLine},
4318 {"previous-line", MovePreviousLine},
4319 {"next-page", MoveNextPage},
4320 {"previous-page", MovePreviousPage},
4321 {"beginning-of-file", MoveBeginningOfFile},
4322 {"end-of-file", MoveEndOfFile},
4323 {"scroll-one-line-up", ScrollOneLineUp},
4324 {"scroll-one-line-down", ScrollOneLineDown},
4327 {"delete-next-character", DeleteForwardChar},
4328 {"delete-previous-character", DeleteBackwardChar},
4329 {"delete-next-word", DeleteForwardWord},
4330 {"delete-previous-word", DeleteBackwardWord},
4331 {"delete-selection", DeleteCurrentSelection},
4335 {"kill-word", KillForwardWord},
4336 {"backward-kill-word", KillBackwardWord},
4337 {"kill-selection", KillCurrentSelection},
4338 {"kill-to-end-of-line", KillToEndOfLine},
4339 {"kill-to-end-of-paragraph", KillToEndOfParagraph},
4342 {"newline-and-indent", InsertNewLineAndIndent},
4343 {"newline-and-backup", InsertNewLineAndBackup},
4344 {"newline", InsertNewLine},
4347 {"select-word", SelectWord},
4348 {"select-all", SelectAll},
4349 {"select-start", SelectStart},
4350 {"select-adjust", SelectAdjust},
4351 {"select-end", SelectEnd},
4352 {"select-save", SelectSave},
4353 {"extend-start", ExtendStart},
4354 {"extend-adjust", ExtendAdjust},
4355 {"extend-end", ExtendEnd},
4356 {"insert-selection", InsertSelection},
4359 {"redraw-display", RedrawDisplay},
4360 {"insert-file", _XawTextInsertFile},
4361 {"search", _XawTextSearch},
4362 {"insert-char", InsertChar},
4363 {"insert-string", InsertString},
4364 {"focus-in", TextFocusIn},
4365 {"focus-out", TextFocusOut},
4366 {"enter-window", TextEnterWindow},
4367 {"leave-window", TextLeaveWindow},
4368 {"display-caret", DisplayCaret},
4369 {"multiply", Multiply},
4370 {"form-paragraph", FormParagraph},
4371 {"transpose-characters", TransposeCharacters},
4372 {"set-keyboard-focus", SetKeyboardFocus},
4374 {"numeric", Numeric},
4376 {"keyboard-reset", KeyboardReset},
4377 {"kill-ring-yank", KillRingYank},
4378 {"toggle-overwrite", ToggleOverwrite},
4383 /* case transformations */
4384 {"capitalize-word", CapitalizeWord},
4385 {"downcase-word", DowncaseWord},
4386 {"upcase-word", UpcaseWord},
4388 /* action to bind translations for text dialogs */
4389 {"InsertFileAction", _XawTextInsertFileAction},
4390 {"DoSearchAction", _XawTextDoSearchAction},
4391 {"DoReplaceAction", _XawTextDoReplaceAction},
4392 {"SetField", _XawTextSetField},
4393 {"PopdownSearchAction", _XawTextPopdownSearchAction},
4395 /* reconnect to Input Method */
4396 {"reconnect-im", Reconnect} /* Li Yuhong, Omron KK, 1991 */
4399 Cardinal _XawTextActionsTableCount = XtNumber(_XawTextActionsTable);