TextAction.c revision 82d1c0e7
1/* 2 3Copyright 1989, 1994, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included in 12all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 21Except as contained in this notice, the name of The Open Group shall not be 22used in advertising or otherwise to promote the sale, use or other dealings 23in this Software without prior written authorization from The Open Group. 24 25*/ 26 27#ifdef HAVE_CONFIG_H 28#include <config.h> 29#endif 30#include <stdio.h> 31#include <stdlib.h> 32#include <unistd.h> 33#include <X11/Xos.h> /* for select() and struct timeval */ 34#include <ctype.h> 35#include <X11/IntrinsicP.h> 36#include <X11/StringDefs.h> 37#include <X11/Xatom.h> 38#include <X11/Xfuncs.h> 39#include <X11/Xutil.h> 40#include <X11/Xmu/Atoms.h> 41#include <X11/Xmu/Misc.h> 42#include <X11/Xmu/StdSel.h> 43#include <X11/Xaw/MultiSinkP.h> 44#include <X11/Xaw/MultiSrcP.h> 45#include <X11/Xaw/TextP.h> 46#include <X11/Xaw/TextSrcP.h> 47#include <X11/Xaw/XawImP.h> 48#include "Private.h" 49#include "XawI18n.h" 50 51#ifdef _WIN32 52#include <X11/Xwinsock.h> 53#endif 54 55#define SrcScan XawTextSourceScan 56#define FindDist XawTextSinkFindDistance 57#define FindPos XawTextSinkFindPosition 58#define MULT(w) (w->text.mult == 0 ? 4 : \ 59 w->text.mult == 32767 ? -4 : w->text.mult) 60 61#define KILL_RING_APPEND 2 62#define KILL_RING_BEGIN 3 63#define KILL_RING_YANK 100 64#define KILL_RING_YANK_DONE 98 65 66#define XawTextActionMaxHexChars 100 67 68/* 69 * Prototypes 70 */ 71static void _DeleteOrKill(TextWidget, XawTextPosition, XawTextPosition, Bool); 72static void _SelectionReceived(Widget, XtPointer, Atom*, Atom*, XtPointer, 73 unsigned long*, int*); 74static void _LoseSelection(Widget, Atom*, char**, int*); 75static void AutoFill(TextWidget); 76static Boolean ConvertSelection(Widget, Atom*, Atom*, Atom*, XtPointer*, 77 unsigned long*, int*); 78static void DeleteOrKill(TextWidget, XEvent*, XawTextScanDirection, 79 XawTextScanType, Bool, Bool); 80static void EndAction(TextWidget); 81#ifndef OLDXAW 82static Bool BlankLine(Widget, XawTextPosition, int*); 83static int DoFormatText(TextWidget, XawTextPosition, Bool, int, 84 XawTextBlock*, XawTextPosition*, int, Bool); 85static int FormatText(TextWidget, XawTextPosition, Bool, 86 XawTextPosition*, int); 87static Bool GetBlockBoundaries(TextWidget, XawTextPosition*, XawTextPosition*); 88#endif 89static int FormRegion(TextWidget, XawTextPosition, XawTextPosition, 90 XawTextPosition*, int); 91static void GetSelection(Widget, Time, String*, Cardinal); 92static char *IfHexConvertHexElseReturnParam(const char*, int*); 93static void InsertNewCRs(TextWidget, XawTextPosition, XawTextPosition, 94 XawTextPosition*, int); 95static int InsertNewLineAndBackupInternal(TextWidget); 96static int LocalInsertNewLine(TextWidget, XEvent*); 97static void LoseSelection(Widget, Atom*); 98static void ParameterError(Widget, String); 99static Bool MatchSelection(Atom, XawTextSelection*); 100static void ModifySelection(TextWidget, XEvent*, XawTextSelectionMode, 101 XawTextSelectionAction, String*, Cardinal*); 102static void Move(TextWidget, XEvent*, XawTextScanDirection, XawTextScanType, 103 Bool); 104static void NotePosition(TextWidget, XEvent*); 105static void StartAction(TextWidget, XEvent*); 106static XawTextPosition StripOutOldCRs(TextWidget, XawTextPosition, 107 XawTextPosition, XawTextPosition*, int); 108#ifndef OLDXAW 109static Bool StripSpaces(TextWidget, XawTextPosition, XawTextPosition, 110 XawTextPosition*, int, XawTextBlock*); 111static Bool Tabify(TextWidget, XawTextPosition, XawTextPosition, 112 XawTextPosition*, int, XawTextBlock*); 113static Bool Untabify(TextWidget, XawTextPosition, XawTextPosition, 114 XawTextPosition*, int, XawTextBlock*); 115#endif 116 117/* 118 * Actions 119 */ 120static void CapitalizeWord(Widget, XEvent*, String*, Cardinal*); 121static void DisplayCaret(Widget, XEvent*, String*, Cardinal*); 122static void Delete(Widget, XEvent*, String*, Cardinal*); 123static void DeleteBackwardChar(Widget, XEvent*, String*, Cardinal*); 124static void DeleteBackwardWord(Widget, XEvent*, String*, Cardinal*); 125static void DeleteCurrentSelection(Widget, XEvent*, String*, Cardinal*); 126static void DeleteForwardChar(Widget, XEvent*, String*, Cardinal*); 127static void DeleteForwardWord(Widget, XEvent*, String*, Cardinal*); 128static void DowncaseWord(Widget, XEvent*, String*, Cardinal*); 129static void ExtendAdjust(Widget, XEvent*, String*, Cardinal*); 130static void ExtendEnd(Widget, XEvent*, String*, Cardinal*); 131static void ExtendStart(Widget, XEvent*, String*, Cardinal*); 132static void FormParagraph(Widget, XEvent*, String*, Cardinal*); 133#ifndef OLDXAW 134static void Indent(Widget, XEvent*, String*, Cardinal*); 135#endif 136static void InsertChar(Widget, XEvent*, String*, Cardinal*); 137static void InsertNewLine(Widget, XEvent*, String*, Cardinal*); 138static void InsertNewLineAndBackup(Widget, XEvent*, String*, Cardinal*); 139static void InsertNewLineAndIndent(Widget, XEvent*, String*, Cardinal*); 140static void InsertSelection(Widget, XEvent*, String*, Cardinal*); 141static void InsertString(Widget, XEvent*, String*, Cardinal*); 142#ifndef OLDXAW 143static void KeyboardReset(Widget, XEvent*, String*, Cardinal*); 144#endif 145static void KillBackwardWord(Widget, XEvent*, String*, Cardinal*); 146static void KillCurrentSelection(Widget, XEvent*, String*, Cardinal*); 147static void KillForwardWord(Widget, XEvent*, String*, Cardinal*); 148#ifndef OLDXAW 149static void KillRingYank(Widget, XEvent*, String*, Cardinal*); 150#endif 151static void KillToEndOfLine(Widget, XEvent*, String*, Cardinal*); 152static void KillToEndOfParagraph(Widget, XEvent*, String*, Cardinal*); 153static void MoveBackwardChar(Widget, XEvent*, String*, Cardinal*); 154static void MoveBackwardWord(Widget, XEvent*, String*, Cardinal*); 155static void MoveBackwardParagraph(Widget, XEvent*, String*, Cardinal*); 156static void MoveBeginningOfFile(Widget, XEvent*, String*, Cardinal*); 157static void MoveEndOfFile(Widget, XEvent*, String*, Cardinal*); 158static void MoveForwardChar(Widget, XEvent*, String*, Cardinal*); 159static void MoveForwardWord(Widget, XEvent*, String*, Cardinal*); 160static void MoveForwardParagraph(Widget, XEvent*, String*, Cardinal*); 161static void MoveNextLine(Widget, XEvent*, String*, Cardinal*); 162static void MoveNextPage(Widget, XEvent*, String*, Cardinal*); 163static void MovePage(TextWidget, XEvent*, XawTextScanDirection); 164static void MovePreviousLine(Widget, XEvent*, String*, Cardinal*); 165static void MovePreviousPage(Widget, XEvent*, String*, Cardinal*); 166static void MoveLine(TextWidget, XEvent*, XawTextScanDirection); 167static void MoveToLineEnd(Widget, XEvent*, String*, Cardinal*); 168static void MoveToLineStart(Widget, XEvent*, String*, Cardinal*); 169static void Multiply(Widget, XEvent*, String*, Cardinal*); 170static void NoOp(Widget, XEvent*, String*, Cardinal*); 171#ifndef OLDXAW 172static void Numeric(Widget, XEvent*, String*, Cardinal*); 173#endif 174static void Reconnect(Widget, XEvent*, String*, Cardinal*); 175static void RedrawDisplay(Widget, XEvent*, String*, Cardinal*); 176static void Scroll(TextWidget, XEvent*, XawTextScanDirection); 177static void ScrollOneLineDown(Widget, XEvent*, String*, Cardinal*); 178static void ScrollOneLineUp(Widget, XEvent*, String*, Cardinal*); 179static void SelectAdjust(Widget, XEvent*, String*, Cardinal*); 180static void SelectAll(Widget, XEvent*, String*, Cardinal*); 181static void SelectEnd(Widget, XEvent*, String*, Cardinal*); 182static void SelectSave(Widget, XEvent*, String*, Cardinal*); 183static void SelectStart(Widget, XEvent*, String*, Cardinal*); 184static void SelectWord(Widget, XEvent*, String*, Cardinal*); 185static void SetKeyboardFocus(Widget, XEvent*, String*, Cardinal*); 186static void TextEnterWindow(Widget, XEvent*, String*, Cardinal*); 187static void TextFocusIn(Widget, XEvent*, String*, Cardinal*); 188static void TextFocusOut(Widget, XEvent*, String*, Cardinal*); 189static void TextLeaveWindow(Widget, XEvent*, String*, Cardinal*); 190static void TransposeCharacters(Widget, XEvent*, String*, Cardinal*); 191#ifndef OLDXAW 192static void ToggleOverwrite(Widget, XEvent*, String*, Cardinal*); 193static void Undo(Widget, XEvent*, String*, Cardinal*); 194#endif 195static void UpcaseWord(Widget, XEvent*, String*, Cardinal*); 196static void DestroyFocusCallback(Widget, XtPointer, XtPointer); 197 198/* 199 * External 200 */ 201void _XawTextZapSelection(TextWidget, XEvent*, Bool); 202 203/* 204 * Defined in TextPop.c 205 */ 206void _XawTextInsertFileAction(Widget, XEvent*, String*, Cardinal*); 207void _XawTextInsertFile(Widget, XEvent*, String*, Cardinal*); 208void _XawTextSearch(Widget, XEvent*, String*, Cardinal*); 209void _XawTextDoSearchAction(Widget, XEvent*, String*, Cardinal*); 210void _XawTextDoReplaceAction(Widget, XEvent*, String*, Cardinal*); 211void _XawTextSetField(Widget, XEvent*, String*, Cardinal*); 212void _XawTextPopdownSearchAction(Widget, XEvent*, String*, Cardinal*); 213 214/* 215 * These are defined in Text.c 216 */ 217void _XawTextAlterSelection(TextWidget, XawTextSelectionMode, 218 XawTextSelectionAction, String*, Cardinal*); 219void _XawTextClearAndCenterDisplay(TextWidget); 220void _XawTextExecuteUpdate(TextWidget); 221char *_XawTextGetText(TextWidget, XawTextPosition, XawTextPosition); 222void _XawTextPrepareToUpdate(TextWidget); 223int _XawTextReplace(TextWidget, XawTextPosition, XawTextPosition, 224 XawTextBlock*); 225Atom *_XawTextSelectionList(TextWidget, String*, Cardinal); 226void _XawTextSetSelection(TextWidget, XawTextPosition, XawTextPosition, 227 String*, Cardinal); 228void _XawTextVScroll(TextWidget, int); 229void XawTextScroll(TextWidget, int, int); 230void _XawTextSetLineAndColumnNumber(TextWidget, Bool); 231 232#ifndef OLDXAW 233/* 234 * Defined in TextSrc.c 235 */ 236Bool _XawTextSrcUndo(TextSrcObject, XawTextPosition*); 237Bool _XawTextSrcToggleUndo(TextSrcObject); 238void _XawSourceSetUndoErase(TextSrcObject, int); 239void _XawSourceSetUndoMerge(TextSrcObject, Bool); 240#endif /* OLDXAW */ 241 242/* 243 * Initialization 244 */ 245#ifndef OLDXAW 246#define MAX_KILL_RINGS 1024 247XawTextKillRing *xaw_text_kill_ring; 248static XawTextKillRing kill_ring_prev, kill_ring_null = { &kill_ring_prev, NULL, 0, 0, 0 }; 249static unsigned num_kill_rings; 250#endif 251 252/* 253 * Implementation 254 */ 255static void 256ParameterError(Widget w, String param) 257{ 258 String params[2]; 259 Cardinal num_params = 2; 260 params[0] = XtName(w); 261 params[1] = param; 262 263 XtAppWarningMsg(XtWidgetToApplicationContext(w), 264 "parameterError", "textAction", "XawError", 265 "Widget: %s Parameter: %s", 266 params, &num_params); 267 XBell(XtDisplay(w), 50); 268} 269 270static void 271StartAction(TextWidget ctx, XEvent *event) 272{ 273#ifndef OLDXAW 274 Cardinal i; 275 TextSrcObject src = (TextSrcObject)ctx->text.source; 276 277 for (i = 0; i < src->textSrc.num_text; i++) 278 _XawTextPrepareToUpdate((TextWidget)src->textSrc.text[i]); 279 _XawSourceSetUndoMerge(src, False); 280#else 281 _XawTextPrepareToUpdate(ctx); 282#endif 283 284 if (event != NULL) { 285 switch (event->type) { 286 case ButtonPress: 287 case ButtonRelease: 288 ctx->text.time = event->xbutton.time; 289 break; 290 case KeyPress: 291 case KeyRelease: 292 ctx->text.time = event->xkey.time; 293 break; 294 case MotionNotify: 295 ctx->text.time = event->xmotion.time; 296 break; 297 case EnterNotify: 298 case LeaveNotify: 299 ctx->text.time = event->xcrossing.time; 300 } 301 } 302} 303 304static void 305NotePosition(TextWidget ctx, XEvent *event) 306{ 307 switch (event->type) { 308 case ButtonPress: 309 case ButtonRelease: 310 ctx->text.ev_x = (Position)event->xbutton.x; 311 ctx->text.ev_y = (Position)event->xbutton.y; 312 break; 313 case KeyPress: 314 case KeyRelease: { 315 XRectangle cursor; 316 XawTextSinkGetCursorBounds(ctx->text.sink, &cursor); 317 ctx->text.ev_x = (Position)(cursor.x + cursor.width / 2); 318 ctx->text.ev_y = (Position)(cursor.y + cursor.height / 2); 319 } break; 320 case MotionNotify: 321 ctx->text.ev_x = (Position)(event->xmotion.x); 322 ctx->text.ev_y = (Position)(event->xmotion.y); 323 break; 324 case EnterNotify: 325 case LeaveNotify: 326 ctx->text.ev_x = (Position)(event->xcrossing.x); 327 ctx->text.ev_y = (Position)(event->xcrossing.y); 328 } 329} 330 331static void 332EndAction(TextWidget ctx) 333{ 334#ifndef OLDXAW 335 Cardinal i; 336 TextSrcObject src = (TextSrcObject)ctx->text.source; 337 338 for (i = 0; i < src->textSrc.num_text; i++) 339 _XawTextExecuteUpdate((TextWidget)src->textSrc.text[i]); 340 341 ctx->text.mult = 1; 342 ctx->text.numeric = False; 343 if (ctx->text.kill_ring) { 344 if (--ctx->text.kill_ring == KILL_RING_YANK_DONE) { 345 if (ctx->text.kill_ring_ptr) { 346 --ctx->text.kill_ring_ptr->refcount; 347 ctx->text.kill_ring_ptr = NULL; 348 } 349 } 350 } 351#else 352 ctx->text.mult = 1; 353 _XawTextExecuteUpdate(ctx); 354#endif /* OLDXAW */ 355} 356 357struct _SelectionList { 358 String* params; 359 Cardinal count; 360 Time time; 361 int asked; /* which selection currently has been asked for: 362 0 = UTF8_STRING, 1 = COMPOUND_TEXT, 2 = STRING */ 363 Atom selection; /* selection atom (normally XA_PRIMARY) */ 364}; 365 366/*ARGSUSED*/ 367static void 368_SelectionReceived(Widget w, XtPointer client_data, Atom *selection _X_UNUSED, 369 Atom *type, XtPointer value, unsigned long *length, 370 int *format _X_UNUSED) 371{ 372 Display *d = XtDisplay(w); 373 TextWidget ctx = (TextWidget)w; 374 XawTextBlock text; 375 376 if (*type == 0 /*XT_CONVERT_FAIL*/ || *length == 0) { 377 struct _SelectionList* list = (struct _SelectionList*)client_data; 378 379 if (list != NULL) { 380 if (list->asked == 0) { 381 /* If we just asked for XA_UTF8_STRING and got no response, 382 we'll ask again, this time for XA_COMPOUND_TEXT. */ 383 list->asked++; 384 XtGetSelectionValue(w, list->selection, XA_COMPOUND_TEXT(d), 385 _SelectionReceived, 386 (XtPointer)list, list->time); 387 } else if (list->asked == 1) { 388 /* If we just asked for XA_COMPOUND_TEXT and got no response, 389 we'll ask again, this time for XA_STRING. */ 390 list->asked++; 391 XtGetSelectionValue(w, list->selection, XA_STRING, 392 _SelectionReceived, 393 (XtPointer)list, list->time); 394 } else { 395 /* We tried all possible text targets in this param. 396 Recurse on the tail of the params list. */ 397 GetSelection(w, list->time, list->params, list->count); 398 XtFree(client_data); 399 } 400 } 401 return; 402 } 403 404 StartAction(ctx, NULL); 405 if (XawTextFormat(ctx, XawFmtWide)) { 406 wchar_t **wlist; 407 int count; 408 XTextProperty textprop = { 409 .encoding = *type, 410 .value = (unsigned char *)value, 411 .nitems = strlen(value), 412 .format = 8 413 }; 414 415 if (XwcTextPropertyToTextList(d, &textprop, &wlist, &count) 416 != Success 417 || count < 1) { 418 XwcFreeStringList(wlist); 419 420 /* Notify the user on strerr and in the insertion :) */ 421 fprintf(stderr, "Xaw Text Widget: An attempt was made to insert " 422 "an illegal selection.\n"); 423 424 textprop.value = (unsigned char *)" >> ILLEGAL SELECTION << "; 425 textprop.nitems = strlen((char *) textprop.value); 426 if (XwcTextPropertyToTextList(d, &textprop, &wlist, &count) 427 != Success 428 || count < 1) 429 return; 430 } 431 432 XFree(value); 433 value = (XPointer)wlist[0]; 434 435 *length = wcslen(wlist[0]); 436 XtFree((XtPointer)wlist); 437 text.format = XawFmtWide; 438 } 439 text.ptr = (char*)value; 440 text.firstPos = 0; 441 text.length = (int)*length; 442 if (_XawTextReplace(ctx, ctx->text.insertPos, ctx->text.insertPos, &text)) { 443 XBell(XtDisplay(ctx), 0); 444 EndAction(ctx); 445 return; 446 } 447 448 ctx->text.from_left = -1; 449 ctx->text.insertPos = SrcScan(ctx->text.source, ctx->text.old_insert, 450 XawstPositions, XawsdRight, text.length, True); 451 452 EndAction(ctx); 453 XtFree(client_data); 454 XFree(value); /* the selection value should be freed with XFree */ 455} 456 457static void 458GetSelection(Widget w, Time timev, String *params, Cardinal num_params) 459{ 460 Display *d = XtDisplay(w); 461 TextWidget ctx = (TextWidget)w; 462 Atom selection; 463 int buffer; 464 465 selection = XInternAtom(XtDisplay(w), *params, False); 466 switch (selection) { 467 case XA_CUT_BUFFER0: buffer = 0; break; 468 case XA_CUT_BUFFER1: buffer = 1; break; 469 case XA_CUT_BUFFER2: buffer = 2; break; 470 case XA_CUT_BUFFER3: buffer = 3; break; 471 case XA_CUT_BUFFER4: buffer = 4; break; 472 case XA_CUT_BUFFER5: buffer = 5; break; 473 case XA_CUT_BUFFER6: buffer = 6; break; 474 case XA_CUT_BUFFER7: buffer = 7; break; 475 default: buffer = -1; 476 } 477 if (buffer >= 0) { 478 int nbytes; 479 unsigned long length; 480 int fmt8 = 8; 481 Atom type = XA_STRING; 482 char *line = XFetchBuffer(XtDisplay(w), &nbytes, buffer); 483 484 if ((length = (unsigned long)nbytes) != 0L) 485 _SelectionReceived(w, NULL, &selection, &type, line, &length, &fmt8); 486 else if (num_params > 1) 487 GetSelection(w, timev, params+1, num_params-1); 488 } 489 else { 490 struct _SelectionList* list; 491 492 if (--num_params) { 493 list = XtNew(struct _SelectionList); 494 list->params = params + 1; 495 list->count = num_params; 496 list->time = timev; 497 list->asked = 0; 498 list->selection = selection; 499 } 500 else 501 list = NULL; 502 XtGetSelectionValue(w, selection, XawTextFormat(ctx, XawFmtWide) ? 503 XA_UTF8_STRING(d) : XA_TEXT(d), 504 _SelectionReceived, (XtPointer)list, timev); 505 } 506} 507 508static void 509InsertSelection(Widget w, XEvent *event, String *params, Cardinal *num_params) 510{ 511 StartAction((TextWidget)w, event); /* Get Time. */ 512 GetSelection(w, ((TextWidget)w)->text.time, params, *num_params); 513 EndAction((TextWidget)w); 514} 515 516/* 517 * Routines for Moving Around 518 */ 519static void 520Move(TextWidget ctx, XEvent *event, XawTextScanDirection dir, 521 XawTextScanType type, Bool include) 522{ 523 XawTextPosition insertPos; 524 short mult = MULT(ctx); 525 526 if (mult < 0) { 527 mult = (short)(-mult); 528 dir = dir == XawsdLeft ? XawsdRight : XawsdLeft; 529 } 530 531 insertPos = SrcScan(ctx->text.source, ctx->text.insertPos, 532 type, dir, mult, (Boolean)include); 533 534 StartAction(ctx, event); 535 536 if (ctx->text.s.left != ctx->text.s.right) 537 XawTextUnsetSelection((Widget)ctx); 538 539#ifndef OLDXAW 540 ctx->text.numeric = False; 541#endif 542 ctx->text.mult = 1; 543 ctx->text.showposition = True; 544 ctx->text.from_left = -1; 545 ctx->text.insertPos = insertPos; 546 EndAction(ctx); 547} 548 549/*ARGSUSED*/ 550static void 551MoveForwardChar(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED) 552{ 553 Move((TextWidget)w, event, XawsdRight, XawstPositions, True); 554} 555 556/*ARGSUSED*/ 557static void 558MoveBackwardChar(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED) 559{ 560 Move((TextWidget)w, event, XawsdLeft, XawstPositions, True); 561} 562 563static void 564MoveForwardWord(Widget w, XEvent *event, String *p, Cardinal *n) 565{ 566 if (*n && (p[0][0] == 'A' || p[0][0] == 'a')) 567 Move((TextWidget)w, event, XawsdRight, XawstAlphaNumeric, False); 568 else 569 Move((TextWidget)w, event, XawsdRight, XawstWhiteSpace, False); 570} 571 572static void 573MoveBackwardWord(Widget w, XEvent *event, String *p, Cardinal *n) 574{ 575 if (*n && (p[0][0] == 'A' || p[0][0] == 'a')) 576 Move((TextWidget)w, event, XawsdLeft, XawstAlphaNumeric, False); 577 else 578 Move((TextWidget)w, event, XawsdLeft, XawstWhiteSpace, False); 579} 580 581static void 582MoveForwardParagraph(Widget w, XEvent *event, String *p, Cardinal *n) 583{ 584 TextWidget ctx = (TextWidget)w; 585 XawTextPosition position = ctx->text.insertPos; 586 short mult = MULT(ctx); 587 588 if (mult < 0) { 589 ctx->text.mult = (short)(-mult); 590 MoveBackwardParagraph(w, event, p, n); 591 return; 592 } 593 594 while (mult--) { 595 position = SrcScan(ctx->text.source, position, 596 XawstEOL, XawsdRight, 1, False) - 1; 597 598 while (position == SrcScan(ctx->text.source, position, 599 XawstEOL, XawsdRight, 1, False)) 600 if (++position > ctx->text.lastPos) { 601 mult = 0; 602 break; 603 } 604 605 position = SrcScan(ctx->text.source, position, 606 XawstParagraph, XawsdRight, 1, True); 607 if (position != ctx->text.lastPos) 608 position = SrcScan(ctx->text.source, position - 1, 609 XawstEOL, XawsdLeft, 1, False); 610 else 611 break; 612 } 613 614 if (position != ctx->text.insertPos) { 615 XawTextUnsetSelection(w); 616 StartAction(ctx, event); 617 ctx->text.showposition = True; 618 ctx->text.from_left = -1; 619 ctx->text.insertPos = position; 620 EndAction(ctx); 621 } 622 else 623 ctx->text.mult = 1; 624} 625 626/*ARGSUSED*/ 627static void 628MoveBackwardParagraph(Widget w, XEvent *event, String *p, Cardinal *n) 629{ 630 TextWidget ctx = (TextWidget)w; 631 XawTextPosition position = ctx->text.insertPos; 632 short mult = MULT(ctx); 633 634 if (mult < 0) { 635 ctx->text.mult = (short)(-mult); 636 MoveForwardParagraph(w, event, p, n); 637 return; 638 } 639 640 while (mult--) { 641 position = SrcScan(ctx->text.source, position, 642 XawstEOL, XawsdLeft, 1, False) + 1; 643 644 while (position == SrcScan(ctx->text.source, position, 645 XawstEOL, XawsdLeft, 1, False)) 646 if (--position < 0) { 647 mult = 0; 648 break; 649 } 650 651 position = SrcScan(ctx->text.source, position, 652 XawstParagraph, XawsdLeft, 1, True); 653 if (position > 0 && position < ctx->text.lastPos) 654 ++position; 655 else 656 break; 657 } 658 659 if (position != ctx->text.insertPos) { 660 XawTextUnsetSelection(w); 661 StartAction(ctx, event); 662 ctx->text.showposition = True; 663 ctx->text.from_left = -1; 664 ctx->text.insertPos = position; 665 EndAction(ctx); 666 } 667 else 668 ctx->text.mult = 1; 669} 670 671/*ARGSUSED*/ 672static void 673MoveToLineEnd(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED) 674{ 675 Move((TextWidget)w, event, XawsdRight, XawstEOL, False); 676} 677 678/*ARGSUSED*/ 679static void 680MoveToLineStart(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED) 681{ 682 Move((TextWidget)w, event, XawsdLeft, XawstEOL, False); 683} 684 685static void 686MoveLine(TextWidget ctx, XEvent *event, XawTextScanDirection dir) 687{ 688 XawTextPosition cnew, next_line, ltemp; 689 int itemp, from_left; 690 short mult = MULT(ctx); 691 692 StartAction(ctx, event); 693 694 XawTextUnsetSelection((Widget)ctx); 695 696 if (dir == XawsdLeft) 697 mult = (short)((mult == 0) ? 5 : mult + 1); 698 699 cnew = SrcScan(ctx->text.source, ctx->text.insertPos, 700 XawstEOL, XawsdLeft, 1, False); 701 702 if (ctx->text.from_left < 0) 703 FindDist(ctx->text.sink, cnew, ctx->text.left_margin, ctx->text.insertPos, 704 &ctx->text.from_left, <emp, &itemp); 705 706 cnew = SrcScan(ctx->text.source, ctx->text.insertPos, XawstEOL, dir, 707 mult, (dir == XawsdRight)); 708 709 next_line = SrcScan(ctx->text.source, cnew, XawstEOL, XawsdRight, 1, False); 710 711 FindPos(ctx->text.sink, cnew, ctx->text.left_margin, ctx->text.from_left, 712 False, &ctx->text.insertPos, &from_left, &itemp); 713 714 if (from_left < ctx->text.from_left) { 715 XawTextBlock block; 716 717 XawTextSourceRead(ctx->text.source, ctx->text.insertPos, &block, 1); 718 if (block.length) { 719 if (XawTextFormat(ctx, XawFmtWide)) { 720 if (*(wchar_t *)block.ptr == _Xaw_atowc(XawTAB)) 721 ++ctx->text.insertPos; 722 } 723 else if (block.ptr[0] == XawTAB) 724 ++ctx->text.insertPos; 725 } 726 } 727 728 if (ctx->text.insertPos > next_line) 729 ctx->text.insertPos = next_line; 730 731 EndAction(ctx); 732} 733 734static void 735MoveNextLine(Widget w, XEvent *event, String *p, Cardinal *n) 736{ 737 TextWidget ctx = (TextWidget)w; 738 short mult = MULT(ctx); 739 740 if (mult < 0) { 741 ctx->text.mult = (short)(-mult); 742 MovePreviousLine(w, event, p, n); 743 return; 744 } 745 746 if (ctx->text.insertPos < ctx->text.lastPos) 747 MoveLine(ctx, event, XawsdRight); 748 else 749 ctx->text.mult = 1; 750} 751 752static void 753MovePreviousLine(Widget w, XEvent *event, String *p, Cardinal *n) 754{ 755 TextWidget ctx = (TextWidget)w; 756 short mult = MULT(ctx); 757 758 if (mult < 0) { 759 ctx->text.mult = (short)(-mult); 760 MoveNextLine(w, event, p, n); 761 return; 762 } 763 764 if (ctx->text.lt.top != 0 || (ctx->text.lt.lines > 1 && 765 ctx->text.insertPos >= ctx->text.lt.info[1].position)) 766 MoveLine(ctx, event, XawsdLeft); 767 else 768 ctx->text.mult = 1; 769} 770 771/*ARGSUSED*/ 772static void 773MoveBeginningOfFile(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED) 774{ 775 Move((TextWidget)w, event, XawsdLeft, XawstAll, True); 776} 777 778/*ARGSUSED*/ 779static void 780MoveEndOfFile(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED) 781{ 782 Move((TextWidget)w, event, XawsdRight, XawstAll, True); 783} 784 785static void 786Scroll(TextWidget ctx, XEvent *event, XawTextScanDirection dir) 787{ 788 short mult = MULT(ctx); 789 790 if (mult < 0) { 791 mult = (short)(-mult); 792 dir = dir == XawsdLeft ? XawsdRight : XawsdLeft; 793 } 794 795 if (ctx->text.lt.lines > 1 796 && (dir == XawsdRight 797 || ctx->text.lastPos >= ctx->text.lt.info[1].position)) { 798 StartAction(ctx, event); 799 800 if (dir == XawsdLeft) 801 _XawTextVScroll(ctx, mult); 802 else 803 _XawTextVScroll(ctx, -mult); 804 805 EndAction(ctx); 806 } 807 else { 808 ctx->text.mult = 1; 809#ifndef OLDXAW 810 ctx->text.numeric = False; 811#endif 812 } 813} 814 815/*ARGSUSED*/ 816static void 817ScrollOneLineUp(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED) 818{ 819 Scroll((TextWidget)w, event, XawsdLeft); 820} 821 822/*ARGSUSED*/ 823static void 824ScrollOneLineDown(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED) 825{ 826 Scroll((TextWidget)w, event, XawsdRight); 827} 828 829static void 830MovePage(TextWidget ctx, XEvent *event _X_UNUSED, XawTextScanDirection dir) 831{ 832 int scroll_val = 0; 833 XawTextPosition old_pos; 834 835 ctx->text.from_left = -1; 836 switch (dir) { 837 case XawsdLeft: 838 if (ctx->text.lt.top != 0) 839 scroll_val = -Max(1, ctx->text.lt.lines - 1); 840 break; 841 case XawsdRight: 842 if (!IsPositionVisible(ctx, Max(0, ctx->text.lastPos))) 843 scroll_val = Max(1, ctx->text.lt.lines - 1); 844 break; 845 } 846 847 if (scroll_val) 848 XawTextScroll(ctx, scroll_val, 849 ctx->text.left_margin - ctx->text.r_margin.left); 850 851 old_pos = ctx->text.insertPos; 852 switch (dir) { 853 case XawsdRight: 854 if (IsPositionVisible(ctx, Max(0, ctx->text.lastPos))) 855 ctx->text.insertPos = Max(0, ctx->text.lastPos); 856 else 857 ctx->text.insertPos = ctx->text.lt.top; 858 if (ctx->text.insertPos < old_pos) 859 ctx->text.insertPos = SrcScan(ctx->text.source, old_pos, 860 XawstEOL, XawsdLeft, 1, False); 861 break; 862 case XawsdLeft: 863 if (IsPositionVisible(ctx, 0)) 864 ctx->text.insertPos = 0; 865 else if (ctx->text.lt.lines) 866 ctx->text.insertPos = 867 ctx->text.lt.info[ctx->text.lt.lines - 1].position; 868 else 869 ctx->text.insertPos = ctx->text.lt.top; 870 if (ctx->text.insertPos > old_pos) 871 ctx->text.insertPos = SrcScan(ctx->text.source, old_pos, 872 XawstEOL, XawsdLeft, 1, False); 873 break; 874 } 875} 876 877static void 878MoveNextPage(Widget w, XEvent *event, String *p, Cardinal *n) 879{ 880 TextWidget ctx = (TextWidget)w; 881 short mult = MULT(ctx); 882 883 if (mult < 0) { 884 ctx->text.mult = (short)(-mult); 885 MovePreviousPage(w, event, p, n); 886 return; 887 } 888 889 if (ctx->text.insertPos < ctx->text.lastPos) { 890 XawTextUnsetSelection(w); 891 StartAction(ctx, event); 892 ctx->text.clear_to_eol = True; 893 while (mult-- && ctx->text.insertPos < ctx->text.lastPos) 894 MovePage(ctx, event, XawsdRight); 895 EndAction(ctx); 896 } 897 else 898 ctx->text.mult = 1; 899} 900 901/*ARGSUSED*/ 902static void 903MovePreviousPage(Widget w, XEvent *event, String *p, Cardinal *n) 904{ 905 TextWidget ctx = (TextWidget)w; 906 short mult = MULT(ctx); 907 908 if (mult < 0) { 909 ctx->text.mult = (short)(-mult); 910 MoveNextPage(w, event, p, n); 911 return; 912 } 913 914 if (ctx->text.insertPos > 0) { 915 XawTextUnsetSelection(w); 916 StartAction(ctx, event); 917 ctx->text.clear_to_eol = True; 918 while (mult-- && ctx->text.insertPos > 0) 919 MovePage(ctx, event, XawsdLeft); 920 EndAction(ctx); 921 } 922 else 923 ctx->text.mult = 1; 924} 925 926/* 927 * Delete Routines 928 */ 929static Bool 930MatchSelection(Atom selection, XawTextSelection *s) 931{ 932 Atom *match; 933 int count; 934 935 for (count = 0, match = s->selections; count < s->atom_count; 936 match++, count++) 937 if (*match == selection) 938 return (True); 939 940 return (False); 941} 942 943#define SrcCvtSel XawTextSourceConvertSelection 944 945static Boolean 946ConvertSelection(Widget w, Atom *selection, Atom *target, Atom *type, 947 XtPointer *value, unsigned long *length, int *format) 948{ 949 Display *d = XtDisplay(w); 950 TextWidget ctx = (TextWidget)w; 951 Widget src = ctx->text.source; 952 XawTextEditType edit_mode; 953 XawTextSelectionSalt *salt = NULL; 954 XawTextSelection *s; 955 956 if (*target == XA_TARGETS(d)) { 957 Atom *targetP, *std_targets; 958 unsigned long std_length; 959 960 if (SrcCvtSel(src, selection, target, type, value, length, format)) 961 return (True); 962 else { 963 Arg args[1]; 964 965 XtSetArg(args[0], XtNeditType,&edit_mode); 966 XtGetValues(src, args, 1); 967 } 968 969 XmuConvertStandardSelection(w, ctx->text.time, selection, 970 target, type, (XPointer *)&std_targets, 971 &std_length, format); 972 973 *length = (7 + (unsigned long)(edit_mode == XawtextEdit) + std_length); 974 *value = XtMalloc((Cardinal)((unsigned)sizeof(Atom)*(*length))); 975 targetP = *(Atom**)value; 976 *targetP++ = XA_STRING; 977 *targetP++ = XA_TEXT(d); 978 *targetP++ = XA_UTF8_STRING(d); 979 *targetP++ = XA_COMPOUND_TEXT(d); 980 *targetP++ = XA_LENGTH(d); 981 *targetP++ = XA_LIST_LENGTH(d); 982 *targetP++ = XA_CHARACTER_POSITION(d); 983 if (edit_mode == XawtextEdit) { 984 *targetP++ = XA_DELETE(d); 985 } 986 memcpy((char*)targetP, (char*)std_targets, sizeof(Atom)*std_length); 987 XtFree((char*)std_targets); 988 *type = XA_ATOM; 989 *format = 32; 990 return (True); 991 } 992 993 if (SrcCvtSel(src, selection, target, type, value, length, format)) 994 return (True); 995 996 for (salt = ctx->text.salt2; salt; salt = salt->next) 997 if (MatchSelection (*selection, &salt->s)) 998 break; 999 if (!salt) 1000 return (False); 1001 s = &salt->s; 1002 if (*target == XA_STRING 1003 || *target == XA_TEXT(d) 1004 || *target == XA_UTF8_STRING(d) 1005 || *target == XA_COMPOUND_TEXT(d)) { 1006 if (*target == XA_TEXT(d)) { 1007 if (XawTextFormat(ctx, XawFmtWide)) 1008 *type = XA_COMPOUND_TEXT(d); 1009 else 1010 *type = XA_STRING; 1011 } 1012 else 1013 *type = *target; 1014 1015 /* 1016 * If salt is True, the salt->contents stores CT string, 1017 * its length is measured in bytes. 1018 * Refer to _XawTextSaltAwaySelection() 1019 * 1020 * by Li Yuhong, Mar. 20, 1991. 1021 */ 1022 if (!salt) { 1023 *value = (char *)_XawTextGetSTRING(ctx, s->left, s->right); 1024 if (XawTextFormat(ctx, XawFmtWide)) { 1025 XTextProperty textprop; 1026 if (XwcTextListToTextProperty(d, (wchar_t**)value, 1, 1027 XCompoundTextStyle, &textprop) 1028 < Success) { 1029 XtFree(*value); 1030 return (False); 1031 } 1032 XtFree(*value); 1033 *value = (XtPointer)textprop.value; 1034 *length = textprop.nitems; 1035 } 1036 else 1037 *length = strlen(*value); 1038 } 1039 else { 1040 *value = XtMalloc((Cardinal)((size_t)(salt->length + 1) * sizeof(unsigned char))); 1041 strcpy (*value, salt->contents); 1042 *length = (unsigned long)salt->length; 1043 } 1044 /* Got *value,*length, now in COMPOUND_TEXT format. */ 1045 if (XawTextFormat(ctx, XawFmtWide)) { 1046 if (*type == XA_STRING) { 1047 wchar_t **wlist; 1048 int count; 1049 XTextProperty textprop = { 1050 .encoding = XA_COMPOUND_TEXT(d), 1051 .value = (unsigned char *)*value, 1052 .nitems = strlen(*value), 1053 .format = 8 1054 }; 1055 1056 if (XwcTextPropertyToTextList(d, &textprop, &wlist, &count) 1057 < Success 1058 || count < 1) { 1059 XtFree(*value); 1060 return (False); 1061 } 1062 XtFree(*value); 1063 if (XwcTextListToTextProperty(d, wlist, 1, XStringStyle, &textprop) 1064 < Success) { 1065 XwcFreeStringList((wchar_t**)wlist); 1066 return (False); 1067 } 1068 *value = (XtPointer)textprop.value; 1069 *length = textprop.nitems; 1070 XwcFreeStringList((wchar_t**) wlist); 1071 } 1072 else if (*type == XA_UTF8_STRING(d)) { 1073 char **list; 1074 int count; 1075 XTextProperty textprop = { 1076 .encoding = XA_COMPOUND_TEXT(d), 1077 .value = (unsigned char *)*value, 1078 .nitems = strlen(*value), 1079 .format = 8 1080 }; 1081 1082 if (Xutf8TextPropertyToTextList(d, &textprop, &list, &count) 1083 < Success 1084 || count < 1) { 1085 XtFree(*value); 1086 return (False); 1087 } 1088 XtFree(*value); 1089 *value = *list; 1090 *length = strlen(*list); 1091 XFree(list); 1092 } 1093 } 1094 *format = 8; 1095 return (True); 1096 } 1097 1098 if (*target == XA_LIST_LENGTH(d) || *target == XA_LENGTH(d)) { 1099 long *temp; 1100 1101 temp = (long *)XtMalloc(sizeof(long)); 1102 if (*target == XA_LIST_LENGTH(d)) 1103 *temp = 1L; 1104 else /* *target == XA_LENGTH(d) */ 1105 *temp = (long)(s->right - s->left); 1106 1107 *value = (XPointer)temp; 1108 *type = XA_INTEGER; 1109 *length = 1L; 1110 *format = 32; 1111 return (True); 1112 } 1113 1114 if (*target == XA_CHARACTER_POSITION(d)) { 1115 long *temp; 1116 1117 temp = (long *) XtMalloc(2 * sizeof(long)); 1118 temp[0] = (long)(s->left + 1); 1119 temp[1] = s->right; 1120 *value = (XPointer)temp; 1121 *type = XA_SPAN(d); 1122 *length = 2L; 1123 *format = 32; 1124 return (True); 1125 } 1126 1127 if (*target == XA_DELETE(d)) { 1128 if (!salt) 1129 _XawTextZapSelection(ctx, NULL, True); 1130 *value = NULL; 1131 *type = XA_NULL(d); 1132 *length = 0; 1133 *format = 32; 1134 return (True); 1135 } 1136 1137 if (XmuConvertStandardSelection(w, ctx->text.time, selection, target, type, 1138 (XPointer *)value, length, format)) 1139 return (True); 1140 1141 return (False); 1142} 1143 1144static void 1145LoseSelection(Widget w, Atom *selection) 1146{ 1147 _LoseSelection(w, selection, NULL, NULL); 1148} 1149 1150static void 1151_LoseSelection(Widget w, Atom *selection, char **contents _X_UNUSED, int *length _X_UNUSED) 1152{ 1153 TextWidget ctx = (TextWidget)w; 1154 Atom *atomP; 1155 int i; 1156 XawTextSelectionSalt *salt, *prevSalt, *nextSalt; 1157 1158 prevSalt = 0; 1159 for (salt = ctx->text.salt2; salt; salt = nextSalt) { 1160 atomP = salt->s.selections; 1161 nextSalt = salt->next; 1162 for (i = 0 ; i < salt->s.atom_count; i++, atomP++) 1163 if (*selection == *atomP) 1164 *atomP = (Atom)0; 1165 1166 while (salt->s.atom_count 1167 && salt->s.selections[salt->s.atom_count-1] == 0) 1168 salt->s.atom_count--; 1169 1170 /* 1171 * Must walk the selection list in opposite order from UnsetSelection. 1172 */ 1173 atomP = salt->s.selections; 1174 for (i = 0 ; i < salt->s.atom_count; i++, atomP++) 1175 if (*atomP == (Atom)0) { 1176 *atomP = salt->s.selections[--salt->s.atom_count]; 1177 1178 while (salt->s.atom_count 1179 && salt->s.selections[salt->s.atom_count-1] == 0) 1180 salt->s.atom_count--; 1181 } 1182 if (salt->s.atom_count == 0) { 1183#ifndef OLDXAW 1184 if (contents == NULL) { 1185 XawTextKillRing *kill_ring = XtNew(XawTextKillRing); 1186 1187 kill_ring->next = xaw_text_kill_ring; 1188 kill_ring->contents = salt->contents; 1189 kill_ring->length = salt->length; 1190 kill_ring->format = XawFmt8Bit; 1191 xaw_text_kill_ring = kill_ring; 1192 kill_ring_prev.next = xaw_text_kill_ring; 1193 1194 if (++num_kill_rings > MAX_KILL_RINGS) { 1195 XawTextKillRing *tail = NULL; 1196 1197 while (kill_ring->next) { 1198 tail = kill_ring; 1199 kill_ring = kill_ring->next; 1200 } 1201 if (tail != NULL && kill_ring->refcount == 0) { 1202 --num_kill_rings; 1203 tail->next = NULL; 1204 XtFree(kill_ring->contents); 1205 XtFree((char*)kill_ring); 1206 } 1207 } 1208 } 1209 else { 1210 *contents = salt->contents; 1211 *length = salt->length; 1212 } 1213#endif 1214 if (prevSalt) 1215 prevSalt->next = nextSalt; 1216 else 1217 ctx->text.salt2 = nextSalt; 1218 1219 XtFree((char *)salt->s.selections); 1220 XtFree((char *)salt); 1221 } 1222 else 1223 prevSalt = salt; 1224 } 1225} 1226 1227static void 1228_DeleteOrKill(TextWidget ctx, XawTextPosition from, XawTextPosition to, 1229 Bool kill) 1230{ 1231 XawTextBlock text; 1232 1233#ifndef OLDXAW 1234 if (ctx->text.kill_ring_ptr) { 1235 --ctx->text.kill_ring_ptr->refcount; 1236 ctx->text.kill_ring_ptr = NULL; 1237 } 1238#endif 1239 if (kill && from < to) { 1240#ifndef OLDXAW 1241 Bool append = False; 1242 char *ring = NULL; 1243 XawTextPosition old_from = from; 1244#endif 1245 char *string; 1246 int size = 0, length; 1247 XawTextSelectionSalt *salt; 1248 Atom selection = XInternAtom(XtDisplay(ctx), "SECONDARY", False); 1249 1250#ifndef OLDXAW 1251 if (ctx->text.kill_ring == KILL_RING_APPEND) { 1252 old_from = ctx->text.salt2->s.left; 1253 append = True; 1254 } 1255 else 1256 ctx->text.kill_ring = KILL_RING_BEGIN; 1257 1258 if (append) 1259 _LoseSelection((Widget)ctx, &selection, &ring, &size); 1260 else 1261#endif 1262 LoseSelection((Widget)ctx, &selection); 1263 1264 salt = (XawTextSelectionSalt*)XtMalloc(sizeof(XawTextSelectionSalt)); 1265 salt->s.selections = (Atom *)XtMalloc(sizeof(Atom)); 1266 salt->s.left = from; 1267 salt->s.right = to; 1268 1269 string = (char *)_XawTextGetSTRING(ctx, from, to); 1270 1271 if (XawTextFormat(ctx, XawFmtWide)) { 1272 XTextProperty textprop; 1273 1274 if (XwcTextListToTextProperty(XtDisplay((Widget)ctx), 1275 (wchar_t**)(&string), 1276 1, XCompoundTextStyle, 1277 &textprop) < Success) { 1278 XtFree(string); 1279 XtFree((char*)salt->s.selections); 1280 XtFree((char*)salt); 1281 return; 1282 } 1283 XtFree(string); 1284 string = (char *)textprop.value; 1285 length = (int)textprop.nitems; 1286 } 1287 else 1288 length = (int)strlen(string); 1289 1290 salt->length = length + size; 1291 1292#ifndef OLDXAW 1293 if (!append) 1294 salt->contents = string; 1295 else { 1296 salt->contents = XtMalloc((Cardinal)(length + size + 1)); 1297 if (from >= old_from) { 1298 if (ring != NULL) { 1299 strncpy(salt->contents, ring, (size_t)size); 1300 salt->contents[size] = '\0'; 1301 } else { 1302 salt->contents[size = 0] = '\0'; 1303 } 1304 strncat(salt->contents, string, (size_t)length); 1305 } 1306 else { 1307 strncpy(salt->contents, string, (size_t)length); 1308 salt->contents[length] = '\0'; 1309 if (ring != NULL) { 1310 strncat(salt->contents, ring, (size_t)size); 1311 } else { 1312 size = 0; 1313 } 1314 } 1315 salt->contents[length + size] = '\0'; 1316 XtFree(ring); 1317 XtFree(string); 1318 } 1319 1320 kill_ring_prev.contents = salt->contents; 1321 kill_ring_prev.length = salt->length; 1322 kill_ring_prev.format = XawFmt8Bit; 1323#else 1324 salt->contents = string; 1325#endif 1326 1327 salt->next = ctx->text.salt2; 1328 ctx->text.salt2 = salt; 1329 1330#ifndef OLDXAW 1331 if (append) 1332 ctx->text.kill_ring = KILL_RING_BEGIN; 1333#endif 1334 1335 salt->s.selections[0] = selection; 1336 1337 XtOwnSelection((Widget)ctx, selection, ctx->text.time, 1338 ConvertSelection, LoseSelection, NULL); 1339 salt->s.atom_count = 1; 1340 } 1341 text.length = 0; 1342 text.firstPos = 0; 1343 1344 text.format = (unsigned long)_XawTextFormat(ctx); 1345 text.ptr = (char*)""; 1346 1347 if (_XawTextReplace(ctx, from, to, &text)) { 1348 XBell(XtDisplay(ctx), 50); 1349 return; 1350 } 1351 ctx->text.from_left = -1; 1352 ctx->text.insertPos = from; 1353 ctx->text.showposition = TRUE; 1354} 1355 1356static void 1357DeleteOrKill(TextWidget ctx, XEvent *event, XawTextScanDirection dir, 1358 XawTextScanType type, Bool include, Bool kill) 1359{ 1360 XawTextPosition from, to; 1361 short mult = MULT(ctx); 1362 1363 if (mult < 0) { 1364 mult = (short)(-mult); 1365 dir = dir == XawsdLeft ? XawsdRight : XawsdLeft; 1366 } 1367 1368 StartAction(ctx, event); 1369#ifndef OLDXAW 1370 if (mult == 1) 1371 _XawSourceSetUndoMerge((TextSrcObject)ctx->text.source, True); 1372#endif 1373 to = SrcScan(ctx->text.source, ctx->text.insertPos, 1374 type, dir, mult, (Boolean)include); 1375 1376 /* 1377 * If no movement actually happened, then bump the count and try again. 1378 * This causes the character position at the very beginning and end of 1379 * a boundary to act correctly 1380 */ 1381 if (to == ctx->text.insertPos) 1382 to = SrcScan(ctx->text.source, ctx->text.insertPos, 1383 type, dir, mult + 1, (Boolean)include); 1384 1385 if (dir == XawsdLeft) { 1386 from = to; 1387 to = ctx->text.insertPos; 1388 } 1389 else 1390 from = ctx->text.insertPos; 1391 1392 _DeleteOrKill(ctx, from, to, kill); 1393 EndAction(ctx); 1394} 1395 1396static void 1397Delete(Widget w, XEvent *event, String *p, Cardinal *n) 1398{ 1399 TextWidget ctx = (TextWidget)w; 1400 1401 if (ctx->text.s.left != ctx->text.s.right) 1402 DeleteCurrentSelection(w, event, p, n); 1403 else 1404 DeleteBackwardChar(w, event, p, n); 1405} 1406 1407static void 1408DeleteChar(Widget w, XEvent *event, XawTextScanDirection dir) 1409{ 1410 TextWidget ctx = (TextWidget)w; 1411 short mul = MULT(ctx); 1412 1413 if (mul < 0) { 1414 mul = -mul; 1415 ctx->text.mult = mul; 1416 dir = dir == XawsdLeft ? XawsdRight : XawsdLeft; 1417 } 1418 DeleteOrKill(ctx, event, dir, XawstPositions, True, False); 1419#ifndef OLDXAW 1420 if (mul == 1) 1421 _XawSourceSetUndoErase((TextSrcObject)ctx->text.source, 1422 dir == XawsdLeft ? -1 : 1); 1423#endif 1424} 1425 1426/*ARGSUSED*/ 1427static void 1428DeleteForwardChar(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED) 1429{ 1430 DeleteChar(w, event, XawsdRight); 1431} 1432 1433/*ARGSUSED*/ 1434static void 1435DeleteBackwardChar(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED) 1436{ 1437 DeleteChar(w, event, XawsdLeft); 1438} 1439 1440static void 1441DeleteForwardWord(Widget w, XEvent *event, String *params, Cardinal *num_params) 1442{ 1443 XawTextScanType type; 1444 1445 if (*num_params && (*params[0] == 'A' || *params[0] == 'a')) 1446 type = XawstAlphaNumeric; 1447 else 1448 type = XawstWhiteSpace; 1449 1450 DeleteOrKill((TextWidget)w, event, XawsdRight, type, False, False); 1451} 1452 1453static void 1454DeleteBackwardWord(Widget w, XEvent *event, String *params, Cardinal *num_params) 1455{ 1456 XawTextScanType type; 1457 1458 if (*num_params && (*params[0] == 'A' || *params[0] == 'a')) 1459 type = XawstAlphaNumeric; 1460 else 1461 type = XawstWhiteSpace; 1462 1463 DeleteOrKill((TextWidget)w, event, XawsdLeft, type, False, False); 1464} 1465 1466static void 1467KillForwardWord(Widget w, XEvent *event, String *params, Cardinal *num_params) 1468{ 1469 XawTextScanType type; 1470 1471 if (*num_params && (*params[0] == 'A' || *params[0] == 'a')) 1472 type = XawstAlphaNumeric; 1473 else 1474 type = XawstWhiteSpace; 1475 1476 DeleteOrKill((TextWidget)w, event, XawsdRight, type, False, True); 1477} 1478 1479static void 1480KillBackwardWord(Widget w, XEvent *event, String *params, Cardinal *num_params) 1481{ 1482 XawTextScanType type; 1483 1484 if (*num_params && (*params[0] == 'A' || *params[0] == 'a')) 1485 type = XawstAlphaNumeric; 1486 else 1487 type = XawstWhiteSpace; 1488 1489 DeleteOrKill((TextWidget) w, event, XawsdLeft, type, False, True); 1490} 1491 1492/*ARGSUSED*/ 1493static void 1494KillToEndOfLine(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED) 1495{ 1496 TextWidget ctx = (TextWidget)w; 1497 XawTextPosition end_of_line; 1498 XawTextScanDirection dir = XawsdRight; 1499 short mult = MULT(ctx); 1500 1501 if (mult < 0) { 1502 dir = XawsdLeft; 1503 mult = (short)(-mult); 1504 } 1505 1506 StartAction(ctx, event); 1507 end_of_line = SrcScan(ctx->text.source, ctx->text.insertPos, XawstEOL, 1508 dir, mult, False); 1509 if (end_of_line == ctx->text.insertPos) 1510 end_of_line = SrcScan(ctx->text.source, ctx->text.insertPos, XawstEOL, 1511 dir, mult, True); 1512 1513 if (dir == XawsdRight) 1514 _DeleteOrKill(ctx, ctx->text.insertPos, end_of_line, True); 1515 else 1516 _DeleteOrKill(ctx, end_of_line, ctx->text.insertPos, True); 1517 EndAction(ctx); 1518} 1519 1520/*ARGSUSED*/ 1521static void 1522KillToEndOfParagraph(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED) 1523{ 1524 DeleteOrKill((TextWidget)w, event, XawsdRight, XawstParagraph, False, True); 1525} 1526 1527void 1528_XawTextZapSelection(TextWidget ctx, XEvent *event, Bool kill) 1529{ 1530 StartAction(ctx, event); 1531 _DeleteOrKill(ctx, ctx->text.s.left, ctx->text.s.right, kill); 1532 EndAction(ctx); 1533} 1534 1535/*ARGSUSED*/ 1536static void 1537KillCurrentSelection(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED) 1538{ 1539 _XawTextZapSelection((TextWidget) w, event, True); 1540} 1541 1542#ifndef OLDXAW 1543/*ARGSUSED*/ 1544static void 1545KillRingYank(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED) 1546{ 1547 TextWidget ctx = (TextWidget)w; 1548 XawTextPosition insertPos = ctx->text.insertPos; 1549 Bool first_yank = False; 1550 1551 if (ctx->text.s.left != ctx->text.s.right) 1552 XawTextUnsetSelection((Widget)ctx); 1553 1554 StartAction(ctx, event); 1555 1556 if (ctx->text.kill_ring_ptr == NULL) { 1557 ctx->text.kill_ring_ptr = &kill_ring_prev; 1558 ++ctx->text.kill_ring_ptr->refcount; 1559 ctx->text.s.left = ctx->text.s.right = insertPos; 1560 first_yank = True; 1561 } 1562 if (ctx->text.kill_ring_ptr) { 1563 int mul = MULT(ctx); 1564 XawTextBlock text; 1565 1566 if (!first_yank) { 1567 if (mul < 0) 1568 mul = 1; 1569 --ctx->text.kill_ring_ptr->refcount; 1570 while (mul--) { 1571 if ((ctx->text.kill_ring_ptr = ctx->text.kill_ring_ptr->next) == NULL) 1572 ctx->text.kill_ring_ptr = &kill_ring_null; 1573 } 1574 ++ctx->text.kill_ring_ptr->refcount; 1575 } 1576 text.firstPos = 0; 1577 text.length = ctx->text.kill_ring_ptr->length; 1578 text.ptr = ctx->text.kill_ring_ptr->contents; 1579 text.format = ctx->text.kill_ring_ptr->format; 1580 1581 if (_XawTextReplace(ctx, ctx->text.s.left, insertPos, &text) == XawEditDone) { 1582 ctx->text.kill_ring = KILL_RING_YANK; 1583 ctx->text.insertPos = ctx->text.s.left + text.length; 1584 } 1585 } 1586 else 1587 XBell(XtDisplay(w), 0); 1588 1589 EndAction(ctx); 1590} 1591#endif /* OLDXAW */ 1592 1593/*ARGSUSED*/ 1594static void 1595DeleteCurrentSelection(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED) 1596{ 1597 _XawTextZapSelection((TextWidget)w, event, False); 1598} 1599 1600#ifndef OLDXAW 1601#define CHECK_SAVE() \ 1602 if (save && !save->ptr) \ 1603 save->ptr = _XawTextGetText(ctx, save->firstPos, \ 1604 save->firstPos + save->length) 1605static Bool 1606StripSpaces(TextWidget ctx, XawTextPosition left, XawTextPosition right, 1607 XawTextPosition *pos, int num_pos, XawTextBlock *save) 1608{ 1609 Bool done, space; 1610 int i, cpos, count = 0; 1611 XawTextBlock block, text; 1612 XawTextPosition ipos, position = left, tmp = left; 1613 1614 text.firstPos = 0; 1615 text.format = XawFmt8Bit; 1616 text.ptr = (char*)" "; 1617 text.length = 1; 1618 1619 XawTextSourceRead(ctx->text.source, position, &block, (int)(right - left)); 1620 done = False; 1621 space = False; 1622 /* convert tabs and returns to spaces */ 1623 while (!done) { 1624 if (XawTextFormat(ctx, XawFmt8Bit)) { 1625 for (i = 0; i < block.length; i++) 1626 if (block.ptr[i] == '\t' || block.ptr[i] == '\n') { 1627 space = True; 1628 break; 1629 } 1630 } 1631 else { 1632 wchar_t *wptr = (wchar_t*)block.ptr; 1633 for (i = 0; i < block.length; i++) 1634 if (wptr[i] == _Xaw_atowc('\t') || wptr[i] == _Xaw_atowc('\n')) { 1635 space = True; 1636 break; 1637 } 1638 } 1639 if (space) { 1640 CHECK_SAVE(); 1641 if (_XawTextReplace(ctx, tmp + i, tmp + i + 1, &text)) 1642 return (False); 1643 space = False; 1644 } 1645 tmp += i; 1646 position = XawTextSourceRead(ctx->text.source, tmp, 1647 &block, (int)(right - tmp)); 1648 if (block.length == 0 || tmp == position || tmp >= right) 1649 done = True; 1650 } 1651 1652 text.ptr = (char*)""; 1653 text.length = 0; 1654 position = tmp = left; 1655 XawTextSourceRead(ctx->text.source, position, &block, (int)(right - left)); 1656 ipos = ctx->text.insertPos; 1657 done = False; 1658 while (!done) { 1659 if (XawTextFormat(ctx, XawFmt8Bit)) { 1660 for (i = 0; i < block.length; i++) 1661 if (block.ptr[i] == ' ') 1662 ++count; 1663 else if (count == 1) 1664 count = 0; 1665 else if (count) 1666 break; 1667 } 1668 else { 1669 wchar_t *wptr = (wchar_t*)block.ptr; 1670 for (i = 0; i < block.length; i++) 1671 if (wptr[i] == _Xaw_atowc(' ')) 1672 ++count; 1673 else if (count == 1) 1674 count = 0; 1675 else if (count) 1676 break; 1677 } 1678 if (--count > 0) { 1679 CHECK_SAVE(); 1680 if (_XawTextReplace(ctx, tmp + i - count, tmp + i, &text)) 1681 return (False); 1682 right -= count; 1683 if (num_pos) { 1684 for (cpos = 0; cpos < num_pos; cpos++) { 1685 if (tmp + i - count < pos[cpos]) { 1686 if (tmp + i < pos[cpos]) 1687 pos[cpos] -= count; 1688 else 1689 pos[cpos] = tmp + i - count; 1690 } 1691 } 1692 } 1693 else { 1694 if (tmp + i - count < ipos) { 1695 if (tmp + i < ipos) 1696 ipos -= count; 1697 else 1698 ipos = tmp + i - count; 1699 } 1700 } 1701 tmp += i - count; 1702 } 1703 else 1704 tmp += i + 1; 1705 count = 0; 1706 position = XawTextSourceRead(ctx->text.source, tmp, 1707 &block, (int)(right - tmp)); 1708 if (block.length == 0 || tmp == position || tmp >= right) 1709 done = True; 1710 } 1711 if (!num_pos) 1712 ctx->text.insertPos = ipos; 1713 1714 return (True); 1715} 1716 1717static Bool 1718Tabify(TextWidget ctx, XawTextPosition left, XawTextPosition right, 1719 XawTextPosition *pos, int num_pos, XawTextBlock *save) 1720{ 1721 Bool done, zero; 1722 int i, cpos, count = 0, column = 0, offset = 0; 1723 XawTextBlock text, block; 1724 XawTextPosition ipos, position = left, tmp = left; 1725 TextSinkObject sink = (TextSinkObject)ctx->text.sink; 1726 short *char_tabs = sink->text_sink.char_tabs; 1727 int tab_count = sink->text_sink.tab_count; 1728 int tab_index = 0, tab_column = 0, TAB_SIZE = DEFAULT_TAB_SIZE; 1729 1730 text.firstPos = 0; 1731 text.ptr = (char*)"\t"; 1732 text.format = XawFmt8Bit; 1733 text.length = 1; 1734 1735 XawTextSourceRead(ctx->text.source, position, &block, (int)(right - left)); 1736 ipos = ctx->text.insertPos; 1737 done = zero = False; 1738 if (tab_count) 1739 TAB_SIZE = *char_tabs; 1740 while (!done) { 1741 if (XawTextFormat(ctx, XawFmt8Bit)) { 1742 for (i = 0; i < block.length; i++) { 1743 ++offset; 1744 ++column; 1745 if (tab_count) { 1746 if (column > tab_column + char_tabs[tab_index]) { 1747 TAB_SIZE = tab_index < tab_count - 1 ? char_tabs[tab_index + 1] - char_tabs[tab_index] : *char_tabs; 1748 if (++tab_index >= tab_count) { 1749 tab_column += char_tabs[tab_count - 1]; 1750 tab_index = 0; 1751 } 1752 } 1753 } 1754 if (block.ptr[i] == ' ') { 1755 if (++count > TAB_SIZE) 1756 count %= TAB_SIZE; 1757 if ((tab_count && column == tab_column + char_tabs[tab_index]) || 1758 (!tab_count && column % TAB_SIZE == 0)) { 1759 if (count % (TAB_SIZE + 1) > 1) 1760 break; 1761 else 1762 count = 0; 1763 } 1764 } 1765 else { 1766 if (block.ptr[i] == '\n') { 1767 zero = True; 1768 break; 1769 } 1770 count = 0; 1771 } 1772 } 1773 } 1774 else { 1775 wchar_t *wptr = (wchar_t*)block.ptr; 1776 for (i = 0; i < block.length; i++) { 1777 ++offset; 1778 ++column; 1779 if (tab_count) { 1780 if (column > tab_column + char_tabs[tab_index]) { 1781 TAB_SIZE = tab_index < tab_count - 1 ? char_tabs[tab_index + 1] - char_tabs[tab_index] : *char_tabs; 1782 if (++tab_index >= tab_count) { 1783 tab_column += char_tabs[tab_count - 1]; 1784 tab_index = 0; 1785 } 1786 } 1787 } 1788 if (wptr[i] == _Xaw_atowc(' ')) { 1789 if (++count > TAB_SIZE) 1790 count %= TAB_SIZE; 1791 if ((tab_count && column == tab_column + char_tabs[tab_index]) || 1792 (!tab_count && column % TAB_SIZE == 0)) { 1793 if (count % (TAB_SIZE + 1) > 1) 1794 break; 1795 else 1796 count = 0; 1797 } 1798 } 1799 else { 1800 if (wptr[i] == _Xaw_atowc('\n')) { 1801 zero = True; 1802 break; 1803 } 1804 count = 0; 1805 } 1806 } 1807 } 1808 count %= TAB_SIZE + 1; 1809 if (!zero && count > 1 && i < block.length) { 1810 CHECK_SAVE(); 1811 if (_XawTextReplace(ctx, tmp + i - count + 1, tmp + i + 1, &text)) 1812 return (False); 1813 right -= count - 1; 1814 offset -= count - 1; 1815 if (num_pos) { 1816 for (cpos = 0; cpos < num_pos; cpos++) { 1817 if (tmp + i - count + 1 < pos[cpos]) { 1818 if (tmp + i + 1 < pos[cpos]) 1819 pos[cpos] -= count; 1820 else 1821 pos[cpos] = tmp + i - count + 1; 1822 ++pos[cpos]; 1823 } 1824 } 1825 } 1826 else { 1827 if (tmp + i - count + 1 < ipos) { 1828 if (tmp + i + 1 < ipos) 1829 ipos -= count; 1830 else 1831 ipos = tmp + i - count + 1; 1832 ++ipos; 1833 } 1834 } 1835 } 1836 if (count) 1837 --count; 1838 if (zero) { 1839 count = column = 0; 1840 zero = False; 1841 if (tab_count) { 1842 tab_column = tab_index = 0; 1843 TAB_SIZE = *char_tabs; 1844 } 1845 } 1846 else if (i < block.length) 1847 count = 0; 1848 tmp = left + offset; 1849 position = XawTextSourceRead(ctx->text.source, tmp, 1850 &block, (int)(right - tmp)); 1851 if (tmp == position || tmp >= right) 1852 done = True; 1853 } 1854 if (!num_pos) 1855 ctx->text.insertPos = ipos; 1856 1857 return (True); 1858} 1859 1860static Bool 1861Untabify(TextWidget ctx, XawTextPosition left, XawTextPosition right, 1862 XawTextPosition *pos, int num_pos, XawTextBlock *save) 1863{ 1864 Bool done, zero; 1865 int i, cpos, count = 0, diff = 0; 1866 XawTextBlock block, text; 1867 XawTextPosition ipos, position = left, tmp = left; 1868 TextSinkObject sink = (TextSinkObject)ctx->text.sink; 1869 short *char_tabs = sink->text_sink.char_tabs; 1870 int tab_count = sink->text_sink.tab_count; 1871 int tab_index = 0, tab_column = 0, tab_base = 0; 1872 static char *tabs = (char*)" "; 1873 1874 text.firstPos = 0; 1875 text.format = XawFmt8Bit; 1876 text.ptr = tabs; 1877 1878 XawTextSourceRead(ctx->text.source, position, &block, (int)(right - left)); 1879 ipos = ctx->text.insertPos; 1880 done = False; 1881 zero = False; 1882 while (!done) { 1883 if (XawTextFormat(ctx, XawFmt8Bit)) 1884 for (i = 0; i < block.length; i++) { 1885 if (block.ptr[i] != '\t') { 1886 ++count; 1887 if (block.ptr[i] == '\n') { 1888 zero = True; 1889 break; 1890 } 1891 } 1892 else 1893 break; 1894 } 1895 else { 1896 wchar_t *wptr = (wchar_t*)block.ptr; 1897 for (i = 0; i < block.length; i++) 1898 if (wptr[i] != _Xaw_atowc('\t')) { 1899 ++count; 1900 if (wptr[i] != _Xaw_atowc('\n')) { 1901 zero = True; 1902 break; 1903 } 1904 } 1905 else 1906 break; 1907 } 1908 if (!zero && i < block.length) { 1909 if (tab_count) { 1910 while (tab_base + tab_column <= count) { 1911 for (; tab_index < tab_count; ++tab_index) 1912 if (tab_base + char_tabs[tab_index] > count) { 1913 tab_column = char_tabs[tab_index]; 1914 break; 1915 } 1916 if (tab_index >= tab_count) { 1917 tab_base += char_tabs[tab_count - 1]; 1918 tab_column = tab_index = 0; 1919 } 1920 } 1921 text.length = (tab_base + tab_column) - count; 1922 if (text.length > 8) { 1923 int j; 1924 1925 text.ptr = XtMalloc((Cardinal)text.length); 1926 for (j = 0; j < text.length; j++) 1927 text.ptr[j] = ' '; 1928 } 1929 else 1930 text.ptr = tabs; 1931 } 1932 else 1933 text.length = DEFAULT_TAB_SIZE - (count % DEFAULT_TAB_SIZE); 1934 CHECK_SAVE(); 1935 if (_XawTextReplace(ctx, tmp + i, tmp + i + 1, &text)) { 1936 if (tab_count && text.length > 8) 1937 XtFree(text.ptr); 1938 return (False); 1939 } 1940 if (tab_count && text.length > 8) 1941 XtFree(text.ptr); 1942 count += text.length; 1943 right += text.length - 1; 1944 if (num_pos) { 1945 for (cpos = 0; cpos < num_pos; cpos++) { 1946 if (tmp + i < pos[cpos]) { 1947 if (tmp + i + 1 < pos[cpos]) 1948 --pos[cpos]; 1949 else 1950 pos[cpos] = tmp + i; 1951 pos[cpos] += text.length; 1952 } 1953 } 1954 } 1955 else { 1956 if (tmp + i < ipos) { 1957 if (tmp + i + 1 < ipos) 1958 --ipos; 1959 else 1960 ipos = tmp + i; 1961 ipos += text.length; 1962 } 1963 } 1964 } 1965 tmp = left + count + diff; 1966 if (zero) { 1967 diff += count; 1968 count = 0; 1969 zero = False; 1970 if (tab_count) 1971 tab_base = tab_column = tab_index = 0; 1972 } 1973 position = XawTextSourceRead(ctx->text.source, tmp, 1974 &block, (int)(right - tmp)); 1975 if (tmp == position || tmp >= right) 1976 done = True; 1977 } 1978 if (!num_pos) 1979 ctx->text.insertPos = ipos; 1980 1981 return (True); 1982} 1983 1984static int 1985FormatText(TextWidget ctx, XawTextPosition left, Bool force, 1986 XawTextPosition *pos, int num_pos) 1987{ 1988 char *ptr = NULL; 1989 Bool freepos = False, undo, paragraph = pos != NULL; 1990 int i, result; 1991 XawTextBlock block, *text; 1992 XawTextPosition end = ctx->text.lastPos, buf[32]; 1993 TextSrcObject src = (TextSrcObject)ctx->text.source; 1994 XawTextPosition right = SrcScan(ctx->text.source, left, XawstEOL, 1995 XawsdRight, 1, False); 1996 1997 undo = src->textSrc.enable_undo && src->textSrc.undo_state == False; 1998 if (undo) { 1999 if (!pos) { 2000 num_pos = (int)src->textSrc.num_text; 2001 pos = (XawStackAlloc(sizeof(XawTextPosition) * (size_t)num_pos, buf)); 2002 for (i = 0; i < num_pos; i++) 2003 pos[i] = ((TextWidget)src->textSrc.text[i])->text.insertPos; 2004 freepos = True; 2005 } 2006 else 2007 freepos = False; 2008 src->textSrc.undo_state = True; 2009 block.ptr = NULL; 2010 block.firstPos = (int)left; 2011 block.length = (int)(right - left); 2012 text = █ 2013 } 2014 else 2015 text = NULL; 2016 2017 result = DoFormatText(ctx, left, force, 1, text, pos, num_pos, paragraph); 2018 if (undo && result == XawEditDone && block.ptr) { 2019 char *lbuf, *rbuf; 2020 unsigned llen, rlen, size; 2021 2022 ptr = lbuf = block.ptr; 2023 llen = (unsigned)block.length; 2024 rlen = (unsigned)(llen + (ctx->text.lastPos - end)); 2025 2026 block.firstPos = 0; 2027 block.format = (unsigned long)_XawTextFormat(ctx); 2028 2029 rbuf = _XawTextGetText(ctx, left, left + rlen); 2030 2031 size = XawTextFormat(ctx, XawFmtWide) ? sizeof(wchar_t) : sizeof(char); 2032 if (llen != rlen || memcmp(lbuf, rbuf, llen * size)) { 2033 block.ptr = lbuf; 2034 block.length = (int)llen; 2035 _XawTextReplace(ctx, left, left + rlen, &block); 2036 2037 src->textSrc.undo_state = False; 2038 block.ptr = rbuf; 2039 block.length = (int)rlen; 2040 _XawTextReplace(ctx, left, left + llen, &block); 2041 } 2042 else 2043 src->textSrc.undo_state = False; 2044 XtFree(rbuf); 2045 } 2046 if (undo) { 2047 src->textSrc.undo_state = False; 2048 if (freepos) { 2049 for (i = 0; i < num_pos; i++) { 2050 TextWidget tw = (TextWidget)src->textSrc.text[i]; 2051 tw->text.insertPos = XawMin(XawMax(0, pos[i]), tw->text.lastPos); 2052 } 2053 XawStackFree(pos, buf); 2054 } 2055 if (ptr) 2056 XtFree(ptr); 2057 } 2058 2059 return (result); 2060} 2061 2062static int 2063DoFormatText(TextWidget ctx, XawTextPosition left, Bool force, int level, 2064 XawTextBlock *save, XawTextPosition *pos, int num_pos, 2065 Bool paragraph) 2066{ 2067 XawTextPosition right = SrcScan(ctx->text.source, left, XawstEOL, 2068 XawsdRight, 1, False); 2069 XawTextPosition position, tmp, ipos; 2070 XawTextBlock block, text; 2071 char buf[128]; 2072 wchar_t *wptr; 2073 int i, count, cpos; 2074 Bool done, force2 = force, recurse = False; 2075 2076 position = XawTextSourceRead(ctx->text.source, left, &block, (int)(right - left)); 2077 if (block.length == 0 || left >= right || 2078 (level == 1 && ((XawTextFormat(ctx, XawFmt8Bit) && 2079 block.ptr[0] != ' ' && 2080 block.ptr[0] != '\t' && 2081 !isalnum(*(unsigned char*)block.ptr)) || 2082 (XawTextFormat(ctx, XawFmtWide) && 2083 _Xaw_atowc(XawSP) != *(wchar_t*)block.ptr && 2084 _Xaw_atowc(XawTAB) != *(wchar_t*)block.ptr && 2085 !iswalnum((wint_t)*(wchar_t*)block.ptr))))) 2086 return (XawEditDone); 2087 2088 if (level == 1 && !paragraph) { 2089 tmp = ctx->text.lastPos; 2090 if (Untabify(ctx, left, right, pos, num_pos, save) == False) 2091 return (XawEditError); 2092 right += ctx->text.lastPos - tmp; 2093 position = XawTextSourceRead(ctx->text.source, left, &block, 2094 (int)(right - left)); 2095 } 2096 2097 text.firstPos = 0; 2098 text.format = XawFmt8Bit; 2099 2100 ipos = ctx->text.insertPos; 2101 count = 0; 2102 done = False; 2103 while (!done) { 2104 if (XawTextFormat(ctx, XawFmt8Bit)) { 2105 for (i = 0; i < block.length; i++) 2106 if (block.ptr[i] == ' ') 2107 ++count; 2108 else { 2109 done = True; 2110 break; 2111 } 2112 } 2113 else { 2114 wptr = (wchar_t*)block.ptr; 2115 for (i = 0; i < block.length; i++) 2116 if (wptr[i] == _Xaw_atowc(' ')) 2117 ++count; 2118 else { 2119 done = True; 2120 break; 2121 } 2122 } 2123 tmp = position; 2124 position = XawTextSourceRead(ctx->text.source, position, 2125 &block, (int)(right - position)); 2126 if (tmp == position) 2127 done = True; 2128 } 2129 position = left + count; 2130 if (count < ctx->text.left_column) { 2131 int bytes = ctx->text.left_column - count; 2132 2133 text.ptr = XawStackAlloc((unsigned)bytes, buf); 2134 text.length = bytes; 2135 for (i = 0; i < bytes; i++) 2136 text.ptr[i] = ' '; 2137 CHECK_SAVE(); 2138 if (_XawTextReplace(ctx, left, left, &text)) { 2139 XawStackFree(text.ptr, buf); 2140 return (XawEditError); 2141 } 2142 XawStackFree(text.ptr, buf); 2143 right += bytes; 2144 if (num_pos) { 2145 for (cpos = 0; cpos < num_pos; cpos++) 2146 if (pos[cpos] >= left) 2147 pos[cpos] += bytes; 2148 } 2149 if (ipos >= left) 2150 ipos += bytes; 2151 count += bytes; 2152 } 2153 2154 done = False; 2155 if (!paragraph && level == 1 2156 && ipos <= right && ipos - left > ctx->text.right_column) { 2157 XawTextPosition len = ctx->text.lastPos; 2158 int skip = ctx->text.justify == XawjustifyRight 2159 || ctx->text.justify == XawjustifyCenter ? 2160 ctx->text.left_column : count; 2161 2162 if (pos) 2163 for (i = 0; i < num_pos; i++) 2164 if (pos[i] == ipos) 2165 break; 2166 2167 StripSpaces(ctx, left + skip, right, pos, num_pos, save); 2168 right += ctx->text.lastPos - len; 2169 if (pos && i < num_pos) 2170 ipos = pos[i]; 2171 else 2172 ipos = ctx->text.insertPos; 2173 done = ipos - left > ctx->text.right_column; 2174 count = skip + (count == skip + 1); 2175 } 2176 if ((paragraph || done) && right - left > ctx->text.right_column) { 2177 position = tmp = right; 2178 XawTextSourceRead(ctx->text.source, position - 1, &block, 1); 2179 if (block.length && 2180 ((XawTextFormat(ctx, XawFmt8Bit) && 2181 block.ptr[0] == ' ') || 2182 (XawTextFormat(ctx, XawFmtWide) && 2183 _Xaw_atowc(XawSP) == *(wchar_t*)block.ptr))) 2184 --position; 2185 while (position - left > ctx->text.right_column) { 2186 tmp = position; 2187 position = SrcScan(ctx->text.source, position, 2188 XawstWhiteSpace, XawsdLeft, 1, True); 2189 } 2190 if (position <= left + ctx->text.left_column) 2191 position = tmp; 2192 if (position > left && position - left > ctx->text.left_column 2193 && position != right) { 2194 text.ptr = (char*)"\n"; 2195 text.length = 1; 2196 CHECK_SAVE(); 2197 if (_XawTextReplace(ctx, position, position + 1, &text)) 2198 return (XawEditError); 2199 right = position; 2200 recurse = True; 2201 force = True; 2202 } 2203 } 2204 2205 if (force) { 2206 if (ctx->text.justify == XawjustifyCenter) 2207 count = ctx->text.right_column - (count - ctx->text.left_column); 2208 else 2209 count = ctx->text.right_column; 2210 if (count > right - left) 2211 count = (int)(count - (right - left)); 2212 else 2213 count = 0; 2214 } 2215 else 2216 count = 0; 2217 if (count > 0) { 2218 switch (ctx->text.justify) { 2219 case XawjustifyLeft: 2220 break; 2221 case XawjustifyRight: 2222 case XawjustifyCenter: 2223 if (ctx->text.justify == XawjustifyCenter) { 2224 int alnum = 0; 2225 2226 if (!(count & 1)) { 2227 XawTextSourceRead(ctx->text.source, right, &block, 1); 2228 if ((XawTextFormat(ctx, XawFmt8Bit) 2229 && isalnum(*(unsigned char*)block.ptr)) || 2230 (XawTextFormat(ctx, XawFmtWide) 2231 && iswalnum((wint_t)*(wchar_t*)block.ptr))) 2232 alnum = 1; 2233 } 2234 count = (count + alnum) >> 1; 2235 } 2236 text.ptr = XawStackAlloc((unsigned)count, buf); 2237 text.length = count; 2238 for (i = 0; i < count; i++) 2239 text.ptr[i] = ' '; 2240 CHECK_SAVE(); 2241 if (_XawTextReplace(ctx, left, left, &text)) { 2242 XawStackFree(text.ptr, buf); 2243 return (XawEditError); 2244 } 2245 XawStackFree(text.ptr, buf); 2246 position += count; 2247 if (num_pos) { 2248 for (cpos = 0; cpos < num_pos; cpos++) 2249 if (pos[cpos] > left) 2250 pos[cpos] += count; 2251 } 2252 else if (ipos > left) 2253 ipos += count; 2254 break; 2255 case XawjustifyFull: 2256 i = 0; 2257 tmp = left; 2258 /*CONSTCOND*/ 2259 while (True) { 2260 tmp = SrcScan(ctx->text.source, tmp, XawstWhiteSpace, 2261 XawsdRight, 1, True); 2262 if (tmp < right) 2263 ++i; 2264 else 2265 break; 2266 } 2267 if (i) { 2268 double inc, ii; 2269 int bytes, steps; 2270 2271 bytes = count; 2272 inc = ii = (count + .5) / (double)i; 2273 2274 steps = count; 2275 text.ptr = XawStackAlloc((unsigned)steps, buf); 2276 for (i = 0; i < steps; i++) 2277 text.ptr[i] = ' '; 2278 tmp = left; 2279 CHECK_SAVE(); 2280 while (bytes) { 2281 steps = 1; 2282 while (inc + ii < 1) { 2283 ++steps; 2284 inc += ii; 2285 } 2286 tmp = SrcScan(ctx->text.source, tmp, XawstWhiteSpace, 2287 XawsdRight, steps, True); 2288 if (bytes > inc) 2289 text.length = (int)inc; 2290 else 2291 text.length = bytes; 2292 bytes -= text.length; 2293 if (_XawTextReplace(ctx, tmp, tmp, &text)) { 2294 XawStackFree(text.ptr, buf); 2295 return (XawEditError); 2296 } 2297 if (num_pos) { 2298 for (cpos = 0; cpos < num_pos; cpos++) 2299 if (tmp <= pos[cpos]) 2300 pos[cpos] += text.length; 2301 } 2302 else if (tmp <= ipos) 2303 ipos += text.length; 2304 inc -= (int)inc; 2305 inc += ii; 2306 } 2307 position += count; 2308 XawStackFree(text.ptr, buf); 2309 } 2310 break; 2311 } 2312 } 2313 2314 if (!num_pos) 2315 ctx->text.insertPos = XawMin(ipos, ctx->text.lastPos); 2316 2317 return (recurse ? DoFormatText(ctx, position + 1, 2318 ctx->text.justify != XawjustifyFull 2319 && (force2 || paragraph), 2320 ++level, save, pos, num_pos, paragraph) 2321 : XawEditDone); 2322} 2323#undef CHECK_SAVE 2324 2325/*ARGSUSED*/ 2326static void 2327Indent(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED) 2328{ 2329 TextWidget ctx = (TextWidget)w; 2330 TextSrcObject src = (TextSrcObject)ctx->text.source; 2331 XawTextPosition from, to, tmp, end = 0, *pos, *posbuf[32]; 2332 XawTextBlock text; 2333 int i, spaces = MULT(ctx); 2334 char *lbuf = NULL, *rbuf; 2335 unsigned llen = 0; 2336 Bool undo = src->textSrc.enable_undo && src->textSrc.undo_state == False; 2337 Bool format = ctx->text.auto_fill 2338 && ctx->text.left_column < ctx->text.right_column; 2339 2340 text.firstPos = 0; 2341 text.format = XawFmt8Bit; 2342 text.ptr = (char*)""; 2343 2344 StartAction(ctx, event); 2345 2346 pos = XawStackAlloc(sizeof(XawTextPosition) * src->textSrc.num_text, posbuf); 2347 for (i = 0; (Cardinal)i < src->textSrc.num_text; i++) 2348 pos[i] = ((TextWidget)src->textSrc.text[i])->text.insertPos; 2349 2350 if (!GetBlockBoundaries(ctx, &from, &to)) { 2351 EndAction(ctx); 2352 XawStackFree(pos, posbuf); 2353 return; 2354 } 2355 2356 if (undo) { 2357 llen = (unsigned)(to - from); 2358 end = ctx->text.lastPos; 2359 lbuf = _XawTextGetText(ctx, from, to); 2360 src->textSrc.undo_state = True; 2361 } 2362 2363 tmp = ctx->text.lastPos; 2364 if (!Untabify(ctx, from, to, pos, (int)src->textSrc.num_text, NULL)) { 2365 XBell(XtDisplay(ctx), 0); 2366 EndAction(ctx); 2367 XawStackFree(pos, posbuf); 2368 if (undo) { 2369 src->textSrc.undo_state = True; 2370 XtFree(lbuf); 2371 } 2372 return; 2373 } 2374 to += ctx->text.lastPos - tmp; 2375 2376 tmp = from; 2377 2378 if (spaces > 0) { 2379 char buf[32]; 2380 2381 text.ptr = XawStackAlloc((unsigned)spaces, buf); 2382 for (i = 0; i < spaces; i++) 2383 text.ptr[i] = ' '; 2384 2385 text.length = spaces; 2386 while (tmp < to) { 2387 _XawTextReplace(ctx, tmp, tmp, &text); 2388 2389 for (i = 0; (Cardinal)i < src->textSrc.num_text; i++) 2390 if (tmp < pos[i]) 2391 pos[i] += spaces; 2392 2393 to += spaces; 2394 tmp = SrcScan(ctx->text.source, tmp, XawstEOL, XawsdRight, 1, True); 2395 } 2396 XawStackFree(text.ptr, buf); 2397 } 2398 else { 2399 int min = 32767; 2400 2401 text.length = 0; 2402 tmp = from; 2403 2404 /* find the amount of spaces to cut */ 2405 while (tmp < to) { 2406 (void)BlankLine(w, tmp, &i); 2407 if (i < min) 2408 min = i; 2409 tmp = SrcScan(ctx->text.source, tmp, XawstEOL, XawsdRight, 1, True); 2410 } 2411 spaces = XawMin(-spaces, min); 2412 2413 /* cut the spaces */ 2414 tmp = from; 2415 while (tmp < to) { 2416 _XawTextReplace(ctx, tmp, tmp + spaces, &text); 2417 2418 for (i = 0; (Cardinal)i < src->textSrc.num_text; i++) 2419 if (tmp < pos[i]) { 2420 if (tmp + spaces < pos[i]) 2421 pos[i] -= spaces; 2422 else 2423 pos[i] = tmp; 2424 } 2425 2426 to -= spaces; 2427 tmp = SrcScan(ctx->text.source, tmp, XawstEOL, XawsdRight, 1, True); 2428 } 2429 } 2430 2431 if (!format) 2432 Tabify(ctx, from, to, pos, (int)src->textSrc.num_text, NULL); 2433 2434 if (undo) { 2435 unsigned rlen = (unsigned)(llen + (ctx->text.lastPos - end)); 2436 unsigned size; 2437 2438 rbuf = _XawTextGetText(ctx, from, from + rlen); 2439 2440 text.format = (unsigned long)_XawTextFormat(ctx); 2441 size = XawTextFormat(ctx, XawFmtWide) ? sizeof(wchar_t) : sizeof(char); 2442 if (llen != rlen || memcmp(lbuf, rbuf, llen * size)) { 2443 text.ptr = lbuf; 2444 text.length = (int)llen; 2445 _XawTextReplace(ctx, from, from + rlen, &text); 2446 2447 src->textSrc.undo_state = False; 2448 text.ptr = rbuf; 2449 text.length = (int)rlen; 2450 _XawTextReplace(ctx, from, from + llen, &text); 2451 } 2452 else 2453 src->textSrc.undo_state = False; 2454 XtFree(lbuf); 2455 XtFree(rbuf); 2456 } 2457 2458 for (i = 0; (Cardinal)i < src->textSrc.num_text; i++) { 2459 TextWidget tw = (TextWidget)src->textSrc.text[i]; 2460 2461 tw->text.insertPos = XawMin(XawMax(0, pos[i]), tw->text.lastPos); 2462 } 2463 XawStackFree(pos, posbuf); 2464 ctx->text.showposition = True; 2465 2466 EndAction(ctx); 2467} 2468 2469/*ARGSUSED*/ 2470static void 2471ToggleOverwrite(Widget w, XEvent *event _X_UNUSED, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED) 2472{ 2473 TextWidget ctx = (TextWidget)w; 2474 2475 ctx->text.overwrite = !ctx->text.overwrite; 2476 2477 /* call information callback */ 2478 _XawTextSetLineAndColumnNumber(ctx, True); 2479} 2480#endif /* OLDXAW */ 2481 2482/* 2483 * Insertion Routines 2484 */ 2485static int 2486InsertNewLineAndBackupInternal(TextWidget ctx) 2487{ 2488 int count, error = XawEditDone, mult = MULT(ctx); 2489#ifndef OLDXAW 2490 XawTextPosition position; 2491#endif 2492 XawTextBlock text; 2493 char buf[32]; 2494 2495 if (mult < 0) { 2496 ctx->text.mult = 1; 2497 return (XawEditError); 2498 } 2499 2500 text.format = (unsigned long)_XawTextFormat(ctx); 2501 text.length = mult; 2502 text.firstPos = 0; 2503 2504 if (text.format == XawFmtWide) { 2505 wchar_t *wptr; 2506 2507 text.ptr = (XawStackAlloc(sizeof(wchar_t) * (size_t)mult, buf)); 2508 wptr = (wchar_t *)text.ptr; 2509 for (count = 0; count < mult; count++) 2510 wptr[count] = _Xaw_atowc(XawLF); 2511 } 2512 else { 2513 text.ptr = (XawStackAlloc(sizeof(char) * (size_t)mult, buf)); 2514 for (count = 0; count < mult; count++) 2515 text.ptr[count] = XawLF; 2516 } 2517 2518#ifndef OLDXAW 2519 position = SrcScan(ctx->text.source, ctx->text.insertPos, 2520 XawstEOL, XawsdLeft, 1, False); 2521#endif 2522 if (_XawTextReplace(ctx, ctx->text.insertPos, ctx->text.insertPos, &text)) { 2523 XBell( XtDisplay(ctx), 50); 2524 error = XawEditError; 2525 } 2526 else { 2527 ctx->text.showposition = TRUE; 2528 ctx->text.insertPos += text.length; 2529 } 2530 2531 XawStackFree(text.ptr, buf); 2532 2533#ifndef OLDXAW 2534 if (ctx->text.auto_fill && error == XawEditDone) 2535 (void)FormatText(ctx, position, ctx->text.justify != XawjustifyFull, 2536 NULL, 0); 2537#endif 2538 2539 return (error); 2540} 2541 2542/*ARGSUSED*/ 2543static void 2544InsertNewLineAndBackup(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED) 2545{ 2546 TextWidget ctx = (TextWidget)w; 2547 XawTextPosition insertPos = ctx->text.insertPos; 2548 2549 StartAction((TextWidget)w, event); 2550 (void)InsertNewLineAndBackupInternal(ctx); 2551 ctx->text.insertPos = SrcScan(ctx->text.source, insertPos, XawstEOL, 2552 XawsdRight, 1, False); 2553 EndAction((TextWidget)w); 2554} 2555 2556static int 2557LocalInsertNewLine(TextWidget ctx, XEvent *event) 2558{ 2559 int error; 2560 2561 StartAction(ctx, event); 2562 error = InsertNewLineAndBackupInternal(ctx); 2563 ctx->text.from_left = -1; 2564 EndAction(ctx); 2565 2566 return (error); 2567} 2568 2569/*ARGSUSED*/ 2570static void 2571InsertNewLine(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED) 2572{ 2573 (void)LocalInsertNewLine((TextWidget)w, event); 2574} 2575 2576/*ARGSUSED*/ 2577static void 2578InsertNewLineAndIndent(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED) 2579{ 2580 XawTextBlock text; 2581 XawTextPosition pos1; 2582 int length; 2583 TextWidget ctx = (TextWidget)w; 2584 char * line_to_ip; 2585 2586 StartAction(ctx, event); 2587 pos1 = SrcScan(ctx->text.source, ctx->text.insertPos, 2588 XawstEOL, XawsdLeft, 1, False); 2589 2590 line_to_ip = _XawTextGetText(ctx, pos1, ctx->text.insertPos); 2591 2592 text.format = (unsigned long)_XawTextFormat(ctx); 2593 text.firstPos = 0; 2594 2595 if (text.format == XawFmtWide) { 2596 wchar_t *ptr; 2597 2598 text.ptr = XtMalloc((Cardinal)((2 + wcslen((wchar_t*)line_to_ip)) 2599 * sizeof(wchar_t))); 2600 ptr = (wchar_t*)text.ptr; 2601 ptr[0] = _Xaw_atowc(XawLF); 2602 wcscpy((wchar_t*)++ptr, (wchar_t*)line_to_ip); 2603 2604 length = (int)wcslen((wchar_t*)text.ptr); 2605 while (length && (iswspace(*ptr) || *ptr == _Xaw_atowc(XawTAB))) 2606 ptr++, length--; 2607 *ptr = (wchar_t)0; 2608 text.length = (int)wcslen((wchar_t*)text.ptr); 2609 } 2610 else { 2611 char *ptr; 2612 2613 length = (int)strlen(line_to_ip); 2614 text.ptr = XtMalloc((Cardinal)((size_t)(2 + length) * sizeof(char))); 2615 ptr = text.ptr; 2616 ptr[0] = XawLF; 2617 strcpy(++ptr, line_to_ip); 2618 2619 length++; 2620 while (length && (isspace((unsigned char)*ptr) || (*ptr == XawTAB))) 2621 ptr++, length--; 2622 *ptr = '\0'; 2623 text.length = (int)strlen(text.ptr); 2624 } 2625 XtFree(line_to_ip); 2626 2627 if (_XawTextReplace(ctx,ctx->text.insertPos, ctx->text.insertPos, &text)) { 2628 XBell(XtDisplay(ctx), 50); 2629 XtFree(text.ptr); 2630 EndAction(ctx); 2631 return; 2632 } 2633 2634 XtFree(text.ptr); 2635 ctx->text.from_left = -1; 2636 ctx->text.insertPos = SrcScan(ctx->text.source, ctx->text.old_insert, 2637 XawstPositions, XawsdRight, text.length, True); 2638 EndAction(ctx); 2639} 2640 2641/* 2642 * Selection Routines 2643 */ 2644static void 2645SelectWord(Widget w, XEvent *event, String *params, Cardinal *num_params) 2646{ 2647 TextWidget ctx = (TextWidget)w; 2648 XawTextPosition l, r; 2649 2650 StartAction(ctx, event); 2651 l = SrcScan(ctx->text.source, ctx->text.insertPos, 2652 XawstWhiteSpace, XawsdLeft, 1, False); 2653 r = SrcScan(ctx->text.source, l, XawstWhiteSpace, XawsdRight, 1, False); 2654 _XawTextSetSelection(ctx, l, r, params, *num_params); 2655 EndAction(ctx); 2656} 2657 2658static void 2659SelectAll(Widget w, XEvent *event, String *params, Cardinal *num_params) 2660{ 2661 TextWidget ctx = (TextWidget)w; 2662 2663 StartAction(ctx, event); 2664 _XawTextSetSelection(ctx,zeroPosition,ctx->text.lastPos,params,*num_params); 2665 EndAction(ctx); 2666} 2667 2668static void 2669ModifySelection(TextWidget ctx, XEvent *event, 2670 XawTextSelectionMode mode, 2671 XawTextSelectionAction action, 2672 String *params, Cardinal *num_params) 2673{ 2674#ifndef OLDXAW 2675 int old_y = ctx->text.ev_y; 2676#endif 2677 2678 StartAction(ctx, event); 2679 NotePosition(ctx, event); 2680 2681#ifndef OLDXAW 2682 if (event->type == MotionNotify) { 2683 if (ctx->text.ev_y <= ctx->text.margin.top) { 2684 if (old_y >= ctx->text.ev_y) 2685 XawTextScroll(ctx, -1, 0); 2686 } 2687 else if (ctx->text.ev_y >= XtHeight(ctx) - ctx->text.margin.bottom) { 2688 if (old_y <= ctx->text.ev_y 2689 && !IsPositionVisible(ctx, ctx->text.lastPos)) 2690 XawTextScroll(ctx, 1, 0); 2691 } 2692 } 2693#endif 2694 ctx->text.from_left = -1; 2695 _XawTextAlterSelection(ctx, mode, action, params, num_params); 2696 2697 EndAction(ctx); 2698} 2699 2700static void 2701SelectStart(Widget w, XEvent *event, String *params, Cardinal *num_params) 2702{ 2703 TextWidget ctx = (TextWidget)w; 2704 2705#ifndef OLDXAW 2706 if (!ctx->text.selection_state) { 2707 ctx->text.selection_state = True; 2708#endif 2709 ModifySelection(ctx, event, 2710 XawsmTextSelect, XawactionStart, params, num_params); 2711#ifndef OLDXAW 2712 } 2713#endif 2714} 2715 2716static void 2717SelectAdjust(Widget w, XEvent *event, String *params, Cardinal *num_params) 2718{ 2719 TextWidget ctx = (TextWidget)w; 2720 2721#ifndef OLDXAW 2722 if (ctx->text.selection_state) 2723#endif 2724 ModifySelection(ctx, event, 2725 XawsmTextSelect, XawactionAdjust, params, num_params); 2726} 2727 2728static void 2729SelectEnd(Widget w, XEvent *event, String *params, Cardinal *num_params) 2730{ 2731 TextWidget ctx = (TextWidget)w; 2732 2733#ifndef OLDXAW 2734 if (ctx->text.selection_state) { 2735 ctx->text.selection_state = False; 2736#endif 2737 ModifySelection(ctx, event, 2738 XawsmTextSelect, XawactionEnd, params, num_params); 2739#ifndef OLDXAW 2740 } 2741#endif 2742} 2743 2744static void 2745ExtendStart(Widget w, XEvent *event, String *params, Cardinal *num_params) 2746{ 2747 TextWidget ctx = (TextWidget)w; 2748 2749#ifndef OLDXAW 2750 if (!ctx->text.selection_state) { 2751 ctx->text.selection_state = True; 2752#endif 2753 ModifySelection(ctx, event, 2754 XawsmTextExtend, XawactionStart, params, num_params); 2755#ifndef OLDXAW 2756 } 2757#endif 2758} 2759 2760static void 2761ExtendAdjust(Widget w, XEvent *event, String *params, Cardinal *num_params) 2762{ 2763 TextWidget ctx = (TextWidget)w; 2764 2765#ifndef OLDXAW 2766 if (ctx->text.selection_state) 2767#endif 2768 ModifySelection(ctx, event, 2769 XawsmTextExtend, XawactionAdjust, params, num_params); 2770} 2771 2772static void 2773ExtendEnd(Widget w, XEvent *event, String *params, Cardinal *num_params) 2774{ 2775 TextWidget ctx = (TextWidget)w; 2776 2777#ifndef OLDXAW 2778 if (ctx->text.selection_state) { 2779 ctx->text.selection_state = False; 2780#endif 2781 ModifySelection(ctx, event, 2782 XawsmTextExtend, XawactionEnd, params, num_params); 2783#ifndef OLDXAW 2784 } 2785#endif 2786} 2787 2788static void 2789SelectSave(Widget w, XEvent *event, String *params, Cardinal *num_params) 2790{ 2791 int num_atoms, n; 2792 Atom *sel; 2793 Display *dpy = XtDisplay(w); 2794 Atom selections[256]; 2795 2796 StartAction((TextWidget)w, event); 2797 num_atoms = (int)*num_params; 2798 if (num_atoms > 256) 2799 num_atoms = 256; 2800 for (sel = selections, n = 0; n < num_atoms; n++, sel++, params++) 2801 *sel = XInternAtom(dpy, *params, False); 2802 _XawTextSaltAwaySelection((TextWidget)w, selections, num_atoms); 2803 EndAction((TextWidget)w); 2804} 2805 2806/* 2807 * Misc. Routines 2808 */ 2809/*ARGSUSED*/ 2810static void 2811SetKeyboardFocus(Widget w, XEvent *event _X_UNUSED, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED) 2812{ 2813 Widget shell, parent; 2814 2815 shell = parent = w; 2816 while (parent) { 2817 if (XtIsShell(shell = parent)) 2818 break; 2819 parent = XtParent(parent); 2820 } 2821 XtSetKeyboardFocus(shell, w); 2822} 2823 2824/*ARGSUSED*/ 2825static void 2826RedrawDisplay(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED) 2827{ 2828 StartAction((TextWidget)w, event); 2829 _XawTextClearAndCenterDisplay((TextWidget)w); 2830 EndAction((TextWidget)w); 2831} 2832 2833/* This is kind of a hack, but, only one text widget can have focus at 2834 * a time on one display. There is a problem in the implementation of the 2835 * text widget, the scrollbars can not be addressed via editres, since they 2836 * are not children of a subclass of composite. 2837 * The focus variable is required to make sure only one text window will 2838 * show a block cursor at one time. 2839 */ 2840struct _focus { Display *display; Widget widget; }; 2841static struct _focus *focus; 2842static Cardinal num_focus; 2843 2844/*ARGSUSED*/ 2845static void 2846DestroyFocusCallback(Widget w, XtPointer user_data, XtPointer call_data _X_UNUSED) 2847{ 2848 struct _focus *f = (struct _focus*)(user_data); 2849 2850 if (f->widget == w) 2851 f->widget = NULL; 2852} 2853 2854/*ARGSUSED*/ 2855static void 2856TextFocusIn(Widget w, XEvent *event, String *p, Cardinal *n) 2857{ 2858 TextWidget ctx = (TextWidget)w; 2859 Bool display_caret = ctx->text.display_caret; 2860 int i; 2861 2862 if (event->xfocus.detail == NotifyPointer) 2863 return; 2864 2865 if (event->xfocus.send_event) { 2866 Window root, child; 2867 int rootx, rooty, x, y; 2868 unsigned int mask; 2869 2870 if (ctx->text.hasfocus) 2871 return; 2872 2873 if (XQueryPointer(XtDisplay(w), XtWindow(w), &root, &child, 2874 &rootx, &rooty, &x, &y, &mask)) { 2875 if (child) 2876 return; 2877 } 2878 } 2879 2880 /* Let the input method know focus has arrived. */ 2881 _XawImSetFocusValues(w, NULL, 0); 2882 2883 if (display_caret) 2884 StartAction(ctx, event); 2885 ctx->text.hasfocus = TRUE; 2886 if (display_caret) 2887 EndAction(ctx); 2888 2889 for (i = 0; (Cardinal)i < num_focus; i++) 2890 if (focus[i].display == XtDisplay(w)) 2891 break; 2892 if ((Cardinal)i >= num_focus) { 2893 focus = (struct _focus*) 2894 XtRealloc((XtPointer)focus, (Cardinal)(sizeof(struct _focus) * (num_focus + 1))); 2895 i = (int)num_focus; 2896 focus[i].widget = NULL; 2897 focus[i].display = XtDisplay(w); 2898 num_focus++; 2899 } 2900 if (focus[i].widget != w) { 2901 Widget old = focus[i].widget; 2902 2903 focus[i].widget = w; 2904 if (old != NULL) { 2905 TextFocusOut(old, event, p, n); 2906 /* TextFocusOut may set it to NULL */ 2907 focus[i].widget = w; 2908 } 2909 XtAddCallback(w, XtNdestroyCallback, 2910 DestroyFocusCallback, (XtPointer)&focus[i]); 2911 } 2912} 2913 2914/*ARGSUSED*/ 2915static void 2916TextFocusOut(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED) 2917{ 2918 TextWidget ctx = (TextWidget)w; 2919 Bool display_caret = ctx->text.display_caret; 2920 Widget shell; 2921 Window window; 2922 int i, revert; 2923 2924 shell = w; 2925 while (shell) { 2926 if (XtIsShell(shell)) 2927 break; 2928 shell = XtParent(shell); 2929 } 2930 2931 for (i = 0; (Cardinal)i < num_focus; i++) 2932 if (focus[i].display == XtDisplay(w)) 2933 break; 2934 XGetInputFocus(XtDisplay(w), &window, &revert); 2935 if ((XtWindow(shell) == window && 2936 ((Cardinal)i < num_focus && focus[i].widget == w)) 2937 || event->xfocus.detail == NotifyPointer) 2938 return; 2939 2940 if ((Cardinal)i < num_focus && focus[i].widget) { 2941 XtRemoveCallback(focus[i].widget, XtNdestroyCallback, 2942 DestroyFocusCallback, (XtPointer)&focus[i]); 2943 focus[i].widget = NULL; 2944 } 2945 2946 /* Let the input method know focus has left.*/ 2947 _XawImUnsetFocus(w); 2948 2949 if (display_caret) 2950 StartAction(ctx, event); 2951 ctx->text.hasfocus = FALSE; 2952 if (display_caret) 2953 EndAction(ctx); 2954} 2955 2956/*ARGSUSED*/ 2957static void 2958TextEnterWindow(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED) 2959{ 2960 TextWidget ctx = (TextWidget)w; 2961 2962 if ((event->xcrossing.detail != NotifyInferior) && event->xcrossing.focus 2963 && !ctx->text.hasfocus) 2964 _XawImSetFocusValues(w, NULL, 0); 2965} 2966 2967/*ARGSUSED*/ 2968static void 2969TextLeaveWindow(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED) 2970{ 2971 TextWidget ctx = (TextWidget)w; 2972 2973 if ((event->xcrossing.detail != NotifyInferior) && event->xcrossing.focus 2974 && !ctx->text.hasfocus) 2975 _XawImUnsetFocus(w); 2976} 2977 2978/* 2979 * Function: 2980 * AutoFill 2981 * Arguments: ctx - The text widget. 2982 * 2983 * Description: 2984 * Breaks the line at the previous word boundary when 2985 * called inside InsertChar. 2986 */ 2987static void 2988AutoFill(TextWidget ctx) 2989{ 2990 int width, height, x, line_num, max_width; 2991 XawTextPosition ret_pos; 2992 XawTextBlock text; 2993 XRectangle cursor; 2994 wchar_t wc_buf[2]; 2995 2996 for (line_num = 0; line_num < ctx->text.lt.lines ; line_num++) 2997 if (ctx->text.lt.info[line_num].position >= ctx->text.insertPos) 2998 break; 2999 if (line_num) 3000 line_num--; /* backup a line. */ 3001 3002 XawTextSinkGetCursorBounds(ctx->text.sink, &cursor); 3003 max_width = Max(0, (int)XtWidth(ctx) - RHMargins(ctx) - cursor.width); 3004 3005 x = ctx->text.r_margin.left; 3006 XawTextSinkFindPosition(ctx->text.sink, ctx->text.lt.info[line_num].position, 3007 x, max_width, True, &ret_pos, 3008 &width, &height); 3009 3010 if (ret_pos <= ctx->text.lt.info[line_num].position 3011 || ret_pos >= ctx->text.insertPos || ret_pos < 1) 3012 return; 3013 3014 XawTextSourceRead(ctx->text.source, ret_pos - 1, &text, 1); 3015 3016 if (XawTextFormat(ctx, XawFmtWide)) { 3017 wc_buf[0] = *(wchar_t *)text.ptr; 3018 if (wc_buf[0] != _Xaw_atowc(XawSP) && wc_buf[0] != _Xaw_atowc(XawTAB)) 3019 /* Only eats white spaces */ 3020 return; 3021 3022 text.format = XawFmtWide; 3023 text.ptr = (char *)wc_buf; 3024 wc_buf[0] = _Xaw_atowc(XawLF); 3025 wc_buf[1] = 0; 3026 } 3027 else { 3028 if (text.ptr[0] != XawSP && text.ptr[0] != XawTAB) 3029 /* Only eats white spaces */ 3030 return; 3031 3032 text.format = XawFmt8Bit; 3033 text.ptr = (char*)"\n"; 3034 } 3035 text.length = 1; 3036 text.firstPos = 0; 3037 3038 if (_XawTextReplace(ctx, ret_pos - 1, ret_pos, &text)) 3039 XBell(XtDisplay((Widget)ctx), 0); 3040 3041 if (++ctx->text.insertPos > ctx->text.lastPos) 3042 ctx->text.insertPos = ctx->text.lastPos; 3043} 3044 3045/*ARGSUSED*/ 3046static void 3047InsertChar(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED) 3048{ 3049 TextWidget ctx = (TextWidget)w; 3050 char *ptr, strbuf[128], ptrbuf[512]; 3051 int count, error, mult = MULT(ctx); 3052 KeySym keysym; 3053 XawTextBlock text; 3054#ifndef OLDXAW 3055 Bool format = False; 3056#endif 3057 XawTextPosition from, to; 3058 3059 if (XtIsSubclass (ctx->text.source, (WidgetClass) multiSrcObjectClass)) 3060 text.length = _XawImWcLookupString(w, &event->xkey, (wchar_t*)strbuf, 3061 sizeof(strbuf), &keysym); 3062 else 3063 text.length = _XawLookupString(w, (XKeyEvent*)event, strbuf, 3064 sizeof(strbuf), &keysym); 3065 3066 if (text.length == 0) 3067 return; 3068 3069 if (mult < 0) { 3070 ctx->text.mult = 1; 3071 return; 3072 } 3073 3074 text.format = (unsigned long)_XawTextFormat(ctx); 3075 if (text.format == XawFmtWide) { 3076 text.ptr = ptr = XawStackAlloc(sizeof(wchar_t) * (size_t)text.length 3077 * (size_t)mult, ptrbuf); 3078 for (count = 0; count < mult; count++) { 3079 memcpy((char*)ptr, (char *)strbuf, sizeof(wchar_t) * (size_t)text.length); 3080 ptr += sizeof(wchar_t) * (size_t)text.length; 3081 } 3082#ifndef OLDXAW 3083 if (mult == 1) 3084 format = ctx->text.left_column < ctx->text.right_column; 3085#endif 3086 } 3087 else { /* == XawFmt8Bit */ 3088 text.ptr = ptr = XawStackAlloc((unsigned)(text.length * mult), ptrbuf); 3089 for (count = 0; count < mult; count++) { 3090 strncpy(ptr, strbuf, (size_t)text.length); 3091 ptr += text.length; 3092 } 3093#ifndef OLDXAW 3094 if (mult == 1) 3095 format = ctx->text.left_column < ctx->text.right_column; 3096#endif 3097 } 3098 3099 text.length = text.length * mult; 3100 text.firstPos = 0; 3101 3102 StartAction(ctx, event); 3103#ifndef OLDXAW 3104 if (mult == 1) 3105 _XawSourceSetUndoMerge((TextSrcObject)ctx->text.source, True); 3106#endif 3107 3108 from = ctx->text.insertPos; 3109#ifndef OLDXAW 3110 if (ctx->text.overwrite) { 3111 XawTextPosition tmp; 3112 3113 to = from + mult; 3114 tmp = SrcScan(ctx->text.source, from, XawstEOL, XawsdRight, 1, False); 3115 if (to > tmp) 3116 to = tmp; 3117 } 3118 else 3119#endif 3120 to = from; 3121 3122 error = _XawTextReplace(ctx, from , to, &text); 3123 3124 if (error == XawEditDone) { 3125 ctx->text.from_left = -1; 3126 ctx->text.insertPos = SrcScan(ctx->text.source, ctx->text.old_insert, 3127 XawstPositions, XawsdRight, 3128 text.length, True); 3129 if (ctx->text.auto_fill) { 3130#ifndef OLDXAW 3131 if (format) 3132 (void)FormatText(ctx, SrcScan(ctx->text.source, 3133 ctx->text.insertPos, XawstEOL, 3134 XawsdLeft, 1, False), False, 3135 NULL, 0); 3136 else 3137#endif 3138 AutoFill(ctx); 3139 } 3140 } 3141 else 3142 XBell(XtDisplay(ctx), 50); 3143 3144 XawStackFree(text.ptr, ptrbuf); 3145 EndAction(ctx); 3146 3147 if (error == XawEditDone && text.format == XawFmt8Bit && text.length == 1 3148 && (text.ptr[0] == ')' || text.ptr[0] == ']' || text.ptr[0] == '}') 3149 && ctx->text.display_caret) { 3150 static struct timeval tmval = {0, 500000}; 3151 fd_set fds; 3152 Widget source = ctx->text.source; 3153 XawTextPosition insertPos = ctx->text.insertPos, pos, tmp, last; 3154 char left, right = text.ptr[0]; 3155 int level = 0; 3156 XtAppContext app_context = XtWidgetToApplicationContext(w); 3157 3158 left = right == ')' ? '(' : right == ']' ? '[' : '{'; 3159 3160 last = insertPos - 1; 3161 do { 3162 text.ptr[0] = left; 3163 pos = XawTextSourceSearch(source, last, XawsdLeft, &text); 3164 if (pos == XawTextSearchError || !IsPositionVisible(ctx, pos)) 3165 return; 3166 text.ptr[0] = right; 3167 tmp = pos; 3168 do { 3169 tmp = XawTextSourceSearch(source, tmp, XawsdRight, &text); 3170 if (tmp == XawTextSearchError) 3171 return; 3172 if (tmp <= last) 3173 ++level; 3174 } while (++tmp <= last); 3175 --level; 3176 last = pos; 3177 } while (level); 3178 3179 StartAction(ctx, NULL); 3180#ifndef OLDXAW 3181 _XawSourceSetUndoMerge((TextSrcObject)ctx->text.source, True); 3182#endif 3183 ctx->text.insertPos = pos; 3184 EndAction(ctx); 3185 3186 XSync(XtDisplay(w), False); 3187 while (XtAppPending(app_context) & XtIMXEvent) { 3188 XEvent ev; 3189 if (! XtAppPeekEvent(app_context, &ev)) 3190 break; 3191 if (ev.type == KeyPress || ev.type == ButtonPress) 3192 break; 3193 XtAppProcessEvent(app_context, XtIMXEvent); 3194 } 3195 FD_ZERO(&fds); 3196 FD_SET(ConnectionNumber(XtDisplay(w)), &fds); 3197 (void)select(FD_SETSIZE, &fds, NULL, NULL, &tmval); 3198 if (tmval.tv_usec != 500000) 3199 usleep(40000); 3200 3201 StartAction(ctx, NULL); 3202#ifndef OLDXAW 3203 _XawSourceSetUndoMerge((TextSrcObject)ctx->text.source, True); 3204#endif 3205 ctx->text.insertPos = insertPos; 3206 EndAction(ctx); 3207 } 3208} 3209 3210/* IfHexConvertHexElseReturnParam() - called by InsertString 3211 * 3212 * i18n requires the ability to specify multiple characters in a hexa- 3213 * decimal string at once. Since Insert was already too long, I made 3214 * this a separate routine. 3215 * 3216 * A legal hex string in MBNF: '0' 'x' ( HEX-DIGIT HEX-DIGIT )+ '\0' 3217 * 3218 * WHEN: the passed param is a legal hex string 3219 * RETURNS: a pointer to that converted, null terminated hex string; 3220 * len_return holds the character count of conversion result 3221 * 3222 * WHEN: the passed param is not a legal hex string: 3223 * RETURNS: the parameter passed; 3224 * len_return holds the char count of param. 3225 * 3226 * NOTE: In neither case will there be strings to free. */ 3227static char * 3228IfHexConvertHexElseReturnParam(const char *param, int *len_return) 3229{ 3230 const char *p; /* steps through param char by char */ 3231 char c; /* holds the character pointed to by p */ 3232 int ind; /* steps through hexval buffer char by char */ 3233 static char hexval[XawTextActionMaxHexChars]; 3234 Boolean first_digit; 3235 3236 /* reject if it doesn't begin with 0x and at least one more character. */ 3237 if ((param[0] != '0') || (param[1] != 'x') || (param[2] == '\0')) { 3238 goto out; 3239 } 3240 3241 /* Skip the 0x; go character by character shifting and adding. */ 3242 first_digit = True; 3243 ind = 0; 3244 hexval[ind] = '\0'; 3245 3246 for (p = param+2; (c = *p) != '\0'; p++) { 3247 hexval[ind] = (char)(hexval[ind] * 16); 3248 if (c >= '0' && c <= '9') 3249 hexval[ind] = (char)(hexval[ind] + (c - '0')); 3250 else if (c >= 'a' && c <= 'f') 3251 hexval[ind] = (char)(hexval[ind] + (c - 'a' + 10)); 3252 else if (c >= 'A' && c <= 'F') 3253 hexval[ind] = (char)(hexval[ind] + (c - 'A' + 10)); 3254 else 3255 break; 3256 3257 /* If we didn't break in preceding line, it was a good hex char. */ 3258 if (first_digit) 3259 first_digit = False; 3260 else { 3261 first_digit = True; 3262 if (++ind < XawTextActionMaxHexChars) 3263 hexval[ind] = '\0'; 3264 else { 3265 goto out; 3266 } 3267 } 3268 } 3269 3270 /* We quit the above loop because we hit a non hex. If that char is \0... */ 3271 if ((c == '\0') && first_digit) { 3272 *len_return = (int)strlen(hexval); 3273 return (hexval); /* ...it was a legal hex string, so return it */ 3274 } 3275 3276 /* Else, there were non-hex chars or odd digit count, so... */ 3277out: 3278 *len_return = (int)strlen(param); 3279 return ((char *)param); /* ...return the verbatim string. */ 3280} 3281 3282/* InsertString() - action 3283 * 3284 * Mostly rewritten for R6 i18n. 3285 * 3286 * Each parameter, in turn, will be insert at the inputPos 3287 * and the inputPos advances to the insertion's end. 3288 * 3289 * The exception is that parameters composed of the two 3290 * characters 0x, followed only by an even number of 3291 * hexadecimal digits will be converted to characters */ 3292/*ARGSUSED*/ 3293static void 3294InsertString(Widget w, XEvent *event, String *params, Cardinal *num_params) 3295{ 3296 TextWidget ctx = (TextWidget)w; 3297 XtAppContext app_con = XtWidgetToApplicationContext(w); 3298 XawTextBlock text; 3299 int i; 3300 3301 text.firstPos = 0; 3302 text.format = (unsigned long)_XawTextFormat(ctx); 3303 3304 StartAction(ctx, event); 3305 for (i = (int)*num_params; i; i--, params++) { /* DO FOR EACH PARAMETER */ 3306 text.ptr = IfHexConvertHexElseReturnParam((char*) *params, &text.length); 3307 3308 if (text.length == 0) 3309 continue; 3310 3311 if (XawTextFormat(ctx, XawFmtWide)) { /* convert to WC */ 3312 int temp_len; 3313 3314 text.ptr = (char*)_XawTextMBToWC(XtDisplay(w), text.ptr, 3315 &text.length); 3316 3317 if (text.ptr == NULL) { /* conversion error */ 3318 XtAppWarningMsg(app_con, 3319 "insertString", "textAction", "XawError", 3320 "insert-string()'s parameter contents " 3321 "not legal in this locale.", 3322 NULL, NULL); 3323 ParameterError(w, *params); 3324 continue; 3325 } 3326 3327 /* Double check that the new input is legal: try to convert to MB. */ 3328 3329 temp_len = text.length; /* _XawTextWCToMB's 3rd arg is in_out */ 3330 if (_XawTextWCToMB(XtDisplay(w), (wchar_t*)text.ptr, &temp_len) 3331 == NULL) { 3332 XtAppWarningMsg( app_con, 3333 "insertString", "textAction", "XawError", 3334 "insert-string()'s parameter contents " 3335 "not legal in this locale.", 3336 NULL, NULL); 3337 ParameterError(w, *params); 3338 continue; 3339 } 3340 } /* convert to WC */ 3341 3342 if (_XawTextReplace(ctx, ctx->text.insertPos, 3343 ctx->text.insertPos, &text)) { 3344 XBell(XtDisplay(ctx), 50); 3345 EndAction(ctx); 3346 return; 3347 } 3348 3349 ctx->text.from_left = -1; 3350 /* Advance insertPos to the end of the string we just inserted. */ 3351 ctx->text.insertPos = SrcScan(ctx->text.source, ctx->text.old_insert, 3352 XawstPositions, XawsdRight, text.length, 3353 True); 3354 3355 } /* DO FOR EACH PARAMETER */ 3356 3357 EndAction(ctx); 3358} 3359 3360/* DisplayCaret() - action 3361 * 3362 * The parameter list should contain one boolean value. If the 3363 * argument is true, the cursor will be displayed. If false, not. 3364 * 3365 * The exception is that EnterNotify and LeaveNotify events may 3366 * have a second argument, "always". If they do not, the cursor 3367 * is only affected if the focus member of the event is true. */ 3368static void 3369DisplayCaret(Widget w, XEvent *event, String *params, Cardinal *num_params) 3370{ 3371 TextWidget ctx = (TextWidget)w; 3372 Bool display_caret = True; 3373 3374 if ((event->type == EnterNotify || event->type == LeaveNotify) 3375 && ((*num_params >= 2) && (strcmp(params[1], "always") == 0)) 3376 && (!event->xcrossing.focus)) 3377 return; 3378 3379 if (*num_params > 0) { /* default arg is "True" */ 3380 XrmValue from, to; 3381 from.size = (unsigned)strlen(from.addr = (char*)params[0]); 3382 XtConvert(w, XtRString, &from, XtRBoolean, &to); 3383 3384 if (to.addr != NULL) 3385 display_caret = *(Boolean*)to.addr; 3386 if (ctx->text.display_caret == display_caret) 3387 return; 3388 } 3389 StartAction(ctx, event); 3390 ctx->text.display_caret = (Boolean)display_caret; 3391 EndAction(ctx); 3392} 3393 3394#ifndef OLDXAW 3395static void 3396Numeric(Widget w, XEvent *event, String *params, Cardinal *num_params) 3397{ 3398 TextWidget ctx = (TextWidget)w; 3399 3400 if (ctx->text.numeric) { 3401 long mult = ctx->text.mult; 3402 3403 if (*num_params != 1 || strlen(params[0]) != 1 3404 || (!isdigit((unsigned char)params[0][0]) 3405 && (params[0][0] != '-' || mult != 0))) { 3406 char err_buf[256]; 3407 3408 if (event && (event->type == KeyPress || event->type == KeyRelease) 3409 && params[0][0] == '-') { 3410 InsertChar(w, event, params, num_params); 3411 return; 3412 } 3413 snprintf(err_buf, sizeof(err_buf), 3414 "numeric: Invalid argument%s'%s'", 3415 *num_params ? ", " : "", 3416 *num_params ? params[0] : ""); 3417 XtAppWarning(XtWidgetToApplicationContext(w), err_buf); 3418 ctx->text.numeric = False; 3419 ctx->text.mult = 1; 3420 return; 3421 } 3422 if (params[0][0] == '-') { 3423 ctx->text.mult = 32767; 3424 return; 3425 } 3426 else if (mult == 32767) { 3427 return; 3428 } 3429 else { 3430 mult = mult * 10 + (params[0][0] - '0') * (mult < 0 ? -1 : 1); 3431 ctx->text.mult = (short)(ctx->text.mult * 10 + (params[0][0] - '0') * 3432 (mult < 0 ? -1 : 1)); 3433 } 3434 if (mult != ctx->text.mult || mult >= 32767) { /* checks for overflow */ 3435 XBell(XtDisplay(w), 0); 3436 ctx->text.mult = 1; 3437 ctx->text.numeric = False; 3438 return; 3439 } 3440 } 3441 else 3442 InsertChar(w, event, params, num_params); 3443} 3444 3445/*ARGSUSED*/ 3446static void 3447KeyboardReset(Widget w, XEvent *event _X_UNUSED, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED) 3448{ 3449 TextWidget ctx = (TextWidget)w; 3450 3451 ctx->text.numeric = False; 3452 ctx->text.mult = 1; 3453 3454 (void)_XawTextSrcToggleUndo((TextSrcObject)ctx->text.source); 3455 3456 if (ctx->text.kill_ring_ptr) { 3457 --ctx->text.kill_ring_ptr->refcount; 3458 ctx->text.kill_ring_ptr = NULL; 3459 } 3460 ctx->text.kill_ring = 0; 3461 3462 XBell(XtDisplay(w), 0); 3463} 3464#endif /* OLDXAW */ 3465 3466/* Multiply() - action 3467 * 3468 * The parameter list may contain either a number or the string 'Reset'. 3469 * 3470 * A number will multiply the current multiplication factor by that number. 3471 * Many of the text widget actions will will perform n actions, where n is 3472 * the multiplication factor. 3473 * 3474 * The string reset will reset the mutiplication factor to 1. */ 3475/*ARGSUSED*/ 3476static void 3477Multiply(Widget w, XEvent *event _X_UNUSED, String *params, Cardinal *num_params) 3478{ 3479 TextWidget ctx = (TextWidget)w; 3480 int mult; 3481 3482 if (*num_params != 1) { 3483 XtAppError(XtWidgetToApplicationContext(w), 3484 "Xaw Text Widget: multiply() takes exactly one argument."); 3485 XBell(XtDisplay(w), 0); 3486 return; 3487 } 3488 3489 if ((params[0][0] == 'r') || (params[0][0] == 'R')) { 3490 XBell(XtDisplay(w), 0); 3491#ifndef OLDXAW 3492 ctx->text.numeric = False; 3493#endif 3494 ctx->text.mult = 1; 3495 return; 3496 } 3497 3498#ifndef OLDXAW 3499 if (params[0][0] == 's' || params[0][0] == 'S') { 3500 ctx->text.numeric = True; 3501 ctx->text.mult = 0; 3502 return; 3503 } 3504 else 3505#endif 3506 if ((mult = atoi(params[0])) == 0) { 3507 char buf[BUFSIZ]; 3508 3509 snprintf(buf, sizeof(buf), 3510 "Xaw Text Widget: multiply() argument " 3511 "must be a number greater than zero, or 'Reset'."); 3512 XtAppError(XtWidgetToApplicationContext(w), buf); 3513 XBell(XtDisplay(w), 50); 3514 return; 3515 } 3516 3517 ctx->text.mult = (short)(ctx->text.mult * mult); 3518} 3519 3520/* StripOutOldCRs() - called from FormRegion 3521 * 3522 * removes CRs in widget ctx, from from to to. 3523 * 3524 * RETURNS: the new ending location (we may add some characters), 3525 * or XawReplaceError if the widget can't be written to. */ 3526static XawTextPosition 3527StripOutOldCRs(TextWidget ctx, XawTextPosition from, XawTextPosition to, 3528 XawTextPosition *pos, int num_pos) 3529{ 3530 XawTextPosition startPos, endPos, eop_begin, eop_end; 3531 Widget src = ctx->text.source; 3532 XawTextBlock text; 3533 char *buf; 3534 int idx; 3535 3536 /* Initialize our TextBlock with two spaces. */ 3537 text.firstPos = 0; 3538 text.format = (unsigned long)_XawTextFormat(ctx); 3539 if (text.format == XawFmt8Bit) { 3540 text.ptr= (char*)" "; 3541 } else { 3542 static wchar_t wc_two_spaces[3]; 3543 3544 wc_two_spaces[0] = _Xaw_atowc(XawSP); 3545 wc_two_spaces[1] = _Xaw_atowc(XawSP); 3546 wc_two_spaces[2] = 0; 3547 text.ptr = (char*)wc_two_spaces; 3548 } 3549 3550 /* Strip out CR's. */ 3551 eop_begin = eop_end = startPos = from; 3552 3553 /* CONSTCOND */ 3554 while (TRUE) { 3555 XawTextPosition temp; 3556 3557 endPos = SrcScan(src, startPos, XawstEOL, XawsdRight, 1, False); 3558 3559 temp = SrcScan(src, endPos, XawstWhiteSpace, XawsdLeft, 1, False); 3560 temp = SrcScan(src, temp, XawstWhiteSpace, XawsdRight,1, False); 3561 3562 if (temp > startPos) 3563 endPos = temp; 3564 3565 if (endPos >= to) 3566 break; 3567 3568 if (endPos >= eop_begin) { 3569 startPos = eop_end; 3570 eop_begin=SrcScan(src, startPos, XawstParagraph, 3571 XawsdRight, 1,False); 3572 eop_end = SrcScan(src, startPos, XawstParagraph, 3573 XawsdRight, 1, True); 3574 } 3575 else { 3576 XawTextPosition periodPos, next_word; 3577 int i, len; 3578 3579 periodPos = SrcScan(src, endPos, XawstPositions, 3580 XawsdLeft, 1, True); 3581 next_word = SrcScan(src, endPos, XawstWhiteSpace, 3582 XawsdRight, 1, False); 3583 3584 len = (int)(next_word - periodPos); 3585 3586 text.length = 1; 3587 buf = _XawTextGetText(ctx, periodPos, next_word); 3588 if (text.format == XawFmtWide) { 3589 if (periodPos < endPos && ((wchar_t*)buf)[0] == _Xaw_atowc('.')) 3590 text.length++; 3591 } 3592 else 3593 if (periodPos < endPos && buf[0] == '.') 3594 text.length++; /* Put in two spaces. */ 3595 3596 /* 3597 * Remove all extra spaces. 3598 */ 3599 for (i = 1 ; i < len; i++) 3600 if (text.format == XawFmtWide) { 3601 if (!iswspace(((wchar_t*)buf)[i]) || ((periodPos + i) >= to)) 3602 break; 3603 } 3604 else if (!isspace((unsigned char)buf[i]) || (periodPos + i) >= to) 3605 break; 3606 3607 XtFree(buf); 3608 3609 to -= (i - text.length - 1); 3610 startPos = SrcScan(src, periodPos, XawstPositions, 3611 XawsdRight, i, True); 3612 if (_XawTextReplace(ctx, endPos, startPos, &text) != XawEditDone) 3613 return (XawReplaceError); 3614 3615 for (idx = 0; idx < num_pos; idx++) { 3616 if (endPos < pos[idx]) { 3617 if (startPos < pos[idx]) 3618 pos[idx] -= startPos - endPos; 3619 else 3620 pos[idx] = endPos; 3621 pos[idx] += text.length; 3622 } 3623 } 3624 3625 startPos -= i - text.length; 3626 } 3627 } 3628 3629 return (to); 3630} 3631 3632/* InsertNewCRs() - called from FormRegion 3633 * 3634 * inserts new CRs for FormRegion, thus for FormParagraph action */ 3635static void 3636InsertNewCRs(TextWidget ctx, XawTextPosition from, XawTextPosition to, 3637 XawTextPosition *pos, int num_pos) 3638{ 3639 XawTextPosition startPos; 3640 XawTextBlock text; 3641 int i, width, height, wwidth, idx; 3642 3643 text.firstPos = 0; 3644 text.length = 1; 3645 text.format = (unsigned long)_XawTextFormat(ctx); 3646 3647 if (text.format == XawFmt8Bit) { 3648 text.ptr = (char*)"\n"; 3649 } else { 3650 static wchar_t wide_CR[2]; 3651 3652 wide_CR[0] = _Xaw_atowc(XawLF); 3653 wide_CR[1] = 0; 3654 text.ptr = (char*)wide_CR; 3655 } 3656 3657 startPos = from; 3658 3659 wwidth = (int)XtWidth(ctx) - (int)HMargins(ctx); 3660 if (ctx->text.wrap != XawtextWrapNever) { 3661 XRectangle cursor; 3662 3663 XawTextSinkGetCursorBounds(ctx->text.sink, &cursor); 3664 wwidth -= (int)cursor.width; 3665 } 3666 wwidth = XawMax(0, wwidth); 3667 3668 /* CONSTCOND */ 3669 while (TRUE) { 3670 int len; 3671 char *buf; 3672 XawTextPosition endPos, space, eol; 3673 3674 XawTextSinkFindPosition(ctx->text.sink, startPos, 3675 (int)ctx->text.r_margin.left, wwidth, 3676 True, &eol, &width, &height); 3677 if (eol == startPos) 3678 ++eol; 3679 if (eol >= to) 3680 break; 3681 3682 eol = SrcScan(ctx->text.source, eol, XawstPositions, 3683 XawsdLeft, 1, True); 3684 space = SrcScan(ctx->text.source, eol, XawstWhiteSpace, 3685 XawsdRight,1, True); 3686 3687 startPos = endPos = eol; 3688 if (eol == space) 3689 return; 3690 3691 len = (int)(space - eol); 3692 buf = _XawTextGetText(ctx, eol, space); 3693 for (i = 0 ; i < len ; i++) 3694 if (text.format == XawFmtWide) { 3695 if (!iswspace(((wchar_t*)buf)[i])) 3696 break; 3697 } 3698 else if (!isspace((unsigned char)buf[i])) 3699 break; 3700 3701 to -= (i - 1); 3702 endPos = SrcScan(ctx->text.source, endPos, 3703 XawstPositions, XawsdRight, i, True); 3704 XtFree(buf); 3705 3706 if (_XawTextReplace(ctx, startPos, endPos, &text)) 3707 return; 3708 3709 for (idx = 0; idx < num_pos; idx++) { 3710 if (startPos < pos[idx]) { 3711 if (endPos < pos[idx]) 3712 pos[idx] -= endPos - startPos; 3713 else 3714 pos[idx] = startPos; 3715 pos[idx] += text.length; 3716 } 3717 } 3718 3719 startPos = SrcScan(ctx->text.source, startPos, 3720 XawstPositions, XawsdRight, 1, True); 3721 } 3722} 3723 3724/* FormRegion() - called by FormParagraph 3725 * 3726 * oversees the work of paragraph-forming a region 3727 * 3728 * Return: 3729 * XawEditDone if successful, or XawReplaceError 3730 */ 3731static int 3732FormRegion(TextWidget ctx, XawTextPosition from, XawTextPosition to, 3733 XawTextPosition *pos, int num_pos) 3734{ 3735#ifndef OLDXAW 3736 Bool format = ctx->text.auto_fill 3737 && ctx->text.left_column < ctx->text.right_column; 3738#endif 3739 3740 if (from >= to) 3741 return (XawEditDone); 3742 3743#ifndef OLDXAW 3744 if (format) { 3745 XawTextPosition len = ctx->text.lastPos; 3746 int inc = 0; 3747 3748 if (ctx->text.justify == XawjustifyLeft || 3749 ctx->text.justify == XawjustifyFull) { 3750 Untabify(ctx, from, to, pos, num_pos, NULL); 3751 to += ctx->text.lastPos - len; 3752 (void)BlankLine((Widget)ctx, from, &inc); 3753 if (from + inc >= to) 3754 return (XawEditDone); 3755 } 3756 if (!StripSpaces(ctx, from + inc, to, pos, num_pos, NULL)) 3757 return (XawReplaceError); 3758 3759 FormatText(ctx, from, ctx->text.justify != XawjustifyFull, pos, num_pos); 3760 } 3761 else { 3762#endif 3763 if ((to = StripOutOldCRs(ctx, from, to, pos, num_pos)) == XawReplaceError) 3764 return (XawReplaceError); 3765 InsertNewCRs(ctx, from, to, pos, num_pos); 3766#ifndef OLDXAW 3767 } 3768#endif 3769 ctx->text.from_left = -1; 3770 3771 return (XawEditDone); 3772} 3773 3774#ifndef OLDXAW 3775static Bool 3776BlankLine(Widget w, XawTextPosition pos, int *blanks_return) 3777{ 3778 int i, blanks = 0; 3779 XawTextBlock block; 3780 Widget src = XawTextGetSource(w); 3781 XawTextPosition l = SrcScan(src, pos, XawstEOL, XawsdLeft, 1, False); 3782 XawTextPosition r = SrcScan(src, pos, XawstEOL, XawsdRight, 1, False); 3783 3784 while (l < r) { 3785 l = XawTextSourceRead(src, l, &block, (int)(r - l)); 3786 if (block.length == 0) { 3787 if (blanks_return) 3788 *blanks_return = blanks; 3789 return (True); 3790 } 3791 if (XawTextFormat((TextWidget)w, XawFmt8Bit)) { 3792 for (i = 0; i < block.length; i++, blanks++) 3793 if (block.ptr[i] != ' ' && 3794 block.ptr[i] != '\t') { 3795 if (blanks_return) 3796 *blanks_return = blanks; 3797 return (block.ptr[i] == '\n'); 3798 } 3799 } 3800 else if (XawTextFormat((TextWidget)w, XawFmtWide)) { 3801 for (i = 0; i < block.length; i++, blanks++) 3802 if (_Xaw_atowc(XawSP) != ((wchar_t*)block.ptr)[i] && 3803 _Xaw_atowc(XawTAB) != ((wchar_t*)block.ptr)[i]) { 3804 if (blanks_return) 3805 *blanks_return = blanks; 3806 return (_Xaw_atowc(XawLF) == ((wchar_t*)block.ptr)[i]); 3807 } 3808 } 3809 } 3810 3811 return (True); 3812} 3813 3814static Bool 3815GetBlockBoundaries(TextWidget ctx, 3816 XawTextPosition *from_return, XawTextPosition *to_return) 3817{ 3818 XawTextPosition from, to; 3819 3820 if (ctx->text.auto_fill && ctx->text.left_column < ctx->text.right_column) { 3821 if (ctx->text.s.left != ctx->text.s.right) { 3822 from = SrcScan(ctx->text.source, 3823 XawMin(ctx->text.s.left, ctx->text.s.right), 3824 XawstEOL, XawsdLeft, 1, False); 3825 to = SrcScan(ctx->text.source, 3826 XawMax(ctx->text.s.left, ctx->text.s.right), 3827 XawstEOL, XawsdRight, 1, False); 3828 } 3829 else { 3830 XawTextBlock block; 3831 XawTextPosition tmp; 3832 Bool first; 3833 3834 from = to = ctx->text.insertPos; 3835 3836 /* find from position */ 3837 first = True; 3838 while (1) { 3839 tmp = from; 3840 from = SrcScan(ctx->text.source, from, XawstEOL, XawsdLeft, 3841 1 + !first, False); 3842 XawTextSourceRead(ctx->text.source, from, &block, 1); 3843 if (block.length == 0 || 3844 (XawTextFormat(ctx, XawFmt8Bit) && 3845 block.ptr[0] != ' ' && 3846 block.ptr[0] != '\t' && 3847 !isalnum(*(unsigned char*)block.ptr)) || 3848 (XawTextFormat(ctx, XawFmtWide) && 3849 _Xaw_atowc(XawSP) != *(wchar_t*)block.ptr && 3850 _Xaw_atowc(XawTAB) != *(wchar_t*)block.ptr && 3851 !iswalnum((wint_t)*(wchar_t*)block.ptr)) || 3852 BlankLine((Widget)ctx, from, NULL)) { 3853 from = tmp; 3854 break; 3855 } 3856 if (from == tmp && !first) 3857 break; 3858 first = False; 3859 } 3860 if (first) 3861 return (False); 3862 3863 /* find to position */ 3864 first = True; 3865 while (1) { 3866 tmp = to; 3867 to = SrcScan(ctx->text.source, to, XawstEOL, XawsdRight, 3868 1 + !first, False); 3869 XawTextSourceRead(ctx->text.source, to + (to < ctx->text.lastPos), 3870 &block, 1); 3871 if (block.length == 0 || 3872 (XawTextFormat(ctx, XawFmt8Bit) && 3873 block.ptr[0] != ' ' && 3874 block.ptr[0] != '\t' && 3875 !isalnum(*(unsigned char*)block.ptr)) || 3876 (XawTextFormat(ctx, XawFmtWide) && 3877 _Xaw_atowc(XawSP) != *(wchar_t*)block.ptr && 3878 _Xaw_atowc(XawTAB) != *(wchar_t*)block.ptr && 3879 !iswalnum((wint_t)*(wchar_t*)block.ptr)) || 3880 BlankLine((Widget)ctx, to, NULL)) 3881 break; 3882 if (to == tmp && !first) 3883 break; 3884 first = False; 3885 } 3886 } 3887 } 3888 else { 3889 from = SrcScan(ctx->text.source, ctx->text.insertPos, XawstEOL, 3890 XawsdLeft, 1, False); 3891 if (BlankLine((Widget)ctx, from, NULL)) 3892 return (False); 3893 from = SrcScan(ctx->text.source, from, XawstParagraph, 3894 XawsdLeft, 1, False); 3895 if (BlankLine((Widget)ctx, from, NULL)) 3896 from = SrcScan(ctx->text.source, from, XawstEOL, 3897 XawsdRight, 1, True); 3898 to = SrcScan(ctx->text.source, from, XawstParagraph, 3899 XawsdRight, 1, False); 3900 } 3901 3902 if (from < to) { 3903 *from_return = from; 3904 *to_return = to; 3905 return (True); 3906 } 3907 3908 return (False); 3909} 3910#endif /* OLDXAW */ 3911 3912/* FormParagraph() - action 3913 * 3914 * removes and reinserts CRs to maximize line length without clipping */ 3915/*ARGSUSED*/ 3916static void 3917FormParagraph(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED) 3918{ 3919 TextWidget ctx = (TextWidget)w; 3920 XawTextPosition from, to, buf[32], *pos; 3921#ifndef OLDXAW 3922 XawTextPosition endPos = 0; 3923 char *lbuf = NULL, *rbuf; 3924 TextSrcObject src = (TextSrcObject)ctx->text.source; 3925 Cardinal i; 3926 Bool undo = src->textSrc.enable_undo && src->textSrc.undo_state == False; 3927#endif 3928 3929 StartAction(ctx, event); 3930 3931#ifndef OLDXAW 3932 pos = XawStackAlloc(sizeof(XawTextPosition) * src->textSrc.num_text, buf); 3933 for (i = 0; i < src->textSrc.num_text; i++) 3934 pos[i] = ((TextWidget)src->textSrc.text[i])->text.old_insert; 3935#else 3936 pos = buf; 3937 *pos = ctx->text.old_insert; 3938#endif 3939 3940#ifndef OLDXAW 3941 if (!GetBlockBoundaries(ctx, &from, &to)) { 3942 EndAction(ctx); 3943 XawStackFree(pos, buf); 3944 return; 3945 } 3946 3947 if (undo) { 3948 src->textSrc.undo_state = True; 3949 lbuf = _XawTextGetText(ctx, from, to); 3950 endPos = ctx->text.lastPos; 3951 } 3952 3953 if (FormRegion(ctx, from, to, pos, (int)src->textSrc.num_text) == XawReplaceError) { 3954 XawStackFree(pos, buf); 3955 pos = buf; 3956#else 3957 from = SrcScan(ctx->text.source, ctx->text.insertPos, 3958 XawstParagraph, XawsdLeft, 1, False); 3959 to = SrcScan(ctx->text.source, from, 3960 XawstParagraph, XawsdRight, 1, False); 3961 3962 if (FormRegion(ctx, from, to, pos, 1) == XawReplaceError) { 3963#endif 3964 XBell(XtDisplay(w), 0); 3965#ifndef OLDXAW 3966 if (undo) { 3967 src->textSrc.undo_state = False; 3968 XtFree(lbuf); 3969 } 3970#endif 3971 } 3972#ifndef OLDXAW 3973 else if (undo) { 3974 /* makes the form-paragraph only one undo/redo step */ 3975 unsigned llen, rlen, size; 3976 XawTextBlock block; 3977 3978 llen = (unsigned)(to - from); 3979 rlen = (unsigned)(llen + (ctx->text.lastPos - endPos)); 3980 3981 block.firstPos = 0; 3982 block.format = (unsigned long)_XawTextFormat(ctx); 3983 3984 rbuf = _XawTextGetText(ctx, from, from + rlen); 3985 3986 size = XawTextFormat(ctx, XawFmtWide) ? sizeof(wchar_t) : sizeof(char); 3987 if (llen != rlen || memcmp(lbuf, rbuf, llen * size)) { 3988 block.ptr = lbuf; 3989 block.length = (int)llen; 3990 _XawTextReplace(ctx, from, from + rlen, &block); 3991 3992 src->textSrc.undo_state = False; 3993 block.ptr = rbuf; 3994 block.length = (int)rlen; 3995 _XawTextReplace(ctx, from, from + llen, &block); 3996 } 3997 else 3998 src->textSrc.undo_state = False; 3999 XtFree(lbuf); 4000 XtFree(rbuf); 4001 } 4002 4003 for (i = 0; i < src->textSrc.num_text; i++) { 4004 TextWidget tw = (TextWidget)src->textSrc.text[i]; 4005 4006 tw->text.old_insert = tw->text.insertPos = pos[i]; 4007 _XawTextBuildLineTable(tw, SrcScan((Widget)src, tw->text.lt.top, XawstEOL, 4008 XawsdLeft, 1, False), False); 4009 tw->text.clear_to_eol = True; 4010 } 4011 XawStackFree(pos, buf); 4012#else 4013 ctx->text.old_insert = ctx->text.insertPos = *pos; 4014 _XawTextBuildLineTable(ctx, SrcScan(ctx->text.source, ctx->text.lt.top, 4015 XawstEOL, XawsdLeft, 1, False), False); 4016 ctx->text.clear_to_eol = True; 4017#endif 4018 ctx->text.showposition = True; 4019 4020 EndAction(ctx); 4021} 4022 4023/* TransposeCharacters() - action 4024 * 4025 * Swaps the character to the left of the mark 4026 * with the character to the right of the mark */ 4027/*ARGSUSED*/ 4028static void 4029TransposeCharacters(Widget w, XEvent *event, 4030 String *params _X_UNUSED, Cardinal *num_params _X_UNUSED) 4031{ 4032 TextWidget ctx = (TextWidget)w; 4033 XawTextPosition start, end; 4034 XawTextBlock text; 4035 char *buf; 4036 int i, mult = MULT(ctx); 4037 4038 if (mult < 0) { 4039 ctx->text.mult = 1; 4040 return; 4041 } 4042 4043 StartAction(ctx, event); 4044 4045 /* Get bounds. */ 4046 4047 start = SrcScan(ctx->text.source, ctx->text.insertPos, XawstPositions, 4048 XawsdLeft, 1, True); 4049 end = SrcScan(ctx->text.source, ctx->text.insertPos, XawstPositions, 4050 XawsdRight, mult, True); 4051 4052 /* Make sure we aren't at the very beginning or end of the buffer. */ 4053 4054 if (start == ctx->text.insertPos || end == ctx->text.insertPos) { 4055 XBell(XtDisplay(w), 0); /* complain. */ 4056 EndAction(ctx); 4057 return; 4058 } 4059 4060 ctx->text.from_left = -1; 4061 ctx->text.insertPos = end; 4062 4063 text.firstPos = 0; 4064 text.format = (unsigned long)_XawTextFormat(ctx); 4065 4066 /* Retrieve text and swap the characters. */ 4067 if (text.format == XawFmtWide) { 4068 wchar_t wc; 4069 wchar_t *wbuf; 4070 4071 wbuf = (wchar_t*)_XawTextGetText(ctx, start, end); 4072 text.length = (int)wcslen(wbuf); 4073 wc = wbuf[0]; 4074 for (i = 1; i < text.length; i++) 4075 wbuf[i - 1] = wbuf[i]; 4076 wbuf[i - 1] = wc; 4077 buf = (char*)wbuf; /* so that it gets assigned and freed */ 4078 } 4079 else { /* thus text.format == XawFmt8Bit */ 4080 char c; 4081 4082 buf = _XawTextGetText(ctx, start, end); 4083 text.length = (int)strlen(buf); 4084 c = buf[0]; 4085 for (i = 1; i < text.length; i++) 4086 buf[i - 1] = buf[i]; 4087 buf[i - 1] = c; 4088 } 4089 4090 text.ptr = buf; 4091 4092 /* Store new text in source. */ 4093 4094 if (_XawTextReplace (ctx, start, end, &text)) 4095 XBell(XtDisplay(w), 0); 4096 XtFree((char *)buf); 4097 EndAction(ctx); 4098} 4099 4100#ifndef OLDXAW 4101/*ARGSUSED*/ 4102static void 4103Undo(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED) 4104{ 4105 TextWidget ctx = (TextWidget)w; 4106 int mul = MULT(ctx); 4107 Bool toggle = False; 4108 4109 if (mul < 0) { 4110 toggle = True; 4111 _XawTextSrcToggleUndo((TextSrcObject)ctx->text.source); 4112 ctx->text.mult = (short)(mul = -mul); 4113 } 4114 4115 StartAction(ctx, event); 4116 for (; mul; --mul) 4117 if (!_XawTextSrcUndo((TextSrcObject)ctx->text.source, &ctx->text.insertPos)) 4118 break; 4119 ctx->text.showposition = True; 4120 4121 if (toggle) 4122 _XawTextSrcToggleUndo((TextSrcObject)ctx->text.source); 4123 EndAction(ctx); 4124} 4125#endif 4126 4127/* NoOp() - action 4128 * This action performs no action, and allows the user or 4129 * application programmer to unbind a translation. 4130 * 4131 * Note: If the parameter list contains the string "RingBell" then 4132 * this action will ring the bell. 4133 */ 4134/*ARGSUSED*/ 4135static void 4136NoOp(Widget w, XEvent *event _X_UNUSED, String *params, Cardinal *num_params) 4137{ 4138 if (*num_params != 1) 4139 return; 4140 4141 switch(params[0][0]) { 4142 case 'R': 4143 case 'r': 4144 XBell(XtDisplay(w), 0); 4145 /*FALLTHROUGH*/ 4146 default: 4147 break; 4148 } 4149} 4150 4151/* Reconnect() - action 4152 * This reconnects to the input method. The user will typically call 4153 * this action if/when connection has been severed, or when the app 4154 * was started up before an IM was started up 4155 */ 4156/*ARGSUSED*/ 4157static void 4158Reconnect(Widget w, XEvent *event _X_UNUSED, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED) 4159{ 4160 _XawImReconnect(w); 4161} 4162 4163#define CAPITALIZE 1 4164#define DOWNCASE 2 4165#define UPCASE 3 4166 4167#ifdef NO_LIBC_I18N 4168static int 4169ToLower(int ch) 4170{ 4171 char buf[2]; 4172 4173 *buf = ch; 4174 XmuNCopyISOLatin1Lowered(buf, buf, sizeof(buf)); 4175 4176 return (*buf); 4177} 4178 4179static int 4180ToUpper(int ch) 4181{ 4182 char buf[2]; 4183 4184 *buf = ch; 4185 XmuNCopyISOLatin1Uppered(buf, buf, sizeof(buf)); 4186 4187 return (*buf); 4188} 4189 4190static int 4191IsAlnum(int ch) 4192{ 4193 return ((ch >= '0' && ch <= '9') || ToUpper(ch) != ch || ToLower(ch) != ch); 4194} 4195 4196static int 4197IsLower(int ch) 4198{ 4199 char upbuf[2]; 4200 char lobuf[2]; 4201 4202 *upbuf = *lobuf = ch; 4203 XmuNCopyISOLatin1Lowered(lobuf, lobuf, sizeof(lobuf)); 4204 XmuNCopyISOLatin1Uppered(upbuf, upbuf, sizeof(upbuf)); 4205 4206 return (*lobuf != *upbuf && ch == *lobuf); 4207} 4208 4209static int 4210IsUpper(int ch) 4211{ 4212 char upbuf[2]; 4213 char lobuf[2]; 4214 4215 *upbuf = *lobuf = ch; 4216 XmuNCopyISOLatin1Lowered(lobuf, lobuf, sizeof(lobuf)); 4217 XmuNCopyISOLatin1Uppered(upbuf, upbuf, sizeof(upbuf)); 4218 4219 return (*lobuf != *upbuf && ch == *upbuf); 4220} 4221#else 4222#define ToLower tolower 4223#define ToUpper toupper 4224#define IsAlnum isalnum 4225#define IsLower islower 4226#define IsUpper isupper 4227#endif 4228 4229static void 4230CaseProc(Widget w, XEvent *event, int cmd) 4231{ 4232 TextWidget ctx = (TextWidget)w; 4233 short mul = MULT(ctx); 4234 XawTextPosition left, right; 4235 XawTextBlock block; 4236 Bool changed = False; 4237 unsigned char ch, mb[sizeof(wchar_t)]; 4238 int i, count; 4239 4240 if (mul > 0) 4241 right = SrcScan(ctx->text.source, left = ctx->text.insertPos, 4242 XawstAlphaNumeric, XawsdRight, mul, False); 4243 else 4244 left = SrcScan(ctx->text.source, right = ctx->text.insertPos, 4245 XawstAlphaNumeric, XawsdLeft, 1 + -mul, False); 4246 block.firstPos = 0; 4247 block.format = (unsigned long)_XawTextFormat(ctx); 4248 block.length = (int)(right - left); 4249 block.ptr = _XawTextGetText(ctx, left, right); 4250 4251 count = 0; 4252 if (block.format == XawFmt8Bit) 4253 for (i = 0; i < block.length; i++) { 4254 if (!IsAlnum(*mb = (unsigned char)block.ptr[i])) 4255 count = 0; 4256 else if (++count == 1 || cmd != CAPITALIZE) { 4257 ch = (unsigned char)((cmd == DOWNCASE) ? ToLower(*mb) : ToUpper(*mb)); 4258 if (ch != *mb) { 4259 changed = True; 4260 block.ptr[i] = (char)ch; 4261 } 4262 } 4263 else if (cmd == CAPITALIZE) { 4264 if ((ch = (unsigned char)(ToLower(*mb))) != *mb) { 4265 changed = True; 4266 block.ptr[i] = (char)ch; 4267 } 4268 } 4269 } 4270 else 4271 for (i = 0; i < block.length; i++) { 4272 wctomb((char*)mb, ((wchar_t*)block.ptr)[i]); 4273 if (!IsAlnum(*mb)) 4274 count = 0; 4275 else if (++count == 1 || cmd != CAPITALIZE) { 4276 ch = (unsigned char)((cmd == DOWNCASE) ? ToLower(*mb) : ToUpper(*mb)); 4277 if (ch != *mb) { 4278 changed = True; 4279 ((wchar_t*)block.ptr)[i] = _Xaw_atowc(ch); 4280 } 4281 } 4282 else if (cmd == CAPITALIZE) { 4283 if ((ch = (unsigned char)(ToLower(*mb))) != *mb) { 4284 changed = True; 4285 ((wchar_t*)block.ptr)[i] = _Xaw_atowc(ch); 4286 } 4287 } 4288 } 4289 4290 StartAction(ctx, event); 4291 if (changed && _XawTextReplace(ctx, left, right, &block) != XawEditDone) 4292 XBell(XtDisplay(ctx), 0); 4293 ctx->text.insertPos = right; 4294 EndAction(ctx); 4295 4296 XtFree(block.ptr); 4297} 4298 4299/*ARGSUSED*/ 4300static void 4301CapitalizeWord(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED) 4302{ 4303 CaseProc(w, event, CAPITALIZE); 4304} 4305 4306/*ARGSUSED*/ 4307static void 4308DowncaseWord(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED) 4309{ 4310 CaseProc(w, event, DOWNCASE); 4311} 4312 4313/*ARGSUSED*/ 4314static void 4315UpcaseWord(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED) 4316{ 4317 CaseProc(w, event, UPCASE); 4318} 4319#undef CAPITALIZE 4320#undef DOWNCASE 4321#undef UPCASE 4322 4323XtActionsRec _XawTextActionsTable[] = { 4324 /* motion */ 4325 {"forward-character", MoveForwardChar}, 4326 {"backward-character", MoveBackwardChar}, 4327 {"forward-word", MoveForwardWord}, 4328 {"backward-word", MoveBackwardWord}, 4329 {"forward-paragraph", MoveForwardParagraph}, 4330 {"backward-paragraph", MoveBackwardParagraph}, 4331 {"beginning-of-line", MoveToLineStart}, 4332 {"end-of-line", MoveToLineEnd}, 4333 {"next-line", MoveNextLine}, 4334 {"previous-line", MovePreviousLine}, 4335 {"next-page", MoveNextPage}, 4336 {"previous-page", MovePreviousPage}, 4337 {"beginning-of-file", MoveBeginningOfFile}, 4338 {"end-of-file", MoveEndOfFile}, 4339 {"scroll-one-line-up", ScrollOneLineUp}, 4340 {"scroll-one-line-down", ScrollOneLineDown}, 4341 4342 /* delete */ 4343 {"delete-next-character", DeleteForwardChar}, 4344 {"delete-previous-character", DeleteBackwardChar}, 4345 {"delete-next-word", DeleteForwardWord}, 4346 {"delete-previous-word", DeleteBackwardWord}, 4347 {"delete-selection", DeleteCurrentSelection}, 4348 {"delete", Delete}, 4349 4350 /* kill */ 4351 {"kill-word", KillForwardWord}, 4352 {"backward-kill-word", KillBackwardWord}, 4353 {"kill-selection", KillCurrentSelection}, 4354 {"kill-to-end-of-line", KillToEndOfLine}, 4355 {"kill-to-end-of-paragraph", KillToEndOfParagraph}, 4356 4357 /* new line */ 4358 {"newline-and-indent", InsertNewLineAndIndent}, 4359 {"newline-and-backup", InsertNewLineAndBackup}, 4360 {"newline", InsertNewLine}, 4361 4362 /* selection */ 4363 {"select-word", SelectWord}, 4364 {"select-all", SelectAll}, 4365 {"select-start", SelectStart}, 4366 {"select-adjust", SelectAdjust}, 4367 {"select-end", SelectEnd}, 4368 {"select-save", SelectSave}, 4369 {"extend-start", ExtendStart}, 4370 {"extend-adjust", ExtendAdjust}, 4371 {"extend-end", ExtendEnd}, 4372 {"insert-selection", InsertSelection}, 4373 4374 /* miscellaneous */ 4375 {"redraw-display", RedrawDisplay}, 4376 {"insert-file", _XawTextInsertFile}, 4377 {"search", _XawTextSearch}, 4378 {"insert-char", InsertChar}, 4379 {"insert-string", InsertString}, 4380 {"focus-in", TextFocusIn}, 4381 {"focus-out", TextFocusOut}, 4382 {"enter-window", TextEnterWindow}, 4383 {"leave-window", TextLeaveWindow}, 4384 {"display-caret", DisplayCaret}, 4385 {"multiply", Multiply}, 4386 {"form-paragraph", FormParagraph}, 4387 {"transpose-characters", TransposeCharacters}, 4388 {"set-keyboard-focus", SetKeyboardFocus}, 4389#ifndef OLDXAW 4390 {"numeric", Numeric}, 4391 {"undo", Undo}, 4392 {"keyboard-reset", KeyboardReset}, 4393 {"kill-ring-yank", KillRingYank}, 4394 {"toggle-overwrite", ToggleOverwrite}, 4395 {"indent", Indent}, 4396#endif 4397 {"no-op", NoOp}, 4398 4399 /* case transformations */ 4400 {"capitalize-word", CapitalizeWord}, 4401 {"downcase-word", DowncaseWord}, 4402 {"upcase-word", UpcaseWord}, 4403 4404 /* action to bind translations for text dialogs */ 4405 {"InsertFileAction", _XawTextInsertFileAction}, 4406 {"DoSearchAction", _XawTextDoSearchAction}, 4407 {"DoReplaceAction", _XawTextDoReplaceAction}, 4408 {"SetField", _XawTextSetField}, 4409 {"PopdownSearchAction", _XawTextPopdownSearchAction}, 4410 4411 /* reconnect to Input Method */ 4412 {"reconnect-im", Reconnect} /* Li Yuhong, Omron KK, 1991 */ 4413}; 4414 4415Cardinal _XawTextActionsTableCount = XtNumber(_XawTextActionsTable); 4416