TextAction.c revision e4543249
1/* 2 3Copyright 1989, 1994, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included in 12all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 21Except as contained in this notice, the name of The Open Group shall not be 22used in advertising or otherwise to promote the sale, use or other dealings 23in 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 */ 71static void _DeleteOrKill(TextWidget, XawTextPosition, XawTextPosition, Bool); 72static void _SelectionReceived(Widget, XtPointer, Atom*, Atom*, XtPointer, 73 unsigned long*, int*); 74static void _LoseSelection(Widget, Atom*, char**, int*); 75static void AutoFill(TextWidget); 76static Boolean ConvertSelection(Widget, Atom*, Atom*, Atom*, XtPointer*, 77 unsigned long*, int*); 78static void DeleteOrKill(TextWidget, XEvent*, XawTextScanDirection, 79 XawTextScanType, Bool, Bool); 80static void EndAction(TextWidget); 81#ifndef OLDXAW 82static Bool BlankLine(Widget, XawTextPosition, int*); 83static int DoFormatText(TextWidget, XawTextPosition, Bool, int, 84 XawTextBlock*, XawTextPosition*, int, Bool); 85static int FormatText(TextWidget, XawTextPosition, Bool, 86 XawTextPosition*, int); 87static Bool GetBlockBoundaries(TextWidget, XawTextPosition*, XawTextPosition*); 88#endif 89static int FormRegion(TextWidget, XawTextPosition, XawTextPosition, 90 XawTextPosition*, int); 91static void GetSelection(Widget, Time, String*, Cardinal); 92static char *IfHexConvertHexElseReturnParam(const char*, int*); 93static void InsertNewCRs(TextWidget, XawTextPosition, XawTextPosition, 94 XawTextPosition*, int); 95static int InsertNewLineAndBackupInternal(TextWidget); 96static int LocalInsertNewLine(TextWidget, XEvent*); 97static void LoseSelection(Widget, Atom*); 98static void ParameterError(Widget, String); 99static Bool MatchSelection(Atom, XawTextSelection*); 100static void ModifySelection(TextWidget, XEvent*, XawTextSelectionMode, 101 XawTextSelectionAction, String*, Cardinal*); 102static void Move(TextWidget, XEvent*, XawTextScanDirection, XawTextScanType, 103 Bool); 104static void NotePosition(TextWidget, XEvent*); 105static void StartAction(TextWidget, XEvent*); 106static XawTextPosition StripOutOldCRs(TextWidget, XawTextPosition, 107 XawTextPosition, XawTextPosition*, int); 108#ifndef OLDXAW 109static Bool StripSpaces(TextWidget, XawTextPosition, XawTextPosition, 110 XawTextPosition*, int, XawTextBlock*); 111static Bool Tabify(TextWidget, XawTextPosition, XawTextPosition, 112 XawTextPosition*, int, XawTextBlock*); 113static Bool Untabify(TextWidget, XawTextPosition, XawTextPosition, 114 XawTextPosition*, int, XawTextBlock*); 115#endif 116 117/* 118 * Actions 119 */ 120static void CapitalizeWord(Widget, XEvent*, String*, Cardinal*); 121static void DisplayCaret(Widget, XEvent*, String*, Cardinal*); 122static void Delete(Widget, XEvent*, String*, Cardinal*); 123static void DeleteBackwardChar(Widget, XEvent*, String*, Cardinal*); 124static void DeleteBackwardWord(Widget, XEvent*, String*, Cardinal*); 125static void DeleteCurrentSelection(Widget, XEvent*, String*, Cardinal*); 126static void DeleteForwardChar(Widget, XEvent*, String*, Cardinal*); 127static void DeleteForwardWord(Widget, XEvent*, String*, Cardinal*); 128static void DowncaseWord(Widget, XEvent*, String*, Cardinal*); 129static void ExtendAdjust(Widget, XEvent*, String*, Cardinal*); 130static void ExtendEnd(Widget, XEvent*, String*, Cardinal*); 131static void ExtendStart(Widget, XEvent*, String*, Cardinal*); 132static void FormParagraph(Widget, XEvent*, String*, Cardinal*); 133#ifndef OLDXAW 134static void Indent(Widget, XEvent*, String*, Cardinal*); 135#endif 136static void InsertChar(Widget, XEvent*, String*, Cardinal*); 137static void InsertNewLine(Widget, XEvent*, String*, Cardinal*); 138static void InsertNewLineAndBackup(Widget, XEvent*, String*, Cardinal*); 139static void InsertNewLineAndIndent(Widget, XEvent*, String*, Cardinal*); 140static void InsertSelection(Widget, XEvent*, String*, Cardinal*); 141static void InsertString(Widget, XEvent*, String*, Cardinal*); 142#ifndef OLDXAW 143static void KeyboardReset(Widget, XEvent*, String*, Cardinal*); 144#endif 145static void KillBackwardWord(Widget, XEvent*, String*, Cardinal*); 146static void KillCurrentSelection(Widget, XEvent*, String*, Cardinal*); 147static void KillForwardWord(Widget, XEvent*, String*, Cardinal*); 148#ifndef OLDXAW 149static void KillRingYank(Widget, XEvent*, String*, Cardinal*); 150#endif 151static void KillToEndOfLine(Widget, XEvent*, String*, Cardinal*); 152static void KillToEndOfParagraph(Widget, XEvent*, String*, Cardinal*); 153static void MoveBackwardChar(Widget, XEvent*, String*, Cardinal*); 154static void MoveBackwardWord(Widget, XEvent*, String*, Cardinal*); 155static void MoveBackwardParagraph(Widget, XEvent*, String*, Cardinal*); 156static void MoveBeginningOfFile(Widget, XEvent*, String*, Cardinal*); 157static void MoveEndOfFile(Widget, XEvent*, String*, Cardinal*); 158static void MoveForwardChar(Widget, XEvent*, String*, Cardinal*); 159static void MoveForwardWord(Widget, XEvent*, String*, Cardinal*); 160static void MoveForwardParagraph(Widget, XEvent*, String*, Cardinal*); 161static void MoveNextLine(Widget, XEvent*, String*, Cardinal*); 162static void MoveNextPage(Widget, XEvent*, String*, Cardinal*); 163static void MovePage(TextWidget, XEvent*, XawTextScanDirection); 164static void MovePreviousLine(Widget, XEvent*, String*, Cardinal*); 165static void MovePreviousPage(Widget, XEvent*, String*, Cardinal*); 166static void MoveLine(TextWidget, XEvent*, XawTextScanDirection); 167static void MoveToLineEnd(Widget, XEvent*, String*, Cardinal*); 168static void MoveToLineStart(Widget, XEvent*, String*, Cardinal*); 169static void Multiply(Widget, XEvent*, String*, Cardinal*); 170static void NoOp(Widget, XEvent*, String*, Cardinal*); 171#ifndef OLDXAW 172static void Numeric(Widget, XEvent*, String*, Cardinal*); 173#endif 174static void Reconnect(Widget, XEvent*, String*, Cardinal*); 175static void RedrawDisplay(Widget, XEvent*, String*, Cardinal*); 176static void Scroll(TextWidget, XEvent*, XawTextScanDirection); 177static void ScrollOneLineDown(Widget, XEvent*, String*, Cardinal*); 178static void ScrollOneLineUp(Widget, XEvent*, String*, Cardinal*); 179static void SelectAdjust(Widget, XEvent*, String*, Cardinal*); 180static void SelectAll(Widget, XEvent*, String*, Cardinal*); 181static void SelectEnd(Widget, XEvent*, String*, Cardinal*); 182static void SelectSave(Widget, XEvent*, String*, Cardinal*); 183static void SelectStart(Widget, XEvent*, String*, Cardinal*); 184static void SelectWord(Widget, XEvent*, String*, Cardinal*); 185static void SetKeyboardFocus(Widget, XEvent*, String*, Cardinal*); 186static void TextEnterWindow(Widget, XEvent*, String*, Cardinal*); 187static void TextFocusIn(Widget, XEvent*, String*, Cardinal*); 188static void TextFocusOut(Widget, XEvent*, String*, Cardinal*); 189static void TextLeaveWindow(Widget, XEvent*, String*, Cardinal*); 190static void TransposeCharacters(Widget, XEvent*, String*, Cardinal*); 191#ifndef OLDXAW 192static void ToggleOverwrite(Widget, XEvent*, String*, Cardinal*); 193static void Undo(Widget, XEvent*, String*, Cardinal*); 194#endif 195static void UpcaseWord(Widget, XEvent*, String*, Cardinal*); 196static void DestroyFocusCallback(Widget, XtPointer, XtPointer); 197 198/* 199 * External 200 */ 201void _XawTextZapSelection(TextWidget, XEvent*, Bool); 202 203/* 204 * Defined in TextPop.c 205 */ 206void _XawTextInsertFileAction(Widget, XEvent*, String*, Cardinal*); 207void _XawTextInsertFile(Widget, XEvent*, String*, Cardinal*); 208void _XawTextSearch(Widget, XEvent*, String*, Cardinal*); 209void _XawTextDoSearchAction(Widget, XEvent*, String*, Cardinal*); 210void _XawTextDoReplaceAction(Widget, XEvent*, String*, Cardinal*); 211void _XawTextSetField(Widget, XEvent*, String*, Cardinal*); 212void _XawTextPopdownSearchAction(Widget, XEvent*, String*, Cardinal*); 213 214/* 215 * These are defined in Text.c 216 */ 217void _XawTextAlterSelection(TextWidget, XawTextSelectionMode, 218 XawTextSelectionAction, String*, Cardinal*); 219void _XawTextClearAndCenterDisplay(TextWidget); 220void _XawTextExecuteUpdate(TextWidget); 221char *_XawTextGetText(TextWidget, XawTextPosition, XawTextPosition); 222void _XawTextPrepareToUpdate(TextWidget); 223int _XawTextReplace(TextWidget, XawTextPosition, XawTextPosition, 224 XawTextBlock*); 225Atom *_XawTextSelectionList(TextWidget, String*, Cardinal); 226void _XawTextSetSelection(TextWidget, XawTextPosition, XawTextPosition, 227 String*, Cardinal); 228void _XawTextVScroll(TextWidget, int); 229void XawTextScroll(TextWidget, int, int); 230void _XawTextSetLineAndColumnNumber(TextWidget, Bool); 231 232#ifndef OLDXAW 233/* 234 * Defined in TextSrc.c 235 */ 236Bool _XawTextSrcUndo(TextSrcObject, XawTextPosition*); 237Bool _XawTextSrcToggleUndo(TextSrcObject); 238void _XawSourceSetUndoErase(TextSrcObject, int); 239void _XawSourceSetUndoMerge(TextSrcObject, Bool); 240#endif /* OLDXAW */ 241 242/* 243 * Initialization 244 */ 245#ifndef OLDXAW 246#define MAX_KILL_RINGS 1024 247XawTextKillRing *xaw_text_kill_ring; 248static XawTextKillRing kill_ring_prev, kill_ring_null = { &kill_ring_prev, NULL, 0, 0, 0 }; 249static unsigned num_kill_rings; 250#endif 251 252/* 253 * Implementation 254 */ 255static void 256ParameterError(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 270static void 271StartAction(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 304static void 305NotePosition(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 331static void 332EndAction(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 357struct _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*/ 367static void 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 = (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 457static void 458GetSelection(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 508static void 509InsertSelection(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 */ 519static void 520Move(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*/ 550static void 551MoveForwardChar(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*/ 557static void 558MoveBackwardChar(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED) 559{ 560 Move((TextWidget)w, event, XawsdLeft, XawstPositions, True); 561} 562 563static void 564MoveForwardWord(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 572static void 573MoveBackwardWord(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 581static void 582MoveForwardParagraph(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*/ 627static void 628MoveBackwardParagraph(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*/ 672static void 673MoveToLineEnd(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*/ 679static void 680MoveToLineStart(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED) 681{ 682 Move((TextWidget)w, event, XawsdLeft, XawstEOL, False); 683} 684 685static void 686MoveLine(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 734static void 735MoveNextLine(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 752static void 753MovePreviousLine(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*/ 772static void 773MoveBeginningOfFile(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*/ 779static void 780MoveEndOfFile(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED) 781{ 782 Move((TextWidget)w, event, XawsdRight, XawstAll, True); 783} 784 785static void 786Scroll(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*/ 816static void 817ScrollOneLineUp(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED) 818{ 819 Scroll((TextWidget)w, event, XawsdLeft); 820} 821 822/*ARGSUSED*/ 823static void 824ScrollOneLineDown(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED) 825{ 826 Scroll((TextWidget)w, event, XawsdRight); 827} 828 829static void 830MovePage(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 877static void 878MoveNextPage(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*/ 902static void 903MovePreviousPage(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 */ 929static Bool 930MatchSelection(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 945static Boolean 946ConvertSelection(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 1140static void 1141LoseSelection(Widget w, Atom *selection) 1142{ 1143 _LoseSelection(w, selection, NULL, NULL); 1144} 1145 1146static void 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 1223static void 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 1344static void 1345DeleteOrKill(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 1384static void 1385Delete(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 1395static void 1396DeleteChar(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*/ 1414static void 1415DeleteForwardChar(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED) 1416{ 1417 DeleteChar(w, event, XawsdRight); 1418} 1419 1420/*ARGSUSED*/ 1421static void 1422DeleteBackwardChar(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED) 1423{ 1424 DeleteChar(w, event, XawsdLeft); 1425} 1426 1427static void 1428DeleteForwardWord(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 1440static void 1441DeleteBackwardWord(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 1453static void 1454KillForwardWord(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 1466static void 1467KillBackwardWord(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*/ 1480static void 1481KillToEndOfLine(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*/ 1508static void 1509KillToEndOfParagraph(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED) 1510{ 1511 DeleteOrKill((TextWidget)w, event, XawsdRight, XawstParagraph, False, True); 1512} 1513 1514void 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*/ 1523static void 1524KillCurrentSelection(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*/ 1531static void 1532KillRingYank(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*/ 1581static void 1582DeleteCurrentSelection(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) 1592static Bool 1593StripSpaces(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 1706static Bool 1707Tabify(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 1850static Bool 1851Untabify(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 1975static int 1976FormatText(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 2053static int 2054DoFormatText(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*/ 2319static void 2320Indent(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*/ 2460static void 2461ToggleOverwrite(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 */ 2475static int 2476InsertNewLineAndBackupInternal(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*/ 2533static void 2534InsertNewLineAndBackup(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 2546static int 2547LocalInsertNewLine(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*/ 2560static void 2561InsertNewLine(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED) 2562{ 2563 (void)LocalInsertNewLine((TextWidget)w, event); 2564} 2565 2566/*ARGSUSED*/ 2567static void 2568InsertNewLineAndIndent(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((unsigned char)*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 */ 2634static void 2635SelectWord(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 2648static void 2649SelectAll(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 2658static void 2659ModifySelection(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 2690static void 2691SelectStart(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 2706static void 2707SelectAdjust(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 2718static void 2719SelectEnd(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 2734static void 2735ExtendStart(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 2750static void 2751ExtendAdjust(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 2762static void 2763ExtendEnd(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 2778static void 2779SelectSave(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*/ 2800static void 2801SetKeyboardFocus(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*/ 2815static void 2816RedrawDisplay(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 addressed 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 */ 2830struct _focus { Display *display; Widget widget; }; 2831static struct _focus *focus; 2832static Cardinal num_focus; 2833 2834/*ARGSUSED*/ 2835static void 2836DestroyFocusCallback(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*/ 2845static void 2846TextFocusIn(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*/ 2905static void 2906TextFocusOut(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*/ 2947static void 2948TextEnterWindow(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*/ 2958static void 2959TextLeaveWindow(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 boundary when 2975 * called inside InsertChar. 2976 */ 2977static void 2978AutoFill(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*/ 3036static void 3037InsertChar(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 separate 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. */ 3217static char * 3218IfHexConvertHexElseReturnParam(const char *param, int *len_return) 3219{ 3220 const 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 goto out; 3229 } 3230 3231 /* Skip the 0x; go character by character shifting and adding. */ 3232 first_digit = True; 3233 ind = 0; 3234 hexval[ind] = '\0'; 3235 3236 for (p = param+2; (c = *p) != '\0'; p++) { 3237 hexval[ind] = (char)(hexval[ind] * 16); 3238 if (c >= '0' && c <= '9') 3239 hexval[ind] = (char)(hexval[ind] + (c - '0')); 3240 else if (c >= 'a' && c <= 'f') 3241 hexval[ind] = (char)(hexval[ind] + (c - 'a' + 10)); 3242 else if (c >= 'A' && c <= 'F') 3243 hexval[ind] = (char)(hexval[ind] + (c - 'A' + 10)); 3244 else 3245 break; 3246 3247 /* If we didn't break in preceding line, it was a good hex char. */ 3248 if (first_digit) 3249 first_digit = False; 3250 else { 3251 first_digit = True; 3252 if (++ind < XawTextActionMaxHexChars) 3253 hexval[ind] = '\0'; 3254 else { 3255 goto out; 3256 } 3257 } 3258 } 3259 3260 /* We quit the above loop because we hit a non hex. If that char is \0... */ 3261 if ((c == '\0') && first_digit) { 3262 *len_return = (int)strlen(hexval); 3263 return (hexval); /* ...it was a legal hex string, so return it */ 3264 } 3265 3266 /* Else, there were non-hex chars or odd digit count, so... */ 3267out: 3268 *len_return = (int)strlen(param); 3269 return ((char *)param); /* ...return the verbatim string. */ 3270} 3271 3272/* InsertString() - action 3273 * 3274 * Mostly rewritten for R6 i18n. 3275 * 3276 * Each parameter, in turn, will be insert at the inputPos 3277 * and the inputPos advances to the insertion's end. 3278 * 3279 * The exception is that parameters composed of the two 3280 * characters 0x, followed only by an even number of 3281 * hexadecimal digits will be converted to characters */ 3282/*ARGSUSED*/ 3283static void 3284InsertString(Widget w, XEvent *event, String *params, Cardinal *num_params) 3285{ 3286 TextWidget ctx = (TextWidget)w; 3287 XtAppContext app_con = XtWidgetToApplicationContext(w); 3288 XawTextBlock text; 3289 int i; 3290 3291 text.firstPos = 0; 3292 text.format = (unsigned long)_XawTextFormat(ctx); 3293 3294 StartAction(ctx, event); 3295 for (i = (int)*num_params; i; i--, params++) { /* DO FOR EACH PARAMETER */ 3296 text.ptr = IfHexConvertHexElseReturnParam(*params, &text.length); 3297 3298 if (text.length == 0) 3299 continue; 3300 3301 if (XawTextFormat(ctx, XawFmtWide)) { /* convert to WC */ 3302 int temp_len; 3303 3304 text.ptr = (char*)_XawTextMBToWC(XtDisplay(w), text.ptr, 3305 &text.length); 3306 3307 if (text.ptr == NULL) { /* conversion error */ 3308 XtAppWarningMsg(app_con, 3309 "insertString", "textAction", "XawError", 3310 "insert-string()'s parameter contents " 3311 "not legal in this locale.", 3312 NULL, NULL); 3313 ParameterError(w, *params); 3314 continue; 3315 } 3316 3317 /* Double check that the new input is legal: try to convert to MB. */ 3318 3319 temp_len = text.length; /* _XawTextWCToMB's 3rd arg is in_out */ 3320 if (_XawTextWCToMB(XtDisplay(w), (wchar_t*)text.ptr, &temp_len) 3321 == NULL) { 3322 XtAppWarningMsg( app_con, 3323 "insertString", "textAction", "XawError", 3324 "insert-string()'s parameter contents " 3325 "not legal in this locale.", 3326 NULL, NULL); 3327 ParameterError(w, *params); 3328 continue; 3329 } 3330 } /* convert to WC */ 3331 3332 if (_XawTextReplace(ctx, ctx->text.insertPos, 3333 ctx->text.insertPos, &text)) { 3334 XBell(XtDisplay(ctx), 50); 3335 EndAction(ctx); 3336 return; 3337 } 3338 3339 ctx->text.from_left = -1; 3340 /* Advance insertPos to the end of the string we just inserted. */ 3341 ctx->text.insertPos = SrcScan(ctx->text.source, ctx->text.old_insert, 3342 XawstPositions, XawsdRight, text.length, 3343 True); 3344 3345 } /* DO FOR EACH PARAMETER */ 3346 3347 EndAction(ctx); 3348} 3349 3350/* DisplayCaret() - action 3351 * 3352 * The parameter list should contain one boolean value. If the 3353 * argument is true, the cursor will be displayed. If false, not. 3354 * 3355 * The exception is that EnterNotify and LeaveNotify events may 3356 * have a second argument, "always". If they do not, the cursor 3357 * is only affected if the focus member of the event is true. */ 3358static void 3359DisplayCaret(Widget w, XEvent *event, String *params, Cardinal *num_params) 3360{ 3361 TextWidget ctx = (TextWidget)w; 3362 Bool display_caret = True; 3363 3364 if ((event->type == EnterNotify || event->type == LeaveNotify) 3365 && ((*num_params >= 2) && (strcmp(params[1], "always") == 0)) 3366 && (!event->xcrossing.focus)) 3367 return; 3368 3369 if (*num_params > 0) { /* default arg is "True" */ 3370 XrmValue from, to; 3371 from.size = (unsigned)strlen(from.addr = (char *)params[0]); 3372 XtConvert(w, XtRString, &from, XtRBoolean, &to); 3373 3374 if (to.addr != NULL) 3375 display_caret = *(Boolean*)to.addr; 3376 if (ctx->text.display_caret == display_caret) 3377 return; 3378 } 3379 StartAction(ctx, event); 3380 ctx->text.display_caret = (Boolean)display_caret; 3381 EndAction(ctx); 3382} 3383 3384#ifndef OLDXAW 3385static void 3386Numeric(Widget w, XEvent *event, String *params, Cardinal *num_params) 3387{ 3388 TextWidget ctx = (TextWidget)w; 3389 3390 if (ctx->text.numeric) { 3391 long mult = ctx->text.mult; 3392 3393 if (*num_params != 1 || strlen(params[0]) != 1 3394 || (!isdigit((unsigned char)params[0][0]) 3395 && (params[0][0] != '-' || mult != 0))) { 3396 char err_buf[256]; 3397 3398 if (event && (event->type == KeyPress || event->type == KeyRelease) 3399 && params[0][0] == '-') { 3400 InsertChar(w, event, params, num_params); 3401 return; 3402 } 3403 snprintf(err_buf, sizeof(err_buf), 3404 "numeric: Invalid argument%s'%s'", 3405 *num_params ? ", " : "", 3406 *num_params ? params[0] : ""); 3407 XtAppWarning(XtWidgetToApplicationContext(w), err_buf); 3408 ctx->text.numeric = False; 3409 ctx->text.mult = 1; 3410 return; 3411 } 3412 if (params[0][0] == '-') { 3413 ctx->text.mult = 32767; 3414 return; 3415 } 3416 else if (mult == 32767) { 3417 mult = ctx->text.mult = (short)(- (params[0][0] - '0')); 3418 return; 3419 } 3420 else { 3421 mult = mult * 10 + (params[0][0] - '0') * (mult < 0 ? -1 : 1); 3422 ctx->text.mult = (short)(ctx->text.mult * 10 + (params[0][0] - '0') * 3423 (mult < 0 ? -1 : 1)); 3424 } 3425 if (mult != ctx->text.mult || mult >= 32767) { /* checks for overflow */ 3426 XBell(XtDisplay(w), 0); 3427 ctx->text.mult = 1; 3428 ctx->text.numeric = False; 3429 return; 3430 } 3431 } 3432 else 3433 InsertChar(w, event, params, num_params); 3434} 3435 3436/*ARGSUSED*/ 3437static void 3438KeyboardReset(Widget w, XEvent *event _X_UNUSED, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED) 3439{ 3440 TextWidget ctx = (TextWidget)w; 3441 3442 ctx->text.numeric = False; 3443 ctx->text.mult = 1; 3444 3445 (void)_XawTextSrcToggleUndo((TextSrcObject)ctx->text.source); 3446 3447 if (ctx->text.kill_ring_ptr) { 3448 --ctx->text.kill_ring_ptr->refcount; 3449 ctx->text.kill_ring_ptr = NULL; 3450 } 3451 ctx->text.kill_ring = 0; 3452 3453 XBell(XtDisplay(w), 0); 3454} 3455#endif /* OLDXAW */ 3456 3457/* Multiply() - action 3458 * 3459 * The parameter list may contain either a number or the string 'Reset'. 3460 * 3461 * A number will multiply the current multiplication factor by that number. 3462 * Many of the text widget actions will will perform n actions, where n is 3463 * the multiplication factor. 3464 * 3465 * The string reset will reset the mutiplication factor to 1. */ 3466/*ARGSUSED*/ 3467static void 3468Multiply(Widget w, XEvent *event _X_UNUSED, String *params, Cardinal *num_params) 3469{ 3470 TextWidget ctx = (TextWidget)w; 3471 int mult; 3472 3473 if (*num_params != 1) { 3474 XtAppError(XtWidgetToApplicationContext(w), 3475 "Xaw Text Widget: multiply() takes exactly one argument."); 3476 XBell(XtDisplay(w), 0); 3477 return; 3478 } 3479 3480 if ((params[0][0] == 'r') || (params[0][0] == 'R')) { 3481 XBell(XtDisplay(w), 0); 3482#ifndef OLDXAW 3483 ctx->text.numeric = False; 3484#endif 3485 ctx->text.mult = 1; 3486 return; 3487 } 3488 3489#ifndef OLDXAW 3490 if (params[0][0] == 's' || params[0][0] == 'S') { 3491 ctx->text.numeric = True; 3492 ctx->text.mult = 0; 3493 return; 3494 } 3495 else 3496#endif 3497 if ((mult = atoi(params[0])) == 0) { 3498 char buf[BUFSIZ]; 3499 3500 snprintf(buf, sizeof(buf), 3501 "Xaw Text Widget: multiply() argument " 3502 "must be a number greater than zero, or 'Reset'."); 3503 XtAppError(XtWidgetToApplicationContext(w), buf); 3504 XBell(XtDisplay(w), 50); 3505 return; 3506 } 3507 3508 ctx->text.mult = (short)(ctx->text.mult * mult); 3509} 3510 3511/* StripOutOldCRs() - called from FormRegion 3512 * 3513 * removes CRs in widget ctx, from from to to. 3514 * 3515 * RETURNS: the new ending location (we may add some characters), 3516 * or XawReplaceError if the widget can't be written to. */ 3517static XawTextPosition 3518StripOutOldCRs(TextWidget ctx, XawTextPosition from, XawTextPosition to, 3519 XawTextPosition *pos, int num_pos) 3520{ 3521 XawTextPosition startPos, endPos, eop_begin, eop_end, temp; 3522 Widget src = ctx->text.source; 3523 XawTextBlock text; 3524 char *buf; 3525 static wchar_t wc_two_spaces[3]; 3526 int idx; 3527 3528 /* Initialize our TextBlock with two spaces. */ 3529 text.firstPos = 0; 3530 text.format = (unsigned long)_XawTextFormat(ctx); 3531 if (text.format == XawFmt8Bit) 3532 text.ptr= " "; 3533 else { 3534 wc_two_spaces[0] = _Xaw_atowc(XawSP); 3535 wc_two_spaces[1] = _Xaw_atowc(XawSP); 3536 wc_two_spaces[2] = 0; 3537 text.ptr = (char*)wc_two_spaces; 3538 } 3539 3540 /* Strip out CR's. */ 3541 eop_begin = eop_end = startPos = endPos = from; 3542 3543 /* CONSTCOND */ 3544 while (TRUE) { 3545 endPos=SrcScan(src, startPos, XawstEOL, XawsdRight, 1, False); 3546 3547 temp = SrcScan(src, endPos, XawstWhiteSpace, XawsdLeft, 1, False); 3548 temp = SrcScan(src, temp, XawstWhiteSpace, XawsdRight,1, False); 3549 3550 if (temp > startPos) 3551 endPos = temp; 3552 3553 if (endPos >= to) 3554 break; 3555 3556 if (endPos >= eop_begin) { 3557 startPos = eop_end; 3558 eop_begin=SrcScan(src, startPos, XawstParagraph, 3559 XawsdRight, 1,False); 3560 eop_end = SrcScan(src, startPos, XawstParagraph, 3561 XawsdRight, 1, True); 3562 } 3563 else { 3564 XawTextPosition periodPos, next_word; 3565 int i, len; 3566 3567 periodPos = SrcScan(src, endPos, XawstPositions, 3568 XawsdLeft, 1, True); 3569 next_word = SrcScan(src, endPos, XawstWhiteSpace, 3570 XawsdRight, 1, False); 3571 3572 len = (int)(next_word - periodPos); 3573 3574 text.length = 1; 3575 buf = _XawTextGetText(ctx, periodPos, next_word); 3576 if (text.format == XawFmtWide) { 3577 if (periodPos < endPos && ((wchar_t*)buf)[0] == _Xaw_atowc('.')) 3578 text.length++; 3579 } 3580 else 3581 if (periodPos < endPos && buf[0] == '.') 3582 text.length++; /* Put in two spaces. */ 3583 3584 /* 3585 * Remove all extra spaces. 3586 */ 3587 for (i = 1 ; i < len; i++) 3588 if (text.format == XawFmtWide) { 3589 if (!iswspace(((wchar_t*)buf)[i]) || ((periodPos + i) >= to)) 3590 break; 3591 } 3592 else if (!isspace((unsigned char)buf[i]) || (periodPos + i) >= to) 3593 break; 3594 3595 XtFree(buf); 3596 3597 to -= (i - text.length - 1); 3598 startPos = SrcScan(src, periodPos, XawstPositions, 3599 XawsdRight, i, True); 3600 if (_XawTextReplace(ctx, endPos, startPos, &text) != XawEditDone) 3601 return (XawReplaceError); 3602 3603 for (idx = 0; idx < num_pos; idx++) { 3604 if (endPos < pos[idx]) { 3605 if (startPos < pos[idx]) 3606 pos[idx] -= startPos - endPos; 3607 else 3608 pos[idx] = endPos; 3609 pos[idx] += text.length; 3610 } 3611 } 3612 3613 startPos -= i - text.length; 3614 } 3615 } 3616 3617 return (to); 3618} 3619 3620/* InsertNewCRs() - called from FormRegion 3621 * 3622 * inserts new CRs for FormRegion, thus for FormParagraph action */ 3623static void 3624InsertNewCRs(TextWidget ctx, XawTextPosition from, XawTextPosition to, 3625 XawTextPosition *pos, int num_pos) 3626{ 3627 XawTextPosition startPos, endPos, space, eol; 3628 XawTextBlock text; 3629 int i, width, height, len, wwidth, idx; 3630 char *buf; 3631 static wchar_t wide_CR[2]; 3632 3633 text.firstPos = 0; 3634 text.length = 1; 3635 text.format = (unsigned long)_XawTextFormat(ctx); 3636 3637 if (text.format == XawFmt8Bit) 3638 text.ptr = "\n"; 3639 else { 3640 wide_CR[0] = _Xaw_atowc(XawLF); 3641 wide_CR[1] = 0; 3642 text.ptr = (char*)wide_CR; 3643 } 3644 3645 startPos = from; 3646 3647 wwidth = (int)XtWidth(ctx) - (int)HMargins(ctx); 3648 if (ctx->text.wrap != XawtextWrapNever) { 3649 XRectangle cursor; 3650 3651 XawTextSinkGetCursorBounds(ctx->text.sink, &cursor); 3652 wwidth -= (int)cursor.width; 3653 } 3654 wwidth = XawMax(0, wwidth); 3655 3656 /* CONSTCOND */ 3657 while (TRUE) { 3658 XawTextSinkFindPosition(ctx->text.sink, startPos, 3659 (int)ctx->text.r_margin.left, wwidth, 3660 True, &eol, &width, &height); 3661 if (eol == startPos) 3662 ++eol; 3663 if (eol >= to) 3664 break; 3665 3666 eol = SrcScan(ctx->text.source, eol, XawstPositions, 3667 XawsdLeft, 1, True); 3668 space = SrcScan(ctx->text.source, eol, XawstWhiteSpace, 3669 XawsdRight,1, True); 3670 3671 startPos = endPos = eol; 3672 if (eol == space) 3673 return; 3674 3675 len = (int)(space - eol); 3676 buf = _XawTextGetText(ctx, eol, space); 3677 for (i = 0 ; i < len ; i++) 3678 if (text.format == XawFmtWide) { 3679 if (!iswspace(((wchar_t*)buf)[i])) 3680 break; 3681 } 3682 else if (!isspace((unsigned char)buf[i])) 3683 break; 3684 3685 to -= (i - 1); 3686 endPos = SrcScan(ctx->text.source, endPos, 3687 XawstPositions, XawsdRight, i, True); 3688 XtFree(buf); 3689 3690 if (_XawTextReplace(ctx, startPos, endPos, &text)) 3691 return; 3692 3693 for (idx = 0; idx < num_pos; idx++) { 3694 if (startPos < pos[idx]) { 3695 if (endPos < pos[idx]) 3696 pos[idx] -= endPos - startPos; 3697 else 3698 pos[idx] = startPos; 3699 pos[idx] += text.length; 3700 } 3701 } 3702 3703 startPos = SrcScan(ctx->text.source, startPos, 3704 XawstPositions, XawsdRight, 1, True); 3705 } 3706} 3707 3708/* FormRegion() - called by FormParagraph 3709 * 3710 * oversees the work of paragraph-forming a region 3711 * 3712 * Return: 3713 * XawEditDone if successful, or XawReplaceError 3714 */ 3715static int 3716FormRegion(TextWidget ctx, XawTextPosition from, XawTextPosition to, 3717 XawTextPosition *pos, int num_pos) 3718{ 3719#ifndef OLDXAW 3720 Bool format = ctx->text.auto_fill 3721 && ctx->text.left_column < ctx->text.right_column; 3722#endif 3723 3724 if (from >= to) 3725 return (XawEditDone); 3726 3727#ifndef OLDXAW 3728 if (format) { 3729 XawTextPosition len = ctx->text.lastPos; 3730 int inc = 0; 3731 3732 if (ctx->text.justify == XawjustifyLeft || 3733 ctx->text.justify == XawjustifyFull) { 3734 Untabify(ctx, from, to, pos, num_pos, NULL); 3735 to += ctx->text.lastPos - len; 3736 len = ctx->text.insertPos; 3737 (void)BlankLine((Widget)ctx, from, &inc); 3738 if (from + inc >= to) 3739 return (XawEditDone); 3740 } 3741 if (!StripSpaces(ctx, from + inc, to, pos, num_pos, NULL)) 3742 return (XawReplaceError); 3743 to += ctx->text.lastPos - len; 3744 3745 FormatText(ctx, from, ctx->text.justify != XawjustifyFull, pos, num_pos); 3746 } 3747 else { 3748#endif 3749 if ((to = StripOutOldCRs(ctx, from, to, pos, num_pos)) == XawReplaceError) 3750 return (XawReplaceError); 3751 InsertNewCRs(ctx, from, to, pos, num_pos); 3752#ifndef OLDXAW 3753 } 3754#endif 3755 ctx->text.from_left = -1; 3756 3757 return (XawEditDone); 3758} 3759 3760#ifndef OLDXAW 3761static Bool 3762BlankLine(Widget w, XawTextPosition pos, int *blanks_return) 3763{ 3764 int i, blanks = 0; 3765 XawTextBlock block; 3766 Widget src = XawTextGetSource(w); 3767 XawTextPosition l = SrcScan(src, pos, XawstEOL, XawsdLeft, 1, False); 3768 XawTextPosition r = SrcScan(src, pos, XawstEOL, XawsdRight, 1, False); 3769 3770 while (l < r) { 3771 l = XawTextSourceRead(src, l, &block, (int)(r - l)); 3772 if (block.length == 0) { 3773 if (blanks_return) 3774 *blanks_return = blanks; 3775 return (True); 3776 } 3777 if (XawTextFormat((TextWidget)w, XawFmt8Bit)) { 3778 for (i = 0; i < block.length; i++, blanks++) 3779 if (block.ptr[i] != ' ' && 3780 block.ptr[i] != '\t') { 3781 if (blanks_return) 3782 *blanks_return = blanks; 3783 return (block.ptr[i] == '\n'); 3784 } 3785 } 3786 else if (XawTextFormat((TextWidget)w, XawFmtWide)) { 3787 for (i = 0; i < block.length; i++, blanks++) 3788 if (_Xaw_atowc(XawSP) != ((wchar_t*)block.ptr)[i] && 3789 _Xaw_atowc(XawTAB) != ((wchar_t*)block.ptr)[i]) { 3790 if (blanks_return) 3791 *blanks_return = blanks; 3792 return (_Xaw_atowc(XawLF) == ((wchar_t*)block.ptr)[i]); 3793 } 3794 } 3795 } 3796 3797 return (True); 3798} 3799 3800static Bool 3801GetBlockBoundaries(TextWidget ctx, 3802 XawTextPosition *from_return, XawTextPosition *to_return) 3803{ 3804 XawTextPosition from, to; 3805 3806 if (ctx->text.auto_fill && ctx->text.left_column < ctx->text.right_column) { 3807 if (ctx->text.s.left != ctx->text.s.right) { 3808 from = SrcScan(ctx->text.source, 3809 XawMin(ctx->text.s.left, ctx->text.s.right), 3810 XawstEOL, XawsdLeft, 1, False); 3811 to = SrcScan(ctx->text.source, 3812 XawMax(ctx->text.s.left, ctx->text.s.right), 3813 XawstEOL, XawsdRight, 1, False); 3814 } 3815 else { 3816 XawTextBlock block; 3817 XawTextPosition tmp; 3818 Bool first; 3819 3820 from = to = ctx->text.insertPos; 3821 3822 /* find from position */ 3823 first = True; 3824 while (1) { 3825 tmp = from; 3826 from = SrcScan(ctx->text.source, from, XawstEOL, XawsdLeft, 3827 1 + !first, False); 3828 XawTextSourceRead(ctx->text.source, from, &block, 1); 3829 if (block.length == 0 || 3830 (XawTextFormat(ctx, XawFmt8Bit) && 3831 block.ptr[0] != ' ' && 3832 block.ptr[0] != '\t' && 3833 !isalnum(*(unsigned char*)block.ptr)) || 3834 (XawTextFormat(ctx, XawFmtWide) && 3835 _Xaw_atowc(XawSP) != *(wchar_t*)block.ptr && 3836 _Xaw_atowc(XawTAB) != *(wchar_t*)block.ptr && 3837 !iswalnum((wint_t)*(wchar_t*)block.ptr)) || 3838 BlankLine((Widget)ctx, from, NULL)) { 3839 from = tmp; 3840 break; 3841 } 3842 if (from == tmp && !first) 3843 break; 3844 first = False; 3845 } 3846 if (first) 3847 return (False); 3848 3849 /* find to position */ 3850 first = True; 3851 while (1) { 3852 tmp = to; 3853 to = SrcScan(ctx->text.source, to, XawstEOL, XawsdRight, 3854 1 + !first, False); 3855 XawTextSourceRead(ctx->text.source, to + (to < ctx->text.lastPos), 3856 &block, 1); 3857 if (block.length == 0 || 3858 (XawTextFormat(ctx, XawFmt8Bit) && 3859 block.ptr[0] != ' ' && 3860 block.ptr[0] != '\t' && 3861 !isalnum(*(unsigned char*)block.ptr)) || 3862 (XawTextFormat(ctx, XawFmtWide) && 3863 _Xaw_atowc(XawSP) != *(wchar_t*)block.ptr && 3864 _Xaw_atowc(XawTAB) != *(wchar_t*)block.ptr && 3865 !iswalnum((wint_t)*(wchar_t*)block.ptr)) || 3866 BlankLine((Widget)ctx, to, NULL)) 3867 break; 3868 if (to == tmp && !first) 3869 break; 3870 first = False; 3871 } 3872 } 3873 } 3874 else { 3875 from = SrcScan(ctx->text.source, ctx->text.insertPos, XawstEOL, 3876 XawsdLeft, 1, False); 3877 if (BlankLine((Widget)ctx, from, NULL)) 3878 return (False); 3879 from = SrcScan(ctx->text.source, from, XawstParagraph, 3880 XawsdLeft, 1, False); 3881 if (BlankLine((Widget)ctx, from, NULL)) 3882 from = SrcScan(ctx->text.source, from, XawstEOL, 3883 XawsdRight, 1, True); 3884 to = SrcScan(ctx->text.source, from, XawstParagraph, 3885 XawsdRight, 1, False); 3886 } 3887 3888 if (from < to) { 3889 *from_return = from; 3890 *to_return = to; 3891 return (True); 3892 } 3893 3894 return (False); 3895} 3896#endif /* OLDXAW */ 3897 3898/* FormParagraph() - action 3899 * 3900 * removes and reinserts CRs to maximize line length without clipping */ 3901/*ARGSUSED*/ 3902static void 3903FormParagraph(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED) 3904{ 3905 TextWidget ctx = (TextWidget)w; 3906 XawTextPosition from, to, buf[32], *pos; 3907#ifndef OLDXAW 3908 XawTextPosition endPos = 0; 3909 char *lbuf = NULL, *rbuf; 3910 TextSrcObject src = (TextSrcObject)ctx->text.source; 3911 Cardinal i; 3912 Bool undo = src->textSrc.enable_undo && src->textSrc.undo_state == False; 3913#endif 3914 3915 StartAction(ctx, event); 3916 3917#ifndef OLDXAW 3918 pos = XawStackAlloc(sizeof(XawTextPosition) * src->textSrc.num_text, buf); 3919 for (i = 0; i < src->textSrc.num_text; i++) 3920 pos[i] = ((TextWidget)src->textSrc.text[i])->text.old_insert; 3921#else 3922 pos = buf; 3923 *pos = ctx->text.old_insert; 3924#endif 3925 3926#ifndef OLDXAW 3927 if (!GetBlockBoundaries(ctx, &from, &to)) { 3928 EndAction(ctx); 3929 XawStackFree(pos, buf); 3930 return; 3931 } 3932 3933 if (undo) { 3934 src->textSrc.undo_state = True; 3935 lbuf = _XawTextGetText(ctx, from, to); 3936 endPos = ctx->text.lastPos; 3937 } 3938 3939 if (FormRegion(ctx, from, to, pos, (int)src->textSrc.num_text) == XawReplaceError) { 3940 XawStackFree(pos, buf); 3941 pos = buf; 3942#else 3943 from = SrcScan(ctx->text.source, ctx->text.insertPos, 3944 XawstParagraph, XawsdLeft, 1, False); 3945 to = SrcScan(ctx->text.source, from, 3946 XawstParagraph, XawsdRight, 1, False); 3947 3948 if (FormRegion(ctx, from, to, pos, 1) == XawReplaceError) { 3949#endif 3950 XBell(XtDisplay(w), 0); 3951#ifndef OLDXAW 3952 if (undo) { 3953 src->textSrc.undo_state = False; 3954 XtFree(lbuf); 3955 } 3956#endif 3957 } 3958#ifndef OLDXAW 3959 else if (undo) { 3960 /* makes the form-paragraph only one undo/redo step */ 3961 unsigned llen, rlen, size; 3962 XawTextBlock block; 3963 3964 llen = (unsigned)(to - from); 3965 rlen = (unsigned)(llen + (ctx->text.lastPos - endPos)); 3966 3967 block.firstPos = 0; 3968 block.format = (unsigned long)_XawTextFormat(ctx); 3969 3970 rbuf = _XawTextGetText(ctx, from, from + rlen); 3971 3972 size = XawTextFormat(ctx, XawFmtWide) ? sizeof(wchar_t) : sizeof(char); 3973 if (llen != rlen || memcmp(lbuf, rbuf, llen * size)) { 3974 block.ptr = lbuf; 3975 block.length = (int)llen; 3976 _XawTextReplace(ctx, from, from + rlen, &block); 3977 3978 src->textSrc.undo_state = False; 3979 block.ptr = rbuf; 3980 block.length = (int)rlen; 3981 _XawTextReplace(ctx, from, from + llen, &block); 3982 } 3983 else 3984 src->textSrc.undo_state = False; 3985 XtFree(lbuf); 3986 XtFree(rbuf); 3987 } 3988 3989 for (i = 0; i < src->textSrc.num_text; i++) { 3990 TextWidget tw = (TextWidget)src->textSrc.text[i]; 3991 3992 tw->text.old_insert = tw->text.insertPos = pos[i]; 3993 _XawTextBuildLineTable(tw, SrcScan((Widget)src, tw->text.lt.top, XawstEOL, 3994 XawsdLeft, 1, False), False); 3995 tw->text.clear_to_eol = True; 3996 } 3997 XawStackFree(pos, buf); 3998#else 3999 ctx->text.old_insert = ctx->text.insertPos = *pos; 4000 _XawTextBuildLineTable(ctx, SrcScan(ctx->text.source, ctx->text.lt.top, 4001 XawstEOL, XawsdLeft, 1, False), False); 4002 ctx->text.clear_to_eol = True; 4003#endif 4004 ctx->text.showposition = True; 4005 4006 EndAction(ctx); 4007} 4008 4009/* TransposeCharacters() - action 4010 * 4011 * Swaps the character to the left of the mark 4012 * with the character to the right of the mark */ 4013/*ARGSUSED*/ 4014static void 4015TransposeCharacters(Widget w, XEvent *event, 4016 String *params _X_UNUSED, Cardinal *num_params _X_UNUSED) 4017{ 4018 TextWidget ctx = (TextWidget)w; 4019 XawTextPosition start, end; 4020 XawTextBlock text; 4021 char *buf; 4022 int i, mult = MULT(ctx); 4023 4024 if (mult < 0) { 4025 ctx->text.mult = 1; 4026 return; 4027 } 4028 4029 StartAction(ctx, event); 4030 4031 /* Get bounds. */ 4032 4033 start = SrcScan(ctx->text.source, ctx->text.insertPos, XawstPositions, 4034 XawsdLeft, 1, True); 4035 end = SrcScan(ctx->text.source, ctx->text.insertPos, XawstPositions, 4036 XawsdRight, mult, True); 4037 4038 /* Make sure we aren't at the very beginning or end of the buffer. */ 4039 4040 if (start == ctx->text.insertPos || end == ctx->text.insertPos) { 4041 XBell(XtDisplay(w), 0); /* complain. */ 4042 EndAction(ctx); 4043 return; 4044 } 4045 4046 ctx->text.from_left = -1; 4047 ctx->text.insertPos = end; 4048 4049 text.firstPos = 0; 4050 text.format = (unsigned long)_XawTextFormat(ctx); 4051 4052 /* Retrieve text and swap the characters. */ 4053 if (text.format == XawFmtWide) { 4054 wchar_t wc; 4055 wchar_t *wbuf; 4056 4057 wbuf = (wchar_t*)_XawTextGetText(ctx, start, end); 4058 text.length = (int)wcslen(wbuf); 4059 wc = wbuf[0]; 4060 for (i = 1; i < text.length; i++) 4061 wbuf[i - 1] = wbuf[i]; 4062 wbuf[i - 1] = wc; 4063 buf = (char*)wbuf; /* so that it gets assigned and freed */ 4064 } 4065 else { /* thus text.format == XawFmt8Bit */ 4066 char c; 4067 4068 buf = _XawTextGetText(ctx, start, end); 4069 text.length = (int)strlen(buf); 4070 c = buf[0]; 4071 for (i = 1; i < text.length; i++) 4072 buf[i - 1] = buf[i]; 4073 buf[i - 1] = c; 4074 } 4075 4076 text.ptr = buf; 4077 4078 /* Store new text in source. */ 4079 4080 if (_XawTextReplace (ctx, start, end, &text)) 4081 XBell(XtDisplay(w), 0); 4082 XtFree((char *)buf); 4083 EndAction(ctx); 4084} 4085 4086#ifndef OLDXAW 4087/*ARGSUSED*/ 4088static void 4089Undo(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED) 4090{ 4091 TextWidget ctx = (TextWidget)w; 4092 int mul = MULT(ctx); 4093 Bool toggle = False; 4094 4095 if (mul < 0) { 4096 toggle = True; 4097 _XawTextSrcToggleUndo((TextSrcObject)ctx->text.source); 4098 ctx->text.mult = (short)(mul = -mul); 4099 } 4100 4101 StartAction(ctx, event); 4102 for (; mul; --mul) 4103 if (!_XawTextSrcUndo((TextSrcObject)ctx->text.source, &ctx->text.insertPos)) 4104 break; 4105 ctx->text.showposition = True; 4106 4107 if (toggle) 4108 _XawTextSrcToggleUndo((TextSrcObject)ctx->text.source); 4109 EndAction(ctx); 4110} 4111#endif 4112 4113/* NoOp() - action 4114 * This action performs no action, and allows the user or 4115 * application programmer to unbind a translation. 4116 * 4117 * Note: If the parameter list contains the string "RingBell" then 4118 * this action will ring the bell. 4119 */ 4120/*ARGSUSED*/ 4121static void 4122NoOp(Widget w, XEvent *event _X_UNUSED, String *params, Cardinal *num_params) 4123{ 4124 if (*num_params != 1) 4125 return; 4126 4127 switch(params[0][0]) { 4128 case 'R': 4129 case 'r': 4130 XBell(XtDisplay(w), 0); 4131 /*FALLTHROUGH*/ 4132 default: 4133 break; 4134 } 4135} 4136 4137/* Reconnect() - action 4138 * This reconnects to the input method. The user will typically call 4139 * this action if/when connection has been severed, or when the app 4140 * was started up before an IM was started up 4141 */ 4142/*ARGSUSED*/ 4143static void 4144Reconnect(Widget w, XEvent *event _X_UNUSED, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED) 4145{ 4146 _XawImReconnect(w); 4147} 4148 4149#define CAPITALIZE 1 4150#define DOWNCASE 2 4151#define UPCASE 3 4152 4153#ifdef NO_LIBC_I18N 4154static int 4155ToLower(int ch) 4156{ 4157 char buf[2]; 4158 4159 *buf = ch; 4160 XmuNCopyISOLatin1Lowered(buf, buf, sizeof(buf)); 4161 4162 return (*buf); 4163} 4164 4165static int 4166ToUpper(int ch) 4167{ 4168 char buf[2]; 4169 4170 *buf = ch; 4171 XmuNCopyISOLatin1Uppered(buf, buf, sizeof(buf)); 4172 4173 return (*buf); 4174} 4175 4176static int 4177IsAlnum(int ch) 4178{ 4179 return ((ch >= '0' && ch <= '9') || ToUpper(ch) != ch || ToLower(ch) != ch); 4180} 4181 4182static int 4183IsLower(int ch) 4184{ 4185 char upbuf[2]; 4186 char lobuf[2]; 4187 4188 *upbuf = *lobuf = ch; 4189 XmuNCopyISOLatin1Lowered(lobuf, lobuf, sizeof(lobuf)); 4190 XmuNCopyISOLatin1Uppered(upbuf, upbuf, sizeof(upbuf)); 4191 4192 return (*lobuf != *upbuf && ch == *lobuf); 4193} 4194 4195static int 4196IsUpper(int ch) 4197{ 4198 char upbuf[2]; 4199 char lobuf[2]; 4200 4201 *upbuf = *lobuf = ch; 4202 XmuNCopyISOLatin1Lowered(lobuf, lobuf, sizeof(lobuf)); 4203 XmuNCopyISOLatin1Uppered(upbuf, upbuf, sizeof(upbuf)); 4204 4205 return (*lobuf != *upbuf && ch == *upbuf); 4206} 4207#else 4208#define ToLower tolower 4209#define ToUpper toupper 4210#define IsAlnum isalnum 4211#define IsLower islower 4212#define IsUpper isupper 4213#endif 4214 4215static void 4216CaseProc(Widget w, XEvent *event, int cmd) 4217{ 4218 TextWidget ctx = (TextWidget)w; 4219 short mul = MULT(ctx); 4220 XawTextPosition left, right; 4221 XawTextBlock block; 4222 Bool changed = False; 4223 unsigned char ch, mb[sizeof(wchar_t)]; 4224 int i, count; 4225 4226 if (mul > 0) 4227 right = SrcScan(ctx->text.source, left = ctx->text.insertPos, 4228 XawstAlphaNumeric, XawsdRight, mul, False); 4229 else 4230 left = SrcScan(ctx->text.source, right = ctx->text.insertPos, 4231 XawstAlphaNumeric, XawsdLeft, 1 + -mul, False); 4232 block.firstPos = 0; 4233 block.format = (unsigned long)_XawTextFormat(ctx); 4234 block.length = (int)(right - left); 4235 block.ptr = _XawTextGetText(ctx, left, right); 4236 4237 count = 0; 4238 if (block.format == XawFmt8Bit) 4239 for (i = 0; i < block.length; i++) { 4240 if (!IsAlnum(*mb = (unsigned char)block.ptr[i])) 4241 count = 0; 4242 else if (++count == 1 || cmd != CAPITALIZE) { 4243 ch = (unsigned char)((cmd == DOWNCASE) ? ToLower(*mb) : ToUpper(*mb)); 4244 if (ch != *mb) { 4245 changed = True; 4246 block.ptr[i] = (char)ch; 4247 } 4248 } 4249 else if (cmd == CAPITALIZE) { 4250 if ((ch = (unsigned char)(ToLower(*mb))) != *mb) { 4251 changed = True; 4252 block.ptr[i] = (char)ch; 4253 } 4254 } 4255 } 4256 else 4257 for (i = 0; i < block.length; i++) { 4258 wctomb((char*)mb, ((wchar_t*)block.ptr)[i]); 4259 if (!IsAlnum(*mb)) 4260 count = 0; 4261 else if (++count == 1 || cmd != CAPITALIZE) { 4262 ch = (unsigned char)((cmd == DOWNCASE) ? ToLower(*mb) : ToUpper(*mb)); 4263 if (ch != *mb) { 4264 changed = True; 4265 ((wchar_t*)block.ptr)[i] = _Xaw_atowc(ch); 4266 } 4267 } 4268 else if (cmd == CAPITALIZE) { 4269 if ((ch = (unsigned char)(ToLower(*mb))) != *mb) { 4270 changed = True; 4271 ((wchar_t*)block.ptr)[i] = _Xaw_atowc(ch); 4272 } 4273 } 4274 } 4275 4276 StartAction(ctx, event); 4277 if (changed && _XawTextReplace(ctx, left, right, &block) != XawEditDone) 4278 XBell(XtDisplay(ctx), 0); 4279 ctx->text.insertPos = right; 4280 EndAction(ctx); 4281 4282 XtFree(block.ptr); 4283} 4284 4285/*ARGSUSED*/ 4286static void 4287CapitalizeWord(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED) 4288{ 4289 CaseProc(w, event, CAPITALIZE); 4290} 4291 4292/*ARGSUSED*/ 4293static void 4294DowncaseWord(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED) 4295{ 4296 CaseProc(w, event, DOWNCASE); 4297} 4298 4299/*ARGSUSED*/ 4300static void 4301UpcaseWord(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED) 4302{ 4303 CaseProc(w, event, UPCASE); 4304} 4305#undef CAPITALIZE 4306#undef DOWNCASE 4307#undef UPCASE 4308 4309XtActionsRec _XawTextActionsTable[] = { 4310 /* motion */ 4311 {"forward-character", MoveForwardChar}, 4312 {"backward-character", MoveBackwardChar}, 4313 {"forward-word", MoveForwardWord}, 4314 {"backward-word", MoveBackwardWord}, 4315 {"forward-paragraph", MoveForwardParagraph}, 4316 {"backward-paragraph", MoveBackwardParagraph}, 4317 {"beginning-of-line", MoveToLineStart}, 4318 {"end-of-line", MoveToLineEnd}, 4319 {"next-line", MoveNextLine}, 4320 {"previous-line", MovePreviousLine}, 4321 {"next-page", MoveNextPage}, 4322 {"previous-page", MovePreviousPage}, 4323 {"beginning-of-file", MoveBeginningOfFile}, 4324 {"end-of-file", MoveEndOfFile}, 4325 {"scroll-one-line-up", ScrollOneLineUp}, 4326 {"scroll-one-line-down", ScrollOneLineDown}, 4327 4328 /* delete */ 4329 {"delete-next-character", DeleteForwardChar}, 4330 {"delete-previous-character", DeleteBackwardChar}, 4331 {"delete-next-word", DeleteForwardWord}, 4332 {"delete-previous-word", DeleteBackwardWord}, 4333 {"delete-selection", DeleteCurrentSelection}, 4334 {"delete", Delete}, 4335 4336 /* kill */ 4337 {"kill-word", KillForwardWord}, 4338 {"backward-kill-word", KillBackwardWord}, 4339 {"kill-selection", KillCurrentSelection}, 4340 {"kill-to-end-of-line", KillToEndOfLine}, 4341 {"kill-to-end-of-paragraph", KillToEndOfParagraph}, 4342 4343 /* new line */ 4344 {"newline-and-indent", InsertNewLineAndIndent}, 4345 {"newline-and-backup", InsertNewLineAndBackup}, 4346 {"newline", InsertNewLine}, 4347 4348 /* selection */ 4349 {"select-word", SelectWord}, 4350 {"select-all", SelectAll}, 4351 {"select-start", SelectStart}, 4352 {"select-adjust", SelectAdjust}, 4353 {"select-end", SelectEnd}, 4354 {"select-save", SelectSave}, 4355 {"extend-start", ExtendStart}, 4356 {"extend-adjust", ExtendAdjust}, 4357 {"extend-end", ExtendEnd}, 4358 {"insert-selection", InsertSelection}, 4359 4360 /* miscellaneous */ 4361 {"redraw-display", RedrawDisplay}, 4362 {"insert-file", _XawTextInsertFile}, 4363 {"search", _XawTextSearch}, 4364 {"insert-char", InsertChar}, 4365 {"insert-string", InsertString}, 4366 {"focus-in", TextFocusIn}, 4367 {"focus-out", TextFocusOut}, 4368 {"enter-window", TextEnterWindow}, 4369 {"leave-window", TextLeaveWindow}, 4370 {"display-caret", DisplayCaret}, 4371 {"multiply", Multiply}, 4372 {"form-paragraph", FormParagraph}, 4373 {"transpose-characters", TransposeCharacters}, 4374 {"set-keyboard-focus", SetKeyboardFocus}, 4375#ifndef OLDXAW 4376 {"numeric", Numeric}, 4377 {"undo", Undo}, 4378 {"keyboard-reset", KeyboardReset}, 4379 {"kill-ring-yank", KillRingYank}, 4380 {"toggle-overwrite", ToggleOverwrite}, 4381 {"indent", Indent}, 4382#endif 4383 {"no-op", NoOp}, 4384 4385 /* case transformations */ 4386 {"capitalize-word", CapitalizeWord}, 4387 {"downcase-word", DowncaseWord}, 4388 {"upcase-word", UpcaseWord}, 4389 4390 /* action to bind translations for text dialogs */ 4391 {"InsertFileAction", _XawTextInsertFileAction}, 4392 {"DoSearchAction", _XawTextDoSearchAction}, 4393 {"DoReplaceAction", _XawTextDoReplaceAction}, 4394 {"SetField", _XawTextSetField}, 4395 {"PopdownSearchAction", _XawTextPopdownSearchAction}, 4396 4397 /* reconnect to Input Method */ 4398 {"reconnect-im", Reconnect} /* Li Yuhong, Omron KK, 1991 */ 4399}; 4400 4401Cardinal _XawTextActionsTableCount = XtNumber(_XawTextActionsTable); 4402