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