TextSrc.c revision 994689c1
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 "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, Widget cnew, 300 ArgList args, Cardinal *num_args) 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) 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, Widget request, Widget cnew, 361 ArgList args, Cardinal *num_args) 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 retreive 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, XawTextPosition pos, XawTextBlock *text, int length) 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, XawTextPosition startPos, XawTextPosition endPos, 435 XawTextBlock *text) 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 occurance if 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, XawTextPosition position, XawTextScanType type, 459 XawTextScanDirection dir, int count, Bool include) 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 * Searchs the text source for the text block passed 476 */ 477/*ARGSUSED*/ 478static XawTextPosition 479Search(Widget w, XawTextPosition position, XawTextScanDirection dir, 480 XawTextBlock *text) 481{ 482 return (XawTextSearchError); 483} 484 485/*ARGSUSED*/ 486static Boolean 487ConvertSelection(Widget w, Atom *selection, Atom *target, Atom *type, 488 XtPointer *value, unsigned long *length, int *format) 489{ 490 return (False); 491} 492 493/*ARGSUSED*/ 494static void 495SetSelection(Widget w, XawTextPosition left, XawTextPosition right, 496 Atom selection) 497{ 498} 499 500/*ARGSUSED*/ 501static void 502CvtStringToEditMode(XrmValuePtr args, Cardinal *num_args, 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, Cardinal *num_args, 530 XrmValuePtr fromVal, XrmValuePtr toVal, 531 XtPointer *data) 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 = 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 = 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 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 diferentiate insert-char's separeted 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 = right - left; 761 } 762 else { 763 l_state->length = 0; 764 l_state->buffer = NULL; 765 } 766 l_state->format = 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 * block->length; 790 r_state->length = 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 (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 = left - offset + block->length; 1023 else 1024 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 (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 += 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 = 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 = 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 occurance 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 * Searchs 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 conver 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 * rigth - "" 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 - lengh 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 = 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 - lengh 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(*len_in_out + 1); 1567 1568 strncpy(buf, str, *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 = 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 ((*(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, sizeof(XawTextAnchor*) * 1662 (src->textSrc.num_anchors + 1)); 1663 src->textSrc.anchors[src->textSrc.num_anchors++] = anchor; 1664 qsort((void*)src->textSrc.anchors, src->textSrc.num_anchors, 1665 sizeof(XawTextAnchor*), qcmp_anchors); 1666 1667 return (anchor); 1668} 1669 1670XawTextAnchor * 1671XawTextSourceFindAnchor(Widget w, XawTextPosition position) 1672{ 1673 TextSrcObject src = (TextSrcObject)w; 1674 int i = 0, left, right, nmemb = src->textSrc.num_anchors; 1675 XawTextAnchor *anchor, **anchors = src->textSrc.anchors; 1676 1677 left = 0; 1678 right = nmemb - 1; 1679 while (left <= right) { 1680 anchor = anchors[i = (left + right) >> 1]; 1681 if (anchor->position == position) 1682 return (anchor); 1683 else if (position < anchor->position) 1684 right = i - 1; 1685 else 1686 left = i + 1; 1687 } 1688 1689 if (nmemb) 1690 return (right < 0 ? anchors[0] : anchors[right]); 1691 1692 return (NULL); 1693} 1694 1695Bool 1696XawTextSourceAnchorAndEntity(Widget w, XawTextPosition position, 1697 XawTextAnchor **anchor_return, 1698 XawTextEntity **entity_return) 1699{ 1700 XawTextAnchor *anchor = XawTextSourceFindAnchor(w, position); 1701 XawTextEntity *pentity, *entity; 1702 XawTextPosition offset; 1703 Bool next_anchor = True, retval = False; 1704 1705 if (anchor->cache && anchor->position + anchor->cache->offset + 1706 anchor->cache->length <= position) 1707 pentity = entity = anchor->cache; 1708 else 1709 pentity = entity = anchor->entities; 1710 while (entity) { 1711 offset = anchor->position + entity->offset; 1712 1713 if (offset > position) { 1714 retval = next_anchor = False; 1715 break; 1716 } 1717 if (offset + entity->length > position) { 1718 retval = True; 1719 next_anchor = False; 1720 break; 1721 } 1722 pentity = entity; 1723 entity = entity->next; 1724 } 1725 1726 if (next_anchor) { 1727 *anchor_return = anchor = XawTextSourceNextAnchor(w, anchor); 1728 *entity_return = anchor ? anchor->entities : NULL; 1729 } 1730 else { 1731 *anchor_return = anchor; 1732 *entity_return = retval ? entity : pentity; 1733 } 1734 1735 if (*anchor_return) 1736 (*anchor_return)->cache = *entity_return; 1737 1738 return (retval); 1739} 1740 1741XawTextAnchor * 1742XawTextSourceNextAnchor(Widget w, XawTextAnchor *anchor) 1743{ 1744 int i; 1745 TextSrcObject src = (TextSrcObject)w; 1746 1747 for (i = 0; i < src->textSrc.num_anchors - 1; i++) 1748 if (src->textSrc.anchors[i] == anchor) 1749 return (src->textSrc.anchors[i + 1]); 1750 1751 return (NULL); 1752} 1753 1754XawTextAnchor * 1755XawTextSourcePrevAnchor(Widget w, XawTextAnchor *anchor) 1756{ 1757 int i; 1758 TextSrcObject src = (TextSrcObject)w; 1759 1760 for (i = src->textSrc.num_anchors - 1; i > 0; i--) 1761 if (src->textSrc.anchors[i] == anchor) 1762 return (src->textSrc.anchors[i - 1]); 1763 1764 return (NULL); 1765} 1766 1767XawTextAnchor * 1768XawTextSourceRemoveAnchor(Widget w, XawTextAnchor *anchor) 1769{ 1770 int i; 1771 TextSrcObject src = (TextSrcObject)w; 1772 1773 for (i = 0; i < src->textSrc.num_anchors; i++) 1774 if (src->textSrc.anchors[i] == anchor) 1775 break; 1776 1777 if (i == 0) 1778 return (src->textSrc.num_anchors > 1 ? src->textSrc.anchors[1] : NULL); 1779 1780 if (i < src->textSrc.num_anchors) { 1781 XtFree((XtPointer)anchor); 1782 if (i < --src->textSrc.num_anchors) { 1783 memmove(&src->textSrc.anchors[i], 1784 &src->textSrc.anchors[i + 1], 1785 (src->textSrc.num_anchors - i) * 1786 sizeof(XawTextAnchor*)); 1787 1788 return (src->textSrc.anchors[i]); 1789 } 1790 } 1791 1792 return (NULL); 1793} 1794 1795XawTextEntity * 1796XawTextSourceAddEntity(Widget w, int type, int flags, XtPointer data, 1797 XawTextPosition position, Cardinal length, 1798 XrmQuark property) 1799{ 1800 XawTextAnchor *next, *anchor = _XawTextSourceFindAnchor(w, position); 1801 XawTextEntity *entity, *eprev; 1802 1803 /* There is no support for zero length entities for now */ 1804 if (length == 0) 1805 return (NULL); 1806 1807 if (anchor->cache && anchor->position + anchor->cache->offset + 1808 anchor->cache->length <= position) 1809 eprev = entity = anchor->cache; 1810 else 1811 eprev = entity = anchor->entities; 1812 1813 while (entity && anchor->position + entity->offset + entity->length <= 1814 position) { 1815 eprev = entity; 1816 entity = entity->next; 1817 } 1818 if (entity && anchor->position + entity->offset < position + length) { 1819 fprintf(stderr, "Cannot (yet) add more than one entity to same region.\n"); 1820 return (NULL); 1821 } 1822 1823 next = XawTextSourceFindAnchor(w, position + length); 1824 if (next && next != anchor) { 1825 if ((entity = next->entities) != NULL) { 1826 if (next->position + entity->offset < position + length) { 1827 fprintf(stderr, "Cannot (yet) add more than one entity to same region.\n"); 1828 return (NULL); 1829 } 1830 } 1831 if (position + length > next->position) { 1832 XawTextPosition diff = position + length - next->position; 1833 1834 next->position += diff; 1835 entity = next->entities; 1836 while (entity) { 1837 entity->offset -= diff; 1838 entity = entity->next; 1839 } 1840 entity = anchor->entities; 1841 while (entity && entity->offset < 0) 1842 entity = entity->next; 1843 if (entity && entity->offset < 0) { 1844 if (eprev) 1845 eprev->next = next->entities; 1846 else 1847 anchor->entities = next->entities; 1848 if ((next->entities = entity->next) == NULL) 1849 (void)XawTextSourceRemoveAnchor(w, next); 1850 entity->next = NULL; 1851 1852 return (XawTextSourceAddEntity(w, type, flags, data, position, 1853 length, property)); 1854 } 1855 } 1856 } 1857 1858 /* Automatically join sequential entities if possible */ 1859 if (eprev && 1860 anchor->position + eprev->offset + eprev->length == position && 1861 eprev->property == property && eprev->type == type && 1862 eprev->flags == flags && eprev->data == data) { 1863 eprev->length += length; 1864 return (eprev); 1865 } 1866 1867 entity = XtNew(XawTextEntity); 1868 entity->type = type; 1869 entity->flags = flags; 1870 entity->data = data; 1871 entity->offset = position - anchor->position; 1872 entity->length = length; 1873 entity->property = property; 1874 1875 if (eprev == NULL) { 1876 anchor->entities = entity; 1877 entity->next = NULL; 1878 anchor->cache = NULL; 1879 } 1880 else if (eprev->offset > entity->offset) { 1881 anchor->cache = NULL; 1882 anchor->entities = entity; 1883 entity->next = eprev; 1884 } 1885 else { 1886 anchor->cache = eprev; 1887 entity->next = eprev->next; 1888 eprev->next = entity; 1889 } 1890 1891 return (entity); 1892} 1893 1894void 1895XawTextSourceClearEntities(Widget w, XawTextPosition left, XawTextPosition right) 1896{ 1897 XawTextAnchor *anchor = XawTextSourceFindAnchor(w, left); 1898 XawTextEntity *entity, *eprev, *enext; 1899 XawTextPosition offset; 1900 int length; 1901 1902 while (anchor && anchor->entities == NULL) 1903 anchor = XawTextSourceRemoveAnchor(w, anchor); 1904 1905 if (anchor == NULL || left >= right) 1906 return; 1907 1908 if (anchor->cache && anchor->position + anchor->cache->offset + 1909 anchor->cache->length < left) 1910 eprev = entity = anchor->cache; 1911 else 1912 eprev = entity = anchor->entities; 1913 1914 /* find first entity before left position */ 1915 while (anchor->position + entity->offset + entity->length < left) { 1916 eprev = entity; 1917 if ((entity = entity->next) == NULL) { 1918 if ((anchor = XawTextSourceNextAnchor(w, anchor)) == NULL) 1919 return; 1920 if ((eprev = entity = anchor->entities) == NULL) { 1921 fprintf(stderr, "Bad anchor found!\n"); 1922 return; 1923 } 1924 } 1925 } 1926 1927 offset = anchor->position + entity->offset; 1928 if (offset <= left) { 1929 length = XawMin(entity->length, left - offset); 1930 1931 if (length <= 0) { 1932 enext = entity->next; 1933 eprev->next = enext; 1934 XtFree((XtPointer)entity); 1935 anchor->cache = NULL; 1936 if (entity == anchor->entities) { 1937 eprev = NULL; 1938 if ((anchor->entities = enext) == NULL) { 1939 if ((anchor = XawTextSourceRemoveAnchor(w, anchor)) == NULL) 1940 return; 1941 entity = anchor->entities; 1942 } 1943 else 1944 entity = enext; 1945 } 1946 else 1947 entity = enext; 1948 } 1949 else { 1950 entity->length = length; 1951 eprev = entity; 1952 entity = entity->next; 1953 } 1954 } 1955 1956 /* clean everything until right position is reached */ 1957 while (anchor) { 1958 while (entity) { 1959 offset = anchor->position + entity->offset + entity->length; 1960 1961 if (offset > right) { 1962 anchor->cache = NULL; 1963 entity->offset = XawMax(entity->offset, right - anchor->position); 1964 entity->length = XawMin(entity->length, offset - right); 1965 return; 1966 } 1967 1968 enext = entity->next; 1969 if (eprev) 1970 eprev->next = enext; 1971 XtFree((XtPointer)entity); 1972 if (entity == anchor->entities) { 1973 eprev = anchor->cache = NULL; 1974 if ((anchor->entities = enext) == NULL) { 1975 if ((anchor = XawTextSourceRemoveAnchor(w, anchor)) == NULL) 1976 return; 1977 entity = anchor->entities; 1978 continue; 1979 } 1980 } 1981 entity = enext; 1982 } 1983 if (anchor) 1984 anchor->cache = NULL; 1985 if ((anchor = XawTextSourceNextAnchor(w, anchor)) != NULL) 1986 entity = anchor->entities; 1987 eprev = NULL; 1988 } 1989} 1990 1991/* checks the anchors up to position, and create an appropriate anchor 1992 * at position, if required. 1993 */ 1994XawTextAnchor * 1995_XawTextSourceFindAnchor(Widget w, XawTextPosition position) 1996{ 1997 XawTextAnchor *anchor; 1998 1999 anchor = XawTextSourceFindAnchor(w, position); 2000 2001 position -= position % ANCHORS_DIST; 2002 2003 if (position - anchor->position >= ANCHORS_DIST) 2004 return (XawTextSourceAddAnchor(w, position)); 2005 2006 return (anchor); 2007} 2008#endif 2009