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