TextSrc.c revision ab902922
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 anchor = NULL; 1097 break; 1098 } 1099 eprev = NULL; 1100 } 1101 1102exit_anchor_loop: 1103 if (anchor) { 1104 XawTextAnchor *aprev; 1105 1106 if (anchor->position >= XawMax(right, left + block->length)) 1107 anchor->position += diff; 1108 else if (anchor->position > left && 1109 (aprev = XawTextSourcePrevAnchor(w, anchor))) { 1110 XawTextPosition tmp = anchor->position - aprev->position; 1111 1112 if (diff) { 1113 while (entity) { 1114 entity->offset += diff; 1115 entity = entity->next; 1116 } 1117 } 1118 entity = anchor->entities; 1119 while (entity) { 1120 entity->offset += tmp; 1121 entity = entity->next; 1122 } 1123 if ((entity = aprev->entities) == NULL) 1124 aprev->entities = anchor->entities; 1125 else { 1126 while (entity->next) 1127 entity = entity->next; 1128 entity->next = anchor->entities; 1129 } 1130 anchor->entities = NULL; 1131 (void)XawTextSourceRemoveAnchor(w, anchor); 1132 --i; 1133 } 1134 else if (diff) { 1135 while (entity) { 1136 entity->offset += diff; 1137 entity = entity->next; 1138 } 1139 } 1140 } 1141 1142 if (diff) { 1143 /* The first anchor is never removed, and should 1144 * have position 0. 1145 * i should be -1 if attempted to removed the first 1146 * anchor, what can be caused when removing a chunk 1147 * of text of the first entity. 1148 * */ 1149 if (++i == 0) { 1150 anchor = src->textSrc.anchors[0]; 1151 eprev = entity = anchor->entities; 1152 while (entity) { 1153 enext = entity->next; 1154 if (entity->offset + entity->length <= -diff) 1155 XtFree((XtPointer)entity); 1156 else 1157 break; 1158 entity = enext; 1159 } 1160 if (eprev != entity) { 1161 anchor->cache = NULL; 1162 if ((anchor->entities = entity) != NULL) { 1163 if ((entity->offset += diff) < 0) { 1164 entity->length += entity->offset; 1165 entity->offset = 0; 1166 } 1167 } 1168 } 1169 ++i; 1170 } 1171 for (; i < src->textSrc.num_anchors; i++) 1172 src->textSrc.anchors[i]->position += diff; 1173 } 1174 } 1175 1176 start = left; 1177 end = start + block->length; 1178 while (start < end) { 1179 start = XawTextSourceScan(w, start, XawstEOL, XawsdRight, 1, True); 1180 if (start <= end) { 1181 ++lines; 1182 if (start == XawTextSourceScan(w, 0, XawstAll, XawsdRight, 1, True)) { 1183 lines -= !_XawTextSourceNewLineAtEOF(w); 1184 break; 1185 } 1186 } 1187 } 1188 1189 info.left = left; 1190 info.right = right; 1191 info.block = block; 1192 XtCallCallbacks(w, XtNpropertyCallback, &info); 1193 1194 TellSourceChanged(src, left, right, block, lines); 1195 /* Call callbacks, we have changed the buffer */ 1196 XtCallCallbacks(w, XtNcallback, 1197 (XtPointer)((long)src->textSrc.changed)); 1198 } 1199 1200#endif /* OLDXAW */ 1201 return (error); 1202} 1203 1204#ifndef OLDXAW 1205Bool 1206_XawTextSrcUndo(TextSrcObject src, XawTextPosition *insert_pos) 1207{ 1208 static wchar_t wnull = 0; 1209 XawTextBlock block; 1210 XawTextUndoList *list, *nlist; 1211 XawTextUndoBuffer *l_state, *r_state; 1212 Boolean changed = src->textSrc.changed; 1213 1214 if (!src->textSrc.enable_undo || !src->textSrc.undo->num_undo) 1215 return (False); 1216 1217 list = src->textSrc.undo->pointer; 1218 1219 if (src->textSrc.undo->dir == XawsdLeft) { 1220 l_state = list->right; 1221 r_state = list->left; 1222 } 1223 else { 1224 l_state = list->left; 1225 r_state = list->right; 1226 } 1227 1228 if (src->textSrc.undo->l_no_change == l_state 1229 && src->textSrc.undo->r_no_change == r_state) 1230 src->textSrc.changed = False; 1231 else 1232 src->textSrc.changed = True; 1233 1234 block.firstPos = 0; 1235 block.length = r_state->length; 1236 block.ptr = r_state->buffer ? r_state->buffer : (char*)&wnull; 1237 block.format = r_state->format; 1238 1239 src->textSrc.undo_state = True; 1240 if (XawTextSourceReplace((Widget)src, l_state->position, l_state->position 1241 + l_state->length, &block) != XawEditDone) { 1242 src->textSrc.undo_state = False; 1243 src->textSrc.changed = changed; 1244 return (False); 1245 } 1246 src->textSrc.undo_state = False; 1247 1248 ++l_state->refcount; 1249 ++r_state->refcount; 1250 nlist = XtNew(XawTextUndoList); 1251 nlist->left = l_state; 1252 nlist->right = r_state; 1253 nlist->undo = src->textSrc.undo->list; 1254 nlist->redo = NULL; 1255 1256 if (list == src->textSrc.undo->list) 1257 src->textSrc.undo->end_mark = nlist; 1258 1259 if (src->textSrc.undo->dir == XawsdLeft) { 1260 if (list->undo == NULL) 1261 src->textSrc.undo->dir = XawsdRight; 1262 else 1263 list = list->undo; 1264 } 1265 else { 1266 if (list->redo == NULL || list->redo == src->textSrc.undo->end_mark) 1267 src->textSrc.undo->dir = XawsdLeft; 1268 else 1269 list = list->redo; 1270 } 1271 *insert_pos = r_state->position + r_state->length; 1272 src->textSrc.undo->pointer = list; 1273 src->textSrc.undo->list->redo = nlist; 1274 src->textSrc.undo->list = nlist; 1275 src->textSrc.undo->merge = src->textSrc.undo->erase = 0; 1276 1277 if (++src->textSrc.undo->num_list >= UNDO_DEPTH) 1278 UndoGC(src->textSrc.undo); 1279 1280 return (True); 1281} 1282 1283Bool 1284_XawTextSrcToggleUndo(TextSrcObject src) 1285{ 1286 if (!src->textSrc.enable_undo || !src->textSrc.undo->num_undo) 1287 return (False); 1288 1289 if (src->textSrc.undo->pointer != src->textSrc.undo->list) { 1290 if (src->textSrc.undo->dir == XawsdLeft) { 1291 if (src->textSrc.undo->pointer->redo 1292 && (src->textSrc.undo->pointer->redo 1293 != src->textSrc.undo->end_mark)) { 1294 src->textSrc.undo->pointer = src->textSrc.undo->pointer->redo; 1295 src->textSrc.undo->dir = XawsdRight; 1296 } 1297 } 1298 else { 1299 if (src->textSrc.undo->pointer->undo 1300 && (src->textSrc.undo->pointer != src->textSrc.undo->head)) { 1301 src->textSrc.undo->pointer = src->textSrc.undo->pointer->undo; 1302 src->textSrc.undo->dir = XawsdLeft; 1303 } 1304 } 1305 } 1306 1307 return (True); 1308} 1309 1310static void 1311FreeUndoBuffer(XawTextUndo *undo) 1312{ 1313 unsigned i; 1314 XawTextUndoList *head, *del; 1315 1316 for (i = 0; i < undo->num_undo; i++) { 1317 if (undo->undo[i]->buffer && undo->undo[i]->buffer != SrcNL && 1318 undo->undo[i]->buffer != (char*)SrcWNL) 1319 XtFree(undo->undo[i]->buffer); 1320 XtFree((char*)undo->undo[i]); 1321 } 1322 XtFree((char*)undo->undo); 1323 head = undo->head; 1324 1325 del = head; 1326 while (head) { 1327 head = head->redo; 1328 XtFree((char*)del); 1329 del = head; 1330 } 1331 1332 if (undo->l_save) { 1333 XtFree((char*)undo->l_save); 1334 undo->l_save = NULL; 1335 } 1336 if (undo->r_save) { 1337 XtFree((char*)undo->r_save); 1338 undo->r_save = NULL; 1339 } 1340 if (undo->u_save) { 1341 XtFree((char*)undo->u_save); 1342 undo->u_save = NULL; 1343 } 1344 1345 undo->list = undo->pointer = undo->head = undo->end_mark = NULL; 1346 undo->l_no_change = undo->r_no_change = NULL; 1347 undo->undo = NULL; 1348 undo->dir = XawsdLeft; 1349 undo->num_undo = undo->num_list = undo->erase = undo->merge = 0; 1350} 1351 1352static void 1353UndoGC(XawTextUndo *undo) 1354{ 1355 unsigned i; 1356 XawTextUndoList *head = undo->head, *redo = head->redo; 1357 1358 if (head == undo->pointer || head == undo->end_mark 1359 || undo->l_no_change == NULL 1360 || head->left == undo->l_no_change || head->right == undo->l_no_change) 1361 return; 1362 1363 undo->head = redo; 1364 redo->undo = NULL; 1365 1366 --head->left->refcount; 1367 if (--head->right->refcount == 0) { 1368 for (i = 0; i < undo->num_undo; i+= 2) 1369 if (head->left == undo->undo[i] || head->left == undo->undo[i+1]) { 1370 if (head->left == undo->undo[i+1]) { 1371 XawTextUndoBuffer *tmp = redo->left; 1372 1373 redo->left = redo->right; 1374 redo->right = tmp; 1375 } 1376 if (head->left->buffer && head->left->buffer != SrcNL && 1377 head->left->buffer != (char*)SrcWNL) 1378 XtFree(head->left->buffer); 1379 XtFree((char*)head->left); 1380 if (head->right->buffer && head->right->buffer != SrcNL && 1381 head->right->buffer != (char*)SrcWNL) 1382 XtFree(head->right->buffer); 1383 XtFree((char*)head->right); 1384 1385 undo->num_undo -= 2; 1386 memmove(&undo->undo[i], &undo->undo[i + 2], 1387 (undo->num_undo - i) * sizeof(XawTextUndoBuffer*)); 1388 break; 1389 } 1390 } 1391 XtFree((char*)head); 1392 --undo->num_list; 1393} 1394#endif /* OLDXAW */ 1395 1396/* 1397 * Function: 1398 * XawTextSourceScan 1399 * 1400 * Parameters: 1401 * w - TextSrc Object 1402 * position - position to start scanning 1403 * type - type of thing to scan for 1404 * dir - direction to scan 1405 * count - which occurance if this thing to search for 1406 * include - whether or not to include the character found in 1407 * the position that is returned. 1408 * 1409 * Description: 1410 * Scans the text source for the number and type of item specified. 1411 * 1412 * Returns: 1413 * The position of the text 1414 */ 1415XawTextPosition 1416XawTextSourceScan(Widget w, XawTextPosition position, 1417#if NeedWidePrototypes 1418 int type, int dir, int count, int include 1419#else 1420 XawTextScanType type, XawTextScanDirection dir, 1421 int count, Boolean include 1422#endif 1423) 1424{ 1425 TextSrcObjectClass cclass = (TextSrcObjectClass)w->core.widget_class; 1426 1427 return ((*cclass->textSrc_class.Scan) 1428 (w, position, type, dir, count, include)); 1429} 1430 1431/* 1432 * Function: 1433 * XawTextSourceSearch 1434 * 1435 * Parameters: 1436 * w - TextSource Object 1437 * position - position to start scanning 1438 * dir - direction to scan 1439 * text - the text block to search for. 1440 * 1441 * Returns: 1442 * The position of the text we are searching for or XawTextSearchError. 1443 * 1444 * Description: 1445 * Searchs the text source for the text block passed 1446 */ 1447XawTextPosition 1448XawTextSourceSearch(Widget w, XawTextPosition position, 1449#if NeedWidePrototypes 1450 int dir, 1451#else 1452 XawTextScanDirection dir, 1453#endif 1454 XawTextBlock *text) 1455{ 1456 TextSrcObjectClass cclass = (TextSrcObjectClass)w->core.widget_class; 1457 1458 return ((*cclass->textSrc_class.Search)(w, position, dir, text)); 1459} 1460 1461/* 1462 * Function: 1463 * XawTextSourceConvertSelection 1464 * 1465 * Parameters: 1466 * w - TextSrc object 1467 * selection - current selection atom 1468 * target - current target atom 1469 * type - type to conver the selection to 1470 * value - return value that has been converted 1471 * length - "" 1472 * format - format of the returned value 1473 * 1474 * Returns: 1475 * True if the selection has been converted 1476 */ 1477Boolean 1478XawTextSourceConvertSelection(Widget w, Atom *selection, Atom *target, 1479 Atom *type, XtPointer *value, 1480 unsigned long *length, int *format) 1481{ 1482 TextSrcObjectClass cclass = (TextSrcObjectClass)w->core.widget_class; 1483 1484 return((*cclass->textSrc_class.ConvertSelection) 1485 (w, selection, target, type, value, length, format)); 1486} 1487 1488/* 1489 * Function: 1490 * XawTextSourceSetSelection 1491 * 1492 * Parameters: 1493 * w - TextSrc object 1494 * left - bounds of the selection 1495 * rigth - "" 1496 * selection - selection atom 1497 * 1498 * Description: 1499 * Allows special setting of the selection. 1500 */ 1501void 1502XawTextSourceSetSelection(Widget w, XawTextPosition left, 1503 XawTextPosition right, Atom selection) 1504{ 1505 TextSrcObjectClass cclass = (TextSrcObjectClass)w->core.widget_class; 1506 1507 (*cclass->textSrc_class.SetSelection)(w, left, right, selection); 1508} 1509 1510/* 1511 * External Functions for Multi Text 1512 */ 1513/* 1514 * TextFormat(): 1515 * returns the format of text: FMT8BIT or FMTWIDE 1516 */ 1517XrmQuark 1518_XawTextFormat(TextWidget tw) 1519{ 1520 return (((TextSrcObject)(tw->text.source))->textSrc.text_format); 1521} 1522 1523/* _XawTextWCToMB(): 1524 * Convert the wchar string to external encoding 1525 * The caller is responsible for freeing both the source and ret string 1526 * 1527 * wstr - source wchar string 1528 * len_in_out - lengh of string. 1529 * As In, length of source wchar string, measured in wchar 1530 * As Out, length of returned string 1531 */ 1532char * 1533_XawTextWCToMB(Display *d, wchar_t *wstr, int *len_in_out) 1534{ 1535 XTextProperty textprop; 1536 1537 if (XwcTextListToTextProperty(d, (wchar_t**)&wstr, 1, 1538 XTextStyle, &textprop) < Success) { 1539 XtWarningMsg("convertError", "textSource", "XawError", 1540 "Non-character code(s) in buffer.", NULL, NULL); 1541 *len_in_out = 0; 1542 return (NULL); 1543 } 1544 *len_in_out = textprop.nitems; 1545 1546 return ((char *)textprop.value); 1547} 1548 1549/* _XawTextMBToWC(): 1550 * Convert the string to internal processing codeset WC. 1551 * The caller is responsible for freeing both the source and ret string. 1552 * 1553 * str - source string 1554 * len_in_out - lengh of string 1555 * As In, it is length of source string 1556 * As Out, it is length of returned string, measured in wchar 1557 */ 1558wchar_t * 1559_XawTextMBToWC(Display *d, char *str, int *len_in_out) 1560{ 1561 XTextProperty textprop; 1562 char *buf; 1563 wchar_t **wlist, *wstr; 1564 int count; 1565 1566 if (*len_in_out == 0) 1567 return (NULL); 1568 1569 buf = XtMalloc(*len_in_out + 1); 1570 1571 strncpy(buf, str, *len_in_out); 1572 *(buf + *len_in_out) = '\0'; 1573 if (XmbTextListToTextProperty(d, &buf, 1, XTextStyle, &textprop) != Success) { 1574 XtWarningMsg("convertError", "textSource", "XawError", 1575 "No Memory, or Locale not supported.", NULL, NULL); 1576 XtFree(buf); 1577 *len_in_out = 0; 1578 return (NULL); 1579 } 1580 1581 XtFree(buf); 1582 if (XwcTextPropertyToTextList(d, &textprop, 1583 (wchar_t***)&wlist, &count) != Success) { 1584 XtWarningMsg("convertError", "multiSourceCreate", "XawError", 1585 "Non-character code(s) in source.", NULL, NULL); 1586 *len_in_out = 0; 1587 return (NULL); 1588 } 1589 wstr = wlist[0]; 1590 *len_in_out = wcslen(wstr); 1591 XtFree((XtPointer)wlist); 1592 1593 return (wstr); 1594} 1595 1596#ifndef OLDXAW 1597static int 1598qcmp_anchors(_Xconst void *left, _Xconst void *right) 1599{ 1600 return ((*(XawTextAnchor**)left)->position - 1601 (*(XawTextAnchor**)right)->position); 1602} 1603 1604XawTextAnchor * 1605XawTextSourceAddAnchor(Widget w, XawTextPosition position) 1606{ 1607 TextSrcObject src = (TextSrcObject)w; 1608 XawTextAnchor *anchor, *panchor; 1609 1610 if ((panchor = XawTextSourceFindAnchor(w, position)) != NULL) { 1611 XawTextEntity *pentity, *entity; 1612 1613 if (position - panchor->position < ANCHORS_DIST) 1614 return (panchor); 1615 1616 if (panchor->cache && panchor->position + panchor->cache->offset + 1617 panchor->cache->length < position) 1618 pentity = entity = panchor->cache; 1619 else 1620 pentity = entity = panchor->entities; 1621 1622 while (entity && panchor->position + entity->offset + 1623 entity->length < position) { 1624 pentity = entity; 1625 entity = entity->next; 1626 } 1627 if (entity) { 1628 XawTextPosition diff; 1629 1630 if (panchor->position + entity->offset < position) 1631 position = panchor->position + entity->offset; 1632 1633 if (position == panchor->position) 1634 return (panchor); 1635 1636 anchor = XtNew(XawTextAnchor); 1637 diff = position - panchor->position; 1638 1639 panchor->cache = NULL; 1640 anchor->entities = entity; 1641 if (pentity != entity) 1642 pentity->next = NULL; 1643 else 1644 panchor->entities = NULL; 1645 while (entity) { 1646 entity->offset -= diff; 1647 entity = entity->next; 1648 } 1649 } 1650 else { 1651 anchor = XtNew(XawTextAnchor); 1652 anchor->entities = NULL; 1653 } 1654 } 1655 else { 1656 anchor = XtNew(XawTextAnchor); 1657 anchor->entities = NULL; 1658 } 1659 1660 anchor->position = position; 1661 anchor->cache = NULL; 1662 1663 src->textSrc.anchors = (XawTextAnchor**) 1664 XtRealloc((XtPointer)src->textSrc.anchors, sizeof(XawTextAnchor*) * 1665 (src->textSrc.num_anchors + 1)); 1666 src->textSrc.anchors[src->textSrc.num_anchors++] = anchor; 1667 qsort((void*)src->textSrc.anchors, src->textSrc.num_anchors, 1668 sizeof(XawTextAnchor*), qcmp_anchors); 1669 1670 return (anchor); 1671} 1672 1673XawTextAnchor * 1674XawTextSourceFindAnchor(Widget w, XawTextPosition position) 1675{ 1676 TextSrcObject src = (TextSrcObject)w; 1677 int i = 0, left, right, nmemb = src->textSrc.num_anchors; 1678 XawTextAnchor *anchor, **anchors = src->textSrc.anchors; 1679 1680 left = 0; 1681 right = nmemb - 1; 1682 while (left <= right) { 1683 anchor = anchors[i = (left + right) >> 1]; 1684 if (anchor->position == position) 1685 return (anchor); 1686 else if (position < anchor->position) 1687 right = i - 1; 1688 else 1689 left = i + 1; 1690 } 1691 1692 if (nmemb) 1693 return (right < 0 ? anchors[0] : anchors[right]); 1694 1695 return (NULL); 1696} 1697 1698Bool 1699XawTextSourceAnchorAndEntity(Widget w, XawTextPosition position, 1700 XawTextAnchor **anchor_return, 1701 XawTextEntity **entity_return) 1702{ 1703 XawTextAnchor *anchor = XawTextSourceFindAnchor(w, position); 1704 XawTextEntity *pentity, *entity; 1705 XawTextPosition offset; 1706 Bool next_anchor = True, retval = False; 1707 1708 if (anchor->cache && anchor->position + anchor->cache->offset + 1709 anchor->cache->length <= position) 1710 pentity = entity = anchor->cache; 1711 else 1712 pentity = entity = anchor->entities; 1713 while (entity) { 1714 offset = anchor->position + entity->offset; 1715 1716 if (offset > position) { 1717 retval = next_anchor = False; 1718 break; 1719 } 1720 if (offset + entity->length > position) { 1721 retval = True; 1722 next_anchor = False; 1723 break; 1724 } 1725 pentity = entity; 1726 entity = entity->next; 1727 } 1728 1729 if (next_anchor) { 1730 *anchor_return = anchor = XawTextSourceNextAnchor(w, anchor); 1731 *entity_return = anchor ? anchor->entities : NULL; 1732 } 1733 else { 1734 *anchor_return = anchor; 1735 *entity_return = retval ? entity : pentity; 1736 } 1737 1738 if (*anchor_return) 1739 (*anchor_return)->cache = *entity_return; 1740 1741 return (retval); 1742} 1743 1744XawTextAnchor * 1745XawTextSourceNextAnchor(Widget w, XawTextAnchor *anchor) 1746{ 1747 int i; 1748 TextSrcObject src = (TextSrcObject)w; 1749 1750 for (i = 0; i < src->textSrc.num_anchors - 1; i++) 1751 if (src->textSrc.anchors[i] == anchor) 1752 return (src->textSrc.anchors[i + 1]); 1753 1754 return (NULL); 1755} 1756 1757XawTextAnchor * 1758XawTextSourcePrevAnchor(Widget w, XawTextAnchor *anchor) 1759{ 1760 int i; 1761 TextSrcObject src = (TextSrcObject)w; 1762 1763 for (i = src->textSrc.num_anchors - 1; i > 0; i--) 1764 if (src->textSrc.anchors[i] == anchor) 1765 return (src->textSrc.anchors[i - 1]); 1766 1767 return (NULL); 1768} 1769 1770XawTextAnchor * 1771XawTextSourceRemoveAnchor(Widget w, XawTextAnchor *anchor) 1772{ 1773 int i; 1774 TextSrcObject src = (TextSrcObject)w; 1775 1776 for (i = 0; i < src->textSrc.num_anchors; i++) 1777 if (src->textSrc.anchors[i] == anchor) 1778 break; 1779 1780 if (i == 0) 1781 return (src->textSrc.num_anchors > 1 ? src->textSrc.anchors[1] : NULL); 1782 1783 if (i < src->textSrc.num_anchors) { 1784 XtFree((XtPointer)anchor); 1785 if (i < --src->textSrc.num_anchors) { 1786 memmove(&src->textSrc.anchors[i], 1787 &src->textSrc.anchors[i + 1], 1788 (src->textSrc.num_anchors - i) * 1789 sizeof(XawTextAnchor*)); 1790 1791 return (src->textSrc.anchors[i]); 1792 } 1793 } 1794 1795 return (NULL); 1796} 1797 1798XawTextEntity * 1799XawTextSourceAddEntity(Widget w, int type, int flags, XtPointer data, 1800 XawTextPosition position, Cardinal length, 1801 XrmQuark property) 1802{ 1803 XawTextAnchor *next, *anchor = _XawTextSourceFindAnchor(w, position); 1804 XawTextEntity *entity, *eprev; 1805 1806 /* There is no support for zero length entities for now */ 1807 if (length == 0) 1808 return (NULL); 1809 1810 if (anchor->cache && anchor->position + anchor->cache->offset + 1811 anchor->cache->length <= position) 1812 eprev = entity = anchor->cache; 1813 else 1814 eprev = entity = anchor->entities; 1815 1816 while (entity && anchor->position + entity->offset + entity->length <= 1817 position) { 1818 eprev = entity; 1819 entity = entity->next; 1820 } 1821 if (entity && anchor->position + entity->offset < position + length) { 1822 fprintf(stderr, "Cannot (yet) add more than one entity to same region.\n"); 1823 return (NULL); 1824 } 1825 1826 next = XawTextSourceFindAnchor(w, position + length); 1827 if (next && next != anchor) { 1828 if ((entity = next->entities) != NULL) { 1829 if (next->position + entity->offset < position + length) { 1830 fprintf(stderr, "Cannot (yet) add more than one entity to same region.\n"); 1831 return (NULL); 1832 } 1833 } 1834 if (position + length > next->position) { 1835 XawTextPosition diff = position + length - next->position; 1836 1837 next->position += diff; 1838 entity = next->entities; 1839 while (entity) { 1840 entity->offset -= diff; 1841 entity = entity->next; 1842 } 1843 entity = anchor->entities; 1844 while (entity && entity->offset < 0) 1845 entity = entity->next; 1846 if (entity && entity->offset < 0) { 1847 if (eprev) 1848 eprev->next = next->entities; 1849 else 1850 anchor->entities = next->entities; 1851 if ((next->entities = entity->next) == NULL) 1852 (void)XawTextSourceRemoveAnchor(w, next); 1853 entity->next = NULL; 1854 1855 return (XawTextSourceAddEntity(w, type, flags, data, position, 1856 length, property)); 1857 } 1858 } 1859 } 1860 1861 /* Automatically join sequential entities if possible */ 1862 if (eprev && 1863 anchor->position + eprev->offset + eprev->length == position && 1864 eprev->property == property && eprev->type == type && 1865 eprev->flags == flags && eprev->data == data) { 1866 eprev->length += length; 1867 return (eprev); 1868 } 1869 1870 entity = XtNew(XawTextEntity); 1871 entity->type = type; 1872 entity->flags = flags; 1873 entity->data = data; 1874 entity->offset = position - anchor->position; 1875 entity->length = length; 1876 entity->property = property; 1877 1878 if (eprev == NULL) { 1879 anchor->entities = entity; 1880 entity->next = NULL; 1881 anchor->cache = NULL; 1882 } 1883 else if (eprev->offset > entity->offset) { 1884 anchor->cache = NULL; 1885 anchor->entities = entity; 1886 entity->next = eprev; 1887 } 1888 else { 1889 anchor->cache = eprev; 1890 entity->next = eprev->next; 1891 eprev->next = entity; 1892 } 1893 1894 return (entity); 1895} 1896 1897void 1898XawTextSourceClearEntities(Widget w, XawTextPosition left, XawTextPosition right) 1899{ 1900 XawTextAnchor *anchor = XawTextSourceFindAnchor(w, left); 1901 XawTextEntity *entity, *eprev, *enext; 1902 XawTextPosition offset; 1903 int length; 1904 1905 while (anchor && anchor->entities == NULL) 1906 anchor = XawTextSourceRemoveAnchor(w, anchor); 1907 1908 if (anchor == NULL || left >= right) 1909 return; 1910 1911 if (anchor->cache && anchor->position + anchor->cache->offset + 1912 anchor->cache->length < left) 1913 eprev = entity = anchor->cache; 1914 else 1915 eprev = entity = anchor->entities; 1916 1917 /* find first entity before left position */ 1918 while (anchor->position + entity->offset + entity->length < left) { 1919 eprev = entity; 1920 if ((entity = entity->next) == NULL) { 1921 if ((anchor = XawTextSourceNextAnchor(w, anchor)) == NULL) 1922 return; 1923 if ((eprev = entity = anchor->entities) == NULL) { 1924 fprintf(stderr, "Bad anchor found!\n"); 1925 return; 1926 } 1927 } 1928 } 1929 1930 offset = anchor->position + entity->offset; 1931 if (offset <= left) { 1932 length = XawMin(entity->length, left - offset); 1933 1934 if (length <= 0) { 1935 enext = entity->next; 1936 eprev->next = enext; 1937 XtFree((XtPointer)entity); 1938 anchor->cache = NULL; 1939 if (entity == anchor->entities) { 1940 eprev = NULL; 1941 if ((anchor->entities = enext) == NULL) { 1942 if ((anchor = XawTextSourceRemoveAnchor(w, anchor)) == NULL) 1943 return; 1944 entity = anchor->entities; 1945 } 1946 else 1947 entity = enext; 1948 } 1949 else 1950 entity = enext; 1951 } 1952 else { 1953 entity->length = length; 1954 eprev = entity; 1955 entity = entity->next; 1956 } 1957 } 1958 1959 /* clean everything until right position is reached */ 1960 while (anchor) { 1961 while (entity) { 1962 offset = anchor->position + entity->offset + entity->length; 1963 1964 if (offset > right) { 1965 anchor->cache = NULL; 1966 entity->offset = XawMax(entity->offset, right - anchor->position); 1967 entity->length = XawMin(entity->length, offset - right); 1968 return; 1969 } 1970 1971 enext = entity->next; 1972 if (eprev) 1973 eprev->next = enext; 1974 XtFree((XtPointer)entity); 1975 if (entity == anchor->entities) { 1976 eprev = anchor->cache = NULL; 1977 if ((anchor->entities = enext) == NULL) { 1978 if ((anchor = XawTextSourceRemoveAnchor(w, anchor)) == NULL) 1979 return; 1980 entity = anchor->entities; 1981 continue; 1982 } 1983 } 1984 entity = enext; 1985 } 1986 if (anchor) 1987 anchor->cache = NULL; 1988 if ((anchor = XawTextSourceNextAnchor(w, anchor)) != NULL) 1989 entity = anchor->entities; 1990 eprev = NULL; 1991 } 1992} 1993 1994/* checks the anchors up to position, and create an appropriate anchor 1995 * at position, if required. 1996 */ 1997XawTextAnchor * 1998_XawTextSourceFindAnchor(Widget w, XawTextPosition position) 1999{ 2000 XawTextAnchor *anchor; 2001 2002 anchor = XawTextSourceFindAnchor(w, position); 2003 2004 position -= position % ANCHORS_DIST; 2005 2006 if (position - anchor->position >= ANCHORS_DIST) 2007 return (XawTextSourceAddAnchor(w, position)); 2008 2009 return (anchor); 2010} 2011#endif 2012