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