1 /*
2
3 Copyright 1989, 1994, 1998 The Open Group
4
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
9 documentation.
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
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.
20
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.
24
25 */
26
27 #ifdef HAVE_CONFIG_H
28 #include <config.h>
29 #endif
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <X11/Xos.h> /* for select() and struct timeval */
34 #include <ctype.h>
35 #include <X11/IntrinsicP.h>
36 #include <X11/StringDefs.h>
37 #include <X11/Xatom.h>
38 #include <X11/Xfuncs.h>
39 #include <X11/Xutil.h>
40 #include <X11/Xmu/Atoms.h>
41 #include <X11/Xmu/Misc.h>
42 #include <X11/Xmu/StdSel.h>
43 #include <X11/Xaw/MultiSinkP.h>
44 #include <X11/Xaw/MultiSrcP.h>
45 #include <X11/Xaw/TextP.h>
46 #include <X11/Xaw/TextSrcP.h>
47 #include <X11/Xaw/XawImP.h>
48 #include "Private.h"
49 #include "XawI18n.h"
50
51 #ifdef _WIN32
52 #include <X11/Xwinsock.h>
53 #endif
54
55 #define SrcScan XawTextSourceScan
56 #define FindDist XawTextSinkFindDistance
57 #define FindPos XawTextSinkFindPosition
58 #define MULT(w) (w->text.mult == 0 ? 4 : \
59 w->text.mult == 32767 ? -4 : w->text.mult)
60
61 #define KILL_RING_APPEND 2
62 #define KILL_RING_BEGIN 3
63 #define KILL_RING_YANK 100
64 #define KILL_RING_YANK_DONE 98
65
66 #define XawTextActionMaxHexChars 100
67
68 /*
69 * Prototypes
70 */
71 static void _DeleteOrKill(TextWidget, XawTextPosition, XawTextPosition, Bool);
72 static void _SelectionReceived(Widget, XtPointer, Atom*, Atom*, XtPointer,
73 unsigned long*, int*);
74 static void _LoseSelection(Widget, Atom*, char**, int*);
75 static void AutoFill(TextWidget);
76 static Boolean ConvertSelection(Widget, Atom*, Atom*, Atom*, XtPointer*,
77 unsigned long*, int*);
78 static void DeleteOrKill(TextWidget, XEvent*, XawTextScanDirection,
79 XawTextScanType, Bool, Bool);
80 static void EndAction(TextWidget);
81 #ifndef OLDXAW
82 static Bool BlankLine(Widget, XawTextPosition, int*);
83 static int DoFormatText(TextWidget, XawTextPosition, Bool, int,
84 XawTextBlock*, XawTextPosition*, int, Bool);
85 static int FormatText(TextWidget, XawTextPosition, Bool,
86 XawTextPosition*, int);
87 static Bool GetBlockBoundaries(TextWidget, XawTextPosition*, XawTextPosition*);
88 #endif
89 static int FormRegion(TextWidget, XawTextPosition, XawTextPosition,
90 XawTextPosition*, int);
91 static void GetSelection(Widget, Time, String*, Cardinal);
92 static char *IfHexConvertHexElseReturnParam(char*, int*);
93 static void InsertNewCRs(TextWidget, XawTextPosition, XawTextPosition,
94 XawTextPosition*, int);
95 static int InsertNewLineAndBackupInternal(TextWidget);
96 static int LocalInsertNewLine(TextWidget, XEvent*);
97 static void LoseSelection(Widget, Atom*);
98 static void ParameterError(Widget, String);
99 static Bool MatchSelection(Atom, XawTextSelection*);
100 static void ModifySelection(TextWidget, XEvent*, XawTextSelectionMode,
101 XawTextSelectionAction, String*, Cardinal*);
102 static void Move(TextWidget, XEvent*, XawTextScanDirection, XawTextScanType,
103 Bool);
104 static void NotePosition(TextWidget, XEvent*);
105 static void StartAction(TextWidget, XEvent*);
106 static XawTextPosition StripOutOldCRs(TextWidget, XawTextPosition,
107 XawTextPosition, XawTextPosition*, int);
108 #ifndef OLDXAW
109 static Bool StripSpaces(TextWidget, XawTextPosition, XawTextPosition,
110 XawTextPosition*, int, XawTextBlock*);
111 static Bool Tabify(TextWidget, XawTextPosition, XawTextPosition,
112 XawTextPosition*, int, XawTextBlock*);
113 static Bool Untabify(TextWidget, XawTextPosition, XawTextPosition,
114 XawTextPosition*, int, XawTextBlock*);
115 #endif
116
117 /*
118 * Actions
119 */
120 static void CapitalizeWord(Widget, XEvent*, String*, Cardinal*);
121 static void DisplayCaret(Widget, XEvent*, String*, Cardinal*);
122 static void Delete(Widget, XEvent*, String*, Cardinal*);
123 static void DeleteBackwardChar(Widget, XEvent*, String*, Cardinal*);
124 static void DeleteBackwardWord(Widget, XEvent*, String*, Cardinal*);
125 static void DeleteCurrentSelection(Widget, XEvent*, String*, Cardinal*);
126 static void DeleteForwardChar(Widget, XEvent*, String*, Cardinal*);
127 static void DeleteForwardWord(Widget, XEvent*, String*, Cardinal*);
128 static void DowncaseWord(Widget, XEvent*, String*, Cardinal*);
129 static void ExtendAdjust(Widget, XEvent*, String*, Cardinal*);
130 static void ExtendEnd(Widget, XEvent*, String*, Cardinal*);
131 static void ExtendStart(Widget, XEvent*, String*, Cardinal*);
132 static void FormParagraph(Widget, XEvent*, String*, Cardinal*);
133 #ifndef OLDXAW
134 static void Indent(Widget, XEvent*, String*, Cardinal*);
135 #endif
136 static void InsertChar(Widget, XEvent*, String*, Cardinal*);
137 static void InsertNewLine(Widget, XEvent*, String*, Cardinal*);
138 static void InsertNewLineAndBackup(Widget, XEvent*, String*, Cardinal*);
139 static void InsertNewLineAndIndent(Widget, XEvent*, String*, Cardinal*);
140 static void InsertSelection(Widget, XEvent*, String*, Cardinal*);
141 static void InsertString(Widget, XEvent*, String*, Cardinal*);
142 #ifndef OLDXAW
143 static void KeyboardReset(Widget, XEvent*, String*, Cardinal*);
144 #endif
145 static void KillBackwardWord(Widget, XEvent*, String*, Cardinal*);
146 static void KillCurrentSelection(Widget, XEvent*, String*, Cardinal*);
147 static void KillForwardWord(Widget, XEvent*, String*, Cardinal*);
148 #ifndef OLDXAW
149 static void KillRingYank(Widget, XEvent*, String*, Cardinal*);
150 #endif
151 static void KillToEndOfLine(Widget, XEvent*, String*, Cardinal*);
152 static void KillToEndOfParagraph(Widget, XEvent*, String*, Cardinal*);
153 static void MoveBackwardChar(Widget, XEvent*, String*, Cardinal*);
154 static void MoveBackwardWord(Widget, XEvent*, String*, Cardinal*);
155 static void MoveBackwardParagraph(Widget, XEvent*, String*, Cardinal*);
156 static void MoveBeginningOfFile(Widget, XEvent*, String*, Cardinal*);
157 static void MoveEndOfFile(Widget, XEvent*, String*, Cardinal*);
158 static void MoveForwardChar(Widget, XEvent*, String*, Cardinal*);
159 static void MoveForwardWord(Widget, XEvent*, String*, Cardinal*);
160 static void MoveForwardParagraph(Widget, XEvent*, String*, Cardinal*);
161 static void MoveNextLine(Widget, XEvent*, String*, Cardinal*);
162 static void MoveNextPage(Widget, XEvent*, String*, Cardinal*);
163 static void MovePage(TextWidget, XEvent*, XawTextScanDirection);
164 static void MovePreviousLine(Widget, XEvent*, String*, Cardinal*);
165 static void MovePreviousPage(Widget, XEvent*, String*, Cardinal*);
166 static void MoveLine(TextWidget, XEvent*, XawTextScanDirection);
167 static void MoveToLineEnd(Widget, XEvent*, String*, Cardinal*);
168 static void MoveToLineStart(Widget, XEvent*, String*, Cardinal*);
169 static void Multiply(Widget, XEvent*, String*, Cardinal*);
170 static void NoOp(Widget, XEvent*, String*, Cardinal*);
171 #ifndef OLDXAW
172 static void Numeric(Widget, XEvent*, String*, Cardinal*);
173 #endif
174 static void Reconnect(Widget, XEvent*, String*, Cardinal*);
175 static void RedrawDisplay(Widget, XEvent*, String*, Cardinal*);
176 static void Scroll(TextWidget, XEvent*, XawTextScanDirection);
177 static void ScrollOneLineDown(Widget, XEvent*, String*, Cardinal*);
178 static void ScrollOneLineUp(Widget, XEvent*, String*, Cardinal*);
179 static void SelectAdjust(Widget, XEvent*, String*, Cardinal*);
180 static void SelectAll(Widget, XEvent*, String*, Cardinal*);
181 static void SelectEnd(Widget, XEvent*, String*, Cardinal*);
182 static void SelectSave(Widget, XEvent*, String*, Cardinal*);
183 static void SelectStart(Widget, XEvent*, String*, Cardinal*);
184 static void SelectWord(Widget, XEvent*, String*, Cardinal*);
185 static void SetKeyboardFocus(Widget, XEvent*, String*, Cardinal*);
186 static void TextEnterWindow(Widget, XEvent*, String*, Cardinal*);
187 static void TextFocusIn(Widget, XEvent*, String*, Cardinal*);
188 static void TextFocusOut(Widget, XEvent*, String*, Cardinal*);
189 static void TextLeaveWindow(Widget, XEvent*, String*, Cardinal*);
190 static void TransposeCharacters(Widget, XEvent*, String*, Cardinal*);
191 #ifndef OLDXAW
192 static void ToggleOverwrite(Widget, XEvent*, String*, Cardinal*);
193 static void Undo(Widget, XEvent*, String*, Cardinal*);
194 #endif
195 static void UpcaseWord(Widget, XEvent*, String*, Cardinal*);
196 static void DestroyFocusCallback(Widget, XtPointer, XtPointer);
197
198 /*
199 * External
200 */
201 void _XawTextZapSelection(TextWidget, XEvent*, Bool);
202
203 /*
204 * Defined in TextPop.c
205 */
206 void _XawTextInsertFileAction(Widget, XEvent*, String*, Cardinal*);
207 void _XawTextInsertFile(Widget, XEvent*, String*, Cardinal*);
208 void _XawTextSearch(Widget, XEvent*, String*, Cardinal*);
209 void _XawTextDoSearchAction(Widget, XEvent*, String*, Cardinal*);
210 void _XawTextDoReplaceAction(Widget, XEvent*, String*, Cardinal*);
211 void _XawTextSetField(Widget, XEvent*, String*, Cardinal*);
212 void _XawTextPopdownSearchAction(Widget, XEvent*, String*, Cardinal*);
213
214 /*
215 * These are defined in Text.c
216 */
217 void _XawTextAlterSelection(TextWidget, XawTextSelectionMode,
218 XawTextSelectionAction, String*, Cardinal*);
219 void _XawTextClearAndCenterDisplay(TextWidget);
220 void _XawTextExecuteUpdate(TextWidget);
221 char *_XawTextGetText(TextWidget, XawTextPosition, XawTextPosition);
222 void _XawTextPrepareToUpdate(TextWidget);
223 int _XawTextReplace(TextWidget, XawTextPosition, XawTextPosition,
224 XawTextBlock*);
225 Atom *_XawTextSelectionList(TextWidget, String*, Cardinal);
226 void _XawTextSetSelection(TextWidget, XawTextPosition, XawTextPosition,
227 String*, Cardinal);
228 void _XawTextVScroll(TextWidget, int);
229 void XawTextScroll(TextWidget, int, int);
230 void _XawTextSetLineAndColumnNumber(TextWidget, Bool);
231
232 #ifndef OLDXAW
233 /*
234 * Defined in TextSrc.c
235 */
236 Bool _XawTextSrcUndo(TextSrcObject, XawTextPosition*);
237 Bool _XawTextSrcToggleUndo(TextSrcObject);
238 void _XawSourceSetUndoErase(TextSrcObject, int);
239 void _XawSourceSetUndoMerge(TextSrcObject, Bool);
240 #endif /* OLDXAW */
241
242 /*
243 * Initialization
244 */
245 #ifndef OLDXAW
246 #define MAX_KILL_RINGS 1024
247 XawTextKillRing *xaw_text_kill_ring;
248 static XawTextKillRing kill_ring_prev, kill_ring_null = { &kill_ring_prev, NULL, 0, 0, 0 };
249 static unsigned num_kill_rings;
250 #endif
251
252 /*
253 * Implementation
254 */
255 static void
ParameterError(Widget w,String param)256 ParameterError(Widget w, String param)
257 {
258 String params[2];
259 Cardinal num_params = 2;
260 params[0] = XtName(w);
261 params[1] = param;
262
263 XtAppWarningMsg(XtWidgetToApplicationContext(w),
264 "parameterError", "textAction", "XawError",
265 "Widget: %s Parameter: %s",
266 params, &num_params);
267 XBell(XtDisplay(w), 50);
268 }
269
270 static void
StartAction(TextWidget ctx,XEvent * event)271 StartAction(TextWidget ctx, XEvent *event)
272 {
273 #ifndef OLDXAW
274 Cardinal i;
275 TextSrcObject src = (TextSrcObject)ctx->text.source;
276
277 for (i = 0; i < src->textSrc.num_text; i++)
278 _XawTextPrepareToUpdate((TextWidget)src->textSrc.text[i]);
279 _XawSourceSetUndoMerge(src, False);
280 #else
281 _XawTextPrepareToUpdate(ctx);
282 #endif
283
284 if (event != NULL) {
285 switch (event->type) {
286 case ButtonPress:
287 case ButtonRelease:
288 ctx->text.time = event->xbutton.time;
289 break;
290 case KeyPress:
291 case KeyRelease:
292 ctx->text.time = event->xkey.time;
293 break;
294 case MotionNotify:
295 ctx->text.time = event->xmotion.time;
296 break;
297 case EnterNotify:
298 case LeaveNotify:
299 ctx->text.time = event->xcrossing.time;
300 }
301 }
302 }
303
304 static void
NotePosition(TextWidget ctx,XEvent * event)305 NotePosition(TextWidget ctx, XEvent *event)
306 {
307 switch (event->type) {
308 case ButtonPress:
309 case ButtonRelease:
310 ctx->text.ev_x = (Position)event->xbutton.x;
311 ctx->text.ev_y = (Position)event->xbutton.y;
312 break;
313 case KeyPress:
314 case KeyRelease: {
315 XRectangle cursor;
316 XawTextSinkGetCursorBounds(ctx->text.sink, &cursor);
317 ctx->text.ev_x = (Position)(cursor.x + cursor.width / 2);
318 ctx->text.ev_y = (Position)(cursor.y + cursor.height / 2);
319 } break;
320 case MotionNotify:
321 ctx->text.ev_x = (Position)(event->xmotion.x);
322 ctx->text.ev_y = (Position)(event->xmotion.y);
323 break;
324 case EnterNotify:
325 case LeaveNotify:
326 ctx->text.ev_x = (Position)(event->xcrossing.x);
327 ctx->text.ev_y = (Position)(event->xcrossing.y);
328 }
329 }
330
331 static void
EndAction(TextWidget ctx)332 EndAction(TextWidget ctx)
333 {
334 #ifndef OLDXAW
335 Cardinal i;
336 TextSrcObject src = (TextSrcObject)ctx->text.source;
337
338 for (i = 0; i < src->textSrc.num_text; i++)
339 _XawTextExecuteUpdate((TextWidget)src->textSrc.text[i]);
340
341 ctx->text.mult = 1;
342 ctx->text.numeric = False;
343 if (ctx->text.kill_ring) {
344 if (--ctx->text.kill_ring == KILL_RING_YANK_DONE) {
345 if (ctx->text.kill_ring_ptr) {
346 --ctx->text.kill_ring_ptr->refcount;
347 ctx->text.kill_ring_ptr = NULL;
348 }
349 }
350 }
351 #else
352 ctx->text.mult = 1;
353 _XawTextExecuteUpdate(ctx);
354 #endif /* OLDXAW */
355 }
356
357 struct _SelectionList {
358 String* params;
359 Cardinal count;
360 Time time;
361 int asked; /* which selection currently has been asked for:
362 0 = UTF8_STRING, 1 = COMPOUND_TEXT, 2 = STRING */
363 Atom selection; /* selection atom (normally XA_PRIMARY) */
364 };
365
366 /*ARGSUSED*/
367 static void
_SelectionReceived(Widget w,XtPointer client_data,Atom * selection _X_UNUSED,Atom * type,XtPointer value,unsigned long * length,int * format _X_UNUSED)368 _SelectionReceived(Widget w, XtPointer client_data, Atom *selection _X_UNUSED,
369 Atom *type, XtPointer value, unsigned long *length,
370 int *format _X_UNUSED)
371 {
372 Display *d = XtDisplay(w);
373 TextWidget ctx = (TextWidget)w;
374 XawTextBlock text;
375
376 if (*type == 0 /*XT_CONVERT_FAIL*/ || *length == 0) {
377 struct _SelectionList* list = (struct _SelectionList*)client_data;
378
379 if (list != NULL) {
380 if (list->asked == 0) {
381 /* If we just asked for XA_UTF8_STRING and got no response,
382 we'll ask again, this time for XA_COMPOUND_TEXT. */
383 list->asked++;
384 XtGetSelectionValue(w, list->selection, XA_COMPOUND_TEXT(d),
385 _SelectionReceived,
386 (XtPointer)list, list->time);
387 } else if (list->asked == 1) {
388 /* If we just asked for XA_COMPOUND_TEXT and got no response,
389 we'll ask again, this time for XA_STRING. */
390 list->asked++;
391 XtGetSelectionValue(w, list->selection, XA_STRING,
392 _SelectionReceived,
393 (XtPointer)list, list->time);
394 } else {
395 /* We tried all possible text targets in this param.
396 Recurse on the tail of the params list. */
397 GetSelection(w, list->time, list->params, list->count);
398 XtFree(client_data);
399 }
400 }
401 return;
402 }
403
404 StartAction(ctx, NULL);
405 if (XawTextFormat(ctx, XawFmtWide)) {
406 XTextProperty textprop;
407 wchar_t **wlist;
408 int count;
409
410 textprop.encoding = *type;
411 textprop.value = (unsigned char *)value;
412 textprop.nitems = strlen(value);
413 textprop.format = 8;
414
415 if (XwcTextPropertyToTextList(d, &textprop, &wlist, &count)
416 != Success
417 || count < 1) {
418 XwcFreeStringList(wlist);
419
420 /* Notify the user on strerr and in the insertion :) */
421 fprintf(stderr, "Xaw Text Widget: An attempt was made to insert "
422 "an illegal selection.\n");
423
424 textprop.value = (const unsigned char *)" >> ILLEGAL SELECTION << ";
425 textprop.nitems = strlen((char *) textprop.value);
426 if (XwcTextPropertyToTextList(d, &textprop, &wlist, &count)
427 != Success
428 || count < 1)
429 return;
430 }
431
432 XFree(value);
433 value = (XPointer)wlist[0];
434
435 *length = wcslen(wlist[0]);
436 XtFree((XtPointer)wlist);
437 text.format = XawFmtWide;
438 }
439 text.ptr = (char*)value;
440 text.firstPos = 0;
441 text.length = (int)*length;
442 if (_XawTextReplace(ctx, ctx->text.insertPos, ctx->text.insertPos, &text)) {
443 XBell(XtDisplay(ctx), 0);
444 EndAction(ctx);
445 return;
446 }
447
448 ctx->text.from_left = -1;
449 ctx->text.insertPos = SrcScan(ctx->text.source, ctx->text.old_insert,
450 XawstPositions, XawsdRight, text.length, True);
451
452 EndAction(ctx);
453 XtFree(client_data);
454 XFree(value); /* the selection value should be freed with XFree */
455 }
456
457 static void
GetSelection(Widget w,Time timev,String * params,Cardinal num_params)458 GetSelection(Widget w, Time timev, String *params, Cardinal num_params)
459 {
460 Display *d = XtDisplay(w);
461 TextWidget ctx = (TextWidget)w;
462 Atom selection;
463 int buffer;
464
465 selection = XInternAtom(XtDisplay(w), *params, False);
466 switch (selection) {
467 case XA_CUT_BUFFER0: buffer = 0; break;
468 case XA_CUT_BUFFER1: buffer = 1; break;
469 case XA_CUT_BUFFER2: buffer = 2; break;
470 case XA_CUT_BUFFER3: buffer = 3; break;
471 case XA_CUT_BUFFER4: buffer = 4; break;
472 case XA_CUT_BUFFER5: buffer = 5; break;
473 case XA_CUT_BUFFER6: buffer = 6; break;
474 case XA_CUT_BUFFER7: buffer = 7; break;
475 default: buffer = -1;
476 }
477 if (buffer >= 0) {
478 int nbytes;
479 unsigned long length;
480 int fmt8 = 8;
481 Atom type = XA_STRING;
482 char *line = XFetchBuffer(XtDisplay(w), &nbytes, buffer);
483
484 if ((length = (unsigned long)nbytes) != 0L)
485 _SelectionReceived(w, NULL, &selection, &type, line, &length, &fmt8);
486 else if (num_params > 1)
487 GetSelection(w, timev, params+1, num_params-1);
488 }
489 else {
490 struct _SelectionList* list;
491
492 if (--num_params) {
493 list = XtNew(struct _SelectionList);
494 list->params = params + 1;
495 list->count = num_params;
496 list->time = timev;
497 list->asked = 0;
498 list->selection = selection;
499 }
500 else
501 list = NULL;
502 XtGetSelectionValue(w, selection, XawTextFormat(ctx, XawFmtWide) ?
503 XA_UTF8_STRING(d) : XA_TEXT(d),
504 _SelectionReceived, (XtPointer)list, timev);
505 }
506 }
507
508 static void
InsertSelection(Widget w,XEvent * event,String * params,Cardinal * num_params)509 InsertSelection(Widget w, XEvent *event, String *params, Cardinal *num_params)
510 {
511 StartAction((TextWidget)w, event); /* Get Time. */
512 GetSelection(w, ((TextWidget)w)->text.time, params, *num_params);
513 EndAction((TextWidget)w);
514 }
515
516 /*
517 * Routines for Moving Around
518 */
519 static void
Move(TextWidget ctx,XEvent * event,XawTextScanDirection dir,XawTextScanType type,Bool include)520 Move(TextWidget ctx, XEvent *event, XawTextScanDirection dir,
521 XawTextScanType type, Bool include)
522 {
523 XawTextPosition insertPos;
524 short mult = MULT(ctx);
525
526 if (mult < 0) {
527 mult = (short)(-mult);
528 dir = dir == XawsdLeft ? XawsdRight : XawsdLeft;
529 }
530
531 insertPos = SrcScan(ctx->text.source, ctx->text.insertPos,
532 type, dir, mult, (Boolean)include);
533
534 StartAction(ctx, event);
535
536 if (ctx->text.s.left != ctx->text.s.right)
537 XawTextUnsetSelection((Widget)ctx);
538
539 #ifndef OLDXAW
540 ctx->text.numeric = False;
541 #endif
542 ctx->text.mult = 1;
543 ctx->text.showposition = True;
544 ctx->text.from_left = -1;
545 ctx->text.insertPos = insertPos;
546 EndAction(ctx);
547 }
548
549 /*ARGSUSED*/
550 static void
MoveForwardChar(Widget w,XEvent * event,String * p _X_UNUSED,Cardinal * n _X_UNUSED)551 MoveForwardChar(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
552 {
553 Move((TextWidget)w, event, XawsdRight, XawstPositions, True);
554 }
555
556 /*ARGSUSED*/
557 static void
MoveBackwardChar(Widget w,XEvent * event,String * p _X_UNUSED,Cardinal * n _X_UNUSED)558 MoveBackwardChar(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
559 {
560 Move((TextWidget)w, event, XawsdLeft, XawstPositions, True);
561 }
562
563 static void
MoveForwardWord(Widget w,XEvent * event,String * p,Cardinal * n)564 MoveForwardWord(Widget w, XEvent *event, String *p, Cardinal *n)
565 {
566 if (*n && (p[0][0] == 'A' || p[0][0] == 'a'))
567 Move((TextWidget)w, event, XawsdRight, XawstAlphaNumeric, False);
568 else
569 Move((TextWidget)w, event, XawsdRight, XawstWhiteSpace, False);
570 }
571
572 static void
MoveBackwardWord(Widget w,XEvent * event,String * p,Cardinal * n)573 MoveBackwardWord(Widget w, XEvent *event, String *p, Cardinal *n)
574 {
575 if (*n && (p[0][0] == 'A' || p[0][0] == 'a'))
576 Move((TextWidget)w, event, XawsdLeft, XawstAlphaNumeric, False);
577 else
578 Move((TextWidget)w, event, XawsdLeft, XawstWhiteSpace, False);
579 }
580
581 static void
MoveForwardParagraph(Widget w,XEvent * event,String * p,Cardinal * n)582 MoveForwardParagraph(Widget w, XEvent *event, String *p, Cardinal *n)
583 {
584 TextWidget ctx = (TextWidget)w;
585 XawTextPosition position = ctx->text.insertPos;
586 short mult = MULT(ctx);
587
588 if (mult < 0) {
589 ctx->text.mult = (short)(-mult);
590 MoveBackwardParagraph(w, event, p, n);
591 return;
592 }
593
594 while (mult--) {
595 position = SrcScan(ctx->text.source, position,
596 XawstEOL, XawsdRight, 1, False) - 1;
597
598 while (position == SrcScan(ctx->text.source, position,
599 XawstEOL, XawsdRight, 1, False))
600 if (++position > ctx->text.lastPos) {
601 mult = 0;
602 break;
603 }
604
605 position = SrcScan(ctx->text.source, position,
606 XawstParagraph, XawsdRight, 1, True);
607 if (position != ctx->text.lastPos)
608 position = SrcScan(ctx->text.source, position - 1,
609 XawstEOL, XawsdLeft, 1, False);
610 else
611 break;
612 }
613
614 if (position != ctx->text.insertPos) {
615 XawTextUnsetSelection(w);
616 StartAction(ctx, event);
617 ctx->text.showposition = True;
618 ctx->text.from_left = -1;
619 ctx->text.insertPos = position;
620 EndAction(ctx);
621 }
622 else
623 ctx->text.mult = 1;
624 }
625
626 /*ARGSUSED*/
627 static void
MoveBackwardParagraph(Widget w,XEvent * event,String * p,Cardinal * n)628 MoveBackwardParagraph(Widget w, XEvent *event, String *p, Cardinal *n)
629 {
630 TextWidget ctx = (TextWidget)w;
631 XawTextPosition position = ctx->text.insertPos;
632 short mult = MULT(ctx);
633
634 if (mult < 0) {
635 ctx->text.mult = (short)(-mult);
636 MoveForwardParagraph(w, event, p, n);
637 return;
638 }
639
640 while (mult--) {
641 position = SrcScan(ctx->text.source, position,
642 XawstEOL, XawsdLeft, 1, False) + 1;
643
644 while (position == SrcScan(ctx->text.source, position,
645 XawstEOL, XawsdLeft, 1, False))
646 if (--position < 0) {
647 mult = 0;
648 break;
649 }
650
651 position = SrcScan(ctx->text.source, position,
652 XawstParagraph, XawsdLeft, 1, True);
653 if (position > 0 && position < ctx->text.lastPos)
654 ++position;
655 else
656 break;
657 }
658
659 if (position != ctx->text.insertPos) {
660 XawTextUnsetSelection(w);
661 StartAction(ctx, event);
662 ctx->text.showposition = True;
663 ctx->text.from_left = -1;
664 ctx->text.insertPos = position;
665 EndAction(ctx);
666 }
667 else
668 ctx->text.mult = 1;
669 }
670
671 /*ARGSUSED*/
672 static void
MoveToLineEnd(Widget w,XEvent * event,String * p _X_UNUSED,Cardinal * n _X_UNUSED)673 MoveToLineEnd(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
674 {
675 Move((TextWidget)w, event, XawsdRight, XawstEOL, False);
676 }
677
678 /*ARGSUSED*/
679 static void
MoveToLineStart(Widget w,XEvent * event,String * p _X_UNUSED,Cardinal * n _X_UNUSED)680 MoveToLineStart(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
681 {
682 Move((TextWidget)w, event, XawsdLeft, XawstEOL, False);
683 }
684
685 static void
MoveLine(TextWidget ctx,XEvent * event,XawTextScanDirection dir)686 MoveLine(TextWidget ctx, XEvent *event, XawTextScanDirection dir)
687 {
688 XawTextPosition cnew, next_line, ltemp;
689 int itemp, from_left;
690 short mult = MULT(ctx);
691
692 StartAction(ctx, event);
693
694 XawTextUnsetSelection((Widget)ctx);
695
696 if (dir == XawsdLeft)
697 mult = (short)((mult == 0) ? 5 : mult + 1);
698
699 cnew = SrcScan(ctx->text.source, ctx->text.insertPos,
700 XawstEOL, XawsdLeft, 1, False);
701
702 if (ctx->text.from_left < 0)
703 FindDist(ctx->text.sink, cnew, ctx->text.left_margin, ctx->text.insertPos,
704 &ctx->text.from_left, <emp, &itemp);
705
706 cnew = SrcScan(ctx->text.source, ctx->text.insertPos, XawstEOL, dir,
707 mult, (dir == XawsdRight));
708
709 next_line = SrcScan(ctx->text.source, cnew, XawstEOL, XawsdRight, 1, False);
710
711 FindPos(ctx->text.sink, cnew, ctx->text.left_margin, ctx->text.from_left,
712 False, &ctx->text.insertPos, &from_left, &itemp);
713
714 if (from_left < ctx->text.from_left) {
715 XawTextBlock block;
716
717 XawTextSourceRead(ctx->text.source, ctx->text.insertPos, &block, 1);
718 if (block.length) {
719 if (XawTextFormat(ctx, XawFmtWide)) {
720 if (*(wchar_t *)block.ptr == _Xaw_atowc(XawTAB))
721 ++ctx->text.insertPos;
722 }
723 else if (block.ptr[0] == XawTAB)
724 ++ctx->text.insertPos;
725 }
726 }
727
728 if (ctx->text.insertPos > next_line)
729 ctx->text.insertPos = next_line;
730
731 EndAction(ctx);
732 }
733
734 static void
MoveNextLine(Widget w,XEvent * event,String * p,Cardinal * n)735 MoveNextLine(Widget w, XEvent *event, String *p, Cardinal *n)
736 {
737 TextWidget ctx = (TextWidget)w;
738 short mult = MULT(ctx);
739
740 if (mult < 0) {
741 ctx->text.mult = (short)(-mult);
742 MovePreviousLine(w, event, p, n);
743 return;
744 }
745
746 if (ctx->text.insertPos < ctx->text.lastPos)
747 MoveLine(ctx, event, XawsdRight);
748 else
749 ctx->text.mult = 1;
750 }
751
752 static void
MovePreviousLine(Widget w,XEvent * event,String * p,Cardinal * n)753 MovePreviousLine(Widget w, XEvent *event, String *p, Cardinal *n)
754 {
755 TextWidget ctx = (TextWidget)w;
756 short mult = MULT(ctx);
757
758 if (mult < 0) {
759 ctx->text.mult = (short)(-mult);
760 MoveNextLine(w, event, p, n);
761 return;
762 }
763
764 if (ctx->text.lt.top != 0 || (ctx->text.lt.lines > 1 &&
765 ctx->text.insertPos >= ctx->text.lt.info[1].position))
766 MoveLine(ctx, event, XawsdLeft);
767 else
768 ctx->text.mult = 1;
769 }
770
771 /*ARGSUSED*/
772 static void
MoveBeginningOfFile(Widget w,XEvent * event,String * p _X_UNUSED,Cardinal * n _X_UNUSED)773 MoveBeginningOfFile(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
774 {
775 Move((TextWidget)w, event, XawsdLeft, XawstAll, True);
776 }
777
778 /*ARGSUSED*/
779 static void
MoveEndOfFile(Widget w,XEvent * event,String * p _X_UNUSED,Cardinal * n _X_UNUSED)780 MoveEndOfFile(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
781 {
782 Move((TextWidget)w, event, XawsdRight, XawstAll, True);
783 }
784
785 static void
Scroll(TextWidget ctx,XEvent * event,XawTextScanDirection dir)786 Scroll(TextWidget ctx, XEvent *event, XawTextScanDirection dir)
787 {
788 short mult = MULT(ctx);
789
790 if (mult < 0) {
791 mult = (short)(-mult);
792 dir = dir == XawsdLeft ? XawsdRight : XawsdLeft;
793 }
794
795 if (ctx->text.lt.lines > 1
796 && (dir == XawsdRight
797 || ctx->text.lastPos >= ctx->text.lt.info[1].position)) {
798 StartAction(ctx, event);
799
800 if (dir == XawsdLeft)
801 _XawTextVScroll(ctx, mult);
802 else
803 _XawTextVScroll(ctx, -mult);
804
805 EndAction(ctx);
806 }
807 else {
808 ctx->text.mult = 1;
809 #ifndef OLDXAW
810 ctx->text.numeric = False;
811 #endif
812 }
813 }
814
815 /*ARGSUSED*/
816 static void
ScrollOneLineUp(Widget w,XEvent * event,String * p _X_UNUSED,Cardinal * n _X_UNUSED)817 ScrollOneLineUp(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
818 {
819 Scroll((TextWidget)w, event, XawsdLeft);
820 }
821
822 /*ARGSUSED*/
823 static void
ScrollOneLineDown(Widget w,XEvent * event,String * p _X_UNUSED,Cardinal * n _X_UNUSED)824 ScrollOneLineDown(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
825 {
826 Scroll((TextWidget)w, event, XawsdRight);
827 }
828
829 static void
MovePage(TextWidget ctx,XEvent * event _X_UNUSED,XawTextScanDirection dir)830 MovePage(TextWidget ctx, XEvent *event _X_UNUSED, XawTextScanDirection dir)
831 {
832 int scroll_val = 0;
833 XawTextPosition old_pos;
834
835 ctx->text.from_left = -1;
836 switch (dir) {
837 case XawsdLeft:
838 if (ctx->text.lt.top != 0)
839 scroll_val = -Max(1, ctx->text.lt.lines - 1);
840 break;
841 case XawsdRight:
842 if (!IsPositionVisible(ctx, Max(0, ctx->text.lastPos)))
843 scroll_val = Max(1, ctx->text.lt.lines - 1);
844 break;
845 }
846
847 if (scroll_val)
848 XawTextScroll(ctx, scroll_val,
849 ctx->text.left_margin - ctx->text.r_margin.left);
850
851 old_pos = ctx->text.insertPos;
852 switch (dir) {
853 case XawsdRight:
854 if (IsPositionVisible(ctx, Max(0, ctx->text.lastPos)))
855 ctx->text.insertPos = Max(0, ctx->text.lastPos);
856 else
857 ctx->text.insertPos = ctx->text.lt.top;
858 if (ctx->text.insertPos < old_pos)
859 ctx->text.insertPos = SrcScan(ctx->text.source, old_pos,
860 XawstEOL, XawsdLeft, 1, False);
861 break;
862 case XawsdLeft:
863 if (IsPositionVisible(ctx, 0))
864 ctx->text.insertPos = 0;
865 else if (ctx->text.lt.lines)
866 ctx->text.insertPos =
867 ctx->text.lt.info[ctx->text.lt.lines - 1].position;
868 else
869 ctx->text.insertPos = ctx->text.lt.top;
870 if (ctx->text.insertPos > old_pos)
871 ctx->text.insertPos = SrcScan(ctx->text.source, old_pos,
872 XawstEOL, XawsdLeft, 1, False);
873 break;
874 }
875 }
876
877 static void
MoveNextPage(Widget w,XEvent * event,String * p,Cardinal * n)878 MoveNextPage(Widget w, XEvent *event, String *p, Cardinal *n)
879 {
880 TextWidget ctx = (TextWidget)w;
881 short mult = MULT(ctx);
882
883 if (mult < 0) {
884 ctx->text.mult = (short)(-mult);
885 MovePreviousPage(w, event, p, n);
886 return;
887 }
888
889 if (ctx->text.insertPos < ctx->text.lastPos) {
890 XawTextUnsetSelection(w);
891 StartAction(ctx, event);
892 ctx->text.clear_to_eol = True;
893 while (mult-- && ctx->text.insertPos < ctx->text.lastPos)
894 MovePage(ctx, event, XawsdRight);
895 EndAction(ctx);
896 }
897 else
898 ctx->text.mult = 1;
899 }
900
901 /*ARGSUSED*/
902 static void
MovePreviousPage(Widget w,XEvent * event,String * p,Cardinal * n)903 MovePreviousPage(Widget w, XEvent *event, String *p, Cardinal *n)
904 {
905 TextWidget ctx = (TextWidget)w;
906 short mult = MULT(ctx);
907
908 if (mult < 0) {
909 ctx->text.mult = (short)(-mult);
910 MoveNextPage(w, event, p, n);
911 return;
912 }
913
914 if (ctx->text.insertPos > 0) {
915 XawTextUnsetSelection(w);
916 StartAction(ctx, event);
917 ctx->text.clear_to_eol = True;
918 while (mult-- && ctx->text.insertPos > 0)
919 MovePage(ctx, event, XawsdLeft);
920 EndAction(ctx);
921 }
922 else
923 ctx->text.mult = 1;
924 }
925
926 /*
927 * Delete Routines
928 */
929 static Bool
MatchSelection(Atom selection,XawTextSelection * s)930 MatchSelection(Atom selection, XawTextSelection *s)
931 {
932 Atom *match;
933 int count;
934
935 for (count = 0, match = s->selections; count < s->atom_count;
936 match++, count++)
937 if (*match == selection)
938 return (True);
939
940 return (False);
941 }
942
943 #define SrcCvtSel XawTextSourceConvertSelection
944
945 static Boolean
ConvertSelection(Widget w,Atom * selection,Atom * target,Atom * type,XtPointer * value,unsigned long * length,int * format)946 ConvertSelection(Widget w, Atom *selection, Atom *target, Atom *type,
947 XtPointer *value, unsigned long *length, int *format)
948 {
949 Display *d = XtDisplay(w);
950 TextWidget ctx = (TextWidget)w;
951 Widget src = ctx->text.source;
952 XawTextEditType edit_mode;
953 Arg args[1];
954 XawTextSelectionSalt *salt = NULL;
955 XawTextSelection *s;
956
957 if (*target == XA_TARGETS(d)) {
958 Atom *targetP, *std_targets;
959 unsigned long std_length;
960
961 if (SrcCvtSel(src, selection, target, type, value, length, format))
962 return (True);
963
964 XtSetArg(args[0], XtNeditType,&edit_mode);
965 XtGetValues(src, args, 1);
966
967 XmuConvertStandardSelection(w, ctx->text.time, selection,
968 target, type, (XPointer *)&std_targets,
969 &std_length, format);
970
971 *length = (7 + (unsigned long)(edit_mode == XawtextEdit) + std_length);
972 *value = XtMalloc((Cardinal)((unsigned)sizeof(Atom)*(*length)));
973 targetP = *(Atom**)value;
974 *targetP++ = XA_STRING;
975 *targetP++ = XA_TEXT(d);
976 *targetP++ = XA_UTF8_STRING(d);
977 *targetP++ = XA_COMPOUND_TEXT(d);
978 *targetP++ = XA_LENGTH(d);
979 *targetP++ = XA_LIST_LENGTH(d);
980 *targetP++ = XA_CHARACTER_POSITION(d);
981 if (edit_mode == XawtextEdit) {
982 *targetP++ = XA_DELETE(d);
983 }
984 memcpy((char*)targetP, (char*)std_targets, sizeof(Atom)*std_length);
985 XtFree((char*)std_targets);
986 *type = XA_ATOM;
987 *format = 32;
988 return (True);
989 }
990
991 if (SrcCvtSel(src, selection, target, type, value, length, format))
992 return (True);
993
994 for (salt = ctx->text.salt2; salt; salt = salt->next)
995 if (MatchSelection (*selection, &salt->s))
996 break;
997 if (!salt)
998 return (False);
999 s = &salt->s;
1000 if (*target == XA_STRING
1001 || *target == XA_TEXT(d)
1002 || *target == XA_UTF8_STRING(d)
1003 || *target == XA_COMPOUND_TEXT(d)) {
1004 if (*target == XA_TEXT(d)) {
1005 if (XawTextFormat(ctx, XawFmtWide))
1006 *type = XA_COMPOUND_TEXT(d);
1007 else
1008 *type = XA_STRING;
1009 }
1010 else
1011 *type = *target;
1012
1013 /*
1014 * If salt is True, the salt->contents stores CT string,
1015 * its length is measured in bytes.
1016 * Refer to _XawTextSaltAwaySelection()
1017 *
1018 * by Li Yuhong, Mar. 20, 1991.
1019 */
1020 if (!salt) {
1021 *value = (char *)_XawTextGetSTRING(ctx, s->left, s->right);
1022 if (XawTextFormat(ctx, XawFmtWide)) {
1023 XTextProperty textprop;
1024 if (XwcTextListToTextProperty(d, (wchar_t**)value, 1,
1025 XCompoundTextStyle, &textprop)
1026 < Success) {
1027 XtFree(*value);
1028 return (False);
1029 }
1030 XtFree(*value);
1031 *value = (XtPointer)textprop.value;
1032 *length = textprop.nitems;
1033 }
1034 else
1035 *length = strlen(*value);
1036 }
1037 else {
1038 *value = XtMalloc(((size_t)(salt->length + 1) * sizeof(unsigned char)));
1039 strcpy (*value, salt->contents);
1040 *length = (unsigned long)salt->length;
1041 }
1042 /* Got *value,*length, now in COMPOUND_TEXT format. */
1043 if (XawTextFormat(ctx, XawFmtWide)) {
1044 if (*type == XA_STRING) {
1045 XTextProperty textprop;
1046 wchar_t **wlist;
1047 int count;
1048
1049 textprop.encoding = XA_COMPOUND_TEXT(d);
1050 textprop.value = (unsigned char *)*value;
1051 textprop.nitems = strlen(*value);
1052 textprop.format = 8;
1053 if (XwcTextPropertyToTextList(d, &textprop, &wlist, &count)
1054 < Success
1055 || count < 1) {
1056 XtFree(*value);
1057 return (False);
1058 }
1059 XtFree(*value);
1060 if (XwcTextListToTextProperty(d, wlist, 1, XStringStyle, &textprop)
1061 < Success) {
1062 XwcFreeStringList((wchar_t**)wlist);
1063 return (False);
1064 }
1065 *value = (XtPointer)textprop.value;
1066 *length = textprop.nitems;
1067 XwcFreeStringList((wchar_t**) wlist);
1068 }
1069 else if (*type == XA_UTF8_STRING(d)) {
1070 XTextProperty textprop;
1071 char **list;
1072 int count;
1073
1074 textprop.encoding = XA_COMPOUND_TEXT(d);
1075 textprop.value = (unsigned char *)*value;
1076 textprop.nitems = strlen(*value);
1077 textprop.format = 8;
1078 if (Xutf8TextPropertyToTextList(d, &textprop, &list, &count)
1079 < Success
1080 || count < 1) {
1081 XtFree(*value);
1082 return (False);
1083 }
1084 XtFree(*value);
1085 *value = *list;
1086 *length = strlen(*list);
1087 XFree(list);
1088 }
1089 }
1090 *format = 8;
1091 return (True);
1092 }
1093
1094 if (*target == XA_LIST_LENGTH(d) || *target == XA_LENGTH(d)) {
1095 long *temp;
1096
1097 temp = (long *)XtMalloc(sizeof(long));
1098 if (*target == XA_LIST_LENGTH(d))
1099 *temp = 1L;
1100 else /* *target == XA_LENGTH(d) */
1101 *temp = (long)(s->right - s->left);
1102
1103 *value = (XPointer)temp;
1104 *type = XA_INTEGER;
1105 *length = 1L;
1106 *format = 32;
1107 return (True);
1108 }
1109
1110 if (*target == XA_CHARACTER_POSITION(d)) {
1111 long *temp;
1112
1113 temp = (long *) XtMalloc(2 * sizeof(long));
1114 temp[0] = (long)(s->left + 1);
1115 temp[1] = s->right;
1116 *value = (XPointer)temp;
1117 *type = XA_SPAN(d);
1118 *length = 2L;
1119 *format = 32;
1120 return (True);
1121 }
1122
1123 if (*target == XA_DELETE(d)) {
1124 if (!salt)
1125 _XawTextZapSelection(ctx, NULL, True);
1126 *value = NULL;
1127 *type = XA_NULL(d);
1128 *length = 0;
1129 *format = 32;
1130 return (True);
1131 }
1132
1133 if (XmuConvertStandardSelection(w, ctx->text.time, selection, target, type,
1134 (XPointer *)value, length, format))
1135 return (True);
1136
1137 return (False);
1138 }
1139
1140 static void
LoseSelection(Widget w,Atom * selection)1141 LoseSelection(Widget w, Atom *selection)
1142 {
1143 _LoseSelection(w, selection, NULL, NULL);
1144 }
1145
1146 static void
_LoseSelection(Widget w,Atom * selection,char ** contents _X_UNUSED,int * length _X_UNUSED)1147 _LoseSelection(Widget w, Atom *selection, char **contents _X_UNUSED, int *length _X_UNUSED)
1148 {
1149 TextWidget ctx = (TextWidget)w;
1150 Atom *atomP;
1151 int i;
1152 XawTextSelectionSalt *salt, *prevSalt, *nextSalt;
1153
1154 prevSalt = 0;
1155 for (salt = ctx->text.salt2; salt; salt = nextSalt) {
1156 atomP = salt->s.selections;
1157 nextSalt = salt->next;
1158 for (i = 0 ; i < salt->s.atom_count; i++, atomP++)
1159 if (*selection == *atomP)
1160 *atomP = (Atom)0;
1161
1162 while (salt->s.atom_count
1163 && salt->s.selections[salt->s.atom_count-1] == 0)
1164 salt->s.atom_count--;
1165
1166 /*
1167 * Must walk the selection list in opposite order from UnsetSelection.
1168 */
1169 atomP = salt->s.selections;
1170 for (i = 0 ; i < salt->s.atom_count; i++, atomP++)
1171 if (*atomP == (Atom)0) {
1172 *atomP = salt->s.selections[--salt->s.atom_count];
1173
1174 while (salt->s.atom_count
1175 && salt->s.selections[salt->s.atom_count-1] == 0)
1176 salt->s.atom_count--;
1177 }
1178 if (salt->s.atom_count == 0) {
1179 #ifndef OLDXAW
1180 if (contents == NULL) {
1181 XawTextKillRing *kill_ring = XtNew(XawTextKillRing);
1182
1183 kill_ring->next = xaw_text_kill_ring;
1184 kill_ring->contents = salt->contents;
1185 kill_ring->length = salt->length;
1186 kill_ring->format = XawFmt8Bit;
1187 xaw_text_kill_ring = kill_ring;
1188 kill_ring_prev.next = xaw_text_kill_ring;
1189
1190 if (++num_kill_rings > MAX_KILL_RINGS) {
1191 XawTextKillRing *tail = NULL;
1192
1193 while (kill_ring->next) {
1194 tail = kill_ring;
1195 kill_ring = kill_ring->next;
1196 }
1197 if (kill_ring->refcount == 0) {
1198 --num_kill_rings;
1199 tail->next = NULL;
1200 XtFree(kill_ring->contents);
1201 XtFree((char*)kill_ring);
1202 }
1203 }
1204 }
1205 else {
1206 *contents = salt->contents;
1207 *length = salt->length;
1208 }
1209 #endif
1210 if (prevSalt)
1211 prevSalt->next = nextSalt;
1212 else
1213 ctx->text.salt2 = nextSalt;
1214
1215 XtFree((char *)salt->s.selections);
1216 XtFree((char *)salt);
1217 }
1218 else
1219 prevSalt = salt;
1220 }
1221 }
1222
1223 static void
_DeleteOrKill(TextWidget ctx,XawTextPosition from,XawTextPosition to,Bool kill)1224 _DeleteOrKill(TextWidget ctx, XawTextPosition from, XawTextPosition to,
1225 Bool kill)
1226 {
1227 XawTextBlock text;
1228
1229 #ifndef OLDXAW
1230 if (ctx->text.kill_ring_ptr) {
1231 --ctx->text.kill_ring_ptr->refcount;
1232 ctx->text.kill_ring_ptr = NULL;
1233 }
1234 #endif
1235 if (kill && from < to) {
1236 #ifndef OLDXAW
1237 Bool append = False;
1238 char *ring = NULL;
1239 XawTextPosition old_from = from;
1240 #endif
1241 char *string;
1242 int size = 0, length;
1243 XawTextSelectionSalt *salt;
1244 Atom selection = XInternAtom(XtDisplay(ctx), "SECONDARY", False);
1245
1246 #ifndef OLDXAW
1247 if (ctx->text.kill_ring == KILL_RING_APPEND) {
1248 old_from = ctx->text.salt2->s.left;
1249 append = True;
1250 }
1251 else
1252 ctx->text.kill_ring = KILL_RING_BEGIN;
1253
1254 if (append)
1255 _LoseSelection((Widget)ctx, &selection, &ring, &size);
1256 else
1257 #endif
1258 LoseSelection((Widget)ctx, &selection);
1259
1260 salt = (XawTextSelectionSalt*)XtMalloc(sizeof(XawTextSelectionSalt));
1261 salt->s.selections = (Atom *)XtMalloc(sizeof(Atom));
1262 salt->s.left = from;
1263 salt->s.right = to;
1264
1265 string = (char *)_XawTextGetSTRING(ctx, from, to);
1266
1267 if (XawTextFormat(ctx, XawFmtWide)) {
1268 XTextProperty textprop;
1269
1270 if (XwcTextListToTextProperty(XtDisplay((Widget)ctx),
1271 (wchar_t**)(&string),
1272 1, XCompoundTextStyle,
1273 &textprop) < Success) {
1274 XtFree(string);
1275 XtFree((char*)salt->s.selections);
1276 XtFree((char*)salt);
1277 return;
1278 }
1279 XtFree(string);
1280 string = (char *)textprop.value;
1281 length = (int)textprop.nitems;
1282 }
1283 else
1284 length = (int)strlen(string);
1285
1286 salt->length = length + size;
1287
1288 #ifndef OLDXAW
1289 if (!append)
1290 salt->contents = string;
1291 else {
1292 salt->contents = XtMalloc((length + size + 1));
1293 if (from >= old_from) {
1294 strncpy(salt->contents, ring, (size_t)size);
1295 salt->contents[size] = '\0';
1296 strncat(salt->contents, string, (size_t)length);
1297 }
1298 else {
1299 strncpy(salt->contents, string, (size_t)length);
1300 salt->contents[length] = '\0';
1301 strncat(salt->contents, ring, (size_t)size);
1302 }
1303 salt->contents[length + size] = '\0';
1304 XtFree(ring);
1305 XtFree(string);
1306 }
1307
1308 kill_ring_prev.contents = salt->contents;
1309 kill_ring_prev.length = salt->length;
1310 kill_ring_prev.format = XawFmt8Bit;
1311 #else
1312 salt->contents = string;
1313 #endif
1314
1315 salt->next = ctx->text.salt2;
1316 ctx->text.salt2 = salt;
1317
1318 #ifndef OLDXAW
1319 if (append)
1320 ctx->text.kill_ring = KILL_RING_BEGIN;
1321 #endif
1322
1323 salt->s.selections[0] = selection;
1324
1325 XtOwnSelection((Widget)ctx, selection, ctx->text.time,
1326 ConvertSelection, LoseSelection, NULL);
1327 salt->s.atom_count = 1;
1328 }
1329 text.length = 0;
1330 text.firstPos = 0;
1331
1332 text.format = (unsigned long)_XawTextFormat(ctx);
1333 text.ptr = "";
1334
1335 if (_XawTextReplace(ctx, from, to, &text)) {
1336 XBell(XtDisplay(ctx), 50);
1337 return;
1338 }
1339 ctx->text.from_left = -1;
1340 ctx->text.insertPos = from;
1341 ctx->text.showposition = TRUE;
1342 }
1343
1344 static void
DeleteOrKill(TextWidget ctx,XEvent * event,XawTextScanDirection dir,XawTextScanType type,Bool include,Bool kill)1345 DeleteOrKill(TextWidget ctx, XEvent *event, XawTextScanDirection dir,
1346 XawTextScanType type, Bool include, Bool kill)
1347 {
1348 XawTextPosition from, to;
1349 short mult = MULT(ctx);
1350
1351 if (mult < 0) {
1352 mult = (short)(-mult);
1353 dir = dir == XawsdLeft ? XawsdRight : XawsdLeft;
1354 }
1355
1356 StartAction(ctx, event);
1357 #ifndef OLDXAW
1358 if (mult == 1)
1359 _XawSourceSetUndoMerge((TextSrcObject)ctx->text.source, True);
1360 #endif
1361 to = SrcScan(ctx->text.source, ctx->text.insertPos,
1362 type, dir, mult, (Boolean)include);
1363
1364 /*
1365 * If no movement actually happened, then bump the count and try again.
1366 * This causes the character position at the very beginning and end of
1367 * a boundary to act correctly
1368 */
1369 if (to == ctx->text.insertPos)
1370 to = SrcScan(ctx->text.source, ctx->text.insertPos,
1371 type, dir, mult + 1, (Boolean)include);
1372
1373 if (dir == XawsdLeft) {
1374 from = to;
1375 to = ctx->text.insertPos;
1376 }
1377 else
1378 from = ctx->text.insertPos;
1379
1380 _DeleteOrKill(ctx, from, to, kill);
1381 EndAction(ctx);
1382 }
1383
1384 static void
Delete(Widget w,XEvent * event,String * p,Cardinal * n)1385 Delete(Widget w, XEvent *event, String *p, Cardinal *n)
1386 {
1387 TextWidget ctx = (TextWidget)w;
1388
1389 if (ctx->text.s.left != ctx->text.s.right)
1390 DeleteCurrentSelection(w, event, p, n);
1391 else
1392 DeleteBackwardChar(w, event, p, n);
1393 }
1394
1395 static void
DeleteChar(Widget w,XEvent * event,XawTextScanDirection dir)1396 DeleteChar(Widget w, XEvent *event, XawTextScanDirection dir)
1397 {
1398 TextWidget ctx = (TextWidget)w;
1399 short mul = MULT(ctx);
1400
1401 if (mul < 0) {
1402 ctx->text.mult = mul = (short)(-mul);
1403 dir = dir == XawsdLeft ? XawsdRight : XawsdLeft;
1404 }
1405 DeleteOrKill(ctx, event, dir, XawstPositions, True, False);
1406 #ifndef OLDXAW
1407 if (mul == 1)
1408 _XawSourceSetUndoErase((TextSrcObject)ctx->text.source,
1409 dir == XawsdLeft ? -1 : 1);
1410 #endif
1411 }
1412
1413 /*ARGSUSED*/
1414 static void
DeleteForwardChar(Widget w,XEvent * event,String * p _X_UNUSED,Cardinal * n _X_UNUSED)1415 DeleteForwardChar(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
1416 {
1417 DeleteChar(w, event, XawsdRight);
1418 }
1419
1420 /*ARGSUSED*/
1421 static void
DeleteBackwardChar(Widget w,XEvent * event,String * p _X_UNUSED,Cardinal * n _X_UNUSED)1422 DeleteBackwardChar(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
1423 {
1424 DeleteChar(w, event, XawsdLeft);
1425 }
1426
1427 static void
DeleteForwardWord(Widget w,XEvent * event,String * params,Cardinal * num_params)1428 DeleteForwardWord(Widget w, XEvent *event, String *params, Cardinal *num_params)
1429 {
1430 XawTextScanType type;
1431
1432 if (*num_params && (*params[0] == 'A' || *params[0] == 'a'))
1433 type = XawstAlphaNumeric;
1434 else
1435 type = XawstWhiteSpace;
1436
1437 DeleteOrKill((TextWidget)w, event, XawsdRight, type, False, False);
1438 }
1439
1440 static void
DeleteBackwardWord(Widget w,XEvent * event,String * params,Cardinal * num_params)1441 DeleteBackwardWord(Widget w, XEvent *event, String *params, Cardinal *num_params)
1442 {
1443 XawTextScanType type;
1444
1445 if (*num_params && (*params[0] == 'A' || *params[0] == 'a'))
1446 type = XawstAlphaNumeric;
1447 else
1448 type = XawstWhiteSpace;
1449
1450 DeleteOrKill((TextWidget)w, event, XawsdLeft, type, False, False);
1451 }
1452
1453 static void
KillForwardWord(Widget w,XEvent * event,String * params,Cardinal * num_params)1454 KillForwardWord(Widget w, XEvent *event, String *params, Cardinal *num_params)
1455 {
1456 XawTextScanType type;
1457
1458 if (*num_params && (*params[0] == 'A' || *params[0] == 'a'))
1459 type = XawstAlphaNumeric;
1460 else
1461 type = XawstWhiteSpace;
1462
1463 DeleteOrKill((TextWidget)w, event, XawsdRight, type, False, True);
1464 }
1465
1466 static void
KillBackwardWord(Widget w,XEvent * event,String * params,Cardinal * num_params)1467 KillBackwardWord(Widget w, XEvent *event, String *params, Cardinal *num_params)
1468 {
1469 XawTextScanType type;
1470
1471 if (*num_params && (*params[0] == 'A' || *params[0] == 'a'))
1472 type = XawstAlphaNumeric;
1473 else
1474 type = XawstWhiteSpace;
1475
1476 DeleteOrKill((TextWidget) w, event, XawsdLeft, type, False, True);
1477 }
1478
1479 /*ARGSUSED*/
1480 static void
KillToEndOfLine(Widget w,XEvent * event,String * p _X_UNUSED,Cardinal * n _X_UNUSED)1481 KillToEndOfLine(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
1482 {
1483 TextWidget ctx = (TextWidget)w;
1484 XawTextPosition end_of_line;
1485 XawTextScanDirection dir = XawsdRight;
1486 short mult = MULT(ctx);
1487
1488 if (mult < 0) {
1489 dir = XawsdLeft;
1490 mult = (short)(-mult);
1491 }
1492
1493 StartAction(ctx, event);
1494 end_of_line = SrcScan(ctx->text.source, ctx->text.insertPos, XawstEOL,
1495 dir, mult, False);
1496 if (end_of_line == ctx->text.insertPos)
1497 end_of_line = SrcScan(ctx->text.source, ctx->text.insertPos, XawstEOL,
1498 dir, mult, True);
1499
1500 if (dir == XawsdRight)
1501 _DeleteOrKill(ctx, ctx->text.insertPos, end_of_line, True);
1502 else
1503 _DeleteOrKill(ctx, end_of_line, ctx->text.insertPos, True);
1504 EndAction(ctx);
1505 }
1506
1507 /*ARGSUSED*/
1508 static void
KillToEndOfParagraph(Widget w,XEvent * event,String * p _X_UNUSED,Cardinal * n _X_UNUSED)1509 KillToEndOfParagraph(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
1510 {
1511 DeleteOrKill((TextWidget)w, event, XawsdRight, XawstParagraph, False, True);
1512 }
1513
1514 void
_XawTextZapSelection(TextWidget ctx,XEvent * event,Bool kill)1515 _XawTextZapSelection(TextWidget ctx, XEvent *event, Bool kill)
1516 {
1517 StartAction(ctx, event);
1518 _DeleteOrKill(ctx, ctx->text.s.left, ctx->text.s.right, kill);
1519 EndAction(ctx);
1520 }
1521
1522 /*ARGSUSED*/
1523 static void
KillCurrentSelection(Widget w,XEvent * event,String * p _X_UNUSED,Cardinal * n _X_UNUSED)1524 KillCurrentSelection(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
1525 {
1526 _XawTextZapSelection((TextWidget) w, event, True);
1527 }
1528
1529 #ifndef OLDXAW
1530 /*ARGSUSED*/
1531 static void
KillRingYank(Widget w,XEvent * event,String * params _X_UNUSED,Cardinal * num_params _X_UNUSED)1532 KillRingYank(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
1533 {
1534 TextWidget ctx = (TextWidget)w;
1535 XawTextPosition insertPos = ctx->text.insertPos;
1536 Bool first_yank = False;
1537
1538 if (ctx->text.s.left != ctx->text.s.right)
1539 XawTextUnsetSelection((Widget)ctx);
1540
1541 StartAction(ctx, event);
1542
1543 if (ctx->text.kill_ring_ptr == NULL) {
1544 ctx->text.kill_ring_ptr = &kill_ring_prev;
1545 ++ctx->text.kill_ring_ptr->refcount;
1546 ctx->text.s.left = ctx->text.s.right = insertPos;
1547 first_yank = True;
1548 }
1549 if (ctx->text.kill_ring_ptr) {
1550 int mul = MULT(ctx);
1551 XawTextBlock text;
1552
1553 if (!first_yank) {
1554 if (mul < 0)
1555 mul = 1;
1556 --ctx->text.kill_ring_ptr->refcount;
1557 while (mul--) {
1558 if ((ctx->text.kill_ring_ptr = ctx->text.kill_ring_ptr->next) == NULL)
1559 ctx->text.kill_ring_ptr = &kill_ring_null;
1560 }
1561 ++ctx->text.kill_ring_ptr->refcount;
1562 }
1563 text.firstPos = 0;
1564 text.length = ctx->text.kill_ring_ptr->length;
1565 text.ptr = ctx->text.kill_ring_ptr->contents;
1566 text.format = ctx->text.kill_ring_ptr->format;
1567
1568 if (_XawTextReplace(ctx, ctx->text.s.left, insertPos, &text) == XawEditDone) {
1569 ctx->text.kill_ring = KILL_RING_YANK;
1570 ctx->text.insertPos = ctx->text.s.left + text.length;
1571 }
1572 }
1573 else
1574 XBell(XtDisplay(w), 0);
1575
1576 EndAction(ctx);
1577 }
1578 #endif /* OLDXAW */
1579
1580 /*ARGSUSED*/
1581 static void
DeleteCurrentSelection(Widget w,XEvent * event,String * p _X_UNUSED,Cardinal * n _X_UNUSED)1582 DeleteCurrentSelection(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
1583 {
1584 _XawTextZapSelection((TextWidget)w, event, False);
1585 }
1586
1587 #ifndef OLDXAW
1588 #define CHECK_SAVE() \
1589 if (save && !save->ptr) \
1590 save->ptr = _XawTextGetText(ctx, save->firstPos, \
1591 save->firstPos + save->length)
1592 static Bool
StripSpaces(TextWidget ctx,XawTextPosition left,XawTextPosition right,XawTextPosition * pos,int num_pos,XawTextBlock * save)1593 StripSpaces(TextWidget ctx, XawTextPosition left, XawTextPosition right,
1594 XawTextPosition *pos, int num_pos, XawTextBlock *save)
1595 {
1596 Bool done, space;
1597 int i, cpos, count = 0;
1598 XawTextBlock block, text;
1599 XawTextPosition ipos, position = left, tmp = left;
1600
1601 text.firstPos = 0;
1602 text.format = XawFmt8Bit;
1603 text.ptr = " ";
1604 text.length = 1;
1605
1606 position = XawTextSourceRead(ctx->text.source, position,
1607 &block, (int)(right - left));
1608 done = False;
1609 space = False;
1610 /* convert tabs and returns to spaces */
1611 while (!done) {
1612 if (XawTextFormat(ctx, XawFmt8Bit)) {
1613 for (i = 0; i < block.length; i++)
1614 if (block.ptr[i] == '\t' || block.ptr[i] == '\n') {
1615 space = True;
1616 break;
1617 }
1618 }
1619 else {
1620 wchar_t *wptr = (wchar_t*)block.ptr;
1621 for (i = 0; i < block.length; i++)
1622 if (wptr[i] == _Xaw_atowc('\t') || wptr[i] == _Xaw_atowc('\n')) {
1623 space = True;
1624 break;
1625 }
1626 }
1627 if (space) {
1628 CHECK_SAVE();
1629 if (_XawTextReplace(ctx, tmp + i, tmp + i + 1, &text))
1630 return (False);
1631 space = False;
1632 }
1633 tmp += i;
1634 position = XawTextSourceRead(ctx->text.source, tmp,
1635 &block, (int)(right - tmp));
1636 if (block.length == 0 || tmp == position || tmp >= right)
1637 done = True;
1638 }
1639
1640 text.ptr = "";
1641 text.length = 0;
1642 position = tmp = left;
1643 position = XawTextSourceRead(ctx->text.source, position,
1644 &block, (int)(right - left));
1645 ipos = ctx->text.insertPos;
1646 done = False;
1647 while (!done) {
1648 if (XawTextFormat(ctx, XawFmt8Bit)) {
1649 for (i = 0; i < block.length; i++)
1650 if (block.ptr[i] == ' ')
1651 ++count;
1652 else if (count == 1)
1653 count = 0;
1654 else if (count)
1655 break;
1656 }
1657 else {
1658 wchar_t *wptr = (wchar_t*)block.ptr;
1659 for (i = 0; i < block.length; i++)
1660 if (wptr[i] == _Xaw_atowc(' '))
1661 ++count;
1662 else if (count == 1)
1663 count = 0;
1664 else if (count)
1665 break;
1666 }
1667 if (--count > 0) {
1668 CHECK_SAVE();
1669 if (_XawTextReplace(ctx, tmp + i - count, tmp + i, &text))
1670 return (False);
1671 right -= count;
1672 if (num_pos) {
1673 for (cpos = 0; cpos < num_pos; cpos++) {
1674 if (tmp + i - count < pos[cpos]) {
1675 if (tmp + i < pos[cpos])
1676 pos[cpos] -= count;
1677 else
1678 pos[cpos] = tmp + i - count;
1679 }
1680 }
1681 }
1682 else {
1683 if (tmp + i - count < ipos) {
1684 if (tmp + i < ipos)
1685 ipos -= count;
1686 else
1687 ipos = tmp + i - count;
1688 }
1689 }
1690 tmp += i - count;
1691 }
1692 else
1693 tmp += i + 1;
1694 count = 0;
1695 position = XawTextSourceRead(ctx->text.source, tmp,
1696 &block, (int)(right - tmp));
1697 if (block.length == 0 || tmp == position || tmp >= right)
1698 done = True;
1699 }
1700 if (!num_pos)
1701 ctx->text.insertPos = ipos;
1702
1703 return (True);
1704 }
1705
1706 static Bool
Tabify(TextWidget ctx,XawTextPosition left,XawTextPosition right,XawTextPosition * pos,int num_pos,XawTextBlock * save)1707 Tabify(TextWidget ctx, XawTextPosition left, XawTextPosition right,
1708 XawTextPosition *pos, int num_pos, XawTextBlock *save)
1709 {
1710 Bool done, zero;
1711 int i, cpos, count = 0, column = 0, offset = 0;
1712 XawTextBlock text, block;
1713 XawTextPosition ipos, position = left, tmp = left;
1714 TextSinkObject sink = (TextSinkObject)ctx->text.sink;
1715 short *char_tabs = sink->text_sink.char_tabs;
1716 int tab_count = sink->text_sink.tab_count;
1717 int tab_index = 0, tab_column = 0, TAB_SIZE = DEFAULT_TAB_SIZE;
1718
1719 text.firstPos = 0;
1720 text.ptr = "\t";
1721 text.format = XawFmt8Bit;
1722 text.length = 1;
1723
1724 position = XawTextSourceRead(ctx->text.source, position,
1725 &block, (int)(right - left));
1726 ipos = ctx->text.insertPos;
1727 done = zero = False;
1728 if (tab_count)
1729 TAB_SIZE = *char_tabs;
1730 while (!done) {
1731 if (XawTextFormat(ctx, XawFmt8Bit)) {
1732 for (i = 0; i < block.length; i++) {
1733 ++offset;
1734 ++column;
1735 if (tab_count) {
1736 if (column > tab_column + char_tabs[tab_index]) {
1737 TAB_SIZE = tab_index < tab_count - 1 ? char_tabs[tab_index + 1] - char_tabs[tab_index] : *char_tabs;
1738 if (++tab_index >= tab_count) {
1739 tab_column += char_tabs[tab_count - 1];
1740 tab_index = 0;
1741 }
1742 }
1743 }
1744 if (block.ptr[i] == ' ') {
1745 if (++count > TAB_SIZE)
1746 count %= TAB_SIZE;
1747 if ((tab_count && column == tab_column + char_tabs[tab_index]) ||
1748 (!tab_count && column % TAB_SIZE == 0)) {
1749 if (count % (TAB_SIZE + 1) > 1)
1750 break;
1751 else
1752 count = 0;
1753 }
1754 }
1755 else {
1756 if (block.ptr[i] == '\n') {
1757 zero = True;
1758 break;
1759 }
1760 count = 0;
1761 }
1762 }
1763 }
1764 else {
1765 wchar_t *wptr = (wchar_t*)block.ptr;
1766 for (i = 0; i < block.length; i++) {
1767 ++offset;
1768 ++column;
1769 if (tab_count) {
1770 if (column > tab_column + char_tabs[tab_index]) {
1771 TAB_SIZE = tab_index < tab_count - 1 ? char_tabs[tab_index + 1] - char_tabs[tab_index] : *char_tabs;
1772 if (++tab_index >= tab_count) {
1773 tab_column += char_tabs[tab_count - 1];
1774 tab_index = 0;
1775 }
1776 }
1777 }
1778 if (wptr[i] == _Xaw_atowc(' ')) {
1779 if (++count > TAB_SIZE)
1780 count %= TAB_SIZE;
1781 if ((tab_count && column == tab_column + char_tabs[tab_index]) ||
1782 (!tab_count && column % TAB_SIZE == 0)) {
1783 if (count % (TAB_SIZE + 1) > 1)
1784 break;
1785 else
1786 count = 0;
1787 }
1788 }
1789 else {
1790 if (wptr[i] == _Xaw_atowc('\n')) {
1791 zero = True;
1792 break;
1793 }
1794 count = 0;
1795 }
1796 }
1797 }
1798 count %= TAB_SIZE + 1;
1799 if (!zero && count > 1 && i < block.length) {
1800 CHECK_SAVE();
1801 if (_XawTextReplace(ctx, tmp + i - count + 1, tmp + i + 1, &text))
1802 return (False);
1803 right -= count - 1;
1804 offset -= count - 1;
1805 if (num_pos) {
1806 for (cpos = 0; cpos < num_pos; cpos++) {
1807 if (tmp + i - count + 1 < pos[cpos]) {
1808 if (tmp + i + 1 < pos[cpos])
1809 pos[cpos] -= count;
1810 else
1811 pos[cpos] = tmp + i - count + 1;
1812 ++pos[cpos];
1813 }
1814 }
1815 }
1816 else {
1817 if (tmp + i - count + 1 < ipos) {
1818 if (tmp + i + 1 < ipos)
1819 ipos -= count;
1820 else
1821 ipos = tmp + i - count + 1;
1822 ++ipos;
1823 }
1824 }
1825 }
1826 if (count)
1827 --count;
1828 if (zero) {
1829 count = column = 0;
1830 zero = False;
1831 if (tab_count) {
1832 tab_column = tab_index = 0;
1833 TAB_SIZE = *char_tabs;
1834 }
1835 }
1836 else if (i < block.length)
1837 count = 0;
1838 tmp = left + offset;
1839 position = XawTextSourceRead(ctx->text.source, tmp,
1840 &block, (int)(right - tmp));
1841 if (tmp == position || tmp >= right)
1842 done = True;
1843 }
1844 if (!num_pos)
1845 ctx->text.insertPos = ipos;
1846
1847 return (True);
1848 }
1849
1850 static Bool
Untabify(TextWidget ctx,XawTextPosition left,XawTextPosition right,XawTextPosition * pos,int num_pos,XawTextBlock * save)1851 Untabify(TextWidget ctx, XawTextPosition left, XawTextPosition right,
1852 XawTextPosition *pos, int num_pos, XawTextBlock *save)
1853 {
1854 Bool done, zero;
1855 int i, cpos, count = 0, diff = 0;
1856 XawTextBlock block, text;
1857 XawTextPosition ipos, position = left, tmp = left;
1858 TextSinkObject sink = (TextSinkObject)ctx->text.sink;
1859 short *char_tabs = sink->text_sink.char_tabs;
1860 int tab_count = sink->text_sink.tab_count;
1861 int tab_index = 0, tab_column = 0, tab_base = 0;
1862 static char *tabs = " ";
1863
1864 text.firstPos = 0;
1865 text.format = XawFmt8Bit;
1866 text.ptr = tabs;
1867
1868 position = XawTextSourceRead(ctx->text.source, position,
1869 &block, (int)(right - left));
1870 ipos = ctx->text.insertPos;
1871 done = False;
1872 zero = False;
1873 while (!done) {
1874 if (XawTextFormat(ctx, XawFmt8Bit))
1875 for (i = 0; i < block.length; i++) {
1876 if (block.ptr[i] != '\t') {
1877 ++count;
1878 if (block.ptr[i] == '\n') {
1879 zero = True;
1880 break;
1881 }
1882 }
1883 else
1884 break;
1885 }
1886 else {
1887 wchar_t *wptr = (wchar_t*)block.ptr;
1888 for (i = 0; i < block.length; i++)
1889 if (wptr[i] != _Xaw_atowc('\t')) {
1890 ++count;
1891 if (wptr[i] != _Xaw_atowc('\n')) {
1892 zero = True;
1893 break;
1894 }
1895 }
1896 else
1897 break;
1898 }
1899 if (!zero && i < block.length) {
1900 if (tab_count) {
1901 while (tab_base + tab_column <= count) {
1902 for (; tab_index < tab_count; ++tab_index)
1903 if (tab_base + char_tabs[tab_index] > count) {
1904 tab_column = char_tabs[tab_index];
1905 break;
1906 }
1907 if (tab_index >= tab_count) {
1908 tab_base += char_tabs[tab_count - 1];
1909 tab_column = tab_index = 0;
1910 }
1911 }
1912 text.length = (tab_base + tab_column) - count;
1913 if (text.length > 8) {
1914 int j;
1915
1916 text.ptr = XtMalloc((Cardinal)text.length);
1917 for (j = 0; j < text.length; j++)
1918 text.ptr[j] = ' ';
1919 }
1920 else
1921 text.ptr = tabs;
1922 }
1923 else
1924 text.length = DEFAULT_TAB_SIZE - (count % DEFAULT_TAB_SIZE);
1925 CHECK_SAVE();
1926 if (_XawTextReplace(ctx, tmp + i, tmp + i + 1, &text)) {
1927 if (tab_count && text.length > 8)
1928 XtFree(text.ptr);
1929 return (False);
1930 }
1931 if (tab_count && text.length > 8)
1932 XtFree(text.ptr);
1933 count += text.length;
1934 right += text.length - 1;
1935 if (num_pos) {
1936 for (cpos = 0; cpos < num_pos; cpos++) {
1937 if (tmp + i < pos[cpos]) {
1938 if (tmp + i + 1 < pos[cpos])
1939 --pos[cpos];
1940 else
1941 pos[cpos] = tmp + i;
1942 pos[cpos] += text.length;
1943 }
1944 }
1945 }
1946 else {
1947 if (tmp + i < ipos) {
1948 if (tmp + i + 1 < ipos)
1949 --ipos;
1950 else
1951 ipos = tmp + i;
1952 ipos += text.length;
1953 }
1954 }
1955 }
1956 tmp = left + count + diff;
1957 if (zero) {
1958 diff += count;
1959 count = 0;
1960 zero = False;
1961 if (tab_count)
1962 tab_base = tab_column = tab_index = 0;
1963 }
1964 position = XawTextSourceRead(ctx->text.source, tmp,
1965 &block, (int)(right - tmp));
1966 if (tmp == position || tmp >= right)
1967 done = True;
1968 }
1969 if (!num_pos)
1970 ctx->text.insertPos = ipos;
1971
1972 return (True);
1973 }
1974
1975 static int
FormatText(TextWidget ctx,XawTextPosition left,Bool force,XawTextPosition * pos,int num_pos)1976 FormatText(TextWidget ctx, XawTextPosition left, Bool force,
1977 XawTextPosition *pos, int num_pos)
1978 {
1979 char *ptr = NULL;
1980 Bool freepos = False, undo, paragraph = pos != NULL;
1981 int i, result;
1982 XawTextBlock block, *text;
1983 XawTextPosition end = ctx->text.lastPos, buf[32];
1984 TextSrcObject src = (TextSrcObject)ctx->text.source;
1985 XawTextPosition right = SrcScan(ctx->text.source, left, XawstEOL,
1986 XawsdRight, 1, False);
1987
1988 undo = src->textSrc.enable_undo && src->textSrc.undo_state == False;
1989 if (undo) {
1990 if (!pos) {
1991 num_pos = (int)src->textSrc.num_text;
1992 pos = (XawStackAlloc(sizeof(XawTextPosition) * (size_t)num_pos, buf));
1993 for (i = 0; i < num_pos; i++)
1994 pos[i] = ((TextWidget)src->textSrc.text[i])->text.insertPos;
1995 freepos = True;
1996 }
1997 else
1998 freepos = False;
1999 src->textSrc.undo_state = True;
2000 block.ptr = NULL;
2001 block.firstPos = (int)left;
2002 block.length = (int)(right - left);
2003 text = █
2004 }
2005 else
2006 text = NULL;
2007
2008 result = DoFormatText(ctx, left, force, 1, text, pos, num_pos, paragraph);
2009 if (undo && result == XawEditDone && block.ptr) {
2010 char *lbuf, *rbuf;
2011 unsigned llen, rlen, size;
2012
2013 ptr = lbuf = block.ptr;
2014 llen = (unsigned)block.length;
2015 rlen = (unsigned)(llen + (ctx->text.lastPos - end));
2016
2017 block.firstPos = 0;
2018 block.format = (unsigned long)_XawTextFormat(ctx);
2019
2020 rbuf = _XawTextGetText(ctx, left, left + rlen);
2021
2022 size = XawTextFormat(ctx, XawFmtWide) ? sizeof(wchar_t) : sizeof(char);
2023 if (llen != rlen || memcmp(lbuf, rbuf, llen * size)) {
2024 block.ptr = lbuf;
2025 block.length = (int)llen;
2026 _XawTextReplace(ctx, left, left + rlen, &block);
2027
2028 src->textSrc.undo_state = False;
2029 block.ptr = rbuf;
2030 block.length = (int)rlen;
2031 _XawTextReplace(ctx, left, left + llen, &block);
2032 }
2033 else
2034 src->textSrc.undo_state = False;
2035 XtFree(rbuf);
2036 }
2037 if (undo) {
2038 src->textSrc.undo_state = False;
2039 if (freepos) {
2040 for (i = 0; i < num_pos; i++) {
2041 TextWidget tw = (TextWidget)src->textSrc.text[i];
2042 tw->text.insertPos = XawMin(XawMax(0, pos[i]), tw->text.lastPos);
2043 }
2044 XawStackFree(pos, buf);
2045 }
2046 if (ptr)
2047 XtFree(ptr);
2048 }
2049
2050 return (result);
2051 }
2052
2053 static int
DoFormatText(TextWidget ctx,XawTextPosition left,Bool force,int level,XawTextBlock * save,XawTextPosition * pos,int num_pos,Bool paragraph)2054 DoFormatText(TextWidget ctx, XawTextPosition left, Bool force, int level,
2055 XawTextBlock *save, XawTextPosition *pos, int num_pos,
2056 Bool paragraph)
2057 {
2058 XawTextPosition right = SrcScan(ctx->text.source, left, XawstEOL,
2059 XawsdRight, 1, False);
2060 XawTextPosition position, tmp, ipos;
2061 XawTextBlock block, text;
2062 char buf[128];
2063 wchar_t *wptr;
2064 int i, count, cpos;
2065 Bool done, force2 = force, recurse = False;
2066
2067 position = XawTextSourceRead(ctx->text.source, left, &block, (int)(right - left));
2068 if (block.length == 0 || left >= right ||
2069 (level == 1 && ((XawTextFormat(ctx, XawFmt8Bit) &&
2070 block.ptr[0] != ' ' &&
2071 block.ptr[0] != '\t' &&
2072 !isalnum(*(unsigned char*)block.ptr)) ||
2073 (XawTextFormat(ctx, XawFmtWide) &&
2074 _Xaw_atowc(XawSP) != *(wchar_t*)block.ptr &&
2075 _Xaw_atowc(XawTAB) != *(wchar_t*)block.ptr &&
2076 !iswalnum((wint_t)*(wchar_t*)block.ptr)))))
2077 return (XawEditDone);
2078
2079 if (level == 1 && !paragraph) {
2080 tmp = ctx->text.lastPos;
2081 if (Untabify(ctx, left, right, pos, num_pos, save) == False)
2082 return (XawEditError);
2083 right += ctx->text.lastPos - tmp;
2084 position = XawTextSourceRead(ctx->text.source, left, &block,
2085 (int)(right - left));
2086 }
2087
2088 text.firstPos = 0;
2089 text.format = XawFmt8Bit;
2090
2091 ipos = ctx->text.insertPos;
2092 count = 0;
2093 done = False;
2094 while (!done) {
2095 if (XawTextFormat(ctx, XawFmt8Bit)) {
2096 for (i = 0; i < block.length; i++)
2097 if (block.ptr[i] == ' ')
2098 ++count;
2099 else {
2100 done = True;
2101 break;
2102 }
2103 }
2104 else {
2105 wptr = (wchar_t*)block.ptr;
2106 for (i = 0; i < block.length; i++)
2107 if (wptr[i] == _Xaw_atowc(' '))
2108 ++count;
2109 else {
2110 done = True;
2111 break;
2112 }
2113 }
2114 tmp = position;
2115 position = XawTextSourceRead(ctx->text.source, position,
2116 &block, (int)(right - position));
2117 if (tmp == position)
2118 done = True;
2119 }
2120 position = left + count;
2121 if (count < ctx->text.left_column) {
2122 int bytes = ctx->text.left_column - count;
2123
2124 text.ptr = XawStackAlloc((unsigned)bytes, buf);
2125 text.length = bytes;
2126 for (i = 0; i < bytes; i++)
2127 text.ptr[i] = ' ';
2128 CHECK_SAVE();
2129 if (_XawTextReplace(ctx, left, left, &text)) {
2130 XawStackFree(text.ptr, buf);
2131 return (XawEditError);
2132 }
2133 XawStackFree(text.ptr, buf);
2134 right += bytes;
2135 if (num_pos) {
2136 for (cpos = 0; cpos < num_pos; cpos++)
2137 if (pos[cpos] >= left)
2138 pos[cpos] += bytes;
2139 }
2140 if (ipos >= left)
2141 ipos += bytes;
2142 count += bytes;
2143 }
2144
2145 done = False;
2146 if (!paragraph && level == 1
2147 && ipos <= right && ipos - left > ctx->text.right_column) {
2148 XawTextPosition len = ctx->text.lastPos;
2149 int skip = ctx->text.justify == XawjustifyRight
2150 || ctx->text.justify == XawjustifyCenter ?
2151 ctx->text.left_column : count;
2152
2153 if (pos)
2154 for (i = 0; i < num_pos; i++)
2155 if (pos[i] == ipos)
2156 break;
2157
2158 StripSpaces(ctx, left + skip, right, pos, num_pos, save);
2159 right += ctx->text.lastPos - len;
2160 if (pos && i < num_pos)
2161 ipos = pos[i];
2162 else
2163 ipos = ctx->text.insertPos;
2164 done = ipos - left > ctx->text.right_column;
2165 count = skip + (count == skip + 1);
2166 }
2167 if ((paragraph || done) && right - left > ctx->text.right_column) {
2168 position = tmp = right;
2169 XawTextSourceRead(ctx->text.source, position - 1, &block, 1);
2170 if (block.length &&
2171 ((XawTextFormat(ctx, XawFmt8Bit) &&
2172 block.ptr[0] == ' ') ||
2173 (XawTextFormat(ctx, XawFmtWide) &&
2174 _Xaw_atowc(XawSP) == *(wchar_t*)block.ptr)))
2175 --position;
2176 while (position - left > ctx->text.right_column) {
2177 tmp = position;
2178 position = SrcScan(ctx->text.source, position,
2179 XawstWhiteSpace, XawsdLeft, 1, True);
2180 }
2181 if (position <= left + ctx->text.left_column)
2182 position = tmp;
2183 if (position > left && position - left > ctx->text.left_column
2184 && position != right) {
2185 text.ptr = "\n";
2186 text.length = 1;
2187 CHECK_SAVE();
2188 if (_XawTextReplace(ctx, position, position + 1, &text))
2189 return (XawEditError);
2190 right = position;
2191 recurse = True;
2192 force = True;
2193 }
2194 }
2195
2196 if (force) {
2197 if (ctx->text.justify == XawjustifyCenter)
2198 count = ctx->text.right_column - (count - ctx->text.left_column);
2199 else
2200 count = ctx->text.right_column;
2201 if (count > right - left)
2202 count = (int)(count - (right - left));
2203 else
2204 count = 0;
2205 }
2206 else
2207 count = 0;
2208 if (count > 0) {
2209 switch (ctx->text.justify) {
2210 case XawjustifyLeft:
2211 break;
2212 case XawjustifyRight:
2213 case XawjustifyCenter:
2214 if (ctx->text.justify == XawjustifyCenter) {
2215 int alnum = 0;
2216
2217 if (!(count & 1)) {
2218 XawTextSourceRead(ctx->text.source, right, &block, 1);
2219 if ((XawTextFormat(ctx, XawFmt8Bit)
2220 && isalnum(*(unsigned char*)block.ptr)) ||
2221 (XawTextFormat(ctx, XawFmtWide)
2222 && iswalnum((wint_t)*(wchar_t*)block.ptr)))
2223 alnum = 1;
2224 }
2225 count = (count + alnum) >> 1;
2226 }
2227 text.ptr = XawStackAlloc((unsigned)count, buf);
2228 text.length = count;
2229 for (i = 0; i < count; i++)
2230 text.ptr[i] = ' ';
2231 CHECK_SAVE();
2232 if (_XawTextReplace(ctx, left, left, &text)) {
2233 XawStackFree(text.ptr, buf);
2234 return (XawEditError);
2235 }
2236 XawStackFree(text.ptr, buf);
2237 position += count;
2238 right += count;
2239 if (num_pos) {
2240 for (cpos = 0; cpos < num_pos; cpos++)
2241 if (pos[cpos] > left)
2242 pos[cpos] += count;
2243 }
2244 else if (ipos > left)
2245 ipos += count;
2246 break;
2247 case XawjustifyFull:
2248 i = 0;
2249 tmp = left;
2250 /*CONSTCOND*/
2251 while (True) {
2252 tmp = SrcScan(ctx->text.source, tmp, XawstWhiteSpace,
2253 XawsdRight, 1, True);
2254 if (tmp < right)
2255 ++i;
2256 else
2257 break;
2258 }
2259 if (i) {
2260 double inc, ii;
2261 int bytes, steps;
2262
2263 bytes = count;
2264 inc = ii = (count + .5) / (double)i;
2265
2266 steps = count;
2267 text.ptr = XawStackAlloc((unsigned)steps, buf);
2268 for (i = 0; i < steps; i++)
2269 text.ptr[i] = ' ';
2270 tmp = left;
2271 CHECK_SAVE();
2272 while (bytes) {
2273 steps = 1;
2274 while (inc + ii < 1) {
2275 ++steps;
2276 inc += ii;
2277 }
2278 tmp = SrcScan(ctx->text.source, tmp, XawstWhiteSpace,
2279 XawsdRight, steps, True);
2280 if (bytes > inc)
2281 text.length = (int)inc;
2282 else
2283 text.length = bytes;
2284 bytes -= text.length;
2285 if (_XawTextReplace(ctx, tmp, tmp, &text)) {
2286 XawStackFree(text.ptr, buf);
2287 return (XawEditError);
2288 }
2289 if (num_pos) {
2290 for (cpos = 0; cpos < num_pos; cpos++)
2291 if (tmp <= pos[cpos])
2292 pos[cpos] += text.length;
2293 }
2294 else if (tmp <= ipos)
2295 ipos += text.length;
2296 inc -= (int)inc;
2297 inc += ii;
2298 }
2299 position += count;
2300 right += count;
2301 XawStackFree(text.ptr, buf);
2302 }
2303 break;
2304 }
2305 }
2306
2307 if (!num_pos)
2308 ctx->text.insertPos = XawMin(ipos, ctx->text.lastPos);
2309
2310 return (recurse ? DoFormatText(ctx, position + 1,
2311 ctx->text.justify != XawjustifyFull
2312 && (force2 || paragraph),
2313 ++level, save, pos, num_pos, paragraph)
2314 : XawEditDone);
2315 }
2316 #undef CHECK_SAVE
2317
2318 /*ARGSUSED*/
2319 static void
Indent(Widget w,XEvent * event,String * params _X_UNUSED,Cardinal * num_params _X_UNUSED)2320 Indent(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
2321 {
2322 TextWidget ctx = (TextWidget)w;
2323 TextSrcObject src = (TextSrcObject)ctx->text.source;
2324 XawTextPosition from, to, tmp, end = 0, *pos, *posbuf[32];
2325 char buf[32];
2326 XawTextBlock text;
2327 int i, spaces = MULT(ctx);
2328 char *lbuf = NULL, *rbuf;
2329 unsigned llen = 0, rlen, size;
2330 Bool undo = src->textSrc.enable_undo && src->textSrc.undo_state == False;
2331 Bool format = ctx->text.auto_fill
2332 && ctx->text.left_column < ctx->text.right_column;
2333
2334 text.firstPos = 0;
2335 text.format = XawFmt8Bit;
2336 text.ptr = "";
2337
2338 StartAction(ctx, event);
2339
2340 pos = XawStackAlloc(sizeof(XawTextPosition) * src->textSrc.num_text, posbuf);
2341 for (i = 0; (Cardinal)i < src->textSrc.num_text; i++)
2342 pos[i] = ((TextWidget)src->textSrc.text[i])->text.insertPos;
2343
2344 if (!GetBlockBoundaries(ctx, &from, &to)) {
2345 EndAction(ctx);
2346 XawStackFree(pos, posbuf);
2347 return;
2348 }
2349
2350 if (undo) {
2351 llen = (unsigned)(to - from);
2352 end = ctx->text.lastPos;
2353 lbuf = _XawTextGetText(ctx, from, to);
2354 src->textSrc.undo_state = True;
2355 }
2356
2357 tmp = ctx->text.lastPos;
2358 if (!Untabify(ctx, from, to, pos, (int)src->textSrc.num_text, NULL)) {
2359 XBell(XtDisplay(ctx), 0);
2360 EndAction(ctx);
2361 XawStackFree(pos, posbuf);
2362 if (undo) {
2363 src->textSrc.undo_state = True;
2364 XtFree(lbuf);
2365 }
2366 return;
2367 }
2368 to += ctx->text.lastPos - tmp;
2369
2370 tmp = from;
2371
2372 if (spaces > 0) {
2373 text.ptr = XawStackAlloc((unsigned)spaces, buf);
2374 for (i = 0; i < spaces; i++)
2375 text.ptr[i] = ' ';
2376
2377 text.length = spaces;
2378 while (tmp < to) {
2379 _XawTextReplace(ctx, tmp, tmp, &text);
2380
2381 for (i = 0; (Cardinal)i < src->textSrc.num_text; i++)
2382 if (tmp < pos[i])
2383 pos[i] += spaces;
2384
2385 to += spaces;
2386 tmp = SrcScan(ctx->text.source, tmp, XawstEOL, XawsdRight, 1, True);
2387 }
2388 XawStackFree(text.ptr, buf);
2389 }
2390 else {
2391 int min = 32767;
2392
2393 text.length = 0;
2394 tmp = from;
2395
2396 /* find the amount of spaces to cut */
2397 while (tmp < to) {
2398 (void)BlankLine(w, tmp, &i);
2399 if (i < min)
2400 min = i;
2401 tmp = SrcScan(ctx->text.source, tmp, XawstEOL, XawsdRight, 1, True);
2402 }
2403 spaces = XawMin(-spaces, min);
2404
2405 /* cut the spaces */
2406 tmp = from;
2407 while (tmp < to) {
2408 _XawTextReplace(ctx, tmp, tmp + spaces, &text);
2409
2410 for (i = 0; (Cardinal)i < src->textSrc.num_text; i++)
2411 if (tmp < pos[i]) {
2412 if (tmp + spaces < pos[i])
2413 pos[i] -= spaces;
2414 else
2415 pos[i] = tmp;
2416 }
2417
2418 to -= spaces;
2419 tmp = SrcScan(ctx->text.source, tmp, XawstEOL, XawsdRight, 1, True);
2420 }
2421 }
2422
2423 if (!format)
2424 Tabify(ctx, from, to, pos, (int)src->textSrc.num_text, NULL);
2425
2426 if (undo) {
2427 rlen = (unsigned)(llen + (ctx->text.lastPos - end));
2428 rbuf = _XawTextGetText(ctx, from, from + rlen);
2429
2430 text.format = (unsigned long)_XawTextFormat(ctx);
2431 size = XawTextFormat(ctx, XawFmtWide) ? sizeof(wchar_t) : sizeof(char);
2432 if (llen != rlen || memcmp(lbuf, rbuf, llen * size)) {
2433 text.ptr = lbuf;
2434 text.length = (int)llen;
2435 _XawTextReplace(ctx, from, from + rlen, &text);
2436
2437 src->textSrc.undo_state = False;
2438 text.ptr = rbuf;
2439 text.length = (int)rlen;
2440 _XawTextReplace(ctx, from, from + llen, &text);
2441 }
2442 else
2443 src->textSrc.undo_state = False;
2444 XtFree(lbuf);
2445 XtFree(rbuf);
2446 }
2447
2448 for (i = 0; (Cardinal)i < src->textSrc.num_text; i++) {
2449 TextWidget tw = (TextWidget)src->textSrc.text[i];
2450
2451 tw->text.insertPos = XawMin(XawMax(0, pos[i]), tw->text.lastPos);
2452 }
2453 XawStackFree(pos, posbuf);
2454 ctx->text.showposition = True;
2455
2456 EndAction(ctx);
2457 }
2458
2459 /*ARGSUSED*/
2460 static void
ToggleOverwrite(Widget w,XEvent * event _X_UNUSED,String * params _X_UNUSED,Cardinal * num_params _X_UNUSED)2461 ToggleOverwrite(Widget w, XEvent *event _X_UNUSED, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
2462 {
2463 TextWidget ctx = (TextWidget)w;
2464
2465 ctx->text.overwrite = !ctx->text.overwrite;
2466
2467 /* call information callback */
2468 _XawTextSetLineAndColumnNumber(ctx, True);
2469 }
2470 #endif /* OLDXAW */
2471
2472 /*
2473 * Insertion Routines
2474 */
2475 static int
InsertNewLineAndBackupInternal(TextWidget ctx)2476 InsertNewLineAndBackupInternal(TextWidget ctx)
2477 {
2478 int count, error = XawEditDone, mult = MULT(ctx);
2479 #ifndef OLDXAW
2480 XawTextPosition position;
2481 #endif
2482 XawTextBlock text;
2483 char buf[32];
2484
2485 if (mult < 0) {
2486 ctx->text.mult = 1;
2487 return (XawEditError);
2488 }
2489
2490 text.format = (unsigned long)_XawTextFormat(ctx);
2491 text.length = mult;
2492 text.firstPos = 0;
2493
2494 if (text.format == XawFmtWide) {
2495 wchar_t *wptr;
2496
2497 text.ptr = (XawStackAlloc(sizeof(wchar_t) * (size_t)mult, buf));
2498 wptr = (wchar_t *)text.ptr;
2499 for (count = 0; count < mult; count++)
2500 wptr[count] = _Xaw_atowc(XawLF);
2501 }
2502 else {
2503 text.ptr = (XawStackAlloc(sizeof(char) * (size_t)mult, buf));
2504 for (count = 0; count < mult; count++)
2505 text.ptr[count] = XawLF;
2506 }
2507
2508 #ifndef OLDXAW
2509 position = SrcScan(ctx->text.source, ctx->text.insertPos,
2510 XawstEOL, XawsdLeft, 1, False);
2511 #endif
2512 if (_XawTextReplace(ctx, ctx->text.insertPos, ctx->text.insertPos, &text)) {
2513 XBell( XtDisplay(ctx), 50);
2514 error = XawEditError;
2515 }
2516 else {
2517 ctx->text.showposition = TRUE;
2518 ctx->text.insertPos += text.length;
2519 }
2520
2521 XawStackFree(text.ptr, buf);
2522
2523 #ifndef OLDXAW
2524 if (ctx->text.auto_fill && error == XawEditDone)
2525 (void)FormatText(ctx, position, ctx->text.justify != XawjustifyFull,
2526 NULL, 0);
2527 #endif
2528
2529 return (error);
2530 }
2531
2532 /*ARGSUSED*/
2533 static void
InsertNewLineAndBackup(Widget w,XEvent * event,String * p _X_UNUSED,Cardinal * n _X_UNUSED)2534 InsertNewLineAndBackup(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
2535 {
2536 TextWidget ctx = (TextWidget)w;
2537 XawTextPosition insertPos = ctx->text.insertPos;
2538
2539 StartAction((TextWidget)w, event);
2540 (void)InsertNewLineAndBackupInternal(ctx);
2541 ctx->text.insertPos = SrcScan(ctx->text.source, insertPos, XawstEOL,
2542 XawsdRight, 1, False);
2543 EndAction((TextWidget)w);
2544 }
2545
2546 static int
LocalInsertNewLine(TextWidget ctx,XEvent * event)2547 LocalInsertNewLine(TextWidget ctx, XEvent *event)
2548 {
2549 int error;
2550
2551 StartAction(ctx, event);
2552 error = InsertNewLineAndBackupInternal(ctx);
2553 ctx->text.from_left = -1;
2554 EndAction(ctx);
2555
2556 return (error);
2557 }
2558
2559 /*ARGSUSED*/
2560 static void
InsertNewLine(Widget w,XEvent * event,String * p _X_UNUSED,Cardinal * n _X_UNUSED)2561 InsertNewLine(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
2562 {
2563 (void)LocalInsertNewLine((TextWidget)w, event);
2564 }
2565
2566 /*ARGSUSED*/
2567 static void
InsertNewLineAndIndent(Widget w,XEvent * event,String * p _X_UNUSED,Cardinal * n _X_UNUSED)2568 InsertNewLineAndIndent(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
2569 {
2570 XawTextBlock text;
2571 XawTextPosition pos1;
2572 int length;
2573 TextWidget ctx = (TextWidget)w;
2574 char * line_to_ip;
2575
2576 StartAction(ctx, event);
2577 pos1 = SrcScan(ctx->text.source, ctx->text.insertPos,
2578 XawstEOL, XawsdLeft, 1, False);
2579
2580 line_to_ip = _XawTextGetText(ctx, pos1, ctx->text.insertPos);
2581
2582 text.format = (unsigned long)_XawTextFormat(ctx);
2583 text.firstPos = 0;
2584
2585 if (text.format == XawFmtWide) {
2586 wchar_t *ptr;
2587
2588 text.ptr = XtMalloc((Cardinal)((2 + wcslen((wchar_t*)line_to_ip))
2589 * sizeof(wchar_t)));
2590 ptr = (wchar_t*)text.ptr;
2591 ptr[0] = _Xaw_atowc(XawLF);
2592 wcscpy((wchar_t*)++ptr, (wchar_t*)line_to_ip);
2593
2594 length = (int)wcslen((wchar_t*)text.ptr);
2595 while (length && (iswspace(*ptr) || *ptr == _Xaw_atowc(XawTAB)))
2596 ptr++, length--;
2597 *ptr = (wchar_t)0;
2598 text.length = (int)wcslen((wchar_t*)text.ptr);
2599 }
2600 else {
2601 char *ptr;
2602
2603 length = (int)strlen(line_to_ip);
2604 text.ptr = XtMalloc(((size_t)(2 + length) * sizeof(char)));
2605 ptr = text.ptr;
2606 ptr[0] = XawLF;
2607 strcpy(++ptr, line_to_ip);
2608
2609 length++;
2610 while (length && (isspace(*ptr) || (*ptr == XawTAB)))
2611 ptr++, length--;
2612 *ptr = '\0';
2613 text.length = (int)strlen(text.ptr);
2614 }
2615 XtFree(line_to_ip);
2616
2617 if (_XawTextReplace(ctx,ctx->text.insertPos, ctx->text.insertPos, &text)) {
2618 XBell(XtDisplay(ctx), 50);
2619 XtFree(text.ptr);
2620 EndAction(ctx);
2621 return;
2622 }
2623
2624 XtFree(text.ptr);
2625 ctx->text.from_left = -1;
2626 ctx->text.insertPos = SrcScan(ctx->text.source, ctx->text.old_insert,
2627 XawstPositions, XawsdRight, text.length, True);
2628 EndAction(ctx);
2629 }
2630
2631 /*
2632 * Selection Routines
2633 */
2634 static void
SelectWord(Widget w,XEvent * event,String * params,Cardinal * num_params)2635 SelectWord(Widget w, XEvent *event, String *params, Cardinal *num_params)
2636 {
2637 TextWidget ctx = (TextWidget)w;
2638 XawTextPosition l, r;
2639
2640 StartAction(ctx, event);
2641 l = SrcScan(ctx->text.source, ctx->text.insertPos,
2642 XawstWhiteSpace, XawsdLeft, 1, False);
2643 r = SrcScan(ctx->text.source, l, XawstWhiteSpace, XawsdRight, 1, False);
2644 _XawTextSetSelection(ctx, l, r, params, *num_params);
2645 EndAction(ctx);
2646 }
2647
2648 static void
SelectAll(Widget w,XEvent * event,String * params,Cardinal * num_params)2649 SelectAll(Widget w, XEvent *event, String *params, Cardinal *num_params)
2650 {
2651 TextWidget ctx = (TextWidget)w;
2652
2653 StartAction(ctx, event);
2654 _XawTextSetSelection(ctx,zeroPosition,ctx->text.lastPos,params,*num_params);
2655 EndAction(ctx);
2656 }
2657
2658 static void
ModifySelection(TextWidget ctx,XEvent * event,XawTextSelectionMode mode,XawTextSelectionAction action,String * params,Cardinal * num_params)2659 ModifySelection(TextWidget ctx, XEvent *event,
2660 XawTextSelectionMode mode,
2661 XawTextSelectionAction action,
2662 String *params, Cardinal *num_params)
2663 {
2664 #ifndef OLDXAW
2665 int old_y = ctx->text.ev_y;
2666 #endif
2667
2668 StartAction(ctx, event);
2669 NotePosition(ctx, event);
2670
2671 #ifndef OLDXAW
2672 if (event->type == MotionNotify) {
2673 if (ctx->text.ev_y <= ctx->text.margin.top) {
2674 if (old_y >= ctx->text.ev_y)
2675 XawTextScroll(ctx, -1, 0);
2676 }
2677 else if (ctx->text.ev_y >= XtHeight(ctx) - ctx->text.margin.bottom) {
2678 if (old_y <= ctx->text.ev_y
2679 && !IsPositionVisible(ctx, ctx->text.lastPos))
2680 XawTextScroll(ctx, 1, 0);
2681 }
2682 }
2683 #endif
2684 ctx->text.from_left = -1;
2685 _XawTextAlterSelection(ctx, mode, action, params, num_params);
2686
2687 EndAction(ctx);
2688 }
2689
2690 static void
SelectStart(Widget w,XEvent * event,String * params,Cardinal * num_params)2691 SelectStart(Widget w, XEvent *event, String *params, Cardinal *num_params)
2692 {
2693 TextWidget ctx = (TextWidget)w;
2694
2695 #ifndef OLDXAW
2696 if (!ctx->text.selection_state) {
2697 ctx->text.selection_state = True;
2698 #endif
2699 ModifySelection(ctx, event,
2700 XawsmTextSelect, XawactionStart, params, num_params);
2701 #ifndef OLDXAW
2702 }
2703 #endif
2704 }
2705
2706 static void
SelectAdjust(Widget w,XEvent * event,String * params,Cardinal * num_params)2707 SelectAdjust(Widget w, XEvent *event, String *params, Cardinal *num_params)
2708 {
2709 TextWidget ctx = (TextWidget)w;
2710
2711 #ifndef OLDXAW
2712 if (ctx->text.selection_state)
2713 #endif
2714 ModifySelection(ctx, event,
2715 XawsmTextSelect, XawactionAdjust, params, num_params);
2716 }
2717
2718 static void
SelectEnd(Widget w,XEvent * event,String * params,Cardinal * num_params)2719 SelectEnd(Widget w, XEvent *event, String *params, Cardinal *num_params)
2720 {
2721 TextWidget ctx = (TextWidget)w;
2722
2723 #ifndef OLDXAW
2724 if (ctx->text.selection_state) {
2725 ctx->text.selection_state = False;
2726 #endif
2727 ModifySelection(ctx, event,
2728 XawsmTextSelect, XawactionEnd, params, num_params);
2729 #ifndef OLDXAW
2730 }
2731 #endif
2732 }
2733
2734 static void
ExtendStart(Widget w,XEvent * event,String * params,Cardinal * num_params)2735 ExtendStart(Widget w, XEvent *event, String *params, Cardinal *num_params)
2736 {
2737 TextWidget ctx = (TextWidget)w;
2738
2739 #ifndef OLDXAW
2740 if (!ctx->text.selection_state) {
2741 ctx->text.selection_state = True;
2742 #endif
2743 ModifySelection(ctx, event,
2744 XawsmTextExtend, XawactionStart, params, num_params);
2745 #ifndef OLDXAW
2746 }
2747 #endif
2748 }
2749
2750 static void
ExtendAdjust(Widget w,XEvent * event,String * params,Cardinal * num_params)2751 ExtendAdjust(Widget w, XEvent *event, String *params, Cardinal *num_params)
2752 {
2753 TextWidget ctx = (TextWidget)w;
2754
2755 #ifndef OLDXAW
2756 if (ctx->text.selection_state)
2757 #endif
2758 ModifySelection(ctx, event,
2759 XawsmTextExtend, XawactionAdjust, params, num_params);
2760 }
2761
2762 static void
ExtendEnd(Widget w,XEvent * event,String * params,Cardinal * num_params)2763 ExtendEnd(Widget w, XEvent *event, String *params, Cardinal *num_params)
2764 {
2765 TextWidget ctx = (TextWidget)w;
2766
2767 #ifndef OLDXAW
2768 if (ctx->text.selection_state) {
2769 ctx->text.selection_state = False;
2770 #endif
2771 ModifySelection(ctx, event,
2772 XawsmTextExtend, XawactionEnd, params, num_params);
2773 #ifndef OLDXAW
2774 }
2775 #endif
2776 }
2777
2778 static void
SelectSave(Widget w,XEvent * event,String * params,Cardinal * num_params)2779 SelectSave(Widget w, XEvent *event, String *params, Cardinal *num_params)
2780 {
2781 int num_atoms, n;
2782 Atom *sel;
2783 Display *dpy = XtDisplay(w);
2784 Atom selections[256];
2785
2786 StartAction((TextWidget)w, event);
2787 num_atoms = (int)*num_params;
2788 if (num_atoms > 256)
2789 num_atoms = 256;
2790 for (sel = selections, n = 0; n < num_atoms; n++, sel++, params++)
2791 *sel = XInternAtom(dpy, *params, False);
2792 _XawTextSaltAwaySelection((TextWidget)w, selections, num_atoms);
2793 EndAction((TextWidget)w);
2794 }
2795
2796 /*
2797 * Misc. Routines
2798 */
2799 /*ARGSUSED*/
2800 static void
SetKeyboardFocus(Widget w,XEvent * event _X_UNUSED,String * params _X_UNUSED,Cardinal * num_params _X_UNUSED)2801 SetKeyboardFocus(Widget w, XEvent *event _X_UNUSED, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
2802 {
2803 Widget shell, parent;
2804
2805 shell = parent = w;
2806 while (parent) {
2807 if (XtIsShell(shell = parent))
2808 break;
2809 parent = XtParent(parent);
2810 }
2811 XtSetKeyboardFocus(shell, w);
2812 }
2813
2814 /*ARGSUSED*/
2815 static void
RedrawDisplay(Widget w,XEvent * event,String * p _X_UNUSED,Cardinal * n _X_UNUSED)2816 RedrawDisplay(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
2817 {
2818 StartAction((TextWidget)w, event);
2819 _XawTextClearAndCenterDisplay((TextWidget)w);
2820 EndAction((TextWidget)w);
2821 }
2822
2823 /* This is kind of a hack, but, only one text widget can have focus at
2824 * a time on one display. There is a problem in the implementation of the
2825 * text widget, the scrollbars can not be adressed via editres, since they
2826 * are not children of a subclass of composite.
2827 * The focus variable is required to make sure only one text window will
2828 * show a block cursor at one time.
2829 */
2830 struct _focus { Display *display; Widget widget; };
2831 static struct _focus *focus;
2832 static Cardinal num_focus;
2833
2834 /*ARGSUSED*/
2835 static void
DestroyFocusCallback(Widget w,XtPointer user_data,XtPointer call_data _X_UNUSED)2836 DestroyFocusCallback(Widget w, XtPointer user_data, XtPointer call_data _X_UNUSED)
2837 {
2838 struct _focus *f = (struct _focus*)(user_data);
2839
2840 if (f->widget == w)
2841 f->widget = NULL;
2842 }
2843
2844 /*ARGSUSED*/
2845 static void
TextFocusIn(Widget w,XEvent * event,String * p,Cardinal * n)2846 TextFocusIn(Widget w, XEvent *event, String *p, Cardinal *n)
2847 {
2848 TextWidget ctx = (TextWidget)w;
2849 Bool display_caret = ctx->text.display_caret;
2850 int i;
2851
2852 if (event->xfocus.detail == NotifyPointer)
2853 return;
2854
2855 if (event->xfocus.send_event) {
2856 Window root, child;
2857 int rootx, rooty, x, y;
2858 unsigned int mask;
2859
2860 if (ctx->text.hasfocus)
2861 return;
2862
2863 if (XQueryPointer(XtDisplay(w), XtWindow(w), &root, &child,
2864 &rootx, &rooty, &x, &y, &mask)) {
2865 if (child)
2866 return;
2867 }
2868 }
2869
2870 /* Let the input method know focus has arrived. */
2871 _XawImSetFocusValues(w, NULL, 0);
2872
2873 if (display_caret)
2874 StartAction(ctx, event);
2875 ctx->text.hasfocus = TRUE;
2876 if (display_caret)
2877 EndAction(ctx);
2878
2879 for (i = 0; (Cardinal)i < num_focus; i++)
2880 if (focus[i].display == XtDisplay(w))
2881 break;
2882 if ((Cardinal)i >= num_focus) {
2883 focus = (struct _focus*)
2884 XtRealloc((XtPointer)focus, (Cardinal)(sizeof(struct _focus) * (num_focus + 1)));
2885 i = (int)num_focus;
2886 focus[i].widget = NULL;
2887 focus[i].display = XtDisplay(w);
2888 num_focus++;
2889 }
2890 if (focus[i].widget != w) {
2891 Widget old = focus[i].widget;
2892
2893 focus[i].widget = w;
2894 if (old != NULL) {
2895 TextFocusOut(old, event, p, n);
2896 /* TextFocusOut may set it to NULL */
2897 focus[i].widget = w;
2898 }
2899 XtAddCallback(w, XtNdestroyCallback,
2900 DestroyFocusCallback, (XtPointer)&focus[i]);
2901 }
2902 }
2903
2904 /*ARGSUSED*/
2905 static void
TextFocusOut(Widget w,XEvent * event,String * p _X_UNUSED,Cardinal * n _X_UNUSED)2906 TextFocusOut(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
2907 {
2908 TextWidget ctx = (TextWidget)w;
2909 Bool display_caret = ctx->text.display_caret;
2910 Widget shell;
2911 Window window;
2912 int i, revert;
2913
2914 shell = w;
2915 while (shell) {
2916 if (XtIsShell(shell))
2917 break;
2918 shell = XtParent(shell);
2919 }
2920
2921 for (i = 0; (Cardinal)i < num_focus; i++)
2922 if (focus[i].display == XtDisplay(w))
2923 break;
2924 XGetInputFocus(XtDisplay(w), &window, &revert);
2925 if ((XtWindow(shell) == window &&
2926 ((Cardinal)i < num_focus && focus[i].widget == w))
2927 || event->xfocus.detail == NotifyPointer)
2928 return;
2929
2930 if ((Cardinal)i < num_focus && focus[i].widget) {
2931 XtRemoveCallback(focus[i].widget, XtNdestroyCallback,
2932 DestroyFocusCallback, (XtPointer)&focus[i]);
2933 focus[i].widget = NULL;
2934 }
2935
2936 /* Let the input method know focus has left.*/
2937 _XawImUnsetFocus(w);
2938
2939 if (display_caret)
2940 StartAction(ctx, event);
2941 ctx->text.hasfocus = FALSE;
2942 if (display_caret)
2943 EndAction(ctx);
2944 }
2945
2946 /*ARGSUSED*/
2947 static void
TextEnterWindow(Widget w,XEvent * event,String * params _X_UNUSED,Cardinal * num_params _X_UNUSED)2948 TextEnterWindow(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
2949 {
2950 TextWidget ctx = (TextWidget)w;
2951
2952 if ((event->xcrossing.detail != NotifyInferior) && event->xcrossing.focus
2953 && !ctx->text.hasfocus)
2954 _XawImSetFocusValues(w, NULL, 0);
2955 }
2956
2957 /*ARGSUSED*/
2958 static void
TextLeaveWindow(Widget w,XEvent * event,String * params _X_UNUSED,Cardinal * num_params _X_UNUSED)2959 TextLeaveWindow(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
2960 {
2961 TextWidget ctx = (TextWidget)w;
2962
2963 if ((event->xcrossing.detail != NotifyInferior) && event->xcrossing.focus
2964 && !ctx->text.hasfocus)
2965 _XawImUnsetFocus(w);
2966 }
2967
2968 /*
2969 * Function:
2970 * AutoFill
2971 * Arguments: ctx - The text widget.
2972 *
2973 * Description:
2974 * Breaks the line at the previous word boundry when
2975 * called inside InsertChar.
2976 */
2977 static void
AutoFill(TextWidget ctx)2978 AutoFill(TextWidget ctx)
2979 {
2980 int width, height, x, line_num, max_width;
2981 XawTextPosition ret_pos;
2982 XawTextBlock text;
2983 XRectangle cursor;
2984 wchar_t wc_buf[2];
2985
2986 for (line_num = 0; line_num < ctx->text.lt.lines ; line_num++)
2987 if (ctx->text.lt.info[line_num].position >= ctx->text.insertPos)
2988 break;
2989 if (line_num)
2990 line_num--; /* backup a line. */
2991
2992 XawTextSinkGetCursorBounds(ctx->text.sink, &cursor);
2993 max_width = Max(0, (int)XtWidth(ctx) - RHMargins(ctx) - cursor.width);
2994
2995 x = ctx->text.r_margin.left;
2996 XawTextSinkFindPosition(ctx->text.sink, ctx->text.lt.info[line_num].position,
2997 x, max_width, True, &ret_pos,
2998 &width, &height);
2999
3000 if (ret_pos <= ctx->text.lt.info[line_num].position
3001 || ret_pos >= ctx->text.insertPos || ret_pos < 1)
3002 return;
3003
3004 XawTextSourceRead(ctx->text.source, ret_pos - 1, &text, 1);
3005
3006 if (XawTextFormat(ctx, XawFmtWide)) {
3007 wc_buf[0] = *(wchar_t *)text.ptr;
3008 if (wc_buf[0] != _Xaw_atowc(XawSP) && wc_buf[0] != _Xaw_atowc(XawTAB))
3009 /* Only eats white spaces */
3010 return;
3011
3012 text.format = XawFmtWide;
3013 text.ptr = (char *)wc_buf;
3014 wc_buf[0] = _Xaw_atowc(XawLF);
3015 wc_buf[1] = 0;
3016 }
3017 else {
3018 if (text.ptr[0] != XawSP && text.ptr[0] != XawTAB)
3019 /* Only eats white spaces */
3020 return;
3021
3022 text.format = XawFmt8Bit;
3023 text.ptr = "\n";
3024 }
3025 text.length = 1;
3026 text.firstPos = 0;
3027
3028 if (_XawTextReplace(ctx, ret_pos - 1, ret_pos, &text))
3029 XBell(XtDisplay((Widget)ctx), 0);
3030
3031 if (++ctx->text.insertPos > ctx->text.lastPos)
3032 ctx->text.insertPos = ctx->text.lastPos;
3033 }
3034
3035 /*ARGSUSED*/
3036 static void
InsertChar(Widget w,XEvent * event,String * p _X_UNUSED,Cardinal * n _X_UNUSED)3037 InsertChar(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
3038 {
3039 TextWidget ctx = (TextWidget)w;
3040 char *ptr, strbuf[128], ptrbuf[512];
3041 int count, error, mult = MULT(ctx);
3042 KeySym keysym;
3043 XawTextBlock text;
3044 #ifndef OLDXAW
3045 Bool format = False;
3046 #endif
3047 XawTextPosition from, to;
3048
3049 if (XtIsSubclass (ctx->text.source, (WidgetClass) multiSrcObjectClass))
3050 text.length = _XawImWcLookupString(w, &event->xkey, (wchar_t*)strbuf,
3051 sizeof(strbuf), &keysym);
3052 else
3053 text.length = _XawLookupString(w, (XKeyEvent*)event, strbuf,
3054 sizeof(strbuf), &keysym);
3055
3056 if (text.length == 0)
3057 return;
3058
3059 if (mult < 0) {
3060 ctx->text.mult = 1;
3061 return;
3062 }
3063
3064 text.format = (unsigned long)_XawTextFormat(ctx);
3065 if (text.format == XawFmtWide) {
3066 text.ptr = ptr = XawStackAlloc(sizeof(wchar_t) * (size_t)text.length
3067 * (size_t)mult, ptrbuf);
3068 for (count = 0; count < mult; count++) {
3069 memcpy((char*)ptr, (char *)strbuf, sizeof(wchar_t) * (size_t)text.length);
3070 ptr += sizeof(wchar_t) * (size_t)text.length;
3071 }
3072 #ifndef OLDXAW
3073 if (mult == 1)
3074 format = ctx->text.left_column < ctx->text.right_column;
3075 #endif
3076 }
3077 else { /* == XawFmt8Bit */
3078 text.ptr = ptr = XawStackAlloc((unsigned)(text.length * mult), ptrbuf);
3079 for (count = 0; count < mult; count++) {
3080 strncpy(ptr, strbuf, (size_t)text.length);
3081 ptr += text.length;
3082 }
3083 #ifndef OLDXAW
3084 if (mult == 1)
3085 format = ctx->text.left_column < ctx->text.right_column;
3086 #endif
3087 }
3088
3089 text.length = text.length * mult;
3090 text.firstPos = 0;
3091
3092 StartAction(ctx, event);
3093 #ifndef OLDXAW
3094 if (mult == 1)
3095 _XawSourceSetUndoMerge((TextSrcObject)ctx->text.source, True);
3096 #endif
3097
3098 from = ctx->text.insertPos;
3099 #ifndef OLDXAW
3100 if (ctx->text.overwrite) {
3101 XawTextPosition tmp;
3102
3103 to = from + mult;
3104 tmp = SrcScan(ctx->text.source, from, XawstEOL, XawsdRight, 1, False);
3105 if (to > tmp)
3106 to = tmp;
3107 }
3108 else
3109 #endif
3110 to = from;
3111
3112 error = _XawTextReplace(ctx, from , to, &text);
3113
3114 if (error == XawEditDone) {
3115 ctx->text.from_left = -1;
3116 ctx->text.insertPos = SrcScan(ctx->text.source, ctx->text.old_insert,
3117 XawstPositions, XawsdRight,
3118 text.length, True);
3119 if (ctx->text.auto_fill) {
3120 #ifndef OLDXAW
3121 if (format)
3122 (void)FormatText(ctx, SrcScan(ctx->text.source,
3123 ctx->text.insertPos, XawstEOL,
3124 XawsdLeft, 1, False), False,
3125 NULL, 0);
3126 else
3127 #endif
3128 AutoFill(ctx);
3129 }
3130 }
3131 else
3132 XBell(XtDisplay(ctx), 50);
3133
3134 XawStackFree(text.ptr, ptrbuf);
3135 EndAction(ctx);
3136
3137 if (error == XawEditDone && text.format == XawFmt8Bit && text.length == 1
3138 && (text.ptr[0] == ')' || text.ptr[0] == ']' || text.ptr[0] == '}')
3139 && ctx->text.display_caret) {
3140 static struct timeval tmval = {0, 500000};
3141 fd_set fds;
3142 Widget source = ctx->text.source;
3143 XawTextPosition insertPos = ctx->text.insertPos, pos, tmp, last;
3144 char left, right = text.ptr[0];
3145 int level = 0;
3146 XtAppContext app_context = XtWidgetToApplicationContext(w);
3147
3148 left = right == ')' ? '(' : right == ']' ? '[' : '{';
3149
3150 last = insertPos - 1;
3151 do {
3152 text.ptr[0] = left;
3153 pos = XawTextSourceSearch(source, last, XawsdLeft, &text);
3154 if (pos == XawTextSearchError || !IsPositionVisible(ctx, pos))
3155 return;
3156 text.ptr[0] = right;
3157 tmp = pos;
3158 do {
3159 tmp = XawTextSourceSearch(source, tmp, XawsdRight, &text);
3160 if (tmp == XawTextSearchError)
3161 return;
3162 if (tmp <= last)
3163 ++level;
3164 } while (++tmp <= last);
3165 --level;
3166 last = pos;
3167 } while (level);
3168
3169 StartAction(ctx, NULL);
3170 #ifndef OLDXAW
3171 _XawSourceSetUndoMerge((TextSrcObject)ctx->text.source, True);
3172 #endif
3173 ctx->text.insertPos = pos;
3174 EndAction(ctx);
3175
3176 XSync(XtDisplay(w), False);
3177 while (XtAppPending(app_context) & XtIMXEvent) {
3178 XEvent ev;
3179 if (! XtAppPeekEvent(app_context, &ev))
3180 break;
3181 if (ev.type == KeyPress || ev.type == ButtonPress)
3182 break;
3183 XtAppProcessEvent(app_context, XtIMXEvent);
3184 }
3185 FD_ZERO(&fds);
3186 FD_SET(ConnectionNumber(XtDisplay(w)), &fds);
3187 (void)select(FD_SETSIZE, &fds, NULL, NULL, &tmval);
3188 if (tmval.tv_usec != 500000)
3189 usleep(40000);
3190
3191 StartAction(ctx, NULL);
3192 #ifndef OLDXAW
3193 _XawSourceSetUndoMerge((TextSrcObject)ctx->text.source, True);
3194 #endif
3195 ctx->text.insertPos = insertPos;
3196 EndAction(ctx);
3197 }
3198 }
3199
3200 /* IfHexConvertHexElseReturnParam() - called by InsertString
3201 *
3202 * i18n requires the ability to specify multiple characters in a hexa-
3203 * decimal string at once. Since Insert was already too long, I made
3204 * this a seperate routine.
3205 *
3206 * A legal hex string in MBNF: '0' 'x' ( HEX-DIGIT HEX-DIGIT )+ '\0'
3207 *
3208 * WHEN: the passed param is a legal hex string
3209 * RETURNS: a pointer to that converted, null terminated hex string;
3210 * len_return holds the character count of conversion result
3211 *
3212 * WHEN: the passed param is not a legal hex string:
3213 * RETURNS: the parameter passed;
3214 * len_return holds the char count of param.
3215 *
3216 * NOTE: In neither case will there be strings to free. */
3217 static char *
IfHexConvertHexElseReturnParam(char * param,int * len_return)3218 IfHexConvertHexElseReturnParam(char *param, int *len_return)
3219 {
3220 char *p; /* steps through param char by char */
3221 char c; /* holds the character pointed to by p */
3222 int ind; /* steps through hexval buffer char by char */
3223 static char hexval[XawTextActionMaxHexChars];
3224 Boolean first_digit;
3225
3226 /* reject if it doesn't begin with 0x and at least one more character. */
3227 if ((param[0] != '0') || (param[1] != 'x') || (param[2] == '\0')) {
3228 *len_return = (int)strlen(param);
3229 return(param);
3230 }
3231
3232 /* Skip the 0x; go character by character shifting and adding. */
3233 first_digit = True;
3234 ind = 0;
3235 hexval[ind] = '\0';
3236
3237 for (p = param+2; (c = *p) != '\0'; p++) {
3238 hexval[ind] = (char)(hexval[ind] * 16);
3239 if (c >= '0' && c <= '9')
3240 hexval[ind] = (char)(hexval[ind] + (c - '0'));
3241 else if (c >= 'a' && c <= 'f')
3242 hexval[ind] = (char)(hexval[ind] + (c - 'a' + 10));
3243 else if (c >= 'A' && c <= 'F')
3244 hexval[ind] = (char)(hexval[ind] + (c - 'A' + 10));
3245 else
3246 break;
3247
3248 /* If we didn't break in preceding line, it was a good hex char. */
3249 if (first_digit)
3250 first_digit = False;
3251 else {
3252 first_digit = True;
3253 if (++ind < XawTextActionMaxHexChars)
3254 hexval[ind] = '\0';
3255 else {
3256 *len_return = (int)strlen(param);
3257 return(param);
3258 }
3259 }
3260 }
3261
3262 /* We quit the above loop becasue we hit a non hex. If that char is \0... */
3263 if ((c == '\0') && first_digit) {
3264 *len_return = (int)strlen(hexval);
3265 return (hexval); /* ...it was a legal hex string, so return it */
3266 }
3267
3268 /* Else, there were non-hex chars or odd digit count, so... */
3269
3270 *len_return = (int)strlen(param);
3271 return (param); /* ...return the verbatim string. */
3272 }
3273
3274 /* InsertString() - action
3275 *
3276 * Mostly rewritten for R6 i18n.
3277 *
3278 * Each parameter, in turn, will be insert at the inputPos
3279 * and the inputPos advances to the insertion's end.
3280 *
3281 * The exception is that parameters composed of the two
3282 * characters 0x, followed only by an even number of
3283 * hexadecimal digits will be converted to characters */
3284 /*ARGSUSED*/
3285 static void
InsertString(Widget w,XEvent * event,String * params,Cardinal * num_params)3286 InsertString(Widget w, XEvent *event, String *params, Cardinal *num_params)
3287 {
3288 TextWidget ctx = (TextWidget)w;
3289 XtAppContext app_con = XtWidgetToApplicationContext(w);
3290 XawTextBlock text;
3291 int i;
3292
3293 text.firstPos = 0;
3294 text.format = (unsigned long)_XawTextFormat(ctx);
3295
3296 StartAction(ctx, event);
3297 for (i = (int)*num_params; i; i--, params++) { /* DO FOR EACH PARAMETER */
3298 text.ptr = IfHexConvertHexElseReturnParam(*params, &text.length);
3299
3300 if (text.length == 0)
3301 continue;
3302
3303 if (XawTextFormat(ctx, XawFmtWide)) { /* convert to WC */
3304 int temp_len;
3305
3306 text.ptr = (char*)_XawTextMBToWC(XtDisplay(w), text.ptr,
3307 &text.length);
3308
3309 if (text.ptr == NULL) { /* conversion error */
3310 XtAppWarningMsg(app_con,
3311 "insertString", "textAction", "XawError",
3312 "insert-string()'s parameter contents "
3313 "not legal in this locale.",
3314 NULL, NULL);
3315 ParameterError(w, *params);
3316 continue;
3317 }
3318
3319 /* Double check that the new input is legal: try to convert to MB. */
3320
3321 temp_len = text.length; /* _XawTextWCToMB's 3rd arg is in_out */
3322 if (_XawTextWCToMB(XtDisplay(w), (wchar_t*)text.ptr, &temp_len)
3323 == NULL) {
3324 XtAppWarningMsg( app_con,
3325 "insertString", "textAction", "XawError",
3326 "insert-string()'s parameter contents "
3327 "not legal in this locale.",
3328 NULL, NULL);
3329 ParameterError(w, *params);
3330 continue;
3331 }
3332 } /* convert to WC */
3333
3334 if (_XawTextReplace(ctx, ctx->text.insertPos,
3335 ctx->text.insertPos, &text)) {
3336 XBell(XtDisplay(ctx), 50);
3337 EndAction(ctx);
3338 return;
3339 }
3340
3341 ctx->text.from_left = -1;
3342 /* Advance insertPos to the end of the string we just inserted. */
3343 ctx->text.insertPos = SrcScan(ctx->text.source, ctx->text.old_insert,
3344 XawstPositions, XawsdRight, text.length,
3345 True);
3346
3347 } /* DO FOR EACH PARAMETER */
3348
3349 EndAction(ctx);
3350 }
3351
3352 /* DisplayCaret() - action
3353 *
3354 * The parameter list should contain one boolean value. If the
3355 * argument is true, the cursor will be displayed. If false, not.
3356 *
3357 * The exception is that EnterNotify and LeaveNotify events may
3358 * have a second argument, "always". If they do not, the cursor
3359 * is only affected if the focus member of the event is true. */
3360 static void
DisplayCaret(Widget w,XEvent * event,String * params,Cardinal * num_params)3361 DisplayCaret(Widget w, XEvent *event, String *params, Cardinal *num_params)
3362 {
3363 TextWidget ctx = (TextWidget)w;
3364 Bool display_caret = True;
3365
3366 if ((event->type == EnterNotify || event->type == LeaveNotify)
3367 && ((*num_params >= 2) && (strcmp(params[1], "always") == 0))
3368 && (!event->xcrossing.focus))
3369 return;
3370
3371 if (*num_params > 0) { /* default arg is "True" */
3372 XrmValue from, to;
3373 from.size = (unsigned)strlen(from.addr = params[0]);
3374 XtConvert(w, XtRString, &from, XtRBoolean, &to);
3375
3376 if (to.addr != NULL)
3377 display_caret = *(Boolean*)to.addr;
3378 if (ctx->text.display_caret == display_caret)
3379 return;
3380 }
3381 StartAction(ctx, event);
3382 ctx->text.display_caret = (Boolean)display_caret;
3383 EndAction(ctx);
3384 }
3385
3386 #ifndef OLDXAW
3387 static void
Numeric(Widget w,XEvent * event,String * params,Cardinal * num_params)3388 Numeric(Widget w, XEvent *event, String *params, Cardinal *num_params)
3389 {
3390 TextWidget ctx = (TextWidget)w;
3391
3392 if (ctx->text.numeric) {
3393 long mult = ctx->text.mult;
3394
3395 if (*num_params != 1 || strlen(params[0]) != 1
3396 || (!isdigit(params[0][0])
3397 && (params[0][0] != '-' || mult != 0))) {
3398 char err_buf[256];
3399
3400 if (event && (event->type == KeyPress || event->type == KeyRelease)
3401 && params[0][0] == '-') {
3402 InsertChar(w, event, params, num_params);
3403 return;
3404 }
3405 snprintf(err_buf, sizeof(err_buf),
3406 "numeric: Invalid argument%s'%s'",
3407 *num_params ? ", " : "",
3408 *num_params ? params[0] : "");
3409 XtAppWarning(XtWidgetToApplicationContext(w), err_buf);
3410 ctx->text.numeric = False;
3411 ctx->text.mult = 1;
3412 return;
3413 }
3414 if (params[0][0] == '-') {
3415 ctx->text.mult = 32767;
3416 return;
3417 }
3418 else if (mult == 32767) {
3419 mult = ctx->text.mult = (short)(- (params[0][0] - '0'));
3420 return;
3421 }
3422 else {
3423 mult = mult * 10 + (params[0][0] - '0') * (mult < 0 ? -1 : 1);
3424 ctx->text.mult = (short)(ctx->text.mult * 10 + (params[0][0] - '0') *
3425 (mult < 0 ? -1 : 1));
3426 }
3427 if (mult != ctx->text.mult || mult >= 32767) { /* checks for overflow */
3428 XBell(XtDisplay(w), 0);
3429 ctx->text.mult = 1;
3430 ctx->text.numeric = False;
3431 return;
3432 }
3433 }
3434 else
3435 InsertChar(w, event, params, num_params);
3436 }
3437
3438 /*ARGSUSED*/
3439 static void
KeyboardReset(Widget w,XEvent * event _X_UNUSED,String * params _X_UNUSED,Cardinal * num_params _X_UNUSED)3440 KeyboardReset(Widget w, XEvent *event _X_UNUSED, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
3441 {
3442 TextWidget ctx = (TextWidget)w;
3443
3444 ctx->text.numeric = False;
3445 ctx->text.mult = 1;
3446
3447 (void)_XawTextSrcToggleUndo((TextSrcObject)ctx->text.source);
3448
3449 if (ctx->text.kill_ring_ptr) {
3450 --ctx->text.kill_ring_ptr->refcount;
3451 ctx->text.kill_ring_ptr = NULL;
3452 }
3453 ctx->text.kill_ring = 0;
3454
3455 XBell(XtDisplay(w), 0);
3456 }
3457 #endif /* OLDXAW */
3458
3459 /* Multiply() - action
3460 *
3461 * The parameter list may contain either a number or the string 'Reset'.
3462 *
3463 * A number will multiply the current multiplication factor by that number.
3464 * Many of the text widget actions will will perform n actions, where n is
3465 * the multiplication factor.
3466 *
3467 * The string reset will reset the mutiplication factor to 1. */
3468 /*ARGSUSED*/
3469 static void
Multiply(Widget w,XEvent * event _X_UNUSED,String * params,Cardinal * num_params)3470 Multiply(Widget w, XEvent *event _X_UNUSED, String *params, Cardinal *num_params)
3471 {
3472 TextWidget ctx = (TextWidget)w;
3473 int mult;
3474
3475 if (*num_params != 1) {
3476 XtAppError(XtWidgetToApplicationContext(w),
3477 "Xaw Text Widget: multiply() takes exactly one argument.");
3478 XBell(XtDisplay(w), 0);
3479 return;
3480 }
3481
3482 if ((params[0][0] == 'r') || (params[0][0] == 'R')) {
3483 XBell(XtDisplay(w), 0);
3484 #ifndef OLDXAW
3485 ctx->text.numeric = False;
3486 #endif
3487 ctx->text.mult = 1;
3488 return;
3489 }
3490
3491 #ifndef OLDXAW
3492 if (params[0][0] == 's' || params[0][0] == 'S') {
3493 ctx->text.numeric = True;
3494 ctx->text.mult = 0;
3495 return;
3496 }
3497 else
3498 #endif
3499 if ((mult = atoi(params[0])) == 0) {
3500 char buf[BUFSIZ];
3501
3502 snprintf(buf, sizeof(buf),
3503 "Xaw Text Widget: multiply() argument "
3504 "must be a number greater than zero, or 'Reset'.");
3505 XtAppError(XtWidgetToApplicationContext(w), buf);
3506 XBell(XtDisplay(w), 50);
3507 return;
3508 }
3509
3510 ctx->text.mult = (short)(ctx->text.mult * mult);
3511 }
3512
3513 /* StripOutOldCRs() - called from FormRegion
3514 *
3515 * removes CRs in widget ctx, from from to to.
3516 *
3517 * RETURNS: the new ending location (we may add some characters),
3518 * or XawReplaceError if the widget can't be written to. */
3519 static XawTextPosition
StripOutOldCRs(TextWidget ctx,XawTextPosition from,XawTextPosition to,XawTextPosition * pos,int num_pos)3520 StripOutOldCRs(TextWidget ctx, XawTextPosition from, XawTextPosition to,
3521 XawTextPosition *pos, int num_pos)
3522 {
3523 XawTextPosition startPos, endPos, eop_begin, eop_end, temp;
3524 Widget src = ctx->text.source;
3525 XawTextBlock text;
3526 char *buf;
3527 static wchar_t wc_two_spaces[3];
3528 int idx;
3529
3530 /* Initialize our TextBlock with two spaces. */
3531 text.firstPos = 0;
3532 text.format = (unsigned long)_XawTextFormat(ctx);
3533 if (text.format == XawFmt8Bit)
3534 text.ptr= " ";
3535 else {
3536 wc_two_spaces[0] = _Xaw_atowc(XawSP);
3537 wc_two_spaces[1] = _Xaw_atowc(XawSP);
3538 wc_two_spaces[2] = 0;
3539 text.ptr = (char*)wc_two_spaces;
3540 }
3541
3542 /* Strip out CR's. */
3543 eop_begin = eop_end = startPos = endPos = from;
3544
3545 /* CONSTCOND */
3546 while (TRUE) {
3547 endPos=SrcScan(src, startPos, XawstEOL, XawsdRight, 1, False);
3548
3549 temp = SrcScan(src, endPos, XawstWhiteSpace, XawsdLeft, 1, False);
3550 temp = SrcScan(src, temp, XawstWhiteSpace, XawsdRight,1, False);
3551
3552 if (temp > startPos)
3553 endPos = temp;
3554
3555 if (endPos >= to)
3556 break;
3557
3558 if (endPos >= eop_begin) {
3559 startPos = eop_end;
3560 eop_begin=SrcScan(src, startPos, XawstParagraph,
3561 XawsdRight, 1,False);
3562 eop_end = SrcScan(src, startPos, XawstParagraph,
3563 XawsdRight, 1, True);
3564 }
3565 else {
3566 XawTextPosition periodPos, next_word;
3567 int i, len;
3568
3569 periodPos = SrcScan(src, endPos, XawstPositions,
3570 XawsdLeft, 1, True);
3571 next_word = SrcScan(src, endPos, XawstWhiteSpace,
3572 XawsdRight, 1, False);
3573
3574 len = (int)(next_word - periodPos);
3575
3576 text.length = 1;
3577 buf = _XawTextGetText(ctx, periodPos, next_word);
3578 if (text.format == XawFmtWide) {
3579 if (periodPos < endPos && ((wchar_t*)buf)[0] == _Xaw_atowc('.'))
3580 text.length++;
3581 }
3582 else
3583 if (periodPos < endPos && buf[0] == '.')
3584 text.length++; /* Put in two spaces. */
3585
3586 /*
3587 * Remove all extra spaces.
3588 */
3589 for (i = 1 ; i < len; i++)
3590 if (text.format == XawFmtWide) {
3591 if (!iswspace(((wchar_t*)buf)[i]) || ((periodPos + i) >= to))
3592 break;
3593 }
3594 else if (!isspace(buf[i]) || (periodPos + i) >= to)
3595 break;
3596
3597 XtFree(buf);
3598
3599 to -= (i - text.length - 1);
3600 startPos = SrcScan(src, periodPos, XawstPositions,
3601 XawsdRight, i, True);
3602 if (_XawTextReplace(ctx, endPos, startPos, &text) != XawEditDone)
3603 return (XawReplaceError);
3604
3605 for (idx = 0; idx < num_pos; idx++) {
3606 if (endPos < pos[idx]) {
3607 if (startPos < pos[idx])
3608 pos[idx] -= startPos - endPos;
3609 else
3610 pos[idx] = endPos;
3611 pos[idx] += text.length;
3612 }
3613 }
3614
3615 startPos -= i - text.length;
3616 }
3617 }
3618
3619 return (to);
3620 }
3621
3622 /* InsertNewCRs() - called from FormRegion
3623 *
3624 * inserts new CRs for FormRegion, thus for FormParagraph action */
3625 static void
InsertNewCRs(TextWidget ctx,XawTextPosition from,XawTextPosition to,XawTextPosition * pos,int num_pos)3626 InsertNewCRs(TextWidget ctx, XawTextPosition from, XawTextPosition to,
3627 XawTextPosition *pos, int num_pos)
3628 {
3629 XawTextPosition startPos, endPos, space, eol;
3630 XawTextBlock text;
3631 int i, width, height, len, wwidth, idx;
3632 char *buf;
3633 static wchar_t wide_CR[2];
3634
3635 text.firstPos = 0;
3636 text.length = 1;
3637 text.format = (unsigned long)_XawTextFormat(ctx);
3638
3639 if (text.format == XawFmt8Bit)
3640 text.ptr = "\n";
3641 else {
3642 wide_CR[0] = _Xaw_atowc(XawLF);
3643 wide_CR[1] = 0;
3644 text.ptr = (char*)wide_CR;
3645 }
3646
3647 startPos = from;
3648
3649 wwidth = (int)XtWidth(ctx) - (int)HMargins(ctx);
3650 if (ctx->text.wrap != XawtextWrapNever) {
3651 XRectangle cursor;
3652
3653 XawTextSinkGetCursorBounds(ctx->text.sink, &cursor);
3654 wwidth -= (int)cursor.width;
3655 }
3656 wwidth = XawMax(0, wwidth);
3657
3658 /* CONSTCOND */
3659 while (TRUE) {
3660 XawTextSinkFindPosition(ctx->text.sink, startPos,
3661 (int)ctx->text.r_margin.left, wwidth,
3662 True, &eol, &width, &height);
3663 if (eol == startPos)
3664 ++eol;
3665 if (eol >= to)
3666 break;
3667
3668 eol = SrcScan(ctx->text.source, eol, XawstPositions,
3669 XawsdLeft, 1, True);
3670 space = SrcScan(ctx->text.source, eol, XawstWhiteSpace,
3671 XawsdRight,1, True);
3672
3673 startPos = endPos = eol;
3674 if (eol == space)
3675 return;
3676
3677 len = (int)(space - eol);
3678 buf = _XawTextGetText(ctx, eol, space);
3679 for (i = 0 ; i < len ; i++)
3680 if (text.format == XawFmtWide) {
3681 if (!iswspace(((wchar_t*)buf)[i]))
3682 break;
3683 }
3684 else if (!isspace(buf[i]))
3685 break;
3686
3687 to -= (i - 1);
3688 endPos = SrcScan(ctx->text.source, endPos,
3689 XawstPositions, XawsdRight, i, True);
3690 XtFree(buf);
3691
3692 if (_XawTextReplace(ctx, startPos, endPos, &text))
3693 return;
3694
3695 for (idx = 0; idx < num_pos; idx++) {
3696 if (startPos < pos[idx]) {
3697 if (endPos < pos[idx])
3698 pos[idx] -= endPos - startPos;
3699 else
3700 pos[idx] = startPos;
3701 pos[idx] += text.length;
3702 }
3703 }
3704
3705 startPos = SrcScan(ctx->text.source, startPos,
3706 XawstPositions, XawsdRight, 1, True);
3707 }
3708 }
3709
3710 /* FormRegion() - called by FormParagraph
3711 *
3712 * oversees the work of paragraph-forming a region
3713 *
3714 * Return:
3715 * XawEditDone if successful, or XawReplaceError
3716 */
3717 static int
FormRegion(TextWidget ctx,XawTextPosition from,XawTextPosition to,XawTextPosition * pos,int num_pos)3718 FormRegion(TextWidget ctx, XawTextPosition from, XawTextPosition to,
3719 XawTextPosition *pos, int num_pos)
3720 {
3721 #ifndef OLDXAW
3722 Bool format = ctx->text.auto_fill
3723 && ctx->text.left_column < ctx->text.right_column;
3724 #endif
3725
3726 if (from >= to)
3727 return (XawEditDone);
3728
3729 #ifndef OLDXAW
3730 if (format) {
3731 XawTextPosition len = ctx->text.lastPos;
3732 int inc = 0;
3733
3734 if (ctx->text.justify == XawjustifyLeft ||
3735 ctx->text.justify == XawjustifyFull) {
3736 Untabify(ctx, from, to, pos, num_pos, NULL);
3737 to += ctx->text.lastPos - len;
3738 len = ctx->text.insertPos;
3739 (void)BlankLine((Widget)ctx, from, &inc);
3740 if (from + inc >= to)
3741 return (XawEditDone);
3742 }
3743 if (!StripSpaces(ctx, from + inc, to, pos, num_pos, NULL))
3744 return (XawReplaceError);
3745 to += ctx->text.lastPos - len;
3746
3747 FormatText(ctx, from, ctx->text.justify != XawjustifyFull, pos, num_pos);
3748 }
3749 else {
3750 #endif
3751 if ((to = StripOutOldCRs(ctx, from, to, pos, num_pos)) == XawReplaceError)
3752 return (XawReplaceError);
3753 InsertNewCRs(ctx, from, to, pos, num_pos);
3754 #ifndef OLDXAW
3755 }
3756 #endif
3757 ctx->text.from_left = -1;
3758
3759 return (XawEditDone);
3760 }
3761
3762 #ifndef OLDXAW
3763 static Bool
BlankLine(Widget w,XawTextPosition pos,int * blanks_return)3764 BlankLine(Widget w, XawTextPosition pos, int *blanks_return)
3765 {
3766 int i, blanks = 0;
3767 XawTextBlock block;
3768 Widget src = XawTextGetSource(w);
3769 XawTextPosition l = SrcScan(src, pos, XawstEOL, XawsdLeft, 1, False);
3770 XawTextPosition r = SrcScan(src, pos, XawstEOL, XawsdRight, 1, False);
3771
3772 while (l < r) {
3773 l = XawTextSourceRead(src, l, &block, (int)(r - l));
3774 if (block.length == 0) {
3775 if (blanks_return)
3776 *blanks_return = blanks;
3777 return (True);
3778 }
3779 if (XawTextFormat((TextWidget)w, XawFmt8Bit)) {
3780 for (i = 0; i < block.length; i++, blanks++)
3781 if (block.ptr[i] != ' ' &&
3782 block.ptr[i] != '\t') {
3783 if (blanks_return)
3784 *blanks_return = blanks;
3785 return (block.ptr[i] == '\n');
3786 }
3787 }
3788 else if (XawTextFormat((TextWidget)w, XawFmtWide)) {
3789 for (i = 0; i < block.length; i++, blanks++)
3790 if (_Xaw_atowc(XawSP) != ((wchar_t*)block.ptr)[i] &&
3791 _Xaw_atowc(XawTAB) != ((wchar_t*)block.ptr)[i]) {
3792 if (blanks_return)
3793 *blanks_return = blanks;
3794 return (_Xaw_atowc(XawLF) == ((wchar_t*)block.ptr)[i]);
3795 }
3796 }
3797 }
3798
3799 return (True);
3800 }
3801
3802 static Bool
GetBlockBoundaries(TextWidget ctx,XawTextPosition * from_return,XawTextPosition * to_return)3803 GetBlockBoundaries(TextWidget ctx,
3804 XawTextPosition *from_return, XawTextPosition *to_return)
3805 {
3806 XawTextPosition from, to;
3807
3808 if (ctx->text.auto_fill && ctx->text.left_column < ctx->text.right_column) {
3809 if (ctx->text.s.left != ctx->text.s.right) {
3810 from = SrcScan(ctx->text.source,
3811 XawMin(ctx->text.s.left, ctx->text.s.right),
3812 XawstEOL, XawsdLeft, 1, False);
3813 to = SrcScan(ctx->text.source,
3814 XawMax(ctx->text.s.right, ctx->text.s.right),
3815 XawstEOL, XawsdRight, 1, False);
3816 }
3817 else {
3818 XawTextBlock block;
3819 XawTextPosition tmp;
3820 Bool first;
3821
3822 from = to = ctx->text.insertPos;
3823
3824 /* find from position */
3825 first = True;
3826 while (1) {
3827 tmp = from;
3828 from = SrcScan(ctx->text.source, from, XawstEOL, XawsdLeft,
3829 1 + !first, False);
3830 XawTextSourceRead(ctx->text.source, from, &block, 1);
3831 if (block.length == 0 ||
3832 (XawTextFormat(ctx, XawFmt8Bit) &&
3833 block.ptr[0] != ' ' &&
3834 block.ptr[0] != '\t' &&
3835 !isalnum(*(unsigned char*)block.ptr)) ||
3836 (XawTextFormat(ctx, XawFmtWide) &&
3837 _Xaw_atowc(XawSP) != *(wchar_t*)block.ptr &&
3838 _Xaw_atowc(XawTAB) != *(wchar_t*)block.ptr &&
3839 !iswalnum((wint_t)*(wchar_t*)block.ptr)) ||
3840 BlankLine((Widget)ctx, from, NULL)) {
3841 from = tmp;
3842 break;
3843 }
3844 if (from == tmp && !first)
3845 break;
3846 first = False;
3847 }
3848 if (first)
3849 return (False);
3850
3851 /* find to position */
3852 first = True;
3853 while (1) {
3854 tmp = to;
3855 to = SrcScan(ctx->text.source, to, XawstEOL, XawsdRight,
3856 1 + !first, False);
3857 XawTextSourceRead(ctx->text.source, to + (to < ctx->text.lastPos),
3858 &block, 1);
3859 if (block.length == 0 ||
3860 (XawTextFormat(ctx, XawFmt8Bit) &&
3861 block.ptr[0] != ' ' &&
3862 block.ptr[0] != '\t' &&
3863 !isalnum(*(unsigned char*)block.ptr)) ||
3864 (XawTextFormat(ctx, XawFmtWide) &&
3865 _Xaw_atowc(XawSP) != *(wchar_t*)block.ptr &&
3866 _Xaw_atowc(XawTAB) != *(wchar_t*)block.ptr &&
3867 !iswalnum((wint_t)*(wchar_t*)block.ptr)) ||
3868 BlankLine((Widget)ctx, to, NULL))
3869 break;
3870 if (to == tmp && !first)
3871 break;
3872 first = False;
3873 }
3874 }
3875 }
3876 else {
3877 from = SrcScan(ctx->text.source, ctx->text.insertPos, XawstEOL,
3878 XawsdLeft, 1, False);
3879 if (BlankLine((Widget)ctx, from, NULL))
3880 return (False);
3881 from = SrcScan(ctx->text.source, from, XawstParagraph,
3882 XawsdLeft, 1, False);
3883 if (BlankLine((Widget)ctx, from, NULL))
3884 from = SrcScan(ctx->text.source, from, XawstEOL,
3885 XawsdRight, 1, True);
3886 to = SrcScan(ctx->text.source, from, XawstParagraph,
3887 XawsdRight, 1, False);
3888 }
3889
3890 if (from < to) {
3891 *from_return = from;
3892 *to_return = to;
3893 return (True);
3894 }
3895
3896 return (False);
3897 }
3898 #endif /* OLDXAW */
3899
3900 /* FormParagraph() - action
3901 *
3902 * removes and reinserts CRs to maximize line length without clipping */
3903 /*ARGSUSED*/
3904 static void
FormParagraph(Widget w,XEvent * event,String * params _X_UNUSED,Cardinal * num_params _X_UNUSED)3905 FormParagraph(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
3906 {
3907 TextWidget ctx = (TextWidget)w;
3908 XawTextPosition from, to, buf[32], *pos;
3909 #ifndef OLDXAW
3910 XawTextPosition endPos = 0;
3911 char *lbuf = NULL, *rbuf;
3912 TextSrcObject src = (TextSrcObject)ctx->text.source;
3913 Cardinal i;
3914 Bool undo = src->textSrc.enable_undo && src->textSrc.undo_state == False;
3915 #endif
3916
3917 StartAction(ctx, event);
3918
3919 #ifndef OLDXAW
3920 pos = XawStackAlloc(sizeof(XawTextPosition) * src->textSrc.num_text, buf);
3921 for (i = 0; i < src->textSrc.num_text; i++)
3922 pos[i] = ((TextWidget)src->textSrc.text[i])->text.old_insert;
3923 #else
3924 pos = buf;
3925 *pos = ctx->text.old_insert;
3926 #endif
3927
3928 #ifndef OLDXAW
3929 if (!GetBlockBoundaries(ctx, &from, &to)) {
3930 EndAction(ctx);
3931 XawStackFree(pos, buf);
3932 return;
3933 }
3934
3935 if (undo) {
3936 src->textSrc.undo_state = True;
3937 lbuf = _XawTextGetText(ctx, from, to);
3938 endPos = ctx->text.lastPos;
3939 }
3940
3941 if (FormRegion(ctx, from, to, pos, (int)src->textSrc.num_text) == XawReplaceError) {
3942 XawStackFree(pos, buf);
3943 pos = buf;
3944 #else
3945 from = SrcScan(ctx->text.source, ctx->text.insertPos,
3946 XawstParagraph, XawsdLeft, 1, False);
3947 to = SrcScan(ctx->text.source, from,
3948 XawstParagraph, XawsdRight, 1, False);
3949
3950 if (FormRegion(ctx, from, to, pos, 1) == XawReplaceError) {
3951 #endif
3952 XBell(XtDisplay(w), 0);
3953 #ifndef OLDXAW
3954 if (undo) {
3955 src->textSrc.undo_state = False;
3956 XtFree(lbuf);
3957 }
3958 #endif
3959 }
3960 #ifndef OLDXAW
3961 else if (undo) {
3962 /* makes the form-paragraph only one undo/redo step */
3963 unsigned llen, rlen, size;
3964 XawTextBlock block;
3965
3966 llen = (unsigned)(to - from);
3967 rlen = (unsigned)(llen + (ctx->text.lastPos - endPos));
3968
3969 block.firstPos = 0;
3970 block.format = (unsigned long)_XawTextFormat(ctx);
3971
3972 rbuf = _XawTextGetText(ctx, from, from + rlen);
3973
3974 size = XawTextFormat(ctx, XawFmtWide) ? sizeof(wchar_t) : sizeof(char);
3975 if (llen != rlen || memcmp(lbuf, rbuf, llen * size)) {
3976 block.ptr = lbuf;
3977 block.length = (int)llen;
3978 _XawTextReplace(ctx, from, from + rlen, &block);
3979
3980 src->textSrc.undo_state = False;
3981 block.ptr = rbuf;
3982 block.length = (int)rlen;
3983 _XawTextReplace(ctx, from, from + llen, &block);
3984 }
3985 else
3986 src->textSrc.undo_state = False;
3987 XtFree(lbuf);
3988 XtFree(rbuf);
3989 }
3990
3991 for (i = 0; i < src->textSrc.num_text; i++) {
3992 TextWidget tw = (TextWidget)src->textSrc.text[i];
3993
3994 tw->text.old_insert = tw->text.insertPos = pos[i];
3995 _XawTextBuildLineTable(tw, SrcScan((Widget)src, tw->text.lt.top, XawstEOL,
3996 XawsdLeft, 1, False), False);
3997 tw->text.clear_to_eol = True;
3998 }
3999 XawStackFree(pos, buf);
4000 #else
4001 ctx->text.old_insert = ctx->text.insertPos = *pos;
4002 _XawTextBuildLineTable(ctx, SrcScan(ctx->text.source, ctx->text.lt.top,
4003 XawstEOL, XawsdLeft, 1, False), False);
4004 ctx->text.clear_to_eol = True;
4005 #endif
4006 ctx->text.showposition = True;
4007
4008 EndAction(ctx);
4009 }
4010
4011 /* TransposeCharacters() - action
4012 *
4013 * Swaps the character to the left of the mark
4014 * with the character to the right of the mark */
4015 /*ARGSUSED*/
4016 static void
4017 TransposeCharacters(Widget w, XEvent *event,
4018 String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
4019 {
4020 TextWidget ctx = (TextWidget)w;
4021 XawTextPosition start, end;
4022 XawTextBlock text;
4023 char *buf;
4024 int i, mult = MULT(ctx);
4025
4026 if (mult < 0) {
4027 ctx->text.mult = 1;
4028 return;
4029 }
4030
4031 StartAction(ctx, event);
4032
4033 /* Get bounds. */
4034
4035 start = SrcScan(ctx->text.source, ctx->text.insertPos, XawstPositions,
4036 XawsdLeft, 1, True);
4037 end = SrcScan(ctx->text.source, ctx->text.insertPos, XawstPositions,
4038 XawsdRight, mult, True);
4039
4040 /* Make sure we aren't at the very beginning or end of the buffer. */
4041
4042 if (start == ctx->text.insertPos || end == ctx->text.insertPos) {
4043 XBell(XtDisplay(w), 0); /* complain. */
4044 EndAction(ctx);
4045 return;
4046 }
4047
4048 ctx->text.from_left = -1;
4049 ctx->text.insertPos = end;
4050
4051 text.firstPos = 0;
4052 text.format = (unsigned long)_XawTextFormat(ctx);
4053
4054 /* Retrieve text and swap the characters. */
4055 if (text.format == XawFmtWide) {
4056 wchar_t wc;
4057 wchar_t *wbuf;
4058
4059 wbuf = (wchar_t*)_XawTextGetText(ctx, start, end);
4060 text.length = (int)wcslen(wbuf);
4061 wc = wbuf[0];
4062 for (i = 1; i < text.length; i++)
4063 wbuf[i - 1] = wbuf[i];
4064 wbuf[i - 1] = wc;
4065 buf = (char*)wbuf; /* so that it gets assigned and freed */
4066 }
4067 else { /* thus text.format == XawFmt8Bit */
4068 char c;
4069
4070 buf = _XawTextGetText(ctx, start, end);
4071 text.length = (int)strlen(buf);
4072 c = buf[0];
4073 for (i = 1; i < text.length; i++)
4074 buf[i - 1] = buf[i];
4075 buf[i - 1] = c;
4076 }
4077
4078 text.ptr = buf;
4079
4080 /* Store new text in source. */
4081
4082 if (_XawTextReplace (ctx, start, end, &text))
4083 XBell(XtDisplay(w), 0);
4084 XtFree((char *)buf);
4085 EndAction(ctx);
4086 }
4087
4088 #ifndef OLDXAW
4089 /*ARGSUSED*/
4090 static void
4091 Undo(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
4092 {
4093 TextWidget ctx = (TextWidget)w;
4094 int mul = MULT(ctx);
4095 Bool toggle = False;
4096
4097 if (mul < 0) {
4098 toggle = True;
4099 _XawTextSrcToggleUndo((TextSrcObject)ctx->text.source);
4100 ctx->text.mult = (short)(mul = -mul);
4101 }
4102
4103 StartAction(ctx, event);
4104 for (; mul; --mul)
4105 if (!_XawTextSrcUndo((TextSrcObject)ctx->text.source, &ctx->text.insertPos))
4106 break;
4107 ctx->text.showposition = True;
4108
4109 if (toggle)
4110 _XawTextSrcToggleUndo((TextSrcObject)ctx->text.source);
4111 EndAction(ctx);
4112 }
4113 #endif
4114
4115 /* NoOp() - action
4116 * This action performs no action, and allows the user or
4117 * application programmer to unbind a translation.
4118 *
4119 * Note: If the parameter list contains the string "RingBell" then
4120 * this action will ring the bell.
4121 */
4122 /*ARGSUSED*/
4123 static void
4124 NoOp(Widget w, XEvent *event _X_UNUSED, String *params, Cardinal *num_params)
4125 {
4126 if (*num_params != 1)
4127 return;
4128
4129 switch(params[0][0]) {
4130 case 'R':
4131 case 'r':
4132 XBell(XtDisplay(w), 0);
4133 /*FALLTROUGH*/
4134 default:
4135 break;
4136 }
4137 }
4138
4139 /* Reconnect() - action
4140 * This reconnects to the input method. The user will typically call
4141 * this action if/when connection has been severed, or when the app
4142 * was started up before an IM was started up
4143 */
4144 /*ARGSUSED*/
4145 static void
4146 Reconnect(Widget w, XEvent *event _X_UNUSED, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
4147 {
4148 _XawImReconnect(w);
4149 }
4150
4151 #define CAPITALIZE 1
4152 #define DOWNCASE 2
4153 #define UPCASE 3
4154
4155 #ifdef NO_LIBC_I18N
4156 static int
4157 ToLower(int ch)
4158 {
4159 char buf[2];
4160
4161 *buf = ch;
4162 XmuNCopyISOLatin1Lowered(buf, buf, sizeof(buf));
4163
4164 return (*buf);
4165 }
4166
4167 static int
4168 ToUpper(int ch)
4169 {
4170 char buf[2];
4171
4172 *buf = ch;
4173 XmuNCopyISOLatin1Uppered(buf, buf, sizeof(buf));
4174
4175 return (*buf);
4176 }
4177
4178 static int
4179 IsAlnum(int ch)
4180 {
4181 return ((ch >= '0' && ch <= '9') || ToUpper(ch) != ch || ToLower(ch) != ch);
4182 }
4183
4184 static int
4185 IsLower(int ch)
4186 {
4187 char upbuf[2];
4188 char lobuf[2];
4189
4190 *upbuf = *lobuf = ch;
4191 XmuNCopyISOLatin1Lowered(lobuf, lobuf, sizeof(lobuf));
4192 XmuNCopyISOLatin1Uppered(upbuf, upbuf, sizeof(upbuf));
4193
4194 return (*lobuf != *upbuf && ch == *lobuf);
4195 }
4196
4197 static int
4198 IsUpper(int ch)
4199 {
4200 char upbuf[2];
4201 char lobuf[2];
4202
4203 *upbuf = *lobuf = ch;
4204 XmuNCopyISOLatin1Lowered(lobuf, lobuf, sizeof(lobuf));
4205 XmuNCopyISOLatin1Uppered(upbuf, upbuf, sizeof(upbuf));
4206
4207 return (*lobuf != *upbuf && ch == *upbuf);
4208 }
4209 #else
4210 #define ToLower tolower
4211 #define ToUpper toupper
4212 #define IsAlnum isalnum
4213 #define IsLower islower
4214 #define IsUpper isupper
4215 #endif
4216
4217 static void
4218 CaseProc(Widget w, XEvent *event, int cmd)
4219 {
4220 TextWidget ctx = (TextWidget)w;
4221 short mul = MULT(ctx);
4222 XawTextPosition left, right;
4223 XawTextBlock block;
4224 Bool changed = False;
4225 unsigned char ch, mb[sizeof(wchar_t)];
4226 int i, count;
4227
4228 if (mul > 0)
4229 right = SrcScan(ctx->text.source, left = ctx->text.insertPos,
4230 XawstAlphaNumeric, XawsdRight, mul, False);
4231 else
4232 left = SrcScan(ctx->text.source, right = ctx->text.insertPos,
4233 XawstAlphaNumeric, XawsdLeft, 1 + -mul, False);
4234 block.firstPos = 0;
4235 block.format = (unsigned long)_XawTextFormat(ctx);
4236 block.length = (int)(right - left);
4237 block.ptr = _XawTextGetText(ctx, left, right);
4238
4239 count = 0;
4240 if (block.format == XawFmt8Bit)
4241 for (i = 0; i < block.length; i++) {
4242 if (!IsAlnum(*mb = (unsigned char)block.ptr[i]))
4243 count = 0;
4244 else if (++count == 1 || cmd != CAPITALIZE) {
4245 ch = (unsigned char)((cmd == DOWNCASE) ? ToLower(*mb) : ToUpper(*mb));
4246 if (ch != *mb) {
4247 changed = True;
4248 block.ptr[i] = (char)ch;
4249 }
4250 }
4251 else if (cmd == CAPITALIZE) {
4252 if ((ch = (unsigned char)(ToLower(*mb))) != *mb) {
4253 changed = True;
4254 block.ptr[i] = (char)ch;
4255 }
4256 }
4257 }
4258 else
4259 for (i = 0; i < block.length; i++) {
4260 wctomb((char*)mb, ((wchar_t*)block.ptr)[i]);
4261 if (!IsAlnum(*mb))
4262 count = 0;
4263 else if (++count == 1 || cmd != CAPITALIZE) {
4264 ch = (unsigned char)((cmd == DOWNCASE) ? ToLower(*mb) : ToUpper(*mb));
4265 if (ch != *mb) {
4266 changed = True;
4267 ((wchar_t*)block.ptr)[i] = _Xaw_atowc(ch);
4268 }
4269 }
4270 else if (cmd == CAPITALIZE) {
4271 if ((ch = (unsigned char)(ToLower(*mb))) != *mb) {
4272 changed = True;
4273 ((wchar_t*)block.ptr)[i] = _Xaw_atowc(ch);
4274 }
4275 }
4276 }
4277
4278 StartAction(ctx, event);
4279 if (changed && _XawTextReplace(ctx, left, right, &block) != XawEditDone)
4280 XBell(XtDisplay(ctx), 0);
4281 ctx->text.insertPos = right;
4282 EndAction(ctx);
4283
4284 XtFree(block.ptr);
4285 }
4286
4287 /*ARGSUSED*/
4288 static void
4289 CapitalizeWord(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
4290 {
4291 CaseProc(w, event, CAPITALIZE);
4292 }
4293
4294 /*ARGSUSED*/
4295 static void
4296 DowncaseWord(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
4297 {
4298 CaseProc(w, event, DOWNCASE);
4299 }
4300
4301 /*ARGSUSED*/
4302 static void
4303 UpcaseWord(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
4304 {
4305 CaseProc(w, event, UPCASE);
4306 }
4307 #undef CAPITALIZE
4308 #undef DOWNCASE
4309 #undef UPCASE
4310
4311 XtActionsRec _XawTextActionsTable[] = {
4312 /* motion */
4313 {"forward-character", MoveForwardChar},
4314 {"backward-character", MoveBackwardChar},
4315 {"forward-word", MoveForwardWord},
4316 {"backward-word", MoveBackwardWord},
4317 {"forward-paragraph", MoveForwardParagraph},
4318 {"backward-paragraph", MoveBackwardParagraph},
4319 {"beginning-of-line", MoveToLineStart},
4320 {"end-of-line", MoveToLineEnd},
4321 {"next-line", MoveNextLine},
4322 {"previous-line", MovePreviousLine},
4323 {"next-page", MoveNextPage},
4324 {"previous-page", MovePreviousPage},
4325 {"beginning-of-file", MoveBeginningOfFile},
4326 {"end-of-file", MoveEndOfFile},
4327 {"scroll-one-line-up", ScrollOneLineUp},
4328 {"scroll-one-line-down", ScrollOneLineDown},
4329
4330 /* delete */
4331 {"delete-next-character", DeleteForwardChar},
4332 {"delete-previous-character", DeleteBackwardChar},
4333 {"delete-next-word", DeleteForwardWord},
4334 {"delete-previous-word", DeleteBackwardWord},
4335 {"delete-selection", DeleteCurrentSelection},
4336 {"delete", Delete},
4337
4338 /* kill */
4339 {"kill-word", KillForwardWord},
4340 {"backward-kill-word", KillBackwardWord},
4341 {"kill-selection", KillCurrentSelection},
4342 {"kill-to-end-of-line", KillToEndOfLine},
4343 {"kill-to-end-of-paragraph", KillToEndOfParagraph},
4344
4345 /* new line */
4346 {"newline-and-indent", InsertNewLineAndIndent},
4347 {"newline-and-backup", InsertNewLineAndBackup},
4348 {"newline", InsertNewLine},
4349
4350 /* selection */
4351 {"select-word", SelectWord},
4352 {"select-all", SelectAll},
4353 {"select-start", SelectStart},
4354 {"select-adjust", SelectAdjust},
4355 {"select-end", SelectEnd},
4356 {"select-save", SelectSave},
4357 {"extend-start", ExtendStart},
4358 {"extend-adjust", ExtendAdjust},
4359 {"extend-end", ExtendEnd},
4360 {"insert-selection", InsertSelection},
4361
4362 /* miscellaneous */
4363 {"redraw-display", RedrawDisplay},
4364 {"insert-file", _XawTextInsertFile},
4365 {"search", _XawTextSearch},
4366 {"insert-char", InsertChar},
4367 {"insert-string", InsertString},
4368 {"focus-in", TextFocusIn},
4369 {"focus-out", TextFocusOut},
4370 {"enter-window", TextEnterWindow},
4371 {"leave-window", TextLeaveWindow},
4372 {"display-caret", DisplayCaret},
4373 {"multiply", Multiply},
4374 {"form-paragraph", FormParagraph},
4375 {"transpose-characters", TransposeCharacters},
4376 {"set-keyboard-focus", SetKeyboardFocus},
4377 #ifndef OLDXAW
4378 {"numeric", Numeric},
4379 {"undo", Undo},
4380 {"keyboard-reset", KeyboardReset},
4381 {"kill-ring-yank", KillRingYank},
4382 {"toggle-overwrite", ToggleOverwrite},
4383 {"indent", Indent},
4384 #endif
4385 {"no-op", NoOp},
4386
4387 /* case transformations */
4388 {"capitalize-word", CapitalizeWord},
4389 {"downcase-word", DowncaseWord},
4390 {"upcase-word", UpcaseWord},
4391
4392 /* action to bind translations for text dialogs */
4393 {"InsertFileAction", _XawTextInsertFileAction},
4394 {"DoSearchAction", _XawTextDoSearchAction},
4395 {"DoReplaceAction", _XawTextDoReplaceAction},
4396 {"SetField", _XawTextSetField},
4397 {"PopdownSearchAction", _XawTextPopdownSearchAction},
4398
4399 /* reconnect to Input Method */
4400 {"reconnect-im", Reconnect} /* Li Yuhong, Omron KK, 1991 */
4401 };
4402
4403 Cardinal _XawTextActionsTableCount = XtNumber(_XawTextActionsTable);
4404