1 /* 2 3 Copyright 1989, 1994, 1998 The Open Group 4 5 Permission to use, copy, modify, distribute, and sell this software and its 6 documentation for any purpose is hereby granted without fee, provided that 7 the above copyright notice appear in all copies and that both that 8 copyright notice and this permission notice appear in supporting 9 documentation. 10 11 The above copyright notice and this permission notice shall be included in 12 all copies or substantial portions of the Software. 13 14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 21 Except as contained in this notice, the name of The Open Group shall not be 22 used in advertising or otherwise to promote the sale, use or other dealings 23 in this Software without prior written authorization from The Open Group. 24 25 */ 26 27 /* 28 * Author: Chris Peterson, MIT X Consortium. 29 * Much code taken from X11R3 String and Disk Sources. 30 */ 31 32 #ifdef HAVE_CONFIG_H 33 #include <config.h> 34 #endif 35 #include <stdio.h> 36 #include <ctype.h> 37 #include <X11/IntrinsicP.h> 38 #include <X11/StringDefs.h> 39 #include <X11/Xfuncs.h> 40 #include <X11/Xutil.h> 41 #include <X11/Xmu/Atoms.h> 42 #include <X11/Xmu/CharSet.h> 43 #include <X11/Xaw/TextSrcP.h> 44 #include <X11/Xaw/XawInit.h> 45 #include "XawI18n.h" 46 #include "Private.h" 47 48 #ifndef OLDXAW 49 #define UNDO_DEPTH 16384 50 51 #define ANCHORS_DIST 4096 /* default distance between anchors */ 52 53 /* 54 * Types 55 */ 56 typedef struct { 57 XawTextPosition position; 58 char *buffer; 59 unsigned length; 60 unsigned refcount; 61 unsigned long format; 62 } XawTextUndoBuffer; 63 64 typedef struct _XawTextUndoList XawTextUndoList; 65 struct _XawTextUndoList { 66 XawTextUndoBuffer *left, *right; 67 XawTextUndoList *undo, *redo; 68 }; 69 70 struct _XawTextUndo { 71 XawTextUndoBuffer **undo; 72 unsigned num_undo; 73 XawTextUndoList *list, *pointer, *end_mark, *head; 74 unsigned num_list; 75 XawTextScanDirection dir; 76 XawTextUndoBuffer *l_save, *r_save; 77 XawTextUndoList *u_save; 78 XawTextUndoBuffer *l_no_change, *r_no_change; 79 int merge; 80 int erase; /* there are two types of erases */ 81 }; 82 #endif /* OLDXAW */ 83 84 /* 85 * Class Methods 86 */ 87 static Boolean ConvertSelection(Widget, Atom*, Atom*, Atom*, XtPointer*, 88 unsigned long*, int*); 89 static XawTextPosition Read(Widget, XawTextPosition, XawTextBlock*, int); 90 static int Replace(Widget, XawTextPosition, XawTextPosition, XawTextBlock*); 91 static XawTextPosition Scan(Widget, XawTextPosition, XawTextScanType, 92 XawTextScanDirection, int, Bool); 93 static XawTextPosition Search(Widget, XawTextPosition, XawTextScanDirection, 94 XawTextBlock*); 95 static void SetSelection(Widget, XawTextPosition, XawTextPosition, Atom); 96 static void XawTextSrcClassInitialize(void); 97 static void XawTextSrcClassPartInitialize(WidgetClass); 98 static void XawTextSrcInitialize(Widget, Widget, ArgList, Cardinal*); 99 static void XawTextSrcDestroy(Widget); 100 static Boolean XawTextSrcSetValues(Widget, Widget, Widget, ArgList, Cardinal*); 101 /* 102 * Prototypes 103 */ 104 static void CvtStringToEditMode(XrmValuePtr, Cardinal*, 105 XrmValuePtr, XrmValuePtr); 106 static Boolean CvtEditModeToString(Display*, XrmValuePtr, Cardinal*, 107 XrmValuePtr, XrmValuePtr, XtPointer*); 108 #ifndef OLDXAW 109 static void FreeUndoBuffer(XawTextUndo*); 110 static void UndoGC(XawTextUndo*); 111 static void TellSourceChanged(TextSrcObject, XawTextPosition, XawTextPosition, 112 XawTextBlock*, int); 113 Bool _XawTextSrcUndo(TextSrcObject, XawTextPosition*); 114 Bool _XawTextSrcToggleUndo(TextSrcObject); 115 XawTextAnchor *_XawTextSourceFindAnchor(Widget, XawTextPosition); 116 117 /* 118 * External 119 */ 120 void _XawSourceAddText(Widget, Widget); 121 void _XawSourceRemoveText(Widget, Widget, Bool); 122 Bool _XawTextSourceNewLineAtEOF(Widget); 123 void _XawSourceSetUndoErase(TextSrcObject, int); 124 void _XawSourceSetUndoMerge(TextSrcObject, Bool); 125 #endif /* OLDXAW */ 126 127 /* 128 * Defined in Text.c 129 */ 130 char *_XawTextGetText(TextWidget, XawTextPosition, XawTextPosition); 131 void _XawTextSourceChanged(Widget, XawTextPosition, XawTextPosition, 132 XawTextBlock*, int); 133 134 /* 135 * Initialization 136 */ 137 #define offset(field) XtOffsetOf(TextSrcRec, textSrc.field) 138 static XtResource resources[] = { 139 { 140 XtNeditType, 141 XtCEditType, 142 XtREditMode, 143 sizeof(XawTextEditType), 144 offset(edit_mode), 145 XtRString, 146 (XtPointer)"read" 147 }, 148 #ifndef OLDXAW 149 { 150 XtNcallback, 151 XtCCallback, 152 XtRCallback, 153 sizeof(XtPointer), 154 offset(callback), 155 XtRCallback, 156 NULL 157 }, 158 { 159 XtNsourceChanged, 160 XtCChanged, 161 XtRBoolean, 162 sizeof(Boolean), 163 offset(changed), 164 XtRImmediate, 165 (XtPointer)False 166 }, 167 { 168 XtNenableUndo, 169 XtCUndo, 170 XtRBoolean, 171 sizeof(Boolean), 172 offset(enable_undo), 173 XtRImmediate, 174 (XtPointer)False 175 }, 176 { 177 XtNpropertyCallback, 178 XtCCallback, 179 XtRCallback, 180 sizeof(XtPointer), 181 offset(property_callback), 182 XtRCallback, 183 NULL 184 }, 185 #endif /* OLDXAW */ 186 }; 187 #undef offset 188 189 #define Superclass (&objectClassRec) 190 TextSrcClassRec textSrcClassRec = { 191 /* object */ 192 { 193 (WidgetClass)Superclass, /* superclass */ 194 "TextSrc", /* class_name */ 195 sizeof(TextSrcRec), /* widget_size */ 196 XawTextSrcClassInitialize, /* class_initialize */ 197 XawTextSrcClassPartInitialize, /* class_part_initialize */ 198 False, /* class_inited */ 199 XawTextSrcInitialize, /* initialize */ 200 NULL, /* initialize_hook */ 201 NULL, /* realize */ 202 NULL, /* actions */ 203 0, /* num_actions */ 204 resources, /* resources */ 205 XtNumber(resources), /* num_resources */ 206 NULLQUARK, /* xrm_class */ 207 False, /* compress_motion */ 208 False, /* compress_exposure */ 209 False, /* compress_enterleave */ 210 False, /* visible_interest */ 211 XawTextSrcDestroy, /* destroy */ 212 NULL, /* resize */ 213 NULL, /* expose */ 214 XawTextSrcSetValues, /* set_values */ 215 NULL, /* set_values_hook */ 216 NULL, /* set_values_almost */ 217 NULL, /* get_values_hook */ 218 NULL, /* accept_focus */ 219 XtVersion, /* version */ 220 NULL, /* callback_private */ 221 NULL, /* tm_table */ 222 NULL, /* query_geometry */ 223 NULL, /* display_accelerator */ 224 NULL, /* extension */ 225 }, 226 /* text_src */ 227 { 228 Read, /* Read */ 229 Replace, /* Replace */ 230 Scan, /* Scan */ 231 Search, /* Search */ 232 SetSelection, /* SetSelection */ 233 ConvertSelection, /* ConvertSelection */ 234 #ifndef OLDXAW 235 NULL, /* extension */ 236 #endif 237 }, 238 }; 239 240 WidgetClass textSrcObjectClass = (WidgetClass)&textSrcClassRec; 241 242 static XrmQuark QRead, QAppend, QEdit; 243 #ifndef OLDXAW 244 static char *SrcNL = (char*)"\n"; 245 static wchar_t SrcWNL[2]; 246 #endif 247 248 /* 249 * Implementation 250 */ 251 static void 252 XawTextSrcClassInitialize(void) 253 { 254 XawInitializeWidgetSet(); 255 256 #ifndef OLDXAW 257 SrcWNL[0] = _Xaw_atowc(XawLF); 258 SrcWNL[1] = 0; 259 #endif 260 QRead = XrmPermStringToQuark(XtEtextRead); 261 QAppend = XrmPermStringToQuark(XtEtextAppend); 262 QEdit = XrmPermStringToQuark(XtEtextEdit); 263 XtAddConverter(XtRString, XtREditMode, CvtStringToEditMode, NULL, 0); 264 XtSetTypeConverter(XtREditMode, XtRString, CvtEditModeToString, NULL, 0, 265 XtCacheNone, NULL); 266 } 267 268 static void 269 XawTextSrcClassPartInitialize(WidgetClass wc) 270 { 271 TextSrcObjectClass t_src, superC; 272 273 t_src = (TextSrcObjectClass)wc; 274 superC = (TextSrcObjectClass)t_src->object_class.superclass; 275 276 /* 277 * We don't need to check for null super since we'll get to TextSrc 278 * eventually 279 */ 280 if (t_src->textSrc_class.Read == XtInheritRead) 281 t_src->textSrc_class.Read = superC->textSrc_class.Read; 282 283 if (t_src->textSrc_class.Replace == XtInheritReplace) 284 t_src->textSrc_class.Replace = superC->textSrc_class.Replace; 285 286 if (t_src->textSrc_class.Scan == XtInheritScan) 287 t_src->textSrc_class.Scan = superC->textSrc_class.Scan; 288 289 if (t_src->textSrc_class.Search == XtInheritSearch) 290 t_src->textSrc_class.Search = superC->textSrc_class.Search; 291 292 if (t_src->textSrc_class.SetSelection == XtInheritSetSelection) 293 t_src->textSrc_class.SetSelection = superC->textSrc_class.SetSelection; 294 295 if (t_src->textSrc_class.ConvertSelection == XtInheritConvertSelection) 296 t_src->textSrc_class.ConvertSelection = 297 superC->textSrc_class.ConvertSelection; 298 } 299 300 /*ARGSUSED*/ 301 static void 302 XawTextSrcInitialize(Widget request _X_UNUSED, Widget cnew _X_UNUSED, 303 ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED) 304 { 305 #ifndef OLDXAW 306 TextSrcObject src = (TextSrcObject)cnew; 307 308 if (src->textSrc.enable_undo) { 309 src->textSrc.undo = (XawTextUndo*)XtCalloc(1, sizeof(XawTextUndo)); 310 src->textSrc.undo->dir = XawsdLeft; 311 } 312 else 313 src->textSrc.undo = NULL; 314 src->textSrc.undo_state = False; 315 if (XtIsSubclass(XtParent(cnew), textWidgetClass)) { 316 src->textSrc.text = (WidgetList)XtMalloc(sizeof(Widget*)); 317 src->textSrc.text[0] = XtParent(cnew); 318 src->textSrc.num_text = 1; 319 } 320 else { 321 src->textSrc.text = NULL; 322 src->textSrc.num_text = 0; 323 } 324 325 src->textSrc.anchors = NULL; 326 src->textSrc.num_anchors = 0; 327 (void)XawTextSourceAddAnchor(cnew, 0); 328 #endif /* OLDXAW */ 329 } 330 331 static void 332 XawTextSrcDestroy(Widget w _X_UNUSED) 333 { 334 #ifndef OLDXAW 335 TextSrcObject src = (TextSrcObject)w; 336 337 if (src->textSrc.enable_undo) { 338 FreeUndoBuffer(src->textSrc.undo); 339 XtFree((char*)src->textSrc.undo); 340 } 341 XtFree((char*)src->textSrc.text); 342 343 if (src->textSrc.num_anchors) { 344 XawTextEntity *entity, *enext; 345 int i; 346 347 for (i = 0; i < src->textSrc.num_anchors; i++) { 348 entity = src->textSrc.anchors[i]->entities; 349 while (entity) { 350 enext = entity->next; 351 XtFree((XtPointer)entity); 352 entity = enext; 353 } 354 XtFree((XtPointer)src->textSrc.anchors[i]); 355 } 356 XtFree((XtPointer)src->textSrc.anchors); 357 } 358 #endif /* OLDXAW */ 359 } 360 361 /*ARGSUSED*/ 362 static Boolean 363 XawTextSrcSetValues(Widget current _X_UNUSED, Widget request _X_UNUSED, Widget cnew _X_UNUSED, 364 ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED) 365 { 366 #ifndef OLDXAW 367 TextSrcObject oldtw = (TextSrcObject)current; 368 TextSrcObject newtw = (TextSrcObject)cnew; 369 370 if (oldtw->textSrc.enable_undo != newtw->textSrc.enable_undo) { 371 if (newtw->textSrc.enable_undo) { 372 newtw->textSrc.undo = (XawTextUndo*) 373 XtCalloc(1, sizeof(XawTextUndo)); 374 newtw->textSrc.undo->dir = XawsdLeft; 375 } 376 else { 377 FreeUndoBuffer(newtw->textSrc.undo); 378 XtFree((char*)newtw->textSrc.undo); 379 newtw->textSrc.undo = NULL; 380 } 381 } 382 if (oldtw->textSrc.changed != newtw->textSrc.changed) { 383 if (newtw->textSrc.enable_undo) { 384 if (newtw->textSrc.undo->list) { 385 newtw->textSrc.undo->l_no_change = 386 newtw->textSrc.undo->list->left; 387 newtw->textSrc.undo->r_no_change = 388 newtw->textSrc.undo->list->right; 389 } 390 else 391 newtw->textSrc.undo->l_no_change = 392 newtw->textSrc.undo->r_no_change = NULL; 393 } 394 } 395 #endif /* OLDXAW */ 396 return (False); 397 } 398 399 /* 400 * Function: 401 * Read 402 * 403 * Parameters: 404 * w - TextSrc Object 405 * pos - position of the text to retrieve 406 * text - text block that will contain returned text 407 * length - maximum number of characters to read 408 * 409 * Description: 410 * This function reads the source. 411 * 412 * Returns: 413 * The character position following the retrieved text. 414 */ 415 /*ARGSUSED*/ 416 static XawTextPosition 417 Read(Widget w _X_UNUSED, XawTextPosition pos _X_UNUSED, XawTextBlock *text _X_UNUSED, int length _X_UNUSED) 418 { 419 return ((XawTextPosition)0); 420 } 421 422 /* 423 * Function: 424 * Replace 425 * 426 * Parameters: 427 * src - Text Source Object 428 * startPos - ends of text that will be removed 429 * endPos - "" 430 * text - new text to be inserted into buffer at startPos 431 * 432 * Description: 433 * Replaces a block of text with new text. 434 */ 435 /*ARGSUSED*/ 436 static int 437 Replace(Widget w _X_UNUSED, XawTextPosition startPos _X_UNUSED, XawTextPosition endPos _X_UNUSED, 438 XawTextBlock *text _X_UNUSED) 439 { 440 return (XawEditError); 441 } 442 443 /* 444 * Function: 445 * Scan 446 * 447 * Parameters: 448 * w - TextSrc Object 449 * position - position to start scanning 450 * type - type of thing to scan for 451 * dir - direction to scan 452 * count - which occurrence 0f this thing to search for 453 * include - whether or not to include the character found in 454 * the position that is returned 455 * 456 * Description: 457 * Scans the text source for the number and type of item specified. 458 */ 459 /*ARGSUSED*/ 460 static XawTextPosition 461 Scan(Widget w _X_UNUSED, XawTextPosition position _X_UNUSED, XawTextScanType type _X_UNUSED, 462 XawTextScanDirection dir _X_UNUSED, int count _X_UNUSED, Bool include _X_UNUSED) 463 { 464 return ((XawTextPosition)0); 465 } 466 467 /* 468 * Function: 469 * Search 470 * 471 * Parameters: 472 * w - TextSource Object 473 * position - position to start searching 474 * dir - direction to search 475 * text - the text block to search for 476 * 477 * Description: 478 * Searches the text source for the text block passed 479 */ 480 /*ARGSUSED*/ 481 static XawTextPosition 482 Search(Widget w _X_UNUSED, XawTextPosition position _X_UNUSED, XawTextScanDirection dir _X_UNUSED, 483 XawTextBlock *text _X_UNUSED) 484 { 485 return (XawTextSearchError); 486 } 487 488 /*ARGSUSED*/ 489 static Boolean 490 ConvertSelection(Widget w _X_UNUSED, Atom *selection _X_UNUSED, Atom *target _X_UNUSED, Atom *type _X_UNUSED, 491 XtPointer *value _X_UNUSED, unsigned long *length _X_UNUSED, int *format _X_UNUSED) 492 { 493 return (False); 494 } 495 496 /*ARGSUSED*/ 497 static void 498 SetSelection(Widget w _X_UNUSED, XawTextPosition left _X_UNUSED, XawTextPosition right _X_UNUSED, 499 Atom selection _X_UNUSED) 500 { 501 } 502 503 /*ARGSUSED*/ 504 static void 505 CvtStringToEditMode(XrmValuePtr args _X_UNUSED, Cardinal *num_args _X_UNUSED, 506 XrmValuePtr fromVal, XrmValuePtr toVal) 507 { 508 static XawTextEditType editType; 509 XrmQuark q; 510 char name[7]; 511 512 XmuNCopyISOLatin1Lowered(name, (char *)fromVal->addr, sizeof(name)); 513 q = XrmStringToQuark(name); 514 515 if (q == QRead) 516 editType = XawtextRead; 517 else if (q == QAppend) 518 editType = XawtextAppend; 519 else if (q == QEdit) 520 editType = XawtextEdit; 521 else { 522 toVal->size = 0; 523 toVal->addr = NULL; 524 XtStringConversionWarning((char *)fromVal->addr, XtREditMode); 525 } 526 toVal->size = sizeof(XawTextEditType); 527 toVal->addr = (XPointer)&editType; 528 } 529 530 /*ARGSUSED*/ 531 static Boolean 532 CvtEditModeToString(Display *dpy, XrmValuePtr args _X_UNUSED, Cardinal *num_args _X_UNUSED, 533 XrmValuePtr fromVal, XrmValuePtr toVal, 534 XtPointer *data _X_UNUSED) 535 { 536 static String buffer; 537 Cardinal size; 538 539 switch (*(XawTextEditType *)fromVal->addr) { 540 case XawtextRead: 541 buffer = XtEtextRead; 542 break; 543 case XawtextAppend: 544 buffer = XtEtextAppend; 545 break; 546 case XawtextEdit: 547 buffer = XtEtextEdit; 548 break; 549 default: 550 XawTypeToStringWarning(dpy, XtREditMode); 551 toVal->addr = NULL; 552 toVal->size = 0; 553 return (False); 554 } 555 556 size = (Cardinal)(strlen(buffer) + 1); 557 if (toVal->addr != NULL) { 558 if (toVal->size < size) { 559 toVal->size = size; 560 return (False); 561 } 562 strcpy((char *)toVal->addr, buffer); 563 } 564 else 565 toVal->addr = (XPointer)buffer; 566 toVal->size = sizeof(String); 567 568 return (True); 569 } 570 571 #ifndef OLDXAW 572 Bool 573 _XawTextSourceNewLineAtEOF(Widget w) 574 { 575 TextSrcObject src = (TextSrcObject)w; 576 XawTextBlock text; 577 578 text.firstPos = 0; 579 if ((text.format = (unsigned long)src->textSrc.text_format) == XawFmt8Bit) 580 text.ptr = SrcNL; 581 else 582 text.ptr = (char*)SrcWNL; 583 text.length = 1; 584 585 return (XawTextSourceSearch(w, XawTextSourceScan(w, 0, XawstAll, 586 XawsdRight, 1, True) - 1, 587 XawsdRight, &text) != XawTextSearchError); 588 } 589 590 void 591 _XawSourceAddText(Widget source, Widget text) 592 { 593 TextSrcObject src = (TextSrcObject)source; 594 Bool found = False; 595 Cardinal i; 596 597 for (i = 0; i < src->textSrc.num_text; i++) 598 if (src->textSrc.text[i] == text) { 599 found = True; 600 break; 601 } 602 603 if (!found) { 604 src->textSrc.text = (WidgetList) 605 XtRealloc((char*)src->textSrc.text, 606 (Cardinal)(sizeof(Widget) * (src->textSrc.num_text + 1))); 607 src->textSrc.text[src->textSrc.num_text++] = text; 608 } 609 } 610 611 void 612 _XawSourceRemoveText(Widget source, Widget text, Bool destroy) 613 { 614 TextSrcObject src = (TextSrcObject)source; 615 Bool found = False; 616 Cardinal i; 617 618 if (src == NULL) 619 return; 620 621 for (i = 0; i < src->textSrc.num_text; i++) 622 if (src->textSrc.text[i] == text) { 623 found = True; 624 break; 625 } 626 627 if (found) { 628 if (--src->textSrc.num_text == 0) { 629 if (destroy) { 630 XtDestroyWidget(source); 631 return; 632 } 633 else { 634 XtFree((char*)src->textSrc.text); 635 src->textSrc.text = NULL; /* for realloc "magic" */ 636 } 637 } 638 else if (i < src->textSrc.num_text) 639 memmove(&src->textSrc.text[i], &src->textSrc.text[i + 1], 640 sizeof(Widget) * (src->textSrc.num_text - i)); 641 } 642 } 643 #endif /* OLDXAW */ 644 645 /* 646 * Function: 647 * XawTextSourceRead 648 * 649 * Parameters: 650 * w - TextSrc Object 651 * pos - position of the text to retrieve 652 * text - text block that will contain returned text (return) 653 * length - maximum number of characters to read 654 * 655 * Description: 656 * This function reads the source. 657 * 658 * Returns: 659 * The number of characters read into the buffer 660 */ 661 XawTextPosition 662 XawTextSourceRead(Widget w, XawTextPosition pos, XawTextBlock *text, 663 int length) 664 { 665 TextSrcObjectClass cclass = (TextSrcObjectClass)w->core.widget_class; 666 667 return ((*cclass->textSrc_class.Read)(w, pos, text, length)); 668 } 669 670 #ifndef OLDXAW 671 static void 672 TellSourceChanged(TextSrcObject src, XawTextPosition left, 673 XawTextPosition right, XawTextBlock *block, int lines) 674 { 675 Cardinal i; 676 677 for (i = 0; i < src->textSrc.num_text; i++) 678 _XawTextSourceChanged(src->textSrc.text[i], left, right, block, lines); 679 } 680 681 /* 682 * This function is required because there is no way to diferentiate 683 * if the first erase was generated by a backward-kill-char and the 684 * second by a forward-kill-char (or vice-versa) from XawTextSourceReplace. 685 * It is only possible to diferentiate after the second character is 686 * killed, but then, it is too late. 687 */ 688 void 689 _XawSourceSetUndoErase(TextSrcObject src, int value) 690 { 691 if (src && src->textSrc.enable_undo) 692 src->textSrc.undo->erase = value; 693 } 694 695 /* 696 * To differentiate insert-char's separated by cursor movements. 697 */ 698 void 699 _XawSourceSetUndoMerge(TextSrcObject src, Bool state) 700 { 701 if (src && src->textSrc.enable_undo) 702 src->textSrc.undo->merge += state ? 1 : -1; 703 } 704 #endif /* OLDXAW */ 705 706 /* 707 * Public Functions 708 */ 709 /* 710 * Function: 711 * XawTextSourceReplace 712 * 713 * Parameters: 714 * src - Text Source Object 715 * startPos - ends of text that will be removed 716 * endPos - "" 717 * text - new text to be inserted into buffer at startPos 718 * 719 * Description: 720 * Replaces a block of text with new text. 721 * 722 * Returns: 723 * XawEditError or XawEditDone. 724 */ 725 /*ARGSUSED*/ 726 int 727 XawTextSourceReplace(Widget w, XawTextPosition left, 728 XawTextPosition right, XawTextBlock *block) 729 { 730 TextSrcObjectClass cclass = (TextSrcObjectClass)w->core.widget_class; 731 #ifndef OLDXAW 732 TextSrcObject src = (TextSrcObject)w; 733 XawTextUndoBuffer *l_state, *r_state; 734 XawTextUndoList *undo; 735 Bool enable_undo; 736 XawTextPosition start, end; 737 int i, error, lines = 0; 738 Cardinal j; 739 740 if (src->textSrc.edit_mode == XawtextRead) 741 return (XawEditError); 742 743 enable_undo = src->textSrc.enable_undo && src->textSrc.undo_state == False; 744 if (enable_undo) { 745 unsigned size, total; 746 747 if (src->textSrc.undo->l_save) { 748 l_state = src->textSrc.undo->l_save; 749 src->textSrc.undo->l_save = NULL; 750 } 751 else 752 l_state = XtNew(XawTextUndoBuffer); 753 l_state->refcount = 1; 754 l_state->position = left; 755 if (left < right) { 756 Widget ctx = NULL; 757 758 for (j = 0; j < src->textSrc.num_text; j++) 759 if (XtIsSubclass(src->textSrc.text[j], textWidgetClass)) { 760 ctx = src->textSrc.text[j]; 761 break; 762 } 763 l_state->buffer = _XawTextGetText((TextWidget)ctx, left, right); 764 l_state->length = (unsigned)(right - left); 765 } 766 else { 767 l_state->length = 0; 768 l_state->buffer = NULL; 769 } 770 l_state->format = (unsigned long)src->textSrc.text_format; 771 if (l_state->length == 1) { 772 if (l_state->format == XawFmtWide && 773 *(wchar_t*)l_state->buffer == *SrcWNL) { 774 XtFree(l_state->buffer); 775 l_state->buffer = (char*)SrcWNL; 776 } 777 else if (*l_state->buffer == '\n') { 778 XtFree(l_state->buffer); 779 l_state->buffer = SrcNL; 780 } 781 } 782 783 if (src->textSrc.undo->r_save) { 784 r_state = src->textSrc.undo->r_save; 785 src->textSrc.undo->r_save = NULL; 786 } 787 else 788 r_state = XtNew(XawTextUndoBuffer); 789 r_state->refcount = 1; 790 r_state->position = left; 791 r_state->format = block->format; 792 size = block->format == XawFmtWide ? sizeof(wchar_t) : sizeof(char); 793 total = (size * (unsigned)block->length); 794 r_state->length = (unsigned)block->length; 795 r_state->buffer = NULL; 796 if (total == size) { 797 if (r_state->format == XawFmtWide && 798 *(wchar_t*)block->ptr == *SrcWNL) 799 r_state->buffer = (char*)SrcWNL; 800 else if (*block->ptr == '\n') 801 r_state->buffer = SrcNL; 802 } 803 if (total && !r_state->buffer) { 804 r_state->buffer = XtMalloc(total); 805 memcpy(r_state->buffer, block->ptr, total); 806 } 807 808 if (src->textSrc.undo->u_save) { 809 undo = src->textSrc.undo->u_save; 810 src->textSrc.undo->u_save = NULL; 811 } 812 else 813 undo = XtNew(XawTextUndoList); 814 undo->left = l_state; 815 undo->right = r_state; 816 undo->undo = src->textSrc.undo->list; 817 undo->redo = NULL; 818 } 819 else { 820 undo = NULL; 821 l_state = r_state = NULL; 822 } 823 824 #define LARGE_VALUE 262144 /* 256 K */ 825 /* optimization, to avoid long delays recalculating the line number 826 * when editing huge files 827 */ 828 if (left > LARGE_VALUE) { 829 start = XawTextSourceScan(w, left, XawstEOL, XawsdLeft, 2, False); 830 for (j = 0; j < src->textSrc.num_text; j++) { 831 TextWidget tw = (TextWidget)src->textSrc.text[j]; 832 833 if (left <= tw->text.lt.top && 834 left + block->length - (right - left) > tw->text.lt.top) 835 _XawTextBuildLineTable(tw, start, False); 836 } 837 } 838 #undef LARGE_VALUE 839 840 start = left; 841 end = right; 842 while (start < end) { 843 start = XawTextSourceScan(w, start, XawstEOL, XawsdRight, 1, True); 844 if (start <= end) { 845 --lines; 846 if (start == XawTextSourceScan(w, 0, XawstAll, XawsdRight, 1, True)) { 847 lines += !_XawTextSourceNewLineAtEOF(w); 848 break; 849 } 850 } 851 } 852 #else 853 int error; 854 #endif /* OLDXAW */ 855 856 error = (*cclass->textSrc_class.Replace)(w, left, right, block); 857 858 #ifndef OLDXAW 859 if (error != XawEditDone) { 860 if (enable_undo) { 861 if (l_state->buffer) { 862 if (l_state->buffer != SrcNL && l_state->buffer != (char*)SrcWNL) 863 XtFree(l_state->buffer); 864 l_state->buffer = NULL; 865 } 866 src->textSrc.undo->l_save = l_state; 867 if (r_state->buffer) { 868 if (r_state->buffer != SrcNL && r_state->buffer != (char*)SrcWNL) 869 XtFree(r_state->buffer); 870 r_state->buffer = NULL; 871 } 872 src->textSrc.undo->r_save = r_state; 873 874 src->textSrc.undo->u_save = undo; 875 } 876 } 877 else if (enable_undo) { 878 XawTextUndoList *list = src->textSrc.undo->list; 879 XawTextUndoBuffer *unl, *lnl; 880 int erase = undo->right->length == 0 && undo->left->length == 1 && list 881 && list->right->length == 0; 882 883 if (erase) { 884 erase = list->left->position - 1 == undo->left->position ? -1 : 885 list->left->position == undo->left->position ? 1 : 0; 886 if (src->textSrc.undo->erase && erase != src->textSrc.undo->erase) 887 erase = 0; 888 else 889 src->textSrc.undo->erase = erase; 890 } 891 892 if (erase) { 893 unl = l_state; 894 lnl = list->left; 895 } 896 else { 897 unl = r_state; 898 lnl = list ? list->right : NULL; 899 } 900 901 /* Try to merge the undo buffers */ 902 if (src->textSrc.undo->merge > 0 && ((erase || 903 (list && ((list->left->length == 0 && undo->left->length == 0) || 904 (list->left->length == list->right->length && 905 undo->left->length == 1)) && 906 undo->right->length == 1 && 907 list->right->position + list->right->length 908 == undo->right->position)) 909 && src->textSrc.undo->pointer == list 910 && unl->format == list->right->format 911 && ((unl->format == XawFmt8Bit && unl->buffer[0] != XawLF) || 912 (unl->format == XawFmtWide && 913 *(wchar_t*)(unl->buffer) != _Xaw_atowc(XawLF))) 914 && ((lnl->format == XawFmt8Bit && lnl->buffer[0] != XawLF) || 915 (lnl->format == XawFmtWide && 916 *(wchar_t*)(lnl->buffer) != _Xaw_atowc(XawLF))))) { 917 unsigned size = lnl->format == XawFmtWide ? 918 sizeof(wchar_t) : sizeof(char); 919 920 if (!erase) { 921 list->right->buffer = XtRealloc(list->right->buffer, 922 (list->right->length + 1) * size); 923 memcpy(list->right->buffer + list->right->length * size, 924 undo->right->buffer, size); 925 ++list->right->length; 926 XtFree(r_state->buffer); 927 } 928 else if (erase < 0) { 929 --list->left->position; 930 --list->right->position; 931 } 932 933 src->textSrc.undo->l_save = l_state; 934 src->textSrc.undo->r_save = r_state; 935 src->textSrc.undo->u_save = undo; 936 937 if (list->left->length) { 938 list->left->buffer = XtRealloc(list->left->buffer, 939 (list->left->length + 1) * size); 940 if (erase >= 0) 941 memcpy(list->left->buffer + list->left->length * size, 942 undo->left->buffer, size); 943 else { 944 /* use memmove, since strings overlap */ 945 memmove(list->left->buffer + size, list->left->buffer, 946 list->left->length * size); 947 memcpy(list->left->buffer, undo->left->buffer, size); 948 } 949 ++list->left->length; 950 if (l_state->buffer != SrcNL && l_state->buffer != (char*)SrcWNL) 951 XtFree(l_state->buffer); 952 } 953 954 if (src->textSrc.undo->num_list >= UNDO_DEPTH) 955 UndoGC(src->textSrc.undo); 956 } 957 else { 958 src->textSrc.undo->undo = (XawTextUndoBuffer**) 959 XtRealloc((char*)src->textSrc.undo->undo, 960 (Cardinal)((2 + src->textSrc.undo->num_undo) 961 * sizeof(XawTextUndoBuffer))); 962 src->textSrc.undo->undo[src->textSrc.undo->num_undo++] = l_state; 963 src->textSrc.undo->undo[src->textSrc.undo->num_undo++] = r_state; 964 965 if (src->textSrc.undo->list) 966 src->textSrc.undo->list->redo = undo; 967 else 968 src->textSrc.undo->head = undo; 969 970 src->textSrc.undo->merge = l_state->length <= 1 && 971 r_state->length <= 1; 972 973 src->textSrc.undo->list = src->textSrc.undo->pointer = 974 src->textSrc.undo->end_mark = undo; 975 976 if (++src->textSrc.undo->num_list >= UNDO_DEPTH) 977 UndoGC(src->textSrc.undo); 978 } 979 src->textSrc.undo->dir = XawsdLeft; 980 if (!src->textSrc.changed) { 981 src->textSrc.undo->l_no_change = src->textSrc.undo->list->right; 982 src->textSrc.undo->r_no_change = src->textSrc.undo->list->left; 983 src->textSrc.changed = True; 984 } 985 } 986 else if (!src->textSrc.enable_undo) 987 src->textSrc.changed = True; 988 989 if (error == XawEditDone) { 990 XawTextAnchor *anchor; 991 992 /* find anchor and index */ 993 /* XXX index (i) could be returned by XawTextSourceFindAnchor 994 * or similar function, to speed up */ 995 if ((anchor = XawTextSourceFindAnchor(w, left))) { 996 XawTextEntity *eprev, *entity, *enext; 997 XawTextPosition offset = 0, diff = block->length - (right - left); 998 999 for (i = 0; i < src->textSrc.num_anchors; i++) 1000 if (src->textSrc.anchors[i] == anchor) 1001 break; 1002 if (anchor->cache && anchor->position + anchor->cache->offset + 1003 anchor->cache->length <= left) 1004 eprev = entity = anchor->cache; 1005 else 1006 eprev = entity = anchor->entities; 1007 while (entity) { 1008 offset = anchor->position + entity->offset; 1009 1010 if (offset > left) 1011 break; 1012 if (offset + entity->length > left) 1013 break; 1014 1015 eprev = entity; 1016 entity = entity->next; 1017 } 1018 1019 /* try to do the right thing here (and most likely correct), but 1020 * other code needs to check what was done */ 1021 1022 /* adjust entity length */ 1023 if (entity && offset <= left) { 1024 if (offset + entity->length < right) 1025 entity->length = (Cardinal)(left - offset + block->length); 1026 else 1027 entity->length = (Cardinal)(entity->length + diff); 1028 1029 if (entity->length == 0) { 1030 enext = entity->next; 1031 eprev->next = enext; 1032 anchor->cache = NULL; 1033 XtFree((XtPointer)entity); 1034 if (entity == anchor->entities) { 1035 if ((anchor->entities = enext) == NULL) { 1036 eprev = NULL; 1037 anchor = XawTextSourceRemoveAnchor(w, anchor); 1038 entity = anchor ? anchor->entities : NULL; 1039 } 1040 else 1041 eprev = entity = enext; 1042 } 1043 else 1044 entity = enext; 1045 } 1046 else { 1047 eprev = entity; 1048 entity = entity->next; 1049 } 1050 } 1051 1052 while (anchor) { 1053 while (entity) { 1054 offset = anchor->position + entity->offset + entity->length; 1055 1056 if (offset > right) { 1057 entity->length = (Cardinal) (XawMin(entity->length, offset - right)); 1058 goto exit_anchor_loop; 1059 } 1060 1061 enext = entity->next; 1062 if (eprev) 1063 eprev->next = enext; 1064 XtFree((XtPointer)entity); 1065 anchor->cache = NULL; 1066 if (entity == anchor->entities) { 1067 eprev = NULL; 1068 if ((anchor->entities = enext) == NULL) { 1069 if (i == 0) 1070 ++i; 1071 else if (i < --src->textSrc.num_anchors) { 1072 memmove(&src->textSrc.anchors[i], 1073 &src->textSrc.anchors[i + 1], 1074 (size_t)(src->textSrc.num_anchors - i) * 1075 sizeof(XawTextAnchor*)); 1076 XtFree((XtPointer)anchor); 1077 } 1078 if (i >= src->textSrc.num_anchors) { 1079 anchor = NULL; 1080 entity = NULL; 1081 break; 1082 } 1083 anchor = src->textSrc.anchors[i]; 1084 entity = anchor->entities; 1085 continue; 1086 } 1087 } 1088 entity = enext; 1089 } 1090 if (i + 1 < src->textSrc.num_anchors) { 1091 anchor = src->textSrc.anchors[++i]; 1092 entity = anchor->entities; 1093 eprev = NULL; 1094 } 1095 else { 1096 anchor = NULL; 1097 break; 1098 } 1099 eprev = NULL; 1100 } 1101 1102 exit_anchor_loop: 1103 if (anchor) { 1104 XawTextAnchor *aprev; 1105 1106 if (anchor->position >= XawMax(right, left + block->length)) 1107 anchor->position += diff; 1108 else if (anchor->position > left && 1109 (aprev = XawTextSourcePrevAnchor(w, anchor))) { 1110 XawTextPosition tmp = anchor->position - aprev->position; 1111 1112 if (diff) { 1113 while (entity) { 1114 entity->offset += diff; 1115 entity = entity->next; 1116 } 1117 } 1118 entity = anchor->entities; 1119 while (entity) { 1120 entity->offset += tmp; 1121 entity = entity->next; 1122 } 1123 if ((entity = aprev->entities) == NULL) 1124 aprev->entities = anchor->entities; 1125 else { 1126 while (entity->next) 1127 entity = entity->next; 1128 entity->next = anchor->entities; 1129 } 1130 anchor->entities = NULL; 1131 (void)XawTextSourceRemoveAnchor(w, anchor); 1132 --i; 1133 } 1134 else if (diff) { 1135 while (entity) { 1136 entity->offset += diff; 1137 entity = entity->next; 1138 } 1139 } 1140 } 1141 1142 if (diff) { 1143 /* The first anchor is never removed, and should 1144 * have position 0. 1145 * i should be -1 if attempted to removed the first 1146 * anchor, what can be caused when removing a chunk 1147 * of text of the first entity. 1148 * */ 1149 if (++i == 0) { 1150 anchor = src->textSrc.anchors[0]; 1151 eprev = entity = anchor->entities; 1152 while (entity) { 1153 enext = entity->next; 1154 if (entity->offset + entity->length <= -diff) 1155 XtFree((XtPointer)entity); 1156 else 1157 break; 1158 entity = enext; 1159 } 1160 if (eprev != entity) { 1161 anchor->cache = NULL; 1162 if ((anchor->entities = entity) != NULL) { 1163 if ((entity->offset += diff) < 0) { 1164 entity->length = (Cardinal)(entity->length + entity->offset); 1165 entity->offset = 0; 1166 } 1167 } 1168 } 1169 ++i; 1170 } 1171 for (; i < src->textSrc.num_anchors; i++) 1172 src->textSrc.anchors[i]->position += diff; 1173 } 1174 } 1175 1176 start = left; 1177 end = start + block->length; 1178 while (start < end) { 1179 start = XawTextSourceScan(w, start, XawstEOL, XawsdRight, 1, True); 1180 if (start <= end) { 1181 ++lines; 1182 if (start == XawTextSourceScan(w, 0, XawstAll, XawsdRight, 1, True)) { 1183 lines -= !_XawTextSourceNewLineAtEOF(w); 1184 break; 1185 } 1186 } 1187 } 1188 1189 { 1190 XawTextPropertyInfo info = { 1191 .left = left, 1192 .right = right, 1193 .block = block 1194 }; 1195 1196 XtCallCallbacks(w, XtNpropertyCallback, &info); 1197 } 1198 1199 TellSourceChanged(src, left, right, block, lines); 1200 /* Call callbacks, we have changed the buffer */ 1201 XtCallCallbacks(w, XtNcallback, 1202 (XtPointer)((long)src->textSrc.changed)); 1203 } 1204 1205 #endif /* OLDXAW */ 1206 return (error); 1207 } 1208 1209 #ifndef OLDXAW 1210 Bool 1211 _XawTextSrcUndo(TextSrcObject src, XawTextPosition *insert_pos) 1212 { 1213 static wchar_t wnull = 0; 1214 XawTextBlock block; 1215 XawTextUndoList *list, *nlist; 1216 XawTextUndoBuffer *l_state, *r_state; 1217 Boolean changed = src->textSrc.changed; 1218 1219 if (!src->textSrc.enable_undo || !src->textSrc.undo->num_undo) 1220 return (False); 1221 1222 list = src->textSrc.undo->pointer; 1223 1224 if (src->textSrc.undo->dir == XawsdLeft) { 1225 l_state = list->right; 1226 r_state = list->left; 1227 } 1228 else { 1229 l_state = list->left; 1230 r_state = list->right; 1231 } 1232 1233 if (src->textSrc.undo->l_no_change == l_state 1234 && src->textSrc.undo->r_no_change == r_state) 1235 src->textSrc.changed = False; 1236 else 1237 src->textSrc.changed = True; 1238 1239 block.firstPos = 0; 1240 block.length = (int)r_state->length; 1241 block.ptr = r_state->buffer ? r_state->buffer : (char*)&wnull; 1242 block.format = r_state->format; 1243 1244 src->textSrc.undo_state = True; 1245 if (XawTextSourceReplace((Widget)src, l_state->position, l_state->position 1246 + l_state->length, &block) != XawEditDone) { 1247 src->textSrc.undo_state = False; 1248 src->textSrc.changed = changed; 1249 return (False); 1250 } 1251 src->textSrc.undo_state = False; 1252 1253 ++l_state->refcount; 1254 ++r_state->refcount; 1255 nlist = XtNew(XawTextUndoList); 1256 nlist->left = l_state; 1257 nlist->right = r_state; 1258 nlist->undo = src->textSrc.undo->list; 1259 nlist->redo = NULL; 1260 1261 if (list == src->textSrc.undo->list) 1262 src->textSrc.undo->end_mark = nlist; 1263 1264 if (src->textSrc.undo->dir == XawsdLeft) { 1265 if (list->undo == NULL) 1266 src->textSrc.undo->dir = XawsdRight; 1267 else 1268 list = list->undo; 1269 } 1270 else { 1271 if (list->redo == NULL || list->redo == src->textSrc.undo->end_mark) 1272 src->textSrc.undo->dir = XawsdLeft; 1273 else 1274 list = list->redo; 1275 } 1276 *insert_pos = r_state->position + r_state->length; 1277 src->textSrc.undo->pointer = list; 1278 src->textSrc.undo->list->redo = nlist; 1279 src->textSrc.undo->list = nlist; 1280 src->textSrc.undo->merge = src->textSrc.undo->erase = 0; 1281 1282 if (++src->textSrc.undo->num_list >= UNDO_DEPTH) 1283 UndoGC(src->textSrc.undo); 1284 1285 return (True); 1286 } 1287 1288 Bool 1289 _XawTextSrcToggleUndo(TextSrcObject src) 1290 { 1291 if (!src->textSrc.enable_undo || !src->textSrc.undo->num_undo) 1292 return (False); 1293 1294 if (src->textSrc.undo->pointer != src->textSrc.undo->list) { 1295 if (src->textSrc.undo->dir == XawsdLeft) { 1296 if (src->textSrc.undo->pointer->redo 1297 && (src->textSrc.undo->pointer->redo 1298 != src->textSrc.undo->end_mark)) { 1299 src->textSrc.undo->pointer = src->textSrc.undo->pointer->redo; 1300 src->textSrc.undo->dir = XawsdRight; 1301 } 1302 } 1303 else { 1304 if (src->textSrc.undo->pointer->undo 1305 && (src->textSrc.undo->pointer != src->textSrc.undo->head)) { 1306 src->textSrc.undo->pointer = src->textSrc.undo->pointer->undo; 1307 src->textSrc.undo->dir = XawsdLeft; 1308 } 1309 } 1310 } 1311 1312 return (True); 1313 } 1314 1315 static void 1316 FreeUndoBuffer(XawTextUndo *undo) 1317 { 1318 unsigned i; 1319 XawTextUndoList *head, *del; 1320 1321 for (i = 0; i < undo->num_undo; i++) { 1322 if (undo->undo[i]->buffer && undo->undo[i]->buffer != SrcNL && 1323 undo->undo[i]->buffer != (char*)SrcWNL) 1324 XtFree(undo->undo[i]->buffer); 1325 XtFree((char*)undo->undo[i]); 1326 } 1327 XtFree((char*)undo->undo); 1328 head = undo->head; 1329 1330 del = head; 1331 while (head) { 1332 head = head->redo; 1333 XtFree((char*)del); 1334 del = head; 1335 } 1336 1337 if (undo->l_save) { 1338 XtFree((char*)undo->l_save); 1339 undo->l_save = NULL; 1340 } 1341 if (undo->r_save) { 1342 XtFree((char*)undo->r_save); 1343 undo->r_save = NULL; 1344 } 1345 if (undo->u_save) { 1346 XtFree((char*)undo->u_save); 1347 undo->u_save = NULL; 1348 } 1349 1350 undo->list = undo->pointer = undo->head = undo->end_mark = NULL; 1351 undo->l_no_change = undo->r_no_change = NULL; 1352 undo->undo = NULL; 1353 undo->dir = XawsdLeft; 1354 undo->num_undo = undo->num_list = (unsigned)(undo->erase = undo->merge = 0); 1355 } 1356 1357 static void 1358 UndoGC(XawTextUndo *undo) 1359 { 1360 XawTextUndoList *head = undo->head, *redo = head->redo; 1361 1362 if (head == undo->pointer || head == undo->end_mark 1363 || undo->l_no_change == NULL 1364 || head->left == undo->l_no_change || head->right == undo->l_no_change) 1365 return; 1366 1367 undo->head = redo; 1368 redo->undo = NULL; 1369 1370 --head->left->refcount; 1371 if (--head->right->refcount == 0) { 1372 unsigned i; 1373 1374 for (i = 0; i < undo->num_undo; i+= 2) 1375 if (head->left == undo->undo[i] || head->left == undo->undo[i+1]) { 1376 if (head->left == undo->undo[i+1]) { 1377 XawTextUndoBuffer *tmp = redo->left; 1378 1379 redo->left = redo->right; 1380 redo->right = tmp; 1381 } 1382 if (head->left->buffer && head->left->buffer != SrcNL && 1383 head->left->buffer != (char*)SrcWNL) 1384 XtFree(head->left->buffer); 1385 XtFree((char*)head->left); 1386 if (head->right->buffer && head->right->buffer != SrcNL && 1387 head->right->buffer != (char*)SrcWNL) 1388 XtFree(head->right->buffer); 1389 XtFree((char*)head->right); 1390 1391 undo->num_undo -= 2; 1392 memmove(&undo->undo[i], &undo->undo[i + 2], 1393 (undo->num_undo - i) * sizeof(XawTextUndoBuffer*)); 1394 break; 1395 } 1396 } 1397 XtFree((char*)head); 1398 --undo->num_list; 1399 } 1400 #endif /* OLDXAW */ 1401 1402 /* 1403 * Function: 1404 * XawTextSourceScan 1405 * 1406 * Parameters: 1407 * w - TextSrc Object 1408 * position - position to start scanning 1409 * type - type of thing to scan for 1410 * dir - direction to scan 1411 * count - which occurrence if this thing to search for 1412 * include - whether or not to include the character found in 1413 * the position that is returned. 1414 * 1415 * Description: 1416 * Scans the text source for the number and type of item specified. 1417 * 1418 * Returns: 1419 * The position of the text 1420 */ 1421 XawTextPosition 1422 XawTextSourceScan(Widget w, XawTextPosition position, 1423 #if NeedWidePrototypes 1424 int type, int dir, int count, int include 1425 #else 1426 XawTextScanType type, XawTextScanDirection dir, 1427 int count, Boolean include 1428 #endif 1429 ) 1430 { 1431 TextSrcObjectClass cclass = (TextSrcObjectClass)w->core.widget_class; 1432 1433 return ((*cclass->textSrc_class.Scan) 1434 (w, position, type, dir, count, include)); 1435 } 1436 1437 /* 1438 * Function: 1439 * XawTextSourceSearch 1440 * 1441 * Parameters: 1442 * w - TextSource Object 1443 * position - position to start scanning 1444 * dir - direction to scan 1445 * text - the text block to search for. 1446 * 1447 * Returns: 1448 * The position of the text we are searching for or XawTextSearchError. 1449 * 1450 * Description: 1451 * Searches the text source for the text block passed 1452 */ 1453 XawTextPosition 1454 XawTextSourceSearch(Widget w, XawTextPosition position, 1455 #if NeedWidePrototypes 1456 int dir, 1457 #else 1458 XawTextScanDirection dir, 1459 #endif 1460 XawTextBlock *text) 1461 { 1462 TextSrcObjectClass cclass = (TextSrcObjectClass)w->core.widget_class; 1463 1464 return ((*cclass->textSrc_class.Search)(w, position, dir, text)); 1465 } 1466 1467 /* 1468 * Function: 1469 * XawTextSourceConvertSelection 1470 * 1471 * Parameters: 1472 * w - TextSrc object 1473 * selection - current selection atom 1474 * target - current target atom 1475 * type - type to convert the selection to 1476 * value - return value that has been converted 1477 * length - "" 1478 * format - format of the returned value 1479 * 1480 * Returns: 1481 * True if the selection has been converted 1482 */ 1483 Boolean 1484 XawTextSourceConvertSelection(Widget w, Atom *selection, Atom *target, 1485 Atom *type, XtPointer *value, 1486 unsigned long *length, int *format) 1487 { 1488 TextSrcObjectClass cclass = (TextSrcObjectClass)w->core.widget_class; 1489 1490 return((*cclass->textSrc_class.ConvertSelection) 1491 (w, selection, target, type, value, length, format)); 1492 } 1493 1494 /* 1495 * Function: 1496 * XawTextSourceSetSelection 1497 * 1498 * Parameters: 1499 * w - TextSrc object 1500 * left - bounds of the selection 1501 * right - "" 1502 * selection - selection atom 1503 * 1504 * Description: 1505 * Allows special setting of the selection. 1506 */ 1507 void 1508 XawTextSourceSetSelection(Widget w, XawTextPosition left, 1509 XawTextPosition right, Atom selection) 1510 { 1511 TextSrcObjectClass cclass = (TextSrcObjectClass)w->core.widget_class; 1512 1513 (*cclass->textSrc_class.SetSelection)(w, left, right, selection); 1514 } 1515 1516 /* 1517 * External Functions for Multi Text 1518 */ 1519 /* 1520 * TextFormat(): 1521 * returns the format of text: FMT8BIT or FMTWIDE 1522 */ 1523 XrmQuark 1524 _XawTextFormat(TextWidget tw) 1525 { 1526 return (((TextSrcObject)(tw->text.source))->textSrc.text_format); 1527 } 1528 1529 /* _XawTextWCToMB(): 1530 * Convert the wchar string to external encoding 1531 * The caller is responsible for freeing both the source and ret string 1532 * 1533 * wstr - source wchar string 1534 * len_in_out - length of string. 1535 * As In, length of source wchar string, measured in wchar 1536 * As Out, length of returned string 1537 */ 1538 char * 1539 _XawTextWCToMB(Display *d, wchar_t *wstr, int *len_in_out) 1540 { 1541 XTextProperty textprop; 1542 1543 if (XwcTextListToTextProperty(d, (wchar_t**)&wstr, 1, 1544 XTextStyle, &textprop) < Success) { 1545 XtWarningMsg("convertError", "textSource", "XawError", 1546 "Non-character code(s) in buffer.", NULL, NULL); 1547 *len_in_out = 0; 1548 return (NULL); 1549 } 1550 *len_in_out = (int)textprop.nitems; 1551 1552 return ((char *)textprop.value); 1553 } 1554 1555 /* _XawTextMBToWC(): 1556 * Convert the string to internal processing codeset WC. 1557 * The caller is responsible for freeing both the source and ret string. 1558 * 1559 * str - source string 1560 * len_in_out - length of string 1561 * As In, it is length of source string 1562 * As Out, it is length of returned string, measured in wchar 1563 */ 1564 wchar_t * 1565 _XawTextMBToWC(Display *d, char *str, int *len_in_out) 1566 { 1567 XTextProperty textprop; 1568 char *buf; 1569 wchar_t **wlist, *wstr; 1570 int count; 1571 1572 if (*len_in_out == 0) 1573 return (NULL); 1574 1575 buf = XtMalloc((Cardinal)(*len_in_out + 1)); 1576 1577 strncpy(buf, str, (size_t)*len_in_out); 1578 *(buf + *len_in_out) = '\0'; 1579 if (XmbTextListToTextProperty(d, &buf, 1, XTextStyle, &textprop) != Success) { 1580 XtWarningMsg("convertError", "textSource", "XawError", 1581 "No Memory, or Locale not supported.", NULL, NULL); 1582 XtFree(buf); 1583 *len_in_out = 0; 1584 return (NULL); 1585 } 1586 1587 XtFree(buf); 1588 if (XwcTextPropertyToTextList(d, &textprop, 1589 (wchar_t***)&wlist, &count) != Success) { 1590 XtWarningMsg("convertError", "multiSourceCreate", "XawError", 1591 "Non-character code(s) in source.", NULL, NULL); 1592 *len_in_out = 0; 1593 return (NULL); 1594 } 1595 wstr = wlist[0]; 1596 *len_in_out = (int)wcslen(wstr); 1597 XtFree((XtPointer)wlist); 1598 1599 return (wstr); 1600 } 1601 1602 #ifndef OLDXAW 1603 static int 1604 qcmp_anchors(_Xconst void *left, _Xconst void *right) 1605 { 1606 return (int)((*(XawTextAnchor**)left)->position - 1607 (*(XawTextAnchor**)right)->position); 1608 } 1609 1610 XawTextAnchor * 1611 XawTextSourceAddAnchor(Widget w, XawTextPosition position) 1612 { 1613 TextSrcObject src = (TextSrcObject)w; 1614 XawTextAnchor *anchor, *panchor; 1615 1616 if ((panchor = XawTextSourceFindAnchor(w, position)) != NULL) { 1617 XawTextEntity *pentity, *entity; 1618 1619 if (position - panchor->position < ANCHORS_DIST) 1620 return (panchor); 1621 1622 if (panchor->cache && panchor->position + panchor->cache->offset + 1623 panchor->cache->length < position) 1624 pentity = entity = panchor->cache; 1625 else 1626 pentity = entity = panchor->entities; 1627 1628 while (entity && panchor->position + entity->offset + 1629 entity->length < position) { 1630 pentity = entity; 1631 entity = entity->next; 1632 } 1633 if (entity) { 1634 XawTextPosition diff; 1635 1636 if (panchor->position + entity->offset < position) 1637 position = panchor->position + entity->offset; 1638 1639 if (position == panchor->position) 1640 return (panchor); 1641 1642 anchor = XtNew(XawTextAnchor); 1643 diff = position - panchor->position; 1644 1645 panchor->cache = NULL; 1646 anchor->entities = entity; 1647 if (pentity != entity) 1648 pentity->next = NULL; 1649 else 1650 panchor->entities = NULL; 1651 while (entity) { 1652 entity->offset -= diff; 1653 entity = entity->next; 1654 } 1655 } 1656 else { 1657 anchor = XtNew(XawTextAnchor); 1658 anchor->entities = NULL; 1659 } 1660 } 1661 else { 1662 anchor = XtNew(XawTextAnchor); 1663 anchor->entities = NULL; 1664 } 1665 1666 anchor->position = position; 1667 anchor->cache = NULL; 1668 1669 src->textSrc.anchors = (XawTextAnchor**) 1670 XtRealloc((XtPointer)src->textSrc.anchors, 1671 (Cardinal)(sizeof(XawTextAnchor*) * 1672 (size_t)(src->textSrc.num_anchors + 1))); 1673 src->textSrc.anchors[src->textSrc.num_anchors++] = anchor; 1674 qsort((void*)src->textSrc.anchors, 1675 (size_t)src->textSrc.num_anchors, 1676 sizeof(XawTextAnchor*), qcmp_anchors); 1677 1678 return (anchor); 1679 } 1680 1681 XawTextAnchor * 1682 XawTextSourceFindAnchor(Widget w, XawTextPosition position) 1683 { 1684 TextSrcObject src = (TextSrcObject)w; 1685 int left, right, nmemb = src->textSrc.num_anchors; 1686 XawTextAnchor **anchors = src->textSrc.anchors; 1687 1688 left = 0; 1689 right = nmemb - 1; 1690 while (left <= right) { 1691 int i = (left + right) >> 1; 1692 XawTextAnchor *anchor = anchors[i]; 1693 1694 if (anchor->position == position) 1695 return (anchor); 1696 else if (position < anchor->position) 1697 right = i - 1; 1698 else 1699 left = i + 1; 1700 } 1701 1702 if (nmemb) 1703 return (right < 0 ? anchors[0] : anchors[right]); 1704 1705 return (NULL); 1706 } 1707 1708 Bool 1709 XawTextSourceAnchorAndEntity(Widget w, XawTextPosition position, 1710 XawTextAnchor **anchor_return, 1711 XawTextEntity **entity_return) 1712 { 1713 XawTextAnchor *anchor = XawTextSourceFindAnchor(w, position); 1714 XawTextEntity *pentity, *entity; 1715 Bool next_anchor = True, retval = False; 1716 1717 if (anchor->cache && anchor->position + anchor->cache->offset + 1718 anchor->cache->length <= position) 1719 pentity = entity = anchor->cache; 1720 else 1721 pentity = entity = anchor->entities; 1722 while (entity) { 1723 XawTextPosition offset = anchor->position + entity->offset; 1724 1725 if (offset > position) { 1726 retval = next_anchor = False; 1727 break; 1728 } 1729 if (offset + entity->length > position) { 1730 retval = True; 1731 next_anchor = False; 1732 break; 1733 } 1734 pentity = entity; 1735 entity = entity->next; 1736 } 1737 1738 if (next_anchor) { 1739 *anchor_return = anchor = XawTextSourceNextAnchor(w, anchor); 1740 *entity_return = anchor ? anchor->entities : NULL; 1741 } 1742 else { 1743 *anchor_return = anchor; 1744 *entity_return = retval ? entity : pentity; 1745 } 1746 1747 if (*anchor_return) 1748 (*anchor_return)->cache = *entity_return; 1749 1750 return (retval); 1751 } 1752 1753 XawTextAnchor * 1754 XawTextSourceNextAnchor(Widget w, XawTextAnchor *anchor) 1755 { 1756 int i; 1757 TextSrcObject src = (TextSrcObject)w; 1758 1759 for (i = 0; i < src->textSrc.num_anchors - 1; i++) 1760 if (src->textSrc.anchors[i] == anchor) 1761 return (src->textSrc.anchors[i + 1]); 1762 1763 return (NULL); 1764 } 1765 1766 XawTextAnchor * 1767 XawTextSourcePrevAnchor(Widget w, XawTextAnchor *anchor) 1768 { 1769 int i; 1770 TextSrcObject src = (TextSrcObject)w; 1771 1772 for (i = src->textSrc.num_anchors - 1; i > 0; i--) 1773 if (src->textSrc.anchors[i] == anchor) 1774 return (src->textSrc.anchors[i - 1]); 1775 1776 return (NULL); 1777 } 1778 1779 XawTextAnchor * 1780 XawTextSourceRemoveAnchor(Widget w, XawTextAnchor *anchor) 1781 { 1782 int i; 1783 TextSrcObject src = (TextSrcObject)w; 1784 1785 for (i = 0; i < src->textSrc.num_anchors; i++) 1786 if (src->textSrc.anchors[i] == anchor) 1787 break; 1788 1789 if (i == 0) 1790 return (src->textSrc.num_anchors > 1 ? src->textSrc.anchors[1] : NULL); 1791 1792 if (i < src->textSrc.num_anchors) { 1793 XtFree((XtPointer)anchor); 1794 if (i < --src->textSrc.num_anchors) { 1795 memmove(&src->textSrc.anchors[i], 1796 &src->textSrc.anchors[i + 1], 1797 (size_t)(src->textSrc.num_anchors - i) * 1798 sizeof(XawTextAnchor*)); 1799 1800 return (src->textSrc.anchors[i]); 1801 } 1802 } 1803 1804 return (NULL); 1805 } 1806 1807 XawTextEntity * 1808 XawTextSourceAddEntity(Widget w, int type, int flags, XtPointer data, 1809 XawTextPosition position, Cardinal length, 1810 XrmQuark property) 1811 { 1812 XawTextAnchor *next, *anchor = _XawTextSourceFindAnchor(w, position); 1813 XawTextEntity *entity, *eprev; 1814 1815 /* There is no support for zero length entities for now */ 1816 if (length == 0) 1817 return (NULL); 1818 1819 if (anchor->cache && anchor->position + anchor->cache->offset + 1820 anchor->cache->length <= position) 1821 eprev = entity = anchor->cache; 1822 else 1823 eprev = entity = anchor->entities; 1824 1825 while (entity && anchor->position + entity->offset + entity->length <= 1826 position) { 1827 eprev = entity; 1828 entity = entity->next; 1829 } 1830 if (entity && anchor->position + entity->offset < position + length) { 1831 fprintf(stderr, "Cannot (yet) add more than one entity to same region.\n"); 1832 return (NULL); 1833 } 1834 1835 next = XawTextSourceFindAnchor(w, position + length); 1836 if (next && next != anchor) { 1837 if ((entity = next->entities) != NULL) { 1838 if (next->position + entity->offset < position + length) { 1839 fprintf(stderr, "Cannot (yet) add more than one entity to same region.\n"); 1840 return (NULL); 1841 } 1842 } 1843 if (position + length > next->position) { 1844 XawTextPosition diff = position + length - next->position; 1845 1846 next->position += diff; 1847 entity = next->entities; 1848 while (entity) { 1849 entity->offset -= diff; 1850 entity = entity->next; 1851 } 1852 entity = anchor->entities; 1853 while (entity && entity->offset < 0) 1854 entity = entity->next; 1855 if (entity && entity->offset < 0) { 1856 if (eprev) 1857 eprev->next = next->entities; 1858 else 1859 anchor->entities = next->entities; 1860 if ((next->entities = entity->next) == NULL) 1861 (void)XawTextSourceRemoveAnchor(w, next); 1862 entity->next = NULL; 1863 1864 return (XawTextSourceAddEntity(w, type, flags, data, position, 1865 length, property)); 1866 } 1867 } 1868 } 1869 1870 /* Automatically join sequential entities if possible */ 1871 if (eprev && 1872 anchor->position + eprev->offset + eprev->length == position && 1873 eprev->property == property && eprev->type == type && 1874 eprev->flags == flags && eprev->data == data) { 1875 eprev->length += length; 1876 return (eprev); 1877 } 1878 1879 entity = XtNew(XawTextEntity); 1880 entity->type = (short)type; 1881 entity->flags = (short)flags; 1882 entity->data = data; 1883 entity->offset = position - anchor->position; 1884 entity->length = length; 1885 entity->property = property; 1886 1887 if (eprev == NULL) { 1888 anchor->entities = entity; 1889 entity->next = NULL; 1890 anchor->cache = NULL; 1891 } 1892 else if (eprev->offset > entity->offset) { 1893 anchor->cache = NULL; 1894 anchor->entities = entity; 1895 entity->next = eprev; 1896 } 1897 else { 1898 anchor->cache = eprev; 1899 entity->next = eprev->next; 1900 eprev->next = entity; 1901 } 1902 1903 return (entity); 1904 } 1905 1906 void 1907 XawTextSourceClearEntities(Widget w, XawTextPosition left, XawTextPosition right) 1908 { 1909 XawTextAnchor *anchor = XawTextSourceFindAnchor(w, left); 1910 XawTextEntity *entity, *eprev, *enext; 1911 XawTextPosition offset; 1912 1913 while (anchor && anchor->entities == NULL) 1914 anchor = XawTextSourceRemoveAnchor(w, anchor); 1915 1916 if (anchor == NULL || left >= right) 1917 return; 1918 1919 if (anchor->cache && anchor->position + anchor->cache->offset + 1920 anchor->cache->length < left) 1921 eprev = entity = anchor->cache; 1922 else 1923 eprev = entity = anchor->entities; 1924 1925 /* find first entity before left position */ 1926 while (anchor->position + entity->offset + entity->length < left) { 1927 eprev = entity; 1928 if ((entity = entity->next) == NULL) { 1929 if ((anchor = XawTextSourceNextAnchor(w, anchor)) == NULL) 1930 return; 1931 if ((eprev = entity = anchor->entities) == NULL) { 1932 fprintf(stderr, "Bad anchor found!\n"); 1933 return; 1934 } 1935 } 1936 } 1937 1938 offset = anchor->position + entity->offset; 1939 if (offset <= left) { 1940 int length = (int) (XawMin(entity->length, left - offset)); 1941 1942 if (length <= 0) { 1943 enext = entity->next; 1944 eprev->next = enext; 1945 XtFree((XtPointer)entity); 1946 anchor->cache = NULL; 1947 if (entity == anchor->entities) { 1948 eprev = NULL; 1949 if ((anchor->entities = enext) == NULL) { 1950 if ((anchor = XawTextSourceRemoveAnchor(w, anchor)) == NULL) 1951 return; 1952 entity = anchor->entities; 1953 } 1954 else 1955 entity = enext; 1956 } 1957 else 1958 entity = enext; 1959 } 1960 else { 1961 entity->length = (Cardinal)length; 1962 eprev = entity; 1963 entity = entity->next; 1964 } 1965 } 1966 1967 /* clean everything until right position is reached */ 1968 while (anchor) { 1969 while (entity) { 1970 offset = anchor->position + entity->offset + entity->length; 1971 1972 if (offset > right) { 1973 anchor->cache = NULL; 1974 entity->offset = XawMax(entity->offset, right - anchor->position); 1975 entity->length = (Cardinal) (XawMin(entity->length, offset - right)); 1976 return; 1977 } 1978 1979 enext = entity->next; 1980 if (eprev) 1981 eprev->next = enext; 1982 XtFree((XtPointer)entity); 1983 if (entity == anchor->entities) { 1984 eprev = anchor->cache = NULL; 1985 if ((anchor->entities = enext) == NULL) { 1986 if ((anchor = XawTextSourceRemoveAnchor(w, anchor)) == NULL) 1987 return; 1988 entity = anchor->entities; 1989 continue; 1990 } 1991 } 1992 entity = enext; 1993 } 1994 if (anchor) 1995 anchor->cache = NULL; 1996 if ((anchor = XawTextSourceNextAnchor(w, anchor)) != NULL) 1997 entity = anchor->entities; 1998 eprev = NULL; 1999 } 2000 } 2001 2002 /* checks the anchors up to position, and create an appropriate anchor 2003 * at position, if required. 2004 */ 2005 XawTextAnchor * 2006 _XawTextSourceFindAnchor(Widget w, XawTextPosition position) 2007 { 2008 XawTextAnchor *anchor; 2009 2010 anchor = XawTextSourceFindAnchor(w, position); 2011 2012 position -= position % ANCHORS_DIST; 2013 2014 if (position - anchor->position >= ANCHORS_DIST) 2015 return (XawTextSourceAddAnchor(w, position)); 2016 2017 return (anchor); 2018 } 2019 #endif 2020