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