1 /*********************************************************** 2 3 Copyright 1987, 1988, 1994, 1998 The Open Group 4 5 Permission to use, copy, modify, distribute, and sell this software and its 6 documentation for any purpose is hereby granted without fee, provided that 7 the above copyright notice appear in all copies and that both that 8 copyright notice and this permission notice appear in supporting 9 documentation. 10 11 The above copyright notice and this permission notice shall be included in 12 all copies or substantial portions of the Software. 13 14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 21 Except as contained in this notice, the name of The Open Group shall not be 22 used in advertising or otherwise to promote the sale, use or other dealings 23 in this Software without prior written authorization from The Open Group. 24 25 26 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts. 27 28 All Rights Reserved 29 30 Permission to use, copy, modify, and distribute this software and its 31 documentation for any purpose and without fee is hereby granted, 32 provided that the above copyright notice appear in all copies and that 33 both that copyright notice and this permission notice appear in 34 supporting documentation, and that the name of Digital not be 35 used in advertising or publicity pertaining to distribution of the 36 software without specific, written prior permission. 37 38 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 39 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 40 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 41 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 42 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 43 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 44 SOFTWARE. 45 46 ******************************************************************/ 47 48 /* 49 * Copyright (c) 1998 by The XFree86 Project, Inc. 50 * 51 * Permission is hereby granted, free of charge, to any person obtaining a 52 * copy of this software and associated documentation files (the "Software"), 53 * to deal in the Software without restriction, including without limitation 54 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 55 * and/or sell copies of the Software, and to permit persons to whom the 56 * Software is furnished to do so, subject to the following conditions: 57 * 58 * The above copyright notice and this permission notice shall be included in 59 * all copies or substantial portions of the Software. 60 * 61 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 62 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 63 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 64 * THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 65 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 66 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 67 * SOFTWARE. 68 * 69 * Except as contained in this notice, the name of the XFree86 Project shall 70 * not be used in advertising or otherwise to promote the sale, use or other 71 * dealings in this Software without prior written authorization from the 72 * XFree86 Project. 73 */ 74 75 #ifdef HAVE_CONFIG_H 76 #include <config.h> 77 #endif 78 #include <stdio.h> 79 #include <X11/IntrinsicP.h> 80 #include <X11/StringDefs.h> 81 #include <X11/Shell.h> 82 #include <X11/Xatom.h> 83 #include <X11/Xfuncs.h> 84 #include <X11/Xutil.h> 85 #include <X11/Xmu/Misc.h> 86 #include <X11/Xmu/Xmu.h> 87 #include <X11/Xaw/Cardinals.h> 88 #include <X11/Xaw/MultiSinkP.h> 89 #include <X11/Xaw/TextP.h> 90 #include <X11/Xaw/TextSrcP.h> 91 #include <X11/Xaw/TextSinkP.h> 92 #include <X11/Xaw/Scrollbar.h> 93 #include <X11/Xaw/XawImP.h> 94 #include <X11/Xaw/XawInit.h> 95 #include "Private.h" 96 #include "XawI18n.h" 97 98 #ifndef MAX_LEN_CT 99 #define MAX_LEN_CT 6 /* for sequence: ESC $ ( A \xx \xx */ 100 #endif 101 102 unsigned long FMT8BIT = 0L; 103 unsigned long XawFmt8Bit = 0L; 104 unsigned long XawFmtWide = 0L; 105 106 #define SinkClearToBG _XawTextSinkClearToBackground 107 108 #define SrcScan XawTextSourceScan 109 #define SrcRead XawTextSourceRead 110 #define SrcReplace XawTextSourceReplace 111 #define SrcSearch XawTextSourceSearch 112 #define SrcCvtSel XawTextSourceConvertSelection 113 #define SrcSetSelection XawTextSourceSetSelection 114 115 #define MULTI_CLICK_TIME 500L 116 117 #define SRC_CHANGE_NONE 0 118 #define SRC_CHANGE_AFTER 1 119 #define SRC_CHANGE_BEFORE 2 120 #define SRC_CHANGE_OVERLAP 3 121 122 #define Superclass (&simpleClassRec) 123 124 /* 125 * Compute a the maximum length of a cut buffer that we can pass at any 126 * time. The 64 allows for the overhead of the Change Property request. 127 */ 128 #define MAX_CUT_LEN(dpy) (XMaxRequestSize(dpy) - 64) 129 130 #define ClearWindow(ctx) \ 131 _XawTextNeedsUpdating((ctx), \ 132 (ctx)->text.lt.top, \ 133 (ctx)->text.lt.info[ctx->text.lt.lines].position) 134 135 /* 136 * Class Methods 137 */ 138 static void XawTextClassInitialize(void); 139 static void XawTextInitialize(Widget, Widget, ArgList, Cardinal*); 140 static void XawTextRealize(Widget, XtValueMask*, XSetWindowAttributes*); 141 static void XawTextDestroy(Widget); 142 static void XawTextResize(Widget); 143 static void XawTextExpose(Widget, XEvent*, Region); 144 static Boolean XawTextSetValues(Widget, Widget, Widget, ArgList, Cardinal*); 145 static void XawTextGetValuesHook(Widget, ArgList, Cardinal*); 146 static Bool XawTextChangeSensitive(Widget); 147 148 /* 149 * Prototypes 150 */ 151 static XawTextPosition _BuildLineTable(TextWidget, XawTextPosition, int); 152 static void _CreateCutBuffers(Display*); 153 static Boolean TextConvertSelection(Widget, Atom*, Atom*, Atom*, XtPointer*, 154 unsigned long*, int*); 155 static int CountLines(TextWidget, XawTextPosition, XawTextPosition); 156 static void CreateHScrollBar(TextWidget); 157 static void CreateVScrollBar(TextWidget); 158 static void CvtStringToScrollMode(XrmValuePtr, Cardinal*, 159 XrmValuePtr, XrmValuePtr); 160 static Boolean CvtScrollModeToString(Display*, XrmValue*, Cardinal*, 161 XrmValue*, XrmValue*, XtPointer*); 162 static void CvtStringToWrapMode(XrmValuePtr, Cardinal*, 163 XrmValuePtr, XrmValuePtr); 164 static Boolean CvtWrapModeToString(Display*, XrmValue*, Cardinal*, 165 XrmValue*, XrmValue*, XtPointer*); 166 static Boolean CvtStringToJustifyMode(Display*, XrmValue*, Cardinal*, 167 XrmValue*, XrmValue*, XtPointer*); 168 static Boolean CvtJustifyModeToString(Display*, XrmValue*, Cardinal*, 169 XrmValue*, XrmValue*, XtPointer*); 170 static void DestroyHScrollBar(TextWidget); 171 static void DestroyVScrollBar(TextWidget); 172 #ifndef OLDXAW 173 static void DisplayText(Widget, XawTextPosition, XawTextPosition); 174 #endif 175 static void OldDisplayText(Widget, XawTextPosition, XawTextPosition); 176 static void DisplayTextWindow(Widget); 177 static void DoCopyArea(TextWidget, int, int, unsigned int, unsigned int, 178 int, int); 179 static void DoSelection(TextWidget, XawTextPosition, Time, Bool); 180 static void ExtendSelection(TextWidget, XawTextPosition, Bool); 181 static XawTextPosition FindGoodPosition(TextWidget, XawTextPosition); 182 static void FlushUpdate(TextWidget); 183 static int GetCutBufferNumber(Atom); 184 static int GetMaxTextWidth(TextWidget); 185 static unsigned int GetWidestLine(TextWidget); 186 static void HScroll(Widget, XtPointer, XtPointer); 187 static void HJump(Widget, XtPointer, XtPointer); 188 static void InsertCursor(Widget, XawTextInsertState); 189 static Bool LineAndXYForPosition(TextWidget, XawTextPosition, int*, 190 int*, int*); 191 static int LineForPosition(TextWidget, XawTextPosition); 192 static void TextLoseSelection(Widget, Atom*); 193 static Bool MatchSelection(Atom, XawTextSelection*); 194 static void ModifySelection(TextWidget, XawTextPosition, XawTextPosition); 195 static XawTextPosition PositionForXY(TextWidget, int, int); 196 static void PositionHScrollBar(TextWidget); 197 static void PositionVScrollBar(TextWidget); 198 #ifndef OLDXAW 199 static int ResolveColumnNumber(TextWidget); 200 static int ResolveLineNumber(TextWidget); 201 #endif 202 static void _SetSelection(TextWidget, XawTextPosition, XawTextPosition, 203 Atom*, Cardinal); 204 static void TextSinkResize(Widget); 205 static void UpdateTextInRectangle(TextWidget, XRectangle*); 206 static void UpdateTextInLine(TextWidget, int, int, int); 207 static void VScroll(Widget, XtPointer, XtPointer); 208 static void VJump(Widget, XtPointer, XtPointer); 209 210 /* 211 * External 212 */ 213 void _XawTextAlterSelection(TextWidget, 214 XawTextSelectionMode, XawTextSelectionAction, 215 String*, Cardinal*); 216 void _XawTextCheckResize(TextWidget); 217 void _XawTextClearAndCenterDisplay(TextWidget); 218 void _XawTextExecuteUpdate(TextWidget); 219 char *_XawTextGetText(TextWidget, XawTextPosition, XawTextPosition); 220 void _XawTextPrepareToUpdate(TextWidget); 221 int _XawTextReplace(TextWidget, XawTextPosition, XawTextPosition, 222 XawTextBlock*); 223 Atom *_XawTextSelectionList(TextWidget, String*, Cardinal); 224 void _XawTextSetScrollBars(TextWidget); 225 void _XawTextSetSelection(TextWidget, XawTextPosition, XawTextPosition, 226 String*, Cardinal); 227 void _XawTextVScroll(TextWidget, int); 228 void XawTextScroll(TextWidget, int, int); 229 void _XawTextSetSource(Widget, Widget, XawTextPosition, XawTextPosition); 230 #ifndef OLDXAW 231 void _XawTextSetLineAndColumnNumber(TextWidget, Bool); 232 #endif 233 void _XawTextSourceChanged(Widget, XawTextPosition, XawTextPosition, 234 XawTextBlock*, int); 235 236 /* Not used by other modules, but were extern on previous versions 237 * of the library 238 */ 239 void _XawTextShowPosition(TextWidget); 240 241 /* 242 * From TextAction.c 243 */ 244 extern void _XawTextZapSelection(TextWidget, XEvent*, Bool); 245 246 /* 247 * From TextSrc.c 248 */ 249 void _XawSourceAddText(Widget, Widget); 250 void _XawSourceRemoveText(Widget, Widget, Bool); 251 Bool _XawTextSourceNewLineAtEOF(Widget); 252 253 /* 254 * From TextSink.c 255 */ 256 void _XawTextSinkClearToBackground(Widget, int, int, unsigned, unsigned); 257 void _XawTextSinkDisplayText(Widget, int, int, XawTextPosition, XawTextPosition, 258 Bool); 259 260 /**************************************************************** 261 * 262 * Full class record constant 263 * 264 ****************************************************************/ 265 /* 266 * From TextTr.c 267 */ 268 static XawTextSelectType defaultSelectTypes[] = { 269 XawselectPosition, XawselectAlphaNumeric, XawselectWord, XawselectLine, 270 XawselectParagraph, XawselectAll, XawselectNull, 271 }; 272 273 static XPointer defaultSelectTypesPtr = (XPointer)defaultSelectTypes; 274 static Dimension defWidth = 100; 275 static Dimension defHeight = DEFAULT_TEXT_HEIGHT; 276 277 #define offset(field) XtOffsetOf(TextRec, field) 278 static XtResource resources[] = { 279 { 280 XtNwidth, 281 XtCWidth, 282 XtRDimension, 283 sizeof(Dimension), 284 offset(core.width), 285 XtRDimension, 286 (XtPointer)&defWidth 287 }, 288 { 289 XtNcursor, 290 XtCCursor, 291 XtRCursor, 292 sizeof(Cursor), 293 offset(simple.cursor), 294 XtRString, 295 (XtPointer)"xterm" 296 }, 297 { 298 XtNheight, 299 XtCHeight, 300 XtRDimension, 301 sizeof(Dimension), 302 offset(core.height), 303 XtRDimension, 304 (XtPointer)&defHeight 305 }, 306 { 307 XtNdisplayPosition, 308 XtCTextPosition, 309 XtRInt, 310 sizeof(XawTextPosition), 311 offset(text.lt.top), 312 XtRImmediate, 313 (XtPointer)0 314 }, 315 { 316 XtNinsertPosition, 317 XtCTextPosition, 318 XtRInt, 319 sizeof(XawTextPosition), 320 offset(text.insertPos), 321 XtRImmediate, 322 (XtPointer)0 323 }, 324 { 325 XtNleftMargin, 326 XtCMargin, 327 XtRPosition, 328 sizeof(Position), 329 offset(text.r_margin.left), 330 XtRImmediate, 331 (XtPointer)2 332 }, 333 { 334 XtNrightMargin, 335 XtCMargin, 336 XtRPosition, 337 sizeof(Position), 338 offset(text.r_margin.right), 339 XtRImmediate, 340 (XtPointer)4 341 }, 342 { 343 XtNtopMargin, 344 XtCMargin, 345 XtRPosition, 346 sizeof(Position), 347 offset(text.r_margin.top), 348 XtRImmediate, 349 (XtPointer)2 350 }, 351 { 352 XtNbottomMargin, 353 XtCMargin, 354 XtRPosition, 355 sizeof(Position), 356 offset(text.r_margin.bottom), 357 XtRImmediate, 358 (XtPointer)2 359 }, 360 { 361 XtNselectTypes, 362 XtCSelectTypes, 363 XtRPointer, 364 sizeof(XawTextSelectType*), 365 offset(text.sarray), 366 XtRPointer, 367 (XtPointer)&defaultSelectTypesPtr 368 }, 369 { 370 XtNtextSource, 371 XtCTextSource, 372 XtRWidget, 373 sizeof(Widget), 374 offset(text.source), 375 XtRImmediate, 376 NULL 377 }, 378 { 379 XtNtextSink, 380 XtCTextSink, 381 XtRWidget, 382 sizeof(Widget), 383 offset(text.sink), 384 XtRImmediate, 385 NULL 386 }, 387 { 388 XtNdisplayCaret, 389 XtCOutput, 390 XtRBoolean, 391 sizeof(Boolean), 392 offset(text.display_caret), 393 XtRImmediate, 394 (XtPointer)True 395 }, 396 { 397 XtNscrollVertical, 398 XtCScroll, 399 XtRScrollMode, 400 sizeof(XawTextScrollMode), 401 offset(text.scroll_vert), 402 XtRImmediate, 403 (XtPointer)False 404 }, 405 { 406 XtNscrollHorizontal, 407 XtCScroll, 408 XtRScrollMode, 409 sizeof(XawTextScrollMode), 410 offset(text.scroll_horiz), 411 XtRImmediate, 412 (XtPointer)False 413 }, 414 { 415 XtNwrap, 416 XtCWrap, 417 XtRWrapMode, 418 sizeof(XawTextWrapMode), 419 offset(text.wrap), 420 XtRImmediate, 421 (XtPointer)XawtextWrapNever 422 }, 423 { 424 XtNautoFill, 425 XtCAutoFill, 426 XtRBoolean, 427 sizeof(Boolean), 428 offset(text.auto_fill), 429 XtRImmediate, 430 (XtPointer)False 431 }, 432 #ifndef OLDXAW 433 { 434 XtNpositionCallback, 435 XtCCallback, 436 XtRCallback, 437 sizeof(XtPointer), 438 offset(text.position_callbacks), 439 XtRCallback, 440 NULL 441 }, 442 { 443 XtNleftColumn, 444 XtCColumn, 445 XtRShort, 446 sizeof(short), 447 offset(text.left_column), 448 XtRImmediate, 449 (XtPointer)0 450 }, 451 { 452 XtNrightColumn, 453 XtCColumn, 454 XtRShort, 455 sizeof(short), 456 offset(text.right_column), 457 XtRImmediate, 458 (XtPointer)0 459 }, 460 { 461 XtNjustifyMode, 462 XtCJustifyMode, 463 XtRJustifyMode, 464 sizeof(XawTextJustifyMode), 465 offset(text.justify), 466 XtRImmediate, 467 (XtPointer)XawjustifyLeft 468 }, 469 #endif /* OLDXAW */ 470 }; 471 #undef offset 472 473 #define done(address, type) \ 474 { toVal->size = sizeof(type); toVal->addr = (XPointer)address; } 475 476 static XrmQuark QWrapNever, QWrapLine, QWrapWord; 477 static XrmQuark QScrollNever, QScrollWhenNeeded, QScrollAlways; 478 static XrmQuark QJustifyLeft, QJustifyRight, QJustifyCenter, QJustifyFull; 479 480 /*ARGSUSED*/ 481 static void 482 CvtStringToScrollMode(XrmValuePtr args _X_UNUSED, Cardinal *num_args _X_UNUSED, 483 XrmValuePtr fromVal, XrmValuePtr toVal) 484 { 485 static XawTextScrollMode scrollMode = XawtextScrollNever; 486 XrmQuark q; 487 char name[32]; 488 489 XmuNCopyISOLatin1Lowered(name, (char *)fromVal->addr, sizeof(name)); 490 q = XrmStringToQuark(name); 491 492 if (q == QScrollNever || q == QScrollWhenNeeded) 493 scrollMode = XawtextScrollNever; 494 else if (q == QScrollAlways) 495 scrollMode = XawtextScrollAlways; 496 else if (strcmp(name, "true") == 0 || strcmp(name, "1") == 0) 497 scrollMode = XawtextScrollAlways; 498 else if (strcmp(name, "false") == 0 || strcmp(name, "0") == 0) 499 scrollMode = XawtextScrollNever; 500 else 501 XtStringConversionWarning((char *)fromVal->addr, XtRScrollMode); 502 503 done(&scrollMode, XawTextScrollMode); 504 } 505 506 /*ARGSUSED*/ 507 static Boolean 508 CvtScrollModeToString(Display *dpy, XrmValue *args _X_UNUSED, Cardinal *num_args _X_UNUSED, 509 XrmValue *fromVal, XrmValue *toVal _X_UNUSED, XtPointer *data _X_UNUSED) 510 { 511 static String buffer; 512 Cardinal size; 513 514 switch (*(XawTextScrollMode *)fromVal->addr) { 515 case XawtextScrollNever: 516 case XawtextScrollWhenNeeded: 517 buffer = XtEtextScrollNever; 518 break; 519 case XawtextScrollAlways: 520 buffer = XtEtextScrollAlways; 521 break; 522 default: 523 XawTypeToStringWarning(dpy, XtRScrollMode); 524 toVal->addr = NULL; 525 toVal->size = 0; 526 return (False); 527 } 528 size = (Cardinal)strlen(buffer) + 1; 529 if (toVal->addr != NULL) { 530 if (toVal->size < size) { 531 toVal->size = size; 532 return (False); 533 } 534 strcpy((char *)toVal->addr, buffer); 535 } 536 else 537 toVal->addr = (XPointer)buffer; 538 toVal->size = sizeof(String); 539 540 return (True); 541 } 542 543 /*ARGSUSED*/ 544 static void 545 CvtStringToWrapMode(XrmValuePtr args _X_UNUSED, Cardinal *num_args _X_UNUSED, 546 XrmValuePtr fromVal, XrmValuePtr toVal) 547 { 548 static XawTextWrapMode wrapMode = XawtextWrapNever; 549 XrmQuark q; 550 char lowerName[6]; 551 552 XmuNCopyISOLatin1Lowered(lowerName, (char *)fromVal->addr, 553 sizeof(lowerName)); 554 q = XrmStringToQuark(lowerName); 555 556 if (q == QWrapNever) 557 wrapMode = XawtextWrapNever; 558 else if (q == QWrapLine) 559 wrapMode = XawtextWrapLine; 560 else if (q == QWrapWord) 561 wrapMode = XawtextWrapWord; 562 else 563 XtStringConversionWarning((char *)fromVal->addr, XtRWrapMode); 564 565 done(&wrapMode, XawTextWrapMode); 566 } 567 568 /*ARGSUSED*/ 569 static Boolean 570 CvtWrapModeToString(Display *dpy, XrmValue *args _X_UNUSED, Cardinal *num_args _X_UNUSED, 571 XrmValue *fromVal, XrmValue *toVal _X_UNUSED, XtPointer *data _X_UNUSED) 572 { 573 static String buffer; 574 Cardinal size; 575 576 switch (*(XawTextWrapMode *)fromVal->addr) { 577 case XawtextWrapNever: 578 buffer = XtEtextWrapNever; 579 break; 580 case XawtextWrapLine: 581 buffer = XtEtextWrapLine; 582 break; 583 case XawtextWrapWord: 584 buffer = XtEtextWrapWord; 585 break; 586 default: 587 XawTypeToStringWarning(dpy, XtRWrapMode); 588 toVal->addr = NULL; 589 toVal->size = 0; 590 return (False); 591 } 592 size = (Cardinal)strlen(buffer) + 1; 593 if (toVal->addr != NULL) { 594 if (toVal->size < size) { 595 toVal->size = size; 596 return (False); 597 } 598 strcpy((char *)toVal->addr, buffer); 599 } 600 else 601 toVal->addr = (XPointer)buffer; 602 toVal->size = sizeof(String); 603 604 return (True); 605 } 606 607 /*ARGSUSED*/ 608 static Boolean 609 CvtStringToJustifyMode(Display *dpy _X_UNUSED, XrmValue *args _X_UNUSED, Cardinal *num_args _X_UNUSED, 610 XrmValue *fromVal, XrmValue *toVal, XtPointer *data _X_UNUSED) 611 { 612 XawTextJustifyMode justify; 613 XrmQuark q; 614 char lowerName[8]; 615 616 XmuNCopyISOLatin1Lowered(lowerName, (char *)fromVal->addr, 617 sizeof(lowerName)); 618 q = XrmStringToQuark(lowerName); 619 620 if (q == QJustifyLeft) 621 justify = XawjustifyLeft; 622 else if (q == QJustifyRight) 623 justify = XawjustifyRight; 624 else if (q == QJustifyCenter) 625 justify = XawjustifyCenter; 626 else if(q == QJustifyFull) 627 justify = XawjustifyFull; 628 else { 629 XtStringConversionWarning((char *)fromVal->addr, XtRJustifyMode); 630 return (False); 631 } 632 633 toVal->size = sizeof(XawTextJustifyMode); 634 *(XawTextJustifyMode *)(toVal->addr) = justify; 635 636 return (True); 637 } 638 639 640 /*ARGSUSED*/ 641 static Boolean 642 CvtJustifyModeToString(Display *dpy, XrmValue *args _X_UNUSED, Cardinal *num_args _X_UNUSED, 643 XrmValue *fromVal, XrmValue *toVal, XtPointer *data _X_UNUSED) 644 { 645 static String buffer; 646 Cardinal size; 647 648 switch (*(XawTextJustifyMode *)fromVal->addr) { 649 case XawjustifyLeft: 650 buffer = XtEtextJustifyLeft; 651 break; 652 case XawjustifyRight: 653 buffer = XtEtextJustifyRight; 654 break; 655 case XawjustifyCenter: 656 buffer = XtEtextJustifyCenter; 657 break; 658 case XawjustifyFull: 659 buffer = XtEtextJustifyFull; 660 break; 661 default: 662 XawTypeToStringWarning(dpy, XtRJustifyMode); 663 toVal->addr = NULL; 664 toVal->size = 0; 665 return (False); 666 } 667 size = (Cardinal)strlen(buffer) + 1; 668 if (toVal->addr != NULL) { 669 if (toVal->size < size) { 670 toVal->size = size; 671 return (False); 672 } 673 strcpy((char *)toVal->addr, buffer); 674 } 675 else 676 toVal->addr = (XPointer)buffer; 677 toVal->size = sizeof(String); 678 679 return (True); 680 } 681 682 #undef done 683 684 static void 685 XawTextClassInitialize(void) 686 { 687 if (!XawFmt8Bit) 688 FMT8BIT = XawFmt8Bit = (unsigned long)XrmPermStringToQuark("FMT8BIT"); 689 if (!XawFmtWide) 690 XawFmtWide = (unsigned long)XrmPermStringToQuark("FMTWIDE"); 691 692 XawInitializeWidgetSet(); 693 694 textClassRec.core_class.num_actions = _XawTextActionsTableCount; 695 696 QWrapNever = XrmPermStringToQuark(XtEtextWrapNever); 697 QWrapLine = XrmPermStringToQuark(XtEtextWrapLine); 698 QWrapWord = XrmPermStringToQuark(XtEtextWrapWord); 699 XtAddConverter(XtRString, XtRWrapMode, CvtStringToWrapMode, NULL, 0); 700 XtSetTypeConverter(XtRWrapMode, XtRString, CvtWrapModeToString, 701 NULL, 0, XtCacheNone, NULL); 702 QScrollNever = XrmPermStringToQuark(XtEtextScrollNever); 703 QScrollWhenNeeded = XrmPermStringToQuark(XtEtextScrollWhenNeeded); 704 QScrollAlways = XrmPermStringToQuark(XtEtextScrollAlways); 705 XtAddConverter(XtRString, XtRScrollMode, CvtStringToScrollMode, 706 NULL, 0); 707 XtSetTypeConverter(XtRScrollMode, XtRString, CvtScrollModeToString, 708 NULL, 0, XtCacheNone, NULL); 709 QJustifyLeft = XrmPermStringToQuark(XtEtextJustifyLeft); 710 QJustifyRight = XrmPermStringToQuark(XtEtextJustifyRight); 711 QJustifyCenter = XrmPermStringToQuark(XtEtextJustifyCenter); 712 QJustifyFull = XrmPermStringToQuark(XtEtextJustifyFull); 713 XtSetTypeConverter(XtRString, XtRJustifyMode, CvtStringToJustifyMode, 714 NULL, 0, XtCacheNone, NULL); 715 XtSetTypeConverter(XtRJustifyMode, XtRString, CvtJustifyModeToString, 716 NULL, 0, XtCacheNone, NULL); 717 } 718 719 /* 720 * Function: 721 * PositionHScrollBar 722 * 723 * Parameters: 724 * ctx - text widget 725 * 726 * Description: 727 * Positions the Horizontal scrollbar. 728 */ 729 static void 730 PositionHScrollBar(TextWidget ctx) 731 { 732 Widget hbar = ctx->text.hbar, vbar = ctx->text.vbar; 733 Position x, y; 734 Dimension width, height; 735 736 if (ctx->text.hbar == NULL) 737 return; 738 739 if (vbar != NULL) 740 x = (Position)XtWidth(vbar); 741 else 742 x = (Position)(-XtBorderWidth(hbar)); 743 y = (Position)(XtHeight(ctx) - XtHeight(hbar) - XtBorderWidth(hbar)); 744 if (vbar != NULL) { 745 width = (Dimension)(XtWidth(ctx) - XtWidth(vbar) - XtBorderWidth(vbar)); 746 if (width > XtWidth(ctx)) 747 width = XtWidth(ctx); 748 } 749 else 750 width = XtWidth(ctx); 751 height = XtHeight(hbar); 752 753 XtConfigureWidget(hbar, x, y, width, height, XtBorderWidth(hbar)); 754 } 755 756 /* 757 * Function: 758 * PositionVScrollBar 759 * 760 * Parameters: 761 * ctx - text widget 762 * 763 * Description: 764 * Positions the Vertical scrollbar. 765 */ 766 static void 767 PositionVScrollBar(TextWidget ctx) 768 { 769 Widget vbar = ctx->text.vbar; 770 Position x, y; 771 Dimension width, height; 772 773 if (vbar == NULL) 774 return; 775 776 x = y = (Position)(-XtBorderWidth(vbar)); 777 height = XtHeight(ctx); 778 width = XtWidth(vbar); 779 780 XtConfigureWidget(vbar, x, y, width, height, XtBorderWidth(vbar)); 781 } 782 783 static void 784 CreateVScrollBar(TextWidget ctx) 785 { 786 Widget vbar; 787 788 if (ctx->text.vbar != NULL) 789 return; 790 791 ctx->text.vbar = vbar = 792 XtCreateWidget("vScrollbar", scrollbarWidgetClass, (Widget)ctx, NULL, 0); 793 XtAddCallback(vbar, XtNscrollProc, VScroll, (XtPointer)ctx); 794 XtAddCallback(vbar, XtNjumpProc, VJump, (XtPointer)ctx); 795 796 ctx->text.r_margin.left += (Position) (XtWidth(vbar) + XtBorderWidth(vbar)); 797 ctx->text.left_margin = ctx->text.margin.left = ctx->text.r_margin.left; 798 799 PositionVScrollBar(ctx); 800 PositionHScrollBar(ctx); 801 TextSinkResize(ctx->text.sink); 802 803 if (XtIsRealized((Widget)ctx)) { 804 XtRealizeWidget(vbar); 805 XtMapWidget(vbar); 806 } 807 XtSetKeyboardFocus(vbar, (Widget)ctx); 808 } 809 810 /* 811 * Function: 812 * DestroyVScrollBar 813 * 814 * Parameters: 815 * ctx - parent text widget 816 * 817 * Description: 818 * Removes vertical ScrollBar. 819 */ 820 static void 821 DestroyVScrollBar(TextWidget ctx) 822 { 823 Widget vbar = ctx->text.vbar; 824 825 if (vbar == NULL) 826 return; 827 828 ctx->text.r_margin.left = (Position)(ctx->text.r_margin.left - (XtWidth(vbar) + XtBorderWidth(vbar))); 829 ctx->text.left_margin = ctx->text.margin.left = ctx->text.r_margin.left; 830 831 XtDestroyWidget(vbar); 832 ctx->text.vbar = NULL; 833 if (!ctx->core.being_destroyed) { 834 PositionHScrollBar(ctx); 835 TextSinkResize(ctx->text.sink); 836 } 837 } 838 839 static void 840 CreateHScrollBar(TextWidget ctx) 841 { 842 Arg args[1]; 843 Widget hbar; 844 int bottom; 845 846 if (ctx->text.hbar != NULL) 847 return; 848 849 XtSetArg(args[0], XtNorientation, XtorientHorizontal); 850 ctx->text.hbar = hbar = 851 XtCreateWidget("hScrollbar", scrollbarWidgetClass, (Widget)ctx, args, 1); 852 XtAddCallback(hbar, XtNscrollProc, HScroll, (XtPointer)ctx); 853 XtAddCallback(hbar, XtNjumpProc, HJump, (XtPointer)ctx); 854 855 bottom = ctx->text.r_margin.bottom + XtHeight(hbar) + XtBorderWidth(hbar); 856 857 ctx->text.margin.bottom = ctx->text.r_margin.bottom = (Position)bottom; 858 859 PositionHScrollBar(ctx); 860 TextSinkResize(ctx->text.sink); 861 862 if (XtIsRealized((Widget)ctx)) { 863 XtRealizeWidget(hbar); 864 XtMapWidget(hbar); 865 } 866 XtSetKeyboardFocus(hbar, (Widget)ctx); 867 } 868 869 /* 870 * Function: 871 * DestroyHScrollBar 872 * 873 * Parameters: 874 * ctx - parent text widget 875 * 876 * Description: 877 * Removes horizontal ScrollBar. 878 */ 879 static void 880 DestroyHScrollBar(TextWidget ctx) 881 { 882 Widget hbar = ctx->text.hbar; 883 884 if (hbar == NULL) 885 return; 886 887 ctx->text.r_margin.bottom = (Position)(ctx->text.r_margin.bottom 888 - (XtHeight(hbar) 889 + XtBorderWidth(hbar))); 890 ctx->text.margin.bottom = ctx->text.r_margin.bottom; 891 892 XtDestroyWidget(hbar); 893 ctx->text.hbar = NULL; 894 if (!ctx->core.being_destroyed) 895 TextSinkResize(ctx->text.sink); 896 } 897 898 /*ARGSUSED*/ 899 static void 900 XawTextInitialize(Widget request _X_UNUSED, Widget cnew, 901 ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED) 902 { 903 TextWidget ctx = (TextWidget)cnew; 904 905 ctx->text.lt.lines = 0; 906 ctx->text.lt.info = (XawTextLineTableEntry *) 907 XtCalloc(1, sizeof(XawTextLineTableEntry)); 908 #ifndef OLDXAW 909 ctx->text.lt.base_line = 1; 910 #endif 911 (void)bzero(&ctx->text.origSel, sizeof(XawTextSelection)); 912 (void)bzero(&ctx->text.s, sizeof(XawTextSelection)); 913 ctx->text.s.type = XawselectPosition; 914 ctx->text.salt = NULL; 915 ctx->text.hbar = ctx->text.vbar = NULL; 916 ctx->text.lasttime = 0; 917 ctx->text.time = 0; 918 ctx->text.showposition = True; 919 ctx->text.lastPos = ctx->text.source != NULL ? 920 XawTextGetLastPosition(ctx) : 0; 921 ctx->text.file_insert = NULL; 922 ctx->text.search = NULL; 923 ctx->text.update = XmuNewScanline(0, 0, 0); 924 ctx->text.gc = XtGetGC(cnew, 0, 0); 925 ctx->text.hasfocus = False; 926 ctx->text.margin = ctx->text.r_margin; /* Structure copy */ 927 ctx->text.left_margin = ctx->text.r_margin.left; 928 ctx->text.update_disabled = False; 929 ctx->text.clear_to_eol = True; 930 ctx->text.old_insert = -1; 931 ctx->text.mult = 1; 932 ctx->text.salt2 = NULL; 933 ctx->text.from_left = -1; 934 935 #ifndef OLDXAW 936 ctx->text.numeric = False; 937 ctx->text.selection_state = False; 938 ctx->text.kill_ring = 0; 939 940 ctx->text.line_number = -1; 941 ctx->text.column_number = -1; 942 ctx->text.source_changed = SRC_CHANGE_NONE; 943 944 ctx->text.kill_ring_ptr = NULL; 945 ctx->text.overwrite = False; 946 #endif 947 948 if (XtHeight(ctx) == DEFAULT_TEXT_HEIGHT) { 949 XtHeight(ctx) = (Dimension)VMargins(ctx); 950 if (ctx->text.sink != NULL) 951 XtHeight(ctx) += (Dimension) XawTextSinkMaxHeight(ctx->text.sink, 1); 952 } 953 954 if (ctx->text.scroll_vert == XawtextScrollAlways) 955 CreateVScrollBar(ctx); 956 if (ctx->text.scroll_horiz == XawtextScrollAlways) 957 CreateHScrollBar(ctx); 958 959 #ifndef OLDXAW 960 if (ctx->text.left_column < 0) 961 ctx->text.left_column = 0; 962 if (ctx->text.right_column < 0) 963 ctx->text.right_column = 0; 964 #endif 965 } 966 967 static void 968 XawTextRealize(Widget w, XtValueMask *mask, XSetWindowAttributes *attr) 969 { 970 TextWidget ctx = (TextWidget)w; 971 972 (*textClassRec.core_class.superclass->core_class.realize)(w, mask, attr); 973 974 if (ctx->text.hbar != NULL) { 975 XtRealizeWidget(ctx->text.hbar); 976 XtMapWidget(ctx->text.hbar); 977 } 978 979 if (ctx->text.vbar != NULL) { 980 XtRealizeWidget(ctx->text.vbar); 981 XtMapWidget(ctx->text.vbar); 982 } 983 984 _XawTextBuildLineTable(ctx, ctx->text.lt.top, True); 985 986 #ifndef OLDXAW 987 _XawTextSetLineAndColumnNumber(ctx, True); 988 #endif 989 } 990 991 /* Utility routines for support of Text */ 992 static void 993 _CreateCutBuffers(Display *d) 994 { 995 static struct _DisplayRec { 996 struct _DisplayRec *next; 997 Display *dpy; 998 } *dpy_list = NULL; 999 struct _DisplayRec *dpy_ptr; 1000 1001 for (dpy_ptr = dpy_list; dpy_ptr != NULL; dpy_ptr = dpy_ptr->next) 1002 if (dpy_ptr->dpy == d) 1003 return; 1004 1005 dpy_ptr = XtNew(struct _DisplayRec); 1006 dpy_ptr->next = dpy_list; 1007 dpy_ptr->dpy = d; 1008 dpy_list = dpy_ptr; 1009 1010 #define Create(buffer) \ 1011 XChangeProperty(d, RootWindow(d, 0), buffer, XA_STRING, 8, \ 1012 PropModeAppend, NULL, 0); 1013 1014 Create(XA_CUT_BUFFER0); 1015 Create(XA_CUT_BUFFER1); 1016 Create(XA_CUT_BUFFER2); 1017 Create(XA_CUT_BUFFER3); 1018 Create(XA_CUT_BUFFER4); 1019 Create(XA_CUT_BUFFER5); 1020 Create(XA_CUT_BUFFER6); 1021 Create(XA_CUT_BUFFER7); 1022 1023 #undef Create 1024 } 1025 1026 /* 1027 * Procedure to manage insert cursor visibility for editable text. It uses 1028 * the value of ctx->insertPos and an implicit argument. In the event that 1029 * position is immediately preceded by an eol graphic, then the insert cursor 1030 * is displayed at the beginning of the next line. 1031 */ 1032 static void 1033 InsertCursor(Widget w, XawTextInsertState state) 1034 { 1035 TextWidget ctx = (TextWidget)w; 1036 int x, y; 1037 int line; 1038 1039 if (ctx->text.lt.lines < 1) 1040 return; 1041 1042 if (ctx->text.display_caret && 1043 LineAndXYForPosition(ctx, ctx->text.insertPos, &line, &x, &y)) { 1044 if (line < ctx->text.lt.lines) 1045 y += (ctx->text.lt.info[line + 1].y - ctx->text.lt.info[line].y) + 1; 1046 else 1047 y += (ctx->text.lt.info[line].y - ctx->text.lt.info[line - 1].y) + 1; 1048 1049 XawTextSinkInsertCursor(ctx->text.sink, (Position)x, (Position)y, state); 1050 } 1051 1052 /* Keep Input Method up to speed */ 1053 if (ctx->simple.international) { 1054 Arg list[1]; 1055 1056 XtSetArg(list[0], XtNinsertPosition, ctx->text.insertPos); 1057 _XawImSetValues(w, list, 1); 1058 } 1059 } 1060 1061 /* 1062 * Procedure to register a span of text that is no longer valid on the display 1063 * It is used to avoid a number of small, and potentially overlapping, screen 1064 * updates. 1065 */ 1066 void 1067 _XawTextNeedsUpdating(TextWidget ctx, 1068 XawTextPosition left, XawTextPosition right) 1069 { 1070 if (left >= right) 1071 return; 1072 else { 1073 XmuSegment segment = { 1074 .x1 = (int)left, 1075 .x2 = (int)right 1076 }; 1077 1078 (void)XmuScanlineOrSegment(ctx->text.update, &segment); 1079 } 1080 } 1081 1082 /* 1083 * Procedure to read a span of text in Ascii form. This is purely a hack and 1084 * we probably need to add a function to sources to provide this functionality. 1085 * [note: this is really a private procedure but is used in multiple modules]. 1086 */ 1087 char * 1088 _XawTextGetText(TextWidget ctx, XawTextPosition left, XawTextPosition right) 1089 { 1090 char *result, *tempResult; 1091 XawTextBlock text; 1092 int bytes; 1093 1094 if (XawTextFormat(ctx, XawFmt8Bit)) 1095 bytes = sizeof(unsigned char); 1096 else if (XawTextFormat(ctx, XawFmtWide)) 1097 bytes = sizeof(wchar_t); 1098 else /* if there is another format, add here */ 1099 bytes = 1; 1100 1101 /* leave space for ZERO */ 1102 tempResult = result = XtMalloc((unsigned)(right - left + ONE) * (unsigned)bytes); 1103 1104 while (left < right) { 1105 left = SrcRead(ctx->text.source, left, &text, (int)(right - left)); 1106 if (!text.length) 1107 break; 1108 memmove(tempResult, text.ptr, (unsigned)(text.length * bytes)); 1109 tempResult += text.length * bytes; 1110 } 1111 1112 if (bytes == sizeof(wchar_t)) 1113 *((wchar_t*)tempResult) = (wchar_t)0; 1114 else 1115 *tempResult = '\0'; 1116 1117 return (result); 1118 } 1119 1120 /* Like _XawTextGetText, but enforces ICCCM STRING type encoding. This 1121 * routine is currently used to put just the ASCII chars in the selection 1122 * into a cut buffer. 1123 */ 1124 char * 1125 _XawTextGetSTRING(TextWidget ctx, XawTextPosition left, XawTextPosition right) 1126 { 1127 /* allow ESC in accordance with ICCCM */ 1128 if (XawTextFormat(ctx, XawFmtWide)) { 1129 MultiSinkObject sink = (MultiSinkObject)ctx->text.sink; 1130 wchar_t *ws = (wchar_t *)_XawTextGetText(ctx, left, right); 1131 long n = (long)wcslen(ws); 1132 long i, j; 1133 1134 for (j = 0, i = 0; j < n; j++) { 1135 wchar_t wc = ws[j]; 1136 if (XwcTextEscapement (sink->multi_sink.fontset, &wc, 1) 1137 || (wc == _Xaw_atowc(XawTAB)) || (wc == _Xaw_atowc(XawLF)) 1138 || (wc == _Xaw_atowc(XawESC))) 1139 ws[i++] = wc; 1140 } 1141 ws[i] = (wchar_t)0; 1142 return ((char *)ws); 1143 } 1144 else { 1145 unsigned char *s = (unsigned char *)_XawTextGetText(ctx, left, right); 1146 /* only HT and NL control chars are allowed, strip out others */ 1147 long n = (long)strlen((char *)s); 1148 long i = 0, j; 1149 1150 for (j = 0; j < n; j++) { 1151 unsigned char c = s[j]; 1152 if (((c >= 0x20) && c <= 0x7f) 1153 ||(c >= 0xa0) || (c == XawTAB) || (c == XawLF) 1154 || (c == XawESC)) { 1155 s[i] = c; 1156 i++; 1157 } 1158 } 1159 s[i] = 0; 1160 1161 return ((char *)s); 1162 } 1163 } 1164 1165 /* 1166 * This routine maps an x and y position in a window that is displaying text 1167 * into the corresponding position in the source. 1168 */ 1169 static XawTextPosition 1170 PositionForXY(TextWidget ctx, int x, int y) 1171 { 1172 int fromx, line, width, height; 1173 XawTextPosition position; 1174 1175 if (ctx->text.lt.lines == 0) 1176 return (0); 1177 1178 for (line = 0; line < ctx->text.lt.lines - 1; line++) { 1179 if (y <= ctx->text.lt.info[line + 1].y) 1180 break; 1181 } 1182 position = ctx->text.lt.info[line].position; 1183 if (position >= ctx->text.lastPos) 1184 return (ctx->text.lastPos); 1185 fromx = ctx->text.left_margin; 1186 XawTextSinkFindPosition(ctx->text.sink, position, fromx, x - fromx, 1187 False, &position, &width, &height); 1188 1189 if (position > ctx->text.lastPos) 1190 return (ctx->text.lastPos); 1191 1192 if (position >= ctx->text.lt.info[line + 1].position) 1193 position = SrcScan(ctx->text.source, ctx->text.lt.info[line + 1].position, 1194 XawstPositions, XawsdLeft, 1, True); 1195 1196 return (position); 1197 } 1198 1199 /* 1200 * This routine maps a source position in to the corresponding line number 1201 * of the text that is displayed in the window. 1202 */ 1203 static int 1204 LineForPosition(TextWidget ctx, XawTextPosition position) 1205 { 1206 int line; 1207 1208 for (line = 0; line < ctx->text.lt.lines; line++) 1209 if (position < ctx->text.lt.info[line + 1].position) 1210 break; 1211 1212 return (line); 1213 } 1214 1215 /* 1216 * This routine maps a source position into the corresponding line number 1217 * and the x, y coordinates of the text that is displayed in the window. 1218 */ 1219 static Bool 1220 LineAndXYForPosition(TextWidget ctx, XawTextPosition pos, 1221 int *line, int *x, int *y) 1222 { 1223 Boolean visible; 1224 1225 *line = 0; 1226 *x = ctx->text.left_margin; 1227 *y = ctx->text.margin.top + 1; 1228 if ((visible = IsPositionVisible(ctx, pos)) != False) { 1229 XawTextPosition linePos, endPos; 1230 int realW, realH; 1231 1232 *line = LineForPosition(ctx, pos); 1233 *y = ctx->text.lt.info[*line].y; 1234 linePos = ctx->text.lt.info[*line].position; 1235 XawTextSinkFindDistance(ctx->text.sink, linePos, 1236 *x, pos, &realW, &endPos, &realH); 1237 *x += realW; 1238 } 1239 1240 return (visible); 1241 } 1242 1243 /* 1244 * This routine builds a line table. It does this by starting at the 1245 * specified position and measuring text to determine the staring position 1246 * of each line to be displayed. It also determines and saves in the 1247 * linetable all the required metrics for displaying a given line (e.g. 1248 * x offset, y offset, line length, etc.). 1249 */ 1250 void 1251 _XawTextBuildLineTable(TextWidget ctx, XawTextPosition position, 1252 _XtBoolean force_rebuild) 1253 { 1254 int lines = 0; 1255 Cardinal size; 1256 1257 if ((int)XtHeight(ctx) > VMargins(ctx)) { 1258 Dimension height = (Dimension)(XtHeight(ctx) - VMargins(ctx)); 1259 lines = XawTextSinkMaxLines(ctx->text.sink, height); 1260 } 1261 size = (Cardinal)(sizeof(XawTextLineTableEntry) * (size_t)(lines + 1)); 1262 1263 if (lines != ctx->text.lt.lines || ctx->text.lt.info == NULL) { 1264 ctx->text.lt.info = (XawTextLineTableEntry *) 1265 XtRealloc((char *)ctx->text.lt.info, size); 1266 ctx->text.lt.lines = lines; 1267 force_rebuild = True; 1268 } 1269 1270 if (force_rebuild) { 1271 (void)bzero((char *)ctx->text.lt.info, size); 1272 /* force a text update in the first text line if it is visible */ 1273 ctx->text.lt.info[0].position = (XawTextPosition)-1; 1274 } 1275 if (position != ctx->text.lt.info[0].position) { 1276 (void)_BuildLineTable(ctx, position, 0); 1277 ctx->text.clear_to_eol = True; 1278 } 1279 } 1280 1281 /* 1282 * We may need to resize the line table here, since there maybe lines with 1283 * different fonts (that can be shorter or taller than the default one) 1284 */ 1285 static XawTextPosition 1286 _BuildLineTable(TextWidget ctx, XawTextPosition position, int line) 1287 { 1288 XawTextLineTableEntry *lt = ctx->text.lt.info + line; 1289 XawTextPosition end, update_from = -1; 1290 Position y; 1291 int wwidth, width, height; 1292 #ifndef OLDXAW 1293 Widget src = ctx->text.source; 1294 #endif 1295 int max_y = (int)XtHeight(ctx) - (int)ctx->text.margin.bottom; 1296 1297 if (ctx->text.wrap == XawtextWrapNever) 1298 wwidth = 0x7fffffff; 1299 else 1300 wwidth = GetMaxTextWidth(ctx); 1301 1302 /* XXX y may change, due to font size changes. See later */ 1303 y = line == 0 ? ctx->text.margin.top : lt->y; 1304 1305 #ifndef OLDXAW 1306 if (ctx->text.lt.base_line < 0) { 1307 if (line == 0) 1308 ctx->text.lt.top = position; 1309 } 1310 else if (line == 0) { 1311 XawTextPosition pos = ctx->text.lt.top; 1312 int base_line = ctx->text.lt.base_line; 1313 1314 if (position == 0) 1315 base_line = 1; 1316 else if (ctx->text.lt.base_line == 0 || 1317 ctx->text.source_changed == SRC_CHANGE_OVERLAP) { 1318 pos = 0; 1319 base_line = 1; 1320 1321 while (pos < position) { 1322 pos = SrcScan(src, pos, XawstEOL, XawsdRight, 1, True); 1323 if (pos <= position) { 1324 ++base_line; 1325 if (pos == ctx->text.lastPos) { 1326 base_line -= !_XawTextSourceNewLineAtEOF(src); 1327 break; 1328 } 1329 } 1330 } 1331 } 1332 else if (ctx->text.wrap == XawtextWrapNever 1333 && IsPositionVisible(ctx, position)) 1334 base_line += LineForPosition(ctx, position); 1335 else if (pos < position) { 1336 while (pos < position) { 1337 pos = SrcScan(src, pos, XawstEOL, XawsdRight, 1, True); 1338 if (pos <= position) { 1339 ++base_line; 1340 if (pos == ctx->text.lastPos) { 1341 base_line -= !_XawTextSourceNewLineAtEOF(src); 1342 break; 1343 } 1344 } 1345 } 1346 } 1347 else if (pos > position) { 1348 while (pos > position) { 1349 pos = SrcScan(src, pos, XawstEOL, XawsdLeft, 1, False); 1350 if (--pos >= position) 1351 --base_line; 1352 } 1353 } 1354 1355 ctx->text.lt.top = position; 1356 ctx->text.lt.base_line = base_line; 1357 } 1358 #else 1359 if (line == 0) 1360 ctx->text.lt.top = position; 1361 #endif 1362 1363 /* CONSTCOND */ 1364 while (True) { 1365 XawTextSinkFindPosition(ctx->text.sink, position, ctx->text.left_margin, 1366 wwidth, ctx->text.wrap == XawtextWrapWord, 1367 &end, &width, &height); 1368 1369 if (lt->position != position) { 1370 _XawTextNeedsUpdating(ctx, position, 1371 end <= position ? position + 1 : end); 1372 ctx->text.clear_to_eol = True; 1373 lt->position = position; 1374 } 1375 if (lt->y != y) { 1376 if (update_from < 0) 1377 update_from = line == 0 ? 1378 ctx->text.lt.info[0].position : 1379 ctx->text.lt.info[line - 1].position; 1380 lt->y = y; 1381 ctx->text.clear_to_eol = True; 1382 } 1383 if (lt->textWidth != (Cardinal)width) { 1384 if (lt->textWidth > (Cardinal)width) 1385 ctx->text.clear_to_eol = True; 1386 lt->textWidth = (Dimension)width; 1387 } 1388 y = (Position)(y + height); 1389 1390 if (end > ctx->text.lastPos) { 1391 position = end; 1392 ctx->text.clear_to_eol = True; 1393 _XawTextNeedsUpdating(ctx, end, end + ctx->text.lt.lines - line); 1394 while (line++ < ctx->text.lt.lines) { 1395 if (line > 1 && y > max_y) { 1396 ctx->text.lt.lines = line - 1; 1397 break; 1398 } 1399 ++lt; 1400 if (lt->y != y) { 1401 if (update_from < 0) 1402 update_from = line < 2 ? 1403 ctx->text.lt.info[0].position : 1404 ctx->text.lt.info[line - 2].position; 1405 lt->y = y; 1406 } 1407 lt->position = ++position; 1408 lt->textWidth = 0; 1409 y = (Position)(y + height); 1410 } 1411 if (update_from >= 0) 1412 _XawTextNeedsUpdating(ctx, update_from, 1413 ctx->text.lt.info[ctx->text.lt.lines].position); 1414 _XawTextSetScrollBars(ctx); 1415 1416 return (ctx->text.lastPos); 1417 } 1418 1419 if (line && y > max_y) 1420 /* will return in the next loop */ 1421 ctx->text.lt.lines = line; 1422 1423 if (++line > ctx->text.lt.lines && y < max_y) { 1424 /* grow the line table */ 1425 ctx->text.lt.info = (XawTextLineTableEntry *) 1426 XtRealloc((char *)ctx->text.lt.info, 1427 (Cardinal)(sizeof(XawTextLineTableEntry) * (size_t)(line + 1))); 1428 lt = ctx->text.lt.info + line; 1429 bzero(lt, sizeof(XawTextLineTableEntry)); 1430 ++ctx->text.lt.lines; 1431 } 1432 else 1433 ++lt; 1434 if (position == end) 1435 ++position; 1436 else 1437 position = end; 1438 1439 if (line > ctx->text.lt.lines) { 1440 if (update_from >= 0) 1441 _XawTextNeedsUpdating(ctx, update_from, 1442 ctx->text.lt.info[ctx->text.lt.lines].position); 1443 _XawTextSetScrollBars(ctx); 1444 1445 return (position); 1446 } 1447 } 1448 /*NOTREACHED*/ 1449 } 1450 1451 /* 1452 * Function: 1453 * GetWidestLine 1454 * 1455 * Parameters: 1456 * ctx - text widget 1457 * 1458 * Description: 1459 * Returns the width (in pixels) of the widest line that 1460 * is currently visible. 1461 * 1462 * Returns: 1463 * The width of the widest line 1464 */ 1465 static unsigned int 1466 GetWidestLine(TextWidget ctx) 1467 { 1468 int i; 1469 unsigned int widest; 1470 XawTextLineTablePtr lt = &(ctx->text.lt); 1471 1472 for (i = 0, widest = 0; i < lt->lines; i++) 1473 if (widest < lt->info[i].textWidth) 1474 widest = lt->info[i].textWidth; 1475 1476 return (widest); 1477 } 1478 1479 /* 1480 * This routine is used by Text to notify an associated scrollbar of the 1481 * correct metrics (position and shown fraction) for the text being currently 1482 * displayed in the window. 1483 */ 1484 void 1485 _XawTextSetScrollBars(TextWidget ctx) 1486 { 1487 float first; 1488 1489 if (ctx->text.scroll_vert == XawtextScrollAlways) { 1490 float last; 1491 1492 if (ctx->text.lastPos == 0) 1493 first = 0.0; 1494 else 1495 first = (float)ctx->text.lt.top / (float)ctx->text.lastPos; 1496 1497 if (ctx->text.lt.info[ctx->text.lt.lines].position < ctx->text.lastPos) 1498 last = (float)ctx->text.lt.info[ctx->text.lt.lines].position / 1499 (float)ctx->text.lastPos; 1500 else 1501 last = 1.0; 1502 1503 XawScrollbarSetThumb(ctx->text.vbar, first, last - first); 1504 } 1505 1506 if (ctx->text.scroll_horiz == XawtextScrollAlways) { 1507 unsigned value = GetWidestLine(ctx); 1508 float denom = (float)value; 1509 float widest; 1510 1511 if (denom <= 0) 1512 denom = (float)((int)XtWidth(ctx) - RHMargins(ctx)); 1513 if (denom <= 0) 1514 denom = 1; 1515 widest = (float)((int)XtWidth(ctx) - RHMargins(ctx)) / denom; 1516 first = (float)(ctx->text.r_margin.left - ctx->text.left_margin); 1517 first /= denom; 1518 1519 XawScrollbarSetThumb(ctx->text.hbar, first, widest); 1520 } 1521 } 1522 1523 static void 1524 DoCopyArea(TextWidget ctx, int src_x, int src_y, 1525 unsigned int width, unsigned int height, int dst_x, int dst_y) 1526 { 1527 int x1, y1, x2, y2; 1528 1529 x1 = ctx->text.r_margin.left; 1530 y1 = ctx->text.r_margin.top; 1531 x2 = XtWidth(ctx) - ctx->text.r_margin.right; 1532 y2 = XtHeight(ctx) - ctx->text.r_margin.bottom; 1533 1534 if (x1 >= x2 || y1 >= y2) 1535 return; 1536 1537 src_x = XawMax(x1, XawMin(src_x, x2)); 1538 src_y = XawMax(y1, XawMin(src_y, y2)); 1539 dst_x = XawMax(x1, XawMin(dst_x, x2)); 1540 dst_y = XawMax(y1, XawMin(dst_y, y2)); 1541 width = (unsigned)XawMax(0, XawMin(x2 - dst_x, (int)width)); 1542 height = (unsigned)XawMax(0, XawMin(y2 - dst_y, (int)height)); 1543 1544 XCopyArea(XtDisplay(ctx), XtWindow(ctx), XtWindow(ctx), ctx->text.gc, 1545 src_x, src_y, width, height, dst_x, dst_y); 1546 } 1547 1548 /* 1549 * Function: 1550 * XawTextScroll 1551 * 1552 * Parameters: 1553 * ctx - text widget 1554 * vlines - number of lines to scroll vertically 1555 * hpixels - number of pixels to scroll horizontally 1556 * 1557 * Description: 1558 * Generic function for scrolling the text window. 1559 * Allows vertical and horizontal scroll at the same time. 1560 */ 1561 void 1562 XawTextScroll(TextWidget ctx, int vlines, int hpixels) 1563 { 1564 XawTextPosition top, tmp, update_from, update_to; 1565 XawTextLineTable *lt; 1566 Arg arglist[1]; 1567 int y0, y1, y2, count, dim, wwidth, lines = ctx->text.lt.lines; 1568 int vwidth, vheight; /* visible width and height */ 1569 Bool scroll; 1570 1571 vwidth = (int)XtWidth(ctx) - RHMargins(ctx); 1572 vheight = (int)XtHeight(ctx) - RVMargins(ctx); 1573 lt = &ctx->text.lt; 1574 1575 if (!lt || vwidth <= 0 || vheight <= 0) 1576 return; 1577 1578 if ((scroll = ctx->core.background_pixmap == XtUnspecifiedPixmap) == True) { 1579 dim = lt->info[1].y - lt->info[0].y; 1580 for (count = 1; count < lt->lines - 1; count++) 1581 if (lt->info[count + 1].y - lt->info[count].y != dim) { 1582 scroll = False; 1583 break; 1584 } 1585 } 1586 1587 wwidth = GetMaxTextWidth(ctx); 1588 1589 /* 1590 * Do the horizontall scrolling 1591 */ 1592 if (hpixels < 0 && ctx->text.left_margin - hpixels > ctx->text.r_margin.left) 1593 hpixels = ctx->text.left_margin - ctx->text.r_margin.left; 1594 ctx->text.left_margin -= hpixels; 1595 1596 update_from = lt->top; /* remember the old value */ 1597 /* 1598 * Checks the requested number of lines and calculates the top 1599 * of the line table 1600 */ 1601 if (vlines < 0) { /* VScroll Up */ 1602 if (IsPositionVisible(ctx, 0)) 1603 vlines = 0; 1604 else if (ctx->text.wrap != XawtextWrapNever) { 1605 XawTextPosition end; 1606 int n_lines = 0; 1607 1608 count = -vlines; 1609 end = lt->top; 1610 while (n_lines < count) { 1611 top = SrcScan(ctx->text.source, end, XawstEOL, 1612 XawsdLeft, 2, False); 1613 n_lines += CountLines(ctx, top, end); 1614 end = top; 1615 } 1616 1617 while (count++ < n_lines) { 1618 tmp = top; 1619 XawTextSinkFindPosition(ctx->text.sink, top, 1620 ctx->text.left_margin, 1621 wwidth,ctx->text.wrap == XawtextWrapWord, 1622 &top, &dim, &dim); 1623 if (tmp == top) 1624 ++top; 1625 } 1626 } 1627 else 1628 top = SrcScan(ctx->text.source, lt->top, XawstEOL, 1629 XawsdLeft, -vlines + 1, False); 1630 if (-vlines >= ctx->text.lt.lines) 1631 scroll = False; 1632 } 1633 else if (vlines > 0) { /* VScroll Down */ 1634 if (LineForPosition(ctx, ctx->text.lastPos) == 0) 1635 vlines = 0; 1636 if (vlines < lt->lines) 1637 top = XawMin(lt->info[vlines].position, ctx->text.lastPos); 1638 else if (ctx->text.wrap == XawtextWrapNever) 1639 top = SrcScan(ctx->text.source, 1640 SrcScan(ctx->text.source, lt->top, 1641 XawstEOL, XawsdRight, vlines, 1642 True), 1643 XawstEOL, XawsdLeft, 1, False); 1644 else { 1645 top = lt->top; 1646 count = 0; 1647 while (count++ < vlines) { 1648 tmp = top; 1649 XawTextSinkFindPosition(ctx->text.sink, top, 1650 ctx->text.left_margin, 1651 wwidth, ctx->text.wrap == XawtextWrapWord, 1652 &top, &dim, &dim); 1653 if (tmp == top) 1654 ++top; 1655 } 1656 } 1657 if (vlines >= ctx->text.lt.lines 1658 || lt->info[vlines].position >= ctx->text.lastPos) 1659 scroll = False; 1660 } 1661 1662 if (!vlines) { 1663 if (hpixels) { 1664 ClearWindow(ctx); 1665 ctx->text.clear_to_eol = True; 1666 } 1667 _XawTextSetScrollBars(ctx); 1668 return; 1669 } 1670 1671 /* Flushes any pending updates. Normally, there may be a call to 1672 * XawTextUnsetSelection not yet updated. 1673 */ 1674 if (!hpixels && scroll) { 1675 ctx->text.clear_to_eol = True; 1676 FlushUpdate(ctx); 1677 } 1678 1679 /* 1680 * Rebuild the line table, doing the vertical scroll 1681 */ 1682 (void)_BuildLineTable(ctx, top, 0); 1683 lt = &ctx->text.lt; 1684 if (scroll) { 1685 for (count = 0; count < lt->lines - 1; count++) 1686 if (lt->info[count + 1].y - lt->info[count].y != dim) { 1687 scroll = False; 1688 break; 1689 } 1690 } 1691 1692 XtSetArg(arglist[0], XtNinsertPosition, lt->top + lt->lines); 1693 _XawImSetValues((Widget)ctx, arglist, 1); 1694 1695 if (hpixels || !scroll || lines != lt->lines) 1696 return; 1697 1698 /* _BuildLineTable updates everything if the top position changes. 1699 * It is not required here. 1700 */ 1701 (void)XmuScanlineXor(ctx->text.update, ctx->text.update); 1702 if (vlines < 0 && IsPositionVisible(ctx, 0)) 1703 vlines = -LineForPosition(ctx, update_from); 1704 1705 y0 = ctx->text.r_margin.top; 1706 if (vlines < 0) { 1707 update_from = lt->top; 1708 update_to = lt->info[-vlines + 1].position - 1; 1709 y1 = lt->info[lt->lines + vlines].y; 1710 y2 = lt->info[-vlines].y; 1711 DoCopyArea(ctx, ctx->text.r_margin.left, y0, (unsigned)vwidth, 1712 (unsigned)(y1 - y0), 1713 ctx->text.r_margin.left, y2); 1714 } 1715 else { 1716 update_from = lt->info[lt->lines - vlines].position; 1717 update_to = lt->info[lt->lines].position; 1718 y2 = lt->info[vlines].y; 1719 DoCopyArea(ctx, ctx->text.r_margin.left, y2, 1720 (unsigned)vwidth, (unsigned)(lt->info[lt->lines].y - y2), 1721 ctx->text.r_margin.left, y0); 1722 } 1723 _XawTextNeedsUpdating(ctx, update_from, update_to); 1724 ctx->text.clear_to_eol = True; 1725 } 1726 1727 /* 1728 * The routine will scroll the displayed text by lines. If the arg is 1729 * positive, move up; otherwise, move down. [note: this is really a private 1730 * procedure but is used in multiple modules]. 1731 */ 1732 void 1733 _XawTextVScroll(TextWidget ctx, int n) 1734 { 1735 XawTextScroll(ctx, n, 0); 1736 } 1737 1738 /*ARGSUSED*/ 1739 static void 1740 HScroll(Widget w _X_UNUSED, XtPointer closure, XtPointer callData) 1741 { 1742 TextWidget ctx = (TextWidget)closure; 1743 long pixels = (long)callData; 1744 1745 if (pixels > 0) { 1746 long max; 1747 1748 max = (int)GetWidestLine(ctx) + ctx->text.left_margin - 1749 ctx->text.r_margin.left; 1750 max = XawMax(0, max); 1751 pixels = XawMin(pixels, max); 1752 } 1753 1754 if (pixels) { 1755 _XawTextPrepareToUpdate(ctx); 1756 XawTextScroll(ctx, 0, (int)pixels); 1757 _XawTextExecuteUpdate(ctx); 1758 } 1759 } 1760 1761 /*ARGSUSED*/ 1762 static void 1763 HJump(Widget w, XtPointer closure, XtPointer callData) 1764 { 1765 TextWidget ctx = (TextWidget)closure; 1766 float percent = *(float *)callData; 1767 unsigned value = GetWidestLine(ctx); 1768 long pixels; 1769 1770 pixels = ctx->text.left_margin - 1771 (ctx->text.r_margin.left - (int)(percent * (float)value)); 1772 1773 HScroll(w, (XtPointer)ctx, (XtPointer)pixels); 1774 } 1775 1776 /* 1777 * Function: 1778 * UpdateTextInLine 1779 * 1780 * Parameters: 1781 * ctx - text widget 1782 * line - line to update 1783 * x1 - left pixel 1784 * x2 - right pixel 1785 * 1786 * Description: 1787 * Updates the text in the given line and pixel interval 1788 */ 1789 static void 1790 UpdateTextInLine(TextWidget ctx, int line, int x1, int x2) 1791 { 1792 XawTextLineTableEntry *lt = ctx->text.lt.info + line; 1793 XawTextPosition left, right; 1794 int from_x, width, height; 1795 1796 if (lt->position >= ctx->text.lastPos 1797 || ctx->text.left_margin > x2 1798 || (int)lt->textWidth + ctx->text.left_margin < x1) { 1799 /* Mark line to be cleared */ 1800 if (ctx->text.clear_to_eol) 1801 _XawTextNeedsUpdating(ctx, lt->position, lt->position + 1); 1802 return; 1803 } 1804 1805 from_x = ctx->text.left_margin; 1806 XawTextSinkFindPosition(ctx->text.sink, lt->position, 1807 from_x, x1 - from_x, 1808 False, &left, &width, &height); 1809 if (line == ctx->text.lt.lines) 1810 right = -1; 1811 else if ((Cardinal)x2 >= (lt->textWidth - (unsigned)from_x)) 1812 right = lt[1].position - 1; 1813 else { 1814 from_x += width; 1815 XawTextSinkFindPosition(ctx->text.sink, left, 1816 from_x, x2 - from_x, 1817 False, &right, &width, &height); 1818 } 1819 1820 if ((right < 0) || (right + 1 <= lt[1].position)) 1821 ++right; 1822 1823 /* Mark text interval to be repainted */ 1824 _XawTextNeedsUpdating(ctx, left, right); 1825 } 1826 1827 /* 1828 * The routine will scroll the displayed text by pixels. If the calldata is 1829 * positive, move up; otherwise, move down. 1830 */ 1831 /*ARGSUSED*/ 1832 static void 1833 VScroll(Widget w _X_UNUSED, XtPointer closure, XtPointer callData) 1834 { 1835 TextWidget ctx = (TextWidget)closure; 1836 long height, lines = (long)callData; 1837 1838 height = XtHeight(ctx) - VMargins(ctx); 1839 if (height < 1) 1840 height = 1; 1841 lines = (lines * ctx->text.lt.lines) / height; 1842 _XawTextPrepareToUpdate(ctx); 1843 XawTextScroll(ctx, (int)lines, 0); 1844 _XawTextExecuteUpdate(ctx); 1845 } 1846 1847 /*ARGSUSED*/ 1848 static void 1849 VJump(Widget w _X_UNUSED, XtPointer closure, XtPointer callData) 1850 { 1851 float percent = *(float *)callData; 1852 TextWidget ctx = (TextWidget)closure; 1853 XawTextPosition top, last, position, tmp; 1854 XawTextLineTable *lt = &(ctx->text.lt); 1855 int dim, vlines = 0, wwidth = GetMaxTextWidth(ctx); 1856 Bool scroll = True; 1857 1858 position = (XawTextPosition)(percent * (float)ctx->text.lastPos); 1859 top = lt->top; 1860 1861 if (!lt->lines || (position >= lt->top && position < lt->info[1].position)) { 1862 _XawTextSetScrollBars(ctx); 1863 return; 1864 } 1865 1866 #ifndef OLDXAW 1867 ctx->text.lt.base_line = -1; 1868 #endif 1869 1870 if (position > lt->top) { /* VScroll Up */ 1871 if (position > lt->top && position < lt->info[lt->lines].position) 1872 vlines = LineForPosition(ctx, position); 1873 else { 1874 scroll = False; 1875 top = SrcScan(ctx->text.source, position, XawstEOL, 1876 XawsdLeft, 1, False); 1877 if (ctx->text.wrap != XawtextWrapNever) { 1878 last = top; 1879 while (last < position) { 1880 tmp = last; 1881 XawTextSinkFindPosition(ctx->text.sink, last, 1882 ctx->text.left_margin, wwidth, 1883 ctx->text.wrap == XawtextWrapWord, 1884 &last, &dim, &dim); 1885 if (last == tmp) 1886 ++last; 1887 if (last < position) 1888 top = last; 1889 } 1890 } 1891 } 1892 } 1893 else { /* VScroll Down */ 1894 /* 1895 * Calculates the number of lines 1896 */ 1897 while (top > position) { 1898 last = top; 1899 top = SrcScan(ctx->text.source, top, XawstEOL, 1900 XawsdLeft, 2, False); 1901 vlines -= CountLines(ctx, top, last); 1902 if (-vlines >= ctx->text.lt.lines) { 1903 scroll = False; 1904 top = SrcScan(ctx->text.source, position, XawstEOL, 1905 XawsdLeft, 1, False); 1906 break; 1907 } 1908 } 1909 /* 1910 * Normalize 1911 */ 1912 if (ctx->text.wrap != XawtextWrapNever) { 1913 last = top; 1914 while (last < position) { 1915 tmp = last; 1916 XawTextSinkFindPosition(ctx->text.sink, last, 1917 ctx->text.left_margin, 1918 wwidth, 1919 ctx->text.wrap == XawtextWrapWord, 1920 &last, &dim, &dim); 1921 if (last == tmp) 1922 ++last; 1923 if (last < position) 1924 top = last; 1925 ++vlines; 1926 } 1927 } 1928 } 1929 1930 if (vlines || !scroll) { 1931 _XawTextPrepareToUpdate(ctx); 1932 if (scroll) 1933 XawTextScroll(ctx, vlines, 0); 1934 else 1935 _BuildLineTable(ctx, top, 0); 1936 _XawTextExecuteUpdate(ctx); 1937 } 1938 } 1939 1940 static Bool 1941 MatchSelection(Atom selection, XawTextSelection *s) 1942 { 1943 Atom *match; 1944 int count; 1945 1946 for (count = 0, match = s->selections; count < s->atom_count; 1947 match++, count++) 1948 if (*match == selection) 1949 return (True); 1950 1951 return (False); 1952 } 1953 1954 static Boolean 1955 TextConvertSelection(Widget w, Atom *selection, Atom *target, Atom *type, 1956 XtPointer *value, unsigned long *length, int *format) 1957 { 1958 Display *d = XtDisplay(w); 1959 TextWidget ctx = (TextWidget)w; 1960 Widget src = ctx->text.source; 1961 XawTextEditType edit_mode; 1962 XawTextSelectionSalt *salt = NULL; 1963 XawTextSelection *s; 1964 1965 if (*target == XA_TARGETS(d)) { 1966 Atom *targetP, *std_targets; 1967 unsigned long std_length; 1968 1969 if (SrcCvtSel(src, selection, target, type, value, length, format)) 1970 return (True); 1971 else { 1972 Arg args[1]; 1973 1974 XtSetArg(args[0], XtNeditType, &edit_mode); 1975 XtGetValues(src, args, ONE); 1976 } 1977 1978 XmuConvertStandardSelection(w, ctx->text.time, selection, 1979 target, type, (XPointer*)&std_targets, 1980 &std_length, format); 1981 1982 *length = 7 + (unsigned long)(edit_mode == XawtextEdit) + std_length; 1983 *value = XtMalloc((Cardinal)(sizeof(Atom)*(*length))); 1984 targetP = *(Atom**)value; 1985 *targetP++ = XA_STRING; 1986 *targetP++ = XA_TEXT(d); 1987 *targetP++ = XA_UTF8_STRING(d); 1988 *targetP++ = XA_COMPOUND_TEXT(d); 1989 *targetP++ = XA_LENGTH(d); 1990 *targetP++ = XA_LIST_LENGTH(d); 1991 *targetP++ = XA_CHARACTER_POSITION(d); 1992 if (edit_mode == XawtextEdit) { 1993 *targetP++ = XA_DELETE(d); 1994 } 1995 (void)memmove((char*)targetP, (char*)std_targets, 1996 sizeof(Atom) * std_length); 1997 XtFree((char*)std_targets); 1998 *type = XA_ATOM; 1999 *format = 32; 2000 return (True); 2001 } 2002 2003 if (SrcCvtSel(src, selection, target, type, value, length, format)) 2004 return (True); 2005 2006 if (MatchSelection(*selection, &ctx->text.s)) 2007 s = &ctx->text.s; 2008 else { 2009 for (salt = ctx->text.salt; salt; salt = salt->next) 2010 if (MatchSelection(*selection, &salt->s)) 2011 break; 2012 if (!salt) 2013 return (False); 2014 s = &salt->s; 2015 } 2016 if (*target == XA_STRING 2017 || *target == XA_TEXT(d) 2018 || *target == XA_UTF8_STRING(d) 2019 || *target == XA_COMPOUND_TEXT(d)) { 2020 if (*target == XA_TEXT(d)) { 2021 if (XawTextFormat(ctx, XawFmtWide)) 2022 *type = XA_COMPOUND_TEXT(d); 2023 else 2024 *type = XA_STRING; 2025 } 2026 else 2027 *type = *target; 2028 /* 2029 * If salt is True, the salt->contents stores CT string, 2030 * its length is measured in bytes. 2031 * Refer to _XawTextSaltAwaySelection(). 2032 * 2033 * by Li Yuhong, Mar. 20, 1991. 2034 */ 2035 if (!salt) { 2036 *value = _XawTextGetSTRING(ctx, s->left, s->right); 2037 if (XawTextFormat(ctx, XawFmtWide)) { 2038 XTextProperty textprop; 2039 if (XwcTextListToTextProperty(d, (wchar_t **)value, 1, 2040 XCompoundTextStyle, &textprop) 2041 < Success) { 2042 XtFree((char *)*value); 2043 return (False); 2044 } 2045 XtFree((char *)*value); 2046 *value = (XtPointer)textprop.value; 2047 *length = textprop.nitems; 2048 } 2049 else 2050 *length = strlen((char *)*value); 2051 } 2052 else { 2053 *value = XtMalloc((Cardinal)((size_t)(salt->length + 1) * sizeof(unsigned char))); 2054 strcpy ((char *)*value, salt->contents); 2055 *length = (unsigned long)salt->length; 2056 } 2057 /* Got *value,*length, now in COMPOUND_TEXT format. */ 2058 if (XawTextFormat(ctx, XawFmtWide) && *type == XA_STRING) { 2059 wchar_t **wlist; 2060 int count; 2061 XTextProperty textprop = { 2062 .encoding = XA_COMPOUND_TEXT(d), 2063 .value = (unsigned char *)*value, 2064 .nitems = strlen(*value), 2065 .format = 8 2066 }; 2067 2068 if (XwcTextPropertyToTextList(d, &textprop, &wlist, &count) 2069 < Success 2070 || count < 1) { 2071 XtFree((char *)*value); 2072 return (False); 2073 } 2074 XtFree((char *)*value); 2075 if (XwcTextListToTextProperty(d, wlist, 1, XStringStyle, &textprop) 2076 < Success) { 2077 XwcFreeStringList((wchar_t**) wlist); 2078 return (False); 2079 } 2080 *value = (XtPointer)textprop.value; 2081 *length = textprop.nitems; 2082 XwcFreeStringList(wlist); 2083 } else if (*type == XA_UTF8_STRING(d)) { 2084 char **list; 2085 int count; 2086 XTextProperty textprop = { 2087 .encoding = XA_COMPOUND_TEXT(d), 2088 .value = (unsigned char *)*value, 2089 .nitems = strlen(*value), 2090 .format = 8 2091 }; 2092 2093 if (Xutf8TextPropertyToTextList(d, &textprop, &list, &count) 2094 < Success 2095 || count < 1) { 2096 XtFree((char *)*value); 2097 return (False); 2098 } 2099 XtFree((char *)*value); 2100 *value = *list; 2101 *length = strlen(*list); 2102 XFree(list); 2103 } 2104 *format = 8; 2105 return (True); 2106 } 2107 2108 if ((*target == XA_LIST_LENGTH(d)) || (*target == XA_LENGTH(d))) { 2109 long * temp; 2110 2111 temp = (long *)XtMalloc((unsigned)sizeof(long)); 2112 if (*target == XA_LIST_LENGTH(d)) 2113 *temp = 1L; 2114 else /* *target == XA_LENGTH(d) */ 2115 *temp = (long) (s->right - s->left); 2116 2117 *value = (XPointer)temp; 2118 *type = XA_INTEGER; 2119 *length = 1L; 2120 *format = 32; 2121 return (True); 2122 } 2123 2124 if (*target == XA_CHARACTER_POSITION(d)) { 2125 long * temp; 2126 2127 temp = (long *)XtMalloc((unsigned)(2 * sizeof(long))); 2128 temp[0] = (long)(s->left + 1); 2129 temp[1] = s->right; 2130 *value = (XPointer)temp; 2131 *type = XA_SPAN(d); 2132 *length = 2L; 2133 *format = 32; 2134 return (True); 2135 } 2136 2137 if (*target == XA_DELETE(d)) { 2138 if (!salt) 2139 _XawTextZapSelection(ctx, NULL, True); 2140 *value = NULL; 2141 *type = XA_NULL(d); 2142 *length = 0; 2143 *format = 32; 2144 return (True); 2145 } 2146 2147 if (XmuConvertStandardSelection(w, ctx->text.time, selection, target, type, 2148 (XPointer *)value, length, format)) 2149 return (True); 2150 2151 /* else */ 2152 return (False); 2153 } 2154 2155 /* 2156 * Function: 2157 * GetCutBuffferNumber 2158 * 2159 * Parameters: 2160 * atom - atom to check 2161 * 2162 * Description: 2163 * Returns the number of the cut buffer. 2164 * 2165 * Returns: 2166 * The number of the cut buffer representing this atom or NOT_A_CUT_BUFFER 2167 */ 2168 #define NOT_A_CUT_BUFFER -1 2169 static int 2170 GetCutBufferNumber(Atom atom) 2171 { 2172 if (atom == XA_CUT_BUFFER0) return (0); 2173 if (atom == XA_CUT_BUFFER1) return (1); 2174 if (atom == XA_CUT_BUFFER2) return (2); 2175 if (atom == XA_CUT_BUFFER3) return (3); 2176 if (atom == XA_CUT_BUFFER4) return (4); 2177 if (atom == XA_CUT_BUFFER5) return (5); 2178 if (atom == XA_CUT_BUFFER6) return (6); 2179 if (atom == XA_CUT_BUFFER7) return (7); 2180 return (NOT_A_CUT_BUFFER); 2181 } 2182 2183 static void 2184 TextLoseSelection(Widget w, Atom *selection) 2185 { 2186 TextWidget ctx = (TextWidget)w; 2187 Atom *atomP; 2188 int i; 2189 XawTextSelectionSalt*salt, *prevSalt, *nextSalt; 2190 2191 atomP = ctx->text.s.selections; 2192 for (i = 0 ; i < ctx->text.s.atom_count; i++, atomP++) 2193 if ((*selection == *atomP) 2194 || (GetCutBufferNumber(*atomP) != NOT_A_CUT_BUFFER)) 2195 *atomP = (Atom)0; 2196 2197 while (ctx->text.s.atom_count 2198 && ctx->text.s.selections[ctx->text.s.atom_count - 1] == 0) 2199 ctx->text.s.atom_count--; 2200 2201 /* 2202 * Must walk the selection list in opposite order from UnsetSelection 2203 */ 2204 atomP = ctx->text.s.selections; 2205 for (i = 0 ; i < ctx->text.s.atom_count; i++, atomP++) 2206 if (*atomP == (Atom)0) { 2207 *atomP = ctx->text.s.selections[--ctx->text.s.atom_count]; 2208 while (ctx->text.s.atom_count 2209 && ctx->text.s.selections[ctx->text.s.atom_count-1] == 0) 2210 ctx->text.s.atom_count--; 2211 } 2212 2213 if (ctx->text.s.atom_count == 0) 2214 ModifySelection(ctx, ctx->text.insertPos, ctx->text.insertPos); 2215 2216 prevSalt = 0; 2217 for (salt = ctx->text.salt; salt; salt = nextSalt) { 2218 atomP = salt->s.selections; 2219 nextSalt = salt->next; 2220 for (i = 0 ; i < salt->s.atom_count; i++, atomP++) 2221 if (*selection == *atomP) 2222 *atomP = (Atom)0; 2223 2224 while (salt->s.atom_count 2225 && salt->s.selections[salt->s.atom_count-1] == 0) 2226 salt->s.atom_count--; 2227 2228 /* 2229 * Must walk the selection list in opposite order from UnsetSelection 2230 */ 2231 atomP = salt->s.selections; 2232 for (i = 0 ; i < salt->s.atom_count; i++, atomP++) 2233 if (*atomP == (Atom)0) { 2234 *atomP = salt->s.selections[--salt->s.atom_count]; 2235 while (salt->s.atom_count 2236 && salt->s.selections[salt->s.atom_count-1] == 0) 2237 salt->s.atom_count--; 2238 } 2239 2240 if (salt->s.atom_count == 0) { 2241 XtFree ((char *) salt->s.selections); 2242 XtFree (salt->contents); 2243 if (prevSalt) 2244 prevSalt->next = nextSalt; 2245 else 2246 ctx->text.salt = nextSalt; 2247 XtFree((char *)salt); 2248 } 2249 else 2250 prevSalt = salt; 2251 } 2252 } 2253 2254 void 2255 _XawTextSaltAwaySelection(TextWidget ctx, Atom *selections, int num_atoms) 2256 { 2257 XawTextSelectionSalt *salt; 2258 int i, j; 2259 2260 for (i = 0; i < num_atoms; i++) 2261 TextLoseSelection((Widget)ctx, selections + i); 2262 if (num_atoms == 0) 2263 return; 2264 salt = (XawTextSelectionSalt *) 2265 XtMalloc((unsigned)sizeof(XawTextSelectionSalt)); 2266 if (!salt) 2267 return; 2268 salt->s.selections = (Atom *)XtMalloc((Cardinal)((size_t)num_atoms * sizeof(Atom))); 2269 if (!salt->s.selections) { 2270 XtFree((char *)salt); 2271 return; 2272 } 2273 salt->s.left = ctx->text.s.left; 2274 salt->s.right = ctx->text.s.right; 2275 salt->s.type = ctx->text.s.type; 2276 salt->contents = _XawTextGetSTRING(ctx, ctx->text.s.left, ctx->text.s.right); 2277 if (XawTextFormat(ctx, XawFmtWide)) { 2278 XTextProperty textprop; 2279 if (XwcTextListToTextProperty(XtDisplay((Widget)ctx), 2280 (wchar_t**)(&(salt->contents)), 1, 2281 XCompoundTextStyle, 2282 &textprop) < Success) { 2283 XtFree(salt->contents); 2284 salt->length = 0; 2285 return; 2286 } 2287 XtFree(salt->contents); 2288 salt->contents = (char *)textprop.value; 2289 salt->length = (int)textprop.nitems; 2290 } 2291 else 2292 salt->length = (int)strlen (salt->contents); 2293 salt->next = ctx->text.salt; 2294 ctx->text.salt = salt; 2295 j = 0; 2296 for (i = 0; i < num_atoms; i++) { 2297 if (GetCutBufferNumber (selections[i]) == NOT_A_CUT_BUFFER) { 2298 salt->s.selections[j++] = selections[i]; 2299 XtOwnSelection((Widget)ctx, selections[i], ctx->text.time, 2300 TextConvertSelection, TextLoseSelection, NULL); 2301 } 2302 } 2303 salt->s.atom_count = j; 2304 } 2305 2306 static void 2307 _SetSelection(TextWidget ctx, XawTextPosition left, XawTextPosition right, 2308 Atom *selections, Cardinal count) 2309 { 2310 #ifndef OLDXAW 2311 Cardinal i; 2312 XawTextPosition pos; 2313 TextSrcObject src = (TextSrcObject)ctx->text.source; 2314 2315 for (i = 0; i < src->textSrc.num_text; i++) { 2316 TextWidget tw = (TextWidget)src->textSrc.text[i]; 2317 Bool needs_updating = tw->text.old_insert < 0; 2318 Bool showposition = tw->text.showposition; 2319 2320 if (needs_updating) { 2321 tw->text.showposition = False; 2322 _XawTextPrepareToUpdate(tw); 2323 } 2324 #else 2325 TextWidget tw = ctx; 2326 XawTextPosition pos; 2327 #endif /* OLDXAW */ 2328 2329 if (left < tw->text.s.left) { 2330 pos = Min(right, tw->text.s.left); 2331 _XawTextNeedsUpdating(tw, left, pos); 2332 } 2333 if (left > tw->text.s.left) { 2334 pos = Min(left, tw->text.s.right); 2335 _XawTextNeedsUpdating(tw, tw->text.s.left, pos); 2336 } 2337 if (right < tw->text.s.right) { 2338 pos = Max(right, tw->text.s.left); 2339 _XawTextNeedsUpdating(tw, pos, tw->text.s.right); 2340 } 2341 if (right > tw->text.s.right) { 2342 pos = Max(left, tw->text.s.right); 2343 _XawTextNeedsUpdating(tw, pos, right); 2344 } 2345 2346 tw->text.s.left = left; 2347 tw->text.s.right = right; 2348 2349 #ifndef OLDXAW 2350 if (needs_updating) { 2351 _XawTextExecuteUpdate(tw); 2352 tw->text.showposition = (Boolean)showposition; 2353 } 2354 } 2355 #endif /* OLDXAW */ 2356 2357 SrcSetSelection(ctx->text.source, left, right, 2358 (count == 0) ? None : selections[0]); 2359 2360 if (left < right) { 2361 Widget w = (Widget)ctx; 2362 2363 while (count) { 2364 Atom selection = selections[--count]; 2365 int buffer; 2366 2367 /* 2368 * If this is a cut buffer 2369 */ 2370 if ((buffer = GetCutBufferNumber(selection)) != NOT_A_CUT_BUFFER) { 2371 unsigned char *ptr, *tptr; 2372 unsigned int amount, max_len = (unsigned)MAX_CUT_LEN(XtDisplay(w)); 2373 unsigned long len; 2374 2375 tptr= ptr= (unsigned char *)_XawTextGetSTRING(ctx, 2376 ctx->text.s.left, 2377 ctx->text.s.right); 2378 if (XawTextFormat(ctx, XawFmtWide)) { 2379 /* 2380 * Only XA_STRING(Latin 1) is allowed in CUT_BUFFER, 2381 * so we get it from wchar string, then free the wchar string 2382 */ 2383 XTextProperty textprop; 2384 2385 if (XwcTextListToTextProperty(XtDisplay(w), (wchar_t**)&ptr, 2386 1, XStringStyle, &textprop) 2387 < Success){ 2388 XtFree((char *)ptr); 2389 return; 2390 } 2391 XtFree((char *)ptr); 2392 tptr = ptr = textprop.value; 2393 } 2394 if (buffer == 0) { 2395 _CreateCutBuffers(XtDisplay(w)); 2396 XRotateBuffers(XtDisplay(w), 1); 2397 } 2398 amount = (unsigned)Min ((len = strlen((char *)ptr)), max_len); 2399 XChangeProperty(XtDisplay(w), RootWindow(XtDisplay(w), 0), 2400 selection, XA_STRING, 8, PropModeReplace, 2401 ptr, (int)amount); 2402 2403 while (len > max_len) { 2404 len -= max_len; 2405 tptr += max_len; 2406 amount = (unsigned) Min (len, max_len); 2407 XChangeProperty(XtDisplay(w), RootWindow(XtDisplay(w), 0), 2408 selection, XA_STRING, 8, PropModeAppend, 2409 tptr, (int)amount); 2410 } 2411 XtFree ((char *)ptr); 2412 } 2413 else /* This is a real selection */ 2414 XtOwnSelection(w, selection, ctx->text.time, TextConvertSelection, 2415 TextLoseSelection, NULL); 2416 } 2417 } 2418 else 2419 XawTextUnsetSelection((Widget)ctx); 2420 } 2421 2422 #ifndef OLDXAW 2423 void 2424 _XawTextSetLineAndColumnNumber(TextWidget ctx, Bool force) 2425 { 2426 int line_number, column_number; 2427 2428 if (ctx->text.old_insert != ctx->text.insertPos && 2429 ctx->text.lt.base_line < 0) { 2430 ctx->text.lt.base_line = 0; 2431 (void)_BuildLineTable(ctx, ctx->text.lt.top, 0); 2432 } 2433 2434 line_number = ResolveLineNumber(ctx); 2435 column_number = ResolveColumnNumber(ctx); 2436 2437 if (force || (ctx->text.column_number != column_number 2438 || ctx->text.line_number != line_number)) { 2439 XawTextPositionInfo info; 2440 2441 ctx->text.line_number = info.line_number = line_number; 2442 ctx->text.column_number = (short)(info.column_number = column_number); 2443 info.insert_position = ctx->text.insertPos; 2444 info.last_position = ctx->text.lastPos; 2445 info.overwrite_mode = ctx->text.overwrite; 2446 2447 XtCallCallbacks((Widget)ctx, XtNpositionCallback, (XtPointer)&info); 2448 } 2449 } 2450 2451 static int 2452 ResolveColumnNumber(TextWidget ctx) 2453 { 2454 Widget src = ctx->text.source; 2455 short column_number = 0; 2456 XawTextPosition position; 2457 XawTextBlock block; 2458 unsigned long format = (unsigned long)_XawTextFormat(ctx); 2459 TextSinkObject sink = (TextSinkObject)ctx->text.sink; 2460 short *char_tabs = sink->text_sink.char_tabs; 2461 int tab_count = sink->text_sink.tab_count; 2462 int tab_index = 0, tab_column = 0, tab_base = 0; 2463 2464 if (ctx->text.lt.base_line < 1) 2465 return (ctx->text.column_number); 2466 2467 position = SrcScan(src, ctx->text.insertPos, XawstEOL, XawsdLeft, 1, False); 2468 XawTextSourceRead(src, position, &block, (int)(ctx->text.insertPos - position)); 2469 2470 for (; position < ctx->text.insertPos; position++) { 2471 if (position - block.firstPos >= block.length) 2472 XawTextSourceRead(src, position, &block, (int)(ctx->text.insertPos - position)); 2473 if ((format == XawFmt8Bit && block.ptr[position - block.firstPos] == '\t') || 2474 (format == XawFmtWide && ((wchar_t*)block.ptr)[position - block.firstPos] == _Xaw_atowc(XawTAB))) { 2475 while (tab_base + tab_column <= column_number) { 2476 if (tab_count) { 2477 for (; tab_index < tab_count; ++tab_index) 2478 if (tab_base + char_tabs[tab_index] > column_number) { 2479 tab_column = char_tabs[tab_index]; 2480 break; 2481 } 2482 if (tab_index >= tab_count) { 2483 tab_base += char_tabs[tab_count - 1]; 2484 tab_column = tab_index = 0; 2485 } 2486 } 2487 else 2488 tab_column += DEFAULT_TAB_SIZE; 2489 } 2490 column_number = (short)(tab_base + tab_column); 2491 } 2492 else 2493 ++column_number; 2494 if (column_number >= 16384) { 2495 column_number = 16383; 2496 break; 2497 } 2498 } 2499 2500 return (column_number); 2501 } 2502 #endif /* OLDXAW */ 2503 2504 void 2505 _XawTextSourceChanged(Widget w, XawTextPosition left, XawTextPosition right, 2506 XawTextBlock *block, int lines _X_UNUSED) 2507 { 2508 TextWidget ctx = (TextWidget)w; 2509 Widget src = ctx->text.source; 2510 XawTextPosition update_from, update_to, top; 2511 Boolean update_disabled; 2512 int delta, line, line_from; 2513 2514 if (left < ctx->text.old_insert) { 2515 XawTextPosition old_insert = ctx->text.old_insert; 2516 2517 if (right < ctx->text.old_insert) 2518 old_insert -= right - left; 2519 else 2520 old_insert = left; 2521 2522 ctx->text.insertPos = old_insert + block->length; 2523 } 2524 #ifndef OLDXAW 2525 if (left <= ctx->text.lt.top) { 2526 if (left + block->length - (right - left) < ctx->text.lt.top) { 2527 ctx->text.source_changed = SRC_CHANGE_BEFORE; 2528 ctx->text.lt.base_line += lines; 2529 } 2530 else 2531 ctx->text.source_changed = SRC_CHANGE_OVERLAP; 2532 } 2533 else 2534 ctx->text.source_changed = SRC_CHANGE_AFTER; 2535 #endif 2536 2537 update_from = left; 2538 update_to = left + block->length; 2539 update_to = SrcScan(src, update_to, XawstEOL, XawsdRight, 1, False); 2540 delta = (int)(block->length - (right - left)); 2541 if (delta < 0) 2542 ctx->text.clear_to_eol = True; 2543 if (update_to == update_from) 2544 ++update_to; 2545 update_disabled = ctx->text.update_disabled; 2546 ctx->text.update_disabled = True; 2547 ctx->text.lastPos = XawTextGetLastPosition(ctx); 2548 top = ctx->text.lt.info[0].position; 2549 2550 XawTextUnsetSelection((Widget)ctx); 2551 2552 if (delta) { 2553 int i; 2554 XmuSegment *seg; 2555 2556 for (seg = ctx->text.update->segment; seg; seg = seg->next) { 2557 if (seg->x1 > (int)left) 2558 break; 2559 else if (seg->x2 > (int)left) { 2560 seg->x2 += delta; 2561 seg = seg->next; 2562 break; 2563 } 2564 } 2565 for (; seg; seg = seg->next) { 2566 seg->x1 += delta; 2567 seg->x2 += delta; 2568 } 2569 XmuOptimizeScanline(ctx->text.update); 2570 2571 for (i = 0; i <= ctx->text.lt.lines; i++) 2572 if (ctx->text.lt.info[i].position > left) 2573 break; 2574 for (; i <= ctx->text.lt.lines; i++) 2575 ctx->text.lt.info[i].position += delta; 2576 } 2577 2578 if (top != ctx->text.lt.info[0].position) { 2579 line_from = line = 0; 2580 ctx->text.lt.top = top = SrcScan(src, ctx->text.lt.info[0].position, 2581 XawstEOL, XawsdLeft, 1, False); 2582 update_from = top; 2583 } 2584 else { 2585 line_from = line = LineForPosition(ctx, update_from + delta); 2586 top = ctx->text.lt.info[line].position; 2587 } 2588 2589 if (line > 0 && ctx->text.wrap == XawtextWrapWord) { 2590 --line; 2591 top = ctx->text.lt.info[line].position; 2592 } 2593 2594 (void)_BuildLineTable(ctx, top, line); 2595 2596 if (ctx->text.wrap == XawtextWrapWord) { 2597 if (line_from != LineForPosition(ctx, update_from) 2598 || line_from != LineForPosition(ctx, update_to)) { 2599 ctx->text.clear_to_eol = True; 2600 update_from = SrcScan(src, update_from, 2601 XawstWhiteSpace, XawsdLeft, 1, True); 2602 if (update_to >= ctx->text.lastPos) 2603 /* this is not an error, it just tells _BuildLineTable to 2604 * clear to the bottom of the window. The value of update_to 2605 * should not be > ctx->text.lastPos. 2606 */ 2607 ++update_to; 2608 } 2609 } 2610 else if (!ctx->text.clear_to_eol) { 2611 if (LineForPosition(ctx, update_from) 2612 != LineForPosition(ctx, update_to)) 2613 ctx->text.clear_to_eol = True; 2614 } 2615 2616 _XawTextNeedsUpdating(ctx, update_from, update_to); 2617 ctx->text.update_disabled = update_disabled; 2618 } 2619 2620 /* 2621 * Function: 2622 * _XawTextReplace 2623 * 2624 * Parameters: 2625 * ctx - text widget 2626 * left - left offset 2627 * right - right offset 2628 * block - text block 2629 * 2630 * Description: 2631 * Replaces the text between left and right by the text in block. 2632 * Does all the required calculations of offsets, and rebuild the 2633 * the line table, from the insertion point (or previous line, if 2634 * wrap mode is 'word'). 2635 * 2636 * Returns: 2637 * XawEditDone - success 2638 * any other value - error code 2639 */ 2640 int 2641 _XawTextReplace(TextWidget ctx, XawTextPosition left, XawTextPosition right, 2642 XawTextBlock *block) 2643 { 2644 Arg args[1]; 2645 Widget src; 2646 XawTextEditType edit_mode; 2647 2648 if (left == right && block->length == 0) 2649 return (XawEditDone); 2650 2651 src = ctx->text.source; 2652 XtSetArg(args[0], XtNeditType, &edit_mode); 2653 XtGetValues(src, args, 1); 2654 2655 if (edit_mode == XawtextAppend) { 2656 if (block->length == 0) 2657 return (XawEditError); 2658 ctx->text.insertPos = ctx->text.lastPos; 2659 } 2660 2661 #ifndef OLDXAW 2662 return (SrcReplace(src, left, right, block)); 2663 #else 2664 if (SrcReplace(src, left, right, block) == XawEditDone) { 2665 _XawTextSourceChanged((Widget)ctx, left, right, block, 0); 2666 2667 return (XawEditDone); 2668 } 2669 2670 return (XawEditError); 2671 #endif 2672 } 2673 2674 /* 2675 * This routine will display text between two arbitrary source positions. 2676 * In the event that this span contains highlighted text for the selection, 2677 * only that portion will be displayed highlighted. 2678 */ 2679 static void 2680 OldDisplayText(Widget w, XawTextPosition left, XawTextPosition right) 2681 { 2682 static XmuSegment segment; 2683 static XmuScanline next; 2684 static XmuScanline scanline = {0, &segment, &next}; 2685 static XmuArea area = {&scanline}; 2686 2687 TextWidget ctx = (TextWidget)w; 2688 int x, y, line; 2689 XawTextPosition last; 2690 XmuScanline *scan; 2691 XmuSegment *seg; 2692 XmuArea *clip = NULL; 2693 Bool cleol = ctx->text.clear_to_eol; 2694 Bool has_selection = ctx->text.s.right > ctx->text.s.left; 2695 XawTextPosition start; 2696 2697 left = left < ctx->text.lt.top ? ctx->text.lt.top : left; 2698 2699 if (left > right || !LineAndXYForPosition(ctx, left, &line, &x, &y)) 2700 return; 2701 2702 last = XawTextGetLastPosition(ctx); 2703 segment.x2 = (int)XtWidth(ctx) - ctx->text.r_margin.right; 2704 2705 if (cleol) 2706 clip = XmuCreateArea(); 2707 2708 for (start = left; 2709 start < right && line < ctx->text.lt.lines; line++) { 2710 XawTextPosition end, final; 2711 2712 if ((end = ctx->text.lt.info[line + 1].position) > right) 2713 end = right; 2714 2715 final = end; 2716 if (end > last) 2717 end = last; 2718 2719 if (end > start) { 2720 if (!has_selection 2721 || (start >= ctx->text.s.right || end <= ctx->text.s.left)) 2722 _XawTextSinkDisplayText(ctx->text.sink, x, y, start, end, False); 2723 else if (start >= ctx->text.s.left && end <= ctx->text.s.right) 2724 _XawTextSinkDisplayText(ctx->text.sink, x, y, start, end, True); 2725 else { 2726 OldDisplayText(w, start, ctx->text.s.left); 2727 OldDisplayText(w, Max(start, ctx->text.s.left), 2728 Min(end, ctx->text.s.right)); 2729 OldDisplayText(w, ctx->text.s.right, end); 2730 } 2731 } 2732 2733 x = ctx->text.left_margin; 2734 if (cleol) { 2735 segment.x1 = (int)(ctx->text.lt.info[line].textWidth + (unsigned)x); 2736 if (XmuValidSegment(&segment)) { 2737 scanline.y = y; 2738 next.y = ctx->text.lt.info[line + 1].y; 2739 XmuAreaOr(clip, &area); 2740 } 2741 } 2742 2743 start = final; 2744 y = ctx->text.lt.info[line + 1].y; 2745 } 2746 2747 if (cleol) { 2748 for (scan = clip->scanline; scan && scan->next; scan = scan->next) 2749 for (seg = scan->segment; seg; seg = seg->next) 2750 SinkClearToBG(ctx->text.sink, 2751 seg->x1, scan->y, 2752 (unsigned)(seg->x2 - seg->x1), 2753 (unsigned)(scan->next->y - scan->y)); 2754 XmuDestroyArea(clip); 2755 } 2756 } 2757 2758 #ifndef OLDXAW 2759 /*ARGSUSED*/ 2760 static void 2761 DisplayText(Widget w, XawTextPosition left, XawTextPosition right) 2762 { 2763 static XmuSegment segment; 2764 static XmuScanline next; 2765 static XmuScanline scanline = {0, &segment, &next}; 2766 static XmuArea area = {&scanline}; 2767 2768 TextWidget ctx = (TextWidget)w; 2769 int y, line; 2770 XawTextPosition lastPos; 2771 Bool cleol = ctx->text.clear_to_eol; 2772 Bool has_selection = ctx->text.s.right > ctx->text.s.left; 2773 XawTextPaintList *paint_list; 2774 XawTextPosition from; 2775 2776 left = left < ctx->text.lt.top ? ctx->text.lt.top : left; 2777 2778 if (left > right || !IsPositionVisible(ctx, left)) 2779 return; 2780 2781 line = LineForPosition(ctx, left); 2782 y = ctx->text.lt.info[line].y; 2783 segment.x2 = (int)XtWidth(ctx) - ctx->text.r_margin.right; 2784 lastPos = XawTextGetLastPosition(ctx); 2785 2786 paint_list = ((TextSinkObject)ctx->text.sink)->text_sink.paint; 2787 2788 for (from = left; 2789 from < right && line < ctx->text.lt.lines; line++) { 2790 XawTextPosition to = ctx->text.lt.info[line + 1].position; 2791 2792 if (to > right) 2793 to = right; 2794 2795 if (to > lastPos) 2796 to = lastPos; 2797 2798 if (from < to) { 2799 if (!has_selection 2800 || (from >= ctx->text.s.right || to <= ctx->text.s.left)) 2801 XawTextSinkPreparePaint(ctx->text.sink, y, line, from, to, False); 2802 else if (from >= ctx->text.s.left && to <= ctx->text.s.right) 2803 XawTextSinkPreparePaint(ctx->text.sink, y, line, from, to, True); 2804 else { 2805 XawTextSinkPreparePaint(ctx->text.sink, y, line, from, 2806 ctx->text.s.left, False); 2807 XawTextSinkPreparePaint(ctx->text.sink, y, line, 2808 XawMax(from, ctx->text.s.left), 2809 XawMin(to, ctx->text.s.right), True); 2810 XawTextSinkPreparePaint(ctx->text.sink, y, line, 2811 ctx->text.s.right, to, False); 2812 } 2813 } 2814 2815 if (cleol) { 2816 segment.x1 = (int)(ctx->text.lt.info[line].textWidth + (unsigned)ctx->text.left_margin); 2817 if (XmuValidSegment(&segment)) { 2818 scanline.y = y; 2819 next.y = ctx->text.lt.info[line + 1].y; 2820 XmuAreaOr(paint_list->clip, &area); 2821 } 2822 } 2823 y = ctx->text.lt.info[line + 1].y; 2824 from = to; 2825 } 2826 2827 /* clear to the bottom of the window */ 2828 if (cleol && line >= ctx->text.lt.lines) { 2829 segment.x1 = ctx->text.left_margin; 2830 if (XmuValidSegment(&segment)) { 2831 scanline.y = y; 2832 next.y = (int)XtHeight(ctx) - (int)ctx->text.margin.bottom; 2833 XmuAreaOr(paint_list->clip, &area); 2834 } 2835 } 2836 } 2837 #endif 2838 2839 /* 2840 * This routine implements multi-click selection in a hardwired manner. 2841 * It supports multi-click entity cycling (char, word, line, file) and mouse 2842 * motion adjustment of the selected entity (i.e. select a word then, with 2843 * button still down, adjust which word you really meant by moving the mouse). 2844 * [NOTE: This routine is to be replaced by a set of procedures that 2845 * will allows clients to implements a wide class of draw through and 2846 * multi-click selection user interfaces.] 2847 */ 2848 static void 2849 DoSelection(TextWidget ctx, XawTextPosition pos, Time time, Bool motion) 2850 { 2851 XawTextPosition newLeft, newRight; 2852 XawTextSelectType newType; 2853 Widget src = ctx->text.source; 2854 2855 if (motion) 2856 newType = ctx->text.s.type; 2857 else { 2858 if ((labs((long) time - (long) ctx->text.lasttime) < MULTI_CLICK_TIME) 2859 && (pos >= ctx->text.s.left && pos <= ctx->text.s.right)) { 2860 XawTextSelectType *sarray = ctx->text.sarray; 2861 2862 for (; *sarray != XawselectNull && *sarray != ctx->text.s.type; 2863 sarray++) 2864 ; 2865 if (*sarray == XawselectNull) 2866 newType = *(ctx->text.sarray); 2867 else { 2868 newType = *(sarray + 1); 2869 if (newType == XawselectNull) 2870 newType = *(ctx->text.sarray); 2871 } 2872 } 2873 else /* single-click event */ 2874 newType = *(ctx->text.sarray); 2875 2876 ctx->text.lasttime = time; 2877 } 2878 switch (newType) { 2879 case XawselectPosition: 2880 newLeft = newRight = pos; 2881 break; 2882 case XawselectChar: 2883 newLeft = pos; 2884 newRight = SrcScan(src, pos, XawstPositions, XawsdRight, 1, False); 2885 break; 2886 case XawselectWord: 2887 case XawselectParagraph: 2888 case XawselectAlphaNumeric: { 2889 XawTextScanType stype; 2890 2891 if (newType == XawselectWord) 2892 stype = XawstWhiteSpace; 2893 else if (newType == XawselectParagraph) 2894 stype = XawstParagraph; 2895 else 2896 stype = XawstAlphaNumeric; 2897 2898 /* 2899 * Somewhat complicated, but basically I treat the space between 2900 * two objects as another object. The object that I am currently 2901 * in then becomes the end of the selection. 2902 * 2903 * Chris Peterson - 4/19/90. 2904 */ 2905 newRight = SrcScan(ctx->text.source, pos, stype, 2906 XawsdRight, 1, False); 2907 newRight = SrcScan(ctx->text.source, newRight, stype, 2908 XawsdLeft, 1, False); 2909 2910 if (pos != newRight) 2911 newLeft = SrcScan(ctx->text.source, pos, stype, 2912 XawsdLeft, 1, False); 2913 else 2914 newLeft = pos; 2915 2916 newLeft =SrcScan(ctx->text.source, newLeft, stype, 2917 XawsdRight, 1, False); 2918 2919 if (newLeft > newRight) { 2920 XawTextPosition temp = newLeft; 2921 newLeft = newRight; 2922 newRight = temp; 2923 } 2924 } break; 2925 case XawselectLine: 2926 newLeft = SrcScan(src, pos, XawstEOL, XawsdLeft, 1, False); 2927 newRight = SrcScan(src, pos, XawstEOL, XawsdRight, 1, False); 2928 break; 2929 case XawselectAll: 2930 newLeft = SrcScan(src, pos, XawstAll, XawsdLeft, 1, False); 2931 newRight = SrcScan(src, pos, XawstAll, XawsdRight, 1, False); 2932 break; 2933 default: 2934 XtAppWarning(XtWidgetToApplicationContext((Widget) ctx), 2935 "Text Widget: empty selection array."); 2936 return; 2937 } 2938 2939 if (newLeft != ctx->text.s.left || newRight != ctx->text.s.right 2940 || newType != ctx->text.s.type) { 2941 ModifySelection(ctx, newLeft, newRight); 2942 if (pos - ctx->text.s.left < ctx->text.s.right - pos) 2943 ctx->text.insertPos = newLeft; 2944 else 2945 ctx->text.insertPos = newRight; 2946 ctx->text.s.type = newType; 2947 } 2948 if (!motion) { /* setup so we can freely mix select extend calls*/ 2949 ctx->text.origSel.type = ctx->text.s.type; 2950 ctx->text.origSel.left = ctx->text.s.left; 2951 ctx->text.origSel.right = ctx->text.s.right; 2952 2953 if (pos >= ctx->text.s.left + (ctx->text.s.right - ctx->text.s.left) / 2) 2954 ctx->text.extendDir = XawsdRight; 2955 else 2956 ctx->text.extendDir = XawsdLeft; 2957 } 2958 } 2959 2960 /* 2961 * This routine implements extension of the currently selected text in 2962 * the "current" mode (i.e. char word, line, etc.). It worries about 2963 * extending from either end of the selection and handles the case when you 2964 * cross through the "center" of the current selection (e.g. switch which 2965 * end you are extending!). 2966 */ 2967 static void 2968 ExtendSelection(TextWidget ctx, XawTextPosition pos, Bool motion) 2969 { 2970 XawTextScanDirection dir; 2971 2972 if (!motion) { /* setup for extending selection */ 2973 if (ctx->text.s.left == ctx->text.s.right) /* no current selection. */ 2974 ctx->text.s.left = ctx->text.s.right = ctx->text.insertPos; 2975 else { 2976 ctx->text.origSel.left = ctx->text.s.left; 2977 ctx->text.origSel.right = ctx->text.s.right; 2978 } 2979 2980 ctx->text.origSel.type = ctx->text.s.type; 2981 2982 if (pos >= ctx->text.s.left + (ctx->text.s.right - ctx->text.s.left) / 2) 2983 ctx->text.extendDir = XawsdRight; 2984 else 2985 ctx->text.extendDir = XawsdLeft; 2986 } 2987 else /* check for change in extend direction */ 2988 if ((ctx->text.extendDir == XawsdRight && 2989 pos <= ctx->text.origSel.left) || 2990 (ctx->text.extendDir == XawsdLeft && 2991 pos >= ctx->text.origSel.right)) { 2992 ctx->text.extendDir = (ctx->text.extendDir == XawsdRight) ? 2993 XawsdLeft : XawsdRight; 2994 ModifySelection(ctx, ctx->text.origSel.left, ctx->text.origSel.right); 2995 } 2996 2997 dir = ctx->text.extendDir; 2998 switch (ctx->text.s.type) { 2999 case XawselectWord: 3000 case XawselectParagraph: 3001 case XawselectAlphaNumeric: { 3002 XawTextPosition left_pos, right_pos; 3003 XawTextScanType stype; 3004 3005 if (ctx->text.s.type == XawselectWord) 3006 stype = XawstWhiteSpace; 3007 else if (ctx->text.s.type == XawselectParagraph) 3008 stype = XawstParagraph; 3009 else 3010 stype = XawstAlphaNumeric; 3011 3012 /* 3013 * Somewhat complicated, but basically I treat the space between 3014 * two objects as another object. The object that I am currently 3015 * in then becomes the end of the selection. 3016 * 3017 * Chris Peterson - 4/19/90. 3018 */ 3019 right_pos = SrcScan(ctx->text.source, pos, stype, 3020 XawsdRight, 1, False); 3021 right_pos =SrcScan(ctx->text.source, right_pos, stype, 3022 XawsdLeft, 1, False); 3023 3024 if (pos != right_pos) 3025 left_pos = SrcScan(ctx->text.source, pos, stype, 3026 XawsdLeft, 1, False); 3027 else 3028 left_pos = pos; 3029 3030 left_pos =SrcScan(ctx->text.source, left_pos, stype, 3031 XawsdRight, 1, False); 3032 3033 if (dir == XawsdLeft) 3034 pos = Min(left_pos, right_pos); 3035 else /* dir == XawsdRight */ 3036 pos = Max(left_pos, right_pos); 3037 } break; 3038 case XawselectLine: 3039 pos = SrcScan(ctx->text.source, pos, XawstEOL, 3040 dir, 1, dir == XawsdRight); 3041 break; 3042 case XawselectAll: 3043 pos = ctx->text.insertPos; 3044 /*FALLTHROUGH*/ 3045 case XawselectPosition: 3046 default: 3047 break; 3048 } 3049 3050 if (dir == XawsdRight) 3051 ModifySelection(ctx, ctx->text.s.left, pos); 3052 else 3053 ModifySelection(ctx, pos, ctx->text.s.right); 3054 3055 ctx->text.insertPos = pos; 3056 } 3057 3058 /* 3059 * Function: 3060 * _XawTextClearAndCenterDisplay 3061 * 3062 * Parameters: 3063 * ctx - text widget 3064 * 3065 * Description: 3066 * Redraws the display with the cursor in insert point 3067 * centered vertically. 3068 */ 3069 void 3070 _XawTextClearAndCenterDisplay(TextWidget ctx) 3071 { 3072 int left_margin = ctx->text.left_margin; 3073 Bool visible = IsPositionVisible(ctx, ctx->text.insertPos); 3074 3075 _XawTextShowPosition(ctx); 3076 3077 if (XtIsRealized((Widget)ctx) && visible && 3078 left_margin == ctx->text.left_margin) { 3079 int insert_line = LineForPosition(ctx, ctx->text.insertPos); 3080 int scroll_by = insert_line - (ctx->text.lt.lines >> 1); 3081 Boolean clear_to_eol; 3082 3083 XawTextScroll(ctx, scroll_by, 0); 3084 SinkClearToBG(ctx->text.sink, 0, 0, XtWidth(ctx), XtHeight(ctx)); 3085 ClearWindow(ctx); 3086 clear_to_eol = ctx->text.clear_to_eol; 3087 ctx->text.clear_to_eol = False; 3088 FlushUpdate(ctx); 3089 ctx->text.clear_to_eol = clear_to_eol; 3090 } 3091 } 3092 3093 /* 3094 * Internal redisplay entire window 3095 * Legal to call only if widget is realized 3096 */ 3097 static void 3098 DisplayTextWindow(Widget w) 3099 { 3100 TextWidget ctx = (TextWidget)w; 3101 3102 _XawTextBuildLineTable(ctx, ctx->text.lt.top, False); 3103 ClearWindow(ctx); 3104 } 3105 3106 static void 3107 TextSinkResize(Widget w) 3108 { 3109 if (w && XtClass(w)->core_class.resize) 3110 XtClass(w)->core_class.resize(w); 3111 } 3112 3113 /* ARGSUSED */ 3114 void 3115 _XawTextCheckResize(TextWidget ctx _X_UNUSED) 3116 { 3117 return; 3118 } 3119 3120 /* 3121 * Converts (params, num_params) to a list of atoms & caches the 3122 * list in the TextWidget instance. 3123 */ 3124 Atom * 3125 _XawTextSelectionList(TextWidget ctx, String *list, Cardinal nelems) 3126 { 3127 Atom *sel = ctx->text.s.selections; 3128 Display *dpy = XtDisplay((Widget)ctx); 3129 int n; 3130 3131 if (nelems > (Cardinal)ctx->text.s.array_size) { 3132 sel = (Atom *)XtRealloc((char *)sel, (Cardinal)(sizeof(Atom) * (size_t)nelems)); 3133 ctx->text.s.array_size = (int)nelems; 3134 ctx->text.s.selections = sel; 3135 } 3136 for (n = (int)nelems; --n >= 0; sel++, list++) 3137 *sel = XInternAtom(dpy, *list, False); 3138 ctx->text.s.atom_count = (int)nelems; 3139 3140 return (ctx->text.s.selections); 3141 } 3142 3143 /* 3144 * Function: 3145 * SetSelection 3146 * 3147 * Parameters: 3148 * ctx - text widget 3149 * defaultSel - default selection 3150 * l - left and right ends of the selection 3151 * r - "" 3152 * list - the selection list (as strings). 3153 * nelems - "" 3154 * 3155 * Description: 3156 * Sets the current selection. 3157 * 3158 * Note: 3159 * if (ctx->text.s.left >= ctx->text.s.right) then the selection is unset 3160 */ 3161 void 3162 _XawTextSetSelection(TextWidget ctx, XawTextPosition l, XawTextPosition r, 3163 String *list, Cardinal nelems) 3164 { 3165 if (nelems == 1 && !strcmp (list[0], "none")) 3166 return; 3167 if (nelems == 0) { 3168 static String defaultSel = "PRIMARY"; 3169 list = &defaultSel; 3170 nelems = 1; 3171 } 3172 _SetSelection(ctx, l, r, _XawTextSelectionList(ctx, list, nelems), nelems); 3173 } 3174 3175 /* 3176 * Function: 3177 * ModifySelection 3178 * 3179 * Parameters: 3180 * ctx - text widget 3181 * left - left and right ends of the selection 3182 * right - "" 3183 * 3184 * Description: 3185 * Modifies the current selection. 3186 * 3187 * Note: 3188 * if (ctx->text.s.left >= ctx->text.s.right) then the selection is unset 3189 */ 3190 static void 3191 ModifySelection(TextWidget ctx, XawTextPosition left, XawTextPosition right) 3192 { 3193 if (left == right) 3194 ctx->text.insertPos = left; 3195 _SetSelection(ctx, left, right, NULL, 0); 3196 } 3197 3198 /* 3199 * This routine is used to perform various selection functions. The goal is 3200 * to be able to specify all the more popular forms of draw-through and 3201 * multi-click selection user interfaces from the outside. 3202 */ 3203 void 3204 _XawTextAlterSelection(TextWidget ctx, XawTextSelectionMode mode, 3205 XawTextSelectionAction action, String *params, 3206 Cardinal *num_params) 3207 { 3208 XawTextPosition position; 3209 Boolean flag; 3210 3211 /* 3212 * This flag is used by TextPop.c:DoReplace() to determine if the selection 3213 * is okay to use, or if it has been modified. 3214 */ 3215 if (ctx->text.search != NULL) 3216 ctx->text.search->selection_changed = True; 3217 3218 position = PositionForXY(ctx, (int) ctx->text.ev_x, (int) ctx->text.ev_y); 3219 3220 flag = (action != XawactionStart); 3221 if (mode == XawsmTextSelect) 3222 DoSelection(ctx, position, ctx->text.time, flag); 3223 else /* mode == XawsmTextExtend */ 3224 ExtendSelection (ctx, position, flag); 3225 3226 if (action == XawactionEnd) 3227 _XawTextSetSelection(ctx, ctx->text.s.left, ctx->text.s.right, 3228 params, *num_params); 3229 } 3230 3231 /* 3232 * Function: 3233 * UpdateTextInRectangle 3234 * 3235 * Parameters: 3236 * ctx - the text widget 3237 * rect - rectangle 3238 * 3239 * Description: 3240 * Updates the text in the given rectangle 3241 */ 3242 static void 3243 UpdateTextInRectangle(TextWidget ctx, XRectangle *rect) 3244 { 3245 XawTextLineTable *lt; 3246 int line, y1, y2, x2; 3247 3248 y1 = rect->y; 3249 y2 = y1 + rect->height; 3250 x2 = rect->x + rect->width; 3251 3252 for (line = 0, lt = &ctx->text.lt; line < lt->lines; line++) 3253 if (lt->info[line + 1].y > y1) 3254 break; 3255 for (; line <= lt->lines; line++) { 3256 if (lt->info[line].y > y2) 3257 break; 3258 UpdateTextInLine(ctx, line, rect->x, x2); 3259 } 3260 } 3261 3262 /* 3263 * This routine processes all "expose region" XEvents. In general, its job 3264 * is to the best job at minimal re-paint of the text, displayed in the 3265 * window, that it can. 3266 */ 3267 /* ARGSUSED */ 3268 static void 3269 XawTextExpose(Widget w, XEvent *event, Region region) 3270 { 3271 TextWidget ctx = (TextWidget)w; 3272 Boolean clear_to_eol; 3273 XRectangle expose; 3274 3275 if (event->type == Expose) { 3276 expose.x = (short)event->xexpose.x; 3277 expose.y = (short)event->xexpose.y; 3278 expose.width = (unsigned short)event->xexpose.width; 3279 expose.height = (unsigned short)event->xexpose.height; 3280 } 3281 else if (event->type == GraphicsExpose) { 3282 expose.x = (short)event->xgraphicsexpose.x; 3283 expose.y = (short)event->xgraphicsexpose.y; 3284 expose.width = (unsigned short)event->xgraphicsexpose.width; 3285 expose.height = (unsigned short)event->xgraphicsexpose.height; 3286 } 3287 else 3288 return; 3289 3290 _XawTextPrepareToUpdate(ctx); 3291 3292 if (Superclass->core_class.expose) 3293 (*Superclass->core_class.expose)(w, event, region); 3294 3295 clear_to_eol = ctx->text.clear_to_eol; 3296 ctx->text.clear_to_eol = False; 3297 3298 UpdateTextInRectangle(ctx, &expose); 3299 XawTextSinkGetCursorBounds(ctx->text.sink, &expose); 3300 UpdateTextInRectangle(ctx, &expose); 3301 SinkClearToBG(ctx->text.sink, expose.x, expose.y, 3302 expose.width, expose.height); 3303 _XawTextExecuteUpdate(ctx); 3304 ctx->text.clear_to_eol = clear_to_eol; 3305 } 3306 3307 /* 3308 * This routine does all setup required to synchronize batched screen updates 3309 */ 3310 void 3311 _XawTextPrepareToUpdate(TextWidget ctx) 3312 { 3313 if (ctx->text.old_insert < 0) { 3314 InsertCursor((Widget)ctx, XawisOff); 3315 ctx->text.showposition = False; 3316 ctx->text.old_insert = ctx->text.insertPos; 3317 ctx->text.clear_to_eol = False; 3318 #ifndef OLDXAW 3319 ctx->text.source_changed = SRC_CHANGE_NONE; 3320 #endif 3321 } 3322 } 3323 3324 /* 3325 * This is a private utility routine used by _XawTextExecuteUpdate. It 3326 * processes all the outstanding update requests and merges update 3327 * ranges where possible. 3328 */ 3329 static void 3330 FlushUpdate(TextWidget ctx) 3331 { 3332 XmuSegment *seg; 3333 void (*display_text)(Widget, XawTextPosition, XawTextPosition); 3334 3335 if (XtIsRealized((Widget)ctx)) { 3336 ctx->text.s.right = XawMin(ctx->text.s.right, ctx->text.lastPos); 3337 ctx->text.s.left = XawMin(ctx->text.s.left, ctx->text.s.right); 3338 3339 #ifndef OLDXAW 3340 if (XawTextSinkBeginPaint(ctx->text.sink) == False) 3341 #endif 3342 display_text = OldDisplayText; 3343 #ifndef OLDXAW 3344 else 3345 display_text = DisplayText; 3346 #endif 3347 for (seg = ctx->text.update->segment; seg; seg = seg->next) 3348 (*display_text)((Widget)ctx, 3349 (XawTextPosition)seg->x1, 3350 (XawTextPosition)seg->x2); 3351 #ifndef OLDXAW 3352 if (display_text != OldDisplayText) { 3353 XawTextSinkDoPaint(ctx->text.sink); 3354 XawTextSinkEndPaint(ctx->text.sink); 3355 } 3356 #endif 3357 } 3358 (void)XmuScanlineXor(ctx->text.update, ctx->text.update); 3359 } 3360 3361 static int 3362 CountLines(TextWidget ctx, XawTextPosition left, XawTextPosition right) 3363 { 3364 if (ctx->text.wrap == XawtextWrapNever || left >= right) 3365 return (1); 3366 else { 3367 int dim, lines = 0, wwidth = GetMaxTextWidth(ctx); 3368 3369 while (left < right) { 3370 XawTextPosition tmp = left; 3371 3372 XawTextSinkFindPosition(ctx->text.sink, left, 3373 ctx->text.left_margin, 3374 wwidth, ctx->text.wrap == XawtextWrapWord, 3375 &left, &dim, &dim); 3376 ++lines; 3377 if (tmp == left) 3378 ++left; 3379 } 3380 3381 return (lines); 3382 } 3383 /*NOTREACHED*/ 3384 } 3385 3386 static int 3387 GetMaxTextWidth(TextWidget ctx) 3388 { 3389 XRectangle cursor; 3390 int width; 3391 3392 XawTextSinkGetCursorBounds(ctx->text.sink, &cursor); 3393 width = (int)XtWidth(ctx) - RHMargins(ctx) - cursor.width; 3394 3395 return (XawMax(0, width)); 3396 } 3397 3398 /* 3399 * Function: 3400 * _XawTextShowPosition 3401 * 3402 * Parameters: 3403 * ctx - the text widget to show the position 3404 * 3405 * Description: 3406 * Makes sure the text cursor visible, scrolling the text window 3407 * if required. 3408 */ 3409 void 3410 _XawTextShowPosition(TextWidget ctx) 3411 { 3412 /* 3413 * Variable scroll is used to avoid scanning large files to calculate 3414 * line offsets 3415 */ 3416 int hpixels, vlines; 3417 XawTextPosition first, last, top, tmp; 3418 Bool visible, scroll; 3419 3420 if (!XtIsRealized((Widget)ctx)) 3421 return; 3422 3423 /* 3424 * Checks if a horizontal scroll is required 3425 */ 3426 if (ctx->text.wrap == XawtextWrapNever) { 3427 int x, vwidth, distance, dim; 3428 XRectangle rect; 3429 3430 vwidth = (int)XtWidth(ctx) - RHMargins(ctx); 3431 last = SrcScan(ctx->text.source, ctx->text.insertPos, 3432 XawstEOL, XawsdLeft, 1, False); 3433 XawTextSinkFindDistance(ctx->text.sink, last, 3434 ctx->text.left_margin, 3435 ctx->text.insertPos, 3436 &distance, &first, &dim); 3437 XawTextSinkGetCursorBounds(ctx->text.sink, &rect); 3438 x = ctx->text.left_margin - ctx->text.r_margin.left; 3439 3440 if (x + distance + rect.width > vwidth) 3441 hpixels = x + distance + rect.width - vwidth + (vwidth >> 2); 3442 else if (x + distance < 0) 3443 hpixels = x + distance - (vwidth >> 2); 3444 else 3445 hpixels = 0; 3446 } 3447 else 3448 hpixels = 0; 3449 3450 visible = IsPositionVisible(ctx, ctx->text.insertPos); 3451 3452 /* 3453 * If the cursor is already visible 3454 */ 3455 if (!hpixels && visible) 3456 return; 3457 3458 scroll = ctx->core.background_pixmap == XtUnspecifiedPixmap && !hpixels; 3459 vlines = 0; 3460 first = ctx->text.lt.top; 3461 3462 /* 3463 * Needs to scroll the text window 3464 */ 3465 if (visible) 3466 top = ctx->text.lt.top; 3467 else { 3468 top = SrcScan(ctx->text.source, ctx->text.insertPos, 3469 XawstEOL, XawsdLeft, 1, False); 3470 3471 /* 3472 * Finds the nearest left position from ctx->text.insertPos 3473 */ 3474 if (ctx->text.wrap != XawtextWrapNever) { 3475 int dim, vwidth = GetMaxTextWidth(ctx); 3476 3477 last = top; 3478 /*CONSTCOND*/ 3479 while (1) { 3480 tmp = last; 3481 XawTextSinkFindPosition(ctx->text.sink, last, 3482 ctx->text.left_margin, vwidth, 3483 ctx->text.wrap == XawtextWrapWord, 3484 &last, &dim, &dim); 3485 if (last == tmp) 3486 ++last; 3487 if (last <= ctx->text.insertPos) 3488 top = last; 3489 else 3490 break; 3491 } 3492 } 3493 } 3494 3495 if (scroll) { 3496 if (ctx->text.insertPos < first) { /* Scroll Down */ 3497 while (first > top) { 3498 last = first; 3499 first = SrcScan(ctx->text.source, first, 3500 XawstEOL, XawsdLeft, 2, False); 3501 vlines -= CountLines(ctx, first, last); 3502 if (-vlines >= ctx->text.lt.lines) { 3503 scroll = False; 3504 break; 3505 } 3506 } 3507 } 3508 else if (!visible) { /* Scroll Up */ 3509 while (first < top) { 3510 last = first; 3511 first = SrcScan(ctx->text.source, first, 3512 XawstEOL, XawsdRight, 1, True); 3513 vlines += CountLines(ctx, last, first); 3514 if (vlines > ctx->text.lt.lines) { 3515 scroll = False; 3516 break; 3517 } 3518 } 3519 } 3520 else 3521 scroll = False; 3522 } 3523 3524 /* 3525 * If a portion of the text that will be scrolled is visible 3526 */ 3527 if (scroll) 3528 XawTextScroll(ctx, vlines ? vlines - (ctx->text.lt.lines >> 1) : 0, 0); 3529 /* 3530 * Else redraw the entire text window 3531 */ 3532 else { 3533 ctx->text.left_margin -= hpixels; 3534 if (ctx->text.left_margin > ctx->text.r_margin.left) 3535 ctx->text.left_margin = ctx->text.margin.left = 3536 ctx->text.r_margin.left; 3537 3538 if (!visible) { 3539 vlines = ctx->text.lt.lines >> 1; 3540 if (vlines) 3541 top = SrcScan(ctx->text.source, ctx->text.insertPos, 3542 XawstEOL, XawsdLeft, vlines + 1, False); 3543 3544 if (ctx->text.wrap != XawtextWrapNever) { 3545 int dim; 3546 int n_lines = CountLines(ctx, top, ctx->text.insertPos); 3547 int vwidth = GetMaxTextWidth(ctx); 3548 3549 while (n_lines-- > vlines) { 3550 tmp = top; 3551 XawTextSinkFindPosition(ctx->text.sink, top, 3552 ctx->text.left_margin, 3553 vwidth, 3554 ctx->text.wrap == XawtextWrapWord, 3555 &top, &dim, &dim); 3556 if (tmp == top) 3557 ++top; 3558 } 3559 } 3560 _XawTextBuildLineTable(ctx, top, True); 3561 } 3562 else 3563 ClearWindow(ctx); 3564 } 3565 ctx->text.clear_to_eol = True; 3566 } 3567 3568 #ifndef OLDXAW 3569 static int 3570 ResolveLineNumber(TextWidget ctx) 3571 { 3572 int line_number = ctx->text.lt.base_line; 3573 XawTextPosition position = ctx->text.lt.top; 3574 3575 if (ctx->text.lt.base_line < 1) 3576 return (ctx->text.line_number); 3577 3578 if (ctx->text.wrap == XawtextWrapNever 3579 && IsPositionVisible(ctx, ctx->text.insertPos)) 3580 line_number += LineForPosition(ctx, ctx->text.insertPos); 3581 else if (position < ctx->text.insertPos) { 3582 while (position < ctx->text.insertPos) { 3583 position = SrcScan(ctx->text.source, position, 3584 XawstEOL, XawsdRight, 1, True); 3585 if (position <= ctx->text.insertPos) { 3586 ++line_number; 3587 if (position == ctx->text.lastPos) { 3588 line_number -= !_XawTextSourceNewLineAtEOF(ctx->text.source); 3589 break; 3590 } 3591 } 3592 } 3593 } 3594 else if (position > ctx->text.insertPos) { 3595 while (position > ctx->text.insertPos) { 3596 position = SrcScan(ctx->text.source, position, 3597 XawstEOL, XawsdLeft, 1, False); 3598 if (--position >= ctx->text.insertPos) 3599 --line_number; 3600 } 3601 } 3602 3603 return (line_number); 3604 } 3605 #endif 3606 3607 /* 3608 * This routine causes all batched screen updates to be performed 3609 */ 3610 void 3611 _XawTextExecuteUpdate(TextWidget ctx) 3612 { 3613 if (ctx->text.update_disabled || ctx->text.old_insert < 0) 3614 return; 3615 3616 if(ctx->text.old_insert != ctx->text.insertPos || ctx->text.showposition) 3617 _XawTextShowPosition(ctx); 3618 3619 FlushUpdate(ctx); 3620 InsertCursor((Widget)ctx, XawisOn); 3621 ctx->text.old_insert = -1; 3622 #ifndef OLDXAW 3623 _XawTextSetLineAndColumnNumber(ctx, False); 3624 #endif 3625 } 3626 3627 static void 3628 XawTextDestroy(Widget w) 3629 { 3630 TextWidget ctx = (TextWidget)w; 3631 3632 DestroyHScrollBar(ctx); 3633 DestroyVScrollBar(ctx); 3634 3635 XtFree((char *)ctx->text.s.selections); 3636 XtFree((char *)ctx->text.lt.info); 3637 XtFree((char *)ctx->text.search); 3638 XmuDestroyScanline(ctx->text.update); 3639 XtReleaseGC((Widget)ctx, ctx->text.gc); 3640 } 3641 3642 /* 3643 * by the time we are managed (and get this far) we had better 3644 * have both a source and a sink 3645 */ 3646 static void 3647 XawTextResize(Widget w) 3648 { 3649 TextWidget ctx = (TextWidget)w; 3650 3651 PositionVScrollBar(ctx); 3652 PositionHScrollBar(ctx); 3653 TextSinkResize(ctx->text.sink); 3654 3655 ctx->text.showposition = True; 3656 _XawTextBuildLineTable(ctx, ctx->text.lt.top, True); 3657 } 3658 3659 /* 3660 * This routine allow the application program to Set attributes. 3661 */ 3662 /*ARGSUSED*/ 3663 static Boolean 3664 XawTextSetValues(Widget current, Widget request _X_UNUSED, Widget cnew, 3665 ArgList args, Cardinal *num_args) 3666 { 3667 TextWidget oldtw = (TextWidget)current; 3668 TextWidget newtw = (TextWidget)cnew; 3669 Boolean redisplay = False; 3670 Boolean display_caret = newtw->text.display_caret; 3671 #ifndef OLDXAW 3672 Boolean show_lc = False; 3673 #endif 3674 3675 newtw->text.display_caret = oldtw->text.display_caret; 3676 _XawTextPrepareToUpdate(newtw); 3677 newtw->text.display_caret = display_caret; 3678 3679 if (oldtw->text.r_margin.left != newtw->text.r_margin.left) { 3680 newtw->text.left_margin = newtw->text.margin.left = 3681 newtw->text.r_margin.left; 3682 if (newtw->text.vbar != NULL) { 3683 newtw->text.left_margin += XtWidth(newtw->text.vbar) + 3684 XtBorderWidth(newtw->text.vbar); 3685 } 3686 redisplay = True; 3687 } 3688 3689 if (oldtw->text.scroll_vert != newtw->text.scroll_vert) { 3690 if (newtw->text.scroll_vert == XawtextScrollAlways) 3691 CreateVScrollBar(newtw); 3692 else 3693 DestroyVScrollBar(newtw); 3694 3695 redisplay = True; 3696 } 3697 3698 if (oldtw->text.r_margin.bottom != newtw->text.r_margin.bottom) { 3699 newtw->text.margin.bottom = newtw->text.r_margin.bottom; 3700 if (newtw->text.hbar != NULL) 3701 newtw->text.margin.bottom = (Position)(newtw->text.margin.bottom 3702 + (newtw->text.hbar->core.height 3703 + newtw->text.hbar->core.border_width)); 3704 redisplay = True; 3705 } 3706 3707 if (oldtw->text.scroll_horiz != newtw->text.scroll_horiz) { 3708 if (newtw->text.scroll_horiz == XawtextScrollAlways) 3709 CreateHScrollBar(newtw); 3710 else 3711 DestroyHScrollBar(newtw); 3712 3713 redisplay = True; 3714 } 3715 3716 if (oldtw->text.source != newtw->text.source) { 3717 #ifndef OLDXAW 3718 show_lc = True; 3719 _XawSourceRemoveText(oldtw->text.source, cnew, 3720 oldtw->text.source && 3721 XtParent(oldtw->text.source) == cnew); 3722 _XawSourceAddText(newtw->text.source, cnew); 3723 #endif 3724 _XawTextSetSource((Widget)newtw, newtw->text.source, newtw->text.lt.top, 3725 newtw->text.insertPos); 3726 } 3727 3728 newtw->text.redisplay_needed = False; 3729 XtSetValues((Widget)newtw->text.source, args, *num_args); 3730 XtSetValues((Widget)newtw->text.sink, args, *num_args); 3731 3732 if (oldtw->text.wrap != newtw->text.wrap 3733 || oldtw->text.lt.top != newtw->text.lt.top 3734 || oldtw->text.insertPos != newtw->text.insertPos 3735 || oldtw->text.r_margin.right != newtw->text.r_margin.right 3736 || oldtw->text.r_margin.top != newtw->text.r_margin.top 3737 || oldtw->text.sink != newtw->text.sink 3738 || newtw->text.redisplay_needed) { 3739 if (oldtw->text.wrap != newtw->text.wrap) { 3740 newtw->text.left_margin = newtw->text.margin.left = 3741 newtw->text.r_margin.left; 3742 if (oldtw->text.lt.top == newtw->text.lt.top) 3743 newtw->text.lt.top = SrcScan(newtw->text.source, 0, XawstEOL, 3744 XawsdLeft, 1, False); 3745 } 3746 newtw->text.showposition = True; 3747 #ifndef OLDXAW 3748 show_lc = True; 3749 newtw->text.source_changed = SRC_CHANGE_OVERLAP; 3750 #endif 3751 _XawTextBuildLineTable(newtw, newtw->text.lt.top, True); 3752 redisplay = True; 3753 } 3754 3755 #ifndef OLDXAW 3756 if (newtw->text.left_column < 0) 3757 newtw->text.left_column = 0; 3758 if (newtw->text.right_column < 0) 3759 newtw->text.right_column = 0; 3760 #endif 3761 3762 _XawTextExecuteUpdate(newtw); 3763 3764 #ifndef OLDXAW 3765 if (show_lc) 3766 _XawTextSetLineAndColumnNumber(newtw, True); 3767 #endif 3768 3769 if (redisplay) 3770 _XawTextSetScrollBars(newtw); 3771 3772 return (redisplay); 3773 } 3774 3775 /* invoked by the Simple widget's SetValues */ 3776 static Bool 3777 XawTextChangeSensitive(Widget w) 3778 { 3779 Arg args[1]; 3780 TextWidget tw = (TextWidget)w; 3781 3782 (*(&simpleClassRec)->simple_class.change_sensitive)(w); 3783 3784 XtSetArg(args[0], XtNancestorSensitive, 3785 (tw->core.ancestor_sensitive && tw->core.sensitive)); 3786 if (tw->text.vbar) 3787 XtSetValues(tw->text.vbar, args, ONE); 3788 if (tw->text.hbar) 3789 XtSetValues(tw->text.hbar, args, ONE); 3790 return (False); 3791 } 3792 3793 /* 3794 * Function: 3795 * XawTextGetValuesHook 3796 * 3797 * Parameters: 3798 * w - Text Widget 3799 * args - argument list 3800 * num_args - number of args 3801 * 3802 * Description: 3803 * This is a get values hook routine that gets the 3804 * values in the text source and sink. 3805 */ 3806 static void 3807 XawTextGetValuesHook(Widget w, ArgList args, Cardinal *num_args) 3808 { 3809 XtGetValues(((TextWidget)w)->text.source, args, *num_args); 3810 XtGetValues(((TextWidget)w)->text.sink, args, *num_args); 3811 } 3812 3813 /* 3814 * Function: 3815 * FindGoodPosition 3816 * 3817 * Parameters: 3818 * pos - any position 3819 * 3820 * Description: 3821 * Returns a valid position given any position. 3822 * 3823 * Returns: 3824 * A position between (0 and lastPos) 3825 */ 3826 static XawTextPosition 3827 FindGoodPosition(TextWidget ctx, XawTextPosition pos) 3828 { 3829 if (pos < 0) 3830 return (0); 3831 return (((pos > ctx->text.lastPos) ? ctx->text.lastPos : pos)); 3832 } 3833 3834 /* Li wrote this so the IM can find a given text position's screen position */ 3835 void 3836 _XawTextPosToXY(Widget w, XawTextPosition pos, Position *x, Position *y) 3837 { 3838 int line, ix, iy; 3839 3840 LineAndXYForPosition((TextWidget)w, pos, &line, &ix, &iy); 3841 *x = (Position)ix; 3842 *y = (Position)iy; 3843 } 3844 3845 /******************************************************************* 3846 The following routines provide procedural interfaces to Text window state 3847 setting and getting. They need to be redone so than the args code can use 3848 them. I suggest we create a complete set that takes the context as an 3849 argument and then have the public version lookup the context and call the 3850 internal one. The major value of this set is that they have actual application 3851 clients and therefore the functionality provided is required for any future 3852 version of Text. 3853 ********************************************************************/ 3854 void 3855 XawTextDisplay(Widget w) 3856 { 3857 TextWidget ctx = (TextWidget)w; 3858 3859 if (!XtIsRealized(w)) 3860 return; 3861 3862 _XawTextPrepareToUpdate(ctx); 3863 ctx->text.clear_to_eol = True; 3864 DisplayTextWindow(w); 3865 _XawTextExecuteUpdate(ctx); 3866 } 3867 3868 void 3869 XawTextSetSelectionArray(Widget w, XawTextSelectType *sarray) 3870 { 3871 ((TextWidget)w)->text.sarray = sarray; 3872 } 3873 3874 void 3875 XawTextGetSelectionPos(Widget w, XawTextPosition *left, XawTextPosition *right) 3876 { 3877 *left = ((TextWidget)w)->text.s.left; 3878 *right = ((TextWidget)w)->text.s.right; 3879 } 3880 3881 void 3882 _XawTextSetSource(Widget w, Widget source, 3883 XawTextPosition top, XawTextPosition startPos) 3884 { 3885 TextWidget ctx = (TextWidget)w; 3886 #ifndef OLDXAW 3887 Bool resolve = False; 3888 #endif 3889 3890 #ifndef OLDXAW 3891 if (source != ctx->text.source) 3892 _XawSourceRemoveText(ctx->text.source, w, ctx->text.source && 3893 XtParent(ctx->text.source) == w); 3894 _XawSourceAddText(source, w); 3895 3896 if (source != ctx->text.source || ctx->text.insertPos != startPos) 3897 resolve = True; 3898 3899 ctx->text.source_changed = SRC_CHANGE_OVERLAP; 3900 #endif 3901 ctx->text.source = source; 3902 ctx->text.s.left = ctx->text.s.right = 0; 3903 ctx->text.lastPos = GETLASTPOS; 3904 top = FindGoodPosition(ctx, top); 3905 startPos = FindGoodPosition(ctx, startPos); 3906 ctx->text.insertPos = ctx->text.old_insert = startPos; 3907 _XawTextPrepareToUpdate(ctx); 3908 3909 _XawTextBuildLineTable(ctx, top, True); 3910 3911 _XawTextExecuteUpdate(ctx); 3912 #ifndef OLDXAW 3913 if (resolve) 3914 _XawTextSetLineAndColumnNumber(ctx, True); 3915 #endif 3916 } 3917 3918 void 3919 XawTextSetSource(Widget w, Widget source, XawTextPosition top) 3920 { 3921 _XawTextSetSource(w, source, top, top); 3922 } 3923 3924 /* 3925 * This public routine deletes the text from startPos to endPos in a source and 3926 * then inserts, at startPos, the text that was passed. As a side effect it 3927 * "invalidates" that portion of the displayed text (if any), so that things 3928 * will be repainted properly. 3929 */ 3930 int 3931 XawTextReplace(Widget w, XawTextPosition startPos, XawTextPosition endPos, 3932 XawTextBlock *text) 3933 { 3934 TextWidget ctx = (TextWidget)w; 3935 int result; 3936 #ifndef OLDXAW 3937 Cardinal i; 3938 TextSrcObject src = (TextSrcObject)ctx->text.source; 3939 3940 for (i = 0; i < src->textSrc.num_text; i++) 3941 _XawTextPrepareToUpdate((TextWidget)src->textSrc.text[i]); 3942 #else 3943 _XawTextPrepareToUpdate(ctx); 3944 #endif 3945 3946 endPos = FindGoodPosition(ctx, endPos); 3947 startPos = FindGoodPosition(ctx, startPos); 3948 result = _XawTextReplace(ctx, startPos, endPos, text); 3949 3950 #ifndef OLDXAW 3951 for (i = 0; i < src->textSrc.num_text; i++) 3952 _XawTextExecuteUpdate((TextWidget)src->textSrc.text[i]); 3953 #else 3954 _XawTextExecuteUpdate(ctx); 3955 #endif 3956 3957 return (result); 3958 } 3959 3960 XawTextPosition 3961 XawTextTopPosition(Widget w) 3962 { 3963 return (((TextWidget)w)->text.lt.top); 3964 } 3965 3966 XawTextPosition 3967 XawTextLastPosition(Widget w) 3968 { 3969 return (((TextWidget)w)->text.lastPos); 3970 } 3971 3972 void 3973 XawTextSetInsertionPoint(Widget w, XawTextPosition position) 3974 { 3975 TextWidget ctx = (TextWidget)w; 3976 3977 _XawTextPrepareToUpdate(ctx); 3978 ctx->text.insertPos = FindGoodPosition(ctx, position); 3979 ctx->text.showposition = True; 3980 ctx->text.from_left = -1; 3981 3982 _XawTextExecuteUpdate(ctx); 3983 #ifndef OLDXAW 3984 _XawTextSetLineAndColumnNumber(ctx, False); 3985 #endif 3986 } 3987 3988 XawTextPosition 3989 XawTextGetInsertionPoint(Widget w) 3990 { 3991 return (((TextWidget)w)->text.insertPos); 3992 } 3993 3994 /* 3995 * Note: Must walk the selection list in opposite order from TextLoseSelection 3996 */ 3997 void 3998 XawTextUnsetSelection(Widget w) 3999 { 4000 TextWidget ctx = (TextWidget)w; 4001 4002 while (ctx->text.s.atom_count != 0) { 4003 Atom sel = ctx->text.s.selections[ctx->text.s.atom_count - 1]; 4004 4005 if (sel != (Atom) 0) { 4006 /* 4007 * As selections are lost the atom_count will decrement 4008 */ 4009 if (GetCutBufferNumber(sel) == NOT_A_CUT_BUFFER) 4010 XtDisownSelection(w, sel, ctx->text.time); 4011 TextLoseSelection(w, &sel); /* In case this is a cut buffer, or 4012 XtDisownSelection failed to call us */ 4013 } 4014 } 4015 } 4016 4017 void 4018 XawTextSetSelection(Widget w, XawTextPosition left, XawTextPosition right) 4019 { 4020 TextWidget ctx = (TextWidget)w; 4021 4022 _XawTextPrepareToUpdate(ctx); 4023 _XawTextSetSelection(ctx, FindGoodPosition(ctx, left), 4024 FindGoodPosition(ctx, right), NULL, 0); 4025 _XawTextExecuteUpdate(ctx); 4026 } 4027 4028 void 4029 XawTextInvalidate(Widget w, XawTextPosition from, XawTextPosition to) 4030 { 4031 TextWidget ctx = (TextWidget)w; 4032 4033 from = FindGoodPosition(ctx, from); 4034 to = FindGoodPosition(ctx, to); 4035 ctx->text.lastPos = GETLASTPOS; 4036 _XawTextPrepareToUpdate(ctx); 4037 _XawTextNeedsUpdating(ctx, from, to); 4038 _XawTextExecuteUpdate(ctx); 4039 } 4040 4041 /*ARGSUSED*/ 4042 void 4043 XawTextDisableRedisplay(Widget w) 4044 { 4045 ((TextWidget)w)->text.update_disabled = True; 4046 _XawTextPrepareToUpdate((TextWidget)w); 4047 } 4048 4049 void 4050 XawTextEnableRedisplay(Widget w) 4051 { 4052 TextWidget ctx = (TextWidget)w; 4053 XawTextPosition lastPos; 4054 4055 if (!ctx->text.update_disabled) 4056 return; 4057 4058 ctx->text.update_disabled = False; 4059 lastPos = ctx->text.lastPos = GETLASTPOS; 4060 ctx->text.lt.top = FindGoodPosition(ctx, ctx->text.lt.top); 4061 ctx->text.insertPos = FindGoodPosition(ctx, ctx->text.insertPos); 4062 4063 if (ctx->text.s.left > lastPos || ctx->text.s.right > lastPos) 4064 ctx->text.s.left = ctx->text.s.right = 0; 4065 4066 _XawTextExecuteUpdate(ctx); 4067 } 4068 4069 Widget 4070 XawTextGetSource(Widget w) 4071 { 4072 return (((TextWidget)w)->text.source); 4073 } 4074 4075 Widget 4076 XawTextGetSink(Widget w) 4077 { 4078 return (((TextWidget)w)->text.sink); 4079 } 4080 4081 void 4082 XawTextDisplayCaret(Widget w, 4083 #if NeedWidePrototypes 4084 int display_caret 4085 #else 4086 Boolean display_caret 4087 #endif 4088 ) 4089 { 4090 TextWidget ctx = (TextWidget)w; 4091 4092 if (XtIsRealized(w)) { 4093 _XawTextPrepareToUpdate(ctx); 4094 ctx->text.display_caret = display_caret; 4095 _XawTextExecuteUpdate(ctx); 4096 } 4097 else 4098 ctx->text.display_caret = display_caret; 4099 } 4100 4101 /* 4102 * Function: 4103 * XawTextSearch 4104 * 4105 * Parameters: 4106 * w - text widget 4107 * dir - direction to search 4108 * text - text block containing info about the string to search for 4109 * 4110 * Description: 4111 * Searches for the given text block. 4112 * 4113 * Returns: 4114 * The position of the text found, or XawTextSearchError on an error 4115 */ 4116 XawTextPosition 4117 XawTextSearch(Widget w, 4118 #if NeedWidePrototypes 4119 int dir, 4120 #else 4121 XawTextScanDirection dir, 4122 #endif 4123 XawTextBlock *text) 4124 { 4125 TextWidget ctx = (TextWidget)w; 4126 4127 return (SrcSearch(ctx->text.source, ctx->text.insertPos, dir, text)); 4128 } 4129 4130 TextClassRec textClassRec = { 4131 /* core */ 4132 { 4133 (WidgetClass)&simpleClassRec, /* superclass */ 4134 "Text", /* class_name */ 4135 sizeof(TextRec), /* widget_size */ 4136 XawTextClassInitialize, /* class_initialize */ 4137 NULL, /* class_part_init */ 4138 False, /* class_inited */ 4139 XawTextInitialize, /* initialize */ 4140 NULL, /* initialize_hook */ 4141 XawTextRealize, /* realize */ 4142 _XawTextActionsTable, /* actions */ 4143 0, /* num_actions */ 4144 resources, /* resources */ 4145 XtNumber(resources), /* num_resource */ 4146 NULLQUARK, /* xrm_class */ 4147 True, /* compress_motion */ 4148 XtExposeGraphicsExpose | /* compress_exposure */ 4149 XtExposeNoExpose, 4150 True, /* compress_enterleave */ 4151 False, /* visible_interest */ 4152 XawTextDestroy, /* destroy */ 4153 XawTextResize, /* resize */ 4154 XawTextExpose, /* expose */ 4155 XawTextSetValues, /* set_values */ 4156 NULL, /* set_values_hook */ 4157 XtInheritSetValuesAlmost, /* set_values_almost */ 4158 XawTextGetValuesHook, /* get_values_hook */ 4159 NULL, /* accept_focus */ 4160 XtVersion, /* version */ 4161 NULL, /* callback_private */ 4162 _XawDefaultTextTranslations, /* tm_table */ 4163 XtInheritQueryGeometry, /* query_geometry */ 4164 XtInheritDisplayAccelerator, /* display_accelerator */ 4165 NULL, /* extension */ 4166 }, 4167 /* simple */ 4168 { 4169 XawTextChangeSensitive, /* change_sensitive */ 4170 #ifndef OLDXAW 4171 NULL, 4172 #endif 4173 }, 4174 /* text */ 4175 { 4176 NULL, /* extension */ 4177 } 4178 }; 4179 4180 WidgetClass textWidgetClass = (WidgetClass)&textClassRec; 4181