1 /*
2 * Motif
3 *
4 * Copyright (c) 1987-2012, The Open Group. All rights reserved.
5 *
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
10 * any later version.
11 *
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
16 * details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
22 */
23 /*
24 * HISTORY
25 */
26 #ifdef REV_INFO
27 #ifndef lint
28 static char rcsid[] = "$TOG: TextOut.c /main/41 1999/08/12 11:37:30 vipin $"
29 #endif
30 #endif
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif
34
35 #include <stdio.h>
36 #include <limits.h>
37 #include <Xm/XmosP.h>
38 #include <X11/Shell.h>
39 #include <X11/Vendor.h>
40 #include <X11/Xatom.h>
41 #include <Xm/AccColorT.h>
42 #include <Xm/AtomMgr.h>
43 #include <Xm/Display.h>
44 #include <Xm/DrawP.h>
45 #include <Xm/NavigatorT.h>
46 #include <Xm/ScrollBar.h>
47 #include <Xm/ScrollFrameT.h>
48 #include <Xm/ScrolledWP.h>
49 #include <Xm/TextStrSoP.h>
50 #include <Xm/TraitP.h>
51 #include "BaseClassI.h"
52 #include "ImageCachI.h"
53 #include "MessagesI.h"
54 #include "ScreenI.h"
55 #include "ScrollFramTI.h"
56 #include "TextI.h"
57 #include "TextInI.h"
58 #include "TextOutI.h"
59 #include "TraversalI.h"
60 #include "XmI.h"
61 #ifdef PRINTING_SUPPORTED
62 #include <Xm/PrintSP.h> /* for XmIsPrintShell */
63 #endif
64 #ifdef USE_XFT
65 #include "XmRenderTI.h"
66 #endif
67 #include <Xm/XmP.h>
68
69
70 #define MSG1 _XmMMsgTextOut_0000
71 #define MSG2 _XmMMsgTextF_0001
72 #define MSG3 _XmMMsgTextF_0002
73 #define MSG4 _XmMMsgTextF_0003
74
75 #define XmDYNAMIC_BOOL ((Boolean) (255))
76
77 /******** Static Function Declarations ********/
78
79
80 static void SliderMove(Widget w,
81 XtPointer closure,
82 XtPointer call_data);
83 static void _XmTextDrawShadow(XmTextWidget tw);
84 static void SetFullGC(XmTextWidget tw,
85 GC gc);
86 static void GetRect(XmTextWidget tw,
87 XRectangle *rect);
88 static void SetMarginGC(XmTextWidget tw,
89 GC gc);
90 static void SetNormGC(XmTextWidget tw,
91 GC gc,
92 #if NeedWidePrototypes
93 int change_stipple,
94 int stipple);
95 #else
96 Boolean change_stipple,
97 Boolean stipple);
98 #endif /* NeedWidePrototypes */
99
100 #ifdef FIX_1381
101 static void SetShadowGC(XmTextWidget tw,
102 GC gc);
103 #endif
104 static void InvertImageGC(XmTextWidget tw);
105 static void SetInvGC(XmTextWidget tw,
106 GC gc);
107 static int _FontStructFindWidth(XmTextWidget tw,
108 int x,
109 XmTextBlock block,
110 int from,
111 int to);
112 static int FindWidth(XmTextWidget tw,
113 int x,
114 XmTextBlock block,
115 int from,
116 int to);
117 static XmTextPosition XYToPos(XmTextWidget tw,
118 #if NeedWidePrototypes
119 int x,
120 int y);
121 #else
122 Position x,
123 Position y);
124 #endif /* NeedWidePrototypes */
125 static Boolean PosToXY(XmTextWidget tw,
126 XmTextPosition position,
127 Position *x,
128 Position *y);
129 static XtGeometryResult TryResize(XmTextWidget tw,
130 #if NeedWidePrototypes
131 int width,
132 int height);
133 #else
134 Dimension width,
135 Dimension height);
136 #endif /* NeedWidePrototypes */
137 static int CountLines(XmTextWidget tw,
138 XmTextPosition start,
139 XmTextPosition end);
140 static void TextFindNewWidth(XmTextWidget tw,
141 Dimension *widthRtn);
142 static void TextFindNewHeight(XmTextWidget tw,
143 XmTextPosition position,
144 Dimension *heightRtn);
145 static void CheckForNewSize(XmTextWidget tw,
146 XmTextPosition position);
147 static XtPointer OutputBaseProc(Widget tw,
148 XtPointer client_data);
149 static Boolean MeasureLine(XmTextWidget tw,
150 LineNum line,
151 XmTextPosition position,
152 XmTextPosition *nextpos,
153 LineTableExtra *extra);
154 static void Draw(XmTextWidget tw,
155 LineNum line,
156 XmTextPosition start,
157 XmTextPosition end,
158 XmHighlightMode highlight);
159 static OnOrOff CurrentCursorState(XmTextWidget tw);
160 static void PaintCursor(XmTextWidget tw);
161 static void ChangeHOffset(XmTextWidget tw,
162 int newhoffset,
163 #if NeedWidePrototypes
164 int redisplay_hbar);
165 #else
166 Boolean redisplay_hbar);
167 #endif /* NeedWidePrototypes */
168 static void ChangeVOffset(XmTextWidget tw,
169 int newvoffset,
170 #if NeedWidePrototypes
171 int redisplay_vbar);
172 #else
173 Boolean redisplay_vbar);
174 #endif /* NeedWidePrototypes */
175 static void DrawInsertionPoint(XmTextWidget tw,
176 XmTextPosition position,
177 OnOrOff onoroff);
178 static void MakePositionVisible(XmTextWidget tw,
179 XmTextPosition position);
180 static void BlinkInsertionPoint(XmTextWidget tw);
181 static Boolean MoveLines(XmTextWidget tw,
182 LineNum fromline,
183 LineNum toline,
184 LineNum destline);
185 static void OutputInvalidate(XmTextWidget tw,
186 XmTextPosition position,
187 XmTextPosition topos,
188 long delta);
189 static void RefigureDependentInfo(XmTextWidget tw);
190 static void SizeFromRowsCols(XmTextWidget tw,
191 Dimension *width,
192 Dimension *height);
193 static Boolean LoadFontMetrics(XmTextWidget tw);
194 static void LoadGCs(XmTextWidget tw,
195 Pixel background,
196 Pixel foreground);
197 static void MakeIBeamOffArea(XmTextWidget tw,
198 #if NeedWidePrototypes
199 int width,
200 int height);
201 #else
202 Dimension width,
203 Dimension height);
204 #endif /* NeedWidePrototypes */
205 static Pixmap FindPixmap(Screen *screen,
206 char *image_name,
207 Pixel foreground,
208 Pixel background,
209 int depth);
210 static void MakeIBeamStencil(XmTextWidget tw,
211 int line_width);
212 static void MakeAddModeCursor(XmTextWidget tw,
213 int line_width);
214 static void MakeCursors(XmTextWidget tw);
215 static void OutputGetValues(Widget wid,
216 ArgList args,
217 Cardinal num_args);
218 static Boolean CKCols(ArgList args,
219 Cardinal num_args);
220 static Boolean CKRows(ArgList args,
221 Cardinal num_args);
222 static Boolean OutputSetValues(Widget oldw,
223 Widget reqw,
224 Widget new_w,
225 ArgList args,
226 Cardinal *num_args);
227 static void NotifyResized(Widget w,
228 #if NeedWidePrototypes
229 int o_create);
230 #else
231 Boolean o_create);
232 #endif /* NeedWidePrototypes */
233 static void HandleTimer(XtPointer closure,
234 XtIntervalId *id);
235 static void HandleFocusEvents(Widget w,
236 XtPointer closure,
237 XEvent *event,
238 Boolean *cont);
239 static void HandleGraphicsExposure(Widget w,
240 XtPointer closure,
241 XEvent *event,
242 Boolean *cont);
243 static void OutputRealize(Widget w,
244 XtValueMask *valueMask,
245 XSetWindowAttributes *attributes);
246 static void OutputDestroy(Widget w);
247 static void RedrawRegion(XmTextWidget tw,
248 int x,
249 int y,
250 int width,
251 int height);
252 static void OutputExpose(Widget w,
253 XEvent *event,
254 Region region);
255 static void GetPreferredSize(Widget widget,
256 Dimension *width,
257 Dimension *height);
258 static void HandleVBarButtonRelease(Widget w,
259 XtPointer closure,
260 XEvent *event,
261 Boolean *cont);
262 static void HandleHBarButtonRelease(Widget w,
263 XtPointer closure,
264 XEvent *event,
265 Boolean *cont);
266 static int _FontStructFindHeight(XmTextWidget tw,
267 int x,
268 XmTextBlock block,
269 int from,
270 int to);
271 static int FindHeight(XmTextWidget tw,
272 int x,
273 XmTextBlock block,
274 int from,
275 int to);
276 static Boolean _FontStructPerCharExtents(XmTextWidget tw,
277 char *str,
278 int length,
279 XCharStruct *overall);
280 static Boolean SetXOCOrientation(XmTextWidget tw,
281 XOC om,
282 XOrientation orientation);
283
284 static void CursorPosVisDefault(
285 Widget widget,
286 int offset,
287 XrmValue *value) ;
288
289 /******** End Static Function Declarations ********/
290
291 #define EraseInsertionPoint(tw)\
292 (*tw->text.output->DrawInsertionPoint)(tw,\
293 tw->text.cursor_position, off)
294
295 #define TextDrawInsertionPoint(tw)\
296 (*tw->text.output->DrawInsertionPoint)(tw,\
297 tw->text.cursor_position, on)
298
299 static XmTextWidget posToXYCachedWidget = NULL;
300 static XmTextPosition posToXYCachedPosition;
301 static Position posToXYCachedX;
302 static Position posToXYCachedY;
303
304 static XtResource output_resources[] =
305 {
306 {
307 XmNfontList, XmCFontList, XmRFontList, sizeof(XmFontList),
308 XtOffsetOf(OutputDataRec, fontlist),
309 XmRImmediate, (XtPointer)NULL
310 },
311
312 {
313 XmNrenderTable, XmCRenderTable, XmRRenderTable, sizeof(XmRenderTable),
314 XtOffsetOf(OutputDataRec, rendertable),
315 XmRImmediate, (XtPointer)NULL
316 },
317
318 {
319 XmNwordWrap, XmCWordWrap, XmRBoolean, sizeof(Boolean),
320 XtOffsetOf(struct _OutputDataRec, wordwrap),
321 XmRImmediate, (XtPointer) False
322 },
323
324 {
325 XmNblinkRate, XmCBlinkRate, XmRInt, sizeof(int),
326 XtOffsetOf(struct _OutputDataRec, blinkrate),
327 XmRImmediate, (XtPointer) 500
328 },
329
330 {
331 XmNcolumns, XmCColumns, XmRShort, sizeof(short),
332 XtOffsetOf(struct _OutputDataRec, columns),
333 XmRImmediate, (XtPointer) 0
334 },
335
336 {
337 XmNrows, XmCRows, XmRShort, sizeof(short),
338 XtOffsetOf(struct _OutputDataRec, rows),
339 XmRImmediate, (XtPointer) 0
340 },
341
342 {
343 XmNresizeWidth, XmCResizeWidth, XmRBoolean, sizeof(Boolean),
344 XtOffsetOf(struct _OutputDataRec, resizewidth),
345 XmRImmediate, (XtPointer) False
346 },
347
348 {
349 XmNresizeHeight, XmCResizeHeight, XmRBoolean, sizeof(Boolean),
350 XtOffsetOf(struct _OutputDataRec, resizeheight),
351 XmRImmediate, (XtPointer) False
352 },
353
354 {
355 XmNscrollVertical, XmCScroll, XmRBoolean, sizeof(Boolean),
356 XtOffsetOf(struct _OutputDataRec, scrollvertical),
357 XmRImmediate,(XtPointer) True
358 },
359
360 {
361 XmNscrollHorizontal, XmCScroll, XmRBoolean, sizeof(Boolean),
362 XtOffsetOf(struct _OutputDataRec, scrollhorizontal),
363 XmRImmediate, (XtPointer) True
364 },
365
366 {
367 XmNscrollLeftSide, XmCScrollSide, XmRBoolean, sizeof(Boolean),
368 XtOffsetOf(struct _OutputDataRec, scrollleftside),
369 XmRImmediate,(XtPointer) XmDYNAMIC_BOOL
370 },
371
372 {
373 XmNscrollTopSide, XmCScrollSide, XmRBoolean, sizeof(Boolean),
374 XtOffsetOf(struct _OutputDataRec, scrolltopside),
375 XmRImmediate, (XtPointer) False
376 },
377
378 {
379 XmNcursorPositionVisible, XmCCursorPositionVisible, XmRBoolean,
380 sizeof(Boolean),
381 XtOffsetOf(struct _OutputDataRec, cursor_position_visible),
382 XmRCallProc, (XtPointer) CursorPosVisDefault
383
384 },
385
386 };
387
388 /*********************************************************************
389 *
390 * CursorPosVisDefault
391 *
392 *
393 *********************************************************************/
394 /*ARGSUSED*/
395 static void
CursorPosVisDefault(Widget widget,int offset,XrmValue * value)396 CursorPosVisDefault(
397 Widget widget,
398 int offset, /* unused */
399 XrmValue *value )
400 {
401 static Boolean cursor_pos_vis ;
402 Widget print_shell ;
403
404 value->addr = (XPointer) &cursor_pos_vis;
405
406 print_shell = widget ;
407 while(print_shell && !XmIsPrintShell(print_shell))
408 print_shell = XtParent(print_shell);
409
410 if (print_shell) cursor_pos_vis = False ;
411 else cursor_pos_vis = True ;
412 }
413
414
415 /*ARGSUSED*/
416 void
_XmTextFreeContextData(Widget w,XtPointer clientData,XtPointer callData)417 _XmTextFreeContextData(Widget w, /* unused */
418 XtPointer clientData,
419 XtPointer callData) /* unused */
420 {
421 XmTextContextData ctx_data = (XmTextContextData) clientData;
422 Display *display = DisplayOfScreen(ctx_data->screen);
423 XtPointer data_ptr;
424
425 if (XFindContext(display, (Window) ctx_data->screen,
426 ctx_data->context, (char **) &data_ptr)) {
427
428 if (ctx_data->type != '\0') {
429 if (data_ptr)
430 XtFree((char *) data_ptr);
431 }
432
433 XDeleteContext (display, (Window) ctx_data->screen, ctx_data->context);
434 }
435
436 XtFree ((char *) ctx_data);
437 }
438
439
440 /*****************************************************************************
441 * To make TextOut a true "Object" this function should be a class function. *
442 *****************************************************************************/
443 static void
_XmTextDrawShadow(XmTextWidget tw)444 _XmTextDrawShadow(XmTextWidget tw)
445 {
446 if (XtIsRealized((Widget)tw)) {
447 if (tw->primitive.shadow_thickness > 0)
448 XmeDrawShadows (XtDisplay (tw), XtWindow (tw),
449 tw->primitive.bottom_shadow_GC,
450 tw->primitive.top_shadow_GC,
451 tw->primitive.highlight_thickness,
452 tw->primitive.highlight_thickness,
453 tw->core.width -
454 2 * tw->primitive.highlight_thickness,
455 tw->core.height -
456 2 * tw->primitive.highlight_thickness,
457 tw->primitive.shadow_thickness,
458 XmSHADOW_OUT);
459
460
461 if (tw->primitive.highlighted) {
462 (*(((XmPrimitiveWidgetClass) XtClass((Widget)tw))
463 ->primitive_class.border_highlight))((Widget)tw);
464 } else {
465 (*(((XmPrimitiveWidgetClass) XtClass((Widget)tw))
466 ->primitive_class.border_unhighlight))((Widget)tw);
467 }
468 }
469 }
470
471 /* ARGSUSED */
472 void
_XmTextResetClipOrigin(XmTextWidget tw,XmTextPosition position,int clip_mask_reset)473 _XmTextResetClipOrigin(XmTextWidget tw,
474 XmTextPosition position,
475 #if NeedWidePrototypes
476 int clip_mask_reset)
477 #else
478 Boolean clip_mask_reset)
479 #endif /* NeedWidePrototypes */
480 {
481 OutputData data = tw->text.output->data;
482 int x, y;
483 Position x_pos, y_pos;
484
485 if (!XtIsRealized((Widget)tw)) return;
486
487 if (!PosToXY(tw, tw->text.cursor_position, &x_pos, &y_pos)) return;
488
489 x = (int) x_pos; y = (int) y_pos;
490
491 x -=(data->cursorwidth >> 1) + 1;
492 y = (y + data->font_descent) - data->cursorheight;
493
494 XSetTSOrigin(XtDisplay((Widget)tw), data->imagegc, x, y);
495 }
496
497 static void
SetFullGC(XmTextWidget tw,GC gc)498 SetFullGC(XmTextWidget tw,
499 GC gc)
500 {
501 XRectangle ClipRect;
502
503 ClipRect.x = tw->primitive.highlight_thickness +
504 tw->primitive.shadow_thickness;
505 ClipRect.y = tw->primitive.highlight_thickness +
506 tw->primitive.shadow_thickness;
507 ClipRect.width = tw->core.width - (2 *(tw->primitive.highlight_thickness +
508 tw->primitive.shadow_thickness));
509 ClipRect.height = tw->core.height - (2 *(tw->primitive.highlight_thickness +
510 tw->primitive.shadow_thickness));
511
512 XSetClipRectangles(XtDisplay(tw), gc, 0, 0,
513 &ClipRect, 1, Unsorted);
514 }
515
516 static void
GetRect(XmTextWidget tw,XRectangle * rect)517 GetRect(XmTextWidget tw,
518 XRectangle *rect)
519 {
520 Dimension margin_width = tw->text.margin_width +
521 tw->primitive.shadow_thickness +
522 tw->primitive.highlight_thickness;
523 Dimension margin_height = tw->text.margin_height +
524 tw->primitive.shadow_thickness +
525 tw->primitive.highlight_thickness;
526
527 if (margin_width < tw->core.width)
528 rect->x = margin_width;
529 else
530 rect->x = tw->core.width;
531
532 if (margin_height < tw->core.height)
533 rect->y = margin_height;
534 else
535 rect->y = tw->core.height;
536
537 if ((int) (2 * margin_width) < (int) tw->core.width)
538 rect->width = (int) tw->core.width - (2 * margin_width);
539 else
540 rect->width = 0;
541
542 if ((int) (2 * margin_height) < (int) tw->core.height)
543 rect->height = (int) tw->core.height - (2 * margin_height);
544 else
545 rect->height = 0;
546 }
547
548 static void
SetMarginGC(XmTextWidget tw,GC gc)549 SetMarginGC(XmTextWidget tw,
550 GC gc)
551 {
552 XRectangle ClipRect;
553
554 GetRect(tw, &ClipRect);
555 #ifdef USE_XFT
556 if (tw->text.output->data->use_xft)
557 _XmXftSetClipRectangles(XtDisplay(tw), XtWindow(tw), 0, 0, &ClipRect, 1);
558 #endif
559 XSetClipRectangles(XtDisplay(tw), gc, 0, 0, &ClipRect, 1,
560 Unsorted);
561 }
562
563
564 /*****************************************************************************
565 * To make TextOut a true "Object" this function should be a class function. *
566 *****************************************************************************/
567 /*
568 * Set new clipping rectangle for text widget. This is
569 * done on each focus in event since the text widgets
570 * share the same GC.
571 */
572 void
_XmTextAdjustGC(XmTextWidget tw)573 _XmTextAdjustGC(XmTextWidget tw)
574 {
575 OutputData data = tw->text.output->data;
576 unsigned long valueMask = (GCForeground | GCBackground);
577 XGCValues values;
578
579 if (!XtIsRealized((Widget)tw)) return;
580
581 SetMarginGC(tw, data->gc);
582
583 /* Restore cached text gc to state correct for this instantiation */
584
585 if (data->gc) {
586 values.foreground = tw->primitive.foreground ^ tw->core.background_pixel;
587 values.background = 0;
588 XChangeGC(XtDisplay(tw), data->gc, valueMask, &values);
589 }
590 }
591
592
593 static void
SetNormGC(XmTextWidget tw,GC gc,int change_stipple,int stipple)594 SetNormGC(XmTextWidget tw,
595 GC gc,
596 #if NeedWidePrototypes
597 int change_stipple,
598 int stipple)
599 #else
600 Boolean change_stipple,
601 Boolean stipple)
602 #endif /* NeedWidePrototypes */
603 {
604 unsigned long valueMask = (GCForeground | GCBackground);
605 XGCValues values;
606 OutputData data = tw->text.output->data;
607
608 values.foreground = tw->primitive.foreground;
609 values.background = tw->core.background_pixel;
610 if (change_stipple) {
611 valueMask |= GCFillStyle;
612 if (stipple) {
613 #ifdef FIX_1381
614 /*generally gray insensitive foreground (instead stipple)*/
615 values.foreground = _XmAssignInsensitiveColor((Widget)tw);
616 values.fill_style = FillSolid;
617 #else
618 values.fill_style = FillStippled;
619 valueMask |= GCStipple;
620 values.stipple = data->stipple_tile;
621 #endif
622
623 } else
624 values.fill_style = FillSolid;
625 }
626
627 XChangeGC(XtDisplay(tw), gc, valueMask, &values);
628 }
629
630 #ifdef FIX_1381
631 static void
SetShadowGC(XmTextWidget tf,GC gc)632 SetShadowGC(XmTextWidget tf, GC gc)
633 {
634 unsigned long valueMask = (GCForeground | GCBackground);
635 XGCValues values;
636
637 /*generally light gray insensitive foreground (instead stipple)*/
638 values.foreground = tf->primitive.top_shadow_color;
639 values.background = tf->core.background_pixel;
640
641 values.fill_style = FillSolid;
642
643 XChangeGC(XtDisplay(tf), gc, valueMask, &values);
644 }
645 #endif
646
647
648
649 static void
InvertImageGC(XmTextWidget tw)650 InvertImageGC(XmTextWidget tw)
651 {
652 OutputData data = tw->text.output->data;
653
654 data->have_inverted_image_gc = !data->have_inverted_image_gc;
655 }
656
657 static void
SetInvGC(XmTextWidget tw,GC gc)658 SetInvGC(XmTextWidget tw,
659 GC gc)
660 {
661 unsigned long valueMask = (GCForeground | GCBackground);
662 XGCValues values;
663
664 values.foreground = tw->core.background_pixel;
665 values.background = tw->primitive.foreground;
666
667 XChangeGC(XtDisplay(tw), gc, valueMask, &values);
668 }
669
670
671 static int
_FontStructFindWidth(XmTextWidget tw,int x,XmTextBlock block,int from,int to)672 _FontStructFindWidth(XmTextWidget tw,
673 int x, /* Starting position (needed for tabs) */
674 XmTextBlock block,
675 int from, /* How many bytes in to start measuring */
676 int to) /* How many bytes in to stop measuring */
677 {
678 OutputData data = tw->text.output->data;
679 XFontStruct *font = data->font;
680 char *ptr;
681 unsigned char c;
682 int i, csize;
683 int result = 0;
684
685 if (tw->text.char_size != 1) {
686 int dummy;
687 XCharStruct overall;
688
689 for (i = from, ptr = block->ptr + from; i < to; i +=csize, ptr += csize) {
690 #ifndef NO_MULTIBYTE
691 csize = mblen(ptr, tw->text.char_size);
692 #else
693 csize = *ptr ? 1 : 0;
694 #endif
695 if (csize <= 0) break;
696 c = (unsigned char) *ptr;
697 if (csize == 1) {
698 if (c == '\t') {
699 result += (data->tabwidth -
700 ((x + result - data->leftmargin) % data->tabwidth));
701 } else {
702 if (font->per_char && (c >= font->min_char_or_byte2 &&
703 c <= font->max_char_or_byte2))
704 result += font->per_char[c - font->min_char_or_byte2].width;
705 else
706 result += font->min_bounds.width;
707 }
708 } else {
709 if (_XmIsISO10646(XtDisplay(tw), data->font)) {
710 size_t ucsstr_len = 0;
711 XChar2b *ucsstr = _XmUtf8ToUcs2(ptr, csize, &ucsstr_len);
712 XTextExtents16(data->font, ucsstr, ucsstr_len,
713 &dummy, &dummy, &dummy, &overall);
714 XFree(ucsstr);
715 } else
716 XTextExtents(data->font, ptr, csize, &dummy, &dummy, &dummy,
717 &overall);
718 result += overall.width;
719 }
720 }
721 } else {
722 for (i=from, ptr = block->ptr + from; i<to; i++, ptr++) {
723 c = (unsigned char) *ptr;
724 if (c == '\t')
725 result += (data->tabwidth -
726 ((x + result - data->leftmargin) % data->tabwidth));
727 /* %%% Do something for non-printing? */
728 else {
729 if (font->per_char) {
730 if (c >= font->min_char_or_byte2 && c <= font->max_char_or_byte2)
731 result += font->per_char[c - font->min_char_or_byte2].width;
732 else if (font->default_char >= font->min_char_or_byte2 &&
733 font->default_char <= font->max_char_or_byte2)
734 result += font->per_char[font->default_char -
735 font->min_char_or_byte2].width;
736 else
737 result += font->min_bounds.width;
738 } else
739 result += font->min_bounds.width;
740 }
741 }
742 }
743 return result;
744 }
745
746 static int
FindWidth(XmTextWidget tw,int x,XmTextBlock block,int from,int to)747 FindWidth(XmTextWidget tw,
748 int x, /* Starting position (needed for tabs) */
749 XmTextBlock block,
750 int from, /* How many bytes in to start measuring */
751 int to) /* How many bytes in to stop measuring */
752 {
753 OutputData data = tw->text.output->data;
754 char *ptr;
755 unsigned char c;
756 int result = 0;
757 int tmp;
758 int csize = 1;
759 int i;
760
761 #if USE_XFT
762 if (!data->use_fontset && !data->use_xft)
763 #else
764 if (!data->use_fontset)
765 #endif
766 return _FontStructFindWidth(tw, x, block, from, to);
767
768 if (to > block->length)
769 to = block->length;
770 if (from > to) {
771 tmp = to;
772 to = from;
773 from = tmp;
774 }
775
776 if (to == from || to == 0) return 0;
777
778 if (tw->text.char_size != 1) {
779 for (i = from, ptr = block->ptr + from; i < to; i +=csize, ptr += csize) {
780 #ifndef NO_MULTIBYTE
781 csize = mblen(ptr, tw->text.char_size);
782 #else
783 csize = *ptr ? 1 : 0;
784 #endif
785 if (csize <= 0) break;
786 c = (unsigned char) *ptr;
787 if (csize == 1 && c == '\t')
788 result += (data->tabwidth -
789 ((x + result - data->leftmargin) % data->tabwidth));
790 else
791 #ifdef USE_XFT
792 if (data->use_xft) {
793 XGlyphInfo ext;
794 XftTextExtentsUtf8(XtDisplay(tw), ((XftFont*)data->font),
795 (FcChar8*)ptr, csize, &ext);
796 result += ext.xOff;
797 } else
798 #endif
799 result += XmbTextEscapement((XFontSet)data->font, ptr, csize);
800 }
801
802 } else { /* no need to pay for mblen if we know all chars are 1 byte */
803 for (i = from, ptr = block->ptr + from; i < to; i++, ptr++) {
804 c = (unsigned char) *ptr;
805 if (c == '\t')
806 result += (data->tabwidth -
807 ((x + result - data->leftmargin) % data->tabwidth));
808 else
809 #ifdef USE_XFT
810 if (data->use_xft) {
811 XGlyphInfo ext;
812 XftTextExtentsUtf8(XtDisplay(tw), ((XftFont*)data->font),
813 (FcChar8*)ptr, 1, &ext);
814 result += ext.xOff;
815 } else
816 #endif
817 result += XmbTextEscapement((XFontSet)data->font, ptr, 1);
818 }
819 }
820 return result;
821 }
822
823
824 static int
_FontStructFindHeight(XmTextWidget tw,int y,XmTextBlock block,int from,int to)825 _FontStructFindHeight(XmTextWidget tw,
826 int y, /* Starting position (needed for tabs) */
827 XmTextBlock block,
828 int from, /* How many bytes in to start measuring */
829 int to) /* How many bytes in to stop measuring */
830 {
831 OutputData data = tw->text.output->data;
832 XFontStruct *font = data->font;
833 char *ptr = NULL;
834 unsigned char c;
835 int i = 0, csize = 0;
836 int result = 0;
837 XCharStruct overall;
838
839 if (tw->text.char_size != 1) {
840 for (i = from, ptr = block->ptr + from; i < to; i +=csize, ptr += csize) {
841 csize = mblen(ptr, tw->text.char_size);
842 if (csize <= 0) break;
843 if (csize == 1 && (unsigned char)*ptr == '\t') {
844 result += (data->tabheight -
845 ((y + result - data->topmargin) % data->tabheight));
846 } else {
847 _FontStructPerCharExtents(tw, ptr, csize, &overall);
848 result += overall.ascent + overall.descent;
849 }
850 }
851 } else {
852 for (i=from, ptr = block->ptr + from; i<to; i++, ptr++) {
853 c = (unsigned char) *ptr;
854 if ((unsigned char) *ptr == '\t') {
855 result += (data->tabheight -
856 ((y + result - data->topmargin) % data->tabheight));
857 } else {
858 _FontStructPerCharExtents(tw, ptr, 1, &overall);
859 result += overall.ascent + overall.descent;
860 }
861 }
862 }
863 return result;
864 }
865
866 #ifdef USE_XFT
867 static int
_XftFindHeight(XmTextWidget tw,int y,XmTextBlock block,int from,int to)868 _XftFindHeight(XmTextWidget tw,
869 int y, /* Starting position (needed for tabs) */
870 XmTextBlock block,
871 int from, /* How many bytes in to start measuring */
872 int to) /* How many bytes in to stop measuring */
873 {
874 OutputData data = tw->text.output->data;
875 XftFont *font = (XftFont*)data->font;
876 char *ptr = NULL;
877 unsigned char c;
878 int i = 0, csize = 0;
879 int result = 0;
880 XGlyphInfo ext;
881
882 if (tw->text.char_size != 1) {
883 for (i = from, ptr = block->ptr + from; i < to; i +=csize, ptr += csize) {
884 csize = mblen(ptr, tw->text.char_size);
885 if (csize <= 0) break;
886 if (csize == 1 && (unsigned char)*ptr == '\t') {
887 result += (data->tabheight -
888 ((y + result - data->topmargin) % data->tabheight));
889 } else {
890 XftTextExtentsUtf8(XtDisplay(tw), font, (FcChar8*)ptr, csize, &ext);
891 result += ext.yOff;
892 }
893 }
894 } else {
895 for (i=from, ptr = block->ptr + from; i<to; i++, ptr++) {
896 c = (unsigned char) *ptr;
897 if ((unsigned char) *ptr == '\t') {
898 result += (data->tabheight -
899 ((y + result - data->topmargin) % data->tabheight));
900 } else {
901 XftTextExtentsUtf8(XtDisplay(tw), font, (FcChar8*)ptr, 1, &ext);
902 result += ext.yOff;
903 }
904 }
905 }
906 return result;
907 }
908 #endif
909
910 static int
FindHeight(XmTextWidget tw,int y,XmTextBlock block,int from,int to)911 FindHeight(XmTextWidget tw,
912 int y, /* Starting position (needed for tabs) */
913 XmTextBlock block,
914 int from, /* How many bytes in to start measuring */
915 int to) /* How many bytes in to stop measuring */
916 {
917 OutputData data = tw->text.output->data;
918 char *ptr = NULL;
919 unsigned char c;
920 int result = 0;
921 int tmp = 0;
922 int csize = 1;
923 int i = 0;
924 XOrientation orient;
925
926 #ifdef USE_XFT
927 if (data->use_xft)
928 return _XftFindHeight(tw, y, block, from, to);
929 #endif
930
931 if (!data->use_fontset)
932 return _FontStructFindHeight(tw, y, block, from, to);
933
934 if (to > block->length)
935 to = block->length;
936 if (from > to) {
937 tmp = to;
938 to = from;
939 from = tmp;
940 }
941
942 if (to == from || to == 0) return 0;
943
944 if(data->use_fontset == True) {
945 XGetOCValues((XOC)data->font, XNOrientation, &orient, NULL);
946 SetXOCOrientation(tw, (XOC)data->font, XOMOrientation_TTB_RTL);
947 }
948 if (tw->text.char_size != 1) {
949 for (i = from, ptr = block->ptr + from; i < to; i +=csize, ptr += csize) {
950 csize = mblen(ptr, tw->text.char_size);
951 if (csize <= 0) break;
952 c = (unsigned char) *ptr;
953 if (csize == 1 && c == '\t')
954 result += (data->tabheight -
955 ((y + result - data->topmargin) % data->tabheight));
956 else
957 result += XmbTextEscapement((XFontSet)data->font, ptr, csize);
958 }
959
960 } else { /* no need to pay for mblen if we know all chars are 1 byte */
961 for (i = from, ptr = block->ptr + from; i < to; i++, ptr++) {
962 c = (unsigned char) *ptr;
963 if (c == '\t')
964 result += (data->tabheight -
965 ((y + result - data->topmargin) % data->tabheight));
966 else
967 result += XmbTextEscapement((XFontSet)data->font, ptr, 1);
968 }
969 }
970 if(data->use_fontset == True) {
971 SetXOCOrientation(tw, (XOC)data->font, orient);
972 }
973 return result;
974 }
975
976
977 /* Semi-public routines. */
978
979 static XmTextPosition
XYToPos(XmTextWidget tw,int x,int y)980 XYToPos(XmTextWidget tw,
981 #if NeedWidePrototypes
982 int x,
983 int y)
984 #else
985 Position x,
986 Position y)
987 #endif /* NeedWidePrototypes */
988 {
989 OutputData data = tw->text.output->data;
990 LineTableExtra extra = (LineTableExtra)NULL;
991 int i = 0, width = 0, lastwidth = 0, length = 0;
992 int height = 0, lastheight = 0;
993 int num_chars = 0;
994 int num_bytes = 0;
995 LineNum line = 0;
996 XmTextPosition start, end, laststart;
997 XmTextBlockRec block;
998 int delta = 0;
999
1000 start = end = laststart = 0;
1001
1002 if(XmDirectionMatch(XmPrim_layout_direction(tw),
1003 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT)) {
1004 y += data->voffset;
1005 /* take care of negative x case */
1006 if (data->linewidth) {
1007 int rightedge = tw->text.inner_widget->core.width - data->rightmargin;
1008 if (x > rightedge) {
1009 delta = ((int)(rightedge - x - 1)/ (int) data->linewidth) + 1;
1010 x = rightedge;
1011 }
1012 line = (rightedge - x) / (int)(data->linewidth);
1013 }
1014 if (line > _XmTextNumLines(tw)) line = _XmTextNumLines(tw);
1015 _XmTextLineInfo(tw, line, &start, &extra);
1016 if (start == PASTENDPOS)
1017 return (*tw->text.source->Scan)(tw->text.source, 0,
1018 XmSELECT_ALL, XmsdRight, 1, False);
1019 _XmTextLineInfo(tw, line+1, &end, &extra);
1020 end = (*tw->text.source->Scan)(tw->text.source, end,
1021 XmSELECT_POSITION, XmsdLeft, 1, True);
1022 height = lastheight = data->topmargin;
1023 if (start >= end && !delta) return start;
1024
1025 /* if original y was negative, we need to find new laststart */
1026 if (delta && start > 0) {
1027 end = (*tw->text.source->Scan)(tw->text.source, start,
1028 XmSELECT_POSITION, XmsdLeft, 1, True);
1029 start = _XmTextFindScroll(tw, start, delta);
1030 }
1031
1032 do {
1033 laststart = start;
1034 start = (*tw->text.source->ReadSource)(tw->text.source, start,
1035 end, &block);
1036 length = block.length;
1037 if ((int)tw->text.char_size > 1) {
1038 for (i = num_chars = 0, num_bytes = mblen(block.ptr,
1039 (int)tw->text.char_size);
1040 i < length && height < y && num_bytes >= 0;
1041 i += num_bytes, num_chars++,
1042 num_bytes = mblen(&block.ptr[i], (int)tw->text.char_size)) {
1043 lastheight = height;
1044 height += FindHeight(tw, height, &block, i, i + num_bytes);
1045 }
1046 i = num_chars;
1047 } else {
1048 for (i=0; i<length && height < y; i++) {
1049 lastheight = height;
1050 height += FindHeight(tw, height, &block, i, i+1);
1051 }
1052 }
1053 } while (height < y && start < end && laststart != end);
1054
1055 if (abs(lastheight - y) < abs(height - y)) i--;
1056 } else {
1057
1058 x += data->hoffset;
1059 y -= data->topmargin;
1060 /* take care of negative y case */
1061 if (data->lineheight) {
1062 if (y < 0) {
1063 delta = ((int)(y + 1)/ (int) data->lineheight) - 1;
1064 y = 0;
1065 }
1066 line = y / (int) data->lineheight;
1067 }
1068 if (line > _XmTextNumLines(tw)) line = _XmTextNumLines(tw);
1069 _XmTextLineInfo(tw, line, &start, &extra);
1070 if (start == PASTENDPOS)
1071 return (*tw->text.source->Scan)(tw->text.source, 0,
1072 XmSELECT_ALL, XmsdRight, 1, False);
1073 _XmTextLineInfo(tw, line+1, &end, &extra);
1074 end = (*tw->text.source->Scan)(tw->text.source, end,
1075 XmSELECT_POSITION, XmsdLeft, 1, True);
1076 width = lastwidth = data->leftmargin;
1077 if (start >= end && !delta) return start;
1078
1079 /* if original y was negative, we need to find new laststart */
1080 if (delta && start > 0) {
1081 end = (*tw->text.source->Scan)(tw->text.source, start,
1082 XmSELECT_POSITION, XmsdLeft, 1, True);
1083 start = _XmTextFindScroll(tw, start, delta);
1084 }
1085
1086 do {
1087 laststart = start;
1088 start = (*tw->text.source->ReadSource)(tw->text.source, start,
1089 end, &block);
1090 length = block.length;
1091 if ((int)tw->text.char_size > 1) {
1092 for (i = num_chars = 0,
1093 #ifndef NO_MULTIBYTE
1094 num_bytes = mblen(block.ptr, (int)tw->text.char_size);
1095 #else
1096 num_bytes = *block.ptr ? 1 : 0;
1097 #endif
1098 i < length && width < x && num_bytes >= 0;
1099 i += num_bytes, num_chars++,
1100 #ifndef NO_MULTIBYTE
1101 num_bytes = mblen(&block.ptr[i], (int)tw->text.char_size)) {
1102 #else
1103 num_bytes = block.ptr[i] ? 1 : 0) {
1104 #endif
1105 lastwidth = width;
1106 width += FindWidth(tw, width, &block, i, i + num_bytes);
1107 }
1108 i = num_chars;
1109 } else {
1110 for (i=0; i<length && width < x; i++) {
1111 lastwidth = width;
1112 width += FindWidth(tw, width, &block, i, i+1);
1113 }
1114 }
1115 } while (width < x && start < end && laststart != end);
1116
1117 if (abs(lastwidth - x) < abs(width - x)) i--;
1118 }
1119 return (*tw->text.source->Scan)(tw->text.source, laststart,
1120 XmSELECT_POSITION, (i < 0) ?
1121 XmsdLeft : XmsdRight, abs(i), True);
1122 }
1123
1124 /*****************************************************************************
1125 * To make TextOut a true "Object" this function should be a class function. *
1126 *****************************************************************************/
1127 Boolean
1128 _XmTextShouldWordWrap(XmTextWidget tw)
1129 {
1130 OutputData data = tw->text.output->data;
1131 return (ShouldWordWrap(data, tw));
1132 }
1133
1134
1135 /*****************************************************************************
1136 * To make TextOut a true "Object" this function should be a class function. *
1137 *****************************************************************************/
1138 Boolean
1139 _XmTextScrollable(XmTextWidget tw)
1140 {
1141 OutputData data = tw->text.output->data;
1142 if(XmDirectionMatch(XmPrim_layout_direction(tw),
1143 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT))
1144 return (data->scrollhorizontal && XmIsScrolledWindow(XtParent(tw)));
1145 else
1146 return (data->scrollvertical && XmIsScrolledWindow(XtParent(tw)));
1147 }
1148
1149 static Boolean
1150 PosToXY(XmTextWidget tw,
1151 XmTextPosition position,
1152 Position *x,
1153 Position *y)
1154 {
1155 OutputData data = tw->text.output->data;
1156 LineNum line;
1157 XmTextPosition linestart;
1158 LineTableExtra extra;
1159 XmTextBlockRec block;
1160 Position local_x, local_y;
1161
1162 if(XmDirectionMatch(XmPrim_layout_direction(tw),
1163 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT)) {
1164 _XmProcessLock();
1165 if (tw == posToXYCachedWidget && position == posToXYCachedPosition) {
1166 *x = posToXYCachedX;
1167 *y = posToXYCachedY;
1168 _XmProcessUnlock();
1169 return True;
1170 }
1171 _XmProcessUnlock();
1172
1173 line = _XmTextPosToLine(tw, position);
1174 if (line == NOLINE || line >= data->number_lines) return False;
1175 local_y = data->topmargin;
1176 local_x = tw->text.inner_widget->core.width -
1177 (data->rightmargin + line * data->linewidth +
1178 data->linewidth * 0.5);
1179 _XmTextLineInfo(tw, line, &linestart, &extra);
1180 while (linestart < position) {
1181 linestart = (*tw->text.source->ReadSource)(tw->text.source,
1182 linestart, position,
1183 &block);
1184 local_y += FindHeight(tw, local_y, &block, 0, block.length);
1185 }
1186 local_y -= data->voffset;
1187 } else {
1188
1189 _XmProcessLock();
1190 if (tw == posToXYCachedWidget && position == posToXYCachedPosition) {
1191 *x = posToXYCachedX;
1192 *y = posToXYCachedY;
1193 _XmProcessUnlock();
1194 return True;
1195 }
1196 _XmProcessUnlock();
1197
1198 line = _XmTextPosToLine(tw, position);
1199 if (line == NOLINE || line >= data->number_lines) return False;
1200 local_y = data->topmargin + line * data->lineheight + data->font_ascent;
1201 local_x = data->leftmargin;
1202 _XmTextLineInfo(tw, line, &linestart, &extra);
1203 while (linestart < position) {
1204 linestart = (*tw->text.source->ReadSource)(tw->text.source,
1205 linestart, position,
1206 &block);
1207 local_x += FindWidth(tw, local_x, &block, 0, block.length);
1208 }
1209 local_x -= data->hoffset;
1210 }
1211 _XmProcessLock();
1212 posToXYCachedWidget = tw;
1213 posToXYCachedPosition = position;
1214 posToXYCachedX = local_x;
1215 posToXYCachedY = local_y;
1216 *x = local_x;
1217 *y = local_y;
1218 _XmProcessUnlock();
1219 return True;
1220 }
1221
1222 /*****************************************************************************
1223 * To make TextOut a true "Object" this function should be a class function. *
1224 *****************************************************************************/
1225 XmTextPosition
1226 _XmTextFindLineEnd(XmTextWidget tw,
1227 XmTextPosition position,
1228 LineTableExtra *extra)
1229 {
1230 OutputData data = tw->text.output->data;
1231 XmTextPosition lastChar, lineEnd, nextLeft, nextBreak, lastBreak, oldpos;
1232 XmTextPosition startpos = 0;
1233 XmTextBlockRec block;
1234 int x, lastX, goalwidth, length, i;
1235 int y, lastY, goalheight;
1236 int num_bytes = 0;
1237
1238 lastChar = (*tw->text.source->Scan)(tw->text.source, position,
1239 XmSELECT_LINE, XmsdRight, 1, False);
1240 lastBreak = startpos = position;
1241
1242 if(XmDirectionMatch(XmPrim_layout_direction(tw),
1243 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT)) {
1244 y = lastY = data->topmargin;
1245 goalheight = tw->text.inner_widget->core.height - data->bottommargin;
1246 while (position < lastChar) {
1247 nextLeft = (*tw->text.source->Scan)(tw->text.source, position,
1248 XmSELECT_WHITESPACE, XmsdRight,
1249 1, False);
1250 nextBreak = (*tw->text.source->Scan)(tw->text.source, nextLeft,
1251 XmSELECT_WHITESPACE, XmsdRight,
1252 1, True);
1253 while (position < nextLeft) {
1254 position = (*tw->text.source->ReadSource)(tw->text.source,
1255 position, nextLeft,
1256 &block);
1257 length = block.length;
1258 y += FindHeight(tw, y, &block, 0, block.length);
1259 if (y > goalheight) {
1260 if (lastBreak > startpos) {
1261 if (lastY <= goalheight) /* word wrap is being performed */
1262 {
1263 return lastBreak;
1264 }
1265 y = lastY;
1266 oldpos = position = lastBreak;
1267 while (y > goalheight && position > startpos) {
1268 oldpos = position;
1269 position = (*tw->text.source->Scan)
1270 (tw->text.source, position, XmSELECT_POSITION,
1271 XmsdLeft, 1, True);
1272 (void) (*tw->text.source->ReadSource)
1273 (tw->text.source, position, oldpos, &block);
1274 num_bytes = mblen(block.ptr,
1275 (int)tw->text.char_size);
1276 /* Pitiful error handling, but what else can you do? */
1277 if (num_bytes < 0) num_bytes = 1;
1278 y -= FindHeight(tw, y, &block, 0, num_bytes);
1279 }
1280 if (extra) {
1281 *extra = (LineTableExtra)
1282 XtMalloc((unsigned) sizeof(LineTableExtraRec));
1283 (*extra)->wrappedbychar = True;
1284 (*extra)->width = 0;
1285 }
1286 return oldpos; /* Allows one whitespace char to appear */
1287 /* partially off the edge. */
1288 }
1289 if (extra) {
1290 *extra = (LineTableExtra)
1291 XtMalloc((unsigned) sizeof(LineTableExtraRec));
1292 (*extra)->wrappedbychar = True;
1293 (*extra)->width = 0;
1294 }
1295 if ((int)tw->text.char_size == 1) {
1296 for (i=length - 1; i>=0 && y > goalheight; i--) {
1297 y -= FindHeight(tw, y, &block, i, i + 1);
1298 position =
1299 (*tw->text.source->Scan)(tw->text.source,
1300 position,
1301 XmSELECT_POSITION,
1302 XmsdLeft, 1, True);
1303 }
1304 return position;
1305 } else {
1306 char tmp_cache[200];
1307 wchar_t * tmp_wc;
1308 Cardinal tmp_wc_size;
1309 char tmp_char[MB_LEN_MAX];
1310 int num_chars = 0;
1311 XmTextBlockRec mini_block;
1312
1313 /* If 16-bit data, convert the char* to wchar_t*... this
1314 * allows us to scan backwards through the text one
1315 * character at a time. Without wchar_t, we would have
1316 * to continually scan from the start of the string to
1317 * find the byte offset of character n-1.
1318 */
1319 mini_block.ptr = tmp_char;
1320 num_chars = _XmTextCountCharacters(block.ptr, block.length);
1321 tmp_wc_size = (num_chars + 1) * sizeof(wchar_t);
1322 tmp_wc = (wchar_t *) XmStackAlloc(tmp_wc_size, tmp_cache);
1323 num_chars = mbstowcs(tmp_wc, block.ptr, num_chars);
1324 if (num_chars > 0) {
1325 for (i = num_chars - 1; i >= 0 && y > goalheight; i--) {
1326 mini_block.length = wctomb(mini_block.ptr, tmp_wc[i]);
1327 if (mini_block.length < 0) mini_block.length = 0;
1328 y -= FindHeight(tw, y, &mini_block,
1329 0, mini_block.length);
1330 position =
1331 (*tw->text.source->Scan)(tw->text.source,
1332 position,
1333 XmSELECT_POSITION,
1334 XmsdLeft, 1, True);
1335 }
1336 }
1337 XmStackFree((char*)tmp_wc, tmp_cache);
1338 } /* end multi-byte handling */
1339 return position;
1340 }
1341 }
1342 while (position < nextBreak) {
1343 position = (*tw->text.source->ReadSource)(tw->text.source,
1344 position, nextBreak,
1345 &block);
1346 length = block.length;
1347 y += FindHeight(tw, y, &block, 0, block.length);
1348 }
1349 lastBreak = nextBreak;
1350 lastY = y;
1351 }
1352 } else {
1353
1354 x = lastX = data->leftmargin;
1355 goalwidth = tw->text.inner_widget->core.width - data->rightmargin;
1356 while (position < lastChar) {
1357 nextLeft = (*tw->text.source->Scan)(tw->text.source, position,
1358 XmSELECT_WHITESPACE, XmsdRight,
1359 1, False);
1360 nextBreak = (*tw->text.source->Scan)(tw->text.source, nextLeft,
1361 XmSELECT_WHITESPACE, XmsdRight,
1362 1, True);
1363 while ((position < nextLeft) ||
1364 (nextBreak == lastChar && position < nextBreak)) {
1365 if (position < nextLeft)
1366 position = (*tw->text.source->ReadSource)(tw->text.source,
1367 position, nextLeft,
1368 &block);
1369 else
1370 position = (*tw->text.source->ReadSource)(tw->text.source,
1371 position, nextBreak,
1372 &block);
1373 length = block.length;
1374 x += FindWidth(tw, x, &block, 0, block.length);
1375 if (x > goalwidth) {
1376 if (lastBreak > startpos) {
1377 if (lastX <= goalwidth) /* word wrap is being performed */
1378 {
1379 return lastBreak;
1380 }
1381 x = lastX;
1382 oldpos = position = lastBreak;
1383 while (x > goalwidth && position > startpos) {
1384 oldpos = position;
1385 position = (*tw->text.source->Scan)
1386 (tw->text.source, position, XmSELECT_POSITION,
1387 XmsdLeft, 1, True);
1388 (void) (*tw->text.source->ReadSource)
1389 (tw->text.source, position, oldpos, &block);
1390 #ifndef NO_MULTIBYTE
1391 num_bytes = mblen(block.ptr, (int)tw->text.char_size);
1392 #else
1393 num_bytes = *block.ptr ? 1 : 0;
1394 #endif
1395 /* Pitiful error handling, but what else can you do? */
1396 if (num_bytes < 0) num_bytes = 1;
1397 x -= FindWidth(tw, x, &block, 0, num_bytes);
1398 }
1399 if (extra) {
1400 *extra = (LineTableExtra)
1401 XtMalloc((unsigned) sizeof(LineTableExtraRec));
1402 (*extra)->wrappedbychar = True;
1403 (*extra)->width = 0;
1404 }
1405 return oldpos; /* Allows one whitespace char to appear */
1406 /* partially off the edge. */
1407 }
1408 if (extra) {
1409 *extra = (LineTableExtra)
1410 XtMalloc((unsigned) sizeof(LineTableExtraRec));
1411 (*extra)->wrappedbychar = True;
1412 (*extra)->width = 0;
1413 }
1414 if ((int)tw->text.char_size == 1) {
1415 for (i=length - 1; i>=0 && x > goalwidth; i--) {
1416 x -= FindWidth(tw, x, &block, i, i + 1);
1417 position =
1418 (*tw->text.source->Scan)(tw->text.source,
1419 position,
1420 XmSELECT_POSITION,
1421 XmsdLeft, 1, True);
1422 }
1423 return position;
1424 } else {
1425 char tmp_cache[200];
1426 wchar_t * tmp_wc;
1427 Cardinal tmp_wc_size;
1428 char tmp_char[MB_LEN_MAX];
1429 int num_chars = 0;
1430 XmTextBlockRec mini_block;
1431
1432 /* If 16-bit data, convert the char* to wchar_t*... this
1433 * allows us to scan backwards through the text one
1434 * character at a time. Without wchar_t, we would have
1435 * to continually scan from the start of the string to
1436 * find the byte offset of character n-1.
1437 */
1438 mini_block.ptr = tmp_char;
1439 num_chars = _XmTextCountCharacters(block.ptr, block.length);
1440 tmp_wc_size = (num_chars + 1) * sizeof(wchar_t);
1441 tmp_wc = (wchar_t *) XmStackAlloc(tmp_wc_size, tmp_cache);
1442 num_chars = mbstowcs(tmp_wc, block.ptr, num_chars);
1443 if (num_chars > 0) {
1444 for (i = num_chars - 1; i >= 0 && x > goalwidth; i--) {
1445 mini_block.length = wctomb(mini_block.ptr, tmp_wc[i]);
1446 if (mini_block.length < 0) mini_block.length = 0;
1447 x -= FindWidth(tw, x, &mini_block,
1448 0, mini_block.length);
1449 position =
1450 (*tw->text.source->Scan)(tw->text.source,
1451 position,
1452 XmSELECT_POSITION,
1453 XmsdLeft, 1, True);
1454 }
1455 }
1456 XmStackFree((char*)tmp_wc, tmp_cache);
1457 } /* end multi-byte handling */
1458 return position;
1459 }
1460 }
1461 while (position < nextBreak) {
1462 position = (*tw->text.source->ReadSource)(tw->text.source,
1463 position, nextBreak,
1464 &block);
1465 length = block.length;
1466 x += FindWidth(tw, x, &block, 0, block.length);
1467 }
1468 lastBreak = nextBreak;
1469 lastX = x;
1470 }
1471 }
1472 lineEnd = (*tw->text.source->Scan)(tw->text.source, lastChar,
1473 XmSELECT_LINE, XmsdRight, 1, True);
1474 if (lineEnd != lastChar) return lineEnd;
1475 else return PASTENDPOS;
1476 }
1477
1478 static XtGeometryResult
1479 TryResize(XmTextWidget tw,
1480 #if NeedWidePrototypes
1481 int width,
1482 int height)
1483 #else
1484 Dimension width,
1485 Dimension height)
1486 #endif /* NeedWidePrototypes */
1487 {
1488 XtGeometryResult result;
1489 Dimension origwidth = tw->text.inner_widget->core.width;
1490 Dimension origheight = tw->text.inner_widget->core.height;
1491 XtWidgetGeometry request, reply;
1492
1493 if (origwidth != width) {
1494 request.request_mode = CWWidth;
1495 request.width = width;
1496 } else
1497 request.request_mode = (XtGeometryMask)0;
1498
1499 if (origheight != height) {
1500 request.request_mode |= CWHeight;
1501 request.height = height;
1502 }
1503
1504 /* requesting current size */
1505 if (request.request_mode == (XtGeometryMask)0) return XtGeometryNo;
1506
1507 result = XtMakeGeometryRequest(tw->text.inner_widget, &request, &reply);
1508
1509 if (result == XtGeometryAlmost) {
1510 if (request.request_mode & CWWidth)
1511 request.width = reply.width;
1512 if (request.request_mode & CWHeight)
1513 request.height = reply.height;
1514
1515 result = XtMakeGeometryRequest(tw->text.inner_widget, &request,
1516 &reply);
1517 if (result == XtGeometryYes) {
1518 result = XtGeometryNo;
1519 if (((request.request_mode & CWWidth) && reply.width != origwidth) ||
1520 ((request.request_mode & CWHeight) && reply.height != origheight))
1521 result = XtGeometryYes;
1522 }
1523 return result;
1524 }
1525
1526
1527 if (result == XtGeometryYes) {
1528 /* Some brain damaged geometry managers return XtGeometryYes and
1529 don't change the widget's size. */
1530 if (((request.request_mode & CWWidth) &&
1531 tw->text.inner_widget->core.width != width) ||
1532 ((request.request_mode & CWHeight) &&
1533 tw->text.inner_widget->core.height != height) ||
1534 ((request.request_mode == (CWWidth & CWHeight)) &&
1535 (tw->text.inner_widget->core.width == origwidth &&
1536 tw->text.inner_widget->core.height == origheight)))
1537 result = XtGeometryNo;
1538 }
1539 return result;
1540 }
1541
1542 void
1543 _XmRedisplayHBar(XmTextWidget tw)
1544 {
1545 OutputData data = tw->text.output->data;
1546 int value, sliderSize, maximum, new_sliderSize;
1547 XmNavigatorDataRec nav_data;
1548 XmNavigatorTrait nav_trait;
1549
1550 if (!(data->scrollhorizontal && XmIsScrolledWindow(XtParent(tw))) ||
1551 data->suspend_hoffset || tw->text.disable_depth != 0 ||
1552 tw->core.being_destroyed || data->hbar == NULL)
1553 return;
1554
1555 ChangeHOffset(tw, data->hoffset, False); /* Makes sure that hoffset is
1556 still reasonable. */
1557
1558 new_sliderSize = tw->text.inner_widget->core.width
1559 - (data->leftmargin + data->rightmargin);
1560
1561 if (new_sliderSize < 1) new_sliderSize = 1;
1562 if (new_sliderSize > data->scrollwidth) new_sliderSize = data->scrollwidth;
1563
1564 nav_data.valueMask = NavValue|NavSliderSize|NavMaximum;
1565 nav_trait = (XmNavigatorTrait)
1566 XmeTraitGet((XtPointer)XtClass(data->hbar), XmQTnavigator);
1567 if (nav_trait) {
1568 nav_trait->getValue(data->hbar, &nav_data);
1569 maximum = nav_data.maximum.x;
1570 sliderSize = nav_data.slider_size.x;
1571 value = nav_data.value.x;
1572
1573 } else
1574 return;
1575
1576 if ((maximum != data->scrollwidth ||
1577 value != data->hoffset ||
1578 sliderSize != new_sliderSize) &&
1579 !(sliderSize == maximum && new_sliderSize == data->scrollwidth)) {
1580
1581 data->ignorehbar = True;
1582
1583 nav_data.value.x = data->hoffset;
1584 nav_data.minimum.x = 0;
1585 nav_data.maximum.x = data->scrollwidth;
1586 nav_data.slider_size.x = new_sliderSize;
1587 nav_data.increment.x = 0; /* increments stay at current values */
1588 nav_data.page_increment.x = new_sliderSize;
1589
1590 nav_data.dimMask = NavigDimensionX;
1591 nav_data.valueMask = NavValue|NavMinimum|NavMaximum|
1592 NavSliderSize|NavIncrement|NavPageIncrement;
1593 _XmSFUpdateNavigatorsValue(XtParent((Widget)tw), &nav_data, True);
1594
1595 data->ignorehbar = False;
1596 }
1597 }
1598
1599
1600 void
1601 _XmRedisplayVBar(XmTextWidget tw)
1602 {
1603 OutputData data = tw->text.output->data;
1604 int value = 0, sliderSize = 0, maximum = 0, new_sliderSize = 0;
1605 XmNavigatorDataRec nav_data;
1606 XmNavigatorTrait nav_trait;
1607
1608 if (!(data->scrollvertical && XmIsScrolledWindow(XtParent(tw))) ||
1609 data->suspend_voffset || tw->text.disable_depth != 0 ||
1610 tw->core.being_destroyed || data->vbar == NULL)
1611 return;
1612
1613 ChangeVOffset(tw, data->voffset, False); /* Makes sure that voffset is
1614 still reasonable. */
1615
1616 new_sliderSize = tw->text.inner_widget->core.height
1617 - (data->topmargin + data->bottommargin);
1618
1619 if (new_sliderSize < 1) new_sliderSize = 1;
1620 if (new_sliderSize > data->scrollheight) new_sliderSize = data->scrollheight;
1621
1622 nav_data.valueMask = NavValue|NavSliderSize|NavMaximum;
1623 nav_trait = (XmNavigatorTrait)
1624 XmeTraitGet((XtPointer)XtClass(data->vbar), XmQTnavigator);
1625 if (nav_trait) {
1626 nav_trait->getValue(data->vbar, &nav_data);
1627 maximum = nav_data.maximum.y;
1628 sliderSize = nav_data.slider_size.y;
1629 value = nav_data.value.y;
1630
1631 } else
1632 return;
1633
1634 if ((maximum != data->scrollheight ||
1635 value != data->voffset ||
1636 sliderSize != new_sliderSize) &&
1637 !(sliderSize == maximum && new_sliderSize == data->scrollheight)) {
1638
1639 data->ignorehbar = True;
1640
1641 nav_data.value.y = data->voffset;
1642 nav_data.minimum.y = 0;
1643 nav_data.maximum.y = data->scrollheight;
1644 nav_data.slider_size.y = new_sliderSize;
1645 nav_data.increment.y = 0; /* increments stay at current values */
1646 nav_data.page_increment.y = new_sliderSize;
1647
1648 nav_data.dimMask = NavigDimensionY;
1649 nav_data.valueMask = NavValue|NavMinimum|NavMaximum|
1650 NavSliderSize|NavIncrement|NavPageIncrement;
1651 _XmSFUpdateNavigatorsValue(XtParent((Widget)tw), &nav_data, True);
1652
1653 data->ignorehbar = False;
1654 }
1655 }
1656
1657
1658 static int
1659 CountLines(XmTextWidget tw,
1660 XmTextPosition start,
1661 XmTextPosition end)
1662 {
1663 register XmTextLineTable line_table;
1664 register unsigned int t_index;
1665 register unsigned int max_index = 0;
1666 int numlines = 0;
1667
1668 line_table = tw->text.line_table;
1669 t_index = tw->text.table_index;
1670
1671 max_index = tw->text.total_lines - 1;
1672
1673 /* look forward to find the current record */
1674 if (line_table[t_index].start_pos < (unsigned int) start) {
1675 while (t_index <= max_index &&
1676 line_table[t_index].start_pos < (unsigned int) start) t_index++;
1677 } else {
1678 /* look backward to find the current record */
1679 while (t_index &&
1680 line_table[t_index].start_pos > (unsigned int) start) t_index--;
1681 }
1682
1683 while(line_table[t_index].start_pos < (unsigned int) end) {
1684 t_index++;
1685 numlines++;
1686 }
1687
1688 return (numlines);
1689 }
1690
1691 void
1692 _XmChangeVSB(XmTextWidget tw)
1693 {
1694 OutputData data = tw->text.output->data;
1695 int local_total;
1696 int new_size;
1697 XmNavigatorDataRec nav_data;
1698
1699 if (tw->text.disable_depth != 0) return;
1700 if (tw->core.being_destroyed) return;
1701
1702 if (!tw->text.top_character) tw->text.top_line = 0;
1703 else
1704 tw->text.top_line = _XmTextGetTableIndex(tw, tw->text.top_character);
1705
1706 if (tw->text.top_line > tw->text.total_lines)
1707 tw->text.top_line = tw->text.total_lines;
1708
1709 if (tw->text.top_line + tw->text.number_lines >
1710 tw->text.total_lines)
1711 local_total = tw->text.top_line + tw->text.number_lines;
1712 else
1713 local_total = tw->text.total_lines;
1714
1715 if (data->vbar) {
1716
1717 if (local_total >= tw->text.number_lines)
1718 new_size = tw->text.number_lines;
1719 else
1720 new_size = local_total;
1721 if (new_size + tw->text.top_line > local_total)
1722 new_size = local_total - tw->text.top_line;
1723
1724 data->ignorevbar = True;
1725
1726 nav_data.value.y = tw->text.top_line;
1727 nav_data.minimum.y = 0;
1728 nav_data.maximum.y = local_total;
1729 nav_data.slider_size.y = new_size;
1730 nav_data.increment.y = 0; /* increments stay at current values */
1731 nav_data.page_increment.y = (data->number_lines > 1)?
1732 (data->number_lines - 1): 1;
1733
1734 nav_data.dimMask = NavigDimensionY;
1735 nav_data.valueMask = NavValue|NavMinimum|NavMaximum|
1736 NavSliderSize|NavIncrement|NavPageIncrement;
1737 _XmSFUpdateNavigatorsValue(XtParent((Widget)tw), &nav_data, True);
1738
1739 data->ignorevbar = False;
1740 }
1741 }
1742
1743
1744 void
1745 _XmChangeHSB(XmTextWidget tw)
1746 {
1747 OutputData data = tw->text.output->data;
1748 int local_total = 0;
1749 int new_size = 0;
1750 XmNavigatorDataRec nav_data;
1751 int offset = 0;
1752
1753 if (tw->text.disable_depth != 0) return;
1754 if (tw->core.being_destroyed) return;
1755
1756 if (!tw->text.top_character) tw->text.top_line = 0;
1757 else
1758 tw->text.top_line = _XmTextGetTableIndex(tw, tw->text.top_character);
1759
1760 if (tw->text.top_line > tw->text.total_lines)
1761 tw->text.top_line = tw->text.total_lines;
1762
1763 if (tw->text.top_line + tw->text.number_lines >
1764 tw->text.total_lines)
1765 local_total = tw->text.top_line + tw->text.number_lines;
1766 else
1767 local_total = tw->text.total_lines;
1768
1769 if (data->hbar) {
1770
1771 if (local_total >= tw->text.number_lines)
1772 new_size = tw->text.number_lines;
1773 else
1774 new_size = local_total;
1775
1776 if (new_size + tw->text.top_line > local_total)
1777 new_size = local_total - tw->text.top_line;
1778
1779 data->ignorehbar = True;
1780
1781 offset = local_total - (tw->text.number_lines + tw->text.top_line);
1782 nav_data.value.x = tw->text.top_line;
1783 nav_data.minimum.x = 0;
1784 nav_data.maximum.x = local_total;
1785 nav_data.slider_size.x = new_size;
1786 nav_data.increment.x = 0; /* increments stay at current values */
1787 nav_data.page_increment.x = (data->number_lines > 1)?
1788 (data->number_lines - 1): 1;
1789
1790 nav_data.dimMask = NavigDimensionX;
1791 nav_data.valueMask = NavValue|NavMinimum|NavMaximum|
1792 NavSliderSize|NavIncrement|NavPageIncrement;
1793 _XmSFUpdateNavigatorsValue(XtParent((Widget)tw), &nav_data, True);
1794
1795 data->ignorehbar = False;
1796 }
1797 }
1798
1799
1800 static void
1801 TextFindNewWidth(XmTextWidget tw,
1802 Dimension *widthRtn)
1803 {
1804 OutputData data = tw->text.output->data;
1805 XmTextPosition start;
1806 Dimension newwidth;
1807
1808 newwidth = 0;
1809
1810 if(XmDirectionMatch(XmPrim_layout_direction(tw),
1811 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT)) {
1812 XmTextPosition first_position = 0;
1813 LineTableExtra extra;
1814
1815 newwidth = (int)(tw->text.total_lines * data->linewidth) +
1816 data->leftmargin + data->rightmargin;
1817
1818 _XmTextLineInfo(tw, (LineNum) 0, &start, &extra);
1819
1820 if (start > 0) {
1821 first_position = (*tw->text.source->Scan)
1822 (tw->text.source, start,
1823 XmSELECT_ALL, XmsdLeft, 1, True);
1824 if (start > first_position) {
1825 _XmTextSetTopCharacter((Widget)tw, start);
1826 return;
1827 }
1828 }
1829 } else {
1830
1831 if (data->resizeheight && tw->text.total_lines > data->number_lines) {
1832 int i;
1833 XmTextPosition linestart, position;
1834 Dimension text_width;
1835 XmTextBlockRec block;
1836
1837 i = _XmTextGetTableIndex(tw, tw->text.top_character);
1838 for (linestart = tw->text.top_character;
1839 i + 1 < tw->text.total_lines; i++) {
1840 text_width = data->leftmargin;
1841 position = tw->text.line_table[i + 1].start_pos - 1;
1842 while (linestart < position) {
1843 linestart = (*tw->text.source->ReadSource)
1844 (tw->text.source, linestart, position, &block);
1845 text_width += FindWidth(tw, text_width, &block, 0, block.length);
1846 }
1847 text_width += data->rightmargin;
1848 if (text_width > newwidth) newwidth = text_width;
1849 }
1850 text_width = data->leftmargin;
1851 position = tw->text.last_position;
1852 while (linestart < position) {
1853 linestart = (*tw->text.source->ReadSource)
1854 (tw->text.source, linestart, position, &block);
1855 text_width += FindWidth(tw, text_width, &block, 0, block.length);
1856 }
1857 text_width += data->rightmargin;
1858 if (text_width > newwidth) newwidth = text_width;
1859 } else {
1860 LineNum l;
1861 LineTableExtra extra;
1862
1863 for (l = 0; l < data->number_lines; l++) {
1864 _XmTextLineInfo(tw, l, &start, &extra);
1865 if (extra && newwidth < extra->width) newwidth = extra->width;
1866 }
1867 }
1868 }
1869
1870 *widthRtn = newwidth;
1871 }
1872
1873
1874 /*ARGSUSED*/
1875 static void
1876 TextFindNewHeight(XmTextWidget tw,
1877 XmTextPosition position, /* unused */
1878 Dimension *heightRtn)
1879 {
1880 OutputData data = tw->text.output->data;
1881 XmTextPosition first_position, start;
1882 LineTableExtra extra;
1883
1884 Dimension newheight = 0;
1885
1886 if(XmDirectionMatch(XmPrim_layout_direction(tw),
1887 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT)) {
1888 if (data->resizeheight && tw->text.total_lines > data->number_lines) {
1889 int i;
1890 XmTextPosition linestart, pos;
1891 Dimension text_height;
1892 XmTextBlockRec block;
1893
1894 i = _XmTextGetTableIndex(tw, tw->text.top_character);
1895 for (linestart = tw->text.top_character;
1896 i + 1 < tw->text.total_lines; i++) {
1897 text_height = data->topmargin;
1898 pos = tw->text.line_table[i + 1].start_pos - 1;
1899 while (linestart < pos) {
1900 linestart = (*tw->text.source->ReadSource)
1901 (tw->text.source, linestart, pos, &block);
1902 text_height += FindHeight(tw, text_height, &block, 0, block.length);
1903 }
1904 text_height += data->bottommargin;
1905 if (text_height > newheight) newheight = text_height;
1906 }
1907 text_height = data->topmargin;
1908 pos = tw->text.last_position;
1909 while (linestart < pos) {
1910 linestart = (*tw->text.source->ReadSource)
1911 (tw->text.source, linestart, pos, &block);
1912 text_height += FindHeight(tw, text_height, &block, 0, block.length);
1913 }
1914 text_height += data->bottommargin;
1915 if (text_height > newheight) newheight = text_height;
1916 } else {
1917 LineNum l;
1918 LineTableExtra extra;
1919
1920 for (l = 0; l < data->number_lines; l++) {
1921 _XmTextLineInfo(tw, l, &start, &extra);
1922 if (extra && newheight < extra->width) newheight = extra->width;
1923 }
1924 }
1925 *heightRtn = newheight;
1926 } else {
1927
1928 *heightRtn = tw->text.total_lines * data->lineheight +
1929 data->topmargin + data->bottommargin;
1930
1931 _XmTextLineInfo(tw, (LineNum) 0, &start, &extra);
1932
1933 if (start > 0) {
1934 first_position = (*tw->text.source->Scan)
1935 (tw->text.source, start,
1936 XmSELECT_ALL, XmsdLeft, 1, True);
1937 if (start > first_position) {
1938 _XmTextSetTopCharacter((Widget)tw, start);
1939 return;
1940 }
1941 }
1942 }
1943
1944 }
1945
1946
1947 static void
1948 CheckForNewSize(XmTextWidget tw,
1949 XmTextPosition position)
1950 {
1951 OutputData data = tw->text.output->data;
1952 Dimension newwidth, newheight;
1953
1954 if(XmDirectionMatch(XmPrim_layout_direction(tw),
1955 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT)) {
1956 if (data->scrollhorizontal &&
1957 XmIsScrolledWindow(XtParent(tw)) &&
1958 !tw->text.hsbar_scrolling)
1959 _XmChangeHSB(tw);
1960 } else {
1961 if (data->scrollvertical &&
1962 XmIsScrolledWindow(XtParent(tw)) &&
1963 !tw->text.vsbar_scrolling)
1964 _XmChangeVSB(tw);
1965 }
1966
1967
1968 if (tw->text.in_resize || tw->text.in_expose) {
1969 if(XmDirectionMatch(XmPrim_layout_direction(tw),
1970 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT)) {
1971 if (data->scrollvertical &&
1972 XmIsScrolledWindow(XtParent(tw))) {
1973 TextFindNewHeight(tw, position, &newheight);
1974 newheight -= (data->bottommargin + data->topmargin);
1975 if (newheight != data->scrollheight &&
1976 !data->suspend_voffset) {
1977 if (newheight) data->scrollheight = newheight;
1978 else data->scrollheight = 1;
1979 _XmRedisplayVBar(tw);
1980 }
1981 }
1982 } else {
1983 if (data->scrollhorizontal &&
1984 XmIsScrolledWindow(XtParent(tw))) {
1985 TextFindNewWidth(tw, &newwidth);
1986 newwidth -= (data->rightmargin + data->leftmargin);
1987 if (newwidth != data->scrollwidth &&
1988 !data->suspend_hoffset) {
1989 if (newwidth) data->scrollwidth = newwidth;
1990 else data->scrollwidth = 1;
1991 _XmRedisplayHBar(tw);
1992 }
1993 }
1994 }
1995 } else {
1996 if(XmDirectionMatch(XmPrim_layout_direction(tw),
1997 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT)) {
1998 if (data->resizeheight ||
1999 (data->scrollvertical &&
2000 XmIsScrolledWindow(XtParent(tw))))
2001 {
2002 TextFindNewHeight(tw, position, &newheight);
2003 if (data->scrollvertical &&
2004 XmIsScrolledWindow(XtParent(tw)))
2005 {
2006 newheight -= (data->bottommargin + data->topmargin);
2007 if (newheight != data->scrollheight &&
2008 !data->suspend_voffset) {
2009 if (newheight) data->scrollheight = newheight;
2010 else data->scrollheight = 1;
2011 _XmRedisplayVBar(tw);
2012 }
2013 newheight = tw->text.inner_widget->core.height;
2014 } else if (newheight < data->minheight) newheight = data->minheight;
2015 } else newheight = tw->text.inner_widget->core.height;
2016
2017 newwidth = tw->text.inner_widget->core.width;
2018
2019 if (data->resizewidth) {
2020 TextFindNewWidth(tw, &newwidth);
2021 if (newwidth < data->minwidth) newwidth = data->minwidth;
2022 }
2023 } else {
2024 if (data->resizewidth ||
2025 (data->scrollhorizontal &&
2026 XmIsScrolledWindow(XtParent(tw))))
2027 {
2028 TextFindNewWidth(tw, &newwidth);
2029 if (data->scrollhorizontal &&
2030 XmIsScrolledWindow(XtParent(tw)))
2031 {
2032 newwidth -= (data->rightmargin + data->leftmargin);
2033 if (newwidth != data->scrollwidth &&
2034 !data->suspend_hoffset) {
2035 if (newwidth) data->scrollwidth = newwidth;
2036 else data->scrollwidth = 1;
2037 _XmRedisplayHBar(tw);
2038 }
2039 newwidth = tw->text.inner_widget->core.width;
2040 } else if (newwidth < data->minwidth) newwidth = data->minwidth;
2041 } else newwidth = tw->text.inner_widget->core.width;
2042
2043 newheight = tw->text.inner_widget->core.height;
2044
2045 if (data->resizeheight
2046 && !(data->scrollvertical &&
2047 XmIsScrolledWindow(XtParent((Widget)tw))) ) {
2048 TextFindNewHeight(tw, position, &newheight);
2049 if (newheight < data->minheight) newheight = data->minheight;
2050 }
2051 }
2052
2053 if ((newwidth != tw->text.inner_widget->core.width ||
2054 newheight != tw->text.inner_widget->core.height)) {
2055 if (tw->text.in_setvalues) {
2056 tw->core.width = newwidth;
2057 tw->core.height = newheight;
2058 } else {
2059 if (TryResize(tw, newwidth, newheight) == XtGeometryYes)
2060 NotifyResized((Widget) tw, False);
2061 else
2062 tw->text.needs_refigure_lines = False;
2063 }
2064 }
2065 }
2066 }
2067
2068 /* ARGSUSED */
2069 static XtPointer
2070 OutputBaseProc(Widget widget,
2071 XtPointer client_data)
2072 {
2073 XmTextWidget tw = (XmTextWidget) widget;
2074 XtPointer ret_val;
2075
2076 _XmProcessLock();
2077 ret_val = (XtPointer) tw->text.output;
2078 _XmProcessUnlock();
2079 return ret_val;
2080 }
2081
2082
2083 /* ARGSUSED */
2084 void
2085 _XmTextOutputGetSecResData(XmSecondaryResourceData *secResDataRtn)
2086 {
2087 XmSecondaryResourceData secResData = XtNew(XmSecondaryResourceDataRec);
2088
2089 _XmTransformSubResources(output_resources, XtNumber(output_resources),
2090 &(secResData->resources),
2091 &(secResData->num_resources));
2092
2093 secResData->name = NULL;
2094 secResData->res_class = NULL;
2095 secResData->client_data = NULL;
2096 secResData->base_proc = OutputBaseProc;
2097 *secResDataRtn = secResData;
2098 }
2099
2100 /*****************************************************************************
2101 * To make TextOut a true "Object" this function should be a class function. *
2102 *****************************************************************************/
2103 int
2104 _XmTextGetNumberLines(XmTextWidget tw)
2105 {
2106 OutputData data = tw->text.output->data;
2107 return (data->number_lines);
2108 }
2109
2110 /*****************************************************************************
2111 * To make TextOut a true "Object" this function should be a class function. *
2112 *****************************************************************************/
2113 /* This routine is used to control foreground vs. background when moving
2114 * cursor position. It ensures that when cursor position is changed
2115 * between "inside the selection" and "outside the selection", that the
2116 * correct foreground and background are used when "painting" the cursor
2117 * through the IBeam stencil.
2118 */
2119 void
2120 _XmTextMovingCursorPosition(XmTextWidget tw,
2121 XmTextPosition position)
2122 {
2123 OutputData data = tw->text.output->data;
2124 _XmHighlightRec *hl_list = tw->text.highlight.list;
2125 int i;
2126
2127 for (i = tw->text.highlight.number - 1; i >= 0; i--)
2128 if (position >= hl_list[i].position)
2129 break;
2130
2131 if (position == hl_list[i].position) {
2132 if (data->have_inverted_image_gc)
2133 InvertImageGC(tw);
2134 } else if (hl_list[i].mode != XmHIGHLIGHT_SELECTED) {
2135 if (data->have_inverted_image_gc)
2136 InvertImageGC(tw);
2137 } else if (!data->have_inverted_image_gc) {
2138 InvertImageGC(tw);
2139 }
2140 }
2141
2142 static Boolean
2143 MeasureLine(XmTextWidget tw,
2144 LineNum line,
2145 XmTextPosition position,
2146 XmTextPosition *nextpos,
2147 LineTableExtra *extra)
2148 {
2149 OutputData data = tw->text.output->data;
2150 XmTextPosition temp, last_position;
2151 XmTextBlockRec block;
2152 Dimension width = 0;
2153 Dimension height = 0;
2154
2155 _XmProcessLock();
2156 posToXYCachedWidget = NULL;
2157 _XmProcessUnlock();
2158 if (extra) *extra = NULL;
2159 if (line >= data->number_lines) {
2160 if (data->resizewidth || data->resizeheight ||
2161 ((data->scrollvertical || data->scrollhorizontal) &&
2162 XmIsScrolledWindow(XtParent(tw)))) {
2163 CheckForNewSize(tw, position);
2164 }
2165 return(False);
2166 }
2167 if (nextpos) {
2168 if (position == PASTENDPOS) {
2169 *nextpos = last_position = PASTENDPOS;
2170 } else {
2171 if (ShouldWordWrap(data, tw)) {
2172 *nextpos = _XmTextFindLineEnd(tw, position, extra);
2173 } else {
2174 last_position = (*tw->text.source->Scan)
2175 (tw->text.source,
2176 position, XmSELECT_LINE,
2177 XmsdRight, 1, False);
2178 *nextpos = (*tw->text.source->Scan)(tw->text.source,
2179 last_position, XmSELECT_LINE,
2180 XmsdRight, 1, True);
2181 if (*nextpos == last_position)
2182 *nextpos = PASTENDPOS;
2183
2184 if(XmDirectionMatch(XmPrim_layout_direction(tw),
2185 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT)) {
2186 if (extra && (data->resizeheight ||
2187 (data->scrollvertical &&
2188 XmIsScrolledWindow(XtParent(tw))))) {
2189 (*extra) = (LineTableExtra)
2190 XtMalloc((unsigned) sizeof(LineTableExtraRec));
2191 (*extra)->wrappedbychar = False;
2192 height = data->topmargin;
2193 temp = position;
2194 while (temp < last_position) {
2195 temp = (*tw->text.source->ReadSource)
2196 (tw->text.source, temp, last_position, &block);
2197 height += FindHeight(tw, (Position) width, &block,
2198 0, block.length);
2199 }
2200 (*extra)->width = height + data->bottommargin;
2201 }
2202 } else {
2203 if (extra && (data->resizewidth ||
2204 (data->scrollhorizontal &&
2205 XmIsScrolledWindow(XtParent(tw))))) {
2206 (*extra) = (LineTableExtra)
2207 XtMalloc((unsigned) sizeof(LineTableExtraRec));
2208 (*extra)->wrappedbychar = False;
2209 width = data->leftmargin;
2210 temp = position;
2211 while (temp < last_position) {
2212 temp = (*tw->text.source->ReadSource)
2213 (tw->text.source, temp, last_position, &block);
2214 width += FindWidth(tw, (Position) width, &block,
2215 0, block.length);
2216 }
2217 (*extra)->width = width + data->rightmargin;
2218 }
2219 }
2220 }
2221 if (*nextpos == position)
2222 *nextpos = (*tw->text.source->Scan)(tw->text.source,
2223 position, XmSELECT_POSITION,
2224 XmsdRight, 1, True);
2225 }
2226 }
2227 return (True);
2228 }
2229
2230
2231 static Boolean
2232 _FontStructPerCharExtents(XmTextWidget tw,
2233 char *str,
2234 int length,
2235 XCharStruct *overall)
2236 {
2237 OutputData data = tw->text.output->data;
2238 XFontStruct *font = data->font;
2239 unsigned char c;
2240 int dummy;
2241
2242 memset((char *)overall, 0x00, sizeof(XCharStruct));
2243
2244 if(data->use_fontset)
2245 return False;
2246
2247 if(length <= 0 || str == (char *) NULL)
2248 return True;
2249
2250 if(tw->text.char_size != 1) {
2251 if(length == 1) {
2252 c = (unsigned char) *str;
2253 if(c == '\t') {
2254 return True;
2255 } else {
2256 if(font->per_char && (c >= font->min_char_or_byte2 &&
2257 c <= font->max_char_or_byte2)) {
2258 overall->lbearing =
2259 font->per_char[c - font->min_char_or_byte2].lbearing;
2260 overall->rbearing =
2261 font->per_char[c - font->min_char_or_byte2].rbearing;
2262 overall->width = font->per_char[c - font->min_char_or_byte2].width;
2263 } else {
2264 overall->lbearing = font->min_bounds.lbearing;
2265 overall->rbearing = font->min_bounds.rbearing;
2266 overall->width = font->min_bounds.width;
2267 }
2268 overall->ascent = font->max_bounds.ascent;
2269 overall->descent = font->max_bounds.descent;
2270 }
2271 } else {
2272 if (_XmIsISO10646(XtDisplay(tw), data->font)) {
2273 size_t ucsstr_len = 0;
2274 XChar2b *ucsstr = _XmUtf8ToUcs2(str, length, &ucsstr_len);
2275 XTextExtents16(data->font, ucsstr, ucsstr_len,
2276 &dummy, &dummy, &dummy, overall);
2277 XFree(ucsstr);
2278 } else
2279 XTextExtents(data->font, str, length, &dummy, &dummy, &dummy, overall);
2280 }
2281 } else {
2282 c = (unsigned char) *str;
2283 if(c == '\t') {
2284 return True;
2285 } else {
2286 if(font->per_char) {
2287 if(c >= font->min_char_or_byte2 && c <= font->max_char_or_byte2) {
2288 overall->lbearing =
2289 font->per_char[c - font->min_char_or_byte2].lbearing;
2290 overall->rbearing =
2291 font->per_char[c - font->min_char_or_byte2].rbearing;
2292 overall->width = font->per_char[c - font->min_char_or_byte2].width;
2293 } else if (font->default_char >= font->min_char_or_byte2 &&
2294 font->default_char <= font->max_char_or_byte2) {
2295 overall->lbearing = font->per_char[font->default_char -
2296 font->min_char_or_byte2].lbearing;
2297 overall->rbearing = font->per_char[font->default_char -
2298 font->min_char_or_byte2].rbearing;
2299 overall->width = font->per_char[font->default_char -
2300 font->min_char_or_byte2].width;
2301 } else {
2302 overall->lbearing = font->min_bounds.lbearing;
2303 overall->rbearing = font->min_bounds.rbearing;
2304 overall->width = font->min_bounds.width;
2305 }
2306 } else {
2307 overall->lbearing = font->min_bounds.lbearing;
2308 overall->rbearing = font->min_bounds.rbearing;
2309 overall->width = font->min_bounds.width;
2310 }
2311 overall->ascent = font->max_bounds.ascent;
2312 overall->descent = font->max_bounds.descent;
2313 }
2314 }
2315 return True;;
2316 }
2317
2318
2319 static void
2320 Draw(XmTextWidget tw,
2321 LineNum line,
2322 XmTextPosition start,
2323 XmTextPosition end,
2324 XmHighlightMode highlight)
2325 {
2326 OutputData data = tw->text.output->data;
2327 XmTextPosition linestart, nextlinestart;
2328 LineTableExtra extra;
2329 XmTextBlockRec block;
2330 int x, y, length, newx, i;
2331 int num_bytes = 0;
2332 int text_border;
2333 int rightedge = (((int)tw->text.inner_widget->core.width) -
2334 data->rightmargin) + data->hoffset;
2335 Boolean stipple = False;
2336
2337 int width, height;
2338 int rec_width = 0;
2339 int rec_height = 0;
2340 Boolean cleartoend, cleartobottom;
2341 XmHighlightMode endhighlight = highlight;
2342 int bottomedge = (((int)tw->text.inner_widget->core.height) -
2343 data->bottommargin) + data->voffset;
2344 int win_width = 0;
2345 int newy = 0;
2346 int charheight = data->font_ascent + data->font_descent;
2347
2348 if (!XtIsRealized((Widget) tw)) return;
2349 _XmTextLineInfo(tw, line+1, &nextlinestart, &extra);
2350 _XmTextLineInfo(tw, line, &linestart, &extra);
2351
2352 _XmTextAdjustGC(tw);
2353
2354 if (!XtIsSensitive((Widget)tw)) stipple = True;
2355
2356 if (linestart == PASTENDPOS) {
2357 start = end = nextlinestart = PASTENDPOS;
2358 cleartoend = cleartobottom = True;
2359 } else if (nextlinestart == PASTENDPOS) {
2360 nextlinestart = (*tw->text.source->Scan)(tw->text.source, 0,
2361 XmSELECT_ALL, XmsdRight, 1,
2362 False);
2363 cleartoend = cleartobottom = (end >= nextlinestart);
2364 if (start >= nextlinestart)
2365 endhighlight = highlight = XmHIGHLIGHT_NORMAL;
2366 else if (cleartoend)
2367 endhighlight = XmHIGHLIGHT_NORMAL;
2368 } else {
2369 cleartobottom = False;
2370 cleartoend = (end >= nextlinestart);
2371 if (cleartoend && (!extra || !extra->wrappedbychar))
2372 end = (*tw->text.source->Scan)(tw->text.source, nextlinestart,
2373 XmSELECT_POSITION, XmsdLeft, 1, True);
2374 }
2375 if (XmDirectionMatch(XmPrim_layout_direction(tw),
2376 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT)) {
2377 y = data->topmargin;
2378 x = tw->text.inner_widget->core.width -
2379 (data->rightmargin + line * data->linewidth +
2380 (int)(data->linewidth * 0.5));
2381 while (linestart < start && x <= rightedge) {
2382 linestart = (*tw->text.source->ReadSource)(tw->text.source,
2383 linestart, start, &block);
2384 y += FindHeight(tw, y, &block, 0, block.length);
2385 }
2386 } else {
2387 y = data->topmargin + line * data->lineheight + data->font_ascent;
2388 x = data->leftmargin;
2389 while (linestart < start && x <= rightedge) {
2390 linestart = (*tw->text.source->ReadSource)(tw->text.source,
2391 linestart, start, &block);
2392 x += FindWidth(tw, x, &block, 0, block.length);
2393 }
2394 }
2395
2396 if(XmDirectionMatch(XmPrim_layout_direction(tw),
2397 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT)) {
2398 XOrientation orient = 0;
2399 newy = y;
2400
2401 if(data->use_fontset == True) {
2402 XGetOCValues((XOC)data->font, XNOrientation, &orient, NULL);
2403 SetXOCOrientation(tw, (XOC)data->font, XOMOrientation_TTB_RTL);
2404 }
2405 while (start < end && y <= bottomedge) {
2406 start = (*tw->text.source->ReadSource)(tw->text.source, start,
2407 end, &block);
2408 if ((int)tw->text.char_size == 1) num_bytes = 1;
2409 else {
2410 num_bytes = mblen(block.ptr, (int)tw->text.char_size);
2411 if (num_bytes < 1) num_bytes = 1;
2412 }
2413 while (block.length > 0) {
2414 while (num_bytes == 1 && block.ptr[0] == '\t') {
2415 newy = y;
2416 while (block.length > 0 && num_bytes == 1 &&
2417 newy - data->voffset < data->topmargin) {
2418 height = FindHeight(tw, newy, &block, 0, 1);
2419 newy += height;
2420
2421 if (newy - data->voffset < data->topmargin) {
2422 block.length--;
2423 block.ptr++;
2424 y = newy;
2425 if ((int)tw->text.char_size != 1) {
2426 /* check if we've got mbyte char */
2427 num_bytes = mblen(block.ptr,
2428 (int)tw->text.char_size);
2429 if (num_bytes < 1) num_bytes = 1;
2430 }
2431 }
2432 }
2433 if (block.length <= 0 || num_bytes != 1 ||
2434 block.ptr[0] != '\t') break;
2435
2436 height = FindHeight(tw, y, &block, 0, 1);
2437
2438 if (highlight == XmHIGHLIGHT_SELECTED)
2439 SetNormGC(tw, data->gc, False, False);
2440 else
2441 SetInvGC(tw, data->gc);
2442 SetFullGC(tw, data->gc);
2443
2444 if (((y - data->voffset) + height) >
2445 (int)(tw->text.inner_widget->core.height - data->bottommargin))
2446 rec_height = (tw->text.inner_widget->core.height -
2447 data->bottommargin) - (y - data->voffset);
2448 else
2449 rec_height = height;
2450
2451 if (x - (int)(data->linewidth * 0.5) < data->leftmargin)
2452 rec_width = (tw->text.inner_widget->core.width -
2453 data->rightmargin) - x;
2454 else
2455 rec_width = data->linewidth;
2456
2457 XFillRectangle(XtDisplay(tw),
2458 XtWindow(tw->text.inner_widget), data->gc,
2459 x - (data->linewidth * 0.5), y - data->voffset,
2460 rec_width, rec_height);
2461
2462 SetMarginGC(tw, data->gc);
2463 if (highlight == XmHIGHLIGHT_SECONDARY_SELECTED) {
2464
2465 if (highlight == XmHIGHLIGHT_SELECTED)
2466 SetInvGC(tw, data->gc);
2467 else
2468 SetNormGC(tw, data->gc, False, False);
2469
2470 XDrawLine(XtDisplay(tw),
2471 XtWindow(tw->text.inner_widget), data->gc,
2472 x + (int)(data->linewidth * 0.5) - 1, y - data->voffset,
2473 (int)(x + data->linewidth * 0.5) - 1,
2474 ((y - data->voffset) + height) - 1);
2475 }
2476 y += height;
2477
2478
2479 block.length--;
2480 block.ptr++;
2481 if ((int)tw->text.char_size != 1) {
2482 num_bytes = mblen(block.ptr, (int)tw->text.char_size);
2483 /* crummy error handling, but ... */
2484 if (num_bytes < 0) num_bytes = 1;
2485 }
2486 if (block.length <= 0) break;
2487 }
2488 if ((int)tw->text.char_size == 1) {
2489 for (length = 0; length < block.length; length++) {
2490 if (block.ptr[length] == '\t') break;
2491 }
2492 } else {
2493 for (length = 0, num_bytes = mblen(block.ptr,
2494 (int)tw->text.char_size);
2495 length < block.length;
2496 num_bytes = mblen(&block.ptr[length],
2497 (int)tw->text.char_size)) {
2498 if ((num_bytes == 1) && block.ptr[length] == '\t') break;
2499 if (num_bytes == 0) break;
2500 if (num_bytes < 0) num_bytes = 1;
2501 length += num_bytes;
2502 }
2503 }
2504 if (length <= 0) break;
2505 newy = y;
2506 while (length > 0 && newy + charheight < data->topmargin) {
2507 newy += FindHeight(tw, newy, &block, 0, 1);
2508 if ((int)tw->text.char_size == 1) {
2509 if (newy + charheight < data->topmargin) {
2510 length--;
2511 block.length--;
2512 block.ptr++;
2513 y = newy;
2514 }
2515 } else {
2516 if (newy + charheight < data->topmargin) {
2517 num_bytes = mblen(block.ptr, (int)tw->text.char_size);
2518 if (num_bytes < 0) num_bytes = 1;
2519 length -= num_bytes;
2520 block.length -= num_bytes;
2521 block.ptr += num_bytes;
2522 y = newy;
2523 }
2524 }
2525 }
2526 if (length == 0) continue;
2527 newy = y + FindHeight(tw, y, &block, 0, length);
2528 if (newy > bottomedge) {
2529 newy = y;
2530 if ((int)tw->text.char_size == 1) {
2531 for (i=0; i < length && (newy - data->voffset) <= bottomedge; i++) {
2532 newy += FindHeight(tw, newy, &block, i, i+1);
2533 }
2534 } else {
2535 for (i=0, num_bytes = mblen(block.ptr, (int)tw->text.char_size);
2536 i < length && (newy - data->voffset) <= bottomedge &&
2537 num_bytes > 0;
2538 i += num_bytes, num_bytes = mblen(&block.ptr[i],
2539 (int)tw->text.char_size))
2540 newy += FindHeight(tw, newy, &block, i, i + num_bytes);
2541 }
2542 length = i;
2543 start = end; /* Force a break out of the outer loop. */
2544 block.length = length; /* ... and out of the inner loop. */
2545 }
2546 if (highlight == XmHIGHLIGHT_SELECTED) {
2547 /* Draw the inverse background, then draw the text over it */
2548 SetNormGC(tw, data->gc, False, False);
2549 SetFullGC(tw, data->gc);
2550
2551 if (((y - data->voffset) + (newy - y)) >
2552 (int) tw->text.inner_widget->core.height - data->bottommargin)
2553 rec_height = tw->text.inner_widget->core.height -
2554 (y - data->voffset) - data->bottommargin;
2555 else
2556 rec_height = newy - y;
2557
2558 if (x + (int)(data->linewidth * 0.5) < data->leftmargin)
2559 rec_width = x + (tw->text.inner_widget->core.width -
2560 data->rightmargin);
2561 else
2562 rec_width = data->linewidth;
2563
2564 XFillRectangle(XtDisplay(tw),
2565 XtWindow(tw->text.inner_widget),
2566 data->gc, x - (int)(data->linewidth * 0.5),
2567 y - data->voffset, rec_width, rec_height);
2568
2569 SetInvGC(tw, data->gc);
2570 SetMarginGC(tw, data->gc);
2571 if (data->use_fontset) {
2572 XmbDrawString(XtDisplay(tw),
2573 XtWindow(tw->text.inner_widget),
2574 (XFontSet) data->font, data->gc,
2575 x, y - data->voffset, block.ptr, length);
2576 #ifdef USE_XFT
2577 } else if (data->use_xft) {
2578 _XmXftDrawString2(XtDisplay(tw), XtWindow(tw->text.inner_widget),
2579 data->gc, (XftFont*) data->font, 1,
2580 x, y - data->voffset, block.ptr, length);
2581 #endif
2582 } else {
2583 int len = 0, csize = 0, wx = 0, orig_x = 0, orig_y = 0;
2584 char *p = NULL;
2585 XCharStruct overall;
2586
2587 wx = x - data->hoffset;
2588 orig_y = y - data->voffset;
2589 for(len = length, p = block.ptr ; len > 0 && p ;
2590 len-= csize, p += csize) {
2591 csize = mblen(p, (int)tw->text.char_size);
2592
2593 _FontStructPerCharExtents(tw, p, csize, &overall);
2594
2595 orig_x = wx - (int)((overall.rbearing - overall.lbearing) >> 1) -
2596 overall.lbearing;
2597 orig_y += overall.ascent;
2598 if (_XmIsISO10646(XtDisplay(tw), data->font)) {
2599 size_t ucsstr_len = 0;
2600 XChar2b *ucsstr = _XmUtf8ToUcs2(p, csize, &ucsstr_len);
2601 XDrawString16(XtDisplay(tw), XtWindow(tw->text.inner_widget),
2602 data->gc, orig_x, orig_y, ucsstr, ucsstr_len);
2603 XFree(ucsstr);
2604 } else
2605 XDrawString(XtDisplay(tw),
2606 XtWindow(tw->text.inner_widget), data->gc,
2607 orig_x, orig_y, p, csize);
2608
2609 orig_y += overall.descent;
2610 }
2611 }
2612 } else {
2613 SetInvGC(tw, data->gc);
2614 if (newy > y) {
2615 if (x + (int)(data->linewidth * 0.5) < data->leftmargin)
2616 rec_width = x + (tw->text.inner_widget->core.width -
2617 data->rightmargin);
2618 else
2619 rec_width = data->linewidth;
2620
2621 XFillRectangle(XtDisplay(tw),
2622 XtWindow(tw->text.inner_widget),
2623 data->gc, x - (int)(data->linewidth * 0.5),
2624 y - data->voffset, rec_width, newy - y);
2625 }
2626 SetNormGC(tw, data->gc, True, stipple);
2627 if (data->use_fontset) {
2628 int wx, wy;
2629
2630 wx = x - data->hoffset;
2631 #ifdef FIX_1381
2632 if (stipple)
2633 {
2634 /*Draw shadow for insensitive text*/
2635 SetShadowGC(tw, data->gc);
2636 XmbDrawString(XtDisplay(tw),
2637 XtWindow(tw->text.inner_widget),
2638 (XFontSet) data->font, data->gc,
2639 wx+1, y - data->voffset+1, block.ptr, length);
2640 SetNormGC(tw, data->gc, True, stipple);
2641 }
2642 #endif
2643
2644 XmbDrawString(XtDisplay(tw),
2645 XtWindow(tw->text.inner_widget),
2646 (XFontSet) data->font, data->gc,
2647 wx, y - data->voffset, block.ptr, length);
2648 #ifdef USE_XFT
2649 } else if (data->use_xft) {
2650 #ifdef FIX_1381
2651 if (stipple)
2652 {
2653 /*Draw shadow for insensitive text*/
2654 SetShadowGC(tw, data->gc);
2655 _XmXftDrawString2(XtDisplay(tw), XtWindow(tw->text.inner_widget),
2656 data->gc, (XftFont*) data->font, 1,
2657 x - data->hoffset+1, y - data->voffset+1,
2658 block.ptr, length);
2659 SetNormGC(tw, data->gc, True, stipple);
2660 }
2661 #endif
2662
2663 _XmXftDrawString2(XtDisplay(tw), XtWindow(tw->text.inner_widget),
2664 data->gc, (XftFont*) data->font, 1,
2665 x - data->hoffset, y - data->voffset,
2666 block.ptr, length);
2667 #endif
2668 } else {
2669 int len = 0, csize = 0, wx = 0, orig_x = 0, orig_y = 0;
2670 char *p = NULL;
2671 XCharStruct overall;
2672 wx = x - data->hoffset;
2673 orig_y = y - data->voffset;
2674 for(len = length, p = block.ptr ; len > 0 && p ;
2675 len-= csize, p += csize) {
2676 csize = mblen(p, (int)tw->text.char_size);
2677
2678 _FontStructPerCharExtents(tw, p, csize, &overall);
2679 orig_x = wx - (int)((overall.rbearing - overall.lbearing) >> 1) -
2680 overall.lbearing;
2681 orig_y += overall.ascent;
2682 if (_XmIsISO10646(XtDisplay(tw), data->font)) {
2683 size_t ucsstr_len = 0;
2684 XChar2b *ucsstr = _XmUtf8ToUcs2(p, csize, &ucsstr_len);
2685 #ifdef FIX_1381
2686 if (stipple)
2687 {
2688 /*Draw shadow for insensitive text*/
2689 SetShadowGC(tw, data->gc);
2690 XDrawString16(XtDisplay(tw), XtWindow(tw->text.inner_widget),
2691 data->gc, orig_x+1, orig_y+1, ucsstr, ucsstr_len);
2692 SetNormGC(tw, data->gc, True, stipple);
2693 }
2694 #endif
2695 XDrawString16(XtDisplay(tw), XtWindow(tw->text.inner_widget),
2696 data->gc, orig_x, orig_y, ucsstr, ucsstr_len);
2697 XFree(ucsstr);
2698 } else {
2699 #ifdef FIX_1381
2700 if (stipple)
2701 {
2702 /*Draw shadow for insensitive text*/
2703 SetShadowGC(tw, data->gc);
2704 XDrawString(XtDisplay(tw),
2705 XtWindow(tw->text.inner_widget), data->gc,
2706 orig_x+1, orig_y+1, p, csize);
2707 SetNormGC(tw, data->gc, True, stipple);
2708 }
2709 #endif
2710 XDrawString(XtDisplay(tw),
2711 XtWindow(tw->text.inner_widget), data->gc,
2712 orig_x, orig_y, p, csize);
2713 }
2714 orig_y += overall.descent;
2715 }
2716 }
2717 if (stipple) SetNormGC(tw, data->gc, True, !stipple);
2718 }
2719 if (highlight == XmHIGHLIGHT_SECONDARY_SELECTED)
2720 XDrawLine(XtDisplay(tw), XtWindow(tw->text.inner_widget),
2721 data->gc, x + (int)(data->linewidth * 0.5) - 1,
2722 y - data->voffset,
2723 x + (int)(data->linewidth * 0.5) - 1,
2724 (newy - data->voffset) - 1);
2725 y = newy;
2726 block.length -= length;
2727 block.ptr += length;
2728 if ((int)tw->text.char_size != 1) {
2729 num_bytes = mblen(block.ptr, (int)tw->text.char_size);
2730 if (num_bytes < 1) num_bytes = 1;
2731 }
2732 }
2733 }
2734 if(data->use_fontset == True) {
2735 SetXOCOrientation(tw, (XOC)data->font, orient);
2736 }
2737 } else {
2738
2739 newx = x;
2740 while (start < end && x <= rightedge) {
2741 start = (*tw->text.source->ReadSource)(tw->text.source, start,
2742 end, &block);
2743 if ((int)tw->text.char_size == 1) num_bytes = 1;
2744 else {
2745 #ifndef NO_MULTIBYTE
2746 num_bytes = mblen(block.ptr, (int)tw->text.char_size);
2747 if (num_bytes < 1) num_bytes = 1;
2748 #else
2749 num_bytes = 1;
2750 #endif
2751 }
2752 while (block.length > 0) {
2753 while (num_bytes == 1 && block.ptr[0] == '\t') {
2754 newx = x;
2755 while (block.length > 0 && num_bytes == 1 &&
2756 newx - data->hoffset < data->leftmargin) {
2757 width = FindWidth(tw, newx, &block, 0, 1);
2758 newx += width;
2759
2760 if (newx - data->hoffset < data->leftmargin) {
2761 block.length--;
2762 block.ptr++;
2763 x = newx;
2764 if ((int)tw->text.char_size != 1) {
2765 /* check if we've got mbyte char */
2766 #ifndef NO_MULTIBYTE
2767 num_bytes = mblen(block.ptr, (int)tw->text.char_size);
2768 if (num_bytes < 1) num_bytes = 1;
2769 #else
2770 num_bytes = 1;
2771 #endif
2772 }
2773 }
2774 }
2775 if (block.length <= 0 || num_bytes != 1 ||
2776 block.ptr[0] != '\t') break;
2777
2778 width = FindWidth(tw, x, &block, 0, 1);
2779
2780 if (highlight == XmHIGHLIGHT_SELECTED)
2781 SetNormGC(tw, data->gc, False, False);
2782 else
2783 SetInvGC(tw, data->gc);
2784 SetFullGC(tw, data->gc);
2785
2786 if ((int) ((x - data->hoffset) + width) >
2787 (int) (tw->text.inner_widget->core.width - data->rightmargin))
2788 rec_width = (tw->text.inner_widget->core.width -
2789 data->rightmargin) - (x - data->hoffset);
2790 else
2791 rec_width = width;
2792
2793 if ((int) (y + data->font_descent) >
2794 (int) (tw->text.inner_widget->core.height - data->bottommargin))
2795 rec_height = (tw->text.inner_widget->core.height -
2796 data->bottommargin) - y;
2797 else
2798 rec_height = data->font_ascent + data->font_descent;
2799
2800 XFillRectangle(XtDisplay(tw),
2801 XtWindow(tw->text.inner_widget), data->gc,
2802 x - data->hoffset, y - data->font_ascent,
2803 rec_width, rec_height);
2804
2805 SetMarginGC(tw, data->gc);
2806 if (highlight == XmHIGHLIGHT_SECONDARY_SELECTED) {
2807
2808 if (highlight == XmHIGHLIGHT_SELECTED)
2809 SetInvGC(tw, data->gc);
2810 else
2811 SetNormGC(tw, data->gc, False, False);
2812
2813 XDrawLine(XtDisplay(tw),
2814 XtWindow(tw->text.inner_widget), data->gc,
2815 x - data->hoffset, y,
2816 ((x - data->hoffset) + width) - 1, y);
2817 }
2818 x += width;
2819
2820
2821 block.length--;
2822 block.ptr++;
2823 if ((int)tw->text.char_size != 1) {
2824 #ifndef NO_MULTIBYTE
2825 num_bytes = mblen(block.ptr, (int)tw->text.char_size);
2826 /* crummy error handling, but ... */
2827 if (num_bytes < 0) num_bytes = 1;
2828 #else
2829 num_bytes = *block.ptr ? 1 : 0;
2830 #endif
2831 }
2832 if (block.length <= 0) break;
2833 }
2834 if ((int)tw->text.char_size == 1) {
2835 for (length = 0; length < block.length; length++) {
2836 if (block.ptr[length] == '\t') break;
2837 }
2838 } else {
2839 for (length = 0,
2840 #ifndef NO_MULTIBYTE
2841 num_bytes = mblen(block.ptr, (int)tw->text.char_size);
2842 #else
2843 num_bytes = *block.ptr ? 1 : 0;
2844 #endif
2845 length < block.length;
2846 #ifndef NO_MULTIBYTE
2847 num_bytes = mblen(&block.ptr[length], (int)tw->text.char_size)) {
2848 #else
2849 num_bytes = block.ptr[length] ? 1 : 0) {
2850 #endif
2851 if ((num_bytes == 1) && block.ptr[length] == '\t') break;
2852 if (num_bytes == 0) break;
2853 if (num_bytes < 0) num_bytes = 1;
2854 length += num_bytes;
2855 }
2856 }
2857 if (length <= 0) break;
2858 newx = x;
2859 while (length > 0 && newx - data->hoffset < data->leftmargin) {
2860 newx += FindWidth(tw, newx, &block, 0, 1);
2861 if ((int)tw->text.char_size == 1) {
2862 if (newx - data->hoffset < data->leftmargin) {
2863 length--;
2864 block.length--;
2865 block.ptr++;
2866 x = newx;
2867 }
2868 } else {
2869 if (newx - data->hoffset < data->leftmargin) {
2870 #ifndef NO_MULTIBYTE
2871 num_bytes = mblen(block.ptr, (int)tw->text.char_size);
2872 if (num_bytes < 0) num_bytes = 1;
2873 #else
2874 num_bytes = *block.ptr ? 1 : 0;
2875 #endif
2876 length -= num_bytes;
2877 block.length -= num_bytes;
2878 block.ptr += num_bytes;
2879 x = newx;
2880 }
2881 }
2882 }
2883 if (length == 0) continue;
2884 newx = x + FindWidth(tw, x, &block, 0, length);
2885 if (newx > rightedge) {
2886 newx = x;
2887 if ((int)tw->text.char_size == 1) {
2888 for (i=0; i < length && newx <= rightedge; i++) {
2889 newx += FindWidth(tw, newx, &block, i, i+1);
2890 }
2891 } else {
2892 for (i=0,
2893 #ifndef NO_MULTIBYTE
2894 num_bytes = mblen(block.ptr, (int)tw->text.char_size);
2895 #else
2896 num_bytes = *block.ptr ? 1 : 0;
2897 #endif
2898 i < length && newx <= rightedge && num_bytes > 0;
2899 i += num_bytes,
2900 #ifndef NO_MULTIBYTE
2901 num_bytes = mblen(&block.ptr[i], (int)tw->text.char_size))
2902 #else
2903 num_bytes = block.ptr[i] ? 1 : 0)
2904 #endif
2905 newx += FindWidth(tw, newx, &block, i, i + num_bytes);
2906 }
2907 length = i;
2908 start = end; /* Force a break out of the outer loop. */
2909 block.length = length; /* ... and out of the inner loop. */
2910 }
2911 if (highlight == XmHIGHLIGHT_SELECTED) {
2912 /* Draw the inverse background, then draw the text over it */
2913 SetNormGC(tw, data->gc, False, False);
2914 SetFullGC(tw, data->gc);
2915
2916 if ((int) ((x - data->hoffset) + (newx - x)) >
2917 (int) (tw->text.inner_widget->core.width - data->rightmargin))
2918 rec_width = tw->text.inner_widget->core.width -
2919 (x - data->hoffset) - data->rightmargin;
2920 else
2921 rec_width = newx - x;
2922
2923 if ((int) (y + data->font_descent) >
2924 (int) (tw->text.inner_widget->core.height - data->bottommargin))
2925 rec_height = (tw->text.inner_widget->core.height -
2926 data->bottommargin) - (y - data->font_ascent);
2927 else
2928 rec_height = data->font_ascent + data->font_descent;
2929
2930 XFillRectangle(XtDisplay(tw),
2931 XtWindow(tw->text.inner_widget),
2932 data->gc, x - data->hoffset,
2933 y - data->font_ascent, rec_width, rec_height);
2934
2935 SetInvGC(tw, data->gc);
2936 SetMarginGC(tw, data->gc);
2937 if (data->use_fontset) {
2938 XmbDrawString(XtDisplay(tw),
2939 XtWindow(tw->text.inner_widget),
2940 (XFontSet) data->font, data->gc,
2941 x - data->hoffset, y, block.ptr, length);
2942 #ifdef USE_XFT
2943 } else if (data->use_xft) {
2944 _XmXftDrawString2(XtDisplay(tw), XtWindow(tw->text.inner_widget),
2945 data->gc, (XftFont*) data->font, 1,
2946 x - data->hoffset, y, block.ptr, length);
2947 #endif
2948 } else {
2949 if (_XmIsISO10646(XtDisplay(tw), data->font)) {
2950 size_t ucsstr_len = 0;
2951 XChar2b *ucsstr = _XmUtf8ToUcs2(block.ptr, length, &ucsstr_len);
2952 XDrawString16(XtDisplay(tw), XtWindow(tw->text.inner_widget),
2953 data->gc, x - data->hoffset, y, ucsstr,
2954 ucsstr_len);
2955 XFree(ucsstr);
2956 } else
2957 XDrawString(XtDisplay(tw),
2958 XtWindow(tw->text.inner_widget),
2959 data->gc, x - data->hoffset, y,
2960 block.ptr, length);
2961 }
2962 } else {
2963 SetInvGC(tw, data->gc);
2964 if (newx > x) {
2965 if ((int) (y + data->font_descent) >
2966 (int) (tw->text.inner_widget->core.height - data->bottommargin))
2967 rec_height = (tw->text.inner_widget->core.height -
2968 data->bottommargin) - (y - data->font_ascent);
2969 else
2970 rec_height = data->font_ascent + data->font_descent;
2971
2972 XFillRectangle(XtDisplay(tw),
2973 XtWindow(tw->text.inner_widget),
2974 data->gc, x - data->hoffset,
2975 y - data->font_ascent, newx - x,
2976 rec_height);
2977 }
2978 SetNormGC(tw, data->gc, True, stipple);
2979 if (data->use_fontset) {
2980 #ifdef FIX_1381
2981 if (stipple)
2982 {
2983 /*Draw shadow for insensitive text*/
2984 SetShadowGC(tw, data->gc);
2985 XmbDrawString(XtDisplay(tw),
2986 XtWindow(tw->text.inner_widget),
2987 (XFontSet) data->font, data->gc,
2988 x - data->hoffset+1, y+1, block.ptr, length);
2989 SetNormGC(tw, data->gc, True, stipple);
2990 }
2991 #endif
2992 XmbDrawString(XtDisplay(tw),
2993 XtWindow(tw->text.inner_widget),
2994 (XFontSet) data->font, data->gc,
2995 x - data->hoffset, y, block.ptr, length);
2996 #ifdef USE_XFT
2997 } else if (data->use_xft) {
2998 #ifdef FIX_1381
2999 if (stipple)
3000 {
3001 /*Draw shadow for insensitive text*/
3002 SetShadowGC(tw, data->gc);
3003 _XmXftDrawString2(XtDisplay(tw), XtWindow(tw->text.inner_widget),
3004 data->gc, (XftFont*) data->font, 1,
3005 x - data->hoffset+1, y+1, block.ptr, length);
3006 SetNormGC(tw, data->gc, True, stipple);
3007 }
3008 #endif
3009 _XmXftDrawString2(XtDisplay(tw), XtWindow(tw->text.inner_widget),
3010 data->gc, (XftFont*) data->font, 1,
3011 x - data->hoffset, y, block.ptr, length);
3012 #endif
3013 } else {
3014 if (_XmIsISO10646(XtDisplay(tw), data->font)) {
3015 size_t ucsstr_len = 0;
3016 XChar2b *ucsstr = _XmUtf8ToUcs2(block.ptr, length, &ucsstr_len);
3017 #ifdef FIX_1381
3018 if (stipple)
3019 {
3020 /*Draw shadow for insensitive text*/
3021 SetShadowGC(tw, data->gc);
3022 XDrawString16(XtDisplay(tw), XtWindow(tw->text.inner_widget),
3023 data->gc, x - data->hoffset+1, y+1, ucsstr,
3024 ucsstr_len);
3025 SetNormGC(tw, data->gc, True, stipple);
3026 }
3027 #endif
3028
3029 XDrawString16(XtDisplay(tw), XtWindow(tw->text.inner_widget),
3030 data->gc, x - data->hoffset, y, ucsstr,
3031 ucsstr_len);
3032 XFree(ucsstr);
3033 } else
3034 {
3035 #ifdef FIX_1381
3036 if (stipple)
3037 {
3038 /*Draw shadow for insensitive text*/
3039 SetShadowGC(tw, data->gc);
3040 XDrawString(XtDisplay(tw),
3041 XtWindow(tw->text.inner_widget), data->gc,
3042 x - data->hoffset+1, y+1, block.ptr, length);
3043 SetNormGC(tw, data->gc, True, stipple);
3044 }
3045 #endif
3046 XDrawString(XtDisplay(tw),
3047 XtWindow(tw->text.inner_widget), data->gc,
3048 x - data->hoffset, y, block.ptr, length);
3049 }
3050 }
3051 if (stipple) SetNormGC(tw, data->gc, True, !stipple);
3052 }
3053 if (highlight == XmHIGHLIGHT_SECONDARY_SELECTED)
3054 XDrawLine(XtDisplay(tw), XtWindow(tw->text.inner_widget),
3055 data->gc, x - data->hoffset, y,
3056 (newx - data->hoffset) - 1, y);
3057 x = newx;
3058 block.length -= length;
3059 block.ptr += length;
3060 if ((int)tw->text.char_size != 1) {
3061 #ifndef NO_MULTIBYTE
3062 num_bytes = mblen(block.ptr, (int)tw->text.char_size);
3063 if (num_bytes < 1) num_bytes = 1;
3064 #else
3065 num_bytes = 1;
3066 #endif
3067 }
3068 }
3069 }
3070 }
3071
3072 if(XmDirectionMatch(XmPrim_layout_direction(tw),
3073 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT)) {
3074 /* clear top margin */
3075 text_border = tw->primitive.shadow_thickness +
3076 tw->primitive.highlight_thickness;
3077 if (data->topmargin - text_border > 0 && x < rightedge + text_border)
3078 XClearArea(XtDisplay(tw), XtWindow(tw->text.inner_widget),
3079 x - (int) (data->linewidth * 0.5)-1, text_border,
3080 rightedge - x + (int) (data->linewidth * 0.5),
3081 data->topmargin - text_border, FALSE);
3082
3083 if (cleartoend) {
3084 y -= data->voffset;
3085 if (y > ((int)tw->text.inner_widget->core.height)- data->bottommargin)
3086 y = ((int)tw->text.inner_widget->core.height)- data->bottommargin;
3087 if (y < data->topmargin)
3088 y = data->topmargin;
3089 height = ((int)tw->text.inner_widget->core.height) - y -
3090 data->bottommargin;
3091 if (height > 0 && data->linewidth > 0) {
3092 if (endhighlight == XmHIGHLIGHT_SELECTED)
3093 SetNormGC(tw, data->gc, False, False);
3094 else
3095 SetInvGC(tw, data->gc);
3096 SetFullGC(tw, data->gc);
3097 if ((int) (x - (data->linewidth * 0.5)) < data->leftmargin)
3098 rec_width = x + (data->linewidth * 0.5) - data->leftmargin;
3099 else
3100 rec_width = data->linewidth;
3101
3102 XFillRectangle(XtDisplay(tw),
3103 XtWindow(tw->text.inner_widget), data->gc,
3104 x - (int)(data->linewidth * 0.5), y, rec_width, height);
3105 SetMarginGC(tw, data->gc);
3106 }
3107 }
3108 if (cleartobottom) {
3109 y = data->topmargin;
3110 width = x - (data->linewidth * 0.5) - data->leftmargin;
3111 height = tw->text.inner_widget->core.height -
3112 (data->topmargin + data->bottommargin);
3113 if (width > 0 && height > 0)
3114 XClearArea(XtDisplay(tw), XtWindow(tw->text.inner_widget),
3115 data->leftmargin, y, width, height, False);
3116 }
3117 } else {
3118 /* clear left margin */
3119 text_border = tw->primitive.shadow_thickness +
3120 tw->primitive.highlight_thickness;
3121 if (data->leftmargin - text_border > 0 && (int) (y + data->font_descent) > 0)
3122 XClearArea(XtDisplay(tw), XtWindow(tw->text.inner_widget),
3123 text_border, text_border, data->leftmargin - text_border,
3124 y + data->font_descent - text_border, False);
3125
3126 if (cleartoend) {
3127 x -= data->hoffset;
3128 if (x > ((int)tw->text.inner_widget->core.width)- data->rightmargin)
3129 x = ((int)tw->text.inner_widget->core.width)- data->rightmargin;
3130 if (x < data->leftmargin)
3131 x = data->leftmargin;
3132 width = ((int)tw->text.inner_widget->core.width) - x -
3133 data->rightmargin;
3134 if (width > 0 && data->lineheight > 0) {
3135 if (endhighlight == XmHIGHLIGHT_SELECTED)
3136 SetNormGC(tw, data->gc, False, False);
3137 else
3138 SetInvGC(tw, data->gc);
3139 SetFullGC(tw, data->gc);
3140 if ((int) (y + data->font_descent) >
3141 (int) (tw->text.inner_widget->core.height - data->bottommargin))
3142 rec_height = (tw->text.inner_widget->core.height -
3143 data->bottommargin) - (y - data->font_ascent);
3144 else
3145 rec_height = data->font_ascent + data->font_descent;
3146
3147 XFillRectangle(XtDisplay(tw),
3148 XtWindow(tw->text.inner_widget), data->gc, x,
3149 y - data->font_ascent, width, rec_height);
3150 SetMarginGC(tw, data->gc);
3151 }
3152 }
3153 if (cleartobottom) {
3154 x = data->leftmargin;
3155 width = tw->text.inner_widget->core.width -
3156 (data->rightmargin + data->leftmargin);
3157 height = tw->text.inner_widget->core.height -
3158 ((y + data->font_descent) + data->bottommargin);
3159 if (width > 0 && height > 0)
3160 XClearArea(XtDisplay(tw), XtWindow(tw->text.inner_widget),
3161 x, y + data->font_descent, width, height, False);
3162 }
3163 }
3164 /* Before exiting, force PaintCursor to refresh its save area */
3165 data->refresh_ibeam_off = True;
3166 }
3167
3168 static OnOrOff
3169 CurrentCursorState(XmTextWidget tw)
3170 {
3171 OutputData data = tw->text.output->data;
3172 if (data->cursor_on < 0) return off;
3173 if (data->blinkstate == on || !XtIsSensitive((Widget)tw))
3174 return on;
3175 return off;
3176 }
3177
3178
3179 /*
3180 * All the info about the cursor has been figured; draw or erase it.
3181 */
3182 static void
3183 PaintCursor(XmTextWidget tw)
3184 {
3185 OutputData data = tw->text.output->data;
3186 Position x, y;
3187
3188 if (!data->cursor_position_visible) return;
3189
3190 _XmTextToggleCursorGC((Widget)tw);
3191
3192 if (!tw->text.input->data->overstrike)
3193 x = data->insertx - (data->cursorwidth >> 1) - 1;
3194 else {
3195 int pxlen;
3196 XmTextBlockRec block;
3197 XmTextPosition cursor_pos = tw->text.cursor_position;
3198 x = data->insertx;
3199 (void) (*tw->text.source->ReadSource) (tw->text.source,
3200 cursor_pos, cursor_pos+1,
3201 &block);
3202 pxlen = FindWidth(tw, x, &block, 0, block.length);
3203 if (pxlen > (int) data->cursorwidth)
3204 x += (short) (pxlen - data->cursorwidth) >> 1;
3205 }
3206 y = data->inserty + data->font_descent - data->cursorheight;
3207
3208 /* If time to paint the I Beam... first capture the IBeamOffArea, then draw
3209 * the I Beam. */
3210 if ((tw->text.top_character <= tw->text.cursor_position) &&
3211 (tw->text.cursor_position <= tw->text.bottom_position)) {
3212 int cursor_width = data->cursorwidth;
3213 int cursor_height = data->cursorheight;
3214 if (data->refresh_ibeam_off == True) { /* get area under IBeam first */
3215 /* Fill is needed to realign clip rectangle with gc */
3216 XFillRectangle(XtDisplay((Widget)tw), XtWindow((Widget)tw),
3217 data->save_gc, 0, 0, 0, 0);
3218 XCopyArea(XtDisplay((Widget)tw), XtWindow((Widget)tw),
3219 data->ibeam_off, data->save_gc, x, y, data->cursorwidth,
3220 data->cursorheight, 0, 0);
3221 data->refresh_ibeam_off = False;
3222 }
3223
3224 /* redraw cursor, being very sure to keep it within the bounds of the
3225 ** text area, not spilling into the highlight area
3226 */
3227 if ((data->cursor_on >= 0) && (data->blinkstate == on)) {
3228 if (x + data->cursorwidth > tw->text.inner_widget->core.width -
3229 tw->primitive.shadow_thickness -
3230 tw->primitive.highlight_thickness)
3231 cursor_width = (tw->text.inner_widget->core.width -
3232 (tw->primitive.shadow_thickness +
3233 tw->primitive.highlight_thickness)) - x;
3234 #ifdef FIX_1501
3235 if ( cursor_width > 0 && cursor_height > 0 ) {
3236 if (!XtIsSensitive((Widget)tw)) {
3237 SetShadowGC(tw, data->imagegc);
3238 XFillRectangle(XtDisplay((Widget)tw), XtWindow((Widget)tw),
3239 data->imagegc, x + 1, y + 1,
3240 (unsigned int )cursor_width,
3241 (unsigned int )cursor_height);
3242 }
3243
3244 _XmTextToggleCursorGC((Widget)tw);
3245 #else
3246 if ( cursor_width > 0 && cursor_height > 0 )
3247 #endif
3248 XFillRectangle(XtDisplay((Widget)tw), XtWindow((Widget)tw),
3249 data->imagegc, x, y,
3250 (unsigned int )cursor_width,
3251 (unsigned int )cursor_height);
3252 #ifdef FIX_1501
3253 }
3254 #endif
3255 } else {
3256 Position src_x = 0;
3257 if (x + data->cursorwidth > tw->text.inner_widget->core.width -
3258 tw->primitive.shadow_thickness -
3259 tw->primitive.highlight_thickness) {
3260 cursor_width = (tw->text.inner_widget->core.width -
3261 (tw->primitive.shadow_thickness +
3262 tw->primitive.highlight_thickness)) - x;
3263 }
3264 else if (x < tw->primitive.highlight_thickness +
3265 tw->primitive.shadow_thickness) {
3266 cursor_width = data->cursorwidth -
3267 (tw->primitive.highlight_thickness +
3268 tw->primitive.shadow_thickness - x);
3269 src_x = data->cursorwidth - cursor_width;
3270 x = tw->primitive.highlight_thickness +
3271 tw->primitive.shadow_thickness;
3272 }
3273 if (y + data->cursorheight > tw->text.inner_widget->core.height -
3274 (tw->primitive.highlight_thickness +
3275 tw->primitive.shadow_thickness)) {
3276 cursor_height = data->cursorheight -
3277 ((y + data->cursorheight) -
3278 (tw->text.inner_widget->core.height -
3279 (tw->primitive.highlight_thickness +
3280 tw->primitive.shadow_thickness)));
3281 }
3282 if (cursor_width > 0 && cursor_height > 0)
3283 {
3284 XCopyArea(XtDisplay((Widget)tw), data->ibeam_off,
3285 XtWindow((Widget)tw), data->save_gc, src_x, 0,
3286 (unsigned int)cursor_width,
3287 (unsigned int)cursor_height, x, y);
3288 }
3289 }
3290 }
3291 }
3292
3293
3294
3295 static void
3296 ChangeHOffset(XmTextWidget tw,
3297 int newhoffset,
3298 #if NeedWidePrototypes
3299 int redisplay_hbar)
3300 #else
3301 Boolean redisplay_hbar)
3302 #endif /* NeedWidePrototypes */
3303 {
3304 OutputData data = tw->text.output->data;
3305 int delta;
3306 int width = tw->text.inner_widget->core.width;
3307 int height = tw->text.inner_widget->core.height;
3308 int innerwidth = width - (data->leftmargin + data->rightmargin);
3309 int innerheight = height - (data->topmargin + data->bottommargin);
3310
3311 if (ShouldWordWrap(data, tw) || data->suspend_hoffset) return;
3312
3313 if ((data->scrollhorizontal &&
3314 XmIsScrolledWindow(XtParent(tw))) &&
3315 data->scrollwidth - innerwidth < newhoffset)
3316 newhoffset = data->scrollwidth - innerwidth;
3317
3318 if (newhoffset < 0) newhoffset = 0;
3319 if (newhoffset == data->hoffset) return;
3320
3321 delta = newhoffset - data->hoffset;
3322 data->hoffset = newhoffset;
3323
3324 _XmProcessLock();
3325 posToXYCachedWidget = NULL;
3326 _XmProcessUnlock();
3327 if (XtIsRealized((Widget)tw)) {
3328 _XmTextAdjustGC(tw);
3329 SetNormGC(tw, data->gc, False, False);
3330 if (delta < 0) {
3331 if (width > 0 && innerheight > 0) {
3332 XCopyArea(XtDisplay(tw), XtWindow(tw->text.inner_widget),
3333 XtWindow(tw->text.inner_widget), data->gc,
3334 data->leftmargin, data->topmargin, width, innerheight,
3335 data->leftmargin - delta, data->topmargin);
3336 /* clear left margin + delta change */
3337 if ((int) (data->leftmargin - delta -
3338 (tw->primitive.shadow_thickness +
3339 tw->primitive.highlight_thickness)) < innerwidth)
3340 XClearArea(XtDisplay(tw), XtWindow(tw),
3341 tw->primitive.shadow_thickness +
3342 tw->primitive.highlight_thickness,
3343 data->topmargin, data->leftmargin -
3344 (tw->primitive.shadow_thickness +
3345 tw->primitive.highlight_thickness) - delta,
3346 innerheight, False);
3347 /* clear right margin */
3348 if ((int) (data->rightmargin-
3349 (tw->primitive.shadow_thickness +
3350 tw->primitive.highlight_thickness)) > 0)
3351 XClearArea(XtDisplay(tw), XtWindow(tw),
3352 data->leftmargin + innerwidth, data->topmargin,
3353 data->rightmargin -
3354 (tw->primitive.shadow_thickness +
3355 tw->primitive.highlight_thickness),
3356 innerheight,
3357 False);
3358 data->exposehscroll++;
3359 }
3360 RedrawRegion(tw, data->leftmargin, 0, -delta, height);
3361 } else {
3362 if (innerwidth - delta > 0 && innerheight > 0) {
3363 XCopyArea(XtDisplay(tw), XtWindow(tw->text.inner_widget),
3364 XtWindow(tw->text.inner_widget), data->gc,
3365 data->leftmargin + delta, data->topmargin,
3366 innerwidth - delta, innerheight,
3367 data->leftmargin, data->topmargin);
3368 /* clear right margin + delta change */
3369 XClearArea(XtDisplay(tw), XtWindow(tw),
3370 data->leftmargin + innerwidth - delta, data->topmargin,
3371 delta + data->rightmargin -
3372 (tw->primitive.shadow_thickness +
3373 tw->primitive.highlight_thickness),
3374 innerheight, False);
3375 /* clear left margin */
3376 if (data->leftmargin - (int)(tw->primitive.shadow_thickness +
3377 tw->primitive.highlight_thickness)
3378 > 0)
3379 XClearArea(XtDisplay(tw), XtWindow(tw),
3380 tw->primitive.shadow_thickness +
3381 tw->primitive.highlight_thickness,
3382 data->topmargin, data->leftmargin -
3383 (tw->primitive.shadow_thickness +
3384 tw->primitive.highlight_thickness),
3385 innerheight, False);
3386 data->exposehscroll++;
3387 } else {
3388 /* clear all text */
3389 XClearArea(XtDisplay(tw), XtWindow(tw),
3390 tw->primitive.shadow_thickness +
3391 tw->primitive.highlight_thickness,
3392 data->topmargin,
3393 width - 2 *(tw->primitive.shadow_thickness +
3394 tw->primitive.highlight_thickness),
3395 innerheight,
3396 False);
3397 data->exposehscroll++;
3398 }
3399 RedrawRegion(tw, width - data->rightmargin - delta, 0,
3400 delta, height);
3401 }
3402 }
3403
3404 if (redisplay_hbar) _XmRedisplayHBar(tw);
3405 }
3406
3407
3408 static void
3409 ChangeVOffset(XmTextWidget tw,
3410 int newvoffset,
3411 #if NeedWidePrototypes
3412 int redisplay_vbar)
3413 #else
3414 Boolean redisplay_vbar)
3415 #endif /* NeedWidePrototypes */
3416 {
3417 OutputData data = tw->text.output->data;
3418 int delta = 0;
3419 int width = tw->text.inner_widget->core.width;
3420 int height = tw->text.inner_widget->core.height;
3421 int innerwidth = width - (data->leftmargin + data->rightmargin);
3422 int innerheight = height - (data->topmargin + data->bottommargin);
3423
3424 if (ShouldWordWrap(data, tw) || data->suspend_voffset) return;
3425
3426 if ((data->scrollvertical &&
3427 XmIsScrolledWindow(XtParent(tw))) &&
3428 data->scrollheight - innerheight < newvoffset)
3429 newvoffset = data->scrollheight - innerheight;
3430
3431 if (newvoffset < 0) newvoffset = 0;
3432 if (newvoffset == data->voffset) return;
3433
3434 delta = newvoffset - data->voffset;
3435 data->voffset = newvoffset;
3436
3437 _XmProcessLock();
3438 posToXYCachedWidget = NULL;
3439 _XmProcessUnlock();
3440 if (XtIsRealized((Widget)tw)) {
3441 _XmTextAdjustGC(tw);
3442 SetNormGC(tw, data->gc, False, False);
3443 if (delta < 0) {
3444 if (height > 0 && innerwidth > 0) {
3445 XCopyArea(XtDisplay(tw), XtWindow(tw->text.inner_widget),
3446 XtWindow(tw->text.inner_widget), data->gc,
3447 data->leftmargin, data->topmargin, innerwidth, height,
3448 data->leftmargin, data->topmargin - delta);
3449 /* clear top margin + delta change */
3450 if ((int) (data->topmargin -
3451 (tw->primitive.shadow_thickness +
3452 tw->primitive.highlight_thickness) - delta) < innerheight)
3453 XClearArea(XtDisplay(tw), XtWindow(tw),
3454 data->leftmargin,
3455 tw->primitive.shadow_thickness +
3456 tw->primitive.highlight_thickness,
3457 innerwidth, data->topmargin -
3458 (tw->primitive.shadow_thickness +
3459 tw->primitive.highlight_thickness) - delta, False);
3460 /* clear right margin */
3461 if ((int) data->topmargin -
3462 (int) (tw->primitive.shadow_thickness +
3463 tw->primitive.highlight_thickness) > 0)
3464 XClearArea(XtDisplay(tw), XtWindow(tw),
3465 data->leftmargin, data->topmargin + innerheight,
3466 innerwidth, data->bottommargin -
3467 (tw->primitive.shadow_thickness +
3468 tw->primitive.highlight_thickness),
3469 False);
3470 data->exposevscroll++;
3471 }
3472 RedrawRegion(tw, 0, data->topmargin, width, -delta);
3473 } else {
3474 if (innerheight - delta > 0 && innerwidth > 0) {
3475 XCopyArea(XtDisplay(tw), XtWindow(tw->text.inner_widget),
3476 XtWindow(tw->text.inner_widget), data->gc,
3477 data->leftmargin, data->topmargin + delta,
3478 innerwidth, innerheight - delta,
3479 data->leftmargin, data->topmargin);
3480 /* clear bottom margin + delta change */
3481 XClearArea(XtDisplay(tw), XtWindow(tw),
3482 data->leftmargin,
3483 data->topmargin + innerheight - delta,
3484 innerwidth,
3485 delta + data->bottommargin -
3486 (tw->primitive.shadow_thickness +
3487 tw->primitive.highlight_thickness),
3488 False);
3489 /* clear top margin */
3490 if (data->topmargin - (int)(tw->primitive.shadow_thickness +
3491 tw->primitive.highlight_thickness)
3492 > 0)
3493 XClearArea(XtDisplay(tw), XtWindow(tw),
3494 data->leftmargin,
3495 tw->primitive.shadow_thickness +
3496 tw->primitive.highlight_thickness,
3497 innerwidth,
3498 data->topmargin -
3499 (tw->primitive.shadow_thickness +
3500 tw->primitive.highlight_thickness),
3501 False);
3502 data->exposevscroll++;
3503 } else {
3504 /* clear all text */
3505 XClearArea(XtDisplay(tw), XtWindow(tw),
3506 data->leftmargin,
3507 tw->primitive.shadow_thickness +
3508 tw->primitive.highlight_thickness,
3509 innerwidth,
3510 height - 2 *(tw->primitive.shadow_thickness +
3511 tw->primitive.highlight_thickness),
3512 False);
3513 data->exposevscroll++;
3514 }
3515 RedrawRegion(tw, 0, height - data->bottommargin - delta,
3516 width, delta);
3517 }
3518 }
3519
3520 if (redisplay_vbar) _XmRedisplayVBar(tw);
3521 }
3522
3523
3524 static void
3525 DrawInsertionPoint(XmTextWidget tw,
3526 XmTextPosition position,
3527 OnOrOff onoroff)
3528 {
3529 OutputData data = tw->text.output->data;
3530
3531 if (onoroff == on) {
3532 data->cursor_on +=1;
3533 if (data->blinkrate == 0 || !data->hasfocus)
3534 data->blinkstate = on;
3535 } else {
3536 if ((data->blinkstate == on) && data->cursor_on == 0)
3537 if (data->blinkstate == CurrentCursorState(tw) &&
3538 XtIsRealized((Widget)tw)) {
3539 data->blinkstate = off; /* Toggle blinkstate to off */
3540 data->cursor_on -= 1; /* must be done before PaintCursor */
3541 PaintCursor(tw);
3542 } else
3543 data->cursor_on -= 1;
3544 else
3545 data->cursor_on -= 1;
3546 }
3547
3548 if (data->cursor_on < 0 || !XtIsRealized((Widget)tw))
3549 return;
3550 if (PosToXY(tw, position, &data->insertx, &data->inserty))
3551 PaintCursor(tw);
3552 }
3553
3554 static void
3555 MakePositionVisible(XmTextWidget tw,
3556 XmTextPosition position)
3557 {
3558 OutputData data = tw->text.output->data;
3559 Position x, y;
3560 LineNum line_num;
3561
3562 if (!ShouldWordWrap(data, tw) && PosToXY(tw, position, &x, &y)) {
3563 if(XmDirectionMatch(XmPrim_layout_direction(tw),
3564 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT)) {
3565 if (y <= data->topmargin) {
3566 if (tw->text.edit_mode == XmSINGLE_LINE_EDIT) {
3567 if (position == tw->text.bottom_position)
3568 position = MAX(position - data->rows/2, 0);
3569 } else {
3570 line_num = _XmTextGetTableIndex(tw, position);
3571 if (position == tw->text.bottom_position ||
3572 (line_num < tw->text.total_lines &&
3573 position == tw->text.line_table[line_num+1].start_pos - 1))
3574 position =
3575 MAX(position - (int) data->rows/2,
3576 line_num ? (int) (tw->text.line_table[line_num].start_pos) :
3577 0);
3578 }
3579 (void)PosToXY(tw, position, &x, &y);
3580 }
3581
3582 y += data->voffset;
3583 if (y - data->voffset < data->topmargin) {
3584 ChangeVOffset(tw, y - data->topmargin, True);
3585 } else if (y - data->voffset >
3586 ((Position) (tw->text.inner_widget->core.height -
3587 data->bottommargin))) {
3588 ChangeVOffset(tw, (int) (y) -
3589 (int) (tw->text.inner_widget->core.height) +
3590 (int) (data->bottommargin), True);
3591 }
3592 } else {
3593 if (x <= data->leftmargin) {
3594 if (tw->text.edit_mode == XmSINGLE_LINE_EDIT) {
3595 if (position == tw->text.bottom_position)
3596 position = MAX(position - data->columns/2, 0);
3597 } else {
3598 line_num = _XmTextGetTableIndex(tw, position);
3599 if (position == tw->text.bottom_position ||
3600 (line_num < tw->text.total_lines &&
3601 position == tw->text.line_table[line_num+1].start_pos - 1))
3602 position =
3603 MAX(position - data->columns/2,
3604 line_num ? (int) (tw->text.line_table[line_num].start_pos) : 0);
3605 }
3606 (void)PosToXY(tw, position, &x, &y);
3607 }
3608
3609 x += data->hoffset;
3610 if (x - data->hoffset < data->leftmargin) {
3611 ChangeHOffset(tw, x - data->leftmargin, True);
3612 } else if (x - data->hoffset >
3613 ((Position) (tw->text.inner_widget->core.width -
3614 data->rightmargin))) {
3615 ChangeHOffset(tw, (int) (x) -
3616 (int) (tw->text.inner_widget->core.width) +
3617 (int) (data->rightmargin), True);
3618 }
3619 }
3620 }
3621 }
3622
3623 static void
3624 BlinkInsertionPoint(XmTextWidget tw)
3625 {
3626 OutputData data = tw->text.output->data;
3627
3628 if ((data->cursor_on >=0) &&
3629 data->blinkstate == CurrentCursorState(tw) &&
3630 XtIsRealized((Widget)tw)) {
3631
3632 /* Toggle blink state */
3633 if (data->blinkstate == on) data->blinkstate = off;
3634 else data->blinkstate = on;
3635
3636 PaintCursor(tw);
3637
3638 }
3639 }
3640
3641 static Boolean
3642 MoveLines(XmTextWidget tw,
3643 LineNum fromline,
3644 LineNum toline,
3645 LineNum destline)
3646 {
3647 OutputData data = tw->text.output->data;
3648 if (!XtIsRealized((Widget) tw)) return False;
3649 _XmTextAdjustGC(tw);
3650 SetNormGC(tw, data->gc, False, False);
3651 SetFullGC(tw, data->gc);
3652 if(XmDirectionMatch(XmPrim_layout_direction(tw),
3653 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT)) {
3654 XCopyArea(XtDisplay(tw), XtWindow(tw->text.inner_widget),
3655 XtWindow(tw->text.inner_widget), data->gc,
3656 tw->text.inner_widget->core.width - data->rightmargin -
3657 (Position)data->linewidth * (toline + 1),
3658 tw->primitive.shadow_thickness +
3659 tw->primitive.highlight_thickness,
3660 (Position)data->linewidth * (toline - fromline + 1),
3661 tw->text.inner_widget->core.height -
3662 2 * (tw->primitive.shadow_thickness +
3663 tw->primitive.highlight_thickness),
3664 tw->text.inner_widget->core.width - data->rightmargin -
3665 (Position)data->linewidth *
3666 (destline + toline - fromline + 1),
3667 tw->primitive.shadow_thickness +
3668 tw->primitive.highlight_thickness);
3669 } else {
3670 XCopyArea(XtDisplay(tw), XtWindow(tw->text.inner_widget),
3671 XtWindow(tw->text.inner_widget), data->gc,
3672 tw->primitive.shadow_thickness +
3673 tw->primitive.highlight_thickness,
3674 (Position) data->lineheight * fromline + data->topmargin,
3675 tw->text.inner_widget->core.width -
3676 2 * (tw->primitive.shadow_thickness +
3677 tw->primitive.highlight_thickness),
3678 data->lineheight * (toline - fromline + 1),
3679 tw->primitive.shadow_thickness +
3680 tw->primitive.highlight_thickness,
3681 (Position) data->lineheight * destline + data->topmargin);
3682 }
3683 SetMarginGC(tw, data->gc);
3684 if(XmDirectionMatch(XmPrim_layout_direction(tw),
3685 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT))
3686 data->exposehscroll++;
3687 else
3688 data->exposevscroll++;
3689 return True;
3690 }
3691
3692 /* ARGSUSED */
3693 static void
3694 OutputInvalidate(XmTextWidget tw,
3695 XmTextPosition position,
3696 XmTextPosition topos,
3697 long delta)
3698 {
3699 _XmProcessLock();
3700 posToXYCachedWidget = NULL;
3701 _XmProcessUnlock();
3702 }
3703
3704 static void
3705 RefigureDependentInfo(XmTextWidget tw)
3706 {
3707 OutputData data = tw->text.output->data;
3708
3709 data->columns = data->number_lines;
3710 if(XmDirectionMatch(XmPrim_layout_direction(tw),
3711 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT)) {
3712 data->rows = (short)(((int) tw->core.height -
3713 (data->topmargin + data->bottommargin))
3714 / (int) (data->font_ascent + data->font_descent));
3715
3716 if (data->rows <= 0)
3717 data->rows = 1;
3718 } else {
3719 data->rows = data->number_lines;
3720 data->columns = (short)(((int) tw->core.width -
3721 (data->leftmargin + data->rightmargin))
3722 / (data->averagecharwidth));
3723
3724 if (data->columns <= 0)
3725 data->columns = 1;
3726 }
3727 }
3728
3729 static void
3730 SizeFromRowsCols(XmTextWidget tw,
3731 Dimension *width,
3732 Dimension *height)
3733 {
3734 OutputData data = tw->text.output->data;
3735 short lines = 0;
3736
3737 if (tw->text.edit_mode == XmSINGLE_LINE_EDIT)
3738 lines = 1;
3739 else {
3740 if(XmDirectionMatch(XmPrim_layout_direction(tw),
3741 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT))
3742 lines = data->columns_set;
3743 else
3744 lines = data->rows_set;
3745 }
3746
3747 if(XmDirectionMatch(XmPrim_layout_direction(tw),
3748 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT)) {
3749 *width = (Dimension) ((lines * data->linewidth) +
3750 data->leftmargin + data->rightmargin);
3751
3752 *height = (Dimension) ((data->rows_set *
3753 (data->font_ascent + data->font_descent)) +
3754 data->topmargin + data->bottommargin);
3755 if (tw->text.source->data->length > 0 && data->resizeheight) {
3756 XmTextPosition nextpos;
3757 LineTableExtra extra = NULL;
3758 Boolean past_end = False;
3759 int i;
3760
3761 for (i = 0; i < tw->text.number_lines && !past_end; i++) {
3762 past_end = !MeasureLine(tw, i, tw->text.line[i].start,
3763 &nextpos, &extra);
3764 if (extra) {
3765 if (extra->width > *height)
3766 *height = extra->width;
3767 XtFree((char *)extra);
3768 }
3769 }
3770 }
3771 } else {
3772 *width = (Dimension) ((data->columns_set * data->averagecharwidth) +
3773 data->leftmargin + data->rightmargin);
3774 if (tw->text.source->data->length > 0 && data->resizewidth) {
3775 XmTextPosition nextpos;
3776 LineTableExtra extra = NULL;
3777 Boolean past_end = False;
3778 int i;
3779
3780 for (i = 0; i < tw->text.number_lines && !past_end; i++) {
3781 past_end = !MeasureLine(tw, i, tw->text.line[i].start,
3782 &nextpos, &extra);
3783 if (extra) {
3784 if (extra->width > *width)
3785 *width = extra->width;
3786 XtFree((char *)extra);
3787 }
3788 }
3789 }
3790
3791 *height = (Dimension) ((lines * data->lineheight) +
3792 data->topmargin + data->bottommargin);
3793
3794 }
3795 }
3796
3797 static Boolean
3798 LoadFontMetrics(XmTextWidget tw)
3799 {
3800 OutputData data = tw->text.output->data;
3801 XmFontContext context;
3802 XmFontListEntry next_entry;
3803 XmFontType type_return = XmFONT_IS_FONT;
3804 XtPointer tmp_font;
3805 Boolean have_font_struct = False;
3806 Boolean have_font_set = False;
3807 #ifdef USE_XFT
3808 Boolean have_xft_font = False;
3809 #endif
3810 XFontSetExtents *fs_extents;
3811 XFontStruct *font = NULL;
3812 unsigned long width = 0;
3813 char* font_tag = NULL;
3814
3815 if (!XmFontListInitFontContext(&context, data->fontlist))
3816 XmeWarning((Widget) tw, MSG3);
3817
3818 do {
3819 next_entry = XmFontListNextEntry(context);
3820 if (next_entry
3821 && (tmp_font = XmFontListEntryGetFont(next_entry, &type_return))) {
3822 if (type_return == XmFONT_IS_FONTSET) {
3823 font_tag = XmFontListEntryGetTag(next_entry);
3824 if (!have_font_set) { /* this saves the first fontset found, just in
3825 * case we don't find a default tag set.
3826 */
3827 data->use_fontset = True;
3828 #ifdef USE_XFT
3829 data->use_xft = False;
3830 #endif
3831 data->font = (XFontStruct *)tmp_font;
3832 have_font_struct = True; /* we have a font set, so no need to
3833 * consider future font structs */
3834 have_font_set = True; /* we have a font set. */
3835
3836 if (!strcmp(XmFONTLIST_DEFAULT_TAG, font_tag)) {
3837 if (font_tag) XtFree(font_tag);
3838 break; /* Break out! We've found the one we want. */
3839 }
3840 } else if (!strcmp(XmFONTLIST_DEFAULT_TAG, font_tag)) {
3841 data->font = (XFontStruct *)tmp_font;
3842 have_font_set = True; /* we have a font set. */
3843 if (font_tag) XtFree(font_tag);
3844 break; /* Break out! We've found the one we want. */
3845 }
3846 if (font_tag) XtFree(font_tag);
3847 } else if (type_return == XmFONT_IS_FONT && !have_font_struct) {
3848 data->use_fontset = False;
3849 #ifdef USE_XFT
3850 data->use_xft = False;
3851 #endif
3852 /* save the first one in case no font set is found */
3853 data->font = (XFontStruct*)tmp_font;
3854 data->use_fontset = False;
3855 have_font_struct = True;
3856 #ifdef USE_XFT
3857 } else if (type_return == XmFONT_IS_XFT && !have_xft_font) {
3858 data->use_fontset = False;
3859 data->use_xft = True;
3860 have_xft_font = True;
3861 data->font = (XFontStruct*)tmp_font;
3862 #endif
3863 }
3864 }
3865 } while(next_entry != NULL);
3866
3867 #if USE_XFT
3868 if (!have_font_struct && !have_font_set && !have_xft_font) {
3869 #else
3870 if (!have_font_struct && !have_font_set) {
3871 #endif
3872 XmeWarning ((Widget)tw, MSG4); /* fontlist without font null entry cause
3873 core dump */
3874 return False;
3875 }
3876
3877 XmFontListFreeFontContext(context);
3878
3879 if(data->use_fontset) {
3880 fs_extents = XExtentsOfFontSet((XFontSet)data->font);
3881 if (XmDirectionMatch(XmPrim_layout_direction(tw),
3882 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT)) {
3883 width = (unsigned long)fs_extents->max_ink_extent.width;
3884 } else {
3885 width = (unsigned long)fs_extents->max_logical_extent.width;
3886 }
3887 /* max_logical_extent.y is number of pixels from origin to top of
3888 * rectangle (i.e. y is negative) */
3889 data->font_ascent = -fs_extents->max_logical_extent.y;
3890 data->font_descent = fs_extents->max_logical_extent.height +
3891 fs_extents->max_logical_extent.y;
3892 #ifdef USE_XFT
3893 } else if (data->use_xft) {
3894 width = ((XftFont*)data->font)->max_advance_width;
3895 data->font_ascent = ((XftFont*)data->font)->ascent;
3896 data->font_descent = ((XftFont*)data->font)->descent;
3897 #endif
3898 } else {
3899 font = data->font;
3900 data->font_ascent = font->max_bounds.ascent;
3901 data->font_descent = font->max_bounds.descent;
3902 if (XmDirectionMatch(XmPrim_layout_direction(tw),
3903 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT)) {
3904 width = font->max_bounds.rbearing - font->max_bounds.lbearing;
3905 } else {
3906 if ((!XGetFontProperty(font, XA_QUAD_WIDTH, &width)) || width == 0) {
3907 if (font->per_char && font->min_char_or_byte2 <= '0' &&
3908 font->max_char_or_byte2 >= '0')
3909 width = font->per_char['0' - font->min_char_or_byte2].width;
3910 else
3911 width = font->max_bounds.width;
3912 }
3913 }
3914 }
3915 if (XmDirectionMatch(XmPrim_layout_direction(tw),
3916 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT)) {
3917 if (width <= 0) width = 1;
3918 data->linewidth = width;
3919 data->averagecharwidth = (int) width;
3920 data->tabheight = (int)(8 * (data->font_ascent + data->font_descent));
3921 } else {
3922 data->lineheight = data->font_descent + data->font_ascent;
3923 if (width <= 0) width = 1;
3924 data->averagecharwidth = (int) width; /* This assumes there will be no
3925 truncation */
3926 if (data->use_fontset) {
3927 data->tabwidth = 8 * XmbTextEscapement((XFontSet)data->font, "0", 1);
3928 /* Check if tabwidth was not calculated correctly */
3929 if (data->tabwidth == 0)
3930 data->tabwidth = (int)(8 * width);
3931 } else {
3932 data->tabwidth = (int)(8 * width); /* This assumes there will be no
3933 truncation */
3934 }
3935 }
3936 return True;
3937 }
3938
3939
3940 static Boolean
3941 SetXOCOrientation(XmTextWidget tw,
3942 XOC oc,
3943 XOrientation orientation)
3944 {
3945 XOM om;
3946 XOMOrientation orients;
3947 int i = 0;
3948
3949 if(!oc)
3950 return False;
3951
3952 om = XOMOfOC(oc);
3953 if(om) {
3954 if(!XGetOMValues(om, XNQueryOrientation, &orients, NULL)) {
3955 for (i = 0 ; i < orients.num_orientation ; i++) {
3956 if(orients.orientation[i] == orientation) {
3957 if(XSetOCValues(oc, XNOrientation, orientation, NULL)!=NULL)
3958 return False;
3959 }
3960 }
3961 } else return False;
3962 } else return False;
3963
3964 return True;
3965 }
3966
3967
3968 static void
3969 LoadGCs(XmTextWidget tw,
3970 Pixel background,
3971 Pixel foreground)
3972 {
3973 OutputData data = tw->text.output->data;
3974 XGCValues values;
3975 unsigned long valueMask = (GCFunction | GCForeground | GCBackground |
3976 GCGraphicsExposures);
3977 unsigned long dynamicMask = GCClipMask;
3978 unsigned long unusedMask = GCClipXOrigin | GCClipYOrigin | GCFont;
3979
3980 /*
3981 *Get GC for saving area under cursor.
3982 */
3983 values.function = GXcopy;
3984 values.foreground = tw->primitive.foreground;
3985 values.background = tw->core.background_pixel;
3986 values.graphics_exposures = (Bool) False;
3987 if (data->save_gc != NULL)
3988 XtReleaseGC((Widget) tw, data->save_gc);
3989 data->save_gc = XtAllocateGC((Widget) tw, tw->core.depth, valueMask,
3990 &values, dynamicMask, unusedMask);
3991
3992 /*
3993 * Get GC for drawing text.
3994 */
3995
3996 #if USE_XFT
3997 if (!data->use_fontset && !data->use_xft) {
3998 #else
3999 if (!data->use_fontset) {
4000 #endif
4001 valueMask |= GCFont;
4002 values.font = data->font->fid;
4003 }
4004
4005 values.graphics_exposures = (Bool) True;
4006 values.foreground = foreground ^ background;
4007 values.background = 0;
4008 if (data->gc != NULL)
4009 XtReleaseGC((Widget) tw, data->gc);
4010 dynamicMask |= GCForeground | GCBackground | GCFillStyle | GCStipple;
4011 data->gc = XtAllocateGC((Widget) tw, tw->core.depth, valueMask,
4012 &values, dynamicMask, 0);
4013
4014 /* Create a temporary GC - change it later in MakeIBeamStencil */
4015 valueMask |= GCStipple | GCFillStyle;
4016 values.graphics_exposures = (Bool) False;
4017 values.stipple = data->stipple_tile;
4018 values.fill_style = FillStippled;
4019 if (data->imagegc != NULL)
4020 XtReleaseGC((Widget) tw, data->imagegc);
4021 dynamicMask |= (GCTileStipXOrigin | GCTileStipYOrigin | GCFunction);
4022 data->imagegc = XtAllocateGC((Widget) tw, tw->core.depth,
4023 valueMask, &values, dynamicMask, 0);
4024 }
4025
4026 static void
4027 MakeIBeamOffArea(XmTextWidget tw,
4028 #if NeedWidePrototypes
4029 int width,
4030 int height)
4031 #else
4032 Dimension width,
4033 Dimension height)
4034 #endif /* NeedWidePrototypes */
4035 {
4036 OutputData data = tw->text.output->data;
4037 Display *dpy = XtDisplay(tw);
4038 Screen *screen = XtScreen((Widget)tw);
4039
4040 /* Create a pixmap for storing the screen data where the I-Beam will
4041 * be painted */
4042 data->ibeam_off = XCreatePixmap(dpy, RootWindowOfScreen(screen), width,
4043 height, tw->core.depth);
4044
4045 data->refresh_ibeam_off = True;
4046 }
4047
4048 static Pixmap
4049 FindPixmap(
4050 Screen *screen,
4051 char *image_name,
4052 Pixel foreground,
4053 Pixel background,
4054 int depth )
4055 {
4056 XmAccessColorDataRec acc_color_rec;
4057
4058 acc_color_rec.foreground = foreground;
4059 acc_color_rec.background = background;
4060 acc_color_rec.top_shadow_color = XmUNSPECIFIED_PIXEL;
4061 acc_color_rec.bottom_shadow_color = XmUNSPECIFIED_PIXEL;
4062 acc_color_rec.select_color = XmUNSPECIFIED_PIXEL;
4063 acc_color_rec.highlight_color = XmUNSPECIFIED_PIXEL;
4064 return _XmGetColoredPixmap(screen, image_name,
4065 &acc_color_rec, depth, True);
4066 }
4067
4068 static void
4069 MakeIBeamStencil(XmTextWidget tw,
4070 int line_width)
4071 {
4072 Screen *screen = XtScreen((Widget)tw);
4073 char pixmap_name[64];
4074 XGCValues values;
4075 unsigned long valueMask;
4076 OutputData data = tw->text.output->data;
4077
4078 sprintf(pixmap_name, "_XmText_%d_%d", data->cursorheight, line_width);
4079 data->cursor = FindPixmap(screen, pixmap_name, 1, 0, 1);
4080
4081 if (data->cursor == XmUNSPECIFIED_PIXMAP) {
4082 Display *dpy = XtDisplay(tw);
4083 XSegment segments[3];
4084
4085 /* Create a pixmap for the I-Beam stencil */
4086 data->cursor = XCreatePixmap(dpy, XtWindow(tw), data->cursorwidth,
4087 data->cursorheight, 1);
4088
4089 values.foreground = 0;
4090 values.line_width = 0;
4091 values.fill_style = FillSolid;
4092 values.function = GXcopy;
4093 valueMask = GCForeground | GCLineWidth | GCFillStyle | GCFunction;
4094 XChangeGC(dpy, data->cursor_gc, valueMask, &values);
4095
4096 XFillRectangle(dpy, data->cursor, data->cursor_gc, 0, 0, data->cursorwidth,
4097 data->cursorheight);
4098
4099 /* Change the GC for use in "cutting out" the I-Beam shape */
4100 values.foreground = 1;
4101 values.line_width = line_width;
4102 XChangeGC(dpy, data->cursor_gc, GCForeground | GCLineWidth, &values);
4103
4104 /* Draw the segments of the I-Beam */
4105 if(XmDirectionMatch(XmPrim_layout_direction(tw),
4106 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT)) {
4107 /* 1st segment is the left vertical line of the cursor */
4108 segments[0].x1 = 1;
4109 segments[0].y1 = line_width - 1;
4110 segments[0].x2 = 1;
4111 segments[0].y2 = data->cursorheight - 1;
4112
4113 /* 2nd segment is the right vertical line of the cursor */
4114 segments[1].x1 = data->cursorwidth - 1;
4115 segments[1].y1 = line_width - 1;
4116 segments[1].x2 = data->cursorwidth - 1;
4117 segments[1].y2 = data->cursorheight - 1;
4118
4119 /* 3rd segment is the horizontal line of the cursor */
4120 segments[2].x1 = 0;
4121 segments[2].y1 = data->cursorheight >> 1;
4122 segments[2].x2 = data->cursorwidth;
4123 segments[2].y2 = data->cursorheight >> 1;
4124 } else {
4125 /* 1st segment is the top horizontal line of the 'I' */
4126 segments[0].x1 = 0;
4127 segments[0].y1 = line_width - 1;
4128 segments[0].x2 = data->cursorwidth;
4129 segments[0].y2 = line_width - 1;
4130
4131 /* 2nd segment is the bottom horizontal line of the 'I' */
4132 segments[1].x1 = 0;
4133 segments[1].y1 = data->cursorheight - 1;
4134 segments[1].x2 = data->cursorwidth;
4135 segments[1].y2 = data->cursorheight - 1;
4136
4137 /* 3rd segment is the vertical line of the 'I' */
4138 segments[2].x1 = data->cursorwidth >> 1;
4139 segments[2].y1 = line_width;
4140 segments[2].x2 = data->cursorwidth >> 1;
4141 segments[2].y2 = data->cursorheight - 1;
4142 }
4143
4144 /* Draw the segments onto the cursor */
4145 XDrawSegments(dpy, data->cursor, data->cursor_gc, segments, 3);
4146
4147 /* Install the cursor for pixmap caching */
4148 (void) _XmCachePixmap(data->cursor, screen, pixmap_name, 1, 0,
4149 1, data->cursorwidth, data->cursorheight);
4150
4151 }
4152
4153 valueMask = (GCForeground | GCBackground | GCStipple |
4154 GCFillStyle);
4155 if (tw->text.input->data->overstrike) {
4156 values.background = values.foreground =
4157 tw->core.background_pixel ^ tw->primitive.foreground;
4158 } else {
4159 values.foreground = tw->primitive.foreground;
4160 values.background = tw->core.background_pixel;
4161 }
4162 values.stipple = data->cursor;
4163 values.fill_style = FillStippled;
4164 XChangeGC(XtDisplay(tw), data->imagegc, valueMask, &values);
4165
4166 }
4167
4168
4169
4170 /* The IBeam Stencil must have already been created before this routine
4171 * is called.
4172 */
4173 /* ARGSUSED */
4174 static void
4175 MakeAddModeCursor(XmTextWidget tw,
4176 int line_width)
4177 {
4178 Screen *screen = XtScreen((Widget)tw);
4179 char pixmap_name[64];
4180 OutputData data = tw->text.output->data;
4181
4182 sprintf(pixmap_name, "_XmText_AddMode_%d_%d",
4183 data->cursorheight,line_width);
4184
4185 data->add_mode_cursor = FindPixmap(screen, pixmap_name, 1, 0, 1);
4186
4187 if (data->add_mode_cursor == XmUNSPECIFIED_PIXMAP) {
4188 XtGCMask valueMask;
4189 XGCValues values;
4190 Display *dpy = XtDisplay((Widget)tw);
4191
4192 data->add_mode_cursor = XCreatePixmap(dpy, XtWindow((Widget)tw),
4193 data->cursorwidth,
4194 data->cursorheight, 1);
4195
4196 values.function = GXcopy;
4197 valueMask = GCFunction;
4198 XChangeGC(dpy, data->cursor_gc, valueMask, &values);
4199
4200 XCopyArea(dpy, data->cursor, data->add_mode_cursor, data->cursor_gc, 0, 0,
4201 data->cursorwidth, data->cursorheight, 0, 0);
4202
4203 valueMask = (GCTile | GCFillStyle | GCForeground |
4204 GCBackground | GCFunction | GCTileStipXOrigin);
4205 values.function = GXand;
4206 values.tile = data->stipple_tile;
4207 values.fill_style = FillTiled;
4208 values.ts_x_origin = -1;
4209 values.foreground = tw->primitive.foreground;
4210 values.background = tw->core.background_pixel;
4211
4212 XChangeGC(XtDisplay((Widget)tw), data->cursor_gc, valueMask, &values);
4213
4214 XFillRectangle(dpy, data->add_mode_cursor, data->cursor_gc,
4215 0, 0, data->cursorwidth, data->cursorheight);
4216
4217 /* Install the pixmap for pixmap caching */
4218 _XmCachePixmap(data->add_mode_cursor, screen, pixmap_name, 1, 0,
4219 1, data->cursorwidth, data->cursorheight);
4220
4221 }
4222 }
4223
4224 static void
4225 MakeCursors(XmTextWidget tw)
4226 {
4227 OutputData data = tw->text.output->data;
4228 Screen *screen = XtScreen(tw);
4229 int line_width = 1;
4230 int oldwidth = data->cursorwidth;
4231 int oldheight = data->cursorheight;
4232
4233 if (!XtIsRealized((Widget) tw)) return;
4234
4235 if(XmDirectionMatch(XmPrim_layout_direction(tw),
4236 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT)) {
4237 data->cursorwidth = data->averagecharwidth;
4238 data->cursorheight = 5;
4239
4240 /* setup parameters to make a thicker I-Beam */
4241 if (data->cursorwidth > 19) {
4242 data->cursorheight++;
4243 line_width = 2;
4244 }
4245 } else {
4246 data->cursorwidth = 5;
4247 data->cursorheight = data->font_ascent + data->font_descent;
4248
4249 /* setup parameters to make a thicker I-Beam */
4250 if (data->cursorheight > 19) {
4251 data->cursorwidth++;
4252 line_width = 2;
4253 }
4254 }
4255
4256 if (data->cursor == XmUNSPECIFIED_PIXMAP ||
4257 data->add_mode_cursor == XmUNSPECIFIED_PIXMAP ||
4258 data->ibeam_off == XmUNSPECIFIED_PIXMAP ||
4259 oldheight != data->cursorheight || oldwidth != data->cursorwidth) {
4260
4261 if (data->cursor_gc == NULL) {
4262 unsigned long valueMask = 0;
4263 XGCValues values;
4264 unsigned long dynamicMask =
4265 GCForeground | GCLineWidth | GCTile | GCFillStyle |
4266 GCBackground | GCFunction | GCTileStipXOrigin;
4267
4268 data->cursor_gc = XtAllocateGC((Widget)tw, 1, valueMask, &values,
4269 dynamicMask, 0);
4270 }
4271
4272 /* Remove old ibeam_off pixmap */
4273 if (data->ibeam_off != XmUNSPECIFIED_PIXMAP)
4274 XFreePixmap(XtDisplay((Widget)tw), data->ibeam_off);
4275
4276 /* Remove old insert stencil */
4277 if (data->cursor != XmUNSPECIFIED_PIXMAP)
4278 (void) XmDestroyPixmap(screen, data->cursor);
4279
4280 /* Remove old add mode cursor */
4281 if (data->add_mode_cursor != XmUNSPECIFIED_PIXMAP)
4282 (void) XmDestroyPixmap(screen, data->add_mode_cursor);
4283
4284 /* Create area in which to save text located underneath I beam */
4285 MakeIBeamOffArea(tw, MAX((int) data->cursorwidth,
4286 (int) data->cursorheight >> 1),
4287 data->cursorheight);
4288
4289 /* Create a new i-beam stencil */
4290 MakeIBeamStencil(tw, line_width);
4291
4292 /* Create a new add_mode cursor */
4293 MakeAddModeCursor(tw, line_width);
4294 }
4295
4296 if (tw->text.input->data->overstrike)
4297 data->cursorwidth = data->cursorheight >> 1;
4298 }
4299
4300 static void
4301 OutputGetValues(Widget w,
4302 ArgList args,
4303 Cardinal num_args)
4304 {
4305 XmTextWidget tw = (XmTextWidget) w;
4306
4307 RefigureDependentInfo(tw);
4308 XtGetSubvalues((XtPointer) tw->text.output->data, output_resources,
4309 XtNumber(output_resources), args, num_args);
4310 }
4311
4312
4313 static Boolean
4314 CKCols(ArgList args,
4315 Cardinal num_args)
4316 {
4317 register ArgList arg;
4318 for (arg = args; num_args != 0; num_args--, arg++) {
4319 if (strcmp(arg->name, XmNcolumns) == 0) return(True);
4320 }
4321 return(False);
4322 }
4323
4324
4325 static Boolean
4326 CKRows(ArgList args,
4327 Cardinal num_args)
4328 {
4329 register ArgList arg;
4330 for (arg = args; num_args != 0; num_args--, arg++) {
4331 if (strcmp(arg->name, XmNrows) == 0) return(True);
4332 }
4333 return(False);
4334 }
4335
4336
4337 /* ARGSUSED */
4338 static Boolean
4339 OutputSetValues(Widget oldw,
4340 Widget reqw,
4341 Widget new_w,
4342 ArgList args,
4343 Cardinal *num_args)
4344 {
4345 #define CK(fld) (newdata->fld != data->fld)
4346 #define CP(fld) (data->fld = newdata->fld)
4347
4348 XmTextWidget oldtw = (XmTextWidget) oldw;
4349 XmTextWidget newtw = (XmTextWidget) new_w;
4350 OutputData data = newtw->text.output->data;
4351 OutputDataRec newdatarec;
4352 OutputData newdata = &newdatarec;
4353 Boolean needgcs = False;
4354 Boolean newsize = False;
4355 Boolean o_redisplay = False;
4356 Dimension new_width = newtw->core.width;/* save in case something changes */
4357 Dimension new_height = newtw->core.height;/* these values during SetValues*/
4358 XPoint xmim_point;
4359 XRectangle xmim_area;
4360 Arg im_args[17];
4361 Cardinal n = 0;
4362
4363 *newdata = *data;
4364 XtSetSubvalues((XtPointer) newdata, output_resources,
4365 XtNumber(output_resources), args, *num_args);
4366
4367 if (newtw->core.background_pixel != oldtw->core.background_pixel) {
4368 needgcs = True;
4369 }
4370
4371 if (newtw->primitive.foreground != oldtw->primitive.foreground) {
4372 needgcs = True;
4373 }
4374
4375 if (CK(fontlist) || CK(rendertable)) {
4376 XmRenderTableFree(data->fontlist);
4377 if (CK(rendertable)) {
4378 if (newdata->rendertable == NULL)
4379 newdata->fontlist = XmeGetDefaultRenderTable(new_w, XmTEXT_FONTLIST);
4380 else
4381 newdata->fontlist = XmRenderTableCopy(newdata->rendertable, NULL, 0);
4382 } else if (CK(fontlist)) {
4383 if (newdata->fontlist == NULL)
4384 newdata->fontlist = XmeGetDefaultRenderTable(new_w, XmTEXT_FONTLIST);
4385 else
4386 newdata->fontlist = XmRenderTableCopy(newdata->fontlist, NULL, 0);
4387 }
4388 newdata->rendertable = newdata->fontlist;
4389 CP(fontlist);
4390 CP(rendertable);
4391 if(! LoadFontMetrics(newtw)) {
4392 XmRenderTableFree(newdata->fontlist);
4393 newdata->fontlist = XmeGetDefaultRenderTable(new_w, XmTEXT_FONTLIST);
4394 newdata->rendertable = newdata->fontlist;
4395 CP(fontlist);
4396 CP(rendertable);
4397 (void)LoadFontMetrics(newtw);
4398 }
4399
4400 /* We want to be able to connect to an IM if XmNfontList has changed. */
4401 if (newtw->text.editable) {
4402 newtw->text.editable = False;
4403 XmTextSetEditable(new_w, True);
4404 }
4405
4406 if(XmDirectionMatch(XmPrim_layout_direction(newtw),
4407 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT)) {
4408 if (data->vbar) {
4409 XmNavigatorDataRec nav_data;
4410 int new_sliderSize = 0;
4411
4412 data->ignorevbar = True;
4413
4414 new_sliderSize = newtw->text.inner_widget->core.height
4415 - (data->topmargin + data->bottommargin);
4416
4417 if (new_sliderSize < 1) new_sliderSize = 1;
4418 if (new_sliderSize > data->scrollheight)
4419 new_sliderSize = data->scrollheight;
4420
4421 nav_data.value.y = data->voffset;
4422 nav_data.minimum.y = 0;
4423 nav_data.maximum.y = data->scrollheight;
4424 nav_data.slider_size.y = new_sliderSize;
4425 nav_data.increment.y = data->font_ascent + data->font_descent;
4426 nav_data.page_increment.y = 0;
4427
4428 nav_data.dimMask = NavigDimensionY;
4429 nav_data.valueMask = NavValue|NavMinimum|NavMaximum|
4430 NavSliderSize|NavIncrement;
4431 _XmSFUpdateNavigatorsValue(XtParent(new_w), &nav_data, True);
4432
4433 data->ignorevbar = False;
4434
4435 }
4436 } else {
4437 if (data->hbar) {
4438 XmNavigatorDataRec nav_data;
4439 int new_sliderSize;
4440
4441 data->ignorehbar = True;
4442
4443 new_sliderSize = newtw->text.inner_widget->core.width
4444 - (data->leftmargin + data->rightmargin);
4445
4446 if (new_sliderSize < 1) new_sliderSize = 1;
4447 if (new_sliderSize > data->scrollwidth)
4448 new_sliderSize = data->scrollwidth;
4449
4450 nav_data.value.x = data->hoffset;
4451 nav_data.minimum.x = 0;
4452 nav_data.maximum.x = data->scrollwidth;
4453 nav_data.slider_size.x = new_sliderSize;
4454 nav_data.increment.x = data->averagecharwidth;
4455 nav_data.page_increment.x = 0;
4456
4457 nav_data.dimMask = NavigDimensionX;
4458 nav_data.valueMask = NavValue|NavMinimum|NavMaximum|
4459 NavSliderSize|NavIncrement;
4460 _XmSFUpdateNavigatorsValue(XtParent(new_w), &nav_data, True);
4461
4462 data->ignorehbar = False;
4463
4464 }
4465 }
4466 o_redisplay = True;
4467 needgcs = True;
4468 newsize = True;
4469 }
4470
4471 if (data->fontlist != oldtw->text.output->data->fontlist ||
4472 newtw->core.background_pixel != oldtw->core.background_pixel ||
4473 newtw->primitive.foreground != oldtw->primitive.foreground) {
4474 XtSetArg(im_args[n], XmNbackground, newtw->core.background_pixel); n++;
4475 XtSetArg(im_args[n], XmNforeground, newtw->primitive.foreground); n++;
4476 XtSetArg(im_args[n], XmNfontList, data->fontlist); n++;
4477 }
4478
4479 /* Don't word wrap, have multiple row or have vertical scrollbars
4480 if editMode is single_line */
4481 if (newtw->text.edit_mode != oldtw->text.edit_mode) {
4482 if (newtw->text.edit_mode == XmSINGLE_LINE_EDIT)
4483 newdata->rows = 1;
4484
4485 if(XmDirectionMatch(XmPrim_layout_direction(newtw),
4486 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT)) {
4487 if (newtw->text.edit_mode == XmSINGLE_LINE_EDIT) {
4488 if (data->hbar) XtUnmanageChild(data->hbar);
4489 } else {
4490 if (data->hbar) XtManageChild(data->hbar);
4491 }
4492 if (newtw->text.edit_mode == XmSINGLE_LINE_EDIT) {
4493 if (data->vbar) XtUnmanageChild(data->vbar);
4494 } else {
4495 if (data->vbar) XtManageChild(data->vbar);
4496 }
4497 } else {
4498 if (data->hbar) XtManageChild(data->hbar);
4499 if (newtw->text.edit_mode != XmSINGLE_LINE_EDIT) {
4500 if (data->vbar) XtManageChild(data->vbar);
4501 } else {
4502 if (data->vbar) XtUnmanageChild(data->vbar);
4503 }
4504 }
4505 o_redisplay = True;
4506 }
4507
4508 /* what is called margin, in this code, is composed of margin, shadow, and
4509 highlight. Previously, only margin was accomodated. This addition
4510 may not be very clever, but it blends in with the rest of the way this
4511 code works.
4512 */
4513
4514 if (newtw->text.margin_width != oldtw->text.margin_width ||
4515 newtw->text.margin_height != oldtw->text.margin_height ||
4516 newtw->primitive.shadow_thickness !=
4517 oldtw->primitive.shadow_thickness ||
4518 newtw->primitive.highlight_thickness !=
4519 oldtw->primitive.highlight_thickness)
4520 {
4521 data->leftmargin = data->rightmargin = newtw->text.margin_width +
4522 newtw->primitive.shadow_thickness +
4523 newtw->primitive.highlight_thickness;
4524 data->topmargin = data->bottommargin = newtw->text.margin_height +
4525 newtw->primitive.shadow_thickness +
4526 newtw->primitive.highlight_thickness;
4527 o_redisplay = True;
4528 newsize = True;
4529 }
4530
4531 if (CK(wordwrap)) {
4532 if(XmDirectionMatch(XmPrim_layout_direction(newtw),
4533 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT)) {
4534 /* If we are turning on wrapping, we don't want any horiz. offset */
4535 if (!data->wordwrap) ChangeVOffset(newtw, 0, True);
4536
4537 if (data->vbar) {
4538 if (newdata->wordwrap) {
4539 XmNavigatorDataRec nav_data;
4540
4541 data->ignorevbar = True;
4542
4543 nav_data.value.y = 0;
4544 nav_data.minimum.y = 0;
4545 nav_data.maximum.y = 1;
4546 nav_data.slider_size.y = 1;
4547 nav_data.increment.y = 0;
4548 nav_data.page_increment.y = 0;
4549
4550 nav_data.dimMask = NavigDimensionY;
4551 nav_data.valueMask = NavValue|NavMinimum|NavMaximum|
4552 NavSliderSize;
4553 _XmSFUpdateNavigatorsValue(XtParent(new_w), &nav_data, True);
4554
4555 data->ignorevbar = False;
4556
4557 data->voffset = 0;
4558 } else {
4559 _XmRedisplayVBar(newtw);
4560 }
4561 }
4562 } else {
4563 /* If we are turning on wrapping, we don't want any horiz. offset */
4564 if (!data->wordwrap) ChangeHOffset(newtw, 0, True);
4565
4566 if (data->hbar) {
4567 if (newdata->wordwrap) {
4568 XmNavigatorDataRec nav_data;
4569
4570 data->ignorehbar = True;
4571
4572 nav_data.value.x = 0;
4573 nav_data.minimum.x = 0;
4574 nav_data.maximum.x = 1;
4575 nav_data.slider_size.x = 1;
4576 nav_data.increment.x = 0;
4577 nav_data.page_increment.x = 0;
4578
4579 nav_data.dimMask = NavigDimensionX;
4580 nav_data.valueMask = NavValue|NavMinimum|NavMaximum|
4581 NavSliderSize;
4582 _XmSFUpdateNavigatorsValue(XtParent(new_w), &nav_data, True);
4583
4584 data->ignorehbar = False;
4585
4586 data->hoffset = 0;
4587 } else {
4588 _XmRedisplayHBar(newtw);
4589 }
4590 }
4591 }
4592
4593 CP(wordwrap);
4594
4595 _XmTextRealignLineTable(newtw, NULL, 0, 0, 0, PASTENDPOS);
4596
4597 /* If we've just turned off wrapping, get new top_character by scanning */
4598 /* left from the current top character until we find a new line. */
4599 if (!oldtw->text.output->data->wordwrap) {
4600 if (data->resizeheight)
4601 newtw->text.top_character = newtw->text.new_top = 0;
4602 else {
4603 newtw->text.top_character = (*newtw->text.source->Scan)
4604 (newtw->text.source, newtw->text.top_character,
4605 XmSELECT_LINE, XmsdLeft, 1, False);
4606 newtw->text.new_top = newtw->text.top_character;
4607 }
4608 }
4609
4610 if (newtw->text.top_character)
4611 newtw->text.top_line = CountLines(newtw, 0,
4612 newtw->text.top_character);
4613
4614
4615 o_redisplay = True;
4616 }
4617
4618 if (data->hasfocus && XtIsSensitive((Widget)newtw) && CK(blinkrate)) {
4619 if (newdata->blinkrate == 0) {
4620 data->blinkstate = on;
4621 if (data->timerid) {
4622 XtRemoveTimeOut(data->timerid);
4623 data->timerid = (XtIntervalId)0;
4624 }
4625 } else if (data->timerid == (XtIntervalId)0) {
4626 data->timerid =
4627 XtAppAddTimeOut(XtWidgetToApplicationContext(new_w),
4628 (unsigned long) newdata->blinkrate,
4629 HandleTimer, (XtPointer) newtw);
4630 }
4631 }
4632 CP(blinkrate);
4633
4634 CP(resizewidth);
4635 CP(resizeheight);
4636
4637 CP(cursor_position_visible);
4638
4639 if (needgcs) {
4640 EraseInsertionPoint(newtw);
4641 LoadGCs(newtw, newtw->core.background_pixel,
4642 newtw->primitive.foreground);
4643 if (XtIsRealized(new_w)) {
4644 MakeCursors(newtw);
4645 }
4646 TextDrawInsertionPoint(newtw);
4647 o_redisplay = True;
4648 }
4649
4650 if (newdata->rows <= 0) {
4651 XmeWarning(new_w, MSG1);
4652 newdata->rows = data->rows;
4653 }
4654
4655 if (newdata->columns <= 0) {
4656 XmeWarning(new_w, MSG2);
4657 newdata->columns = data->columns;
4658 }
4659
4660 /* Process arglist to verify the a value is being set */
4661 if (CKCols(args, *num_args))
4662 data->columns_set = newdata->columns_set = newdata->columns;
4663
4664 /* Process arglist to verify the a value is being set */
4665 if (CKRows(args, *num_args))
4666 data->rows_set = newdata->rows_set = newdata->rows;
4667
4668 if (!(new_width != oldtw->core.width &&
4669 new_height != oldtw->core.height)) {
4670 if (CK(columns) || CK(rows) || newsize) {
4671 Dimension width, height;
4672 SizeFromRowsCols(newtw, &width, &height);
4673 if(XmDirectionMatch(XmPrim_layout_direction(newtw),
4674 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT)) {
4675 if (new_width == oldtw->core.width)
4676 newtw->core.width = width;
4677 data->minwidth = newtw->core.width;
4678 if (new_height == oldtw->core.height) {
4679 newtw->core.height = height;
4680 data->minheight =
4681 (Dimension)((data->rows_set *
4682 (data->font_ascent + data->font_descent)) +
4683 data->topmargin + data->bottommargin);
4684 } else {
4685 data->minheight = new_height;
4686 }
4687 } else {
4688 if (new_width == oldtw->core.width) {
4689 newtw->core.width = width;
4690 data->minwidth =
4691 (Dimension)((data->columns_set * data->averagecharwidth) +
4692 data->leftmargin + data->rightmargin);
4693 } else {
4694 data->minwidth = new_width;
4695 }
4696 if (new_height == oldtw->core.height)
4697 newtw->core.height = height;
4698 data->minheight = newtw->core.height;
4699 }
4700 CP(columns);
4701 CP(rows);
4702 o_redisplay = True;
4703 }
4704 } else {
4705 newtw->core.width = new_width;
4706 data->minwidth = new_width;
4707 newtw->core.height = new_height;
4708 data->minheight = new_height;
4709 }
4710
4711 PosToXY(newtw, newtw->text.cursor_position, &xmim_point.x, &xmim_point.y);
4712 (void)_XmTextGetDisplayRect((Widget)newtw, &xmim_area);
4713 XtSetArg(im_args[n], XmNbackgroundPixmap,
4714 newtw->core.background_pixmap);n++;
4715 XtSetArg(im_args[n], XmNspotLocation, &xmim_point); n++;
4716 XtSetArg(im_args[n], XmNarea, &xmim_area); n++;
4717 XtSetArg(im_args[n], XmNlineSpace, newdata->lineheight); n++;
4718 XmImSetValues(new_w, im_args, n);
4719
4720 return (o_redisplay);
4721 #undef CK
4722 #undef CP
4723 }
4724
4725 static void
4726 NotifyResized(Widget w,
4727 #if NeedWidePrototypes
4728 int o_create)
4729 #else
4730 Boolean o_create)
4731 #endif /* NeedWidePrototypes */
4732 {
4733 XmTextWidget tw = (XmTextWidget) w;
4734 OutputData data = tw->text.output->data;
4735 Boolean resizewidth = data->resizewidth;
4736 Boolean resizeheight = data->resizeheight;
4737 XmTextPosition linestart = 0;
4738 XmTextPosition position;
4739 XPoint xmim_point;
4740 XRectangle xmim_area;
4741 int n;
4742 XmTextBlockRec block;
4743 Arg args[10];
4744
4745 data->resizewidth = data->resizeheight = False;
4746 if(XmDirectionMatch(XmPrim_layout_direction(tw),
4747 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT)) {
4748 data->number_lines = tw->text.inner_widget->core.width -
4749 data->leftmargin - data->rightmargin;
4750 if (data->number_lines < (int) data->linewidth || !data->linewidth)
4751 data->number_lines = 1;
4752 else
4753 data->number_lines /= (int) data->linewidth;
4754
4755 if (tw->text.top_character)
4756 {
4757 tw->text.top_line = CountLines(tw, 0,
4758 tw->text.top_character);
4759 if (tw->text.total_lines >= data->number_lines &&
4760 (tw->text.total_lines - tw->text.top_line) < data->number_lines)
4761 tw->text.top_line = tw->text.total_lines - data->number_lines;
4762 tw->text.new_top = tw->text.line_table[tw->text.top_line].start_pos;
4763 }
4764 } else {
4765 data->number_lines = tw->text.inner_widget->core.height -
4766 data->topmargin - data->bottommargin;
4767 if (data->number_lines < (int) data->lineheight || !data->lineheight)
4768 data->number_lines = 1;
4769 else
4770 data->number_lines /= (int) data->lineheight;
4771
4772 if (tw->text.top_character)
4773 {
4774 tw->text.top_line = CountLines(tw, 0,
4775 tw->text.top_character);
4776 if (tw->text.total_lines >= data->number_lines &&
4777 (tw->text.total_lines - tw->text.top_line) < data->number_lines)
4778 tw->text.top_line = tw->text.total_lines - data->number_lines;
4779 tw->text.new_top = tw->text.line_table[tw->text.top_line].start_pos;
4780 }
4781 }
4782
4783 if (data->vbar)
4784 {
4785 int local_total, new_size;
4786 XmNavigatorDataRec nav_data;
4787 #ifdef FIX_1396
4788 int new_voffset = 0;
4789 #endif
4790
4791 if(XmDirectionMatch(XmPrim_layout_direction(tw),
4792 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT)) {
4793 new_size = tw->text.inner_widget->core.height
4794 - (data->topmargin + data->bottommargin);
4795 if (new_size < 1) new_size = 1;
4796 if (new_size > data->scrollheight) new_size = data->scrollheight;
4797 #ifdef FIX_1396
4798 new_voffset = data->voffset;
4799 if (new_voffset > data->scrollheight - new_size)
4800 new_voffset = data->scrollheight - new_size;
4801 #endif
4802 data->ignorevbar = True;
4803 #ifdef FIX_1396
4804 nav_data.value.y = new_voffset;
4805 #else
4806 nav_data.value.y = data->voffset;
4807 #endif
4808 nav_data.minimum.y = 0;
4809 nav_data.maximum.y = data->scrollheight;
4810 nav_data.slider_size.y = new_size;
4811 nav_data.page_increment.y = new_size;
4812 } else {
4813 data->ignorevbar = True;
4814
4815 if (tw->text.top_line + tw->text.number_lines >
4816 tw->text.total_lines)
4817 local_total = tw->text.top_line + tw->text.number_lines;
4818 else
4819 local_total = tw->text.total_lines;
4820
4821 if (local_total >= tw->text.number_lines)
4822 new_size = tw->text.number_lines;
4823 else
4824 new_size = local_total;
4825 if (new_size + tw->text.top_line > local_total)
4826 new_size = local_total - tw->text.top_line;
4827
4828 nav_data.value.y = tw->text.top_line;
4829 nav_data.minimum.y = 0;
4830 nav_data.maximum.y = local_total;
4831 nav_data.slider_size.y = new_size;
4832 nav_data.page_increment.y = (data->number_lines > 1)?
4833 (data->number_lines - 1): 1;
4834 }
4835
4836 nav_data.dimMask = NavigDimensionY;
4837 nav_data.valueMask = NavValue|NavMinimum|NavMaximum|
4838 NavSliderSize|NavPageIncrement;
4839 _XmSFUpdateNavigatorsValue(XtParent((Widget)tw), &nav_data, True);
4840
4841 data->ignorevbar = False;
4842
4843 }
4844
4845 if (data->hbar)
4846 {
4847 XmNavigatorDataRec nav_data;
4848 int new_size = 0;
4849 int local_total = 0;
4850 #ifdef FIX_1396
4851 int new_hoffset = 0;
4852 #endif
4853 if(XmDirectionMatch(XmPrim_layout_direction(tw),
4854 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT)) {
4855 data->ignorehbar = True;
4856
4857 if (tw->text.top_line + tw->text.number_lines >
4858 tw->text.total_lines)
4859 local_total = tw->text.top_line + tw->text.number_lines;
4860 else
4861 local_total = tw->text.total_lines;
4862
4863 if (local_total >= tw->text.number_lines)
4864 new_size = tw->text.number_lines;
4865 else
4866 new_size = local_total;
4867 if (new_size + tw->text.top_line > local_total)
4868 new_size = local_total - tw->text.top_line;
4869
4870 nav_data.value.x = tw->text.top_line;
4871 nav_data.minimum.x = 0;
4872 nav_data.maximum.x = local_total;
4873 nav_data.slider_size.x = new_size;
4874 nav_data.page_increment.x = (data->number_lines > 1)?
4875 (data->number_lines - 1): 1;
4876 } else {
4877 new_size = tw->text.inner_widget->core.width
4878 - (data->leftmargin + data->rightmargin);
4879 if (new_size < 1) new_size = 1;
4880 if (new_size > data->scrollwidth) new_size = data->scrollwidth;
4881 #ifdef FIX_1396
4882 new_hoffset = data->hoffset;
4883 if (new_hoffset > data->scrollwidth - new_size)
4884 new_hoffset = data->scrollwidth - new_size;
4885 #endif
4886 data->ignorehbar = True;
4887 #ifdef FIX_1396
4888 nav_data.value.x = new_hoffset;
4889 #else
4890 nav_data.value.x = data->hoffset;
4891 #endif
4892 nav_data.minimum.x = 0;
4893 nav_data.maximum.x = data->scrollwidth;
4894 nav_data.slider_size.x = new_size;
4895 nav_data.page_increment.x = new_size;
4896 }
4897
4898 nav_data.dimMask = NavigDimensionX;
4899 nav_data.valueMask = NavValue|NavMinimum|NavMaximum|
4900 NavSliderSize|NavPageIncrement;
4901 _XmSFUpdateNavigatorsValue(XtParent((Widget)tw), &nav_data, True);
4902
4903 data->ignorehbar = False;
4904 }
4905
4906 RefigureDependentInfo(tw);
4907 if (resizewidth)
4908 data->columns_set = data->columns;
4909 if (resizeheight)
4910 data->rows_set = data->rows;
4911
4912 if (XtIsRealized(w)) {
4913 XClearWindow(XtDisplay(tw), XtWindow(tw->text.inner_widget));
4914 data->refresh_ibeam_off = True;
4915 }
4916
4917 if (!o_create) /* False only if called from OutputCreate */
4918 _XmTextInvalidate(tw, (XmTextPosition) 0, (XmTextPosition) 0,
4919 NODELTA);
4920
4921 /* the new size grew enough to include new text */
4922
4923 if (XmDirectionMatch(XmPrim_layout_direction(tw),
4924 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT)) {
4925 if (tw->text.edit_mode == XmSINGLE_LINE_EDIT) {
4926 /* this assumes only one line of text! (linestart = 0) */
4927 #ifdef AS_TEXTFIELD
4928 ChangeVOffset(tw, 0, True);
4929 #else
4930 int text_height = data->topmargin; /* to make tab calculation correct */
4931 int new_height = tw->core.height - (data->topmargin + data->bottommargin);
4932
4933 position = (*tw->text.source->Scan)(tw->text.source, linestart,
4934 XmSELECT_LINE, XmsdRight,
4935 1, False);
4936 while (linestart < position) {
4937 linestart = (*tw->text.source->ReadSource) (tw->text.source,
4938 linestart, position,
4939 &block);
4940 text_height += FindHeight(tw, text_height, &block, 0, block.length);
4941 }
4942 text_height -= data->topmargin;
4943 if (text_height - new_height < data->voffset) {
4944 /* space top over */
4945 if (text_height - new_height >= 0)
4946 ChangeVOffset(tw, text_height - new_height, True);
4947 else
4948 ChangeVOffset(tw, 0, True);
4949 }
4950 #endif
4951 if (tw->text.auto_show_cursor_position) {
4952 MakePositionVisible(tw, tw->text.cursor_position);
4953 }
4954 } else _XmRedisplayVBar(tw);
4955 } else {
4956 if (tw->text.edit_mode == XmSINGLE_LINE_EDIT) {
4957 /* this assumes only one line of text! (linestart = 0) */
4958 #ifdef AS_TEXTFIELD
4959 ChangeHOffset(tw, 0, True);
4960 #else
4961 int text_width = data->leftmargin; /* to make tab calculation correct */
4962 int new_width = tw->core.width - (data->leftmargin + data->rightmargin);
4963
4964 position = (*tw->text.source->Scan)(tw->text.source, linestart,
4965 XmSELECT_LINE, XmsdRight,
4966 1, False);
4967 while (linestart < position) {
4968 linestart = (*tw->text.source->ReadSource) (tw->text.source,
4969 linestart, position, &block);
4970 text_width += FindWidth(tw, text_width, &block, 0, block.length);
4971 }
4972 text_width -= data->leftmargin;
4973 if (text_width - new_width < data->hoffset) {
4974 /* space left over */
4975 if (text_width - new_width >= 0)
4976 ChangeHOffset(tw, text_width - new_width, True);
4977 else
4978 ChangeHOffset(tw, 0, True);
4979 }
4980 #endif
4981 if (tw->text.auto_show_cursor_position) {
4982 MakePositionVisible(tw, tw->text.cursor_position);
4983 }
4984 } else _XmRedisplayHBar(tw);
4985 }
4986
4987 data->resizewidth = resizewidth;
4988 data->resizeheight = resizeheight;
4989
4990 if (XtIsRealized(w))
4991 _XmTextDrawShadow(tw);
4992
4993 /* Text is now rediplayed at the correct location, so force the tw to
4994 * refresh the putback area.
4995 */
4996
4997 data->refresh_ibeam_off = True;
4998
4999 /* Somehow we need to let the input method know that the window has
5000 * changed size (for case of over-the-spot). Try telling it that
5001 * the cursor position has changed and hopefully it will re-evaluate
5002 * the position/visibility/... of the pre-edit window.
5003 */
5004
5005 PosToXY(tw, tw->text.cursor_position, &xmim_point.x, &xmim_point.y);
5006 (void)_XmTextGetDisplayRect((Widget)tw, &xmim_area);
5007 n = 0;
5008 XtSetArg(args[n], XmNspotLocation, &xmim_point); n++;
5009 XtSetArg(args[n], XmNarea, &xmim_area); n++;
5010 XmImSetValues(w, args, n);
5011 }
5012
5013 /* ARGSUSED */
5014 static void
5015 HandleTimer(XtPointer closure,
5016 XtIntervalId *id)
5017 {
5018 XmTextWidget tw = (XmTextWidget) closure;
5019 OutputData data = tw->text.output->data;
5020 if (data->blinkrate != 0)
5021 data->timerid =
5022 XtAppAddTimeOut(XtWidgetToApplicationContext((Widget) tw),
5023 (unsigned long)data->blinkrate,
5024 HandleTimer, (XtPointer) closure);
5025 if (data->hasfocus && XtIsSensitive((Widget)tw)) BlinkInsertionPoint(tw);
5026 }
5027
5028 /*****************************************************************************
5029 * To make TextOut a True "Object" this function should be a class function. *
5030 *****************************************************************************/
5031 void
5032 _XmTextChangeBlinkBehavior(XmTextWidget tw,
5033 #if NeedWidePrototypes
5034 int newvalue)
5035 #else
5036 Boolean newvalue)
5037 #endif /* NeedWidePrototypes */
5038 {
5039 OutputData data = tw->text.output->data;
5040
5041 if (newvalue) {
5042 if (data->blinkrate != 0 && data->timerid == (XtIntervalId)0)
5043 data->timerid =
5044 XtAppAddTimeOut(XtWidgetToApplicationContext((Widget) tw),
5045 (unsigned long)data->blinkrate,
5046 HandleTimer, (XtPointer) tw);
5047 data->blinkstate = on;
5048 } else {
5049 if (data->timerid)
5050 XtRemoveTimeOut(data->timerid);
5051 data->timerid = (XtIntervalId)0;
5052 }
5053 }
5054
5055 /* ARGSUSED */
5056
5057 static void
5058 HandleFocusEvents(Widget w,
5059 XtPointer closure,
5060 XEvent *event,
5061 Boolean *cont)
5062 {
5063 XmTextWidget tw = (XmTextWidget) w;
5064 OutputData data = tw->text.output->data;
5065 Boolean newhasfocus = data->hasfocus;
5066 XmAnyCallbackStruct cb;
5067 XPoint xmim_point;
5068 XRectangle xmim_area;
5069 Arg args[10];
5070 int n = 0;
5071
5072 PosToXY(tw, tw->text.cursor_position, &xmim_point.x, &xmim_point.y);
5073 (void)_XmTextGetDisplayRect((Widget)tw, &xmim_area);
5074
5075 switch (event->type) {
5076 case FocusIn:
5077 if (event->xfocus.send_event && !(newhasfocus)) {
5078 cb.reason = XmCR_FOCUS;
5079 cb.event = event;
5080 XtCallCallbackList (w, tw->text.focus_callback, (Opaque) &cb);
5081 newhasfocus = True;
5082
5083 n = 0;
5084 XtSetArg(args[n], XmNspotLocation, &xmim_point); n++;
5085 XtSetArg(args[n], XmNarea, &xmim_area); n++;
5086 XmImSetFocusValues(w, args, n);
5087 }
5088 break;
5089 case FocusOut:
5090 if (event->xfocus.send_event && newhasfocus) {
5091 newhasfocus = False;
5092 XmImUnsetFocus(w);
5093 }
5094 break;
5095 case EnterNotify:
5096 if ((_XmGetFocusPolicy(w) != XmEXPLICIT) && !(newhasfocus) &&
5097 event->xcrossing.focus &&
5098 (event->xcrossing.detail != NotifyInferior)) {
5099 cb.reason = XmCR_FOCUS;
5100 cb.event = event;
5101 XtCallCallbackList (w, tw->text.focus_callback, (Opaque) &cb);
5102 newhasfocus = True;
5103 n = 0;
5104 XtSetArg(args[n], XmNspotLocation, &xmim_point); n++;
5105 XtSetArg(args[n], XmNarea, &xmim_area); n++;
5106 XmImSetFocusValues(w, args, n);
5107 }
5108 break;
5109 case LeaveNotify:
5110 if ((_XmGetFocusPolicy(w) != XmEXPLICIT) && newhasfocus &&
5111 event->xcrossing.focus &&
5112 (event->xcrossing.detail != NotifyInferior)) {
5113 newhasfocus = False;
5114 XmImUnsetFocus(w);
5115 }
5116 break;
5117 }
5118 if (newhasfocus != data->hasfocus) {
5119 if (newhasfocus && XtIsSensitive((Widget)tw)) {
5120 EraseInsertionPoint(tw);
5121 data->hasfocus = newhasfocus;
5122 data->blinkstate = off;
5123 _XmTextChangeBlinkBehavior(tw, True);
5124 TextDrawInsertionPoint(tw);
5125 } else {
5126 _XmTextChangeBlinkBehavior(tw, False);
5127 EraseInsertionPoint(tw);
5128 data->hasfocus = newhasfocus;
5129 data->blinkstate = on;
5130 TextDrawInsertionPoint(tw);
5131 }
5132 }
5133 }
5134
5135
5136
5137 /* ARGSUSED */
5138 static void
5139 HandleGraphicsExposure(Widget w,
5140 XtPointer closure,
5141 XEvent *event,
5142 Boolean *cont)
5143 {
5144 XmTextWidget tw = (XmTextWidget) w;
5145 OutputData data = tw->text.output->data;
5146 if (event->xany.type == GraphicsExpose) {
5147 XGraphicsExposeEvent *xe = (XGraphicsExposeEvent *) event;
5148 if (data->exposehscroll != 0) {
5149 xe->x = 0;
5150 xe->width = tw->core.width;
5151 }
5152 if (data->exposevscroll != 0) {
5153 xe->y = 0;
5154 xe->height = tw->core.height;
5155 }
5156 RedrawRegion(tw, xe->x, xe->y, xe->width, xe->height);
5157 if (xe->count == 0) {
5158 if (data->exposehscroll) data->exposehscroll--;
5159 if (data->exposevscroll) data->exposevscroll--;
5160 }
5161 }
5162 if (event->xany.type == NoExpose) {
5163 if (data->exposehscroll) data->exposehscroll--;
5164 if (data->exposevscroll) data->exposevscroll--;
5165 }
5166 }
5167
5168
5169 static void
5170 OutputRealize(Widget w,
5171 XtValueMask *valueMask,
5172 XSetWindowAttributes *attributes)
5173 {
5174 XmTextWidget tw = (XmTextWidget) w;
5175
5176 XtCreateWindow(w, (unsigned int) InputOutput, (Visual *) CopyFromParent,
5177 *valueMask, attributes);
5178 MakeCursors(tw);
5179 }
5180
5181
5182 static void
5183 OutputDestroy(Widget w)
5184 {
5185 XmTextWidget tw = (XmTextWidget) w;
5186 OutputData data = tw->text.output->data;
5187
5188 if (data->timerid)
5189 XtRemoveTimeOut(data->timerid);
5190
5191 XtRemoveEventHandler((Widget) tw->text.inner_widget,
5192 FocusChangeMask|EnterWindowMask|LeaveWindowMask,
5193 False, HandleFocusEvents, NULL);
5194
5195 XtRemoveEventHandler((Widget) tw->text.inner_widget,
5196 (EventMask) 0, True, HandleGraphicsExposure,
5197 NULL);
5198
5199 XtReleaseGC(w, data->imagegc);
5200 XtReleaseGC(w, data->gc);
5201 XtReleaseGC(w, data->save_gc);
5202 XtReleaseGC(w, data->cursor_gc);
5203
5204 XmFontListFree(data->fontlist);
5205
5206 if (data->add_mode_cursor != XmUNSPECIFIED_PIXMAP)
5207 (void) XmDestroyPixmap(XtScreen(tw), data->add_mode_cursor);
5208
5209 if (data->cursor != XmUNSPECIFIED_PIXMAP)
5210 (void) XmDestroyPixmap(XtScreen(tw), data->cursor);
5211
5212 if (data->ibeam_off != XmUNSPECIFIED_PIXMAP)
5213 XFreePixmap(XtDisplay((Widget)tw), data->ibeam_off);
5214
5215 XtFree((char *)data);
5216 XtFree((char *)tw->text.output);
5217 _XmProcessLock();
5218 posToXYCachedWidget = NULL;
5219 _XmProcessUnlock();
5220 }
5221
5222 static void
5223 RedrawRegion(XmTextWidget tw,
5224 int x,
5225 int y,
5226 int width,
5227 int height)
5228 {
5229 OutputData data = tw->text.output->data;
5230 int i;
5231 XmTextPosition first, last;
5232
5233 if(XmDirectionMatch(XmPrim_layout_direction(tw),
5234 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT)) {
5235 for (i = x; i < (int) (x + width + data->linewidth); i += data->linewidth) {
5236 first = XYToPos(tw, i, y);
5237 last = XYToPos(tw, i, y + height);
5238 first = (*tw->text.source->Scan)(tw->text.source, first,
5239 XmSELECT_POSITION,
5240 XmsdLeft, 1, True);
5241 last = (*tw->text.source->Scan)(tw->text.source, last,
5242 XmSELECT_POSITION,
5243 XmsdRight, 1, True);
5244 _XmTextMarkRedraw(tw, first, last);
5245 }
5246 } else {
5247 for (i = y; i < (int) (y + height + data->lineheight);
5248 i += data->lineheight) {
5249 first = XYToPos(tw, x, i);
5250 last = XYToPos(tw, x + width, i);
5251 first = (*tw->text.source->Scan)(tw->text.source, first,
5252 XmSELECT_POSITION,
5253 XmsdLeft, 1, True);
5254 last = (*tw->text.source->Scan)(tw->text.source, last,
5255 XmSELECT_POSITION,
5256 XmsdRight, 1, True);
5257 _XmTextMarkRedraw(tw, first, last);
5258 }
5259 }
5260 }
5261
5262 /* ARGSUSED */
5263 static void
5264 OutputExpose(Widget w,
5265 XEvent *event,
5266 Region region)
5267 {
5268 XmTextWidget tw = (XmTextWidget) w;
5269 XExposeEvent *xe = (XExposeEvent *) event;
5270 OutputData data = tw->text.output->data;
5271 Boolean erased_cursor = False;
5272 int old_number_lines = data->number_lines;
5273 Arg im_args[10];
5274 XRectangle xmim_area;
5275 XPoint xmim_point;
5276 int n = 0;
5277 Boolean font_may_have_changed = False;
5278 int offset = 0;
5279
5280 if (tw->text.in_setvalues) {
5281 /* Get here via SetValues. Force x,y of IM and clip origin for
5282 * I-beam in case font changed.
5283 */
5284 tw->text.in_setvalues = False;
5285 font_may_have_changed = True;
5286 }
5287
5288 if (event->xany.type != Expose)
5289 return;
5290
5291 if (XtIsSensitive(w) && data->hasfocus)
5292 _XmTextChangeBlinkBehavior(tw, False);
5293 EraseInsertionPoint(tw);
5294
5295 if(XmDirectionMatch(XmPrim_layout_direction(tw),
5296 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT)) {
5297 data->number_lines = tw->text.inner_widget->core.width -
5298 data->leftmargin - data->rightmargin;
5299 if (data->number_lines < (int) data->linewidth || !data->linewidth)
5300 data->number_lines = 1;
5301 else
5302 data->number_lines /= (int) data->linewidth;
5303
5304 if (data->hbar && old_number_lines != data->number_lines)
5305 {
5306 int local_total, new_size;
5307 XmNavigatorDataRec nav_data;
5308
5309 data->ignorehbar = True;
5310
5311 if (tw->text.top_line + tw->text.number_lines >
5312 tw->text.total_lines)
5313 local_total = tw->text.top_line + tw->text.number_lines;
5314 else
5315 local_total = tw->text.total_lines;
5316
5317 if (local_total >= tw->text.number_lines)
5318 new_size = tw->text.number_lines;
5319 else
5320 new_size = local_total;
5321 if (new_size + tw->text.top_line > local_total)
5322 new_size = local_total - tw->text.top_line;
5323
5324 offset = local_total - (tw->text.number_lines + tw->text.top_line);
5325 nav_data.value.x = offset;
5326 nav_data.minimum.x = 0;
5327 nav_data.maximum.x = local_total;
5328 nav_data.slider_size.x = new_size;
5329 nav_data.page_increment.x = (data->number_lines > 1)?
5330 (data->number_lines - 1): 1;
5331
5332 nav_data.dimMask = NavigDimensionX;
5333 nav_data.valueMask = NavValue|NavMinimum|NavMaximum|
5334 NavSliderSize|NavPageIncrement;
5335 _XmSFUpdateNavigatorsValue(XtParent((Widget)tw), &nav_data, True);
5336
5337 data->ignorehbar = False;
5338 }
5339 } else {
5340 data->number_lines = tw->text.inner_widget->core.height -
5341 data->topmargin - data->bottommargin;
5342 if (data->number_lines < (int) data->lineheight || !data->lineheight)
5343 data->number_lines = 1;
5344 else
5345 data->number_lines /= (int) data->lineheight;
5346
5347 if (data->vbar && old_number_lines != data->number_lines)
5348 {
5349 int local_total, new_size;
5350 XmNavigatorDataRec nav_data;
5351
5352 data->ignorevbar = True;
5353
5354 if (tw->text.top_line + tw->text.number_lines >
5355 tw->text.total_lines)
5356 local_total = tw->text.top_line + tw->text.number_lines;
5357 else
5358 local_total = tw->text.total_lines;
5359
5360 if (local_total >= tw->text.number_lines)
5361 new_size = tw->text.number_lines;
5362 else
5363 new_size = local_total;
5364 if (new_size + tw->text.top_line > local_total)
5365 new_size = local_total - tw->text.top_line;
5366
5367 nav_data.value.y = tw->text.top_line;
5368 nav_data.minimum.y = 0;
5369 nav_data.maximum.y = local_total;
5370 nav_data.slider_size.y = new_size;
5371 nav_data.page_increment.y = (data->number_lines > 1)?
5372 (data->number_lines - 1): 1;
5373
5374 nav_data.dimMask = NavigDimensionY;
5375 nav_data.valueMask = NavValue|NavMinimum|NavMaximum|
5376 NavSliderSize|NavPageIncrement;
5377 _XmSFUpdateNavigatorsValue(XtParent((Widget)tw), &nav_data, True);
5378
5379 data->ignorevbar = False;
5380 }
5381 }
5382
5383 if (!data->handlingexposures) {
5384 _XmTextDisableRedisplay(tw, False);
5385 data->handlingexposures = True;
5386 }
5387 if (data->exposehscroll != 0) {
5388 xe->x = 0;
5389 xe->width = tw->core.width;
5390 }
5391 if (data->exposevscroll != 0) {
5392 xe->y = 0;
5393 xe->height = tw->core.height;
5394 }
5395 if (xe->x == 0 && xe->y == 0 && xe->width == tw->core.width &&
5396 xe->height == tw->core.height)
5397 _XmTextMarkRedraw(tw, (XmTextPosition)0, 9999999);
5398 else {
5399 if (!erased_cursor)
5400 RedrawRegion(tw, xe->x, xe->y, xe->width, xe->height);
5401 }
5402
5403 _XmTextInvalidate(tw, (XmTextPosition) tw->text.top_character,
5404 (XmTextPosition) tw->text.top_character, NODELTA);
5405
5406 _XmTextEnableRedisplay(tw);
5407
5408 data->handlingexposures = False;
5409
5410 _XmTextDrawShadow(tw);
5411
5412 /* If the expose happened because of SetValues, the font may have changed.
5413 * At this point, RefigureLines has run and the tw is relayed out.
5414 * So it is safe to calculate the x,y position of the cursor to pass
5415 * to the IM. And we can reset the clip origin so that the I-Beam will
5416 * be drawn correctly.
5417 */
5418 if (font_may_have_changed) {
5419 EraseInsertionPoint(tw);
5420 TextDrawInsertionPoint(tw);
5421 PosToXY(tw, tw->text.cursor_position, &xmim_point.x,
5422 &xmim_point.y);
5423 (void)_XmTextGetDisplayRect((Widget)tw, &xmim_area);
5424 XtSetArg(im_args[n], XmNspotLocation, &xmim_point); n++;
5425 XtSetArg(im_args[n], XmNarea, &xmim_area); n++;
5426 XmImSetValues(w, im_args, n);
5427 }
5428
5429 if ((data->cursor_on < 0) || (data->blinkstate == off))
5430 data->refresh_ibeam_off = True;
5431
5432 if (XtIsSensitive((Widget)tw) && data->hasfocus)
5433 _XmTextChangeBlinkBehavior(tw, True);
5434 TextDrawInsertionPoint(tw);
5435 }
5436
5437 static void
5438 GetPreferredSize(Widget w,
5439 Dimension *width,
5440 Dimension *height)
5441 {
5442 XmTextWidget tw = (XmTextWidget) w;
5443 OutputData data = tw->text.output->data;
5444
5445 SizeFromRowsCols(tw, width, height);
5446
5447 if (data->resizewidth) {
5448 TextFindNewWidth(tw, width);
5449 if (*width < data->minwidth) *width = data->minwidth;
5450 }
5451
5452 if (data->resizeheight) {
5453 TextFindNewHeight(tw, PASTENDPOS, height);
5454 if (*height < data->minheight) *height = data->minheight;
5455 }
5456
5457 if (*width == 0) *width = 1;
5458 if (*height == 0) *height = 1;
5459 }
5460
5461 /* ARGSUSED */
5462 static void
5463 HandleVBarButtonRelease(Widget w,
5464 XtPointer closure,
5465 XEvent *event,
5466 Boolean *cont)
5467 {
5468 XmTextWidget tw = (XmTextWidget) closure;
5469 OutputData data = tw->text.output->data;
5470
5471 data->suspend_hoffset = False;
5472
5473 EraseInsertionPoint(tw);
5474 XmTextScroll((Widget) tw, 0);
5475 TextDrawInsertionPoint(tw);
5476 }
5477
5478
5479 /* ARGSUSED */
5480 static void
5481 HandleHBarButtonRelease(Widget w,
5482 XtPointer closure,
5483 XEvent *event,
5484 Boolean *cont)
5485 {
5486 XmTextWidget tw = (XmTextWidget) closure;
5487 OutputData data = tw->text.output->data;
5488
5489 data->suspend_voffset = False;
5490
5491 EraseInsertionPoint(tw);
5492 XmTextScroll((Widget) tw, 0);
5493 TextDrawInsertionPoint(tw);
5494 }
5495
5496
5497 /************************************************************************
5498 *
5499 * SliderMove
5500 * Callback for the value changes of navigators.
5501 *
5502 ************************************************************************/
5503 /* ARGSUSED */
5504 static void
5505 SliderMove(Widget w,
5506 XtPointer closure,
5507 XtPointer cd)
5508 {
5509 /* w is a navigator tw */
5510
5511 XmTextWidget tw = (XmTextWidget) closure;
5512 XmNavigatorDataRec nav_data;
5513 int offset, n;
5514 XPoint xmim_point;
5515 XRectangle xmim_area;
5516 Arg args[10];
5517 OutputData data = tw->text.output->data;
5518 int local_total = 0;
5519 int new_top = 0;
5520
5521 /* get the navigator information using the trait getValue since I
5522 cannot use a callback struct */
5523
5524 nav_data.valueMask = NavValue;
5525 ((XmNavigatorTrait)XmeTraitGet((XtPointer) XtClass(w), XmQTnavigator))
5526 ->getValue(w, &nav_data);
5527
5528
5529 /* look at the kind of navigator and make the appropriate update */
5530
5531 if (!data->ignorehbar && (nav_data.dimMask & NavigDimensionX)) {
5532 if(XmDirectionMatch(XmPrim_layout_direction(tw),
5533 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT)) {
5534 data->suspend_voffset = True;
5535 tw->text.hsbar_scrolling = True;
5536 if (tw->text.top_line + tw->text.number_lines > tw->text.total_lines)
5537 local_total = tw->text.top_line + tw->text.number_lines;
5538 else
5539 local_total = tw->text.total_lines;
5540
5541 new_top = local_total - nav_data.value.x - tw->text.number_lines;
5542 offset = nav_data.value.x - tw->text.top_line;
5543 tw->text.top_line = nav_data.value.x;
5544 EraseInsertionPoint(tw);
5545 XmTextScroll((Widget)tw, offset);
5546 TextDrawInsertionPoint(tw);
5547 tw->text.hsbar_scrolling = False;
5548 } else {
5549 offset = nav_data.value.x;
5550 EraseInsertionPoint(tw);
5551 ChangeHOffset(tw, offset, False);
5552 TextDrawInsertionPoint(tw);
5553 }
5554
5555 PosToXY(tw, tw->text.cursor_position, &xmim_point.x, &xmim_point.y);
5556 (void)_XmTextGetDisplayRect((Widget)tw, &xmim_area);
5557 n = 0;
5558 XtSetArg(args[n], XmNarea, &xmim_area); n++;
5559 XtSetArg(args[n], XmNspotLocation, &xmim_point); n++;
5560 XmImSetValues(w, args, n);
5561 data->suspend_voffset = False;
5562 }
5563
5564 if (!data->ignorevbar && (nav_data.dimMask & NavigDimensionY)) {
5565 if(XmDirectionMatch(XmPrim_layout_direction(tw),
5566 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT)) {
5567 offset = nav_data.value.y;
5568 EraseInsertionPoint(tw);
5569 ChangeVOffset(tw, offset, False);
5570 TextDrawInsertionPoint(tw);
5571 } else {
5572 data->suspend_hoffset = True;
5573
5574 tw->text.vsbar_scrolling = True;
5575 offset = nav_data.value.y - tw->text.top_line;
5576 tw->text.top_line = nav_data.value.y;
5577 EraseInsertionPoint(tw);
5578 XmTextScroll((Widget)tw, offset);
5579 TextDrawInsertionPoint(tw);
5580
5581 tw->text.vsbar_scrolling = False;
5582 }
5583 PosToXY(tw, tw->text.cursor_position, &xmim_point.x, &xmim_point.y);
5584 (void)_XmTextGetDisplayRect((Widget)tw, &xmim_area);
5585 n = 0;
5586 XtSetArg(args[n], XmNarea, &xmim_area); n++;
5587 XtSetArg(args[n], XmNspotLocation, &xmim_point); n++;
5588 XmImSetValues(w, args, n);
5589 data->suspend_hoffset = False;
5590 }
5591
5592 /* now update the other navigator value */
5593 _XmSFUpdateNavigatorsValue(XtParent((Widget)tw), &nav_data, False);
5594
5595
5596 }
5597
5598
5599 /* Public routines. */
5600
5601 /*****************************************************************************
5602 * To make TextOut a True "Object" this function should be a class function. *
5603 *****************************************************************************/
5604 void
5605 _XmTextOutputCreate(Widget wid,
5606 ArgList args,
5607 Cardinal num_args)
5608 {
5609 XmTextWidget tw = (XmTextWidget) wid;
5610 Output output;
5611 OutputData data;
5612 Dimension width, height;
5613 XmScrollFrameTrait scrollFrameTrait;
5614
5615 tw->text.output = output = (Output)
5616 XtMalloc((unsigned) sizeof(OutputRec));
5617 output->data = data = (OutputData)
5618 XtMalloc((unsigned) sizeof(OutputDataRec));
5619
5620 XtGetSubresources(wid, (XtPointer)data, NULL, NULL, output_resources,
5621 XtNumber(output_resources), args, num_args);
5622
5623 if (output->data->scrollleftside == XmDYNAMIC_BOOL) {
5624 if (XmDirectionMatch(XmPrim_layout_direction(tw),
5625 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT))
5626 output->data->scrollleftside = True;
5627 else
5628 output->data->scrollleftside = False;
5629 }
5630
5631 output->XYToPos = XYToPos;
5632 output->PosToXY = PosToXY;
5633 output->MeasureLine = MeasureLine;
5634 output->Draw = Draw;
5635 output->DrawInsertionPoint = DrawInsertionPoint;
5636 output->MakePositionVisible = MakePositionVisible;
5637 output->MoveLines = MoveLines;
5638 output->Invalidate = OutputInvalidate;
5639 output->GetPreferredSize = GetPreferredSize;
5640 output->GetValues = OutputGetValues;
5641 output->SetValues = OutputSetValues;
5642 output->realize = OutputRealize;
5643 output->destroy = OutputDestroy;
5644 output->resize = NotifyResized;
5645 output->expose = OutputExpose;
5646
5647 data->insertx = data->inserty = -99;
5648 data->suspend_hoffset = False;
5649 data->hoffset = 0;
5650 data->scrollwidth = 1;
5651 data->exposehscroll = data->exposevscroll = False;
5652 data->stipple_tile = _XmGetInsensitiveStippleBitmap((Widget) tw);
5653 data->add_mode_cursor = XmUNSPECIFIED_PIXMAP;
5654 data->ibeam_off = XmUNSPECIFIED_PIXMAP;
5655 data->cursor = XmUNSPECIFIED_PIXMAP;
5656 data->timerid = (XtIntervalId)0;
5657 data->font = NULL;
5658 data->scrollheight = 1;
5659 data->voffset = 0;
5660 data->suspend_voffset = False;
5661
5662 /* copy over the fontlist/rendertable */
5663 /* Final result stored in fontlist since that's what the rest of the
5664 * code is expecting, but rendertable takes precedence since that's the
5665 * model for 2.0.
5666 */
5667 if ((data->fontlist == NULL) && (data->rendertable == NULL)) {
5668 data->fontlist =
5669 XmRenderTableCopy(XmeGetDefaultRenderTable(wid, XmTEXT_FONTLIST),
5670 NULL, 0);
5671 }
5672 else if (data->rendertable != NULL)
5673 data->fontlist = XmRenderTableCopy(data->rendertable, NULL, 0);
5674 else data->fontlist = XmRenderTableCopy(data->fontlist, NULL, 0);
5675 if(!LoadFontMetrics(tw)) {
5676 XmFontListFree(data->fontlist);
5677 data->fontlist = XmRenderTableCopy(
5678 XmeGetDefaultRenderTable(wid, XmTEXT_FONTLIST), NULL, 0);
5679 (void)!LoadFontMetrics(tw);
5680 }
5681 data->rendertable = data->fontlist;
5682
5683 data->cursorwidth = 5;
5684 data->cursorheight = data->font_ascent + data->font_descent;
5685 tw->text.inner_widget = wid;
5686 data->leftmargin = data->rightmargin = tw->text.margin_width +
5687 tw->primitive.shadow_thickness +
5688 tw->primitive.highlight_thickness;
5689 data->topmargin = data->bottommargin = tw->text.margin_height +
5690 tw->primitive.shadow_thickness +
5691 tw->primitive.highlight_thickness;
5692
5693 /* Don't word wrap, have multiple row or have vertical scrollbars
5694 if editMode is single_line */
5695 if (tw->text.edit_mode == XmSINGLE_LINE_EDIT) {
5696 if(XmDirectionMatch(XmPrim_layout_direction(tw),
5697 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT))
5698 data->columns = 1;
5699 else
5700 data->rows = 1;
5701 }
5702
5703 /* Don't grow in width if word wrap is on */
5704 if (tw->text.edit_mode != XmSINGLE_LINE_EDIT &&
5705 data->wordwrap) {
5706 if(XmDirectionMatch(XmPrim_layout_direction(tw),
5707 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT))
5708 data->resizeheight = False;
5709 else
5710 data->resizewidth = False;
5711 }
5712
5713 if (data->rows <= 0) {
5714 if (data->rows < 0)
5715 XmeWarning(wid, MSG1);
5716
5717 if(XmDirectionMatch(XmPrim_layout_direction(tw),
5718 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT))
5719 data->rows = 20;
5720 else
5721 data->rows = 1;
5722 }
5723
5724 if (data->columns <= 0) {
5725 if (data->columns < 0)
5726 XmeWarning(wid, MSG2);
5727
5728 if(XmDirectionMatch(XmPrim_layout_direction(tw),
5729 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT))
5730 data->columns = 1;
5731 else
5732 data->columns = 20;
5733 }
5734
5735 /* Initialize columns_set and rows_set for Query Geometry. Also
5736 * used in SizeFromRowsCols().
5737 */
5738 data->columns_set = data->columns;
5739 data->rows_set = data->rows;
5740
5741 SizeFromRowsCols(tw, &width, &height);
5742
5743 if (tw->core.width == 0)
5744 tw->core.width = width;
5745 if (tw->core.height == 0)
5746 tw->core.height = height;
5747
5748 /* initialize number_lines before RefigureDependentInfo() */
5749 if(XmDirectionMatch(XmPrim_layout_direction(tw),
5750 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT)) {
5751 data->number_lines = tw->text.inner_widget->core.width -
5752 data->leftmargin - data->rightmargin;
5753 if (data->number_lines < (int) data->linewidth || !data->linewidth)
5754 data->number_lines = 1;
5755 else
5756 data->number_lines /= (int) data->linewidth;
5757 } else {
5758 data->number_lines = tw->text.inner_widget->core.height -
5759 data->topmargin - data->bottommargin;
5760 if (data->number_lines < (int) data->lineheight || !data->lineheight)
5761 data->number_lines = 1;
5762 else
5763 data->number_lines /= (int) data->lineheight;
5764 }
5765
5766 if (tw->core.height != height || tw->core.width != width)
5767 RefigureDependentInfo(tw);
5768
5769 /* reset columns_set and rows_set after RefigureDependentInfo() */
5770 data->columns_set = data->columns;
5771 data->rows_set = data->rows;
5772 data->prevW = tw->core.width;
5773 data->prevH = tw->core.height;
5774 data->minwidth = tw->core.width;
5775 data->minheight = tw->core.height;
5776
5777 data->imagegc = NULL;
5778 data->gc = NULL;
5779 data->save_gc = NULL;
5780 data->cursor_gc = NULL;
5781 data->has_rect = False;
5782
5783 LoadGCs(tw, tw->core.background_pixel,
5784 tw->primitive.foreground);
5785
5786
5787 /****************
5788 *
5789 * Now look at our parent and see if it's a non inited ScrollFrame.
5790 * If it is, create the navigators
5791 * and set up all the scrolling stuff using the trait.
5792 *
5793 */
5794 scrollFrameTrait = (XmScrollFrameTrait)
5795 XmeTraitGet((XtPointer) XtClass(wid->core.parent), XmQTscrollFrame);
5796
5797 if (scrollFrameTrait != NULL &&
5798 !(scrollFrameTrait -> getInfo (wid->core.parent, NULL, NULL, NULL))) {
5799 int n;
5800 Arg arglist[30];
5801 Arg swarglist[1];
5802
5803 /***********************
5804 set up the default move callback, so that our navigator gets
5805 associated nicely by the scrollFrame */
5806 scrollFrameTrait -> init (wid->core.parent, SliderMove, wid);
5807
5808 if (data->scrollhorizontal) {
5809 data->resizewidth = False;
5810 data->ignorehbar = False;
5811
5812 n = 0;
5813 /* Force to use pixels for shadowThickness */
5814 XtSetArg(arglist[n], XmNunitType, XmPIXELS); n++;
5815 XtSetArg(arglist[n], XmNshadowThickness,
5816 tw->primitive.shadow_thickness); n++;
5817
5818 XtSetArg(arglist[n], XmNorientation, XmHORIZONTAL); n++;
5819
5820 XtSetArg(arglist[n], XmNtraversalOn, False); n++;
5821 XtSetArg(arglist[n], XmNhighlightThickness, 0); n++;
5822
5823 data->hbar = XmCreateScrollBar(XtParent(tw), "HorScrollBar",
5824 arglist, n);
5825
5826 if(XmDirectionMatch(XmPrim_layout_direction(tw),
5827 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT)) {
5828 if (tw->text.edit_mode != XmSINGLE_LINE_EDIT)
5829 XtManageChild(data->hbar);
5830
5831 XtAddEventHandler(data->hbar, (EventMask)ButtonReleaseMask,
5832 False, HandleHBarButtonRelease, (Opaque)tw);
5833 } else
5834 XtManageChild(data->hbar);
5835
5836
5837 } else data->hbar = NULL;
5838
5839 if (data->scrollvertical) {
5840 data->resizeheight = False;
5841 data->ignorevbar = False;
5842
5843 n = 0;
5844 /* Force to use pixels for shadowThickness */
5845 XtSetArg(arglist[n], XmNunitType, XmPIXELS); n++;
5846 XtSetArg(arglist[n], XmNshadowThickness,
5847 tw->primitive.shadow_thickness); n++;
5848
5849 XtSetArg(arglist[n], XmNorientation, XmVERTICAL); n++;
5850
5851 XtSetArg(arglist[n], XmNtraversalOn, False); n++;
5852 XtSetArg(arglist[n], XmNhighlightThickness, 0); n++;
5853
5854
5855 data->vbar = XmCreateScrollBar(XtParent(tw),
5856 "VertScrollBar", arglist, n);
5857
5858 if(XmDirectionMatch(XmPrim_layout_direction(tw),
5859 XmTOP_TO_BOTTOM_RIGHT_TO_LEFT)) {
5860 XtManageChild(data->vbar);
5861 } else {
5862 if (tw->text.edit_mode != XmSINGLE_LINE_EDIT)
5863 XtManageChild(data->vbar);
5864
5865 XtAddEventHandler(data->vbar, (EventMask)ButtonReleaseMask,
5866 False, HandleVBarButtonRelease, (Opaque)tw);
5867 }
5868
5869
5870 } else data->vbar = NULL;
5871
5872
5873 /* Tell scrolled window parent where to put the scrollbars */
5874
5875 if (data->scrollleftside) {
5876 if (data->scrolltopside)
5877 XtSetArg(swarglist[0], XmNscrollBarPlacement, XmTOP_LEFT);
5878 else
5879 XtSetArg(swarglist[0], XmNscrollBarPlacement, XmBOTTOM_LEFT);
5880 } else {
5881 if (data->scrolltopside)
5882 XtSetArg(swarglist[0], XmNscrollBarPlacement, XmTOP_RIGHT);
5883 else
5884 XtSetArg(swarglist[0], XmNscrollBarPlacement, XmBOTTOM_RIGHT);
5885 }
5886
5887 XtSetValues(tw->core.parent, swarglist, 1);
5888
5889 } else {
5890 data->vbar = NULL;
5891 data->hbar = NULL;
5892 if (XmIsScrolledWindow(XtParent(tw)) &&
5893 (((XmScrolledWindowWidget)tw->core.parent)->swindow.VisualPolicy
5894 == XmCONSTANT)) {
5895 data->scrollhorizontal = False;
5896 data->scrollvertical = False;
5897 data->resizewidth = True;
5898 data->resizeheight = True;
5899 }
5900 }
5901
5902 data->hasfocus = False;
5903 data->blinkstate = on;
5904 data->cursor_on = 0;
5905 data->refresh_ibeam_off = True;
5906 data->have_inverted_image_gc = False;
5907 data->handlingexposures = False;
5908 XtAddEventHandler((Widget) tw->text.inner_widget,
5909 (EventMask) FocusChangeMask|EnterWindowMask|
5910 LeaveWindowMask,
5911 False, HandleFocusEvents, (Opaque)NULL);
5912 XtAddEventHandler((Widget) tw->text.inner_widget,
5913 (EventMask) 0, True, HandleGraphicsExposure,
5914 (Opaque)NULL);
5915 }
5916
5917 /*****************************************************************************
5918 * To make TextOut a True "Object" this function should be a class function. *
5919 *****************************************************************************/
5920 Boolean
5921 _XmTextGetBaselines(Widget w,
5922 Dimension ** baselines,
5923 int *line_count)
5924 {
5925 XmTextWidget tw = (XmTextWidget) w;
5926 OutputData data = tw->text.output->data;
5927 Dimension *base_array;
5928 int i;
5929
5930 *line_count = data->number_lines;
5931
5932 base_array = (Dimension *)XtMalloc((sizeof(Dimension) * (*line_count)));
5933
5934 for (i = 0; i < *line_count; i++) {
5935 base_array[i] = data->topmargin + i * data->lineheight +
5936 data->font_ascent;
5937 }
5938
5939 *baselines = base_array;
5940
5941 return (True);
5942 }
5943
5944
5945 /*****************************************************************************
5946 * To make TextOut a True "Object" this function should be a class function. *
5947 *****************************************************************************/
5948 Boolean
5949 _XmTextGetDisplayRect(Widget w,
5950 XRectangle * display_rect)
5951 {
5952 XmTextWidget tw = (XmTextWidget) w;
5953 OutputData data = tw->text.output->data;
5954
5955 (*display_rect).x = data->leftmargin;
5956 (*display_rect).y = data->topmargin;
5957 (*display_rect).width = tw->core.width -
5958 (data->leftmargin + data->rightmargin);
5959 (*display_rect).height = data->number_lines * data->lineheight;
5960
5961 return(True);
5962 }
5963
5964
5965 /*****************************************************************************
5966 * To make TextOut a true "Object" this function should be a class function. *
5967 *****************************************************************************/
5968 /* ARGSUSED */
5969 void
5970 _XmTextMarginsProc(Widget w,
5971 XmBaselineMargins *margins_rec)
5972 {
5973 XmTextWidget tw = (XmTextWidget) w;
5974 OutputData data = tw->text.output->data;
5975
5976 if (margins_rec->get_or_set == XmBASELINE_SET) {
5977 data->topmargin = margins_rec->margin_top +
5978 tw->primitive.shadow_thickness +
5979 tw->primitive.highlight_thickness;
5980 _XmProcessLock();
5981 posToXYCachedWidget = NULL;
5982 _XmProcessUnlock();
5983 } else {
5984 margins_rec->margin_top = data->topmargin -
5985 (tw->primitive.shadow_thickness +
5986 tw->primitive.highlight_thickness);
5987 margins_rec->margin_bottom = data->bottommargin -
5988 (tw->primitive.shadow_thickness +
5989 tw->primitive.highlight_thickness);
5990 margins_rec->text_height = data->font_ascent + data->font_descent;
5991 margins_rec->shadow = tw->primitive.shadow_thickness;
5992 margins_rec->highlight = tw->primitive.highlight_thickness;
5993 margins_rec->margin_height = 0;
5994 }
5995 }
5996
5997 /*****************************************************************************
5998 * To make TextOut a True "Object" this function should be a class function. *
5999 *****************************************************************************/
6000 void
6001 _XmTextChangeHOffset(XmTextWidget tw,
6002 int length)
6003 {
6004 OutputData data = tw->text.output->data;
6005 Dimension margin_width = tw->text.margin_width +
6006 tw->primitive.shadow_thickness +
6007 tw->primitive.highlight_thickness;
6008 int new_offset = data->hoffset;
6009 XmTextPosition nextpos;
6010 XmTextPosition last_position;
6011 XmTextPosition temp;
6012 int inner_width, width, i;
6013 int text_width = 0;
6014 int new_text_width;
6015 XmTextBlockRec block;
6016
6017 /* subtract margins from the offset: Fixes CR 3187 */
6018 length += (length < 0 ? (2 * margin_width) : - (2 * margin_width));
6019 new_offset += length;
6020
6021 for (i = 0; i < tw->text.number_lines; i++) {
6022 last_position = (*tw->text.source->Scan) (tw->text.source,
6023 tw->text.line[i].start,
6024 XmSELECT_LINE,
6025 XmsdRight, 1, False);
6026 nextpos = (*tw->text.source->Scan)(tw->text.source,
6027 last_position, XmSELECT_LINE,
6028 XmsdRight, 1, True);
6029 if (nextpos == last_position)
6030 nextpos = PASTENDPOS;
6031 width = data->leftmargin;
6032 temp = tw->text.line[i].start;
6033 while (temp < last_position) {
6034 temp = (*tw->text.source->ReadSource)
6035 (tw->text.source, temp, last_position, &block);
6036 width += FindWidth(tw, (Position) width, &block,
6037 0, block.length);
6038 }
6039 new_text_width = width - data->leftmargin;
6040 if (new_text_width > text_width) text_width = new_text_width;
6041 }
6042
6043 inner_width = tw->core.width - (2 * margin_width);
6044 if (new_offset >= text_width - inner_width)
6045 new_offset = text_width - inner_width;
6046
6047 ChangeHOffset(tw, new_offset, True);
6048 }
6049
6050
6051 /*****************************************************************************
6052 * To make TextOut a True "Object" this function should be a class function. *
6053 *****************************************************************************/
6054 void
6055 _XmTextChangeVOffset(XmTextWidget tw,
6056 int length)
6057 {
6058 OutputData data = tw->text.output->data;
6059 Dimension margin_height = tw->text.margin_height +
6060 tw->primitive.shadow_thickness +
6061 tw->primitive.highlight_thickness;
6062 int new_offset = data->voffset;
6063 XmTextPosition nextpos = 0;
6064 XmTextPosition last_position = 0;
6065 XmTextPosition temp = 0;
6066 int inner_height = 0, height = 0, i = 0;
6067 int text_height = 0;
6068 int new_text_height = 0;
6069 XmTextBlockRec block;
6070
6071 /* subtract margins from the offset: Fixes CR 3187 */
6072 length += (length < 0 ? (2 * margin_height) : - (2 * margin_height));
6073 new_offset += length;
6074
6075 for (i = 0; i < tw->text.number_lines; i++) {
6076 last_position = (*tw->text.source->Scan) (tw->text.source,
6077 tw->text.line[i].start,
6078 XmSELECT_LINE,
6079 XmsdRight, 1, False);
6080 nextpos = (*tw->text.source->Scan)(tw->text.source,
6081 last_position, XmSELECT_LINE,
6082 XmsdRight, 1, True);
6083 if (nextpos == last_position)
6084 nextpos = PASTENDPOS;
6085 height = data->topmargin;
6086 temp = tw->text.line[i].start;
6087 while (temp < last_position) {
6088 temp = (*tw->text.source->ReadSource)
6089 (tw->text.source, temp, last_position, &block);
6090 height += FindHeight(tw, (Position) height, &block,
6091 0, block.length);
6092 }
6093 new_text_height = height - data->topmargin;
6094 if (new_text_height > text_height) text_height = new_text_height;
6095 }
6096
6097 inner_height = tw->core.height - (2 * margin_height);
6098 if (new_offset >= text_height - inner_height)
6099 new_offset = text_height - inner_height;
6100
6101 ChangeVOffset(tw, new_offset, True);
6102 }
6103
6104
6105 /*****************************************************************************
6106 * To make TextOut a true "Object" this function should be a class function. *
6107 *****************************************************************************/
6108 void
6109 _XmTextToggleCursorGC(Widget w)
6110 {
6111 XmTextWidget tw = (XmTextWidget) w;
6112 OutputData data = tw->text.output->data;
6113 InputData i_data = tw->text.input->data;
6114 XGCValues values;
6115 unsigned long valueMask;
6116 Pixmap stipple = XmUNSPECIFIED_PIXMAP;
6117
6118 if (!XtIsRealized((Widget)tw)) return;
6119
6120 SetFullGC(tw, data->imagegc);
6121
6122 _XmTextResetClipOrigin(tw, tw->text.cursor_position, False);
6123
6124 #ifdef FIX_1501
6125 if (!XtIsSensitive((Widget)tw)) {
6126 valueMask = GCForeground|GCBackground|GCFillStyle|GCStipple|GCFunction;
6127 values.foreground = _XmAssignInsensitiveColor((Widget)tw);
6128 values.background = tw->core.background_pixel;
6129 values.fill_style = FillStippled;
6130
6131 if (i_data->overstrike) {
6132 if (data->stipple_tile == XmUNSPECIFIED_PIXMAP) return;
6133 values.stipple = data->stipple_tile;
6134 values.function = GXxor;
6135 } else {
6136 if (data->cursor == XmUNSPECIFIED_PIXMAP) return;
6137 values.stipple = data->cursor;
6138 values.function = GXcopy;
6139 }
6140 } else {
6141 #endif
6142 if (i_data->overstrike) {
6143 valueMask = GCFillStyle|GCFunction|GCForeground|GCBackground;
6144 if (XtIsSensitive(w) && !tw->text.add_mode &&
6145 (data->hasfocus || _XmTextHasDestination(w)))
6146 values.fill_style = FillSolid;
6147 else {
6148 valueMask |= GCStipple;
6149 values.fill_style = FillStippled;
6150 values.stipple = data->stipple_tile;
6151 }
6152 values.foreground = values.background =
6153 tw->primitive.foreground ^ tw->core.background_pixel;
6154 values.function = GXxor;
6155 } else {
6156 valueMask = GCStipple;
6157 if (XGetGCValues(XtDisplay(tw), data->imagegc,
6158 valueMask, &values))
6159 stipple = values.stipple;
6160 valueMask = GCFillStyle|GCFunction|GCForeground|GCBackground;
6161 if (XtIsSensitive(w) && !tw->text.add_mode &&
6162 (data->hasfocus || _XmTextHasDestination(w))) {
6163 if (stipple != data->cursor) {
6164 values.stipple = data->cursor;
6165 valueMask |= GCStipple;
6166 }
6167 } else
6168 if (stipple != data->add_mode_cursor) {
6169 values.stipple = data->add_mode_cursor;
6170 valueMask |= GCStipple;
6171 }
6172 if (tw->text.input->data->overstrike) {
6173 values.background = values.foreground =
6174 tw->core.background_pixel ^ tw->primitive.foreground;
6175 } else if (data->have_inverted_image_gc) {
6176 values.background = tw->primitive.foreground;
6177 values.foreground = tw->core.background_pixel;
6178 } else {
6179 values.foreground = tw->primitive.foreground;
6180 values.background = tw->core.background_pixel;
6181 }
6182 values.fill_style = FillStippled;
6183 values.function = GXcopy;
6184 }
6185 #ifdef FIX_1501
6186 }
6187 #endif
6188
6189 XSetClipMask(XtDisplay(tw), data->save_gc, None);
6190 XChangeGC(XtDisplay(tw), data->imagegc, valueMask, &values);
6191 }
6192