1 /* $XConsortium: Text.c /main/198 1995/08/17 09:37:40 kaleb $ */
2
3 /*
4 * MODIFIED FOR N*XTSTEP LOOK by Carlos A M dos Santos - 1999
5 * <casantos@cpmet.ufpel.tche.br>
6 */
7
8 /***********************************************************
9
10 Copyright (c) 1987, 1988, 1994 X Consortium
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in
20 all copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
26 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
27 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28
29 Except as contained in this notice, the name of the X Consortium shall not be
30 used in advertising or otherwise to promote the sale, use or other dealings
31 in this Software without prior written authorization from the X Consortium.
32
33
34 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
35
36 All Rights Reserved
37
38 Permission to use, copy, modify, and distribute this software and its
39 documentation for any purpose and without fee is hereby granted,
40 provided that the above copyright notice appear in all copies and that
41 both that copyright notice and this permission notice appear in
42 supporting documentation, and that the name of Digital not be
43 used in advertising or publicity pertaining to distribution of the
44 software without specific, written prior permission.
45
46 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
47 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
48 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
49 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
50 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
51 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
52 SOFTWARE.
53
54 ******************************************************************/
55
56 /* $XFree86: xc/lib/Xaw/Text.c,v 3.2.4.3 1998/10/04 13:36:29 hohndel Exp $ */
57
58 #include <X11/IntrinsicP.h>
59 #include <X11/StringDefs.h>
60 #include <X11/Shell.h>
61 #include <X11/Xatom.h>
62 #include <X11/Xutil.h>
63 #include "XawI18n.h"
64 #include <stdio.h>
65 #include <stdlib.h>
66
67 #include <X11/Xmu/Atoms.h>
68 #include <X11/Xmu/CharSet.h>
69 #include <X11/Xmu/Converters.h>
70 #include <X11/Xmu/StdSel.h>
71 #include <X11/Xmu/Misc.h>
72
73 #include "XawInit.h"
74 #include "Cardinals.h"
75 #include "Scrollbar.h"
76 #include "TextP.h"
77 #include "MultiSinkP.h"
78 #include "XawImP.h"
79 #include "TraversalP.h"
80 #include "ThreeDP.h"
81 #include "Misc.h"
82
83 #include <X11/Xfuncs.h>
84 #include <ctype.h> /* for isprint() */
85
86 #include "XawAlloc.h"
87
88 #ifndef MAX_LEN_CT
89 #define MAX_LEN_CT 6 /* for sequence: ESC $ ( A \xx \xx */
90 #endif
91
92 unsigned long FMT8BIT = 0L;
93 unsigned long XawFmt8Bit = 0L;
94 unsigned long XawFmtWide = 0L;
95
96 #define SinkClearToBG XawTextSinkClearToBackground
97
98 #define SrcScan XawTextSourceScan
99 #define SrcRead XawTextSourceRead
100 #define SrcReplace XawTextSourceReplace
101 #define SrcSearch XawTextSourceSearch
102 #define SrcCvtSel XawTextSourceConvertSelection
103 #define SrcSetSelection XawTextSourceSetSelection
104
105 #define BIGNUM ((Dimension)32023)
106 #define MULTI_CLICK_TIME 500L
107
108 /*
109 * Compute a the maximum length of a cut buffer that we can pass at any
110 * time. The 64 allows for the overhead of the Change Property request.
111 */
112
113 #define MAX_CUT_LEN(dpy) (XMaxRequestSize(dpy) - 64)
114
115 #define IsValidLine(ctx, num) ( ((num) == 0) || \
116 ((ctx)->text.lt.info[(num)].position != 0) )
117
118 /*
119 * Defined in Text.c
120 */
121 static void UnrealizeScrollbars();
122 static void VScroll(), VJump(), HScroll(), HJump(), ClearWindow();
123 static void DisplayTextWindow(), ModifySelection(), PushCopyQueue();
124 static void UpdateTextInLine(), UpdateTextInRectangle(), PopCopyQueue();
125 static void FlushUpdate();
126 static Boolean LineAndXYForPosition(), TranslateExposeRegion();
127 static XawTextPosition FindGoodPosition(), _BuildLineTable();
128
129 void _XawTextAlterSelection(), _XawTextExecuteUpdate();
130 void _XawTextSetScrollBars(), _XawTextPrepareToUpdate();
131
132 /****************************************************************
133 *
134 * Full class record constant
135 *
136 ****************************************************************/
137
138 static XawTextSelectType defaultSelectTypes[] = {
139 XawselectPosition, XawselectWord, XawselectLine, XawselectParagraph,
140 XawselectAll, XawselectNull,
141 };
142
143 static XPointer defaultSelectTypesPtr = (XPointer)defaultSelectTypes;
144 extern char *_XawDefaultTextTranslations1, *_XawDefaultTextTranslations2,
145 *_XawDefaultTextTranslations3, *_XawDefaultTextTranslations4;
146 static Dimension defWidth = 100;
147 static Dimension defHeight = DEFAULT_TEXT_HEIGHT;
148
149 #define offset(field) XtOffsetOf(TextRec, field)
150 static XtResource resources[] = {
151 {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
152 offset(core.width), XtRDimension, (XtPointer)&defWidth},
153 {XtNcursor, XtCCursor, XtRCursor, sizeof(Cursor),
154 offset(simple.cursor), XtRString, "xterm"},
155 {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
156 offset(core.height), XtRDimension, (XtPointer)&defHeight},
157 {XtNdisplayPosition, XtCTextPosition, XtRInt, sizeof(XawTextPosition),
158 offset(text.lt.top), XtRImmediate, (XtPointer)0},
159 {XtNinsertPosition, XtCTextPosition, XtRInt, sizeof(XawTextPosition),
160 offset(text.insertPos), XtRImmediate,(XtPointer)0},
161 {XtNleftMargin, XtCMargin, XtRPosition, sizeof (Position),
162 offset(text.r_margin.left), XtRImmediate, (XtPointer)2},
163 {XtNrightMargin, XtCMargin, XtRPosition, sizeof (Position),
164 offset(text.r_margin.right), XtRImmediate, (XtPointer)4},
165 {XtNtopMargin, XtCMargin, XtRPosition, sizeof (Position),
166 offset(text.r_margin.top), XtRImmediate, (XtPointer)2},
167 {XtNbottomMargin, XtCMargin, XtRPosition, sizeof (Position),
168 offset(text.r_margin.bottom), XtRImmediate, (XtPointer)2},
169 {XtNselectTypes, XtCSelectTypes, XtRPointer,
170 sizeof(XawTextSelectType*), offset(text.sarray),
171 XtRPointer, (XtPointer)&defaultSelectTypesPtr},
172 {XtNtextSource, XtCTextSource, XtRWidget, sizeof (Widget),
173 offset(text.source), XtRImmediate, NULL},
174 {XtNtextSink, XtCTextSink, XtRWidget, sizeof (Widget),
175 offset(text.sink), XtRImmediate, NULL},
176 {XtNdisplayCaret, XtCOutput, XtRBoolean, sizeof(Boolean),
177 offset(text.display_caret), XtRImmediate, (XtPointer)True},
178 {XtNscrollVertical, XtCScroll, XtRScrollMode, sizeof(XawTextScrollMode),
179 offset(text.scroll_vert), XtRImmediate, (XtPointer) XawtextScrollNever},
180 {XtNscrollHorizontal, XtCScroll, XtRScrollMode, sizeof(XawTextScrollMode),
181 offset(text.scroll_horiz), XtRImmediate, (XtPointer) XawtextScrollNever},
182 {XtNwrap, XtCWrap, XtRWrapMode, sizeof(XawTextWrapMode),
183 offset(text.wrap), XtRImmediate, (XtPointer) XawtextWrapNever},
184 {XtNresize, XtCResize, XtRResizeMode, sizeof(XawTextResizeMode),
185 offset(text.resize), XtRImmediate, (XtPointer) XawtextResizeNever},
186 {XtNautoFill, XtCAutoFill, XtRBoolean, sizeof(Boolean),
187 offset(text.auto_fill), XtRImmediate, (XtPointer) FALSE},
188 {XtNunrealizeCallback, XtCCallback, XtRCallback, sizeof(XtPointer),
189 offset(text.unrealize_callbacks), XtRCallback, (XtPointer) NULL}
190 };
191 #undef offset
192
193 #define done(address, type) \
194 { toVal->size = sizeof(type); toVal->addr = (XPointer) address; }
195
196
197
198 /* ARGSUSED */
199 static void
CvtStringToScrollMode(args,num_args,fromVal,toVal)200 CvtStringToScrollMode(args, num_args, fromVal, toVal)
201 XrmValuePtr args; /* unused */
202 Cardinal *num_args; /* unused */
203 XrmValuePtr fromVal;
204 XrmValuePtr toVal;
205 {
206 static XawTextScrollMode scrollMode;
207 static XrmQuark QScrollNever, QScrollAlways, QScrollWhenNeeded;
208 XrmQuark q;
209 char lowerName[BUFSIZ];
210 static Boolean inited = FALSE;
211
212 if ( !inited ) {
213 QScrollNever = XrmPermStringToQuark(XtEtextScrollNever);
214 QScrollWhenNeeded = XrmPermStringToQuark(XtEtextScrollWhenNeeded);
215 QScrollAlways = XrmPermStringToQuark(XtEtextScrollAlways);
216 inited = TRUE;
217 }
218
219 if (strlen((char *)fromVal->addr) >= sizeof(lowerName)) {
220 XtStringConversionWarning((char *) fromVal->addr, XtRScrollMode);
221 return;
222 }
223 XmuCopyISOLatin1Lowered (lowerName, (char *)fromVal->addr);
224 q = XrmStringToQuark(lowerName);
225
226 if (q == QScrollNever) scrollMode = XawtextScrollNever;
227 else if (q == QScrollWhenNeeded) scrollMode = XawtextScrollWhenNeeded;
228 else if (q == QScrollAlways) scrollMode = XawtextScrollAlways;
229 else {
230 XtStringConversionWarning((char *) fromVal->addr, XtRScrollMode);
231 return;
232 }
233 done(&scrollMode, XawTextScrollMode);
234 return;
235 }
236
237 /* ARGSUSED */
238 static void
CvtStringToWrapMode(args,num_args,fromVal,toVal)239 CvtStringToWrapMode(args, num_args, fromVal, toVal)
240 XrmValuePtr args; /* unused */
241 Cardinal *num_args; /* unused */
242 XrmValuePtr fromVal;
243 XrmValuePtr toVal;
244 {
245 static XawTextWrapMode wrapMode;
246 static XrmQuark QWrapNever, QWrapLine, QWrapWord;
247 XrmQuark q;
248 char lowerName[BUFSIZ];
249 static Boolean inited = FALSE;
250
251 if ( !inited ) {
252 QWrapNever = XrmPermStringToQuark(XtEtextWrapNever);
253 QWrapLine = XrmPermStringToQuark(XtEtextWrapLine);
254 QWrapWord = XrmPermStringToQuark(XtEtextWrapWord);
255 inited = TRUE;
256 }
257
258 if (strlen((char *)fromVal->addr) >= sizeof(lowerName)) {
259 XtStringConversionWarning((char *) fromVal->addr, XtRWrapMode);
260 return;
261 }
262 XmuCopyISOLatin1Lowered (lowerName, (char *)fromVal->addr);
263 q = XrmStringToQuark(lowerName);
264
265 if (q == QWrapNever) wrapMode = XawtextWrapNever;
266 else if (q == QWrapLine) wrapMode = XawtextWrapLine;
267 else if (q == QWrapWord) wrapMode = XawtextWrapWord;
268 else {
269 XtStringConversionWarning((char *) fromVal->addr, XtRWrapMode);
270 return;
271 }
272 done(&wrapMode, XawTextWrapMode);
273 return;
274 }
275
276 /* ARGSUSED */
277 static void
CvtStringToResizeMode(args,num_args,fromVal,toVal)278 CvtStringToResizeMode(args, num_args, fromVal, toVal)
279 XrmValuePtr args; /* unused */
280 Cardinal *num_args; /* unused */
281 XrmValuePtr fromVal;
282 XrmValuePtr toVal;
283 {
284 static XawTextResizeMode resizeMode;
285 static XrmQuark QResizeNever, QResizeWidth, QResizeHeight, QResizeBoth;
286 XrmQuark q;
287 char lowerName[BUFSIZ];
288 static Boolean inited = FALSE;
289
290 if ( !inited ) {
291 QResizeNever = XrmPermStringToQuark(XtEtextResizeNever);
292 QResizeWidth = XrmPermStringToQuark(XtEtextResizeWidth);
293 QResizeHeight = XrmPermStringToQuark(XtEtextResizeHeight);
294 QResizeBoth = XrmPermStringToQuark(XtEtextResizeBoth);
295 inited = TRUE;
296 }
297
298 if (strlen((char *)fromVal->addr) >= sizeof(lowerName)) {
299 XtStringConversionWarning((char *) fromVal->addr, XtRResizeMode);
300 return;
301 }
302 XmuCopyISOLatin1Lowered (lowerName, (char *)fromVal->addr);
303 q = XrmStringToQuark(lowerName);
304
305 if (q == QResizeNever) resizeMode = XawtextResizeNever;
306 else if (q == QResizeWidth) resizeMode = XawtextResizeWidth;
307 else if (q == QResizeHeight) resizeMode = XawtextResizeHeight;
308 else if (q == QResizeBoth) resizeMode = XawtextResizeBoth;
309 else {
310 XtStringConversionWarning((char *) fromVal->addr, XtRResizeMode);
311 return;
312 }
313 done(&resizeMode, XawTextResizeMode);
314 return;
315 }
316
317 #undef done
318
319 static void
ClassInitialize()320 ClassInitialize()
321 {
322 int len1 = strlen (_XawDefaultTextTranslations1);
323 int len2 = strlen (_XawDefaultTextTranslations2);
324 int len3 = strlen (_XawDefaultTextTranslations3);
325 int len4 = strlen (_XawDefaultTextTranslations4);
326 char *buf = XtMalloc ((unsigned)(len1 + len2 + len3 + len4 + 1));
327 char *cp = buf;
328
329 if (!XawFmt8Bit)
330 FMT8BIT = XawFmt8Bit = XrmPermStringToQuark("FMT8BIT");
331 if (!XawFmtWide)
332 XawFmtWide = XrmPermStringToQuark("FMTWIDE");
333
334 XawInitializeWidgetSet();
335
336 /*
337 * Set the number of actions.
338 */
339
340 textClassRec.core_class.num_actions = _XawTextActionsTableCount;
341
342 (void) strcpy( cp, _XawDefaultTextTranslations1); cp += len1;
343 (void) strcpy( cp, _XawDefaultTextTranslations2); cp += len2;
344 (void) strcpy( cp, _XawDefaultTextTranslations3); cp += len3;
345 (void) strcpy( cp, _XawDefaultTextTranslations4);
346 textWidgetClass->core_class.tm_table = buf;
347
348 XtAddConverter(XtRString, XtRScrollMode, CvtStringToScrollMode,
349 (XtConvertArgList)NULL, (Cardinal)0 );
350 XtAddConverter(XtRString, XtRWrapMode, CvtStringToWrapMode,
351 (XtConvertArgList)NULL, (Cardinal)0 );
352 XtAddConverter(XtRString, XtRResizeMode, CvtStringToResizeMode,
353 (XtConvertArgList)NULL, (Cardinal)0 );
354 }
355
356 /* Function Name: PositionHScrollBar.
357 * Description: Positions the Horizontal scrollbar.
358 * Arguments: ctx - the text widget.
359 * Returns: none
360 */
361
362 static void
PositionHScrollBar(ctx)363 PositionHScrollBar(ctx)
364 TextWidget ctx;
365 {
366 Widget vbar = ctx->text.vbar, hbar = ctx->text.hbar;
367 Position top, left = 0;
368
369 if (ctx->text.hbar == NULL) return;
370
371 if (vbar != NULL)
372 left += (Position) (vbar->core.width + vbar->core.border_width);
373
374 XtResizeWidget( hbar, ctx->core.width - left, hbar->core.height,
375 hbar->core.border_width );
376
377 left -= (Position) hbar->core.border_width;
378
379 top = ctx->core.height - ( hbar->core.height + hbar->core.border_width);
380 XtMoveWidget( hbar, left, top);
381 }
382
383 /* Function Name: PositionVScrollBar.
384 * Description: Positions the Vertical scrollbar.
385 * Arguments: ctx - the text widget.
386 * Returns: none.
387 */
388
389 static void
PositionVScrollBar(ctx)390 PositionVScrollBar(ctx)
391 TextWidget ctx;
392 {
393 Widget vbar = ctx->text.vbar;
394 Dimension bw;
395
396 if (vbar == NULL) return;
397 bw = vbar->core.border_width;
398
399 XtResizeWidget( vbar, vbar->core.width, ctx->core.height, bw);
400 XtMoveWidget( vbar, -(Position)bw, -(Position)bw );
401 }
402
403 static void
CreateVScrollBar(ctx)404 CreateVScrollBar(ctx)
405 TextWidget ctx;
406 {
407 Widget vbar;
408
409 if (ctx->text.vbar != NULL) return;
410
411 ctx->text.vbar = vbar =
412 XtCreateWidget("vScrollbar", scrollbarWidgetClass, (Widget)ctx,
413 (ArgList) NULL, ZERO);
414 XtAddCallback( vbar, XtNscrollProc, VScroll, (XtPointer)ctx );
415 XtAddCallback( vbar, XtNjumpProc, VJump, (XtPointer)ctx );
416 if (ctx->text.hbar == NULL)
417 XtAddCallback((Widget) ctx, XtNunrealizeCallback, UnrealizeScrollbars,
418 (XtPointer) NULL);
419
420 ctx->text.r_margin.left += vbar->core.width + vbar->core.border_width;
421 ctx->text.margin.left = ctx->text.r_margin.left;
422
423 PositionVScrollBar(ctx);
424 PositionHScrollBar(ctx); /* May modify location of Horiz. Bar. */
425
426 if (XtIsRealized((Widget)ctx)) {
427 XtRealizeWidget(vbar);
428 XtMapWidget(vbar);
429 }
430 }
431
432 /* Function Name: DestroyVScrollBar
433 * Description: Removes a vertical ScrollBar.
434 * Arguments: ctx - the parent text widget.
435 * Returns: none.
436 */
437
438 static void
DestroyVScrollBar(ctx)439 DestroyVScrollBar(ctx)
440 TextWidget ctx;
441 {
442 Widget vbar = ctx->text.vbar;
443
444 if (vbar == NULL) return;
445
446 ctx->text.r_margin.left -= vbar->core.width + vbar->core.border_width;
447 ctx->text.margin.left = ctx->text.r_margin.left;
448 if (ctx->text.hbar == NULL)
449 XtRemoveCallback((Widget) ctx, XtNunrealizeCallback, UnrealizeScrollbars,
450 (XtPointer) NULL);
451 XtDestroyWidget(vbar);
452 ctx->text.vbar = NULL;
453 PositionHScrollBar(ctx);
454 }
455
456 static void
CreateHScrollBar(ctx)457 CreateHScrollBar(ctx)
458 TextWidget ctx;
459 {
460 Arg args[1];
461 Widget hbar;
462
463 if (ctx->text.hbar != NULL) return;
464
465 XtSetArg(args[0], XtNorientation, XtorientHorizontal);
466 ctx->text.hbar = hbar =
467 XtCreateWidget("hScrollbar", scrollbarWidgetClass, (Widget)ctx, args, ONE);
468 XtAddCallback( hbar, XtNscrollProc, HScroll, (XtPointer)ctx );
469 XtAddCallback( hbar, XtNjumpProc, HJump, (XtPointer)ctx );
470 if (ctx->text.vbar == NULL)
471 XtAddCallback((Widget) ctx, XtNunrealizeCallback, UnrealizeScrollbars,
472 (XtPointer) NULL);
473
474 PositionHScrollBar(ctx);
475 if (XtIsRealized((Widget)ctx)) {
476 XtRealizeWidget(hbar);
477 XtMapWidget(hbar);
478 }
479 }
480
481 /* Function Name: DestroyHScrollBar
482 * Description: Removes a horizontal ScrollBar.
483 * Arguments: ctx - the parent text widget.
484 * Returns: none.
485 */
486
487 static void
DestroyHScrollBar(ctx)488 DestroyHScrollBar(ctx)
489 TextWidget ctx;
490 {
491 Widget hbar = ctx->text.hbar;
492
493 if (hbar == NULL) return;
494
495 /*
496 ctx->text.r_margin.bottom -= hbar->core.height + hbar->core.border_width;
497 ctx->text.margin.bottom = ctx->text.r_margin.bottom;
498 */
499 if (ctx->text.vbar == NULL)
500 XtRemoveCallback((Widget) ctx, XtNunrealizeCallback, UnrealizeScrollbars,
501 (XtPointer) NULL);
502 XtDestroyWidget(hbar);
503 ctx->text.hbar = NULL;
504 }
505
506 /* ARGSUSED */
507 static void
Initialize(request,new,args,num_args)508 Initialize(request, new, args, num_args)
509 Widget request, new;
510 ArgList args; /* unused */
511 Cardinal *num_args; /* unused */
512 {
513 TextWidget ctx = (TextWidget) new;
514 char error_buf[BUFSIZ];
515 char *perr;
516 int len;
517
518 ctx->text.lt.lines = 0;
519 ctx->text.lt.info = NULL;
520 (void) bzero((char *) &(ctx->text.origSel), sizeof(XawTextSelection));
521 (void) bzero((char *) &(ctx->text.s), sizeof(XawTextSelection));
522 ctx->text.s.type = XawselectPosition;
523 ctx->text.salt = NULL;
524 ctx->text.hbar = ctx->text.vbar = (Widget) NULL;
525 ctx->text.lasttime = 0; /* ||| correct? */
526 ctx->text.time = 0; /* ||| correct? */
527 ctx->text.showposition = TRUE;
528 ctx->text.lastPos = (ctx->text.source != NULL) ? GETLASTPOS : 0;
529 ctx->text.file_insert = NULL;
530 ctx->text.search = NULL;
531 ctx->text.updateFrom = (XawTextPosition *) XtMalloc((unsigned) ONE);
532 ctx->text.updateTo = (XawTextPosition *) XtMalloc((unsigned) ONE);
533 ctx->text.numranges = ctx->text.maxranges = 0;
534 ctx->text.gc = DefaultGCOfScreen(XtScreen(ctx));
535 ctx->text.hasfocus = FALSE;
536 ctx->text.margin = ctx->text.r_margin; /* Strucure copy. */
537 ctx->text.update_disabled = FALSE;
538 ctx->text.old_insert = -1;
539 ctx->text.mult = 1;
540 ctx->text.single_char = FALSE;
541 ctx->text.copy_area_offsets = NULL;
542 ctx->text.salt2 = NULL;
543
544 /* Create dummy ThreeD widget for the bevel */
545 ctx->text.threeD = XtVaCreateWidget("threeD", threeDWidgetClass, new,
546 XtNx, 0, XtNy, 0, XtNwidth, 10, XtNheight, 10, (char*)0);
547 XtVaGetValues(ctx->text.threeD, XtNshadowWidth,
548 &ctx->text.shadow_width, (char *)0);
549 /* Adjust the margins */
550 ctx->text.r_margin.left += ctx->text.shadow_width;
551 ctx->text.r_margin.right += ctx->text.shadow_width;
552 ctx->text.r_margin.top += ctx->text.shadow_width;
553 ctx->text.r_margin.bottom += ctx->text.shadow_width;
554 ctx->text.margin = ctx->text.r_margin;
555
556 if (ctx->core.height == DEFAULT_TEXT_HEIGHT) {
557 ctx->core.height = VMargins(ctx);
558 if (ctx->text.sink != NULL)
559 ctx->core.height += XawTextSinkMaxHeight(ctx->text.sink, 1);
560 }
561
562 if (ctx->text.scroll_vert != XawtextScrollNever) {
563 if ( (ctx->text.resize == XawtextResizeHeight) ||
564 (ctx->text.resize == XawtextResizeBoth) ) {
565 char *err1 = "Xaw Text Widget ";
566 char *err2 = ":\nVertical scrolling not allowed with height resize.\n";
567 char *err3 = "Vertical scrolling has been DEACTIVATED.";
568 len = strlen(err1) + strlen(err2) + strlen(err3) +
569 strlen(ctx->core.name) + 1;
570 perr = XtStackAlloc(len, error_buf);
571 if (perr != NULL) {
572 (void) sprintf(perr, "%s%s%s%s", err1, ctx->core.name, err2, err3);
573 XtAppWarning(XtWidgetToApplicationContext(new), perr);
574 XtStackFree(perr, error_buf);
575 }
576 ctx->text.scroll_vert = XawtextScrollNever;
577 }
578 else if (ctx->text.scroll_vert == XawtextScrollAlways)
579 CreateVScrollBar(ctx);
580 }
581
582 if (ctx->text.scroll_horiz != XawtextScrollNever) {
583 if (ctx->text.wrap != XawtextWrapNever) {
584 char *err1 = "Xaw Text Widget ";
585 char *err2 = ":\nHorizontal scrolling not allowed with wrapping active.";
586 char *err3 = "\nHorizontal scrolling has been DEACTIVATED.";
587 len = strlen(err1) + strlen(err2) + strlen(err3) +
588 strlen(ctx->core.name) + 1;
589 perr = XtStackAlloc(len, error_buf);
590 if (perr != NULL) {
591 (void) sprintf(perr, "%s%s%s%s", err1, ctx->core.name, err2, err3);
592 XtAppWarning(XtWidgetToApplicationContext(new), perr);
593 XtStackFree(perr, error_buf);
594 }
595 ctx->text.scroll_horiz = XawtextScrollNever;
596 }
597 else if ( (ctx->text.resize == XawtextResizeWidth) ||
598 (ctx->text.resize == XawtextResizeBoth) ) {
599 char *err1 = "Xaw Text Widget ";
600 char *err2 = ":\nHorizontal scrolling not allowed with width resize.\n";
601 char *err3 = "Horizontal scrolling has been DEACTIVATED.";
602 len = strlen(err1) + strlen(err2) + strlen(err3) +
603 strlen(ctx->core.name) + 1;
604 perr = XtStackAlloc(len, error_buf);
605 if (perr != NULL) {
606 (void) sprintf(perr, "%s%s%s%s", err1, ctx->core.name, err2, err3);
607 XtAppWarning(XtWidgetToApplicationContext(new), perr);
608 XtStackFree(perr, error_buf);
609 }
610 ctx->text.scroll_horiz = XawtextScrollNever;
611 }
612 else if (ctx->text.scroll_horiz == XawtextScrollAlways)
613 CreateHScrollBar(ctx);
614 }
615 }
616
617 static void
Realize(w,valueMask,attributes)618 Realize( w, valueMask, attributes )
619 Widget w;
620 Mask *valueMask;
621 XSetWindowAttributes *attributes;
622 {
623 TextWidget ctx = (TextWidget)w;
624 void _XawTextCheckResize();
625
626 (*textClassRec.core_class.superclass->core_class.realize)
627 (w, valueMask, attributes);
628
629 if (ctx->text.hbar != NULL) { /* Put up Hbar -- Must be first. */
630 XtRealizeWidget(ctx->text.hbar);
631 XtMapWidget(ctx->text.hbar);
632 }
633
634 if (ctx->text.vbar != NULL) { /* Put up Vbar. */
635 XtRealizeWidget(ctx->text.vbar);
636 XtMapWidget(ctx->text.vbar);
637 }
638
639 _XawTextBuildLineTable(ctx, ctx->text.lt.top, TRUE);
640 _XawTextSetScrollBars(ctx);
641 _XawTextCheckResize(ctx);
642 }
643
644 /*ARGSUSED*/
UnrealizeScrollbars(widget,client,call)645 static void UnrealizeScrollbars(widget, client, call)
646 Widget widget; /* Text widget */
647 XtPointer client; /* unused */
648 XtPointer call; /* unused */
649 {
650 TextWidget ctx = (TextWidget) widget;
651
652 if (ctx->text.hbar)
653 XtUnrealizeWidget(ctx->text.hbar);
654 if (ctx->text.vbar)
655 XtUnrealizeWidget(ctx->text.vbar);
656 }
657
658 /* Utility routines for support of Text */
659
660 static void
_CreateCutBuffers(d)661 _CreateCutBuffers(d)
662 Display *d;
663 {
664 static struct _DisplayRec {
665 struct _DisplayRec *next;
666 Display *dpy;
667 } *dpy_list = NULL;
668 struct _DisplayRec *dpy_ptr;
669
670 for (dpy_ptr = dpy_list; dpy_ptr != NULL; dpy_ptr = dpy_ptr->next)
671 if (dpy_ptr->dpy == d) return;
672
673 dpy_ptr = XtNew(struct _DisplayRec);
674 dpy_ptr->next = dpy_list;
675 dpy_ptr->dpy = d;
676 dpy_list = dpy_ptr;
677
678 #define Create(buffer) \
679 XChangeProperty(d, RootWindow(d, 0), buffer, XA_STRING, 8, \
680 PropModeAppend, NULL, 0 );
681
682 Create( XA_CUT_BUFFER0 );
683 Create( XA_CUT_BUFFER1 );
684 Create( XA_CUT_BUFFER2 );
685 Create( XA_CUT_BUFFER3 );
686 Create( XA_CUT_BUFFER4 );
687 Create( XA_CUT_BUFFER5 );
688 Create( XA_CUT_BUFFER6 );
689 Create( XA_CUT_BUFFER7 );
690
691 #undef Create
692 }
693
694 /*
695 * Procedure to manage insert cursor visibility for editable text. It uses
696 * the value of ctx->insertPos and an implicit argument. In the event that
697 * position is immediately preceded by an eol graphic, then the insert cursor
698 * is displayed at the beginning of the next line.
699 */
700 static void
InsertCursor(w,state)701 InsertCursor (w, state)
702 Widget w;
703 XawTextInsertState state;
704 {
705 TextWidget ctx = (TextWidget)w;
706 Position x, y;
707 int line;
708
709 if (ctx->text.lt.lines < 1) return;
710
711 if ( LineAndXYForPosition(ctx, ctx->text.insertPos, &line, &x, &y) ) {
712 if (line < ctx->text.lt.lines)
713 y += (ctx->text.lt.info[line + 1].y - ctx->text.lt.info[line].y) + 1;
714 else
715 y += (ctx->text.lt.info[line].y - ctx->text.lt.info[line - 1].y) + 1;
716
717 if (ctx->text.display_caret)
718 XawTextSinkInsertCursor(ctx->text.sink, x, y, state);
719 }
720 ctx->text.ev_x = x;
721 ctx->text.ev_y = y;
722
723 /* Keep Input Method up to speed */
724
725 if ( ctx->simple.international ) {
726 Arg list[1];
727
728 XtSetArg (list[0], XtNinsertPosition, ctx->text.insertPos);
729 _XawImSetValues (w, list, 1);
730 }
731 }
732
733 /*
734 * Procedure to register a span of text that is no longer valid on the display
735 * It is used to avoid a number of small, and potentially overlapping, screen
736 * updates.
737 */
738
739 void
_XawTextNeedsUpdating(ctx,left,right)740 _XawTextNeedsUpdating(ctx, left, right)
741 TextWidget ctx;
742 XawTextPosition left, right;
743 {
744 int i;
745 if (left < right) {
746 for (i = 0; i < ctx->text.numranges; i++) {
747 if (left <= ctx->text.updateTo[i] && right >= ctx->text.updateFrom[i]) {
748 ctx->text.updateFrom[i] = Min(left, ctx->text.updateFrom[i]);
749 ctx->text.updateTo[i] = Max(right, ctx->text.updateTo[i]);
750 return;
751 }
752 }
753 ctx->text.numranges++;
754 if (ctx->text.numranges > ctx->text.maxranges) {
755 ctx->text.maxranges = ctx->text.numranges;
756 i = ctx->text.maxranges * sizeof(XawTextPosition);
757 ctx->text.updateFrom = (XawTextPosition *)
758 XtRealloc((char *)ctx->text.updateFrom, (unsigned) i);
759 ctx->text.updateTo = (XawTextPosition *)
760 XtRealloc((char *)ctx->text.updateTo, (unsigned) i);
761 }
762 ctx->text.updateFrom[ctx->text.numranges - 1] = left;
763 ctx->text.updateTo[ctx->text.numranges - 1] = right;
764 }
765 }
766
767 /*
768 * Procedure to read a span of text in Ascii form. This is purely a hack and
769 * we probably need to add a function to sources to provide this functionality.
770 * [note: this is really a private procedure but is used in multiple modules].
771 */
772
773 char *
_XawTextGetText(ctx,left,right)774 _XawTextGetText(ctx, left, right)
775 TextWidget ctx;
776 XawTextPosition left, right;
777 {
778 char *result, *tempResult;
779 XawTextBlock text;
780 int bytes;
781
782 if (_XawTextFormat(ctx) == XawFmt8Bit)
783 bytes = sizeof(unsigned char);
784 else if (_XawTextFormat(ctx) == XawFmtWide)
785 bytes = sizeof(wchar_t);
786 else /* if there is another fomat, add here */
787 bytes = 1;
788
789 /* leave space for ZERO */
790 tempResult=result=XtMalloc( (unsigned)(((Cardinal)(right-left))+ONE )* bytes);
791 while (left < right) {
792 left = SrcRead(ctx->text.source, left, &text, (int)(right - left));
793 if (!text.length)
794 break;
795 memmove(tempResult, text.ptr, text.length * bytes);
796 tempResult += text.length * bytes;
797 }
798
799 if (bytes == sizeof(wchar_t))
800 *((wchar_t*)tempResult) = (wchar_t)0;
801 else
802 *tempResult = '\0';
803 return(result);
804 }
805
806 /* Like _XawTextGetText, but enforces ICCCM STRING type encoding. This
807 routine is currently used to put just the ASCII chars in the selection into a
808 cut buffer. */
809
810 char *
_XawTextGetSTRING(ctx,left,right)811 _XawTextGetSTRING(ctx, left, right)
812 TextWidget ctx;
813 XawTextPosition left, right;
814 {
815 unsigned char *s;
816 unsigned char c;
817 long i, j, n;
818 wchar_t *ws, wc;
819
820 /* allow ESC in accordance with ICCCM */
821 if (_XawTextFormat(ctx) == XawFmtWide) {
822 MultiSinkObject sink = (MultiSinkObject) ctx->text.sink;
823 ws = (wchar_t *)_XawTextGetText(ctx, left, right);
824 n = wcslen(ws);
825 for (j = 0, i = 0; j < n; j++) {
826 wc = ws[j];
827 if (XwcTextEscapement (sink->multi_sink.fontset, &wc, 1) ||
828 (wc == _Xaw_atowc(XawTAB)) || (wc == _Xaw_atowc(XawLF)) || (wc == _Xaw_atowc(XawESC)))
829 ws[i++] = wc;
830 }
831 ws[i] = (wchar_t)0;
832 return (char *)ws;
833 } else {
834 s = (unsigned char *)_XawTextGetText(ctx, left, right);
835 /* only HT and NL control chars are allowed, strip out others */
836 n = strlen((char *)s);
837 i = 0;
838 for (j = 0; j < n; j++) {
839 c = s[j];
840 if (((c >= 0x20) && c <= 0x7f) ||
841 (c >= 0xa0) || (c == XawTAB) || (c == XawLF) || (c == XawESC)) {
842 s[i] = c;
843 i++;
844 }
845 }
846 s[i] = 0;
847 return (char *)s;
848 }
849 #undef ESC
850
851 }
852
853 /*
854 * This routine maps an x and y position in a window that is displaying text
855 * into the corresponding position in the source.
856 *
857 * NOTE: it is illegal to call this routine unless there is a valid line table!
858 */
859
860 /*** figure out what line it is on ***/
861
862 static XawTextPosition
PositionForXY(ctx,x,y)863 PositionForXY (ctx, x, y)
864 TextWidget ctx;
865 Position x,y;
866 {
867 int fromx, line, width, height;
868 XawTextPosition position;
869
870 if (ctx->text.lt.lines == 0) return 0;
871
872 for (line = 0; line < ctx->text.lt.lines - 1; line++) {
873 if (y <= ctx->text.lt.info[line + 1].y)
874 break;
875 }
876 position = ctx->text.lt.info[line].position;
877 if (position >= ctx->text.lastPos)
878 return(ctx->text.lastPos);
879 fromx = (int) ctx->text.margin.left;
880 XawTextSinkFindPosition( ctx->text.sink, position, fromx, x - fromx,
881 FALSE, &position, &width, &height);
882 if (position > ctx->text.lastPos) return(ctx->text.lastPos);
883 if (position >= ctx->text.lt.info[line + 1].position)
884 position = SrcScan(ctx->text.source, ctx->text.lt.info[line + 1].position,
885 XawstPositions, XawsdLeft, 1, TRUE);
886 return(position);
887 }
888
889 /*
890 * This routine maps a source position in to the corresponding line number
891 * of the text that is displayed in the window.
892 *
893 * NOTE: It is illegal to call this routine unless there is a valid line table!
894 */
895
896 static int
LineForPosition(ctx,position)897 LineForPosition (ctx, position)
898 TextWidget ctx;
899 XawTextPosition position;
900 {
901 int line;
902
903 for (line = 0; line < ctx->text.lt.lines; line++)
904 if (position < ctx->text.lt.info[line + 1].position)
905 break;
906 return(line);
907 }
908
909 /*
910 * This routine maps a source position into the corresponding line number
911 * and the x, y coordinates of the text that is displayed in the window.
912 *
913 * NOTE: It is illegal to call this routine unless there is a valid line table!
914 */
915
916 static Boolean
LineAndXYForPosition(ctx,pos,line,x,y)917 LineAndXYForPosition (ctx, pos, line, x, y)
918 TextWidget ctx;
919 XawTextPosition pos;
920 int *line;
921 Position *x, *y;
922 {
923 XawTextPosition linePos, endPos;
924 Boolean visible;
925 int realW, realH;
926
927 *line = 0;
928 *x = ctx->text.margin.left;
929 *y = ctx->text.margin.top;
930 if ((visible = IsPositionVisible(ctx, pos))) {
931 *line = LineForPosition(ctx, pos);
932 *y = ctx->text.lt.info[*line].y;
933 *x = ctx->text.margin.left;
934 linePos = ctx->text.lt.info[*line].position;
935 XawTextSinkFindDistance( ctx->text.sink, linePos,
936 *x, pos, &realW, &endPos, &realH);
937 *x += realW;
938 }
939 return(visible);
940 }
941
942 /*
943 * This routine builds a line table. It does this by starting at the
944 * specified position and measuring text to determine the staring position
945 * of each line to be displayed. It also determines and saves in the
946 * linetable all the required metrics for displaying a given line (e.g.
947 * x offset, y offset, line length, etc.).
948 */
949
950 void
951 #if NeedFunctionPrototypes
_XawTextBuildLineTable(TextWidget ctx,XawTextPosition position,_XtBoolean force_rebuild)952 _XawTextBuildLineTable (
953 TextWidget ctx,
954 XawTextPosition position,
955 _XtBoolean force_rebuild)
956 #else
957 _XawTextBuildLineTable (ctx, position, force_rebuild)
958 TextWidget ctx;
959 XawTextPosition position;
960 Boolean force_rebuild;
961 #endif
962 {
963 Dimension height = 0;
964 int lines = 0;
965 Cardinal size;
966
967 if ((int)ctx->core.height > VMargins(ctx)) {
968 height = ctx->core.height - VMargins(ctx);
969 lines = XawTextSinkMaxLines(ctx->text.sink, height);
970 }
971 size = sizeof(XawTextLineTableEntry) * (lines + 1);
972
973 if ( (lines != ctx->text.lt.lines) || (ctx->text.lt.info == NULL) ) {
974 ctx->text.lt.info = (XawTextLineTableEntry *) XtRealloc((char *) ctx->text.
975 lt.info, size);
976 ctx->text.lt.lines = lines;
977 force_rebuild = TRUE;
978 }
979
980 if ( force_rebuild || (position != ctx->text.lt.top) ) {
981 (void) bzero((char *) ctx->text.lt.info, size);
982 (void) _BuildLineTable(ctx, ctx->text.lt.top = position, zeroPosition, 0);
983 }
984 }
985
986 /*
987 * This assumes that the line table does not change size.
988 */
989
990 static XawTextPosition
_BuildLineTable(ctx,position,min_pos,line)991 _BuildLineTable(ctx, position, min_pos, line)
992 TextWidget ctx;
993 XawTextPosition position, min_pos;
994 int line;
995 {
996 XawTextLineTableEntry * lt = ctx->text.lt.info + line;
997 XawTextPosition endPos;
998 Position y;
999 int count, width, realW, realH;
1000 Widget src = ctx->text.source;
1001
1002 if ( ((ctx->text.resize == XawtextResizeWidth) ||
1003 (ctx->text.resize == XawtextResizeBoth) ) ||
1004 (ctx->text.wrap == XawtextWrapNever) )
1005 width = BIGNUM;
1006 else
1007 width = Max(0, ((int)ctx->core.width - (int)HMargins(ctx)));
1008
1009 y = ( (line == 0) ? ctx->text.margin.top : lt->y );
1010
1011 /* CONSTCOND */
1012 while ( TRUE ) {
1013 lt->y = y;
1014 lt->position = position;
1015
1016 XawTextSinkFindPosition( ctx->text.sink, position, ctx->text.margin.left,
1017 width, ctx->text.wrap == XawtextWrapWord,
1018 &endPos, &realW, &realH);
1019 lt->textWidth = realW;
1020 y += realH;
1021
1022 if (ctx->text.wrap == XawtextWrapNever)
1023 endPos = SrcScan(src, position, XawstEOL, XawsdRight, 1, TRUE);
1024
1025 if ( endPos == ctx->text.lastPos) { /* We have reached the end. */
1026 if(SrcScan(src, position, XawstEOL, XawsdRight, 1, FALSE) == endPos)
1027 break;
1028 }
1029
1030 ++lt;
1031 ++line;
1032 if ( (line > ctx->text.lt.lines) ||
1033 ((lt->position == (position = endPos)) && (position > min_pos)) )
1034 return(position);
1035 }
1036
1037 /*
1038 * If we are at the end of the buffer put two special lines in the table.
1039 *
1040 * a) Both have position > text.lastPos and lt->textWidth = 0.
1041 * b) The first has a real height, and the second has a height that
1042 * is the rest of the screen.
1043 *
1044 * I could fill in the rest of the table with valid heights and a large
1045 * lastPos, but this method keeps the number of fill regions down to a
1046 * minimum.
1047 *
1048 * One valid entry is needed at the end of the table so that the cursor
1049 * does not jump off the bottom of the window.
1050 */
1051
1052 for ( count = 0; count < 2 ; count++)
1053 if (line++ < ctx->text.lt.lines) { /* make sure not to run of the end. */
1054 (++lt)->y = (count == 0) ? y : ctx->core.height;
1055 lt->textWidth = 0;
1056 lt->position = ctx->text.lastPos + 100;
1057 }
1058
1059 if (line < ctx->text.lt.lines) /* Clear out rest of table. */
1060 (void) bzero( (char *) (lt + 1),
1061 (ctx->text.lt.lines - line) * sizeof(XawTextLineTableEntry) );
1062
1063 ctx->text.lt.info[ctx->text.lt.lines].position = lt->position;
1064
1065 return(endPos);
1066 }
1067
1068 /* Function Name: GetWidestLine
1069 * Description: Returns the width (in pixels) of the widest line that
1070 * is currently visable.
1071 * Arguments: ctx - the text widget.
1072 * Returns: the width of the widest line.
1073 *
1074 * NOTE: This function requires a valid line table.
1075 */
1076
1077 static Dimension
GetWidestLine(ctx)1078 GetWidestLine(ctx)
1079 TextWidget ctx;
1080 {
1081 int i;
1082 Dimension widest;
1083 XawTextLineTablePtr lt = &(ctx->text.lt);
1084
1085 for (i = 0, widest = 1 ; i < lt->lines ; i++)
1086 if (widest < lt->info[i].textWidth)
1087 widest = lt->info[i].textWidth;
1088
1089 return(widest);
1090 }
1091
1092 static void
CheckVBarScrolling(ctx)1093 CheckVBarScrolling(ctx)
1094 TextWidget ctx;
1095 {
1096 float first, last;
1097 Boolean temp = (ctx->text.vbar == NULL);
1098
1099 if (ctx->text.scroll_vert == XawtextScrollNever) return;
1100
1101 if ( (ctx->text.lastPos > 0) && (ctx->text.lt.lines > 0)) {
1102 first = ctx->text.lt.top;
1103 first /= (float) ctx->text.lastPos;
1104 last = ctx->text.lt.info[ctx->text.lt.lines].position;
1105 if ( ctx->text.lt.info[ctx->text.lt.lines].position < ctx->text.lastPos )
1106 last /= (float) ctx->text.lastPos;
1107 else
1108 last = 1.0;
1109
1110 if (ctx->text.scroll_vert == XawtextScrollWhenNeeded) {
1111 int line;
1112 XawTextPosition last_pos;
1113 Position y = ctx->core.height - ctx->text.margin.bottom;
1114
1115 if (ctx->text.hbar != NULL)
1116 y -= (ctx->text.hbar->core.height +
1117 2 * ctx->text.hbar->core.border_width);
1118
1119 last_pos = PositionForXY(ctx, (Position) ctx->core.width, y);
1120 line = LineForPosition(ctx, last_pos);
1121
1122 if ( (y < ctx->text.lt.info[line + 1].y) || ((last - first) < 1.0) )
1123 CreateVScrollBar(ctx);
1124 else
1125 DestroyVScrollBar(ctx);
1126 }
1127
1128 if (ctx->text.vbar != NULL)
1129 XawScrollbarSetThumb(ctx->text.vbar, first, last - first);
1130
1131 if ( (ctx->text.vbar == NULL) != temp) {
1132 _XawTextNeedsUpdating(ctx, zeroPosition, ctx->text.lastPos);
1133 if (ctx->text.vbar == NULL)
1134 _XawTextBuildLineTable (ctx, zeroPosition, FALSE);
1135 }
1136 }
1137 else if (ctx->text.vbar != NULL) {
1138 if (ctx->text.scroll_vert == XawtextScrollWhenNeeded)
1139 DestroyVScrollBar(ctx);
1140 else if (ctx->text.scroll_vert == XawtextScrollAlways)
1141 XawScrollbarSetThumb(ctx->text.vbar, 0.0, 1.0);
1142 }
1143 }
1144
1145 /*
1146 * This routine is used by Text to notify an associated scrollbar of the
1147 * correct metrics (position and shown fraction) for the text being currently
1148 * displayed in the window.
1149 */
1150
1151 void
_XawTextSetScrollBars(ctx)1152 _XawTextSetScrollBars(ctx)
1153 TextWidget ctx;
1154 {
1155 float first, last, widest;
1156 Boolean temp = (ctx->text.hbar == NULL);
1157 Boolean vtemp = (ctx->text.vbar == NULL);
1158
1159 CheckVBarScrolling(ctx);
1160
1161 if (ctx->text.scroll_horiz == XawtextScrollNever) return;
1162
1163 if (ctx->text.vbar != NULL)
1164 widest = (int)(ctx->core.width - ctx->text.vbar->core.width -
1165 ctx->text.vbar->core.border_width);
1166 else
1167 widest = ctx->core.width;
1168 widest /= (last = GetWidestLine(ctx));
1169 if (ctx->text.scroll_horiz == XawtextScrollWhenNeeded) {
1170 if (widest < 1.0)
1171 CreateHScrollBar(ctx);
1172 else
1173 DestroyHScrollBar(ctx);
1174 }
1175
1176 if ( (ctx->text.hbar == NULL) != temp ) {
1177 _XawTextBuildLineTable (ctx, ctx->text.lt.top, TRUE);
1178 CheckVBarScrolling(ctx); /* Recheck need for vbar, now that we added
1179 or removed the hbar.*/
1180 }
1181
1182 if (ctx->text.hbar != NULL) {
1183 first = ctx->text.r_margin.left - ctx->text.margin.left;
1184 first /= last;
1185 XawScrollbarSetThumb(ctx->text.hbar, first, widest);
1186 }
1187
1188 if (((ctx->text.hbar == NULL) && (ctx->text.margin.left !=
1189 ctx->text.r_margin.left)) ||
1190 (ctx->text.vbar == NULL) != vtemp)
1191 {
1192 ctx->text.margin.left = ctx->text.r_margin.left;
1193 _XawTextNeedsUpdating(ctx, zeroPosition, ctx->text.lastPos);
1194 FlushUpdate(ctx);
1195 }
1196 }
1197
1198 /*
1199 * The routine will scroll the displayed text by lines. If the arg is
1200 * positive, move up; otherwise, move down. [note: this is really a private
1201 * procedure but is used in multiple modules].
1202 */
1203
1204 void
_XawTextVScroll(ctx,n)1205 _XawTextVScroll(ctx, n)
1206 TextWidget ctx;
1207 int n;
1208 {
1209 ThreeDWidget tdw = (ThreeDWidget)ctx->text.threeD;
1210 XawTextPosition top, target;
1211 int y;
1212 Arg list[1];
1213 XawTextLineTable * lt = &(ctx->text.lt);
1214
1215 if (abs(n) > ctx->text.lt.lines)
1216 n = (n > 0) ? ctx->text.lt.lines : -ctx->text.lt.lines;
1217
1218 if (n == 0) return;
1219
1220 if (n > 0) {
1221 if ( IsValidLine(ctx, n) )
1222 top = Min(lt->info[n].position, ctx->text.lastPos);
1223 else
1224 top = ctx->text.lastPos;
1225
1226 y = IsValidLine(ctx, n) ? lt->info[n].y : ctx->core.height;
1227 _XawTextBuildLineTable(ctx, top, FALSE);
1228 if (top >= ctx->text.lastPos)
1229 DisplayTextWindow( (Widget) ctx);
1230 else {
1231 XCopyArea(XtDisplay(ctx), XtWindow(ctx), XtWindow(ctx), ctx->text.gc,
1232 0, y, (int)ctx->core.width, (int)ctx->core.height - y,
1233 0, ctx->text.margin.top);
1234
1235 PushCopyQueue(ctx, 0, (int) -y);
1236 SinkClearToBG(ctx->text.sink,
1237 (Position) 0,
1238 (Position) (ctx->text.margin.top + ctx->core.height - y),
1239 (Dimension) ctx->core.width, (Dimension) ctx->core.height);
1240
1241 if (n < lt->lines) n++; /* update descenders at bottom */
1242 _XawTextNeedsUpdating(ctx, lt->info[lt->lines - n].position,
1243 ctx->text.lastPos);
1244 _XawTextSetScrollBars(ctx);
1245 }
1246 }
1247 else {
1248 XawTextPosition updateTo;
1249 unsigned int height, clear_height;
1250
1251 n = -n;
1252 target = lt->top;
1253 top = SrcScan(ctx->text.source, target, XawstEOL,
1254 XawsdLeft, n+1, FALSE);
1255
1256 _XawTextBuildLineTable(ctx, top, FALSE);
1257 y = IsValidLine(ctx, n) ? lt->info[n].y : ctx->core.height;
1258 updateTo = IsValidLine(ctx, n) ? lt->info[n].position : ctx->text.lastPos;
1259 if (IsValidLine(ctx, lt->lines - n))
1260 height = lt->info[lt->lines-n].y - ctx->text.margin.top;
1261 else if (ctx->core.height - HMargins(ctx))
1262 height = ctx->core.height - HMargins(ctx);
1263 else
1264 height = 0;
1265 if (y > (int) ctx->text.margin.top)
1266 clear_height = y - ctx->text.margin.top;
1267 else
1268 clear_height = 0;
1269
1270 if ( updateTo == target ) {
1271 XCopyArea(XtDisplay(ctx), XtWindow(ctx), XtWindow(ctx), ctx->text.gc,
1272 0, ctx->text.margin.top, (int) ctx->core.width, height, 0, y);
1273 PushCopyQueue(ctx, 0, (int) y);
1274 SinkClearToBG(ctx->text.sink, (Position) 0, ctx->text.margin.top,
1275 (Dimension) ctx->core.width, (Dimension) clear_height);
1276
1277 _XawTextNeedsUpdating(ctx, lt->info[0].position, updateTo);
1278 _XawTextSetScrollBars(ctx);
1279 }
1280 else if (lt->top != target)
1281 DisplayTextWindow((Widget)ctx);
1282 }
1283 XtSetArg (list[0], XtNinsertPosition, ctx->text.lt.top+ctx->text.lt.lines);
1284 _XawImSetValues ((Widget) ctx, list, 1);
1285 neXtawDrawShadowBox((Widget)ctx, tdw, 0, 0, ctx->core.width, ctx->core.height, False);
1286 }
1287
1288 /*ARGSUSED*/
1289 static void
HScroll(w,closure,callData)1290 HScroll(w, closure, callData)
1291 Widget w;
1292 XtPointer closure; /* TextWidget */
1293 XtPointer callData; /* #pixels */
1294 {
1295 TextWidget ctx = (TextWidget) closure;
1296 Widget tw = (Widget) ctx;
1297 ThreeDWidget tdw = (ThreeDWidget)ctx->text.threeD;
1298 Position old_left, pixels = (Position)(long) callData;
1299 XRectangle rect, t_rect;
1300
1301 _XawTextPrepareToUpdate(ctx);
1302
1303 old_left = ctx->text.margin.left;
1304 ctx->text.margin.left -= pixels;
1305 if (ctx->text.margin.left > ctx->text.r_margin.left) {
1306 ctx->text.margin.left = ctx->text.r_margin.left;
1307 pixels = old_left - ctx->text.margin.left;
1308 }
1309
1310 if (pixels > 0) {
1311 rect.width = (unsigned short) pixels + ctx->text.margin.right;
1312 rect.x = (short) ctx->core.width - (short) rect.width;
1313 rect.y = (short) ctx->text.margin.top;
1314 rect.height = (unsigned short) ctx->core.height - rect.y;
1315
1316 XCopyArea(XtDisplay(tw), XtWindow(tw), XtWindow(tw), ctx->text.gc,
1317 pixels, (int) rect.y,
1318 (unsigned int) rect.x, (unsigned int) ctx->core.height,
1319 0, (int) rect.y);
1320
1321 PushCopyQueue(ctx, (int) -pixels, 0);
1322 }
1323 else if (pixels < 0) {
1324 rect.x = 0;
1325
1326 if (ctx->text.vbar != NULL)
1327 rect.x += (short) (ctx->text.vbar->core.width +
1328 ctx->text.vbar->core.border_width);
1329
1330 rect.width = (Position) - pixels;
1331 rect.y = ctx->text.margin.top;
1332 rect.height = ctx->core.height - rect.y;
1333
1334 XCopyArea(XtDisplay(tw), XtWindow(tw), XtWindow(tw), ctx->text.gc,
1335 (int) rect.x, (int) rect.y,
1336 (unsigned int) ctx->core.width - rect.width,
1337 (unsigned int) rect.height,
1338 (int) rect.x + rect.width, (int) rect.y);
1339
1340 PushCopyQueue(ctx, (int) rect.width, 0);
1341
1342 /*
1343 * Redraw the line overflow marks.
1344 */
1345
1346 t_rect.x = ctx->core.width - ctx->text.margin.right;
1347 t_rect.width = ctx->text.margin.right;
1348 t_rect.y = rect.y;
1349 t_rect.height = rect.height;
1350
1351 SinkClearToBG(ctx->text.sink, (Position) t_rect.x, (Position) t_rect.y,
1352 (Dimension) t_rect.width, (Dimension) t_rect.height);
1353
1354 UpdateTextInRectangle(ctx, &t_rect);
1355 }
1356
1357 /*
1358 * Put in the text that just became visible.
1359 */
1360
1361 if ( pixels != 0 ) {
1362 SinkClearToBG(ctx->text.sink, (Position) rect.x, (Position) rect.y,
1363 (Dimension) rect.width, (Dimension) rect.height);
1364
1365 UpdateTextInRectangle(ctx, &rect);
1366 }
1367 _XawTextExecuteUpdate(ctx);
1368 _XawTextSetScrollBars(ctx);
1369
1370 neXtawDrawShadowBox(w, tdw, 0, 0, ctx->core.width, ctx->core.height, False);
1371 }
1372
1373 /*ARGSUSED*/
1374 static void
HJump(w,closure,callData)1375 HJump(w, closure, callData)
1376 Widget w;
1377 XtPointer closure, callData; /* closure = TextWidget, callData = percent. */
1378 {
1379 TextWidget ctx = (TextWidget) closure;
1380 float * percent = (float *) callData;
1381 Position new_left, old_left = ctx->text.margin.left;
1382
1383 long move; /*difference of Positions can be bigger than Position; lint err */
1384
1385 new_left = ctx->text.r_margin.left;
1386 new_left -= (Position) (*percent * GetWidestLine(ctx));
1387 move = old_left - new_left;
1388
1389 if (abs(move) < (int)ctx->core.width) {
1390 HScroll(w, (XtPointer) ctx, (XtPointer) move);
1391 return;
1392 }
1393 _XawTextPrepareToUpdate(ctx);
1394 ctx->text.margin.left = new_left;
1395 if (XtIsRealized((Widget) ctx)) DisplayTextWindow((Widget) ctx);
1396 _XawTextExecuteUpdate(ctx);
1397 }
1398
1399 /* Function Name: UpdateTextInLine
1400 * Description: Updates some text in a given line.
1401 * Arguments: ctx - the text widget.
1402 * line - the line number (in the line table) of this line.
1403 * left, right - left and right pixel offsets of the
1404 * area to update.
1405 * Returns: none.
1406 */
1407
1408 static void
UpdateTextInLine(ctx,line,left,right)1409 UpdateTextInLine(ctx, line, left, right)
1410 TextWidget ctx;
1411 int line;
1412 Position left, right;
1413 {
1414 XawTextPosition pos1, pos2;
1415 int width, height, local_left, local_width;
1416 XawTextLineTableEntry * lt = ctx->text.lt.info + line;
1417
1418 if ( ((int)(lt->textWidth + ctx->text.margin.left) < left) ||
1419 ( ctx->text.margin.left > right ) )
1420 return; /* no need to update. */
1421
1422 local_width = left - ctx->text.margin.left;
1423 XawTextSinkFindPosition(ctx->text.sink, lt->position,
1424 (int) ctx->text.margin.left,
1425 local_width, FALSE, &pos1, &width, &height);
1426
1427 if (right >= (Position) lt->textWidth - ctx->text.margin.left)
1428 if ( (IsValidLine(ctx, line + 1)) &&
1429 (ctx->text.lt.info[line + 1].position <= ctx->text.lastPos) )
1430 pos2 = SrcScan( ctx->text.source, (lt + 1)->position, XawstPositions,
1431 XawsdLeft, 1, TRUE);
1432 else
1433 pos2 = GETLASTPOS;
1434 else {
1435 XawTextPosition t_pos;
1436
1437 local_left = ctx->text.margin.left + width;
1438 local_width = right - local_left;
1439 XawTextSinkFindPosition(ctx->text.sink, pos1, local_left,
1440 local_width, FALSE, &pos2, &width, &height);
1441
1442 t_pos = SrcScan( ctx->text.source, pos2,
1443 XawstPositions, XawsdRight, 1, TRUE);
1444 if (t_pos < (lt + 1)->position)
1445 pos2 = t_pos;
1446 }
1447
1448 _XawTextNeedsUpdating(ctx, pos1, pos2);
1449 }
1450
1451 /*
1452 * The routine will scroll the displayed text by pixels. If the calldata is
1453 * positive, move up; otherwise, move down.
1454 */
1455
1456 /*ARGSUSED*/
1457 static void
VScroll(w,closure,callData)1458 VScroll(w, closure, callData)
1459 Widget w;
1460 XtPointer closure; /* TextWidget */
1461 XtPointer callData; /* #pixels */
1462 {
1463 TextWidget ctx = (TextWidget)closure;
1464 int height, lines = (long) callData;
1465
1466 height = ctx->core.height - VMargins(ctx);
1467 if (height < 1)
1468 height = 1;
1469 lines = (int) (lines * (int) ctx->text.lt.lines) / height;
1470 _XawTextPrepareToUpdate(ctx);
1471 _XawTextVScroll(ctx, lines);
1472 _XawTextExecuteUpdate(ctx);
1473 }
1474
1475 /*
1476 * The routine "thumbs" the displayed text. Thumbing means reposition the
1477 * displayed view of the source to a new position determined by a fraction
1478 * of the way from beginning to end. Ideally, this should be determined by
1479 * the number of displayable lines in the source. This routine does it as a
1480 * fraction of the first position and last position and then normalizes to
1481 * the start of the line containing the position.
1482 *
1483 * BUG/deficiency: The normalize to line portion of this routine will
1484 * cause thumbing to always position to the start of the source.
1485 */
1486
1487 /*ARGSUSED*/
1488 static void
VJump(w,closure,callData)1489 VJump(w, closure, callData)
1490 Widget w;
1491 XtPointer closure, callData; /* closuer = TextWidget, callData = percent. */
1492 {
1493 float * percent = (float *) callData;
1494 TextWidget ctx = (TextWidget)closure;
1495 XawTextPosition position, old_top, old_bot;
1496 XawTextLineTable * lt = &(ctx->text.lt);
1497
1498 _XawTextPrepareToUpdate(ctx);
1499 old_top = lt->top;
1500 if ( (lt->lines > 0) && (IsValidLine(ctx, lt->lines - 1)) )
1501 old_bot = lt->info[lt->lines - 1].position;
1502 else
1503 old_bot = ctx->text.lastPos;
1504
1505 position = (long) (*percent * (float) ctx->text.lastPos);
1506 position= SrcScan(ctx->text.source, position, XawstEOL, XawsdLeft, 1, FALSE);
1507 if ( (position >= old_top) && (position <= old_bot) ) {
1508 int line = 0;
1509 for (;(line < lt->lines) && (position > lt->info[line].position) ; line++);
1510 _XawTextVScroll(ctx, line);
1511 }
1512 else {
1513 XawTextPosition new_bot;
1514 _XawTextBuildLineTable(ctx, position, FALSE);
1515 new_bot = IsValidLine(ctx, lt->lines-1) ? lt->info[lt->lines-1].position
1516 : ctx->text.lastPos;
1517
1518 if ((old_top >= lt->top) && (old_top <= new_bot)) {
1519 int line = 0;
1520 for (;(line < lt->lines) && (old_top > lt->info[line].position); line++);
1521 _XawTextBuildLineTable(ctx, old_top, FALSE);
1522 _XawTextVScroll(ctx, -line);
1523 }
1524 else
1525 DisplayTextWindow( (Widget) ctx);
1526 }
1527 _XawTextExecuteUpdate(ctx);
1528 }
1529
1530 static Boolean
MatchSelection(selection,s)1531 MatchSelection(selection, s)
1532 Atom selection;
1533 XawTextSelection *s;
1534 {
1535 Atom *match;
1536 int count;
1537
1538 for (count = 0, match = s->selections; count < s->atom_count; match++, count++)
1539 if (*match == selection)
1540 return True;
1541 return False;
1542 }
1543
1544 static Boolean
ConvertSelection(w,selection,target,type,value,length,format)1545 ConvertSelection(w, selection, target, type, value, length, format)
1546 Widget w;
1547 Atom *selection, *target, *type;
1548 XtPointer *value;
1549 unsigned long *length;
1550 int *format;
1551 {
1552 Display* d = XtDisplay(w);
1553 TextWidget ctx = (TextWidget)w;
1554 Widget src = ctx->text.source;
1555 XawTextEditType edit_mode;
1556 Arg args[1];
1557
1558 XawTextSelectionSalt *salt = NULL;
1559 XawTextSelection *s;
1560
1561 if (*target == XA_TARGETS(d)) {
1562 Atom* targetP, * std_targets;
1563 unsigned long std_length;
1564
1565 if ( SrcCvtSel(src, selection, target, type, value, length, format) )
1566 return True;
1567
1568 XmuConvertStandardSelection(w, ctx->text.time, selection,
1569 target, type, (XPointer*)&std_targets,
1570 &std_length, format);
1571
1572 *value = XtMalloc((unsigned) sizeof(Atom)*(std_length + 7));
1573 targetP = *(Atom**)value;
1574 *length = std_length + 6;
1575 *targetP++ = XA_STRING;
1576 *targetP++ = XA_TEXT(d);
1577 *targetP++ = XA_COMPOUND_TEXT(d);
1578 *targetP++ = XA_LENGTH(d);
1579 *targetP++ = XA_LIST_LENGTH(d);
1580 *targetP++ = XA_CHARACTER_POSITION(d);
1581
1582 XtSetArg(args[0], XtNeditType,&edit_mode);
1583 XtGetValues(src, args, ONE);
1584
1585 if (edit_mode == XawtextEdit) {
1586 *targetP++ = XA_DELETE(d);
1587 (*length)++;
1588 }
1589 (void) memmove((char*)targetP, (char*)std_targets, sizeof(Atom)*std_length);
1590 XtFree((char*)std_targets);
1591 *type = XA_ATOM;
1592 *format = 32;
1593 return True;
1594 }
1595
1596 if ( SrcCvtSel(src, selection, target, type, value, length, format) )
1597 return True;
1598
1599 if (MatchSelection (*selection, &ctx->text.s))
1600 s = &ctx->text.s;
1601 else
1602 {
1603 for (salt = ctx->text.salt; salt; salt = salt->next)
1604 if (MatchSelection (*selection, &salt->s))
1605 break;
1606 if (!salt)
1607 return False;
1608 s = &salt->s;
1609 }
1610 if (*target == XA_STRING ||
1611 *target == XA_TEXT(d) ||
1612 *target == XA_COMPOUND_TEXT(d)) {
1613 if (*target == XA_TEXT(d)) {
1614 if (_XawTextFormat(ctx) == XawFmtWide)
1615 *type = XA_COMPOUND_TEXT(d);
1616 else
1617 *type = XA_STRING;
1618 } else {
1619 *type = *target;
1620 }
1621 /*
1622 * If salt is True, the salt->contents stores CT string,
1623 * its length is measured in bytes.
1624 * Refer to _XawTextSaltAwaySelection().
1625 *
1626 * by Li Yuhong, Mar. 20, 1991.
1627 */
1628 if (!salt) {
1629 *value = _XawTextGetSTRING(ctx, s->left, s->right);
1630 if (_XawTextFormat(ctx) == XawFmtWide) {
1631 XTextProperty textprop;
1632 if (XwcTextListToTextProperty(d, (wchar_t **)value, 1,
1633 XCompoundTextStyle, &textprop)
1634 < Success) {
1635 XtFree(*value);
1636 return False;
1637 }
1638 XtFree(*value);
1639 *value = (XtPointer)textprop.value;
1640 *length = textprop.nitems;
1641 } else {
1642 *length = strlen(*value);
1643 }
1644 } else {
1645 *value = XtMalloc((salt->length + 1) * sizeof(unsigned char));
1646 strcpy (*value, salt->contents);
1647 *length = salt->length;
1648 }
1649 if (_XawTextFormat(ctx) == XawFmtWide && *type == XA_STRING) {
1650 XTextProperty textprop;
1651 wchar_t **wlist;
1652 int count;
1653 textprop.encoding = XA_COMPOUND_TEXT(d);
1654 textprop.value = (unsigned char *)*value;
1655 textprop.nitems = strlen(*value);
1656 textprop.format = 8;
1657 if (XwcTextPropertyToTextList(d, &textprop, (wchar_t ***)&wlist, &count)
1658 < Success) {
1659 XtFree(*value);
1660 return False;
1661 }
1662 XtFree(*value);
1663 if (XwcTextListToTextProperty( d, (wchar_t **)wlist, 1,
1664 XStringStyle, &textprop) < Success) {
1665 XwcFreeStringList( (wchar_t**) wlist );
1666 return False;
1667 }
1668 *value = (XtPointer) textprop.value;
1669 *length = textprop.nitems;
1670 XwcFreeStringList( (wchar_t**) wlist );
1671 }
1672 *format = 8;
1673 return True;
1674 }
1675
1676 if ( (*target == XA_LIST_LENGTH(d)) || (*target == XA_LENGTH(d)) ) {
1677 long * temp;
1678
1679 temp = (long *) XtMalloc( (unsigned) sizeof(long) );
1680 if (*target == XA_LIST_LENGTH(d))
1681 *temp = 1L;
1682 else /* *target == XA_LENGTH(d) */
1683 *temp = (long) (s->right - s->left);
1684
1685 *value = (XPointer) temp;
1686 *type = XA_INTEGER;
1687 *length = 1L;
1688 *format = 32;
1689 return True;
1690 }
1691
1692 if (*target == XA_CHARACTER_POSITION(d)) {
1693 long * temp;
1694
1695 temp = (long *) XtMalloc( (unsigned)( 2 * sizeof(long) ) );
1696 temp[0] = (long) (s->left + 1);
1697 temp[1] = s->right;
1698 *value = (XPointer) temp;
1699 *type = XA_SPAN(d);
1700 *length = 2L;
1701 *format = 32;
1702 return True;
1703 }
1704
1705 if (*target == XA_DELETE(d)) {
1706 void _XawTextZapSelection(); /* From TextAction.c */
1707
1708 if (!salt)
1709 _XawTextZapSelection( ctx, (XEvent *) NULL, TRUE);
1710 *value = NULL;
1711 *type = XA_NULL(d);
1712 *length = 0;
1713 *format = 32;
1714 return True;
1715 }
1716
1717 if (XmuConvertStandardSelection(w, ctx->text.time, selection, target, type,
1718 (XPointer *)value, length, format))
1719 return True;
1720
1721 /* else */
1722 return False;
1723 }
1724
1725 /* Function Name: GetCutBuffferNumber
1726 * Description: Returns the number of the cut buffer.
1727 * Arguments: atom - the atom to check.
1728 * Returns: the number of the cut buffer representing this atom or
1729 * NOT_A_CUT_BUFFER.
1730 */
1731
1732 #define NOT_A_CUT_BUFFER -1
1733
1734 static int
GetCutBufferNumber(atom)1735 GetCutBufferNumber(atom)
1736 Atom atom;
1737 {
1738 if (atom == XA_CUT_BUFFER0) return(0);
1739 if (atom == XA_CUT_BUFFER1) return(1);
1740 if (atom == XA_CUT_BUFFER2) return(2);
1741 if (atom == XA_CUT_BUFFER3) return(3);
1742 if (atom == XA_CUT_BUFFER4) return(4);
1743 if (atom == XA_CUT_BUFFER5) return(5);
1744 if (atom == XA_CUT_BUFFER6) return(6);
1745 if (atom == XA_CUT_BUFFER7) return(7);
1746 return(NOT_A_CUT_BUFFER);
1747 }
1748
1749 static void
LoseSelection(w,selection)1750 LoseSelection(w, selection)
1751 Widget w;
1752 Atom *selection;
1753 {
1754 TextWidget ctx = (TextWidget) w;
1755 Atom* atomP;
1756 int i;
1757 XawTextSelectionSalt *salt, *prevSalt, *nextSalt;
1758
1759 _XawTextPrepareToUpdate(ctx);
1760
1761 atomP = ctx->text.s.selections;
1762 for (i = 0 ; i < ctx->text.s.atom_count; i++, atomP++)
1763 if ( (*selection == *atomP) ||
1764 (GetCutBufferNumber(*atomP) != NOT_A_CUT_BUFFER) )/* is a cut buffer */
1765 *atomP = (Atom)0;
1766
1767 while (ctx->text.s.atom_count &&
1768 ctx->text.s.selections[ctx->text.s.atom_count-1] == 0)
1769 ctx->text.s.atom_count--;
1770
1771 /*
1772 * Must walk the selection list in opposite order from UnsetSelection.
1773 */
1774
1775 atomP = ctx->text.s.selections;
1776 for (i = 0 ; i < ctx->text.s.atom_count; i++, atomP++)
1777 if (*atomP == (Atom)0) {
1778 *atomP = ctx->text.s.selections[--ctx->text.s.atom_count];
1779 while (ctx->text.s.atom_count &&
1780 ctx->text.s.selections[ctx->text.s.atom_count-1] == 0)
1781 ctx->text.s.atom_count--;
1782 }
1783
1784 if (ctx->text.s.atom_count == 0)
1785 ModifySelection(ctx, ctx->text.insertPos, ctx->text.insertPos);
1786
1787 if (ctx->text.old_insert >= 0) /* Update in progress. */
1788 _XawTextExecuteUpdate(ctx);
1789
1790 prevSalt = 0;
1791 for (salt = ctx->text.salt; salt; salt = nextSalt)
1792 {
1793 atomP = salt->s.selections;
1794 nextSalt = salt->next;
1795 for (i = 0 ; i < salt->s.atom_count; i++, atomP++)
1796 if (*selection == *atomP)
1797 *atomP = (Atom)0;
1798
1799 while (salt->s.atom_count &&
1800 salt->s.selections[salt->s.atom_count-1] == 0)
1801 {
1802 salt->s.atom_count--;
1803 }
1804
1805 /*
1806 * Must walk the selection list in opposite order from UnsetSelection.
1807 */
1808
1809 atomP = salt->s.selections;
1810 for (i = 0 ; i < salt->s.atom_count; i++, atomP++)
1811 if (*atomP == (Atom)0)
1812 {
1813 *atomP = salt->s.selections[--salt->s.atom_count];
1814 while (salt->s.atom_count &&
1815 salt->s.selections[salt->s.atom_count-1] == 0)
1816 salt->s.atom_count--;
1817 }
1818 if (salt->s.atom_count == 0)
1819 {
1820 XtFree ((char *) salt->s.selections);
1821 XtFree (salt->contents);
1822 if (prevSalt)
1823 prevSalt->next = nextSalt;
1824 else
1825 ctx->text.salt = nextSalt;
1826 XtFree ((char *) salt);
1827 }
1828 else
1829 prevSalt = salt;
1830 }
1831 }
1832
1833 void
_XawTextSaltAwaySelection(ctx,selections,num_atoms)1834 _XawTextSaltAwaySelection (ctx, selections, num_atoms)
1835 TextWidget ctx;
1836 Atom* selections;
1837 int num_atoms;
1838 {
1839 XawTextSelectionSalt *salt;
1840 int i, j;
1841
1842 for (i = 0; i < num_atoms; i++)
1843 LoseSelection ((Widget) ctx, selections + i);
1844 if (num_atoms == 0)
1845 return;
1846 salt = (XawTextSelectionSalt *)
1847 XtMalloc( (unsigned) sizeof(XawTextSelectionSalt) );
1848 if (!salt)
1849 return;
1850 salt->s.selections = (Atom *)
1851 XtMalloc( (unsigned) ( num_atoms * sizeof (Atom) ) );
1852 if (!salt->s.selections)
1853 {
1854 XtFree ((char *) salt);
1855 return;
1856 }
1857 salt->s.left = ctx->text.s.left;
1858 salt->s.right = ctx->text.s.right;
1859 salt->s.type = ctx->text.s.type;
1860 salt->contents = _XawTextGetSTRING(ctx, ctx->text.s.left, ctx->text.s.right);
1861 if (_XawTextFormat(ctx) == XawFmtWide) {
1862 XTextProperty textprop;
1863 if (XwcTextListToTextProperty(XtDisplay((Widget)ctx),
1864 (wchar_t**)(&(salt->contents)), 1, XCompoundTextStyle,
1865 &textprop) < Success) {
1866 XtFree(salt->contents);
1867 salt->length = 0;
1868 return;
1869 }
1870 XtFree(salt->contents);
1871 salt->contents = (char *)textprop.value;
1872 salt->length = textprop.nitems;
1873 } else
1874 salt->length = strlen (salt->contents);
1875 salt->next = ctx->text.salt;
1876 ctx->text.salt = salt;
1877 j = 0;
1878 for (i = 0; i < num_atoms; i++)
1879 {
1880 if (GetCutBufferNumber (selections[i]) == NOT_A_CUT_BUFFER)
1881 {
1882 salt->s.selections[j++] = selections[i];
1883 XtOwnSelection ((Widget) ctx, selections[i], ctx->text.time,
1884 ConvertSelection, LoseSelection, (XtSelectionDoneProc)NULL);
1885 }
1886 }
1887 salt->s.atom_count = j;
1888 }
1889
1890 static void
_SetSelection(ctx,left,right,selections,count)1891 _SetSelection(ctx, left, right, selections, count)
1892 TextWidget ctx;
1893 XawTextPosition left, right;
1894 Atom *selections;
1895 Cardinal count;
1896 {
1897 XawTextPosition pos;
1898
1899 if (left < ctx->text.s.left) {
1900 pos = Min(right, ctx->text.s.left);
1901 _XawTextNeedsUpdating(ctx, left, pos);
1902 }
1903 if (left > ctx->text.s.left) {
1904 pos = Min(left, ctx->text.s.right);
1905 _XawTextNeedsUpdating(ctx, ctx->text.s.left, pos);
1906 }
1907 if (right < ctx->text.s.right) {
1908 pos = Max(right, ctx->text.s.left);
1909 _XawTextNeedsUpdating(ctx, pos, ctx->text.s.right);
1910 }
1911 if (right > ctx->text.s.right) {
1912 pos = Max(left, ctx->text.s.right);
1913 _XawTextNeedsUpdating(ctx, pos, right);
1914 }
1915
1916 ctx->text.s.left = left;
1917 ctx->text.s.right = right;
1918
1919 SrcSetSelection(ctx->text.source, left, right,
1920 (count == 0) ? None : selections[0]);
1921
1922 if (left < right) {
1923 Widget w = (Widget) ctx;
1924 int buffer;
1925
1926 while (count) {
1927 Atom selection = selections[--count];
1928
1929 /*
1930 * If this is a cut buffer.
1931 */
1932
1933 if ((buffer = GetCutBufferNumber(selection)) != NOT_A_CUT_BUFFER) {
1934 unsigned char *ptr, *tptr;
1935 unsigned int amount, max_len = MAX_CUT_LEN(XtDisplay(w));
1936 unsigned long len;
1937
1938 tptr= ptr= (unsigned char *) _XawTextGetSTRING(ctx, ctx->text.s.left,
1939 ctx->text.s.right);
1940 if (_XawTextFormat(ctx) == XawFmtWide) {
1941 /*
1942 * Only XA_STRING(Latin 1) is allowed in CUT_BUFFER,
1943 * so we get it from wchar string, then free the wchar string.
1944 */
1945 XTextProperty textprop;
1946 if (XwcTextListToTextProperty(XtDisplay(w), (wchar_t**)&ptr, 1,
1947 XStringStyle, &textprop) < Success) {
1948 XtFree((char *)ptr);
1949 return;
1950 }
1951 XtFree((char *)ptr);
1952 tptr = ptr = textprop.value;
1953 }
1954 if (buffer == 0) {
1955 _CreateCutBuffers(XtDisplay(w));
1956 XRotateBuffers(XtDisplay(w), 1);
1957 }
1958 amount = Min ( (len = strlen((char *)ptr)), max_len);
1959 XChangeProperty(XtDisplay(w), RootWindow(XtDisplay(w), 0), selection,
1960 XA_STRING, 8, PropModeReplace, ptr, amount);
1961
1962 while (len > max_len) {
1963 len -= max_len;
1964 tptr += max_len;
1965 amount = Min (len, max_len);
1966 XChangeProperty(XtDisplay(w), RootWindow(XtDisplay(w), 0),
1967 selection, XA_STRING, 8, PropModeAppend,
1968 tptr, amount);
1969 }
1970 XtFree ((char *)ptr);
1971 }
1972 else /* This is a real selection */
1973 XtOwnSelection(w, selection, ctx->text.time, ConvertSelection,
1974 LoseSelection, (XtSelectionDoneProc)NULL);
1975 }
1976 }
1977 else
1978 XawTextUnsetSelection((Widget)ctx);
1979 }
1980
1981 /*
1982 * This internal routine deletes the text from pos1 to pos2 in a source and
1983 * then inserts, at pos1, the text that was passed. As a side effect it
1984 * "invalidates" that portion of the displayed text (if any).
1985 *
1986 * NOTE: It is illegal to call this routine unless there is a valid line table!
1987 */
1988
1989 int
_XawTextReplace(ctx,pos1,pos2,text)1990 _XawTextReplace (ctx, pos1, pos2, text)
1991 TextWidget ctx;
1992 XawTextPosition pos1, pos2;
1993 XawTextBlock *text;
1994 {
1995 int i, line1, delta, error;
1996 XawTextPosition updateFrom, updateTo;
1997 Widget src = ctx->text.source;
1998 XawTextEditType edit_mode;
1999 Arg args[1];
2000 Boolean tmp = ctx->text.update_disabled;
2001
2002 ctx->text.update_disabled = True; /* No redisplay during replacement. */
2003
2004 /*
2005 * The insertPos may not always be set to the right spot in XawtextAppend
2006 */
2007
2008 XtSetArg(args[0], XtNeditType, &edit_mode);
2009 XtGetValues(src, args, ONE);
2010
2011 if ((pos1 == ctx->text.insertPos) && (edit_mode == XawtextAppend)) {
2012 ctx->text.insertPos = ctx->text.lastPos;
2013 pos2 = SrcScan(src, ctx->text.insertPos, XawstPositions, XawsdRight,
2014 (int)(ctx->text.insertPos - pos1), (Boolean)TRUE);
2015 pos1 = ctx->text.insertPos;
2016 if ( (pos1 == pos2) && (text->length == 0) ) {
2017 ctx->text.update_disabled = FALSE; /* rearm redisplay. */
2018 return( XawEditError );
2019 }
2020 }
2021
2022 updateFrom = SrcScan(src, pos1, XawstWhiteSpace, XawsdLeft, 1, FALSE);
2023 updateFrom = Max(updateFrom, ctx->text.lt.top);
2024
2025 line1 = LineForPosition(ctx, updateFrom);
2026 if ( (error = SrcReplace(src, pos1, pos2, text)) != 0) {
2027 ctx->text.update_disabled = tmp; /* restore redisplay */
2028 return(error);
2029 }
2030
2031 XawTextUnsetSelection((Widget)ctx);
2032
2033 ctx->text.lastPos = GETLASTPOS;
2034 if (ctx->text.lt.top >= ctx->text.lastPos) {
2035 _XawTextBuildLineTable(ctx, ctx->text.lastPos, FALSE);
2036 ClearWindow( (Widget) ctx);
2037 ctx->text.update_disabled = tmp; /* restore redisplay */
2038 return(0); /* Things are fine. */
2039 }
2040
2041 ctx->text.single_char = (text->length <= 1 && pos2 - pos1 <= 1);
2042
2043 delta = text->length - (pos2 - pos1);
2044
2045 if (delta < ctx->text.lastPos) {
2046 for (pos2 += delta, i = 0; i < ctx->text.numranges; i++) {
2047 if (ctx->text.updateFrom[i] > pos1)
2048 ctx->text.updateFrom[i] += delta;
2049 if (ctx->text.updateTo[i] >= pos1)
2050 ctx->text.updateTo[i] += delta;
2051 }
2052 }
2053
2054 /*
2055 * fixup all current line table entries to reflect edit.
2056 * %%% it is not legal to do arithmetic on positions.
2057 * using Scan would be more proper.
2058 */
2059 if (delta != 0) {
2060 XawTextLineTableEntry *lineP;
2061 i = LineForPosition(ctx, pos1) + 1;
2062 for (lineP = ctx->text.lt.info + i; i <= ctx->text.lt.lines; i++, lineP++)
2063 lineP->position += delta;
2064 }
2065
2066 /*
2067 * Now process the line table and fixup in case edits caused
2068 * changes in line breaks. If we are breaking on word boundaries,
2069 * this code checks for moving words to and from lines.
2070 */
2071
2072 if (IsPositionVisible(ctx, updateFrom)) {
2073 updateTo = _BuildLineTable(ctx,
2074 ctx->text.lt.info[line1].position, pos1, line1);
2075 _XawTextNeedsUpdating(ctx, updateFrom, updateTo);
2076 }
2077
2078 ctx->text.update_disabled = tmp; /* restore redisplay */
2079 return(0); /* Things are fine. */
2080 }
2081
2082 /*
2083 * This routine will display text between two arbitrary source positions.
2084 * In the event that this span contains highlighted text for the selection,
2085 * only that portion will be displayed highlighted.
2086 *
2087 * NOTE: it is illegal to call this routine unless there
2088 * is a valid line table!
2089 */
2090
2091 static void
DisplayText(w,pos1,pos2)2092 DisplayText(w, pos1, pos2)
2093 Widget w;
2094 XawTextPosition pos1, pos2;
2095 {
2096 TextWidget ctx = (TextWidget)w;
2097 ThreeDWidget tdw = (ThreeDWidget)ctx->text.threeD;
2098 Position x, y;
2099 int height, line, i, lastPos = ctx->text.lastPos;
2100 XawTextPosition startPos, endPos;
2101 Boolean clear_eol, done_painting;
2102
2103 pos1 = (pos1 < ctx->text.lt.top) ? ctx->text.lt.top : pos1;
2104 pos2 = FindGoodPosition(ctx, pos2);
2105 if ( (pos1 >= pos2) || !LineAndXYForPosition(ctx, pos1, &line, &x, &y) )
2106 return; /* line not visible, or pos1 >= pos2. */
2107
2108 for ( startPos = pos1, i = line; IsValidLine(ctx, i) &&
2109 (i < ctx->text.lt.lines) ; i++) {
2110
2111
2112 if ( (endPos = ctx->text.lt.info[i + 1].position) > pos2 ) {
2113 clear_eol = ((endPos = pos2) >= lastPos);
2114 done_painting = (!clear_eol || ctx->text.single_char);
2115 }
2116 else {
2117 clear_eol = TRUE;
2118 done_painting = FALSE;
2119 }
2120
2121 height = ctx->text.lt.info[i + 1].y - ctx->text.lt.info[i].y;
2122
2123 if ( (endPos > startPos) ) {
2124 if ( (x == (Position) ctx->text.margin.left) && (x > 0) )
2125 SinkClearToBG (ctx->text.sink,
2126 (Position) 0, y,
2127 (Dimension) ctx->text.margin.left, (Dimension)height);
2128
2129 if ( (startPos >= ctx->text.s.right) || (endPos <= ctx->text.s.left) )
2130 XawTextSinkDisplayText(ctx->text.sink, x, y, startPos, endPos, FALSE);
2131 else if ((startPos >= ctx->text.s.left) && (endPos <= ctx->text.s.right))
2132 XawTextSinkDisplayText(ctx->text.sink, x, y, startPos, endPos, TRUE);
2133 else {
2134 DisplayText(w, startPos, ctx->text.s.left);
2135 DisplayText(w, Max(startPos, ctx->text.s.left),
2136 Min(endPos, ctx->text.s.right));
2137 DisplayText(w, ctx->text.s.right, endPos);
2138 }
2139 }
2140 startPos = endPos;
2141 if (clear_eol) {
2142 SinkClearToBG(ctx->text.sink,
2143 (Position) (ctx->text.lt.info[i].textWidth +
2144 ctx->text.margin.left),
2145 (Position) y, w->core.width, (Dimension) height);
2146
2147 /*
2148 * We only get here if single character is true, and we need
2149 * to clear to the end of the screen. We know that since there
2150 * was only one character deleted that this is the same
2151 * as clearing an extra line, so we do this, and are done.
2152 *
2153 * This a performance hack, and a pretty gross one, but it works.
2154 *
2155 * Chris Peterson 11/13/89.
2156 */
2157
2158 if (done_painting) {
2159 y += height;
2160 SinkClearToBG(ctx->text.sink,
2161 (Position) ctx->text.margin.left, (Position) y,
2162 w->core.width, (Dimension) height);
2163
2164 break; /* set single_char to FALSE and return. */
2165 }
2166 }
2167
2168 x = (Position) ctx->text.margin.left;
2169 y = ctx->text.lt.info[i + 1].y;
2170 if ( done_painting
2171 || (y >= (int)(ctx->core.height - ctx->text.margin.bottom)) )
2172 break;
2173 }
2174 ctx->text.single_char = FALSE;
2175 neXtawDrawShadowBox(w, tdw, 0, 0, ctx->core.width, ctx->core.height, False);
2176 }
2177
2178 /*
2179 * This routine implements multi-click selection in a hardwired manner.
2180 * It supports multi-click entity cycling (char, word, line, file) and mouse
2181 * motion adjustment of the selected entitie (i.e. select a word then, with
2182 * button still down, adjust wich word you really meant by moving the mouse).
2183 * [NOTE: This routine is to be replaced by a set of procedures that
2184 * will allows clients to implements a wide class of draw through and
2185 * multi-click selection user interfaces.]
2186 */
2187
2188 static void
DoSelection(ctx,pos,time,motion)2189 DoSelection (ctx, pos, time, motion)
2190 TextWidget ctx;
2191 XawTextPosition pos;
2192 Time time;
2193 Boolean motion;
2194 {
2195 XawTextPosition newLeft, newRight;
2196 XawTextSelectType newType, *sarray;
2197 Widget src = ctx->text.source;
2198
2199 if (motion)
2200 newType = ctx->text.s.type;
2201 else {
2202 if ( (abs((long) time - (long) ctx->text.lasttime) < MULTI_CLICK_TIME) &&
2203 ((pos >= ctx->text.s.left) && (pos <= ctx->text.s.right))) {
2204 sarray = ctx->text.sarray;
2205 for (;*sarray != XawselectNull && *sarray != ctx->text.s.type; sarray++);
2206
2207 if (*sarray == XawselectNull)
2208 newType = *(ctx->text.sarray);
2209 else {
2210 newType = *(sarray + 1);
2211 if (newType == XawselectNull)
2212 newType = *(ctx->text.sarray);
2213 }
2214 }
2215 else /* single-click event */
2216 newType = *(ctx->text.sarray);
2217
2218 ctx->text.lasttime = time;
2219 }
2220 switch (newType) {
2221 case XawselectPosition:
2222 newLeft = newRight = pos;
2223 break;
2224 case XawselectChar:
2225 newLeft = pos;
2226 newRight = SrcScan(src, pos, XawstPositions, XawsdRight, 1, FALSE);
2227 break;
2228 case XawselectWord:
2229 case XawselectParagraph:
2230 {
2231 XawTextScanType stype;
2232
2233 if (newType == XawselectWord)
2234 stype = XawstWhiteSpace;
2235 else
2236 stype = XawstParagraph;
2237
2238 /*
2239 * Somewhat complicated, but basically I treat the space between
2240 * two objects as another object. The object that I am currently
2241 * in then becomes the end of the selection.
2242 *
2243 * Chris Peterson - 4/19/90.
2244 */
2245
2246 newRight = SrcScan(ctx->text.source, pos, stype, XawsdRight, 1, FALSE);
2247 newRight =SrcScan(ctx->text.source, newRight,stype,XawsdLeft,1, FALSE);
2248
2249 if (pos != newRight)
2250 newLeft = SrcScan(ctx->text.source, pos, stype, XawsdLeft, 1, FALSE);
2251 else
2252 newLeft = pos;
2253
2254 newLeft =SrcScan(ctx->text.source, newLeft, stype, XawsdRight,1,FALSE);
2255
2256 if (newLeft > newRight) {
2257 XawTextPosition temp = newLeft;
2258 newLeft = newRight;
2259 newRight = temp;
2260 }
2261 }
2262 break;
2263 case XawselectLine:
2264 newLeft = SrcScan(src, pos, XawstEOL, XawsdLeft, 1, FALSE);
2265 newRight = SrcScan(src, pos, XawstEOL, XawsdRight, 1, FALSE);
2266 break;
2267 case XawselectAll:
2268 newLeft = SrcScan(src, pos, XawstAll, XawsdLeft, 1, FALSE);
2269 newRight = SrcScan(src, pos, XawstAll, XawsdRight, 1, FALSE);
2270 break;
2271 default:
2272 XtAppWarning(XtWidgetToApplicationContext((Widget) ctx),
2273 "Text Widget: empty selection array.");
2274 return;
2275 }
2276
2277 if ( (newLeft != ctx->text.s.left) || (newRight != ctx->text.s.right)
2278 || (newType != ctx->text.s.type)) {
2279 ModifySelection(ctx, newLeft, newRight);
2280 if (pos - ctx->text.s.left < ctx->text.s.right - pos)
2281 ctx->text.insertPos = newLeft;
2282 else
2283 ctx->text.insertPos = newRight;
2284 ctx->text.s.type = newType;
2285 }
2286 if (!motion) { /* setup so we can freely mix select extend calls*/
2287 ctx->text.origSel.type = ctx->text.s.type;
2288 ctx->text.origSel.left = ctx->text.s.left;
2289 ctx->text.origSel.right = ctx->text.s.right;
2290
2291 if (pos >= ctx->text.s.left + ((ctx->text.s.right - ctx->text.s.left) / 2))
2292 ctx->text.extendDir = XawsdRight;
2293 else
2294 ctx->text.extendDir = XawsdLeft;
2295 }
2296 }
2297
2298 /*
2299 * This routine implements extension of the currently selected text in
2300 * the "current" mode (i.e. char word, line, etc.). It worries about
2301 * extending from either end of the selection and handles the case when you
2302 * cross through the "center" of the current selection (e.g. switch which
2303 * end you are extending!).
2304 */
2305
2306 static void
ExtendSelection(ctx,pos,motion)2307 ExtendSelection (ctx, pos, motion)
2308 TextWidget ctx;
2309 XawTextPosition pos;
2310 Boolean motion;
2311 {
2312 XawTextScanDirection dir;
2313
2314 if (!motion) { /* setup for extending selection */
2315 if (ctx->text.s.left == ctx->text.s.right) /* no current selection. */
2316 ctx->text.s.left = ctx->text.s.right = ctx->text.insertPos;
2317 else {
2318 ctx->text.origSel.left = ctx->text.s.left;
2319 ctx->text.origSel.right = ctx->text.s.right;
2320 }
2321
2322 ctx->text.origSel.type = ctx->text.s.type;
2323
2324 if (pos >= ctx->text.s.left + ((ctx->text.s.right - ctx->text.s.left) / 2))
2325 ctx->text.extendDir = XawsdRight;
2326 else
2327 ctx->text.extendDir = XawsdLeft;
2328 }
2329 else /* check for change in extend direction */
2330 if ((ctx->text.extendDir == XawsdRight && pos <= ctx->text.origSel.left) ||
2331 (ctx->text.extendDir == XawsdLeft && pos >= ctx->text.origSel.right)) {
2332 ctx->text.extendDir = (ctx->text.extendDir == XawsdRight) ?
2333 XawsdLeft : XawsdRight;
2334 ModifySelection(ctx, ctx->text.origSel.left, ctx->text.origSel.right);
2335 }
2336
2337 dir = ctx->text.extendDir;
2338 switch (ctx->text.s.type) {
2339 case XawselectWord:
2340 case XawselectParagraph:
2341 {
2342 XawTextPosition left_pos, right_pos;
2343 XawTextScanType stype;
2344
2345 if (ctx->text.s.type == XawselectWord)
2346 stype = XawstWhiteSpace;
2347 else
2348 stype = XawstParagraph;
2349
2350 /*
2351 * Somewhat complicated, but basically I treat the space between
2352 * two objects as another object. The object that I am currently
2353 * in then becomes the end of the selection.
2354 *
2355 * Chris Peterson - 4/19/90.
2356 */
2357
2358 right_pos = SrcScan(ctx->text.source, pos, stype, XawsdRight, 1, FALSE);
2359 right_pos =SrcScan(ctx->text.source, right_pos,stype,XawsdLeft,1, FALSE);
2360
2361 if (pos != right_pos)
2362 left_pos = SrcScan(ctx->text.source, pos, stype, XawsdLeft, 1, FALSE);
2363 else
2364 left_pos = pos;
2365
2366 left_pos =SrcScan(ctx->text.source, left_pos, stype, XawsdRight,1,FALSE);
2367
2368 if (dir == XawsdLeft)
2369 pos = Min(left_pos, right_pos);
2370 else /* dir == XawsdRight */
2371 pos = Max(left_pos, right_pos);
2372 }
2373 break;
2374 case XawselectLine:
2375 pos = SrcScan(ctx->text.source, pos, XawstEOL, dir, 1, dir == XawsdRight);
2376 break;
2377 case XawselectAll:
2378 pos = ctx->text.insertPos;
2379 case XawselectPosition: /* fall through. */
2380 default:
2381 break;
2382 }
2383
2384 if (dir == XawsdRight)
2385 ModifySelection(ctx, ctx->text.s.left, pos);
2386 else
2387 ModifySelection(ctx, pos, ctx->text.s.right);
2388
2389 ctx->text.insertPos = pos;
2390 }
2391
2392 /*
2393 * Clear the window to background color.
2394 */
2395
2396 static void
ClearWindow(w)2397 ClearWindow (w)
2398 Widget w;
2399 {
2400 TextWidget ctx = (TextWidget) w;
2401 ThreeDWidget tdw = (ThreeDWidget)ctx->text.threeD;
2402
2403 if (XtIsRealized(w)) {
2404 SinkClearToBG(ctx->text.sink,
2405 (Position) 0, (Position) 0,
2406 w->core.width, w->core.height);
2407 neXtawDrawShadowBox(w, tdw, 0, 0, ctx->core.width, ctx->core.height, False);
2408 }
2409 }
2410
2411 /* Function Name: _XawTextClearAndCenterDisplay
2412 * Description: Redraws the display with the cursor in insert point
2413 * centered vertically.
2414 * Arguments: ctx - the text widget.
2415 * Returns: none.
2416 */
2417
2418 void
_XawTextClearAndCenterDisplay(ctx)2419 _XawTextClearAndCenterDisplay(ctx)
2420 TextWidget ctx;
2421 {
2422 int insert_line = LineForPosition(ctx, ctx->text.insertPos);
2423 int scroll_by = insert_line - ctx->text.lt.lines/2;
2424
2425 _XawTextVScroll(ctx, scroll_by);
2426 DisplayTextWindow( (Widget) ctx);
2427 }
2428
2429 /*
2430 * Internal redisplay entire window.
2431 * Legal to call only if widget is realized.
2432 */
2433
2434 static void
DisplayTextWindow(w)2435 DisplayTextWindow (w)
2436 Widget w;
2437 {
2438 TextWidget ctx = (TextWidget) w;
2439 ClearWindow(w);
2440 _XawTextBuildLineTable(ctx, ctx->text.lt.top, FALSE);
2441 _XawTextNeedsUpdating(ctx, zeroPosition, ctx->text.lastPos);
2442 _XawTextSetScrollBars(ctx);
2443 }
2444
2445 /*
2446 * This routine checks to see if the window should be resized (grown or
2447 * shrunk) when text to be painted overflows to the right or
2448 * the bottom of the window. It is used by the keyboard input routine.
2449 */
2450
2451 void
_XawTextCheckResize(ctx)2452 _XawTextCheckResize(ctx)
2453 TextWidget ctx;
2454 {
2455 Widget w = (Widget) ctx;
2456 int line = 0, old_height;
2457 XtWidgetGeometry rbox, return_geom;
2458
2459 if ( (ctx->text.resize == XawtextResizeWidth) ||
2460 (ctx->text.resize == XawtextResizeBoth) ) {
2461 XawTextLineTableEntry *lt;
2462 rbox.width = 0;
2463 for (lt = ctx->text.lt.info;
2464 IsValidLine(ctx, line) && (line < ctx->text.lt.lines);
2465 line++, lt++) {
2466 if ((int)(lt->textWidth + ctx->text.margin.left) > (int)rbox.width)
2467 rbox.width = lt->textWidth + ctx->text.margin.left;
2468 }
2469
2470 rbox.width += ctx->text.margin.right;
2471 if (rbox.width > ctx->core.width) { /* Only get wider. */
2472 rbox.request_mode = CWWidth;
2473 if (XtMakeGeometryRequest(w, &rbox, &return_geom) == XtGeometryAlmost)
2474 (void) XtMakeGeometryRequest(w, &return_geom, (XtWidgetGeometry*) NULL);
2475 }
2476 }
2477
2478 if ( !((ctx->text.resize == XawtextResizeHeight) ||
2479 (ctx->text.resize == XawtextResizeBoth)) )
2480 return;
2481
2482 if (IsPositionVisible(ctx, ctx->text.lastPos))
2483 line = LineForPosition(ctx, ctx->text.lastPos);
2484 else
2485 line = ctx->text.lt.lines;
2486
2487 if ( (line + 1) == ctx->text.lt.lines ) return;
2488
2489 old_height = ctx->core.height;
2490 rbox.request_mode = CWHeight;
2491 rbox.height = XawTextSinkMaxHeight(ctx->text.sink, line + 1) + VMargins(ctx);
2492
2493 if ((int)rbox.height < old_height) return; /* It will only get taller. */
2494
2495 if (XtMakeGeometryRequest(w, &rbox, &return_geom) == XtGeometryAlmost)
2496 if (XtMakeGeometryRequest(w, &return_geom, (XtWidgetGeometry*)NULL) != XtGeometryYes)
2497 return;
2498
2499 _XawTextBuildLineTable(ctx, ctx->text.lt.top, TRUE);
2500 }
2501
2502 /*
2503 * Converts (params, num_params) to a list of atoms & caches the
2504 * list in the TextWidget instance.
2505 */
2506
2507 Atom*
_XawTextSelectionList(ctx,list,nelems)2508 _XawTextSelectionList(ctx, list, nelems)
2509 TextWidget ctx;
2510 String *list;
2511 Cardinal nelems;
2512 {
2513 Atom * sel = ctx->text.s.selections;
2514 Display *dpy = XtDisplay((Widget) ctx);
2515 int n;
2516
2517 if (nelems > ctx->text.s.array_size) {
2518 sel = (Atom *) XtRealloc((char *) sel, sizeof(Atom) * nelems);
2519 ctx->text.s.array_size = nelems;
2520 ctx->text.s.selections = sel;
2521 }
2522 for (n=nelems; --n >= 0; sel++, list++)
2523 *sel = XInternAtom(dpy, *list, False);
2524 ctx->text.s.atom_count = nelems;
2525 return ctx->text.s.selections;
2526 }
2527
2528 /* Function Name: SetSelection
2529 * Description: Sets the current selection.
2530 * Arguments: ctx - the text widget.
2531 * defaultSel - the default selection.
2532 * l, r - the left and right ends of the selection.
2533 * list, nelems - the selection list (as strings).
2534 * Returns: none.
2535 *
2536 * NOTE: if (ctx->text.s.left >= ctx->text.s.right) then the selection
2537 * is unset.
2538 */
2539
2540 void
_XawTextSetSelection(ctx,l,r,list,nelems)2541 _XawTextSetSelection(ctx, l, r, list, nelems)
2542 TextWidget ctx;
2543 XawTextPosition l, r;
2544 String *list;
2545 Cardinal nelems;
2546 {
2547 if (nelems == 1 && !strcmp (list[0], "none"))
2548 return;
2549 if (nelems == 0) {
2550 String defaultSel = "PRIMARY";
2551 list = &defaultSel;
2552 nelems = 1;
2553 }
2554 _SetSelection(ctx, l, r, _XawTextSelectionList(ctx, list, nelems), nelems);
2555 }
2556
2557
2558 /* Function Name: ModifySelection
2559 * Description: Modifies the current selection.
2560 * Arguments: ctx - the text widget.
2561 * left, right - the left and right ends of the selection.
2562 * Returns: none.
2563 *
2564 * NOTE: if (ctx->text.s.left >= ctx->text.s.right) then the selection
2565 * is unset.
2566 */
2567
2568 static void
ModifySelection(ctx,left,right)2569 ModifySelection(ctx, left, right)
2570 TextWidget ctx;
2571 XawTextPosition left, right;
2572 {
2573 if (left == right)
2574 ctx->text.insertPos = left;
2575 _SetSelection( ctx, left, right, (Atom*) NULL, ZERO );
2576 }
2577
2578 /*
2579 * This routine is used to perform various selection functions. The goal is
2580 * to be able to specify all the more popular forms of draw-through and
2581 * multi-click selection user interfaces from the outside.
2582 */
2583
2584 void
_XawTextAlterSelection(ctx,mode,action,params,num_params)2585 _XawTextAlterSelection (ctx, mode, action, params, num_params)
2586 TextWidget ctx;
2587 XawTextSelectionMode mode; /* {XawsmTextSelect, XawsmTextExtend} */
2588 XawTextSelectionAction action; /* {XawactionStart,
2589 XawactionAdjust, XawactionEnd} */
2590 String *params;
2591 Cardinal *num_params;
2592 {
2593 XawTextPosition position;
2594 Boolean flag;
2595
2596 /*
2597 * This flag is used by TextPop.c:DoReplace() to determine if the selection
2598 * is okay to use, or if it has been modified.
2599 */
2600
2601 if (ctx->text.search != NULL)
2602 ctx->text.search->selection_changed = TRUE;
2603
2604 position = PositionForXY (ctx, (int) ctx->text.ev_x, (int) ctx->text.ev_y);
2605
2606 flag = (action != XawactionStart);
2607 if (mode == XawsmTextSelect)
2608 DoSelection (ctx, position, ctx->text.time, flag);
2609 else /* mode == XawsmTextExtend */
2610 ExtendSelection (ctx, position, flag);
2611
2612 if (action == XawactionEnd)
2613 _XawTextSetSelection(ctx, ctx->text.s.left, ctx->text.s.right,
2614 params, *num_params);
2615 }
2616
2617 /* Function Name: RectanglesOverlap
2618 * Description: Returns TRUE if two rectangles overlap.
2619 * Arguments: rect1, rect2 - the two rectangles to check.
2620 * Returns: TRUE iff these rectangles overlap.
2621 */
2622
2623 static Boolean
RectanglesOverlap(rect1,rect2)2624 RectanglesOverlap(rect1, rect2)
2625 XRectangle *rect1, *rect2;
2626 {
2627 return ( (rect1->x < rect2->x + (short) rect2->width) &&
2628 (rect2->x < rect1->x + (short) rect1->width) &&
2629 (rect1->y < rect2->y + (short) rect2->height) &&
2630 (rect2->y < rect1->y + (short) rect1->height) );
2631 }
2632
2633 /* Function Name: UpdateTextInRectangle.
2634 * Description: Updates the text in a rectangle.
2635 * Arguments: ctx - the text widget.
2636 * rect - the rectangle to update.
2637 * Returns: none.
2638 */
2639
2640 static void
UpdateTextInRectangle(ctx,rect)2641 UpdateTextInRectangle(ctx, rect)
2642 TextWidget ctx;
2643 XRectangle * rect;
2644 {
2645 XawTextLineTableEntry *info = ctx->text.lt.info;
2646 int line, x = rect->x, y = rect->y;
2647 int right = rect->width + x, bottom = rect->height + y;
2648
2649 for (line = 0;( (line < ctx->text.lt.lines) &&
2650 IsValidLine(ctx, line) && (info->y < bottom)); line++, info++)
2651 if ( (info + 1)->y >= y )
2652 UpdateTextInLine(ctx, line, x, right);
2653 }
2654
2655 /*
2656 * This routine processes all "expose region" XEvents. In general, its job
2657 * is to the best job at minimal re-paint of the text, displayed in the
2658 * window, that it can.
2659 */
2660
2661 /* ARGSUSED */
2662 static void
ProcessExposeRegion(w,event,region)2663 ProcessExposeRegion(w, event, region)
2664 Widget w;
2665 XEvent *event;
2666 Region region; /* Unused. */
2667 {
2668 TextWidget ctx = (TextWidget) w;
2669 ThreeDWidget tdw = (ThreeDWidget)ctx->text.threeD;
2670 XRectangle expose, cursor;
2671 Boolean need_to_draw;
2672
2673 if (event->type == Expose) {
2674 expose.x = event->xexpose.x;
2675 expose.y = event->xexpose.y;
2676 expose.width = event->xexpose.width;
2677 expose.height = event->xexpose.height;
2678 }
2679 else if (event->type == GraphicsExpose) {
2680 expose.x = event->xgraphicsexpose.x;
2681 expose.y = event->xgraphicsexpose.y;
2682 expose.width = event->xgraphicsexpose.width;
2683 expose.height = event->xgraphicsexpose.height;
2684 }
2685 else { /* No Expose */
2686 PopCopyQueue(ctx);
2687 return; /* no more processing necessary. */
2688 }
2689
2690 need_to_draw = TranslateExposeRegion(ctx, &expose);
2691 if ((event->type == GraphicsExpose) && (event->xgraphicsexpose.count == 0))
2692 PopCopyQueue(ctx);
2693
2694 if (!need_to_draw)
2695 return; /* don't draw if we don't need to. */
2696
2697 _XawTextPrepareToUpdate(ctx);
2698 UpdateTextInRectangle(ctx, &expose);
2699 XawTextSinkGetCursorBounds(ctx->text.sink, &cursor);
2700 if (RectanglesOverlap(&cursor, &expose)) {
2701 SinkClearToBG(ctx->text.sink, (Position) cursor.x, (Position) cursor.y,
2702 (Dimension) cursor.width, (Dimension) cursor.height);
2703 UpdateTextInRectangle(ctx, &cursor);
2704 }
2705 _XawTextExecuteUpdate(ctx);
2706
2707 neXtawDrawShadowBox(w, tdw, 0, 0, ctx->core.width, ctx->core.height, False);
2708 }
2709
2710 /*
2711 * This routine does all setup required to syncronize batched screen updates
2712 */
2713
2714 void
_XawTextPrepareToUpdate(ctx)2715 _XawTextPrepareToUpdate(ctx)
2716 TextWidget ctx;
2717 {
2718 if (ctx->text.old_insert < 0) {
2719 InsertCursor((Widget)ctx, XawisOff);
2720 ctx->text.numranges = 0;
2721 ctx->text.showposition = FALSE;
2722 ctx->text.old_insert = ctx->text.insertPos;
2723 }
2724 }
2725
2726 /*
2727 * This is a private utility routine used by _XawTextExecuteUpdate. It
2728 * processes all the outstanding update requests and merges update
2729 * ranges where possible.
2730 */
2731
2732 static
FlushUpdate(ctx)2733 void FlushUpdate(ctx)
2734 TextWidget ctx;
2735 {
2736 int i, w;
2737 XawTextPosition updateFrom, updateTo;
2738 if (!XtIsRealized((Widget)ctx)) {
2739 ctx->text.numranges = 0;
2740 return;
2741 }
2742 while (ctx->text.numranges > 0) {
2743 updateFrom = ctx->text.updateFrom[0];
2744 w = 0;
2745 for (i = 1 ; i < ctx->text.numranges ; i++) {
2746 if (ctx->text.updateFrom[i] < updateFrom) {
2747 updateFrom = ctx->text.updateFrom[i];
2748 w = i;
2749 }
2750 }
2751 updateTo = ctx->text.updateTo[w];
2752 ctx->text.numranges--;
2753 ctx->text.updateFrom[w] = ctx->text.updateFrom[ctx->text.numranges];
2754 ctx->text.updateTo[w] = ctx->text.updateTo[ctx->text.numranges];
2755 for (i = ctx->text.numranges - 1 ; i >= 0 ; i--) {
2756 while (ctx->text.updateFrom[i] <= updateTo && i < ctx->text.numranges) {
2757 updateTo = ctx->text.updateTo[i];
2758 ctx->text.numranges--;
2759 ctx->text.updateFrom[i] = ctx->text.updateFrom[ctx->text.numranges];
2760 ctx->text.updateTo[i] = ctx->text.updateTo[ctx->text.numranges];
2761 }
2762 }
2763 DisplayText((Widget)ctx, updateFrom, updateTo);
2764 }
2765 }
2766
2767 /*
2768 * This is a private utility routine used by _XawTextExecuteUpdate. This
2769 * routine worries about edits causing new data or the insertion point becoming
2770 * invisible (off the screen, or under the horiz. scrollbar). Currently
2771 * it always makes it visible by scrolling. It probably needs
2772 * generalization to allow more options.
2773 */
2774
2775 void
_XawTextShowPosition(ctx)2776 _XawTextShowPosition(ctx)
2777 TextWidget ctx;
2778 {
2779 int x, y, lines, number;
2780 Boolean no_scroll;
2781 XawTextPosition max_pos, top, first;
2782
2783 if ( (!XtIsRealized((Widget)ctx)) || (ctx->text.lt.lines <= 0) )
2784 return;
2785
2786 /*
2787 * Find out the bottom the visable window, and make sure that the
2788 * cursor does not go past the end of this space.
2789 *
2790 * This makes sure that the cursor does not go past the end of the
2791 * visable window.
2792 */
2793
2794 x = ctx->core.width;
2795 y = ctx->core.height - ctx->text.margin.bottom;
2796 if (ctx->text.hbar != NULL)
2797 y -= ctx->text.hbar->core.height + 2 * ctx->text.hbar->core.border_width;
2798
2799 max_pos = PositionForXY (ctx, x, y);
2800 lines = LineForPosition(ctx, max_pos) + 1; /* number of visable lines. */
2801
2802 if ( (ctx->text.insertPos >= ctx->text.lt.top) &&
2803 (ctx->text.insertPos < max_pos))
2804 return;
2805
2806 first = ctx->text.lt.top;
2807 no_scroll = FALSE;
2808
2809 if (ctx->text.insertPos < first) { /* We need to scroll down. */
2810 top = SrcScan(ctx->text.source, ctx->text.insertPos,
2811 XawstEOL, XawsdLeft, 1, FALSE);
2812
2813 /* count the number of lines we have to scroll */
2814
2815 number = 0;
2816 while (first > top) {
2817 first = SrcScan(ctx->text.source, first,
2818 XawstEOL, XawsdLeft, 1, TRUE);
2819
2820 if ( - number > lines )
2821 break;
2822
2823 number--;
2824 }
2825
2826 if (first <= top) { /* If we found the proper number
2827 of lines. */
2828
2829 /* Back up to just before the last CR. */
2830
2831 first = SrcScan(ctx->text.source, first,
2832 XawstPositions, XawsdRight, 1, TRUE);
2833
2834 /* Check to make sure the cursor is visable. */
2835
2836 if (first <= top)
2837 number++;
2838
2839 lines = number;
2840 }
2841 else
2842 no_scroll = TRUE;
2843 }
2844 else { /* We need to Scroll up */
2845 top = SrcScan(ctx->text.source, ctx->text.insertPos,
2846 XawstEOL, XawsdLeft, lines, FALSE);
2847
2848 if (top < max_pos)
2849 lines = LineForPosition(ctx, top);
2850 else
2851 no_scroll = TRUE;
2852 }
2853
2854 if (no_scroll) {
2855 _XawTextBuildLineTable(ctx, top, FALSE);
2856 DisplayTextWindow((Widget)ctx);
2857 }
2858 else
2859 _XawTextVScroll(ctx, lines);
2860
2861 _XawTextSetScrollBars(ctx);
2862 }
2863
2864 /*
2865 * This routine causes all batched screen updates to be performed
2866 */
2867
2868 void
_XawTextExecuteUpdate(ctx)2869 _XawTextExecuteUpdate(ctx)
2870 TextWidget ctx;
2871 {
2872 if ( ctx->text.update_disabled || (ctx->text.old_insert < 0) )
2873 return;
2874
2875 if((ctx->text.old_insert != ctx->text.insertPos) || (ctx->text.showposition))
2876 _XawTextShowPosition(ctx);
2877 FlushUpdate(ctx);
2878 InsertCursor((Widget)ctx, XawisOn);
2879 ctx->text.old_insert = -1;
2880 }
2881
2882
2883 static void
TextDestroy(w)2884 TextDestroy(w)
2885 Widget w;
2886 {
2887 TextWidget ctx = (TextWidget)w;
2888
2889 DestroyHScrollBar(ctx);
2890 DestroyVScrollBar(ctx);
2891
2892 XtFree((char *)ctx->text.s.selections);
2893 XtFree((char *)ctx->text.lt.info);
2894 XtFree((char *)ctx->text.search);
2895 XtFree((char *)ctx->text.updateFrom);
2896 XtFree((char *)ctx->text.updateTo);
2897 }
2898
2899 /*
2900 * by the time we are managed (and get this far) we had better
2901 * have both a source and a sink
2902 */
2903
2904 static void
Resize(w)2905 Resize(w)
2906 Widget w;
2907 {
2908 TextWidget ctx = (TextWidget) w;
2909
2910 PositionVScrollBar(ctx);
2911 PositionHScrollBar(ctx);
2912
2913 _XawTextBuildLineTable(ctx, ctx->text.lt.top, TRUE);
2914 _XawTextSetScrollBars(ctx);
2915 }
2916
2917 /*
2918 * This routine allow the application program to Set attributes.
2919 */
2920
2921 /*ARGSUSED*/
2922 static Boolean
SetValues(current,request,new,args,num_args)2923 SetValues(current, request, new, args, num_args)
2924 Widget current, request, new;
2925 ArgList args;
2926 Cardinal *num_args;
2927 {
2928 TextWidget oldtw = (TextWidget) current;
2929 TextWidget newtw = (TextWidget) new;
2930 Boolean redisplay = FALSE;
2931 Boolean display_caret = newtw->text.display_caret;
2932
2933
2934 newtw->text.display_caret = oldtw->text.display_caret;
2935 _XawTextPrepareToUpdate(newtw);
2936 newtw->text.display_caret = display_caret;
2937
2938 if (oldtw->text.r_margin.left != newtw->text.r_margin.left) {
2939 newtw->text.margin.left = newtw->text.r_margin.left+newtw->text.shadow_width;
2940 if (newtw->text.vbar != NULL)
2941 newtw->text.margin.left += newtw->text.vbar->core.width +
2942 newtw->text.vbar->core.border_width;
2943 redisplay = TRUE;
2944 }
2945
2946 if (oldtw->text.scroll_vert != newtw->text.scroll_vert) {
2947 if (newtw->text.scroll_vert == XawtextScrollNever)
2948 DestroyVScrollBar(newtw);
2949 else if (newtw->text.scroll_vert == XawtextScrollAlways)
2950 CreateVScrollBar(newtw);
2951 redisplay = TRUE;
2952 }
2953
2954 if (oldtw->text.r_margin.bottom != newtw->text.r_margin.bottom) {
2955 newtw->text.margin.bottom = newtw->text.r_margin.bottom+newtw->text.shadow_width;
2956 if (newtw->text.hbar != NULL)
2957 newtw->text.margin.bottom += newtw->text.hbar->core.height +
2958 newtw->text.hbar->core.border_width;
2959 redisplay = TRUE;
2960 }
2961
2962 if (oldtw->text.scroll_horiz != newtw->text.scroll_horiz) {
2963 if (newtw->text.scroll_horiz == XawtextScrollNever)
2964 DestroyHScrollBar(newtw);
2965 else if (newtw->text.scroll_horiz == XawtextScrollAlways)
2966 CreateHScrollBar(newtw);
2967 redisplay = TRUE;
2968 }
2969
2970 if ( oldtw->text.source != newtw->text.source )
2971 XawTextSetSource( (Widget) newtw, newtw->text.source, newtw->text.lt.top);
2972
2973 newtw->text.redisplay_needed = False;
2974 XtSetValues( (Widget)newtw->text.source, args, *num_args );
2975 XtSetValues( (Widget)newtw->text.sink, args, *num_args );
2976
2977 if ( oldtw->text.wrap != newtw->text.wrap ||
2978 oldtw->text.lt.top != newtw->text.lt.top ||
2979 oldtw->text.r_margin.right != newtw->text.r_margin.right ||
2980 oldtw->text.r_margin.top != newtw->text.r_margin.top ||
2981 oldtw->text.sink != newtw->text.sink ||
2982 newtw->text.redisplay_needed )
2983 {
2984 _XawTextBuildLineTable(newtw, newtw->text.lt.top, TRUE);
2985 redisplay = TRUE;
2986 }
2987
2988 if (oldtw->text.insertPos != newtw->text.insertPos) {
2989 newtw->text.showposition = TRUE;
2990 redisplay = TRUE;
2991 }
2992
2993 _XawTextExecuteUpdate(newtw);
2994 if (redisplay)
2995 _XawTextSetScrollBars(newtw);
2996
2997 return redisplay;
2998 }
2999
3000 /* invoked by the Simple widget's SetValues */
ChangeSensitive(w)3001 static Boolean ChangeSensitive(w)
3002 Widget w; /* the new widget */
3003 {
3004 Arg args[1];
3005 TextWidget tw = (TextWidget) w;
3006
3007 (*(&simpleClassRec)->simple_class.change_sensitive)(w);
3008
3009 XtSetArg(args[0], XtNancestorSensitive,
3010 (tw->core.ancestor_sensitive && tw->core.sensitive));
3011 if (tw->text.vbar)
3012 XtSetValues(tw->text.vbar, args, ONE);
3013 if (tw->text.hbar)
3014 XtSetValues(tw->text.hbar, args, ONE);
3015 return False;
3016 }
3017
3018 /* Function Name: GetValuesHook
3019 * Description: This is a get values hook routine that gets the
3020 * values in the text source and sink.
3021 * Arguments: w - the Text Widget.
3022 * args - the argument list.
3023 * num_args - the number of args.
3024 * Returns: none.
3025 */
3026
3027 static void
GetValuesHook(w,args,num_args)3028 GetValuesHook(w, args, num_args)
3029 Widget w;
3030 ArgList args;
3031 Cardinal * num_args;
3032 {
3033 XtGetValues( ((TextWidget) w)->text.source, args, *num_args );
3034 XtGetValues( ((TextWidget) w)->text.sink, args, *num_args );
3035 }
3036
3037 /* Function Name: FindGoodPosition
3038 * Description: Returns a valid position given any postition
3039 * Arguments: pos - any position.
3040 * Returns: a position between (0 and lastPos);
3041 */
3042
3043 static XawTextPosition
FindGoodPosition(ctx,pos)3044 FindGoodPosition(ctx, pos)
3045 TextWidget ctx;
3046 XawTextPosition pos;
3047 {
3048 if (pos < 0) return(0);
3049 return ( ((pos > ctx->text.lastPos) ? ctx->text.lastPos : pos) );
3050 }
3051
3052 /************************************************************
3053 *
3054 * Routines for handling the copy area expose queue.
3055 *
3056 ************************************************************/
3057
3058 /* Function Name: PushCopyQueue
3059 * Description: Pushes a value onto the copy queue.
3060 * Arguments: ctx - the text widget.
3061 * h, v - amount of offset in the horiz and vert directions.
3062 * Returns: none
3063 */
3064
3065 static void
PushCopyQueue(ctx,h,v)3066 PushCopyQueue(ctx, h, v)
3067 TextWidget ctx;
3068 int h, v;
3069 {
3070 struct text_move * offsets = XtNew(struct text_move);
3071
3072 offsets->h = h;
3073 offsets->v = v;
3074 offsets->next = NULL;
3075
3076 if (ctx->text.copy_area_offsets == NULL)
3077 ctx->text.copy_area_offsets = offsets;
3078 else {
3079 struct text_move * end = ctx->text.copy_area_offsets;
3080 for ( ; end->next != NULL; end = end->next) {}
3081 end->next = offsets;
3082 }
3083 }
3084
3085 /* Function Name: PopCopyQueue
3086 * Description: Pops the top value off of the copy queue.
3087 * Arguments: ctx - the text widget.
3088 * Returns: none.
3089 */
3090
3091 static void
PopCopyQueue(ctx)3092 PopCopyQueue(ctx)
3093 TextWidget ctx;
3094 {
3095 struct text_move * offsets = ctx->text.copy_area_offsets;
3096
3097 if (offsets == NULL)
3098 (void) printf( "Xaw Text widget %s: empty copy queue\n",
3099 XtName( (Widget) ctx ) );
3100 else {
3101 ctx->text.copy_area_offsets = offsets->next;
3102 XtFree((char *) offsets); /* free what you allocate. */
3103 }
3104 }
3105
3106 /* Function Name: TranslateExposeRegion
3107 * Description: Translates the expose that came into
3108 * the cordinates that now exist in the Text widget.
3109 * Arguments: ctx - the text widget.
3110 * expose - a Rectangle, who's region currently
3111 * contains the expose event location.
3112 * this region will be returned containing
3113 * the new rectangle.
3114 * Returns: True if there is drawing that needs to be done.
3115 */
3116
3117 static Boolean
TranslateExposeRegion(ctx,expose)3118 TranslateExposeRegion(ctx, expose)
3119 TextWidget ctx;
3120 XRectangle * expose;
3121 {
3122 struct text_move * offsets = ctx->text.copy_area_offsets;
3123 int value;
3124 int x, y, width, height;
3125
3126 /*
3127 * Skip over the first one, this has already been taken into account.
3128 */
3129
3130 if (!offsets || !(offsets = offsets->next))
3131 return(TRUE);
3132
3133 x = expose->x;
3134 y = expose->y;
3135 width = expose->width;
3136 height = expose->height;
3137
3138 while (offsets) {
3139 x += offsets->h;
3140 y += offsets->v;
3141 offsets = offsets->next;
3142 }
3143
3144 /*
3145 * remove that area of the region that is now outside the window.
3146 */
3147
3148 if (y < 0) {
3149 height += y;
3150 y = 0;
3151 }
3152
3153 value = y + height - ctx->core.height;
3154 if (value > 0)
3155 height -= value;
3156
3157 if (height <= 0)
3158 return(FALSE); /* no need to draw outside the window. */
3159
3160 /*
3161 * and now in the horiz direction...
3162 */
3163
3164 if (x < 0) {
3165 width += x;
3166 x = 0;
3167 }
3168
3169 value = x + width - ctx->core.width;
3170 if (value > 0)
3171 width -= value;
3172
3173 if (width <= 0)
3174 return(FALSE); /* no need to draw outside the window. */
3175
3176 expose->x = x;
3177 expose->y = y;
3178 expose->width = width;
3179 expose->height = height;
3180 return(TRUE);
3181 }
3182
3183 /* Li wrote this so the IM can find a given text position's screen position. */
3184
3185 void
3186 #if NeedFunctionPrototypes
_XawTextPosToXY(Widget w,XawTextPosition pos,Position * x,Position * y)3187 _XawTextPosToXY(
3188 Widget w,
3189 XawTextPosition pos,
3190 Position* x,
3191 Position* y )
3192 #else
3193 _XawTextPosToXY( w, pos, x, y )
3194 Widget w;
3195 XawTextPosition pos;
3196 Position *x, *y;
3197 #endif
3198 {
3199 int line;
3200 LineAndXYForPosition( (TextWidget)w, pos, &line, x, y );
3201 }
3202
3203 /*******************************************************************
3204 The following routines provide procedural interfaces to Text window state
3205 setting and getting. They need to be redone so than the args code can use
3206 them. I suggest we create a complete set that takes the context as an
3207 argument and then have the public version lookup the context and call the
3208 internal one. The major value of this set is that they have actual application
3209 clients and therefore the functionality provided is required for any future
3210 version of Text.
3211 ********************************************************************/
3212
3213 void
3214 #if NeedFunctionPrototypes
XawTextDisplay(Widget w)3215 XawTextDisplay (Widget w)
3216 #else
3217 XawTextDisplay (w)
3218 Widget w;
3219 #endif
3220 {
3221 if (!XtIsRealized(w)) return;
3222
3223 _XawTextPrepareToUpdate( (TextWidget) w);
3224 DisplayTextWindow(w);
3225 _XawTextExecuteUpdate( (TextWidget) w);
3226 }
3227
3228 void
3229 #if NeedFunctionPrototypes
XawTextSetSelectionArray(Widget w,XawTextSelectType * sarray)3230 XawTextSetSelectionArray(Widget w, XawTextSelectType *sarray)
3231 #else
3232 XawTextSetSelectionArray(w, sarray)
3233 Widget w;
3234 XawTextSelectType *sarray;
3235 #endif
3236 {
3237 ((TextWidget)w)->text.sarray = sarray;
3238 }
3239
3240 void
3241 #if NeedFunctionPrototypes
XawTextGetSelectionPos(Widget w,XawTextPosition * left,XawTextPosition * right)3242 XawTextGetSelectionPos(Widget w, XawTextPosition *left, XawTextPosition *right)
3243 #else
3244 XawTextGetSelectionPos(w, left, right)
3245 Widget w;
3246 XawTextPosition* left,* right;
3247 #endif
3248 {
3249 *left = ((TextWidget) w)->text.s.left;
3250 *right = ((TextWidget) w)->text.s.right;
3251 }
3252
3253
3254 void
3255 #if NeedFunctionPrototypes
XawTextSetSource(Widget w,Widget source,XawTextPosition startPos)3256 XawTextSetSource(Widget w, Widget source, XawTextPosition startPos)
3257 #else
3258 XawTextSetSource(w, source, startPos)
3259 Widget w, source;
3260 XawTextPosition startPos;
3261 #endif
3262 {
3263 TextWidget ctx = (TextWidget) w;
3264
3265 ctx->text.source = source;
3266 ctx->text.lt.top = startPos;
3267 ctx->text.s.left = ctx->text.s.right = 0;
3268 ctx->text.insertPos = startPos;
3269 ctx->text.lastPos = GETLASTPOS;
3270
3271 _XawTextBuildLineTable(ctx, ctx->text.lt.top, TRUE);
3272 XawTextDisplay(w);
3273 }
3274
3275 /*
3276 * This public routine deletes the text from startPos to endPos in a source and
3277 * then inserts, at startPos, the text that was passed. As a side effect it
3278 * "invalidates" that portion of the displayed text (if any), so that things
3279 * will be repainted properly.
3280 */
3281
3282 int
3283 #if NeedFunctionPrototypes
XawTextReplace(Widget w,XawTextPosition startPos,XawTextPosition endPos,XawTextBlock * text)3284 XawTextReplace(Widget w, XawTextPosition startPos, XawTextPosition endPos,
3285 XawTextBlock *text)
3286 #else
3287 XawTextReplace(w, startPos, endPos, text)
3288 Widget w;
3289 XawTextPosition startPos, endPos;
3290 XawTextBlock *text;
3291 #endif
3292 {
3293 TextWidget ctx = (TextWidget) w;
3294 int result;
3295
3296 _XawTextPrepareToUpdate(ctx);
3297 endPos = FindGoodPosition(ctx, endPos);
3298 startPos = FindGoodPosition(ctx, startPos);
3299 if ((result = _XawTextReplace(ctx, startPos, endPos, text)) == XawEditDone) {
3300 int delta = text->length - (endPos - startPos);
3301 if (ctx->text.insertPos >= (endPos + delta)) {
3302 XawTextScanDirection sd = (delta < 0) ? XawsdLeft : XawsdRight;
3303 ctx->text.insertPos = SrcScan(ctx->text.source, ctx->text.insertPos,
3304 XawstPositions, sd, abs(delta), TRUE);
3305 }
3306 }
3307
3308 _XawTextCheckResize(ctx);
3309 _XawTextExecuteUpdate(ctx);
3310 _XawTextSetScrollBars(ctx);
3311
3312 return result;
3313 }
3314
3315 XawTextPosition
3316 #if NeedFunctionPrototypes
XawTextTopPosition(Widget w)3317 XawTextTopPosition(Widget w)
3318 #else
3319 XawTextTopPosition(w)
3320 Widget w;
3321 #endif
3322 {
3323 return( ((TextWidget) w)->text.lt.top );
3324 }
3325
3326 void
3327 #if NeedFunctionPrototypes
XawTextSetInsertionPoint(Widget w,XawTextPosition position)3328 XawTextSetInsertionPoint(Widget w, XawTextPosition position)
3329 #else
3330 XawTextSetInsertionPoint(w, position)
3331 Widget w;
3332 XawTextPosition position;
3333 #endif
3334 {
3335 TextWidget ctx = (TextWidget) w;
3336
3337 _XawTextPrepareToUpdate(ctx);
3338 ctx->text.insertPos = FindGoodPosition(ctx, position);
3339 ctx->text.showposition = TRUE;
3340
3341 _XawTextExecuteUpdate(ctx);
3342 }
3343
3344 XawTextPosition
3345 #if NeedFunctionPrototypes
XawTextGetInsertionPoint(Widget w)3346 XawTextGetInsertionPoint(Widget w)
3347 #else
3348 XawTextGetInsertionPoint(w)
3349 Widget w;
3350 #endif
3351 {
3352 return( ((TextWidget) w)->text.insertPos);
3353 }
3354
3355 /*
3356 * NOTE: Must walk the selection list in opposite order from LoseSelection.
3357 */
3358
3359 void
3360 #if NeedFunctionPrototypes
XawTextUnsetSelection(Widget w)3361 XawTextUnsetSelection(Widget w)
3362 #else
3363 XawTextUnsetSelection(w)
3364 Widget w;
3365 #endif
3366 {
3367 TextWidget ctx = (TextWidget)w;
3368
3369 while (ctx->text.s.atom_count != 0) {
3370 Atom sel = ctx->text.s.selections[ctx->text.s.atom_count - 1];
3371 if ( sel != (Atom) 0 ) {
3372 /*
3373 * As selections are lost the atom_count will decrement.
3374 */
3375 if (GetCutBufferNumber(sel) == NOT_A_CUT_BUFFER)
3376 XtDisownSelection(w, sel, ctx->text.time);
3377 LoseSelection(w, &sel); /* In case this is a cut buffer, or
3378 XtDisownSelection failed to call us. */
3379 }
3380 }
3381 }
3382
3383 void
3384 #if NeedFunctionPrototypes
XawTextSetSelection(Widget w,XawTextPosition left,XawTextPosition right)3385 XawTextSetSelection (Widget w, XawTextPosition left, XawTextPosition right)
3386 #else
3387 XawTextSetSelection (w, left, right)
3388 Widget w;
3389 XawTextPosition left, right;
3390 #endif
3391 {
3392 TextWidget ctx = (TextWidget) w;
3393
3394 _XawTextPrepareToUpdate(ctx);
3395 _XawTextSetSelection(ctx, FindGoodPosition(ctx, left),
3396 FindGoodPosition(ctx, right), (String*)NULL, ZERO);
3397 _XawTextExecuteUpdate(ctx);
3398 }
3399
3400 void
3401 #if NeedFunctionPrototypes
XawTextInvalidate(Widget w,XawTextPosition from,XawTextPosition to)3402 XawTextInvalidate(Widget w, XawTextPosition from, XawTextPosition to)
3403 #else
3404 XawTextInvalidate(w, from, to)
3405 Widget w;
3406 XawTextPosition from,to;
3407 #endif
3408 {
3409 TextWidget ctx = (TextWidget) w;
3410
3411 from = FindGoodPosition(ctx, from);
3412 to = FindGoodPosition(ctx, to);
3413 ctx->text.lastPos = GETLASTPOS;
3414 _XawTextPrepareToUpdate(ctx);
3415 _XawTextNeedsUpdating(ctx, from, to);
3416 _XawTextBuildLineTable(ctx, ctx->text.lt.top, TRUE);
3417 _XawTextExecuteUpdate(ctx);
3418 }
3419
3420 /*ARGSUSED*/
3421 void
3422 #if NeedFunctionPrototypes
XawTextDisableRedisplay(Widget w)3423 XawTextDisableRedisplay(Widget w)
3424 #else
3425 XawTextDisableRedisplay(w)
3426 Widget w;
3427 #endif
3428 {
3429 ((TextWidget) w)->text.update_disabled = True;
3430 _XawTextPrepareToUpdate( (TextWidget) w);
3431 }
3432
3433 void
3434 #if NeedFunctionPrototypes
XawTextEnableRedisplay(Widget w)3435 XawTextEnableRedisplay(Widget w)
3436 #else
3437 XawTextEnableRedisplay(w)
3438 Widget w;
3439 #endif
3440 {
3441 TextWidget ctx = (TextWidget)w;
3442 XawTextPosition lastPos;
3443
3444 if (!ctx->text.update_disabled) return;
3445
3446 ctx->text.update_disabled = False;
3447 lastPos = ctx->text.lastPos = GETLASTPOS;
3448 ctx->text.lt.top = FindGoodPosition(ctx, ctx->text.lt.top);
3449 ctx->text.insertPos = FindGoodPosition(ctx, ctx->text.insertPos);
3450 if ( (ctx->text.s.left > lastPos) || (ctx->text.s.right > lastPos) )
3451 ctx->text.s.left = ctx->text.s.right = 0;
3452
3453 _XawTextBuildLineTable(ctx, ctx->text.lt.top, TRUE);
3454 if (XtIsRealized(w))
3455 DisplayTextWindow(w);
3456 _XawTextExecuteUpdate(ctx);
3457 }
3458
3459 Widget
3460 #if NeedFunctionPrototypes
XawTextGetSource(Widget w)3461 XawTextGetSource(Widget w)
3462 #else
3463 XawTextGetSource(w)
3464 Widget w;
3465 #endif
3466 {
3467 return ((TextWidget)w)->text.source;
3468 }
3469
3470 void
3471 #if NeedFunctionPrototypes
XawTextDisplayCaret(Widget w,int display_caret)3472 XawTextDisplayCaret (Widget w,
3473 #if NeedWidePrototypes
3474 /* Boolean */ int display_caret)
3475 #else
3476 Boolean display_caret)
3477 #endif
3478 #else
3479 XawTextDisplayCaret (w, display_caret)
3480 Widget w;
3481 Boolean display_caret;
3482 #endif
3483 {
3484 TextWidget ctx = (TextWidget) w;
3485
3486 if (ctx->text.display_caret == display_caret) return;
3487
3488 if (XtIsRealized(w)) {
3489 _XawTextPrepareToUpdate(ctx);
3490 ctx->text.display_caret = display_caret;
3491 _XawTextExecuteUpdate(ctx);
3492 }
3493 else
3494 ctx->text.display_caret = display_caret;
3495 }
3496
3497 /* Function Name: XawTextSearch(w, dir, text).
3498 * Description: searches for the given text block.
3499 * Arguments: w - The text widget.
3500 * dir - The direction to search.
3501 * text - The text block containing info about the string
3502 * to search for.
3503 * Returns: The position of the text found, or XawTextSearchError on
3504 * an error.
3505 */
3506
3507 XawTextPosition
3508 #if NeedFunctionPrototypes
XawTextSearch(Widget w,int dir,XawTextBlock * text)3509 XawTextSearch(Widget w,
3510 #if NeedWidePrototypes
3511 /* XawTextScanDirection */ int dir,
3512 #else
3513 XawTextScanDirection dir,
3514 #endif
3515 XawTextBlock *text)
3516 #else
3517 XawTextSearch(w, dir, text)
3518 Widget w;
3519 XawTextScanDirection dir;
3520 XawTextBlock * text;
3521 #endif
3522 {
3523 TextWidget ctx = (TextWidget) w;
3524
3525 return(SrcSearch(ctx->text.source, ctx->text.insertPos, dir, text));
3526 }
3527
3528 TextClassRec textClassRec = {
3529 { /* core fields */
3530 /* superclass */ (WidgetClass) &simpleClassRec,
3531 /* class_name */ "Text",
3532 /* widget_size */ sizeof(TextRec),
3533 /* class_initialize */ ClassInitialize,
3534 /* class_part_init */ NULL,
3535 /* class_inited */ FALSE,
3536 /* initialize */ Initialize,
3537 /* initialize_hook */ NULL,
3538 /* realize */ Realize,
3539 /* actions */ _XawTextActionsTable,
3540 /* num_actions */ 0, /* Set in ClassInitialize. */
3541 /* resources */ resources,
3542 /* num_ resource */ XtNumber(resources),
3543 /* xrm_class */ NULLQUARK,
3544 /* compress_motion */ TRUE,
3545 /* compress_exposure*/ XtExposeGraphicsExpose | XtExposeNoExpose,
3546 /* compress_enterleave*/ TRUE,
3547 /* visible_interest */ FALSE,
3548 /* destroy */ TextDestroy,
3549 /* resize */ Resize,
3550 /* expose */ ProcessExposeRegion,
3551 /* set_values */ SetValues,
3552 /* set_values_hook */ NULL,
3553 /* set_values_almost*/ XtInheritSetValuesAlmost,
3554 /* get_values_hook */ GetValuesHook,
3555 /* accept_focus */ XawAcceptFocus,
3556 /* version */ XtVersion,
3557 /* callback_private */ NULL,
3558 /* tm_table */ NULL, /* set in ClassInitialize */
3559 /* query_geometry */ XtInheritQueryGeometry,
3560 /* display_accelerator*/ XtInheritDisplayAccelerator,
3561 /* extension */ NULL
3562 },
3563 { /* Simple fields */
3564 /* change_sensitive */ ChangeSensitive
3565 },
3566 { /* text fields */
3567 /* empty */ 0
3568 }
3569 };
3570
3571 WidgetClass textWidgetClass = (WidgetClass)&textClassRec;
3572