1/*
2
3Copyright 1989, 1994, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24
25*/
26
27/*
28 * Author:  Chris Peterson, MIT X Consortium.
29 *
30 * Much code taken from X11R3 AsciiSink.
31 */
32
33/*
34 * TextSink.c - TextSink object. (For use with the text widget).
35 *
36 */
37
38#ifdef HAVE_CONFIG_H
39#include <config.h>
40#endif
41#include <stdio.h>
42#include <stdlib.h>
43#include <ctype.h>
44#include <X11/IntrinsicP.h>
45#include <X11/StringDefs.h>
46#include <X11/Xaw/TextP.h>
47#include <X11/Xaw/TextSinkP.h>
48#include <X11/Xaw/XawInit.h>
49#include "Private.h"
50
51/*
52 * Prototypes
53 */
54static void XawTextSinkClassPartInitialize(WidgetClass);
55static void XawTextSinkInitialize(Widget, Widget, ArgList, Cardinal*);
56static void XawTextSinkDestroy(Widget);
57static Boolean XawTextSinkSetValues(Widget, Widget, Widget,
58				    ArgList, Cardinal*);
59
60static int  MaxLines(Widget, unsigned int);
61static int  MaxHeight(Widget, int);
62static void DisplayText(Widget, int, int, XawTextPosition, XawTextPosition,
63			Bool);
64static void InsertCursor(Widget, int, int, XawTextInsertState);
65static void ClearToBackground(Widget, int, int, unsigned int, unsigned int);
66static void FindPosition(Widget, XawTextPosition, int, int, Bool,
67			 XawTextPosition*, int*, int*);
68static void FindDistance(Widget, XawTextPosition, int, XawTextPosition, int*,
69			 XawTextPosition*, int*);
70static void Resolve(Widget, XawTextPosition, int, int, XawTextPosition*);
71static void SetTabs(Widget, int, short*);
72static void GetCursorBounds(Widget, XRectangle*);
73
74#ifndef OLDXAW
75static Boolean CvtStringToPropertyList(Display*, XrmValue*, Cardinal*,
76				       XrmValue*, XrmValue*, XtPointer*);
77static Boolean CvtPropertyListToString(Display*, XrmValue*, Cardinal*,
78				       XrmValue*, XrmValue*, XtPointer*);
79static Bool BeginPaint(Widget);
80static Bool EndPaint(Widget);
81static void SetXlfdDefaults(Display*, XawTextProperty*);
82#endif
83
84/*
85 * External
86 */
87void _XawTextSinkClearToBackground(Widget, int, int, unsigned, unsigned);
88void _XawTextSinkDisplayText(Widget, int, int, XawTextPosition, XawTextPosition,
89			     Bool);
90
91/*
92 * Initialization
93 */
94#define offset(field) XtOffsetOf(TextSinkRec, text_sink.field)
95static XtResource resources[] = {
96  {
97    XtNforeground,
98    XtCForeground,
99    XtRPixel,
100    sizeof(Pixel),
101    offset(foreground),
102    XtRString,
103    (XtPointer)XtDefaultForeground
104  },
105  {
106    XtNbackground,
107    XtCBackground,
108    XtRPixel,
109    sizeof(Pixel),
110    offset(background),
111    XtRString,
112    (XtPointer)XtDefaultBackground
113  },
114#ifndef OLDXAW
115  {
116    XtNcursorColor,
117    XtCColor,
118    XtRPixel,
119    sizeof(Pixel),
120    offset(cursor_color),
121    XtRString,
122    (XtPointer)XtDefaultForeground
123  },
124  {
125    XawNtextProperties,
126    XawCTextProperties,
127    XawRTextProperties,
128    sizeof(XawTextPropertyList*),
129    offset(properties),
130    XtRImmediate,
131    NULL
132  },
133#endif
134};
135#undef offset
136
137#ifndef OLDXAW
138static TextSinkExtRec extension_rec = {
139    NULL,				/* next_extension */
140    NULLQUARK,				/* record_type */
141    1,					/* version */
142    sizeof(TextSinkExtRec),		/* record_size */
143    BeginPaint,
144    NULL,
145    NULL,
146    EndPaint
147};
148
149static XrmQuark Qdefault;
150#endif
151
152#define Superclass	(&objectClassRec)
153TextSinkClassRec textSinkClassRec = {
154  /* object */
155  {
156    (WidgetClass)Superclass,		/* superclass */
157    "TextSink",				/* class_name */
158    sizeof(TextSinkRec),		/* widget_size */
159    XawInitializeWidgetSet,		/* class_initialize */
160    XawTextSinkClassPartInitialize,	/* class_part_initialize */
161    False,				/* class_inited */
162    XawTextSinkInitialize,		/* initialize */
163    NULL,				/* initialize_hook */
164    NULL,				/* obj1 */
165    NULL,				/* obj2 */
166    0,					/* obj3 */
167    resources,				/* resources */
168    XtNumber(resources),		/* num_resources */
169    NULLQUARK,				/* xrm_class */
170    False,				/* obj4 */
171    False,				/* obj5 */
172    False,				/* obj6 */
173    False,				/* obj7 */
174    XawTextSinkDestroy,			/* destroy */
175    NULL,				/* obj8 */
176    NULL,				/* obj9 */
177    XawTextSinkSetValues,		/* set_values */
178    NULL,				/* set_values_hook */
179    NULL,				/* obj10 */
180    NULL,				/* get_values_hook */
181    NULL,				/* obj11 */
182    XtVersion,				/* version */
183    NULL,				/* callback_private */
184    NULL,				/* obj12 */
185    NULL,				/* obj13 */
186    NULL,				/* obj14 */
187    NULL,				/* extension */
188  },
189  /* text_sink */
190  {
191    DisplayText,			/* DisplayText */
192    InsertCursor,			/* InsertCursor */
193    ClearToBackground,			/* ClearToBackground */
194    FindPosition,			/* FindPosition */
195    FindDistance,			/* FindDistance */
196    Resolve,				/* Resolve */
197    MaxLines,				/* MaxLines */
198    MaxHeight,				/* MaxHeight */
199    SetTabs,				/* SetTabs */
200    GetCursorBounds,			/* GetCursorBounds */
201#ifndef OLDXAW
202    NULL,
203#endif
204  },
205};
206
207WidgetClass textSinkObjectClass = (WidgetClass)&textSinkClassRec;
208
209/*
210 * Implementation
211 */
212static void
213XawTextSinkClassPartInitialize(WidgetClass wc)
214{
215    TextSinkObjectClass t_src, superC;
216#ifndef OLDXAW
217    static XtConvertArgRec CvtArgs[] = {
218      {XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.self),
219       sizeof(Widget)},
220    };
221#endif
222
223    t_src = (TextSinkObjectClass) wc;
224    superC = (TextSinkObjectClass) t_src->object_class.superclass;
225
226#ifndef OLDXAW
227    extension_rec.record_type = XrmPermStringToQuark("TextSink");
228    extension_rec.next_extension = (XtPointer)t_src->text_sink_class.extension;
229    t_src->text_sink_class.extension = &extension_rec;
230
231    Qdefault = XrmPermStringToQuark("default");
232#endif
233
234    /*
235     * We don't need to check for null super since we'll get to TextSink
236     * eventually.
237     */
238    if (t_src->text_sink_class.DisplayText == XtInheritDisplayText)
239	t_src->text_sink_class.DisplayText =
240	    superC->text_sink_class.DisplayText;
241
242    if (t_src->text_sink_class.InsertCursor == XtInheritInsertCursor)
243	t_src->text_sink_class.InsertCursor =
244	    superC->text_sink_class.InsertCursor;
245
246    if (t_src->text_sink_class.ClearToBackground== XtInheritClearToBackground)
247	t_src->text_sink_class.ClearToBackground =
248	    superC->text_sink_class.ClearToBackground;
249
250    if (t_src->text_sink_class.FindPosition == XtInheritFindPosition)
251	t_src->text_sink_class.FindPosition =
252	    superC->text_sink_class.FindPosition;
253
254    if (t_src->text_sink_class.FindDistance == XtInheritFindDistance)
255	t_src->text_sink_class.FindDistance =
256	    superC->text_sink_class.FindDistance;
257
258    if (t_src->text_sink_class.Resolve == XtInheritResolve)
259	t_src->text_sink_class.Resolve =
260	    superC->text_sink_class.Resolve;
261
262    if (t_src->text_sink_class.MaxLines == XtInheritMaxLines)
263	t_src->text_sink_class.MaxLines =
264	    superC->text_sink_class.MaxLines;
265
266    if (t_src->text_sink_class.MaxHeight == XtInheritMaxHeight)
267	t_src->text_sink_class.MaxHeight =
268	    superC->text_sink_class.MaxHeight;
269
270    if (t_src->text_sink_class.SetTabs == XtInheritSetTabs)
271	t_src->text_sink_class.SetTabs =
272	    superC->text_sink_class.SetTabs;
273
274    if (t_src->text_sink_class.GetCursorBounds == XtInheritGetCursorBounds)
275	t_src->text_sink_class.GetCursorBounds =
276	    superC->text_sink_class.GetCursorBounds;
277
278#ifndef OLDXAW
279    XtSetTypeConverter(XtRString, XawRTextProperties, CvtStringToPropertyList,
280		       &CvtArgs[0], XtNumber(CvtArgs), XtCacheNone, NULL);
281    XtSetTypeConverter(XawRTextProperties, XtRString, CvtPropertyListToString,
282		       NULL, 0, XtCacheNone, NULL);
283#endif
284}
285
286/*
287 * Function:
288 *	XawTextSinkInitialize
289 *
290 * Parameters:
291 *	request - requested and new values for the object instance
292 *	cnew	- ""
293 *
294 * Description:
295 *	Initializes the TextSink Object.
296 */
297/*ARGSUSED*/
298static void
299XawTextSinkInitialize(Widget request _X_UNUSED, Widget cnew,
300		      ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED)
301{
302    TextSinkObject sink = (TextSinkObject)cnew;
303
304    sink->text_sink.tab_count = 0; /* Initialize the tab stops. */
305    sink->text_sink.tabs = NULL;
306    sink->text_sink.char_tabs = NULL;
307#ifndef OLDXAW
308    sink->text_sink.paint = NULL;
309#endif
310}
311
312/*
313 * Function:
314 *	XawTextSinkDestroy
315 *
316 * Parameters:
317 *	w - TextSink Object
318 *
319 * Description:
320 *	This function cleans up when the object is destroyed.
321 */
322static void
323XawTextSinkDestroy(Widget w)
324{
325    TextSinkObject sink = (TextSinkObject) w;
326
327    XtFree((char *)sink->text_sink.tabs);
328    XtFree((char *)sink->text_sink.char_tabs);
329}
330
331/*
332 * Function:
333 *	XawTextSinkSetValues
334 *
335 * Parameters:
336 *	current - current state of the object
337 *	request - what was requested
338 *	cnew	- what the object will become
339 *
340 * Description:
341 *	Sets the values for the TextSink.
342 *
343 * Returns:
344 *	True if redisplay is needed
345 */
346/*ARGSUSED*/
347static Boolean
348XawTextSinkSetValues(Widget current, Widget request _X_UNUSED, Widget cnew,
349		     ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED)
350{
351    TextSinkObject w = (TextSinkObject)cnew;
352    TextSinkObject old_w = (TextSinkObject)current;
353
354    if (w->text_sink.foreground != old_w->text_sink.foreground)
355	((TextWidget)XtParent(cnew))->text.redisplay_needed = True;
356
357    return (False);
358}
359
360/*
361 * Function:
362 *	DisplayText
363 *
364 * Parameters:
365 *	w	  - TextSink Object
366 *	x	  - location to start drawing text
367 *	y	  - ""
368 *	pos1	  - location of starting and ending points in the text buffer
369 *	pos2	  - ""
370 *		 highlight - highlight this text?
371 *
372 * Description:
373 *	Stub function that in subclasses will display text.
374 */
375/*ARGSUSED*/
376static void
377DisplayText(Widget w _X_UNUSED, int x _X_UNUSED, int y _X_UNUSED,
378	    XawTextPosition pos1 _X_UNUSED, XawTextPosition pos2 _X_UNUSED, Bool highlight _X_UNUSED)
379{
380    return;
381}
382
383/*
384 * Function:
385 *	InsertCursor
386 *
387 * Parameters:
388 *	w     - TextSink Object
389 *	x     - location for the cursor
390 *	y     - ""
391 *	state - whether to turn the cursor on, or off
392 *
393 * Description:
394 *	Places the InsertCursor.
395 */
396/*ARGSUSED*/
397static void
398InsertCursor(Widget w _X_UNUSED, int x _X_UNUSED, int y _X_UNUSED, XawTextInsertState state _X_UNUSED)
399{
400    return;
401}
402
403/*
404 * Function:
405 *	ClearToBackground
406 *
407 * Parameters:
408 *	w      - TextSink Object
409 *	x      - location of area to clear
410 *	y      - ""
411 *	width  - size of area to clear
412 *	height - ""
413 *
414 * Description:
415 *	Clears a region of the sink to the background color.
416 */
417/*ARGSUSED*/
418static void
419ClearToBackground(Widget w, int x, int y,
420		  unsigned int width, unsigned int height)
421{
422    /*
423     * Don't clear in height or width are zero
424     * XClearArea() has special semantic for these values
425     */
426    TextWidget xaw = (TextWidget)XtParent(w);
427    Position x1, y1, x2, y2;
428
429    x1 = (Position) (XawMax(x, xaw->text.r_margin.left));
430    y1 = (Position) (XawMax(y, xaw->text.r_margin.top));
431    x2 = (Position) (XawMin(x + (int)width, (int)XtWidth(xaw) - xaw->text.r_margin.right));
432    y2 = (Position) (XawMin(y + (int)height, (int)XtHeight(xaw) - xaw->text.r_margin.bottom));
433
434    x = (int)x1;
435    y = (int)y1;
436    width = (unsigned)(XawMax(0, x2 - x1));
437    height = (unsigned)(XawMax(0, y2 - y1));
438
439    if (height != 0 && width != 0)
440	XClearArea(XtDisplayOfObject(w), XtWindowOfObject(w),
441		   x, y, width, height, False);
442}
443
444/*
445 * Function:
446 *	FindPosition
447 *
448 * Parameters:
449 *	w		- TextSink Object
450 *	fromPos		- reference position
451 *	fromX		- reference location
452 *	width		- width of section to paint text
453 *	stopAtWordBreak - returned position is a word break?
454 *	resPos		- position found (return)
455 *	resWidth	- Width actually used (return)
456 *	resHeight	- Height actually used (return)
457 *
458 * Description:
459 *	Finds a position in the text.
460 */
461/*ARGSUSED*/
462static void
463FindPosition(Widget w _X_UNUSED, XawTextPosition fromPos _X_UNUSED, int fromx _X_UNUSED, int width _X_UNUSED,
464	     Bool stopAtWordBreak _X_UNUSED, XawTextPosition *resPos,
465	     int *resWidth, int *resHeight)
466{
467    *resPos = fromPos;
468    *resHeight = *resWidth = 0;
469}
470
471/*
472 * Function:
473 *	FindDistance
474 *
475 * Parameters:
476 *	w	  - TextSink Object
477 *	fromPos	  - starting Position
478 *	fromX	  - x location of starting Position
479 *	toPos	  - end Position
480 *	resWidth  - Distance between fromPos and toPos
481 *	resPos	  - Actual toPos used
482 *	resHeight - Height required by this text
483 *
484 * Description:
485 *	Find the Pixel Distance between two text Positions.
486 */
487/*ARGSUSED*/
488static void
489FindDistance(Widget w _X_UNUSED, XawTextPosition fromPos, int fromx _X_UNUSED,
490	     XawTextPosition toPos _X_UNUSED, int *resWidth,
491	     XawTextPosition *resPos, int *resHeight)
492{
493    *resWidth = *resHeight = 0;
494    *resPos = fromPos;
495}
496
497/*
498 * Function:
499 *	Resolve
500 *
501 * Parameters:
502 *	w      - TextSink Object
503 *	pos    - reference Position
504 *	fromx  - reference Location
505 *	width  - width to move
506 *	resPos - resulting position
507 *
508 * Description:
509 *	Resolves a location to a position.
510 */
511/*ARGSUSED*/
512static void
513Resolve(Widget w _X_UNUSED, XawTextPosition pos _X_UNUSED, int fromx _X_UNUSED, int width _X_UNUSED,
514	XawTextPosition *resPos)
515{
516    *resPos = pos;
517}
518
519/*
520 * Function:
521 *	MaxLines
522 *
523 * Parameters:
524 *	w      - TextSink Object
525 *	height - height to fit lines into
526 *
527 * Description:
528 *	Finds the Maximum number of lines that will fit in a given height.
529 *
530 * Returns:
531 *	Number of lines that will fit
532 */
533/*ARGSUSED*/
534static int
535MaxLines(Widget w _X_UNUSED, unsigned int height _X_UNUSED)
536{
537    /*
538     * The fontset has gone down to descent Sink Widget, so
539     * the functions such MaxLines, SetTabs... are bound to the descent.
540     *
541     * by Li Yuhong, Jan. 15, 1991
542     */
543    return (0);
544}
545
546/*
547 * Function:
548 *	MaxHeight
549 *
550 * Parameters:
551 *	w     - TextSink Object
552 *	lines - number of lines
553 *
554 * Description:
555 *	Finds the Minimum height that will contain a given number lines.
556 *
557 * Returns:
558 *	the height
559 */
560/*ARGSUSED*/
561static int
562MaxHeight(Widget w _X_UNUSED, int lines _X_UNUSED)
563{
564    return (0);
565}
566
567/*
568 * Function:
569 *	SetTabs
570 *
571 * Parameters:
572 *	w	  - TextSink Object
573 *	tab_count - the number of tabs in the list
574 *	tabs	  - text positions of the tabs
575 * Description:
576 *	Sets the Tab stops.
577 */
578/*ARGSUSED*/
579static void
580SetTabs(Widget w _X_UNUSED, int tab_count _X_UNUSED, short *tabs _X_UNUSED)
581{
582    return;
583}
584
585/*
586 * Function:
587 *	GetCursorBounds
588 *
589 * Parameters:
590 *	w - TextSinkObject.
591 *	rect - X rectangle containing the cursor bounds
592 *
593 * Description:
594 *	Finds the bounding box for the insert cursor (caret)
595 */
596/*ARGSUSED*/
597static void
598GetCursorBounds(Widget w _X_UNUSED, XRectangle *rect)
599{
600    rect->x = rect->y = (short)(rect->width = rect->height = 0);
601}
602
603/*
604 * Public Functions
605 */
606/*
607 * Function:
608 *	XawTextSinkDisplayText
609 *
610 * Parameters:
611 *	w	  - TextSink Object
612 *	x	  - location to start drawing text
613 *	y	  - ""
614 *	pos1	  - location of starting and ending points in the text buffer
615 *	pos2	  - ""
616 *	highlight - highlight this text?
617 */
618/*ARGSUSED*/
619void
620XawTextSinkDisplayText(Widget w,
621#if NeedWidePrototypes
622		       int x, int y,
623#else
624		       Position x, Position y,
625#endif
626		       XawTextPosition pos1, XawTextPosition pos2,
627#if NeedWidePrototypes
628		       int highlight
629#else
630		       Boolean highlight
631#endif
632)
633{
634    _XawTextSinkDisplayText(w, x, y, pos1, pos2, highlight);
635}
636
637void
638_XawTextSinkDisplayText(Widget w, int x, int y,
639			XawTextPosition pos1, XawTextPosition pos2,
640			Bool highlight)
641{
642    TextSinkObjectClass cclass = (TextSinkObjectClass)w->core.widget_class;
643
644    (*cclass->text_sink_class.DisplayText)(w, x, y, pos1, pos2, highlight);
645}
646
647/*
648 * Function:
649 *	XawTextSinkInsertCursor
650 *
651 * Parameters:
652 *	w     - TextSink Object
653 *	x     - location for the cursor
654 *	y     - ""
655 *	state - whether to turn the cursor on, or off
656 *
657 * Description:
658 *	Places the InsertCursor.
659 */
660/*ARGSUSED*/
661void
662#if NeedWidePrototypes
663XawTextSinkInsertCursor(Widget w, int x, int y, int state)
664#else
665XawTextSinkInsertCursor(Widget w, Position x, Position y, XawTextInsertState state)
666#endif
667{
668    TextSinkObjectClass cclass = (TextSinkObjectClass)w->core.widget_class;
669
670    (*cclass->text_sink_class.InsertCursor)(w, x, y, state);
671}
672
673/*
674 * Function:
675 *	XawTextSinkClearToBackground
676 *
677 * Parameters:
678 *	w      - TextSink Object
679 *	x      - location of area to clear
680 *	y      - ""
681 *	width  - size of area to clear
682 *	height - ""
683 *
684 * Description:
685 *	Clears a region of the sink to the background color.
686 */
687/*ARGSUSED*/
688void
689XawTextSinkClearToBackground(Widget w,
690#if NeedWidePrototypes
691			     int x, int y,
692			     unsigned int width, unsigned int height
693#else
694			     Position x, Position y,
695			     Dimension width, Dimension height
696#endif
697)
698{
699    _XawTextSinkClearToBackground(w, x, y, width, height);
700}
701
702void
703_XawTextSinkClearToBackground(Widget w,
704			      int x, int y,
705			      unsigned int width, unsigned int height)
706{
707    TextSinkObjectClass cclass = (TextSinkObjectClass)w->core.widget_class;
708
709    (*cclass->text_sink_class.ClearToBackground)(w, x, y, width, height);
710}
711
712/*
713 * Function:
714 *	XawTextSinkFindPosition
715 *
716 *  Parameters:
717 *	w		- TextSink Object
718 *	fromPos		- reference position
719 *	fromX		- reference location
720 *	width		- width of section to paint text
721 *	stopAtWordBreak - returned position is a word break?
722 *	resPos		- position found (return)
723 *	resWidth	- Width actually used (return)
724 *	resHeight	- Height actually used (return)
725 *
726 * Description:
727 *	Finds a position in the text.
728 */
729/*ARGSUSED*/
730void
731XawTextSinkFindPosition(Widget w, XawTextPosition fromPos, int fromx, int width,
732#if NeedWidePrototypes
733			int stopAtWordBreak,
734#else
735			Boolean stopAtWordBreak,
736#endif
737			XawTextPosition *resPos, int *resWidth, int *resHeight)
738{
739    TextSinkObjectClass cclass = (TextSinkObjectClass)w->core.widget_class;
740
741    (*cclass->text_sink_class.FindPosition)(w, fromPos, fromx, width,
742					    stopAtWordBreak,
743					    resPos, resWidth, resHeight);
744}
745
746/*
747 * Function:
748 *	XawTextSinkFindDistance
749 *
750 *  Parameters:
751 *	w	  - TextSink Object
752 *	fromPos	  - starting Position
753 *	fromX	  - x location of starting Position
754 *	toPos	  - end Position
755 *	resWidth  - Distance between fromPos and toPos
756 *	resPos	  - Actual toPos used
757 *	resHeight - Height required by this text
758 *
759 * Description:
760 *	Find the Pixel Distance between two text Positions.
761 */
762/*ARGSUSED*/
763void
764XawTextSinkFindDistance(Widget w, XawTextPosition fromPos, int fromx,
765			XawTextPosition toPos, int *resWidth,
766			XawTextPosition *resPos, int *resHeight)
767{
768    TextSinkObjectClass cclass = (TextSinkObjectClass)w->core.widget_class;
769
770    (*cclass->text_sink_class.FindDistance)(w, fromPos, fromx, toPos,
771					    resWidth, resPos, resHeight);
772}
773
774/*
775 * Function:
776 *	XawTextSinkResolve
777 *
778 *  Parameters:
779 *	w      - TextSink Object
780 *	pos    - reference Position
781 *	fromx  - reference Location
782 *	width  - width to move
783 *	resPos - resulting position
784 *
785 * Description:
786 *	Resolves a location to a position.
787 */
788/*ARGSUSED*/
789void
790XawTextSinkResolve(Widget w, XawTextPosition pos, int fromx, int width,
791		   XawTextPosition *resPos)
792{
793    TextSinkObjectClass cclass = (TextSinkObjectClass) w->core.widget_class;
794
795    (*cclass->text_sink_class.Resolve)(w, pos, fromx, width, resPos);
796}
797
798/*
799 * Function:
800 *	XawTextSinkMaxLines
801 *
802 *  Parameters:
803 *	w      - TextSink Object
804 *	height - height to fit lines into
805 *
806 * Description:
807 *	Finds the Maximum number of lines that will fit in a given height.
808 *
809 * Returns:
810 *	Number of lines that will fit
811 */
812/*ARGSUSED*/
813int
814#if NeedWidePrototypes
815XawTextSinkMaxLines(Widget w, unsigned int height)
816#else
817XawTextSinkMaxLines(Widget w, Dimension height)
818#endif
819{
820    TextSinkObjectClass cclass = (TextSinkObjectClass)w->core.widget_class;
821
822    return((*cclass->text_sink_class.MaxLines)(w, height));
823}
824
825/*
826 * Function:
827 *	XawTextSinkMaxHeight
828 *
829 *  Parameters:
830 *	w     - TextSink Object
831 *	lines - number of lines
832 *
833 * Description:
834 *	Finds the Minimum height that will contain a given number lines.
835 *
836 * Returns:
837 *	the height
838 */
839/*ARGSUSED*/
840int
841XawTextSinkMaxHeight(Widget w, int lines)
842{
843    TextSinkObjectClass cclass = (TextSinkObjectClass)w->core.widget_class;
844
845    return((*cclass->text_sink_class.MaxHeight)(w, lines));
846}
847
848/*
849 * Function:
850 *	XawTextSinkSetTabs
851 *
852 *  Parameters:
853 *	w	  - TextSink Object
854 *	tab_count - the number of tabs in the list
855 *	tabs	  - text positions of the tabs
856 * Description:
857 *	Sets the Tab stops.
858 */
859void
860XawTextSinkSetTabs(Widget w, int tab_count, int *tabs)
861{
862    if (tab_count > 0) {
863	TextSinkObjectClass cclass = (TextSinkObjectClass)w->core.widget_class;
864	short *char_tabs = (short*)XtMalloc((Cardinal)((unsigned)tab_count * sizeof(short)));
865	short *tab, len = 0;
866	int i;
867
868	for (i = tab_count, tab = char_tabs; i; i--) {
869	    if ((short)*tabs > len)
870		*tab++ = (len = (short)*tabs++);
871	    else {
872		tabs++;
873		--tab_count;
874	    }
875	}
876
877	if (tab_count > 0)
878	    (*cclass->text_sink_class.SetTabs)(w, tab_count, char_tabs);
879	XtFree((char *)char_tabs);
880    }
881}
882
883/*
884 * Function:
885 *	XawTextSinkGetCursorBounds
886 *
887 * Parameters:
888 *	w    - TextSinkObject
889 *	rect - X rectance containing the cursor bounds
890 *
891 * Description:
892 *	Finds the bounding box for the insert cursor (caret).
893 */
894/*ARGSUSED*/
895void
896XawTextSinkGetCursorBounds(Widget w, XRectangle *rect)
897{
898    TextSinkObjectClass cclass = (TextSinkObjectClass)w->core.widget_class;
899
900    (*cclass->text_sink_class.GetCursorBounds)(w, rect);
901}
902
903#ifndef OLDXAW
904Bool
905XawTextSinkBeginPaint(Widget w)
906{
907    TextSinkObjectClass cclass = (TextSinkObjectClass)w->core.widget_class;
908
909    if (cclass->text_sink_class.extension->BeginPaint == NULL ||
910	cclass->text_sink_class.extension->PreparePaint == NULL ||
911	cclass->text_sink_class.extension->DoPaint == NULL ||
912	cclass->text_sink_class.extension->EndPaint == NULL)
913	return (False);
914
915    return ((*cclass->text_sink_class.extension->BeginPaint)(w));
916}
917
918static Bool
919BeginPaint(Widget w)
920{
921    TextSinkObject sink = (TextSinkObject)w;
922
923    if (sink->text_sink.paint != NULL)
924	return (False);
925
926    sink->text_sink.paint = XtNew(XawTextPaintList);
927    sink->text_sink.paint->clip = XmuCreateArea();
928    sink->text_sink.paint->hightabs = NULL;
929    sink->text_sink.paint->paint = NULL;
930    sink->text_sink.paint->bearings = NULL;
931
932    return (True);
933}
934
935void
936XawTextSinkPreparePaint(Widget w, int y, int line, XawTextPosition from,
937			XawTextPosition to, Bool highlight)
938{
939    TextSinkObjectClass cclass = (TextSinkObjectClass)w->core.widget_class;
940
941    (*cclass->text_sink_class.extension->PreparePaint)
942	(w, y, line, from, to, highlight);
943}
944
945void
946XawTextSinkDoPaint(Widget w)
947{
948    TextSinkObjectClass cclass = (TextSinkObjectClass)w->core.widget_class;
949
950    (*cclass->text_sink_class.extension->DoPaint)(w);
951}
952
953Bool
954XawTextSinkEndPaint(Widget w)
955{
956    TextSinkObjectClass cclass = (TextSinkObjectClass)w->core.widget_class;
957
958    return ((*cclass->text_sink_class.extension->EndPaint)(w));
959}
960
961static Bool
962EndPaint(Widget w)
963{
964    TextSinkObject sink = (TextSinkObject)w;
965    XawTextPaintStruct *paint, *next;
966
967    if (sink->text_sink.paint == NULL)
968	return (False);
969
970    XmuDestroyArea(sink->text_sink.paint->clip);
971    if (sink->text_sink.paint->hightabs)
972	XmuDestroyArea(sink->text_sink.paint->hightabs);
973    paint = sink->text_sink.paint->paint;
974    while (paint) {
975	next = paint->next;
976	if (paint->text)
977	    XtFree((XtPointer)paint->text);
978	if (paint->backtabs)
979	    XmuDestroyArea(paint->backtabs);
980	XtFree((XtPointer)paint);
981	paint = next;
982    }
983
984    paint = sink->text_sink.paint->bearings;
985    while (paint) {
986	next = paint->next;
987	if (paint->text)
988	    XtFree((XtPointer)paint->text);
989	XtFree((XtPointer)paint);
990	paint = next;
991    }
992
993    XtFree((XtPointer)sink->text_sink.paint);
994    sink->text_sink.paint = NULL;
995    return (True);
996}
997
998static XawTextPropertyList **prop_lists;
999static Cardinal num_prop_lists;
1000
1001static int
1002bcmp_qident(_Xconst void *left, _Xconst void *right)
1003{
1004    return (int)((long)left - (*(XawTextProperty**)right)->identifier);
1005}
1006
1007static int
1008qcmp_qident(_Xconst void *left, _Xconst void *right)
1009{
1010    return ((*(XawTextProperty**)left)->identifier -
1011	    (*(XawTextProperty**)right)->identifier);
1012}
1013
1014static void
1015SetXlfdDefaults(Display *display, XawTextProperty *property)
1016{
1017    Atom atom = XInternAtom(display, "FONT", True);
1018    unsigned long value;
1019    char *str;
1020
1021    if (XGetFontProperty(property->font, atom, &value)) {
1022	char *xlfd = XGetAtomName(display, value);
1023
1024	if (xlfd) {
1025	    char *sep = xlfd + 1;
1026	    char *name = sep;
1027
1028	    property->xlfd = XrmStringToQuark(xlfd);
1029
1030	    sep = strchr(sep, '-');     *sep++ = '\0';
1031	    property->foundry = XrmStringToQuark(name);
1032	    name = sep;
1033
1034	    sep = strchr(sep, '-');	*sep++ = '\0';
1035	    property->family = XrmStringToQuark(name);
1036	    name = sep;
1037
1038	    sep = strchr(sep, '-');	*sep++ = '\0';
1039	    property->weight = XrmStringToQuark(name);
1040	    name = sep;
1041
1042	    sep = strchr(sep, '-');	*sep++ = '\0';
1043	    property->slant = XrmStringToQuark(name);
1044	    name = sep;
1045
1046	    sep = strchr(sep, '-');	*sep++ = '\0';
1047	    property->setwidth = XrmStringToQuark(name);
1048	    name = sep;
1049
1050	    sep = strchr(sep, '-');     *sep++ = '\0';
1051	    property->addstyle = XrmStringToQuark(name);
1052	    name = sep;
1053
1054	    sep = strchr(sep, '-');     *sep++ = '\0';
1055	    property->pixel_size = XrmStringToQuark(name);
1056	    name = sep;
1057
1058	    sep = strchr(sep, '-');     *sep++ = '\0';
1059	    property->point_size = XrmStringToQuark(name);
1060	    name = sep;
1061
1062	    sep = strchr(sep, '-');     *sep++ = '\0';
1063	    property->res_x = XrmStringToQuark(name);
1064	    name = sep;
1065
1066	    sep = strchr(sep, '-');     *sep++ = '\0';
1067	    property->res_y = XrmStringToQuark(name);
1068	    name = sep;
1069
1070	    sep = strchr(sep, '-');     *sep++ = '\0';
1071	    property->spacing = XrmStringToQuark(name);
1072	    name = sep;
1073
1074	    sep = strchr(sep, '-');     *sep++ = '\0';
1075	    property->avgwidth = XrmStringToQuark(name);
1076	    name = sep;
1077
1078	    sep = strchr(sep, '-');     *sep++ = '\0';
1079	    property->registry = XrmStringToQuark(name);
1080	    name = sep;
1081
1082	    property->encoding = XrmStringToQuark(name);
1083
1084	    XFree(xlfd);
1085	}
1086    }
1087
1088    atom = XInternAtom(display, "UNDERLINE_THICKNESS", True);
1089    if (XGetFontProperty(property->font, atom, &value) &&
1090	(str = XGetAtomName(display, value)) != NULL) {
1091	property->underline_thickness = (short)(atoi(str));
1092	XFree(str);
1093    }
1094    else {
1095	/* XLFD says:
1096	 * CapStemWidth = average width of the stems of capitals
1097	 * if (UNDERLINE_THICKNESS undefined) then
1098	 *   UNDERLINE_THICKNESS = CapStemWidth
1099	 *
1100	 * How do I know the value of CapStemWidth??
1101	 */
1102	if (property->pixel_size != NULLQUARK) {
1103	    property->underline_thickness =
1104		(short)(atoi(XrmQuarkToString(property->pixel_size)) / 10);
1105	    property->underline_thickness =
1106		(XawMax(1, property->underline_thickness));
1107	}
1108	else
1109	    property->underline_thickness = 1;
1110    }
1111
1112    atom = XInternAtom(display, "UNDERLINE_POSITION", True);
1113    if (XGetFontProperty(property->font, atom, &value) &&
1114	(str = XGetAtomName(display, value)) != NULL) {
1115	property->underline_position = (short)(atoi(str));
1116	XFree(str);
1117    }
1118    else
1119	/* XLFD says:
1120	 * if (UNDERLINE_POSITION undefined) then
1121	 *   UNDERLINE_POSITION = ROUND((maximum_descent) / 2)
1122	 */
1123	property->underline_position =
1124	    property->font->max_bounds.descent >> 1;
1125
1126    /* I am assuming xlfd does not consider that lines are
1127     * centered in the path */
1128    property->underline_position = (short)(property->underline_position
1129					   + (property->underline_thickness >> 1));
1130}
1131
1132static void
1133DestroyTextPropertyList(XawTextPropertyList *list)
1134{
1135    int i;
1136
1137    for (i = 0; (Cardinal)i < list->num_properties; i++) {
1138	if (list->properties[i]->font)
1139	    XFreeFont(DisplayOfScreen(list->screen), list->properties[i]->font);
1140	XtFree((char*)list->properties[i]);
1141    }
1142    if (list->properties)
1143	XtFree((char*)list->properties);
1144    XtFree((char*)list);
1145}
1146
1147static XawTextProperty *
1148_XawTextSinkGetProperty(XawTextPropertyList *list, XrmQuark property)
1149{
1150    if (property != NULLQUARK && list && list->properties) {
1151	XawTextProperty **ptr = (XawTextProperty**)
1152	    bsearch((void*)(long)property,
1153		    list->properties, list->num_properties,
1154		    sizeof(XawTextProperty*), bcmp_qident);
1155
1156	if (ptr)
1157	    return (*ptr);
1158    }
1159
1160    return (NULL);
1161}
1162
1163XawTextProperty *
1164XawTextSinkGetProperty(Widget w, XrmQuark property)
1165{
1166    TextSinkObject sink = (TextSinkObject)w;
1167    XawTextPropertyList *list = sink->text_sink.properties;
1168
1169    return (_XawTextSinkGetProperty(list, property));
1170}
1171
1172XawTextProperty *
1173XawTextSinkCopyProperty(Widget w, XrmQuark property)
1174{
1175    XawTextProperty *cur, *ret;
1176
1177    if ((cur = XawTextSinkGetProperty(w, property)) == NULL)
1178	cur = XawTextSinkGetProperty(w, Qdefault);
1179    ret = (XawTextProperty*)XtCalloc(1, sizeof(XawTextProperty));
1180    if (cur)
1181	memcpy(ret, cur, sizeof(XawTextProperty));
1182    ret->identifier = NULLQUARK;
1183    ret->mask &= (unsigned long)(~XAW_TPROP_FONT);
1184
1185    return (ret);
1186}
1187
1188static XawTextProperty *
1189_XawTextSinkAddProperty(XawTextPropertyList *list, XawTextProperty *property,
1190			Bool replace)
1191{
1192    XawTextProperty *result;
1193    XColor color;
1194    char identifier[1024];
1195    char foreground[16];
1196    char background[16];
1197    const char *foundry, *family, *weight, *slant, *setwidth, *addstyle, *pixel_size,
1198	 *point_size, *res_x, *res_y, *spacing, *avgwidth, *registry, *encoding;
1199    const char *xlfd;
1200    static const char *asterisk = "*";
1201    static const char *null = "";
1202    XrmQuark quark;
1203
1204    if (list == NULL || property == NULL)
1205	return (NULL);
1206
1207    if (property->mask & XAW_TPROP_FOREGROUND) {
1208	color.pixel = property->foreground;
1209	XQueryColor(DisplayOfScreen(list->screen), list->colormap, &color);
1210	snprintf(foreground, sizeof(foreground), "%04x%04x%04x",
1211		 color.red, color.green, color.blue);
1212    }
1213    else
1214	strcpy(foreground, asterisk);
1215    if (property->mask & XAW_TPROP_BACKGROUND) {
1216	color.pixel = property->background;
1217	XQueryColor(DisplayOfScreen(list->screen), list->colormap, &color);
1218	snprintf(background, sizeof(background), "%04x%04x%04x",
1219		 color.red, color.green, color.blue);
1220    }
1221    else
1222	strcpy(background, asterisk);
1223
1224    if (property->xlfd_mask & XAW_TPROP_FOUNDRY)
1225	foundry = XrmQuarkToString(property->foundry);
1226    else
1227	foundry = asterisk;
1228
1229    /* use default, or what was requested */
1230    if (property->family != NULLQUARK)
1231	family = XrmQuarkToString(property->family);
1232    else
1233	family = asterisk;
1234    if (property->weight != NULLQUARK)
1235	weight = XrmQuarkToString(property->weight);
1236    else
1237	weight = asterisk;
1238    if (property->slant != NULLQUARK) {
1239	slant = XrmQuarkToString(property->slant);
1240	if (toupper((unsigned char)*slant) != 'R')
1241	    slant = asterisk;	/* X defaults to italics, so, don't
1242				   care in resolving between `I' and `O' */
1243    }
1244    else
1245	slant = asterisk;
1246
1247    if (property->xlfd_mask & XAW_TPROP_SETWIDTH)
1248	setwidth = XrmQuarkToString(property->setwidth);
1249    else
1250	setwidth = asterisk;
1251    if (property->xlfd_mask & XAW_TPROP_ADDSTYLE)
1252	addstyle = XrmQuarkToString(property->addstyle);
1253    else
1254	addstyle = null;
1255
1256    /* use default, or what was requested */
1257    if (!(property->mask & XAW_TPROP_POINTSIZE) &&
1258	property->pixel_size != NULLQUARK)
1259	pixel_size = XrmQuarkToString(property->pixel_size);
1260    else
1261	pixel_size = asterisk;
1262
1263    if (property->xlfd_mask & XAW_TPROP_POINTSIZE)
1264	point_size = XrmQuarkToString(property->point_size);
1265    else
1266	point_size = asterisk;
1267    if (property->xlfd_mask & XAW_TPROP_RESX)
1268	res_x = XrmQuarkToString(property->res_x);
1269    else
1270	res_x = asterisk;
1271    if (property->xlfd_mask & XAW_TPROP_RESY)
1272	res_y = XrmQuarkToString(property->res_y);
1273    else
1274	res_y = asterisk;
1275    if (property->xlfd_mask & XAW_TPROP_SPACING)
1276	spacing = XrmQuarkToString(property->spacing);
1277    else
1278	spacing = asterisk;
1279    if (property->xlfd_mask & XAW_TPROP_AVGWIDTH)
1280	avgwidth = XrmQuarkToString(property->avgwidth);
1281    else
1282	avgwidth = asterisk;
1283
1284    /* use default, or what that was requested */
1285    if (property->registry != NULLQUARK)
1286	registry = XrmQuarkToString(property->registry);
1287    else
1288	registry = asterisk;
1289    if (property->encoding != NULLQUARK)
1290	encoding = XrmQuarkToString(property->encoding);
1291    else
1292	encoding = asterisk;
1293
1294    if (replace) {
1295	result = XtNew(XawTextProperty);
1296	memcpy(result, property, sizeof(XawTextProperty));
1297    }
1298    else
1299	result = property;
1300
1301    /* XXX should do the best to load a suitable font here */
1302    if (!(result->mask & XAW_TPROP_FONT)) {
1303	snprintf(identifier, sizeof(identifier),
1304		 "-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s",
1305		 foundry, family, weight, slant, setwidth, addstyle,
1306		 pixel_size, point_size, res_x, res_y, spacing, avgwidth,
1307		 registry, encoding);
1308	if ((result->font = XLoadQueryFont(DisplayOfScreen(list->screen),
1309					   identifier)) != NULL) {
1310	    result->mask |= XAW_TPROP_FONT;
1311	    SetXlfdDefaults(DisplayOfScreen(list->screen), result);
1312	}
1313	else
1314	    result->mask &= (unsigned long)(~XAW_TPROP_FONT);
1315    }
1316
1317    if (result->font)
1318	xlfd = XrmQuarkToString(result->xlfd);
1319    else
1320	xlfd = null;
1321
1322    snprintf(identifier, sizeof(identifier), "%08lx%08lx%s%s%d%d%d%d%s",
1323	     property->mask, property->xlfd_mask,
1324	     foreground, background,
1325	     (result->mask & XAW_TPROP_UNDERLINE) != 0,
1326	     (result->mask & XAW_TPROP_OVERSTRIKE) != 0,
1327	     (result->mask & XAW_TPROP_SUBSCRIPT) != 0,
1328	     (result->mask & XAW_TPROP_SUPERSCRIPT) != 0,
1329	     xlfd);
1330
1331    quark = XrmStringToQuark(identifier);
1332    if (result->identifier == NULLQUARK)
1333	result->identifier = quark;
1334    result->code = quark;
1335
1336    if ((property = _XawTextSinkGetProperty(list, result->identifier)) != NULL) {
1337	if (result->font)
1338	    XFreeFont(DisplayOfScreen(list->screen), result->font);
1339	if (replace)
1340	    XtFree((XtPointer)result);
1341
1342	return (property);
1343    }
1344
1345    list->properties = (XawTextProperty**)
1346	XtRealloc((XtPointer)list->properties,
1347		  (Cardinal)(sizeof(XawTextProperty*) *
1348			     (list->num_properties + 1)));
1349    list->properties[list->num_properties++] = result;
1350    qsort((void*)list->properties, list->num_properties,
1351	      sizeof(XawTextProperty*), qcmp_qident);
1352
1353    return (result);
1354}
1355
1356XawTextProperty *
1357XawTextSinkAddProperty(Widget w, XawTextProperty *property)
1358{
1359    TextSinkObject sink = (TextSinkObject)w;
1360    XawTextPropertyList *list = sink->text_sink.properties;
1361
1362    return (_XawTextSinkAddProperty(list, property, True));
1363}
1364
1365XawTextProperty *
1366XawTextSinkCombineProperty(Widget w _X_UNUSED,
1367			   XawTextProperty *property, XawTextProperty *combine,
1368			   Bool override)
1369{
1370    if (property == NULL || combine == NULL)
1371	return (property);
1372
1373    if ((override || !(property->mask & XAW_TPROP_FOREGROUND)) &&
1374	(combine->mask & XAW_TPROP_FOREGROUND)) {
1375	property->mask |= XAW_TPROP_FOREGROUND;
1376	property->foreground = combine->foreground;
1377    }
1378    if ((override || !(property->mask & XAW_TPROP_BACKGROUND)) &&
1379	(combine->mask & XAW_TPROP_BACKGROUND)) {
1380	property->mask |= XAW_TPROP_BACKGROUND;
1381	property->background = combine->background;
1382    }
1383    if ((override || !(property->mask & XAW_TPROP_FPIXMAP)) &&
1384	(combine->mask & XAW_TPROP_FPIXMAP)) {
1385	property->mask |= XAW_TPROP_FPIXMAP;
1386	property->foreground_pixmap = combine->foreground_pixmap;
1387    }
1388    if ((override || !(property->mask & XAW_TPROP_BPIXMAP)) &&
1389	(combine->mask & XAW_TPROP_BPIXMAP)) {
1390	property->mask |= XAW_TPROP_BPIXMAP;
1391	property->background_pixmap = combine->background_pixmap;
1392    }
1393    if (combine->mask & XAW_TPROP_UNDERLINE)
1394	property->mask |= XAW_TPROP_UNDERLINE;
1395    if (combine->mask & XAW_TPROP_OVERSTRIKE)
1396	property->mask |= XAW_TPROP_OVERSTRIKE;
1397    if ((override || !(property->mask & XAW_TPROP_SUPERSCRIPT)) &&
1398	(combine->mask & XAW_TPROP_SUBSCRIPT))
1399	property->mask |= XAW_TPROP_SUBSCRIPT;
1400    if ((property->mask & XAW_TPROP_SUBSCRIPT) &&
1401	(combine->mask & XAW_TPROP_SUPERSCRIPT))
1402	property->mask |= XAW_TPROP_SUPERSCRIPT;
1403    if ((override || !(property->xlfd_mask & XAW_TPROP_FOUNDRY)) &&
1404	(combine->xlfd_mask & XAW_TPROP_FOUNDRY)) {
1405	property->xlfd_mask |= XAW_TPROP_FOUNDRY;
1406	property->foundry = combine->foundry;
1407    }
1408    if ((override || !(property->xlfd_mask & XAW_TPROP_FAMILY)) &&
1409	(combine->xlfd_mask & XAW_TPROP_FAMILY)) {
1410	property->xlfd_mask |= XAW_TPROP_FAMILY;
1411	property->family = combine->family;
1412    }
1413    if ((override || !(property->xlfd_mask & XAW_TPROP_WEIGHT)) &&
1414	(combine->xlfd_mask & XAW_TPROP_WEIGHT)) {
1415	property->xlfd_mask |= XAW_TPROP_WEIGHT;
1416	property->weight = combine->weight;
1417    }
1418    if ((override || !(property->xlfd_mask & XAW_TPROP_SLANT)) &&
1419	(combine->xlfd_mask & XAW_TPROP_SLANT)) {
1420	property->xlfd_mask |= XAW_TPROP_SLANT;
1421	property->slant = combine->slant;
1422    }
1423    if ((override || !(property->xlfd_mask & XAW_TPROP_SETWIDTH)) &&
1424	(combine->xlfd_mask & XAW_TPROP_SETWIDTH)) {
1425	property->xlfd_mask |= XAW_TPROP_SETWIDTH;
1426	property->setwidth = combine->setwidth;
1427    }
1428    if ((override || !(property->xlfd_mask & XAW_TPROP_ADDSTYLE)) &&
1429	(combine->xlfd_mask & XAW_TPROP_ADDSTYLE)) {
1430	property->xlfd_mask |= XAW_TPROP_ADDSTYLE;
1431	property->addstyle = combine->addstyle;
1432    }
1433    if ((override || !(property->xlfd_mask & XAW_TPROP_PIXELSIZE)) &&
1434	(combine->xlfd_mask & XAW_TPROP_PIXELSIZE)) {
1435	property->xlfd_mask |= XAW_TPROP_PIXELSIZE;
1436	property->pixel_size = combine->pixel_size;
1437    }
1438    if ((override || !(property->xlfd_mask & XAW_TPROP_POINTSIZE)) &&
1439	(combine->xlfd_mask & XAW_TPROP_POINTSIZE)) {
1440	property->xlfd_mask |= XAW_TPROP_POINTSIZE;
1441	property->point_size = combine->point_size;
1442    }
1443    if ((override || !(property->xlfd_mask & XAW_TPROP_RESX)) &&
1444	(combine->xlfd_mask & XAW_TPROP_RESX)) {
1445	property->xlfd_mask |= XAW_TPROP_RESX;
1446	property->res_x = combine->res_x;
1447    }
1448    if ((override || !(property->xlfd_mask & XAW_TPROP_RESY)) &&
1449	(combine->xlfd_mask & XAW_TPROP_RESY)) {
1450	property->xlfd_mask |= XAW_TPROP_RESY;
1451	property->res_y = combine->res_y;
1452    }
1453    if ((override || !(property->xlfd_mask & XAW_TPROP_SPACING)) &&
1454	(combine->xlfd_mask & XAW_TPROP_SPACING)) {
1455	property->xlfd_mask |= XAW_TPROP_SPACING;
1456	property->spacing = combine->spacing;
1457    }
1458    if ((override || !(property->xlfd_mask & XAW_TPROP_AVGWIDTH)) &&
1459	(combine->xlfd_mask & XAW_TPROP_AVGWIDTH)) {
1460	property->xlfd_mask |= XAW_TPROP_AVGWIDTH;
1461	property->avgwidth = combine->avgwidth;
1462    }
1463    if ((override || !(property->xlfd_mask & XAW_TPROP_REGISTRY)) &&
1464	(combine->xlfd_mask & XAW_TPROP_REGISTRY)) {
1465	property->xlfd_mask |= XAW_TPROP_REGISTRY;
1466	property->registry = combine->registry;
1467    }
1468    if ((override || !(property->xlfd_mask & XAW_TPROP_ENCODING)) &&
1469	(combine->xlfd_mask & XAW_TPROP_ENCODING)) {
1470	property->xlfd_mask |= XAW_TPROP_ENCODING;
1471	property->encoding = combine->encoding;
1472    }
1473
1474    return (property);
1475}
1476
1477/*
1478 * The default property must be defined first, if the code is willing to
1479 * combine properties.
1480 */
1481XawTextPropertyList *
1482XawTextSinkConvertPropertyList(String name, String spec, Screen *screen,
1483			       Colormap colormap, int depth)
1484{
1485    XrmQuark qname = XrmStringToQuark(name);
1486    XawTextPropertyList **ptr = NULL;
1487    XawTextPropertyList *propl, *prev = NULL;
1488    XawTextProperty *def_prop = NULL;
1489    char * str;
1490    String tok;
1491    char *tmp;
1492    char buffer[BUFSIZ];
1493
1494    if (prop_lists) ptr = (XawTextPropertyList**)
1495	bsearch((void*)(long)qname, prop_lists, num_prop_lists,
1496		sizeof(XawTextPropertyList*), bcmp_qident);
1497    if (ptr) {
1498	propl = *ptr;
1499	while (propl) {
1500	    prev = propl;
1501	    if (propl->screen == screen &&
1502		propl->colormap == colormap &&
1503		propl->depth == depth)
1504		return (propl);
1505	    propl = propl->next;
1506	}
1507    }
1508
1509    propl = XtNew(XawTextPropertyList);
1510    propl->identifier = qname;
1511    propl->screen = screen;
1512    propl->colormap = colormap;
1513    propl->depth = depth;
1514    propl->next = NULL;
1515
1516    if (prev)
1517	prev->next = propl;
1518
1519    propl->properties = NULL;
1520    propl->num_properties = 0;
1521
1522    str = XtNewString(spec);
1523    for (tok = str; tok; tok = tmp) {
1524	XawTextProperty *prop;
1525	XawParams *params;
1526	XrmQuark ident;
1527	XawArgVal *argval;
1528	XColor color, exact;
1529
1530	if (def_prop == NULL && propl->num_properties)
1531	    def_prop = _XawTextSinkGetProperty(propl, Qdefault);
1532	tmp = strchr(tok, ',');
1533	if (tmp) {
1534	    *tmp = '\0';
1535	    if (*++tmp == '\0')
1536		tmp = NULL;
1537	}
1538	params = XawParseParamsString(tok);
1539	ident = XrmStringToQuark(params->name);
1540	if (ident == NULLQUARK) {
1541	    snprintf(buffer, sizeof(buffer), "Bad text property name \"%s\".",
1542		     params->name);
1543	    XtAppWarning(XtDisplayToApplicationContext
1544			 (DisplayOfScreen(screen)), buffer);
1545	    DestroyTextPropertyList(propl);
1546	    if (prev)
1547		prev->next = NULL;
1548	    XawFreeParamsStruct(params);
1549	    return (NULL);
1550	}
1551	else if (_XawTextSinkGetProperty(propl, ident) != NULL) {
1552	    XawFreeParamsStruct(params);
1553	    continue;
1554	}
1555
1556	prop = (XawTextProperty*)XtCalloc(1, sizeof(XawTextProperty));
1557	prop->identifier = ident;
1558
1559	if ((argval = XawFindArgVal(params, "font")) != NULL &&
1560	    argval->value) {
1561
1562	    if ((prop->font = XLoadQueryFont(DisplayOfScreen(screen),
1563					     argval->value)) == NULL) {
1564		snprintf(buffer, sizeof(buffer), "Cannot load font \"%s\".",
1565			 argval->value);
1566		XtAppWarning(XtDisplayToApplicationContext
1567			     (DisplayOfScreen(screen)), buffer);
1568		DestroyTextPropertyList(propl);
1569		if (prev)
1570		    prev->next = NULL;
1571		XawFreeParamsStruct(params);
1572		XtFree((char *)prop);
1573		return (NULL);
1574	    }
1575	    prop->mask |= XAW_TPROP_FONT;
1576	    SetXlfdDefaults(DisplayOfScreen(screen), prop);
1577	}
1578	/* fontset processing here */
1579
1580	if ((argval = XawFindArgVal(params, "foreground")) != NULL &&
1581	    argval->value) {
1582	    if (!XAllocNamedColor(DisplayOfScreen(screen), colormap,
1583				  argval->value, &color, &exact)) {
1584		snprintf(buffer, sizeof(buffer),
1585			 "Cannot allocate color \"%s\".", argval->value);
1586		XtAppWarning(XtDisplayToApplicationContext
1587			     (DisplayOfScreen(screen)), buffer);
1588		DestroyTextPropertyList(propl);
1589		if (prev)
1590		    prev->next = NULL;
1591		XawFreeParamsStruct(params);
1592		XtFree((char *)prop);
1593		return (NULL);
1594	    }
1595	    prop->foreground = color.pixel;
1596	    prop->mask |= XAW_TPROP_FOREGROUND;
1597	}
1598	if ((argval = XawFindArgVal(params, "background")) != NULL &&
1599	    argval->value) {
1600	    if (!XAllocNamedColor(DisplayOfScreen(screen), colormap,
1601				  argval->value, &color, &exact)) {
1602		snprintf(buffer, sizeof(buffer),
1603			 "Cannot allocate color \"%s\".", argval->value);
1604		XtAppWarning(XtDisplayToApplicationContext
1605			     (DisplayOfScreen(screen)), buffer);
1606		DestroyTextPropertyList(propl);
1607		if (prev)
1608		    prev->next = NULL;
1609		XawFreeParamsStruct(params);
1610		XtFree((char *)prop);
1611		return (NULL);
1612	    }
1613	    prop->background = color.pixel;
1614	    prop->mask |= XAW_TPROP_BACKGROUND;
1615	}
1616	/* foreground_pixmap and background_pixmap processing here */
1617
1618	if (XawFindArgVal(params, "underline"))
1619	    prop->mask |= XAW_TPROP_UNDERLINE;
1620	if (XawFindArgVal(params, "overstrike"))
1621	    prop->mask |= XAW_TPROP_OVERSTRIKE;
1622
1623	if (XawFindArgVal(params, "subscript"))
1624	    prop->mask |= XAW_TPROP_SUBSCRIPT;
1625	else if (XawFindArgVal(params, "superscript"))
1626	    prop->mask |= XAW_TPROP_SUPERSCRIPT;
1627
1628	/* xlfd */
1629	if ((argval = XawFindArgVal(params, "foundry")) != NULL &&
1630	    argval->value) {
1631	    prop->xlfd_mask |= XAW_TPROP_FOUNDRY;
1632	    prop->foundry = XrmStringToQuark(argval->value);
1633	}
1634	if ((argval = XawFindArgVal(params, "family")) != NULL &&
1635	    argval->value) {
1636	    prop->xlfd_mask |= XAW_TPROP_FAMILY;
1637	    prop->family = XrmStringToQuark(argval->value);
1638	}
1639	if ((argval = XawFindArgVal(params, "weight")) != NULL &&
1640	    argval->value) {
1641	    prop->xlfd_mask |= XAW_TPROP_WEIGHT;
1642	    prop->weight = XrmStringToQuark(argval->value);
1643	}
1644	if ((argval = XawFindArgVal(params, "slant")) != NULL &&
1645	    argval->value) {
1646	    prop->xlfd_mask |= XAW_TPROP_SLANT;
1647	    prop->slant = XrmStringToQuark(argval->value);
1648	}
1649	if ((argval = XawFindArgVal(params, "setwidth")) != NULL &&
1650	    argval->value) {
1651	    prop->xlfd_mask |= XAW_TPROP_SETWIDTH;
1652	    prop->setwidth = XrmStringToQuark(argval->value);
1653	}
1654	if ((argval = XawFindArgVal(params, "addstyle")) != NULL &&
1655	    argval->value) {
1656	    prop->xlfd_mask |= XAW_TPROP_ADDSTYLE;
1657	    prop->addstyle = XrmStringToQuark(argval->value);
1658	}
1659	if ((argval = XawFindArgVal(params, "pixelsize")) != NULL &&
1660	    argval->value) {
1661	    prop->xlfd_mask |= XAW_TPROP_PIXELSIZE;
1662	    prop->pixel_size = XrmStringToQuark(argval->value);
1663	}
1664	if ((argval = XawFindArgVal(params, "pointsize")) != NULL &&
1665	    argval->value) {
1666	    prop->xlfd_mask |= XAW_TPROP_POINTSIZE;
1667	    prop->point_size = XrmStringToQuark(argval->value);
1668	}
1669	if ((argval = XawFindArgVal(params, "resx")) != NULL &&
1670	    argval->value) {
1671	    prop->xlfd_mask |= XAW_TPROP_RESX;
1672	    prop->res_x = XrmStringToQuark(argval->value);
1673	}
1674	if ((argval = XawFindArgVal(params, "resy")) != NULL &&
1675	    argval->value) {
1676	    prop->xlfd_mask |= XAW_TPROP_RESY;
1677	    prop->res_y = XrmStringToQuark(argval->value);
1678	}
1679	if ((argval = XawFindArgVal(params, "spacing")) != NULL &&
1680	    argval->value) {
1681	    prop->xlfd_mask |= XAW_TPROP_SPACING;
1682	    prop->spacing = XrmStringToQuark(argval->value);
1683	}
1684	if ((argval = XawFindArgVal(params, "avgwidth")) != NULL &&
1685	    argval->value) {
1686	    prop->xlfd_mask |= XAW_TPROP_AVGWIDTH;
1687	    prop->avgwidth = XrmStringToQuark(argval->value);
1688	}
1689	if ((argval = XawFindArgVal(params, "registry")) != NULL &&
1690	    argval->value) {
1691	    prop->xlfd_mask |= XAW_TPROP_REGISTRY;
1692	    prop->registry = XrmStringToQuark(argval->value);
1693	}
1694	if ((argval = XawFindArgVal(params, "encoding")) != NULL &&
1695	    argval->value) {
1696	    prop->xlfd_mask |= XAW_TPROP_ENCODING;
1697	    prop->encoding = XrmStringToQuark(argval->value);
1698	}
1699
1700	if (def_prop)
1701	    (void)XawTextSinkCombineProperty(NULL, prop, def_prop, False);
1702	(void)_XawTextSinkAddProperty(propl, prop, False);
1703
1704	XawFreeParamsStruct(params);
1705    }
1706
1707    prop_lists = (XawTextPropertyList**)
1708    XtRealloc((XtPointer)prop_lists,
1709	      (Cardinal)(sizeof(XawTextPropertyList*) *
1710			 (num_prop_lists + 1)));
1711    prop_lists[num_prop_lists++] = propl;
1712    qsort((void*)prop_lists, num_prop_lists, sizeof(XawTextPropertyList*),
1713	  qcmp_qident);
1714
1715    XtFree(str);
1716
1717    return (propl);
1718}
1719
1720/*ARGSUSED*/
1721static Boolean
1722CvtStringToPropertyList(Display *dpy, XrmValue *args, Cardinal *num_args,
1723			XrmValue *fromVal, XrmValue *toVal,
1724			XtPointer *converter_data _X_UNUSED)
1725{
1726    XawTextPropertyList *propl = NULL;
1727    String name;
1728    Widget w;
1729
1730    if (*num_args != 1) {
1731      XtAppWarningMsg(XtDisplayToApplicationContext(dpy),
1732		      "wrongParameters", "cvtStringToTextProperties",
1733		      "ToolkitError",
1734		      "String to textProperties conversion needs widget argument",
1735		      NULL, NULL);
1736	return (False);
1737    }
1738
1739    w = *(Widget*)args[0].addr;
1740    while (w && !XtIsWidget(w))
1741	w = XtParent(w);
1742
1743    name = (String)(fromVal[0].addr);
1744
1745    if (w) {
1746	XawTextPropertyList **ptr = NULL;
1747	if (prop_lists) ptr = (XawTextPropertyList**)
1748	    bsearch((void*)(long)XrmStringToQuark(name),
1749		    prop_lists, num_prop_lists,
1750		    sizeof(XawTextPropertyList*), bcmp_qident);
1751
1752	if (ptr) {
1753	    Screen *screen = w->core.screen;
1754	    Colormap colormap = w->core.colormap;
1755	    int depth = (int)w->core.depth;
1756
1757	    propl = *ptr;
1758	    while (propl) {
1759		if (propl->screen == screen &&
1760		    propl->colormap == colormap &&
1761		    propl->depth == depth)
1762		    break;
1763		propl = propl->next;
1764	    }
1765	}
1766    }
1767
1768    if (!propl) {
1769	XtDisplayStringConversionWarning(dpy, (String)fromVal->addr,
1770					 XawRTextProperties);
1771	toVal->addr = NULL;
1772	toVal->size = sizeof(XawTextPropertyList*);
1773	return (False);
1774    }
1775
1776    if (toVal->addr != NULL) {
1777	if (toVal->size < sizeof(XawTextPropertyList*))	{
1778	    toVal->size = sizeof(XawTextPropertyList*);
1779	    return (False);
1780	}
1781	*(XawTextPropertyList**)(toVal->addr) = propl;
1782    }
1783    else {
1784	static XawTextPropertyList *static_val;
1785
1786	static_val = propl;
1787	toVal->addr = (XPointer)&static_val;
1788    }
1789    toVal->size = sizeof(XawTextProperty*);
1790
1791    return (True);
1792}
1793
1794/*ARGSUSED*/
1795static Boolean
1796CvtPropertyListToString(Display *dpy, XrmValue *args _X_UNUSED, Cardinal *num_args _X_UNUSED,
1797			XrmValue *fromVal, XrmValue *toVal,
1798			XtPointer *converter_data _X_UNUSED)
1799{
1800    static char *buffer;
1801    Cardinal size;
1802    XawTextPropertyList *propl;
1803
1804    propl = *(XawTextPropertyList**)fromVal[0].addr;
1805    if (propl == NULL) {
1806        XtAppWarningMsg(XtDisplayToApplicationContext(dpy),
1807		      "wrongParameters", "cvtPropertyListToString",
1808		      "ToolkitError",
1809		      "textProperties to String conversion needs property list argument",
1810		      NULL, NULL);
1811	return (False);
1812    }
1813
1814    buffer = XrmQuarkToString(propl->identifier);
1815    size = (Cardinal)(strlen(buffer) + 1);
1816
1817    if (toVal->addr != NULL) {
1818	if (toVal->size < size) {
1819	    toVal->size = size;
1820	    return (False);
1821	}
1822	strcpy((char *)toVal->addr, buffer);
1823    }
1824    else
1825	toVal->addr = buffer;
1826    toVal->size = size;
1827
1828    return (True);
1829}
1830#endif
1831