1 /*
2  * Copyright 1991 by OMRON Corporation
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation, and that the name of OMRON not be used in advertising
9  * or publicity pertaining to distribution of the software without specific,
10  * written prior permission.  OMRON makes no representations about the
11  * suitability of this software for any purpose.  It is provided "as is"
12  * without express or implied warranty.
13  *
14  * OMRON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16  * EVENT SHALL OMRON BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19  * TORTUOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20  * PERFORMANCE OF THIS SOFTWARE.
21  *
22  *      Author: Li Yuhong	 OMRON Corporation
23  */
24 
25 /***********************************************************
26 
27 Copyright (c) 1987, 1988, 1994  X Consortium
28 
29 Permission is hereby granted, free of charge, to any person obtaining a copy
30 of this software and associated documentation files (the "Software"), to deal
31 in the Software without restriction, including without limitation the rights
32 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
33 copies of the Software, and to permit persons to whom the Software is
34 furnished to do so, subject to the following conditions:
35 
36 The above copyright notice and this permission notice shall be included in
37 all copies or substantial portions of the Software.
38 
39 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
40 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
41 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
42 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
43 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
44 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
45 
46 Except as contained in this notice, the name of the X Consortium shall not be
47 used in advertising or otherwise to promote the sale, use or other dealings
48 in this Software without prior written authorization from the X Consortium.
49 
50 
51 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
52 
53                         All Rights Reserved
54 
55 Permission to use, copy, modify, and distribute this software and its
56 documentation for any purpose and without fee is hereby granted,
57 provided that the above copyright notice appear in all copies and that
58 both that copyright notice and this permission notice appear in
59 supporting documentation, and that the name of Digital not be
60 used in advertising or publicity pertaining to distribution of the
61 software without specific, written prior permission.
62 
63 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
64 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
65 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
66 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
67 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
68 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
69 SOFTWARE.
70 
71 ******************************************************************/
72 
73 #ifdef HAVE_CONFIG_H
74 #include "config.h"
75 #endif
76 #include <X11/IntrinsicP.h>
77 #include <X11/StringDefs.h>
78 #include <X11/Xatom.h>
79 #include <X11/Xaw3dxft/XawInit.h>
80 #include <X11/Xaw3dxft/MultiSinkP.h>
81 #include <X11/Xaw3dxft/MultiSrcP.h>
82 #include <X11/Xaw3dxft/TextP.h>
83 #include "XawI18n.h"
84 #include <stdio.h>
85 #include <stdlib.h>
86 #include <ctype.h>
87 
88 #ifdef GETLASTPOS
89 #undef GETLASTPOS		/* We will use our own GETLASTPOS. */
90 #endif
91 
92 #define GETLASTPOS XawTextSourceScan(source, (XawTextPosition) 0, XawstAll, XawsdRight, 1, TRUE)
93 
94 static void Initialize(Widget, Widget, ArgList, Cardinal *);
95 static void Destroy(Widget);
96 static Boolean SetValues(Widget, Widget, Widget, ArgList, Cardinal *);
97 static int MaxLines(Widget, Dimension);
98 static int MaxHeight(Widget, int);
99 static void SetTabs(Widget, int, short *);
100 
101 static void DisplayText(Widget, Position, Position, XawTextPosition,
102                         XawTextPosition, Boolean);
103 static void InsertCursor(Widget, Position, Position, XawTextInsertState);
104 static void FindPosition(Widget, XawTextPosition, int, int, Boolean,
105                          XawTextPosition *, int *, int *);
106 static void FindDistance(Widget, XawTextPosition, int, XawTextPosition,
107                          int *, XawTextPosition *, int *);
108 static void Resolve(Widget, XawTextPosition, int, int, XawTextPosition *);
109 static void GetCursorBounds(Widget, XRectangle *);
110 
111 #define offset(field) XtOffsetOf(MultiSinkRec, multi_sink.field)
112 
113 static XtResource resources[] = {
114     {XtNfontSet, XtCFontSet, XtRFontSet, sizeof (XFontSet),
115 	offset(fontset), XtRString, XtDefaultFontSet},
116     {XtNecho, XtCOutput, XtRBoolean, sizeof(Boolean),
117 	offset(echo), XtRImmediate, (XtPointer) True},
118     {XtNdisplayNonprinting, XtCOutput, XtRBoolean, sizeof(Boolean),
119 	offset(display_nonprinting), XtRImmediate, (XtPointer) True},
120 };
121 #undef offset
122 
123 #define SuperClass		(&textSinkClassRec)
124 MultiSinkClassRec multiSinkClassRec = {
125   { /* core_class fields */
126     /* superclass	  	*/	(WidgetClass) SuperClass,
127     /* class_name	  	*/	"MultiSink",
128     /* widget_size	  	*/	sizeof(MultiSinkRec),
129     /* class_initialize   	*/	XawInitializeWidgetSet,
130     /* class_part_initialize	*/	NULL,
131     /* class_inited       	*/	FALSE,
132     /* initialize	  	*/	Initialize,
133     /* initialize_hook		*/	NULL,
134     /* obj1		  	*/	NULL,
135     /* obj2		  	*/	NULL,
136     /* obj3		  	*/	0,
137     /* resources	  	*/	resources,
138     /* num_resources	  	*/	XtNumber(resources),
139     /* xrm_class	  	*/	NULLQUARK,
140     /* obj4		  	*/	FALSE,
141     /* obj5		  	*/	FALSE,
142     /* obj6			*/	FALSE,
143     /* obj7		  	*/	FALSE,
144     /* destroy		  	*/	Destroy,
145     /* obj8		  	*/	NULL,
146     /* obj9		  	*/	NULL,
147     /* set_values	  	*/	SetValues,
148     /* set_values_hook		*/	NULL,
149     /* obj10			*/	NULL,
150     /* get_values_hook		*/	NULL,
151     /* obj11		 	*/	NULL,
152     /* version			*/	XtVersion,
153     /* callback_private   	*/	NULL,
154     /* obj12		   	*/	NULL,
155     /* obj13			*/	NULL,
156     /* obj14			*/	NULL,
157     /* extension		*/	NULL
158   },
159   { /* text_sink_class fields */
160     /* DisplayText              */      DisplayText,
161     /* InsertCursor             */      InsertCursor,
162     /* ClearToBackground        */      XtInheritClearToBackground,
163     /* FindPosition             */      FindPosition,
164     /* FindDistance             */      FindDistance,
165     /* Resolve                  */      Resolve,
166     /* MaxLines                 */      MaxLines,
167     /* MaxHeight                */      MaxHeight,
168     /* SetTabs                  */      SetTabs,
169     /* GetCursorBounds          */      GetCursorBounds
170   },
171   { /* multi_sink_class fields */
172     /* unused			*/	0
173   }
174 };
175 
176 WidgetClass multiSinkObjectClass = (WidgetClass)&multiSinkClassRec;
177 
178 /* Utilities */
179 
180 static int
CharWidth(Widget w,int x,wchar_t c)181 CharWidth (
182     Widget w,
183     int x,
184     wchar_t c)
185 {
186     int    i, width;
187     MultiSinkObject sink = (MultiSinkObject) w;
188     XFontSet fontset = sink->multi_sink.fontset;
189     Position *tab;
190 
191     if ( c == _Xaw_atowc(XawLF) ) return(0);
192 
193     if (c == _Xaw_atowc(XawTAB)) {
194 	/* Adjust for Left Margin. */
195 	x -= ((TextWidget) XtParent(w))->text.margin.left;
196 
197 	if (x >= (int)XtParent(w)->core.width) return 0;
198 	for (i = 0, tab = sink->text_sink.tabs ;
199 	     i < sink->text_sink.tab_count ; i++, tab++) {
200 	    if (x < *tab) {
201 		if (*tab < (int)XtParent(w)->core.width)
202 		    return *tab - x;
203 		else
204 		    return 0;
205 	    }
206 	}
207 	return 0;
208     }
209 
210     if (XwcTextEscapement (fontset, &c, 1) == 0) {
211 	if (sink->multi_sink.display_nonprinting)
212 	    c = _Xaw_atowc('@');
213 	else {
214 	    c = _Xaw_atowc(XawSP);
215 	}
216     }
217 
218     /*
219      * if more efficiency(suppose one column is one ASCII char)
220 
221     width = XwcGetColumn(fontset->font_charset, fontset->num_of_fonts, c) *
222             fontset->font_struct_list[0]->min_bounds.width;
223      *
224      * WARNING: Very Slower!!!
225      *
226      * Li Yuhong.
227      */
228 
229     width = XwcTextEscapement(fontset, &c, 1);
230 
231     return width;
232 }
233 
234 /*	Function Name: PaintText
235  *	Description: Actually paints the text into the windoe.
236  *	Arguments: w - the text widget.
237  *                 gc - gc to paint text with.
238  *                 x, y - location to paint the text.
239  *                 buf, len - buffer and length of text to paint.
240  *	Returns: the width of the text painted, or 0.
241  *
242  * NOTE:  If this string attempts to paint past the end of the window
243  *        then this function will return zero.
244  */
245 
246 static Dimension
PaintText(Widget w,GC gc,Position x,Position y,wchar_t * buf,int len)247 PaintText(Widget w, GC gc, Position x, Position y, wchar_t* buf, int len)
248 {
249     MultiSinkObject sink = (MultiSinkObject) w;
250     TextWidget ctx = (TextWidget) XtParent(w);
251 
252     XFontSet fontset = sink->multi_sink.fontset;
253     Position max_x;
254     Dimension width = XwcTextEscapement(fontset, buf, len);
255     XFontSetExtents *ext = XExtentsOfFontSet(fontset);
256     max_x = (Position) ctx->core.width;
257 
258     if ( ((int) width) <= -x)	           /* Don't draw if we can't see it. */
259       return(width);
260 
261     XwcDrawImageString(XtDisplay(ctx), XtWindow(ctx), fontset, gc,
262                      (int) x, (int) y, buf, len);
263     if ( (((Position) width + x) > max_x) && (ctx->text.margin.right != 0) ) {
264 	x = ctx->core.width - ctx->text.margin.right;
265 	width = ctx->text.margin.right;
266 	XFillRectangle(XtDisplay((Widget) ctx), XtWindow( (Widget) ctx),
267 		       sink->multi_sink.normgc, (int) x,
268                        (int) y - abs(ext->max_logical_extent.y),
269                        (unsigned int) width,
270                        (unsigned int) ext->max_logical_extent.height);
271 	return(0);
272     }
273     return(width);
274 }
275 
276 /* Sink Object Functions */
277 
278 /*
279  * This function does not know about drawing more than one line of text.
280  */
281 
282 static void
DisplayText(Widget w,Position x,Position y,XawTextPosition pos1,XawTextPosition pos2,Boolean highlight)283 DisplayText(Widget w, Position x, Position y, XawTextPosition pos1,
284             XawTextPosition pos2, Boolean highlight)
285 {
286     MultiSinkObject sink = (MultiSinkObject) w;
287     Widget source = XawTextGetSource(XtParent(w));
288     wchar_t buf[BUFSIZ];
289     XFontSetExtents *ext = XExtentsOfFontSet(sink->multi_sink.fontset);
290 
291     int j, k;
292     XawTextBlock blk;
293     GC gc = highlight ? sink->multi_sink.invgc : sink->multi_sink.normgc;
294     GC invgc = highlight ? sink->multi_sink.normgc : sink->multi_sink.invgc;
295 
296     if (!sink->multi_sink.echo) return;
297 
298     y += abs(ext->max_logical_extent.y);
299     for ( j = 0 ; pos1 < pos2 ; ) {
300 	pos1 = XawTextSourceRead(source, pos1, &blk, (int) pos2 - pos1);
301 	for (k = 0; k < blk.length; k++) {
302 	    if (j >= BUFSIZ) {	/* buffer full, dump the text. */
303 	        x += PaintText(w, gc, x, y, buf, j);
304 		j = 0;
305 	    }
306 	    buf[j] = ((wchar_t *)blk.ptr)[k];
307 	    if (buf[j] == _Xaw_atowc(XawLF))
308 	        continue;
309 
310 	    else if (buf[j] == _Xaw_atowc(XawTAB)) {
311 	        Position temp = 0;
312 		Dimension width;
313 
314 	        if ((j != 0) && ((temp = PaintText(w, gc, x, y, buf, j)) == 0))
315 		  return;
316 
317 	        x += temp;
318                 width = CharWidth(w, x, _Xaw_atowc(XawTAB));
319 		XFillRectangle(XtDisplayOfObject(w), XtWindowOfObject(w),
320 			       invgc, (int) x,
321                                (int) y - abs(ext->max_logical_extent.y),
322                                (unsigned int)width,
323                                (unsigned int)ext->max_logical_extent.height);
324                 x += width;
325                 j = -1;
326             }
327             else if (XwcTextEscapement (sink->multi_sink.fontset, &buf[j], 1) == 0) {
328                 if (sink->multi_sink.display_nonprinting)
329                     buf[j] = _Xaw_atowc('@');
330                 else
331                     buf[j] = _Xaw_atowc(' ');
332             }
333 	    j++;
334 	}
335     }
336     if (j > 0)
337         (void) PaintText(w, gc, x, y, buf, j);
338 }
339 
340 #define insertCursor_width 6
341 #define insertCursor_height 3
342 static char insertCursor_bits[] = {0x0c, 0x1e, 0x33};
343 
344 static Pixmap
CreateInsertCursor(Screen * s)345 CreateInsertCursor(Screen *s)
346 {
347     return (XCreateBitmapFromData (DisplayOfScreen(s), RootWindowOfScreen(s),
348 		  insertCursor_bits, insertCursor_width, insertCursor_height));
349 }
350 
351 /*	Function Name: GetCursorBounds
352  *	Description: Returns the size and location of the cursor.
353  *	Arguments: w - the text object.
354  * RETURNED        rect - an X rectangle to return the cursor bounds in.
355  *	Returns: none.
356  */
357 
358 static void
GetCursorBounds(Widget w,XRectangle * rect)359 GetCursorBounds(Widget w, XRectangle * rect)
360 {
361     MultiSinkObject sink = (MultiSinkObject) w;
362 
363     rect->width = (unsigned short) insertCursor_width;
364     rect->height = (unsigned short) insertCursor_height;
365     rect->x = sink->multi_sink.cursor_x - (short) (rect->width / 2);
366     rect->y = sink->multi_sink.cursor_y - (short) rect->height;
367 }
368 
369 /*
370  * The following procedure manages the "insert" cursor.
371  */
372 
373 static void
InsertCursor(Widget w,Position x,Position y,XawTextInsertState state)374 InsertCursor (Widget w, Position x, Position y, XawTextInsertState state)
375 {
376     MultiSinkObject sink = (MultiSinkObject) w;
377     Widget text_widget = XtParent(w);
378     XRectangle rect;
379 
380     sink->multi_sink.cursor_x = x;
381     sink->multi_sink.cursor_y = y;
382 
383     GetCursorBounds(w, &rect);
384     if (state != sink->multi_sink.laststate && XtIsRealized(text_widget))
385         XCopyPlane(XtDisplay(text_widget),
386 		   sink->multi_sink.insertCursorOn,
387 		   XtWindow(text_widget), sink->multi_sink.xorgc,
388 		   0, 0, (unsigned int) rect.width, (unsigned int) rect.height,
389 		   (int) rect.x, (int) rect.y, 1);
390     sink->multi_sink.laststate = state;
391 }
392 
393 /*
394  * Given two positions, find the distance between them.
395  */
396 
397 static void
FindDistance(Widget w,XawTextPosition fromPos,int fromx,XawTextPosition toPos,int * resWidth,XawTextPosition * resPos,int * resHeight)398 FindDistance (Widget w, XawTextPosition fromPos, int fromx, XawTextPosition toPos,
399               int *resWidth, XawTextPosition *resPos, int *resHeight)
400 {
401     MultiSinkObject sink = (MultiSinkObject) w;
402     Widget source = XawTextGetSource(XtParent(w));
403 
404     XawTextPosition index, lastPos;
405     wchar_t c;
406     XFontSetExtents *ext = XExtentsOfFontSet(sink->multi_sink.fontset);
407     XawTextBlock blk;
408 
409     /* we may not need this */
410     lastPos = GETLASTPOS;
411     XawTextSourceRead(source, fromPos, &blk, (int) toPos - fromPos);
412     *resWidth = 0;
413     for (index = fromPos; index != toPos && index < lastPos; index++) {
414 	if (index - blk.firstPos >= blk.length)
415 	    XawTextSourceRead(source, index, &blk, (int) toPos - fromPos);
416         c = ((wchar_t *)blk.ptr)[index - blk.firstPos];
417 	*resWidth += CharWidth(w, fromx + *resWidth, c);
418 	if (c == _Xaw_atowc(XawLF)) {
419 	    index++;
420 	    break;
421 	}
422     }
423     *resPos = index;
424     *resHeight = ext->max_logical_extent.height;
425 }
426 
427 
428 static void
FindPosition(Widget w,XawTextPosition fromPos,int fromx,int width,Boolean stopAtWordBreak,XawTextPosition * resPos,int * resWidth,int * resHeight)429 FindPosition(Widget w, XawTextPosition fromPos, int fromx, int width,
430              Boolean stopAtWordBreak, XawTextPosition *resPos, int *resWidth,
431              int *resHeight)
432 {
433     MultiSinkObject sink = (MultiSinkObject) w;
434     Widget source = XawTextGetSource(XtParent(w));
435 
436     XawTextPosition lastPos, index, whiteSpacePosition = 0;
437     int     lastWidth = 0, whiteSpaceWidth = 0;
438     Boolean whiteSpaceSeen;
439     wchar_t c;
440     XFontSetExtents *ext = XExtentsOfFontSet(sink->multi_sink.fontset);
441     XawTextBlock blk;
442 
443     lastPos = GETLASTPOS;
444 
445     XawTextSourceRead(source, fromPos, &blk, BUFSIZ);
446     *resWidth = 0;
447     whiteSpaceSeen = FALSE;
448     c = 0;
449     for (index = fromPos; *resWidth <= width && index < lastPos; index++) {
450 	lastWidth = *resWidth;
451 	if (index - blk.firstPos >= blk.length)
452 	    XawTextSourceRead(source, index, &blk, BUFSIZ);
453         c = ((wchar_t *)blk.ptr)[index - blk.firstPos];
454         *resWidth += CharWidth(w, fromx + *resWidth, c);
455 
456         if ((c == _Xaw_atowc(XawSP) || c == _Xaw_atowc(XawTAB)) &&
457 	    *resWidth <= width) {
458 	    whiteSpaceSeen = TRUE;
459 	    whiteSpacePosition = index;
460 	    whiteSpaceWidth = *resWidth;
461 	}
462 	if (c == _Xaw_atowc(XawLF)) {
463 	    index++;
464 	    break;
465 	}
466     }
467     if (*resWidth > width && index > fromPos) {
468 	*resWidth = lastWidth;
469 	index--;
470 	if (stopAtWordBreak && whiteSpaceSeen) {
471 	    index = whiteSpacePosition + 1;
472 	    *resWidth = whiteSpaceWidth;
473 	}
474     }
475     if (index == lastPos && c != _Xaw_atowc(XawLF)) index = lastPos + 1;
476     *resPos = index;
477     *resHeight = ext->max_logical_extent.height;
478 }
479 
480 static void
Resolve(Widget w,XawTextPosition pos,int fromx,int width,XawTextPosition * resPos)481 Resolve (Widget w, XawTextPosition pos, int fromx, int width,
482          XawTextPosition *resPos)
483 {
484     int resWidth, resHeight;
485     Widget source = XawTextGetSource(XtParent(w));
486 
487     FindPosition(w, pos, fromx, width, FALSE, resPos, &resWidth, &resHeight);
488     if (*resPos > GETLASTPOS)
489       *resPos = GETLASTPOS;
490 }
491 
492 static void
GetGC(MultiSinkObject sink)493 GetGC(MultiSinkObject sink)
494 {
495     XtGCMask valuemask = (GCGraphicsExposures | GCForeground | GCBackground );
496     XGCValues values;
497 
498     values.graphics_exposures = (Bool) FALSE;
499 
500     values.foreground = sink->text_sink.foreground;
501     values.background = sink->text_sink.background;
502 
503     sink->multi_sink.normgc = XtAllocateGC( (Widget)sink, 0, valuemask, &values, GCFont, 0 );
504 
505     values.foreground = sink->text_sink.background;
506     values.background = sink->text_sink.foreground;
507     sink->multi_sink.invgc = XtAllocateGC( (Widget)sink, 0, valuemask, &values, GCFont, 0 );
508 
509     values.function = GXxor;
510     values.background = (unsigned long) 0L;	/* (pix ^ 0) = pix */
511     values.foreground = (sink->text_sink.background ^
512 			 sink->text_sink.foreground);
513     valuemask = GCGraphicsExposures | GCFunction | GCForeground | GCBackground;
514 
515     /* if this GC is not used for fontset rendering then AllocateGC aint needed. Dont hurt tho.*/
516     sink->multi_sink.xorgc = XtAllocateGC( (Widget)sink, 0, valuemask, &values, GCFont, 0 );
517 }
518 
519 
520 /***** Public routines *****/
521 
522 /*	Function Name: Initialize
523  *	Description: Initializes the TextSink Object.
524  *	Arguments: request, new - the requested and new values for the object
525  *                                instance.
526  *	Returns: none.
527  *
528  */
529 
530 /* ARGSUSED */
531 static void
Initialize(Widget request,Widget new,ArgList args,Cardinal * num_args)532 Initialize(Widget request, Widget new, ArgList args, Cardinal *num_args)
533 {
534     MultiSinkObject sink = (MultiSinkObject) new;
535 
536     GetGC(sink);
537 
538     sink->multi_sink.insertCursorOn= CreateInsertCursor(XtScreenOfObject(new));
539     sink->multi_sink.laststate = XawisOff;
540     sink->multi_sink.cursor_x = sink->multi_sink.cursor_y = 0;
541 }
542 
543 /*	Function Name: Destroy
544  *	Description: This function cleans up when the object is
545  *                   destroyed.
546  *	Arguments: w - the MultiSink Object.
547  *	Returns: none.
548  */
549 
550 static void
Destroy(Widget w)551 Destroy(Widget w)
552 {
553    MultiSinkObject sink = (MultiSinkObject) w;
554 
555    XtReleaseGC(w, sink->multi_sink.normgc);
556    XtReleaseGC(w, sink->multi_sink.invgc);
557    XtReleaseGC(w, sink->multi_sink.xorgc);
558 
559    XFreePixmap(XtDisplayOfObject(w), sink->multi_sink.insertCursorOn);
560 }
561 
562 /*	Function Name: SetValues
563  *	Description: Sets the values for the MultiSink
564  *	Arguments: current - current state of the object.
565  *                 request - what was requested.
566  *                 new - what the object will become.
567  *	Returns: True if redisplay is needed.
568  */
569 
570 /* ARGSUSED */
571 static Boolean
SetValues(Widget current,Widget request,Widget new,ArgList args,Cardinal * num_args)572 SetValues(Widget current, Widget request, Widget new, ArgList args, Cardinal *num_args)
573 {
574     MultiSinkObject w = (MultiSinkObject) new;
575     MultiSinkObject old_w = (MultiSinkObject) current;
576 
577     /* Font set is not in the GC! Do not make a new GC when font set changes! */
578 
579     if ( w->multi_sink.fontset != old_w->multi_sink.fontset ) {
580 	((TextWidget)XtParent(new))->text.redisplay_needed = True;
581 #ifndef NO_TAB_FIX
582 	SetTabs((Widget) w, w->text_sink.tab_count, w->text_sink.char_tabs );
583 #endif
584     }
585 
586     if (   w->text_sink.background != old_w->text_sink.background ||
587 	   w->text_sink.foreground != old_w->text_sink.foreground     ) {
588 
589 	XtReleaseGC((Widget)w, w->multi_sink.normgc);
590 	XtReleaseGC((Widget)w, w->multi_sink.invgc);
591 	XtReleaseGC((Widget)w, w->multi_sink.xorgc);
592 	GetGC(w);
593 	((TextWidget)XtParent(new))->text.redisplay_needed = True;
594     } else {
595 	if ( (w->multi_sink.echo != old_w->multi_sink.echo) ||
596 	     (w->multi_sink.display_nonprinting !=
597                                      old_w->multi_sink.display_nonprinting) )
598 	    ((TextWidget)XtParent(new))->text.redisplay_needed = True;
599     }
600 
601     return False;
602 }
603 
604 /*	Function Name: MaxLines
605  *	Description: Finds the Maximum number of lines that will fit in
606  *                   a given height.
607  *	Arguments: w - the MultiSink Object.
608  *                 height - height to fit lines into.
609  *	Returns: the number of lines that will fit.
610  */
611 
612 /* ARGSUSED */
613 static int
MaxLines(Widget w,Dimension height)614 MaxLines(Widget w, Dimension height)
615 {
616   MultiSinkObject sink = (MultiSinkObject) w;
617   int font_height;
618   XFontSetExtents *ext = XExtentsOfFontSet(sink->multi_sink.fontset);
619 
620   font_height = ext->max_logical_extent.height;
621   return( ((int) height) / font_height );
622 }
623 
624 /*	Function Name: MaxHeight
625  *	Description: Finds the Minium height that will contain a given number
626  *                   lines.
627  *	Arguments: w - the MultiSink Object.
628  *                 lines - the number of lines.
629  *	Returns: the height.
630  */
631 
632 /* ARGSUSED */
633 static int
MaxHeight(Widget w,int lines)634 MaxHeight(
635     Widget w,
636     int lines )
637 {
638   MultiSinkObject sink = (MultiSinkObject) w;
639   XFontSetExtents *ext = XExtentsOfFontSet(sink->multi_sink.fontset);
640 
641   return(lines * ext->max_logical_extent.height);
642 }
643 
644 /*	Function Name: SetTabs
645  *	Description: Sets the Tab stops.
646  *	Arguments: w - the MultiSink Object.
647  *                 tab_count - the number of tabs in the list.
648  *                 tabs - the text positions of the tabs.
649  *	Returns: none
650  */
651 
652 static void
SetTabs(Widget w,int tab_count,short * tabs)653 SetTabs(
654     Widget w,
655     int tab_count,
656     short* tabs )
657 {
658   MultiSinkObject sink = (MultiSinkObject) w;
659   int i;
660   Atom XA_FIGURE_WIDTH;
661   unsigned long figure_width = 0;
662   XFontStruct *font;
663 
664   /*
665    * Bug:
666    *   Suppose the first font of fontset stores the unit of column.
667    *
668    * By Li Yuhong, Mar. 14, 1991
669    */
670   { XFontStruct **f_list;
671     char	**f_name;
672 
673     (void) XFontsOfFontSet(sink->multi_sink.fontset, &f_list, &f_name);
674     font = f_list[0];
675   }
676 
677 /*
678  * Find the figure width of the current font.
679  */
680 
681   XA_FIGURE_WIDTH = XInternAtom(XtDisplayOfObject(w), "FIGURE_WIDTH", FALSE);
682   if ( (XA_FIGURE_WIDTH != None) &&
683        ( (!XGetFontProperty(font, XA_FIGURE_WIDTH, &figure_width)) ||
684 	 (figure_width == 0)) ) {
685     if (font->per_char && font->min_char_or_byte2 <= '$' &&
686 	font->max_char_or_byte2 >= '$')
687       figure_width = font->per_char['$' - font->min_char_or_byte2].width;
688     else
689       figure_width = font->max_bounds.width;
690   }
691 
692   if (tab_count > sink->text_sink.tab_count) {
693     sink->text_sink.tabs = (Position *)
694 	XtRealloc((char *) sink->text_sink.tabs,
695 		  (Cardinal) (tab_count * sizeof(Position)));
696     sink->text_sink.char_tabs = (short *)
697 	XtRealloc((char *) sink->text_sink.char_tabs,
698 		  (Cardinal) (tab_count * sizeof(short)));
699   }
700 
701   for ( i = 0 ; i < tab_count ; i++ ) {
702     sink->text_sink.tabs[i] = tabs[i] * figure_width;
703     sink->text_sink.char_tabs[i] = tabs[i];
704   }
705 
706   sink->text_sink.tab_count = tab_count;
707 
708 #ifndef NO_TAB_FIX
709   ((TextWidget)XtParent(w))->text.redisplay_needed = True;
710 #endif
711 }
712 
713 void
_XawMultiSinkPosToXY(Widget w,XawTextPosition pos,Position * x,Position * y)714 _XawMultiSinkPosToXY(
715     Widget w,
716     XawTextPosition pos,
717     Position *x,
718     Position *y )
719 {
720     MultiSinkObject sink = (MultiSinkObject) ((TextWidget)w)->text.sink;
721     XFontSetExtents *ext = XExtentsOfFontSet( sink->multi_sink.fontset );
722 
723     _XawTextPosToXY( w, pos, x, y );
724     *y += abs( ext->max_logical_extent.y );
725 }
726