xref: /netbsd-src/external/bsd/nvi/dist/motif_l/xtabbed.c (revision dbd550ed1a6686d6600f748306f9cc03d8cd4c94)
1 /* ***********************************************************************
2  * This module implements a motif tabbed window widget.
3  * The source is copied from the Free Widget Foundation
4  * This file is divided into thse parts
5  *	o - Conversion routines for the X resource manager
6  *	o - Routines for drawing rotated text
7  *	o - A motif widget for tabbed windows
8  *	o - A driver for the above in the flavor of the xt utilities module
9  * ***********************************************************************
10  */
11 
12 
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <Xm/Xm.h>
17 #include <Xm/Form.h>
18 #include <Xm/RowColumn.h>
19 #include <X11/StringDefs.h>
20 #include <X11/IntrinsicP.h>
21 #if defined(VMS_HOST)
22 #include <DECW$INCLUDE/shape.h>
23 #else
24 #include <X11/extensions/shape.h>
25 #endif
26 #include <X11/Xlib.h>
27 #include <X11/Xutil.h>
28 #include <X11/Xatom.h>
29 #include <math.h>
30 
31 
32 /* ***********************************************************************
33  * "rotated.h"
34  * ***********************************************************************
35  */
36 
37 /* ************************************************************************ */
38 
39 
40 /* Header file for the `xvertext 5.0' routines.
41 
42    Copyright (c) 1993 Alan Richardson (mppa3@uk.ac.sussex.syma) */
43 
44 
45 /* ************************************************************************ */
46 
47 #ifndef _XVERTEXT_INCLUDED_
48 #define _XVERTEXT_INCLUDED_
49 
50 
51 #define XV_VERSION      5.0
52 #define XV_COPYRIGHT \
53       "xvertext routines Copyright (c) 1993 Alan Richardson"
54 
55 
56 /* ---------------------------------------------------------------------- */
57 
58 
59 /* text alignment */
60 
61 #define NONE             0
62 #define TLEFT            1
63 #define TCENTRE          2
64 #define TRIGHT           3
65 #define MLEFT            4
66 #define MCENTRE          5
67 #define MRIGHT           6
68 #define BLEFT            7
69 #define BCENTRE          8
70 #define BRIGHT           9
71 
72 
73 /* ---------------------------------------------------------------------- */
74 
75 /* this shoulf be C++ compliant, thanks to
76      vlp@latina.inesc.pt (Vasco Lopes Paulo) */
77 
78 #if defined(__cplusplus) || defined(c_plusplus)
79 
80 extern "C" {
81 static float   XRotVersion(char*, int);
82 static void    XRotSetMagnification(float);
83 static void    XRotSetBoundingBoxPad(int);
84 static int     XRotDrawString(Display*, XFontStruct*, float,
85                        Drawable, GC, int, int, char*);
86 static int     XRotDrawImageString(Display*, XFontStruct*, float,
87                             Drawable, GC, int, int, char*);
88 static int     XRotDrawAlignedString(Display*, XFontStruct*, float,
89                               Drawable, GC, int, int, char*, int);
90 static int     XRotDrawAlignedImageString(Display*, XFontStruct*, float,
91                                    Drawable, GC, int, int, char*, int);
92 static XPoint *XRotTextExtents(Display*, XFontStruct*, float,
93 			int, int, char*, int);
94 }
95 
96 #else
97 
98 static float   XRotVersion(char *str, int n);
99 static void    XRotSetMagnification(float m);
100 static void    XRotSetBoundingBoxPad(int p);
101 static int     XRotDrawString(Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *str);
102 static int     XRotDrawImageString(Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *str);
103 static int     XRotDrawAlignedString(Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *text, int align);
104 static int     XRotDrawAlignedImageString(Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *text, int align);
105 static XPoint *XRotTextExtents(Display *dpy, XFontStruct *font, float angle, int x, int y, char *text, int align);
106 
107 #endif /* __cplusplus */
108 
109 /* ---------------------------------------------------------------------- */
110 
111 
112 #endif /* _XVERTEXT_INCLUDED_ */
113 
114 
115 
116 
117 /* ***********************************************************************
118  * "strarray.h"
119  * ***********************************************************************
120  */
121 
122 #ifndef _strarray_h_
123 #define _strarray_h_
124 /*
125    StringArray
126    ===========
127    The type |StringArray| represents an array of |String|s, with the
128    proviso that by convention the last member of a |StringArray| is
129    always a |NULL| pointer. There is a converter that can construct a
130    |StringArray| from a single string.
131 
132 
133    cvtStringToStringArray
134    ======================
135    The converter from |String| to |StringArray| makes a copy of the
136    passed string and then replaces all occurences of the delimiter
137    with a nul byte. The |StringArray| is filled with pointers to the
138    parts of the string.
139 
140    The delimiter character is the first character in the string.
141 
142 
143    newStringArray
144    ==============
145    The function |newStringArray| makes a copy of a |StringArray|. It
146    allocates new space for the array itself and for the strings that
147    it contains.
148 
149 
150    freeStringArray
151    ===============
152    |freeStringArray| deallocates the array and all strings it
153    contains. Note that this works for StringArrays produced with
154    |newStringArray|, but not for those created by
155    |cvtStringToStringArray|!
156 
157 */
158 
159 
160 typedef String * StringArray;
161 
162 static Boolean cvtStringToStringArray(
163 #if NeedFunctionPrototypes
164     Display *display,
165     XrmValuePtr args,
166     Cardinal *num_args,
167     XrmValuePtr from,
168     XrmValuePtr to,
169     XtPointer *converter_data
170 #endif
171 );
172 
173 
174 StringArray newStringArray(
175 #if NeedFunctionPrototypes
176     StringArray a
177 #endif
178 );
179 
180 
181 void freeStringArray(
182 #if NeedFunctionPrototypes
183     StringArray a
184 #endif
185 );
186 
187 
188 #endif /* _strarray_h_ */
189 
190 
191 /* ***********************************************************************
192  * "XmTabs.h"
193  * ***********************************************************************
194  */
195 
196 /* Generated by wbuild from "XmTabs.w"
197 ** (generator version Revision: 8.5  of Date: 2001/06/25 15:19:28 )
198 */
199 #ifndef _XmTabs_H_
200 #define _XmTabs_H_
201 typedef enum {
202 	    XfwfUpTabs, XfwfDownTabs, XfwfLeftTabs, XfwfRightTabs,
203 	} TabsOrientation;
204 
205 #ifndef XtNorientation
206 #define XtNorientation "orientation"
207 #endif
208 #ifndef XtCOrientation
209 #define XtCOrientation "Orientation"
210 #endif
211 #ifndef XtRTabsOrientation
212 #define XtRTabsOrientation "TabsOrientation"
213 #endif
214 
215 #ifndef XtNlefttabs
216 #define XtNlefttabs "lefttabs"
217 #endif
218 #ifndef XtCLefttabs
219 #define XtCLefttabs "Lefttabs"
220 #endif
221 #ifndef XtRInt
222 #define XtRInt "Int"
223 #endif
224 
225 #ifndef XtNrighttabs
226 #define XtNrighttabs "righttabs"
227 #endif
228 #ifndef XtCRighttabs
229 #define XtCRighttabs "Righttabs"
230 #endif
231 #ifndef XtRInt
232 #define XtRInt "Int"
233 #endif
234 
235 #ifndef XtNlabels
236 #define XtNlabels "labels"
237 #endif
238 #ifndef XtCLabels
239 #define XtCLabels "Labels"
240 #endif
241 #ifndef XtRStringArray
242 #define XtRStringArray "StringArray"
243 #endif
244 
245 #ifndef XtNtabWidthPercentage
246 #define XtNtabWidthPercentage "tabWidthPercentage"
247 #endif
248 #ifndef XtCTabWidthPercentage
249 #define XtCTabWidthPercentage "TabWidthPercentage"
250 #endif
251 #ifndef XtRInt
252 #define XtRInt "Int"
253 #endif
254 
255 #ifndef XtNcornerwidth
256 #define XtNcornerwidth "cornerwidth"
257 #endif
258 #ifndef XtCCornerwidth
259 #define XtCCornerwidth "Cornerwidth"
260 #endif
261 #ifndef XtRCardinal
262 #define XtRCardinal "Cardinal"
263 #endif
264 
265 #ifndef XtNcornerheight
266 #define XtNcornerheight "cornerheight"
267 #endif
268 #ifndef XtCCornerheight
269 #define XtCCornerheight "Cornerheight"
270 #endif
271 #ifndef XtRCardinal
272 #define XtRCardinal "Cardinal"
273 #endif
274 
275 #ifndef XtNtextmargin
276 #define XtNtextmargin "textmargin"
277 #endif
278 #ifndef XtCTextmargin
279 #define XtCTextmargin "Textmargin"
280 #endif
281 #ifndef XtRInt
282 #define XtRInt "Int"
283 #endif
284 
285 #ifndef XtNtabcolor
286 #define XtNtabcolor "tabcolor"
287 #endif
288 #ifndef XtCTabcolor
289 #define XtCTabcolor "Tabcolor"
290 #endif
291 #ifndef XtRPixel
292 #define XtRPixel "Pixel"
293 #endif
294 
295 #ifndef XtNfont
296 #define XtNfont "font"
297 #endif
298 #ifndef XtCFont
299 #define XtCFont "Font"
300 #endif
301 #ifndef XtRFontStruct
302 #define XtRFontStruct "FontStruct"
303 #endif
304 
305 #ifndef XtNactivateCallback
306 #define XtNactivateCallback "activateCallback"
307 #endif
308 #ifndef XtCActivateCallback
309 #define XtCActivateCallback "ActivateCallback"
310 #endif
311 #ifndef XtRCallback
312 #define XtRCallback "Callback"
313 #endif
314 
315 typedef struct _XmTabsClassRec *XmTabsWidgetClass;
316 typedef struct _XmTabsRec *XmTabsWidget;
317 #endif /*_XmTabs_H_*/
318 
319 
320 /* ***********************************************************************
321  * "XmTabsP.h"
322  * ***********************************************************************
323  */
324 
325 /* Generated by wbuild from "XmTabs.w"
326 ** (generator version Revision: 8.5  of Date: 2001/06/25 15:19:28 )
327 */
328 #ifndef _XmTabsP_H_
329 #define _XmTabsP_H_
330 
331 /* raz modified 22 Jul 96 for bluestone */
332 #include <Xm/XmP.h>
333 #if ! defined(MGR_ShadowThickness)
334 #include <Xm/ManagerP.h>
335 #endif
336 
337 typedef void (*border_highlight_Proc)(
338 #if NeedFunctionPrototypes
339 void
340 #endif
341 );
342 #define XtInherit_border_highlight ((border_highlight_Proc) _XtInherit)
343 typedef void (*border_unhighlight_Proc)(
344 #if NeedFunctionPrototypes
345 void
346 #endif
347 );
348 #define XtInherit_border_unhighlight ((border_unhighlight_Proc) _XtInherit)
349 typedef struct {
350 /* Constraint resources */
351 /* Private constraint variables */
352 int dummy;
353 } XmTabsConstraintPart;
354 
355 typedef struct _XmTabsConstraintRec {
356 XmManagerConstraintPart xmManager;
357 XmTabsConstraintPart xmTabs;
358 } XmTabsConstraintRec;
359 
360 
361 typedef struct {
362 /* methods */
363 border_highlight_Proc border_highlight;
364 border_unhighlight_Proc border_unhighlight;
365 /* class variables */
366 } XmTabsClassPart;
367 
368 typedef struct _XmTabsClassRec {
369 CoreClassPart core_class;
370 CompositeClassPart composite_class;
371 ConstraintClassPart constraint_class;
372 XmManagerClassPart xmManager_class;
373 XmTabsClassPart xmTabs_class;
374 } XmTabsClassRec;
375 
376 typedef struct {
377 /* resources */
378 TabsOrientation  orientation;
379 int  lefttabs;
380 int  righttabs;
381 StringArray  labels;
382 int  tabWidthPercentage;
383 Cardinal  cornerwidth;
384 Cardinal  cornerheight;
385 int  textmargin;
386 Pixel  tabcolor;
387 XFontStruct * font;
388 XtCallbackList  activateCallback;
389 /* private state */
390 GC  textgc;
391 GC  topgc;
392 GC  bottomgc;
393 GC  backgc;
394 GC  fillgc;
395 int * tabwidths;
396 int * offsets;
397 } XmTabsPart;
398 
399 typedef struct _XmTabsRec {
400 CorePart core;
401 CompositePart composite;
402 ConstraintPart constraint;
403 XmManagerPart xmManager;
404 XmTabsPart xmTabs;
405 } XmTabsRec;
406 
407 #endif /* _XmTabsP_H_ */
408 
409 
410 /* ***********************************************************************
411  * A motif widget for tabbed windows
412  * ***********************************************************************
413  */
414 
415 static void activate(
416 #if NeedFunctionPrototypes
417 Widget,XEvent*,String*,Cardinal*
418 #endif
419 );
420 
421 static XtActionsRec actionsList[] = {
422 {"activate", activate},
423 };
424 
425 static char defaultTranslations[] = "\
426 <Btn1Down>,<Btn1Up>: activate() \n\
427 ";
428 static void _resolve_inheritance(
429 #if NeedFunctionPrototypes
430 WidgetClass
431 #endif
432 );
433 static void class_initialize(
434 #if NeedFunctionPrototypes
435 void
436 #endif
437 );
438 static void initialize(
439 #if NeedFunctionPrototypes
440 Widget ,Widget,ArgList ,Cardinal *
441 #endif
442 );
443 static Boolean  set_values(
444 #if NeedFunctionPrototypes
445 Widget ,Widget ,Widget,ArgList ,Cardinal *
446 #endif
447 );
448 static void realize(
449 #if NeedFunctionPrototypes
450 Widget,XtValueMask *,XSetWindowAttributes *
451 #endif
452 );
453 static void resize(
454 #if NeedFunctionPrototypes
455 Widget
456 #endif
457 );
458 static void expose(
459 #if NeedFunctionPrototypes
460 Widget,XEvent *,Region
461 #endif
462 );
463 static void border_highlight(
464 #if NeedFunctionPrototypes
465 void
466 #endif
467 );
468 static void border_unhighlight(
469 #if NeedFunctionPrototypes
470 void
471 #endif
472 );
473 static void destroy(
474 #if NeedFunctionPrototypes
475 Widget
476 #endif
477 );
478 #define min(a, b) ((a )<(b )?(a ):(b ))
479 
480 
481 #define abs(x) ((x )<0 ?-(x ):(x ))
482 
483 
484 static void compute_tabsizes(
485 #if NeedFunctionPrototypes
486 Widget
487 #endif
488 );
489 static void comp_hor_tab_shape(
490 #if NeedFunctionPrototypes
491 Widget,int ,XPoint  p[12],int *,int *,int *
492 #endif
493 );
494 static void comp_ver_tab_shape(
495 #if NeedFunctionPrototypes
496 Widget,int ,XPoint  p[12],int *,int *,int *
497 #endif
498 );
499 static void draw_border(
500 #if NeedFunctionPrototypes
501 Widget,XPoint  poly[12]
502 #endif
503 );
504 static void draw_hor_tab(
505 #if NeedFunctionPrototypes
506 Widget,Region ,int
507 #endif
508 );
509 static void draw_ver_tab(
510 #if NeedFunctionPrototypes
511 Widget,Region ,int
512 #endif
513 );
514 static void create_topgc(
515 #if NeedFunctionPrototypes
516 Widget
517 #endif
518 );
519 static void create_bottomgc(
520 #if NeedFunctionPrototypes
521 Widget
522 #endif
523 );
524 static void create_textgc(
525 #if NeedFunctionPrototypes
526 Widget
527 #endif
528 );
529 static void create_fillgc(
530 #if NeedFunctionPrototypes
531 Widget
532 #endif
533 );
534 static void create_backgc(
535 #if NeedFunctionPrototypes
536 Widget
537 #endif
538 );
539 static void copy_bg(
540 #if NeedFunctionPrototypes
541 Widget,int ,XrmValue *
542 #endif
543 );
544 static void set_shape(
545 #if NeedFunctionPrototypes
546 Widget
547 #endif
548 );
549 #define done(type, value) do {\
550 	if (to->addr != NULL) {\
551 	    if (to->size < sizeof(type)) {\
552 	        to->size = sizeof(type);\
553 	        return False;\
554 	    }\
555 	    *(type*)(to->addr) = (value);\
556         } else {\
557 	    static type static_val;\
558 	    static_val = (value);\
559 	    to->addr = (XtPointer)&static_val;\
560         }\
561         to->size = sizeof(type);\
562         return True;\
563     }while (0 )
564 
565 
566 static Boolean  cvtStringToTabsOrientation(
567 #if NeedFunctionPrototypes
568 Display *,XrmValuePtr ,Cardinal *,XrmValuePtr ,XrmValuePtr ,XtPointer *
569 #endif
570 );
571 static Boolean  cvtTabsOrientationToString(
572 #if NeedFunctionPrototypes
573 Display *,XrmValuePtr ,Cardinal *,XrmValuePtr ,XrmValuePtr ,XtPointer *
574 #endif
575 );
576 /*ARGSUSED*/
577 #if NeedFunctionPrototypes
compute_tabsizes(Widget self)578 static void compute_tabsizes(Widget self)
579 #else
580 static void compute_tabsizes(self)Widget self;
581 #endif
582 {
583     int maxwd, basewidth, delta, i, n = ((XmTabsWidget)self)->xmTabs.lefttabs + ((XmTabsWidget)self)->xmTabs.righttabs + 1;
584     int sum, len, h, length, breadth, shad = ((XmTabsWidget)self)->xmManager.shadow_thickness;
585 
586     if (((XmTabsWidget)self)->xmTabs.offsets) XtFree((XtPointer) ((XmTabsWidget)self)->xmTabs.offsets);
587     if (((XmTabsWidget)self)->xmTabs.tabwidths) XtFree((XtPointer) ((XmTabsWidget)self)->xmTabs.tabwidths);
588     ((XmTabsWidget)self)->xmTabs.offsets = (XtPointer) XtMalloc(n * sizeof(*((XmTabsWidget)self)->xmTabs.offsets));
589     ((XmTabsWidget)self)->xmTabs.tabwidths = (XtPointer) XtMalloc(n * sizeof(*((XmTabsWidget)self)->xmTabs.tabwidths));
590 
591     if (((XmTabsWidget)self)->xmTabs.orientation == XfwfUpTabs || ((XmTabsWidget)self)->xmTabs.orientation == XfwfDownTabs) {
592 	length = ((XmTabsWidget)self)->core.width;
593 	breadth = ((XmTabsWidget)self)->core.height;
594     } else {
595 	length = ((XmTabsWidget)self)->core.height;
596 	breadth = ((XmTabsWidget)self)->core.width;
597     }
598     if (((XmTabsWidget)self)->xmTabs.tabWidthPercentage != 0) {		/* Fixed width tabs */
599 	basewidth = ((XmTabsWidget)self)->xmTabs.tabWidthPercentage * length/100;
600 	if (n > 1) delta = (length - basewidth)/(((XmTabsWidget)self)->xmTabs.lefttabs + ((XmTabsWidget)self)->xmTabs.righttabs);
601 	for (i = 0; i < n; i++) {
602 	    ((XmTabsWidget)self)->xmTabs.tabwidths[i] = basewidth;
603 	    ((XmTabsWidget)self)->xmTabs.offsets[i] = i * delta;
604 	}
605     } else if (((XmTabsWidget)self)->xmTabs.labels == NULL) {		/* Empty tabs */
606 	basewidth = length/n;
607 	delta = (length - basewidth)/(((XmTabsWidget)self)->xmTabs.lefttabs + ((XmTabsWidget)self)->xmTabs.righttabs);
608 	for (i = 0; i < n; i++) {
609 	    ((XmTabsWidget)self)->xmTabs.tabwidths[i] = basewidth;
610 	    ((XmTabsWidget)self)->xmTabs.offsets[i] = i * delta;
611 	}
612     } else {					/* Variable width tabs */
613 	sum = 0;
614 	h = 2 * (((XmTabsWidget)self)->xmTabs.cornerwidth + shad + ((XmTabsWidget)self)->xmTabs.textmargin);
615 	maxwd = length - n * (shad + ((XmTabsWidget)self)->xmTabs.textmargin);
616 	for (i = 0; i < n; i++) {
617 	    len = strlen(((XmTabsWidget)self)->xmTabs.labels[i]);
618 	    ((XmTabsWidget)self)->xmTabs.tabwidths[i] = min(maxwd, XTextWidth(((XmTabsWidget)self)->xmTabs.font,((XmTabsWidget)self)->xmTabs.labels[i],len) + h);
619 	    sum += ((XmTabsWidget)self)->xmTabs.tabwidths[i];
620 	}
621 	((XmTabsWidget)self)->xmTabs.offsets[0] = 0;
622 	if (length >= sum)
623 	    delta = (length - sum)/(n - 1);	/* Between tabs */
624 	else
625 	    delta = -((sum - length + n - 2)/(n - 1)); /* Round down! */
626 	for (i = 1; i < n; i++)
627 	    ((XmTabsWidget)self)->xmTabs.offsets[i] = ((XmTabsWidget)self)->xmTabs.offsets[i-1] + ((XmTabsWidget)self)->xmTabs.tabwidths[i-1] + delta;
628     }
629 }
630 /*ARGSUSED*/
631 #if NeedFunctionPrototypes
comp_hor_tab_shape(Widget self,int i,XPoint p[12],int * x0,int * x1,int * midy)632 static void comp_hor_tab_shape(Widget self,int  i,XPoint  p[12],int * x0,int * x1,int * midy)
633 #else
634 static void comp_hor_tab_shape(self,i,p,x0,x1,midy)Widget self;int  i;XPoint  p[12];int * x0;int * x1;int * midy;
635 #endif
636 {
637     int shad = ((XmTabsWidget)self)->xmManager.shadow_thickness;
638     int k = min(((XmTabsWidget)self)->xmTabs.cornerheight, (((XmTabsWidget)self)->core.height - shad)/2);
639     /*
640      *                4 o-------------o 5
641      *                 /               \
642      *              3 o                 o 6
643      *                |                 |
644      *              2 o                 o 7
645      *             1 /                   \ 8
646      *   0 o--------o                     o--------o 9
647      *  11 o---------------------------------------o 10
648      *
649      *  11 o---------------------------------------o 10
650      *   0 o--------o                     o--------o 9
651      *             1 \                   / 8
652      *              2 o                 o 7
653      *                |                 |
654      *              3 o                 o 6
655      *                 \               /
656      *                4 o-------------o 5
657      */
658     p[0].x = 0;
659     p[1].x = ((XmTabsWidget)self)->xmTabs.offsets[i];
660     p[2].x = ((XmTabsWidget)self)->xmTabs.offsets[i] + ((XmTabsWidget)self)->xmTabs.cornerwidth;
661     p[3].x = ((XmTabsWidget)self)->xmTabs.offsets[i] + ((XmTabsWidget)self)->xmTabs.cornerwidth;
662     p[4].x = ((XmTabsWidget)self)->xmTabs.offsets[i] + 2 * ((XmTabsWidget)self)->xmTabs.cornerwidth;
663     p[5].x = ((XmTabsWidget)self)->xmTabs.offsets[i] + ((XmTabsWidget)self)->xmTabs.tabwidths[i] - 2 * ((XmTabsWidget)self)->xmTabs.cornerwidth;
664     p[6].x = ((XmTabsWidget)self)->xmTabs.offsets[i] + ((XmTabsWidget)self)->xmTabs.tabwidths[i] - ((XmTabsWidget)self)->xmTabs.cornerwidth;
665     p[7].x = ((XmTabsWidget)self)->xmTabs.offsets[i] + ((XmTabsWidget)self)->xmTabs.tabwidths[i] - ((XmTabsWidget)self)->xmTabs.cornerwidth;
666     p[8].x = ((XmTabsWidget)self)->xmTabs.offsets[i] + ((XmTabsWidget)self)->xmTabs.tabwidths[i];
667     p[9].x = ((XmTabsWidget)self)->core.width;
668     p[10].x = ((XmTabsWidget)self)->core.width;
669     p[11].x = 0;
670 
671     if (((XmTabsWidget)self)->xmTabs.orientation == XfwfUpTabs) {
672 	p[0].y = ((XmTabsWidget)self)->core.height - shad;
673 	p[1].y = ((XmTabsWidget)self)->core.height - shad;
674 	p[2].y = ((XmTabsWidget)self)->core.height - shad - k;
675 	p[3].y = k;
676 	p[4].y = 0;
677 	p[5].y = 0;
678 	p[6].y = k;
679 	p[7].y = ((XmTabsWidget)self)->core.height - shad - k;
680 	p[8].y = ((XmTabsWidget)self)->core.height - shad;
681 	p[9].y = ((XmTabsWidget)self)->core.height - shad;
682 	p[10].y = ((XmTabsWidget)self)->core.height;
683 	p[11].y = ((XmTabsWidget)self)->core.height;
684     } else {
685 	p[0].y = shad;
686 	p[1].y = shad;
687 	p[2].y = shad + k;
688 	p[3].y = ((XmTabsWidget)self)->core.height - k;
689 	p[4].y = ((XmTabsWidget)self)->core.height;
690 	p[5].y = ((XmTabsWidget)self)->core.height;
691 	p[6].y = ((XmTabsWidget)self)->core.height - k;
692 	p[7].y = shad + k;
693 	p[8].y = shad;
694 	p[9].y = shad;
695 	p[10].y = 0;
696 	p[11].y = 0;
697     }
698     *x0 = p[4].x;
699     *x1 = p[5].x;
700     *midy = (p[1].y + p[4].y)/2;
701 }
702 /*ARGSUSED*/
703 #if NeedFunctionPrototypes
comp_ver_tab_shape(Widget self,int i,XPoint p[12],int * y0,int * y1,int * midx)704 static void comp_ver_tab_shape(Widget self,int  i,XPoint  p[12],int * y0,int * y1,int * midx)
705 #else
706 static void comp_ver_tab_shape(self,i,p,y0,y1,midx)Widget self;int  i;XPoint  p[12];int * y0;int * y1;int * midx;
707 #endif
708 {
709     int shad = ((XmTabsWidget)self)->xmManager.shadow_thickness;
710     int k = min(((XmTabsWidget)self)->xmTabs.cornerheight, (((XmTabsWidget)self)->core.width - shad)/2);
711     /*
712      *       0 o_o 11  11 o_o 0
713      *         | |        | |
714      *       1 o |        | o 1
715      *     3 2/  |        |  \2 3
716      *     o-o   |        |   o-o
717      *    /      |        |      \
718      * 4 o       |        |       o 4
719      *   |       |        |       |
720      * 5 o       |        |       o 5
721      *    \      |        |      /
722      *     o-o   |        |   o-o
723      *     6 7\  |        |  /7 6
724      *       8 o |        | o 8
725      *         | |        | |
726      *       9 o_o 10  10 o_o 9
727      */
728     if (((XmTabsWidget)self)->xmTabs.orientation == XfwfLeftTabs) {
729 	p[0].x = ((XmTabsWidget)self)->core.width - shad;
730 	p[1].x = ((XmTabsWidget)self)->core.width - shad;
731 	p[2].x = ((XmTabsWidget)self)->core.width - shad - k;
732 	p[3].x = k;
733 	p[4].x = 0;
734 	p[5].x = 0;
735 	p[6].x = k;
736 	p[7].x = ((XmTabsWidget)self)->core.width - shad - k;
737 	p[8].x = ((XmTabsWidget)self)->core.width - shad;
738 	p[9].x = ((XmTabsWidget)self)->core.width - shad;
739 	p[10].x = ((XmTabsWidget)self)->core.width;
740 	p[11].x = ((XmTabsWidget)self)->core.width;
741     } else {
742 	p[0].x = shad;
743 	p[1].x = shad;
744 	p[2].x = shad + k;
745 	p[3].x = ((XmTabsWidget)self)->core.width - k;
746 	p[4].x = ((XmTabsWidget)self)->core.width;
747 	p[5].x = ((XmTabsWidget)self)->core.width;
748 	p[6].x = ((XmTabsWidget)self)->core.width - k;
749 	p[7].x = shad + k;
750 	p[8].x = shad;
751 	p[9].x = shad;
752 	p[10].x = 0;
753 	p[11].x = 0;
754     }
755     p[0].y = 0;
756     p[1].y = ((XmTabsWidget)self)->xmTabs.offsets[i];
757     p[2].y = ((XmTabsWidget)self)->xmTabs.offsets[i] + ((XmTabsWidget)self)->xmTabs.cornerwidth;
758     p[3].y = ((XmTabsWidget)self)->xmTabs.offsets[i] + ((XmTabsWidget)self)->xmTabs.cornerwidth;
759     p[4].y = ((XmTabsWidget)self)->xmTabs.offsets[i] + 2 * ((XmTabsWidget)self)->xmTabs.cornerwidth;
760     p[5].y = ((XmTabsWidget)self)->xmTabs.offsets[i] + ((XmTabsWidget)self)->xmTabs.tabwidths[i] - 2 * ((XmTabsWidget)self)->xmTabs.cornerwidth;
761     p[6].y = ((XmTabsWidget)self)->xmTabs.offsets[i] + ((XmTabsWidget)self)->xmTabs.tabwidths[i] - ((XmTabsWidget)self)->xmTabs.cornerwidth;
762     p[7].y = ((XmTabsWidget)self)->xmTabs.offsets[i] + ((XmTabsWidget)self)->xmTabs.tabwidths[i] - ((XmTabsWidget)self)->xmTabs.cornerwidth;
763     p[8].y = ((XmTabsWidget)self)->xmTabs.offsets[i] + ((XmTabsWidget)self)->xmTabs.tabwidths[i];
764     p[9].y = ((XmTabsWidget)self)->core.height;
765     p[10].y = ((XmTabsWidget)self)->core.height;
766     p[11].y = 0;
767     *y0 = p[4].y;
768     *y1 = p[5].y;
769     *midx = (p[1].x + p[4].x)/2;
770 }
771 /*ARGSUSED*/
772 #if NeedFunctionPrototypes
draw_border(Widget self,XPoint poly[12])773 static void draw_border(Widget self,XPoint  poly[12])
774 #else
775 static void draw_border(self,poly)Widget self;XPoint  poly[12];
776 #endif
777 {
778     Display *dpy = XtDisplay(self);
779     Window win = XtWindow(self);
780 
781     if (((XmTabsWidget)self)->xmTabs.orientation == XfwfUpTabs) {
782 	XDrawLines(dpy, win, ((XmTabsWidget)self)->xmTabs.topgc, poly, 6, CoordModeOrigin);
783 	XDrawLines(dpy, win, ((XmTabsWidget)self)->xmTabs.bottomgc, poly + 5, 4, CoordModeOrigin);
784 	XDrawLines(dpy, win, ((XmTabsWidget)self)->xmTabs.topgc, poly + 8, 2, CoordModeOrigin);
785     } else {
786 	XDrawLines(dpy, win, ((XmTabsWidget)self)->xmTabs.bottomgc, poly, 2, CoordModeOrigin);
787 	XDrawLines(dpy, win, ((XmTabsWidget)self)->xmTabs.topgc, poly + 1, 4, CoordModeOrigin);
788 	XDrawLines(dpy, win, ((XmTabsWidget)self)->xmTabs.bottomgc, poly + 4, 6, CoordModeOrigin);
789     }
790 }
791 /*ARGSUSED*/
792 #if NeedFunctionPrototypes
draw_hor_tab(Widget self,Region region,int i)793 static void draw_hor_tab(Widget self,Region  region,int  i)
794 #else
795 static void draw_hor_tab(self,region,i)Widget self;Region  region;int  i;
796 #endif
797 {
798     XPoint p[12];
799     Display *dpy = XtDisplay(self);
800     Window win = XtWindow(self);
801     Region clip;
802     int x0, x1, midy;
803 
804     comp_hor_tab_shape(self, i, p, &x0, &x1, &midy);
805     clip = XPolygonRegion(p, XtNumber(p), WindingRule);
806     if (region) XIntersectRegion(clip, region, clip);
807     if (XEmptyRegion(clip)) return;
808 
809     XSetRegion(dpy, ((XmTabsWidget)self)->xmTabs.textgc, clip);
810     XSetRegion(dpy, ((XmTabsWidget)self)->xmTabs.topgc, clip);
811     XSetRegion(dpy, ((XmTabsWidget)self)->xmTabs.bottomgc, clip);
812     if (i == ((XmTabsWidget)self)->xmTabs.lefttabs) {
813 	XSetRegion(dpy, ((XmTabsWidget)self)->xmTabs.backgc, clip);
814 	XFillPolygon(dpy, win, ((XmTabsWidget)self)->xmTabs.backgc,
815 		     p, XtNumber(p), Convex, CoordModeOrigin);
816     } else {
817 	XSetRegion(dpy, ((XmTabsWidget)self)->xmTabs.fillgc, clip);
818 	XFillPolygon(dpy, win, ((XmTabsWidget)self)->xmTabs.fillgc,
819 		     p, XtNumber(p), Convex, CoordModeOrigin);
820     }
821     if (((XmTabsWidget)self)->xmTabs.labels) {
822 	int w, y, x, len = strlen(((XmTabsWidget)self)->xmTabs.labels[i]);
823 	y = midy - (((XmTabsWidget)self)->xmTabs.font->ascent + ((XmTabsWidget)self)->xmTabs.font->descent)/2 + ((XmTabsWidget)self)->xmTabs.font->ascent;
824 	w = XTextWidth(((XmTabsWidget)self)->xmTabs.font, ((XmTabsWidget)self)->xmTabs.labels[i], len);
825 	if (i == ((XmTabsWidget)self)->xmTabs.lefttabs
826 	    || ((XmTabsWidget)self)->xmTabs.tabWidthPercentage <= 100/(((XmTabsWidget)self)->xmTabs.lefttabs + ((XmTabsWidget)self)->xmTabs.righttabs + 1))
827 	    x = (x0 + x1 - w)/2;		/* Centered text */
828 	else if (i < ((XmTabsWidget)self)->xmTabs.lefttabs)
829 	    x = x0 + ((XmTabsWidget)self)->xmTabs.textmargin;		/* Left aligned text */
830 	else
831 	    x = x1 - ((XmTabsWidget)self)->xmTabs.textmargin - w;		/* Right aligned text */
832 	XDrawString(dpy, win, ((XmTabsWidget)self)->xmTabs.textgc, x, y, ((XmTabsWidget)self)->xmTabs.labels[i], len);
833     }
834     draw_border(self, p);
835     XDestroyRegion(clip);
836 }
837 /*ARGSUSED*/
838 #if NeedFunctionPrototypes
draw_ver_tab(Widget self,Region region,int i)839 static void draw_ver_tab(Widget self,Region  region,int  i)
840 #else
841 static void draw_ver_tab(self,region,i)Widget self;Region  region;int  i;
842 #endif
843 {
844     Display *dpy = XtDisplay(self);
845     Window win = XtWindow(self);
846     XPoint p[12];
847     Region clip;
848     int y0, y1, midx;
849 
850     comp_ver_tab_shape(self, i, p, &y0, &y1, &midx);
851     clip = XPolygonRegion(p, XtNumber(p), WindingRule);
852     if (region) XIntersectRegion(clip, region, clip);
853     if (XEmptyRegion(clip)) return;
854 
855     XSetRegion(dpy, ((XmTabsWidget)self)->xmTabs.textgc, clip);
856     XSetRegion(dpy, ((XmTabsWidget)self)->xmTabs.topgc, clip);
857     XSetRegion(dpy, ((XmTabsWidget)self)->xmTabs.bottomgc, clip);
858     if (i == ((XmTabsWidget)self)->xmTabs.lefttabs) {
859 	XSetRegion(dpy, ((XmTabsWidget)self)->xmTabs.backgc, clip);
860 	XFillPolygon(dpy, win, ((XmTabsWidget)self)->xmTabs.backgc,
861 		     p, XtNumber(p), Convex, CoordModeOrigin);
862     } else {
863 	XSetRegion(dpy, ((XmTabsWidget)self)->xmTabs.fillgc, clip);
864 	XFillPolygon(dpy, win, ((XmTabsWidget)self)->xmTabs.fillgc,
865 		     p, XtNumber(p), Convex, CoordModeOrigin);
866     }
867     if (((XmTabsWidget)self)->xmTabs.labels) {
868 	int y, align;
869 	float angle = ((XmTabsWidget)self)->xmTabs.orientation == XfwfLeftTabs ? 90.0 : -90.0;
870 	if (i == ((XmTabsWidget)self)->xmTabs.lefttabs
871 	    || ((XmTabsWidget)self)->xmTabs.tabWidthPercentage <= 100/(((XmTabsWidget)self)->xmTabs.lefttabs + ((XmTabsWidget)self)->xmTabs.righttabs + 1)) {
872 	    y = (y0 + y1)/2;
873 	    align = MCENTRE;
874 	} else if (i < ((XmTabsWidget)self)->xmTabs.lefttabs) {
875 	    y = y0 + ((XmTabsWidget)self)->xmTabs.textmargin;
876 	    align = ((XmTabsWidget)self)->xmTabs.orientation == XfwfLeftTabs ? MRIGHT : MLEFT;
877 	} else {
878 	    y = y1 - ((XmTabsWidget)self)->xmTabs.textmargin;
879 	    align = ((XmTabsWidget)self)->xmTabs.orientation == XfwfLeftTabs ? MLEFT : MRIGHT;
880 	}
881 	XRotDrawAlignedString
882 	    (dpy, ((XmTabsWidget)self)->xmTabs.font, angle, win, ((XmTabsWidget)self)->xmTabs.textgc, midx, y, ((XmTabsWidget)self)->xmTabs.labels[i], align);
883     }
884     draw_border(self, p);
885     XDestroyRegion(clip);
886 }
887 /*ARGSUSED*/
888 #if NeedFunctionPrototypes
create_topgc(Widget self)889 static void create_topgc(Widget self)
890 #else
891 static void create_topgc(self)Widget self;
892 #endif
893 {
894     XtGCMask mask = GCForeground | GCLineWidth;
895     XGCValues values;
896 
897     if (((XmTabsWidget)self)->xmTabs.topgc != NULL) XFreeGC(XtDisplay(self), ((XmTabsWidget)self)->xmTabs.topgc);
898     values.foreground = ((XmTabsWidget)self)->xmManager.top_shadow_color;
899     values.line_width = 2 * ((XmTabsWidget)self)->xmManager.shadow_thickness;
900     ((XmTabsWidget)self)->xmTabs.topgc = XCreateGC(XtDisplay(self), RootWindowOfScreen(XtScreen(self)),
901 		       mask, &values);
902 }
903 /*ARGSUSED*/
904 #if NeedFunctionPrototypes
create_bottomgc(Widget self)905 static void create_bottomgc(Widget self)
906 #else
907 static void create_bottomgc(self)Widget self;
908 #endif
909 {
910     XtGCMask mask = GCForeground | GCLineWidth;
911     XGCValues values;
912 
913     if (((XmTabsWidget)self)->xmTabs.bottomgc != NULL) XFreeGC(XtDisplay(self), ((XmTabsWidget)self)->xmTabs.bottomgc);
914     values.foreground = ((XmTabsWidget)self)->xmManager.bottom_shadow_color;
915     values.line_width = 2 * ((XmTabsWidget)self)->xmManager.shadow_thickness;
916     ((XmTabsWidget)self)->xmTabs.bottomgc = XCreateGC(XtDisplay(self), RootWindowOfScreen(XtScreen(self)),
917 			  mask, &values);
918 }
919 /*ARGSUSED*/
920 #if NeedFunctionPrototypes
create_textgc(Widget self)921 static void create_textgc(Widget self)
922 #else
923 static void create_textgc(self)Widget self;
924 #endif
925 {
926     XtGCMask mask = GCForeground | GCFont;
927     XGCValues values;
928 
929     if (((XmTabsWidget)self)->xmTabs.textgc != NULL) XFreeGC(XtDisplay(self), ((XmTabsWidget)self)->xmTabs.textgc);
930     values.foreground = ((XmTabsWidget)self)->xmManager.foreground;
931     values.font = ((XmTabsWidget)self)->xmTabs.font->fid;
932     ((XmTabsWidget)self)->xmTabs.textgc = XCreateGC(XtDisplay(self), RootWindowOfScreen(XtScreen(self)),
933 			mask, &values);
934 }
935 /*ARGSUSED*/
936 #if NeedFunctionPrototypes
create_fillgc(Widget self)937 static void create_fillgc(Widget self)
938 #else
939 static void create_fillgc(self)Widget self;
940 #endif
941 {
942     XtGCMask mask = GCForeground;
943     XGCValues values;
944 
945     if (((XmTabsWidget)self)->xmTabs.fillgc != NULL) XFreeGC(XtDisplay(self), ((XmTabsWidget)self)->xmTabs.fillgc);
946     values.foreground = ((XmTabsWidget)self)->xmTabs.tabcolor;
947     ((XmTabsWidget)self)->xmTabs.fillgc = XCreateGC(XtDisplay(self), RootWindowOfScreen(XtScreen(self)),
948 			mask, &values);
949 }
950 /*ARGSUSED*/
951 #if NeedFunctionPrototypes
create_backgc(Widget self)952 static void create_backgc(Widget self)
953 #else
954 static void create_backgc(self)Widget self;
955 #endif
956 {
957     XtGCMask mask = GCForeground;
958     XGCValues values;
959 
960     if (((XmTabsWidget)self)->xmTabs.backgc != NULL) XFreeGC(XtDisplay(self), ((XmTabsWidget)self)->xmTabs.backgc);
961     values.foreground = ((XmTabsWidget)self)->core.background_pixel;
962     ((XmTabsWidget)self)->xmTabs.backgc = XCreateGC(XtDisplay(self), RootWindowOfScreen(XtScreen(self)),
963 			mask, &values);
964 }
965 /*ARGSUSED*/
966 #if NeedFunctionPrototypes
copy_bg(Widget self,int offset,XrmValue * value)967 static void copy_bg(Widget self,int  offset,XrmValue * value)
968 #else
969 static void copy_bg(self,offset,value)Widget self;int  offset;XrmValue * value;
970 #endif
971 {
972     value->addr = (XtPointer) &((XmTabsWidget)self)->core.background_pixel;
973 }
974 /*ARGSUSED*/
975 #if NeedFunctionPrototypes
set_shape(Widget self)976 static void set_shape(Widget self)
977 #else
978 static void set_shape(self)Widget self;
979 #endif
980 {
981     int x0, x1, midy, y0, y1, midx, i;
982     Region region, clip;
983     XPoint poly[12];
984 
985     if (! XtIsRealized(self)) return;
986 
987     region = XCreateRegion();
988 
989     switch (((XmTabsWidget)self)->xmTabs.orientation) {
990     case XfwfUpTabs:
991     case XfwfDownTabs:
992 	for (i = 0; i <= ((XmTabsWidget)self)->xmTabs.lefttabs + ((XmTabsWidget)self)->xmTabs.righttabs; i++) {
993 	    comp_hor_tab_shape(self, i, poly, &x0, &x1, &midy);
994 	    clip = XPolygonRegion(poly, XtNumber(poly), WindingRule);
995 	    XUnionRegion(region, clip, region);
996 	    XDestroyRegion(clip);
997 	}
998 	break;
999     case XfwfLeftTabs:
1000     case XfwfRightTabs:
1001 	for (i = 0; i <= ((XmTabsWidget)self)->xmTabs.lefttabs + ((XmTabsWidget)self)->xmTabs.righttabs; i++) {
1002 	    comp_ver_tab_shape(self, i, poly, &y0, &y1, &midx);
1003 	    clip = XPolygonRegion(poly, XtNumber(poly), WindingRule);
1004 	    XUnionRegion(region, clip, region);
1005 	    XDestroyRegion(clip);
1006 	}
1007 	break;
1008     }
1009     XShapeCombineRegion(XtDisplay(self), XtWindow(self), ShapeBounding,
1010 			0, 0, region, ShapeSet);
1011     XDestroyRegion(region);
1012 }
1013 
1014 /*ARGSUSED*/
1015 #if NeedFunctionPrototypes
cvtStringToTabsOrientation(Display * display,XrmValuePtr args,Cardinal * num_args,XrmValuePtr from,XrmValuePtr to,XtPointer * converter_data)1016 static Boolean  cvtStringToTabsOrientation(Display * display,XrmValuePtr  args,Cardinal * num_args,XrmValuePtr  from,XrmValuePtr  to,XtPointer * converter_data)
1017 #else
1018 static Boolean  cvtStringToTabsOrientation(display,args,num_args,from,to,converter_data)Display * display;XrmValuePtr  args;Cardinal * num_args;XrmValuePtr  from;XrmValuePtr  to;XtPointer * converter_data;
1019 #endif
1020 {
1021     TabsOrientation a = XfwfUpTabs;
1022     char *s = (char*) from->addr;
1023     static struct {
1024 	char *name;
1025 	TabsOrientation orient;
1026     } strings[] = {
1027     	{ "up",  XfwfUpTabs },
1028     	{ "uptabs",  XfwfUpTabs },
1029     	{ "down",  XfwfDownTabs },
1030     	{ "downtabs",  XfwfDownTabs },
1031     	{ "left",  XfwfLeftTabs },
1032     	{ "lefttabs",  XfwfLeftTabs },
1033     	{ "right",  XfwfRightTabs },
1034     	{ "righttabs",  XfwfRightTabs },
1035     };
1036     int i;
1037 
1038     if (*num_args != 0)
1039 	XtAppErrorMsg
1040 	    (XtDisplayToApplicationContext(display),
1041 	     "cvtStringToTabsOrientation", "wrongParameters", "XtToolkitError",
1042 	     "String to TabsOrientation conversion needs no arguments",
1043 	     (String*) NULL, (Cardinal*) NULL);
1044 
1045     for (i=0; i<XtNumber(strings); i++)
1046 	if ( strcmp( s, strings[i].name ) == 0 ) {
1047 	    a |= strings[i].orient;
1048 	    break;
1049     }
1050 
1051     if ( i >= XtNumber(strings) )
1052 	XtDisplayStringConversionWarning(display, s, "TabsOrientation");
1053     done(TabsOrientation, a);
1054 }
1055 /*ARGSUSED*/
1056 #if NeedFunctionPrototypes
cvtTabsOrientationToString(Display * display,XrmValuePtr args,Cardinal * num_args,XrmValuePtr from,XrmValuePtr to,XtPointer * converter_data)1057 static Boolean  cvtTabsOrientationToString(Display * display,XrmValuePtr  args,Cardinal * num_args,XrmValuePtr  from,XrmValuePtr  to,XtPointer * converter_data)
1058 #else
1059 static Boolean  cvtTabsOrientationToString(display,args,num_args,from,to,converter_data)Display * display;XrmValuePtr  args;Cardinal * num_args;XrmValuePtr  from;XrmValuePtr  to;XtPointer * converter_data;
1060 #endif
1061 {
1062     TabsOrientation *a = (TabsOrientation*) from->addr;
1063 
1064     if (*num_args != 0)
1065 	XtAppErrorMsg
1066 	    (XtDisplayToApplicationContext(display),
1067 	     "cvtTabsOrientationToString", "wrongParameters", "XtToolkitError",
1068 	     "TabsOrientation to String conversion needs no arguments",
1069 	     (String*) NULL, (Cardinal*) NULL);
1070     switch (*a) {
1071     case XfwfUpTabs: done(String, "up");
1072     case XfwfDownTabs: done(String, "down");
1073     case XfwfLeftTabs: done(String, "left");
1074     case XfwfRightTabs: done(String, "right");
1075     }
1076     XtAppErrorMsg
1077 	(XtDisplayToApplicationContext(display),
1078 	 "cvtTabsOrientationToString", "illParameters", "XtToolkitError",
1079 	     "TabsOrientation to String conversion got illegal argument",
1080 	     (String*) NULL, (Cardinal*) NULL);
1081     return TRUE;
1082 }
1083 
1084 static XtResource resources[] = {
1085 {XtNorientation,XtCOrientation,XtRTabsOrientation,sizeof(((XmTabsRec*)NULL)->xmTabs.orientation),XtOffsetOf(XmTabsRec,xmTabs.orientation),XtRImmediate,(XtPointer)XfwfUpTabs },
1086 {XtNlefttabs,XtCLefttabs,XtRInt,sizeof(((XmTabsRec*)NULL)->xmTabs.lefttabs),XtOffsetOf(XmTabsRec,xmTabs.lefttabs),XtRImmediate,(XtPointer)0 },
1087 {XtNrighttabs,XtCRighttabs,XtRInt,sizeof(((XmTabsRec*)NULL)->xmTabs.righttabs),XtOffsetOf(XmTabsRec,xmTabs.righttabs),XtRImmediate,(XtPointer)0 },
1088 {XtNlabels,XtCLabels,XtRStringArray,sizeof(((XmTabsRec*)NULL)->xmTabs.labels),XtOffsetOf(XmTabsRec,xmTabs.labels),XtRImmediate,(XtPointer)NULL },
1089 {XtNtabWidthPercentage,XtCTabWidthPercentage,XtRInt,sizeof(((XmTabsRec*)NULL)->xmTabs.tabWidthPercentage),XtOffsetOf(XmTabsRec,xmTabs.tabWidthPercentage),XtRImmediate,(XtPointer)50 },
1090 {XtNcornerwidth,XtCCornerwidth,XtRCardinal,sizeof(((XmTabsRec*)NULL)->xmTabs.cornerwidth),XtOffsetOf(XmTabsRec,xmTabs.cornerwidth),XtRImmediate,(XtPointer)3 },
1091 {XtNcornerheight,XtCCornerheight,XtRCardinal,sizeof(((XmTabsRec*)NULL)->xmTabs.cornerheight),XtOffsetOf(XmTabsRec,xmTabs.cornerheight),XtRImmediate,(XtPointer)3 },
1092 {XtNtextmargin,XtCTextmargin,XtRInt,sizeof(((XmTabsRec*)NULL)->xmTabs.textmargin),XtOffsetOf(XmTabsRec,xmTabs.textmargin),XtRImmediate,(XtPointer)3 },
1093 {XtNtabcolor,XtCTabcolor,XtRPixel,sizeof(((XmTabsRec*)NULL)->xmTabs.tabcolor),XtOffsetOf(XmTabsRec,xmTabs.tabcolor),XtRCallProc,(XtPointer)copy_bg },
1094 {XtNfont,XtCFont,XtRFontStruct,sizeof(((XmTabsRec*)NULL)->xmTabs.font),XtOffsetOf(XmTabsRec,xmTabs.font),XtRString,(XtPointer)XtDefaultFont },
1095 {XtNactivateCallback,XtCActivateCallback,XtRCallback,sizeof(((XmTabsRec*)NULL)->xmTabs.activateCallback),XtOffsetOf(XmTabsRec,xmTabs.activateCallback),XtRImmediate,(XtPointer)NULL },
1096 };
1097 
1098 XmTabsClassRec xmTabsClassRec = {
1099 { /* core_class part */
1100 /* superclass   	*/  (WidgetClass) &xmManagerClassRec,
1101 /* class_name   	*/  "XmTabs",
1102 /* widget_size  	*/  sizeof(XmTabsRec),
1103 /* class_initialize 	*/  class_initialize,
1104 /* class_part_initialize*/  _resolve_inheritance,
1105 /* class_inited 	*/  FALSE,
1106 /* initialize   	*/  initialize,
1107 /* initialize_hook 	*/  NULL,
1108 /* realize      	*/  realize,
1109 /* actions      	*/  actionsList,
1110 /* num_actions  	*/  1,
1111 /* resources    	*/  resources,
1112 /* num_resources 	*/  11,
1113 /* xrm_class    	*/  NULLQUARK,
1114 /* compres_motion 	*/  True ,
1115 /* compress_exposure 	*/  XtExposeCompressMultiple ,
1116 /* compress_enterleave 	*/  True ,
1117 /* visible_interest 	*/  False ,
1118 /* destroy      	*/  destroy,
1119 /* resize       	*/  resize,
1120 /* expose       	*/  expose,
1121 /* set_values   	*/  set_values,
1122 /* set_values_hook 	*/  NULL,
1123 /* set_values_almost 	*/  XtInheritSetValuesAlmost,
1124 /* get_values+hook 	*/  NULL,
1125 /* accept_focus 	*/  XtInheritAcceptFocus,
1126 /* version      	*/  XtVersion,
1127 /* callback_private 	*/  NULL,
1128 /* tm_table      	*/  defaultTranslations,
1129 /* query_geometry 	*/  XtInheritQueryGeometry,
1130 /* display_acceleator 	*/  XtInheritDisplayAccelerator,
1131 /* extension    	*/  NULL
1132 },
1133 { /* composite_class part */
1134 XtInheritGeometryManager,
1135 XtInheritChangeManaged,
1136 XtInheritInsertChild,
1137 XtInheritDeleteChild,
1138 NULL
1139 },
1140 { /* constraint_class part */
1141 /* constraint_resources     */  NULL,
1142 /* num_constraint_resources */  0,
1143 /* constraint_size          */  sizeof(XmTabsConstraintRec),
1144 /* constraint_initialize    */  NULL,
1145 /* constraint_destroy       */  NULL,
1146 /* constraint_set_values    */  NULL,
1147 /* constraint_extension     */  NULL
1148 },
1149 { /* XmManager class part */
1150 #define manager_extension extension
1151 /* translations                 */  XtInheritTranslations ,
1152 /* syn_resources                */  NULL ,
1153 /* num_syn_resources            */  0 ,
1154 /* syn_constraint_resources     */  NULL ,
1155 /* num_syn_constraint_resources */  0 ,
1156 /* parent_process               */  XmInheritParentProcess,
1157 /* manager_extension            */  NULL ,
1158 },
1159 { /* XmTabs_class part */
1160 border_highlight,
1161 border_unhighlight,
1162 },
1163 };
1164 WidgetClass xmTabsWidgetClass = (WidgetClass) &xmTabsClassRec;
1165 /*ARGSUSED*/
activate(Widget self,XEvent * event,String * params,Cardinal * num_params)1166 static void activate(Widget self, XEvent *event, String *params, Cardinal *num_params)
1167 {
1168     int x0, x1, dummy, i, x, y;
1169     XPoint poly[12];
1170 
1171     switch (((XmTabsWidget)self)->xmTabs.orientation) {
1172     case XfwfUpTabs:
1173     case XfwfDownTabs:
1174 	x = event->xbutton.x;
1175 	comp_hor_tab_shape(self, ((XmTabsWidget)self)->xmTabs.lefttabs, poly, &x0, &x1, &dummy);
1176 	if (x0 <= x && x < x1) {
1177 	    XtCallCallbackList(self, ((XmTabsWidget)self)->xmTabs.activateCallback, (XtPointer) 0);
1178 	    return;
1179 	}
1180 	for (i = -1; i >= -((XmTabsWidget)self)->xmTabs.lefttabs; i--) {
1181 	    comp_hor_tab_shape(self, i + ((XmTabsWidget)self)->xmTabs.lefttabs, poly, &x0, &x1, &dummy);
1182 	    if (x0 <= x && x < x1) {
1183 		XtCallCallbackList(self, ((XmTabsWidget)self)->xmTabs.activateCallback, (XtPointer) i);
1184 		return;
1185 	    }
1186 	}
1187 	for (i = 1; i <= ((XmTabsWidget)self)->xmTabs.righttabs; i++) {
1188 	    comp_hor_tab_shape(self, i + ((XmTabsWidget)self)->xmTabs.lefttabs, poly, &x0, &x1, &dummy);
1189 	    if (x0 <= x && x < x1) {
1190 		XtCallCallbackList(self, ((XmTabsWidget)self)->xmTabs.activateCallback, (XtPointer) i);
1191 		return;
1192 	    }
1193 	}
1194 	break;
1195     case XfwfLeftTabs:
1196     case XfwfRightTabs:
1197 	y = event->xbutton.y;
1198 	comp_ver_tab_shape(self, ((XmTabsWidget)self)->xmTabs.lefttabs, poly, &x0, &x1, &dummy);
1199 	if (x0 <= y && y < x1) {
1200 	    XtCallCallbackList(self, ((XmTabsWidget)self)->xmTabs.activateCallback, (XtPointer) 0);
1201 	    return;
1202 	}
1203 	for (i = -1; i >= -((XmTabsWidget)self)->xmTabs.lefttabs; i--) {
1204 	    comp_ver_tab_shape(self, i + ((XmTabsWidget)self)->xmTabs.lefttabs, poly, &x0, &x1, &dummy);
1205 	    if (x0 <= y && y < x1) {
1206 		XtCallCallbackList(self, ((XmTabsWidget)self)->xmTabs.activateCallback, (XtPointer) i);
1207 		return;
1208 	    }
1209 	}
1210 	for (i = 1; i <= ((XmTabsWidget)self)->xmTabs.righttabs; i++) {
1211 	    comp_ver_tab_shape(self, i + ((XmTabsWidget)self)->xmTabs.lefttabs, poly, &x0, &x1, &dummy);
1212 	    if (x0 <= y && y < x1) {
1213 		XtCallCallbackList(self, ((XmTabsWidget)self)->xmTabs.activateCallback, (XtPointer) i);
1214 		return;
1215 	    }
1216 	}
1217 	break;
1218     }
1219 }
1220 
_resolve_inheritance(WidgetClass class)1221 static void _resolve_inheritance(WidgetClass class)
1222 {
1223   XmTabsWidgetClass c = (XmTabsWidgetClass) class;
1224   XmTabsWidgetClass super;
1225   static CompositeClassExtensionRec extension_rec = {
1226     NULL, NULLQUARK, XtCompositeExtensionVersion,
1227     sizeof(CompositeClassExtensionRec), True};
1228   CompositeClassExtensionRec *ext;
1229   ext = (XtPointer)XtMalloc(sizeof(*ext));
1230   *ext = extension_rec;
1231   ext->next_extension = c->composite_class.extension;
1232   c->composite_class.extension = ext;
1233   if (class == xmTabsWidgetClass) return;
1234   super = (XmTabsWidgetClass)class->core_class.superclass;
1235   if (c->xmTabs_class.border_highlight == XtInherit_border_highlight)
1236     c->xmTabs_class.border_highlight = super->xmTabs_class.border_highlight;
1237   if (c->xmTabs_class.border_unhighlight == XtInherit_border_unhighlight)
1238     c->xmTabs_class.border_unhighlight = super->xmTabs_class.border_unhighlight;
1239 }
1240 /*ARGSUSED*/
1241 #if NeedFunctionPrototypes
class_initialize(void)1242 static void class_initialize(void)
1243 #else
1244 static void class_initialize(void)
1245 #endif
1246 {
1247     XtSetTypeConverter(XtRString, "StringArray",
1248 		       cvtStringToStringArray,
1249 		       NULL, 0, XtCacheNone, NULL);
1250     XtSetTypeConverter(XtRString, "TabsOrientation",
1251 		       cvtStringToTabsOrientation,
1252 		       NULL, 0, XtCacheNone, NULL);
1253     XtSetTypeConverter("TabsOrientation", XtRString,
1254 		       cvtTabsOrientationToString,
1255 		       NULL, 0, XtCacheNone, NULL);
1256 }
1257 /*ARGSUSED*/
1258 #if NeedFunctionPrototypes
initialize(Widget request,Widget self,ArgList args,Cardinal * num_args)1259 static void initialize(Widget  request,Widget self,ArgList  args,Cardinal * num_args)
1260 #else
1261 static void initialize(request,self,args,num_args)Widget  request;Widget self;ArgList  args;Cardinal * num_args;
1262 #endif
1263 {
1264     String *h;
1265     int i;
1266 
1267     ((XmTabsWidget)self)->xmManager.traversal_on = FALSE;
1268     ((XmTabsWidget)self)->xmTabs.topgc = NULL;
1269     create_topgc(self);
1270     ((XmTabsWidget)self)->xmTabs.bottomgc = NULL;
1271     create_bottomgc(self);
1272     ((XmTabsWidget)self)->xmTabs.textgc = NULL;
1273     create_textgc(self);
1274     ((XmTabsWidget)self)->xmTabs.fillgc = NULL;
1275     create_fillgc(self);
1276     ((XmTabsWidget)self)->xmTabs.backgc = NULL;
1277     create_backgc(self);
1278     if (((XmTabsWidget)self)->xmTabs.labels) {
1279 	h = (String*) XtMalloc((((XmTabsWidget)self)->xmTabs.lefttabs + ((XmTabsWidget)self)->xmTabs.righttabs + 1) * sizeof(*h));
1280 	for (i = ((XmTabsWidget)self)->xmTabs.lefttabs + ((XmTabsWidget)self)->xmTabs.righttabs; i >= 0; i--)
1281 	    h[i] = XtNewString(((XmTabsWidget)self)->xmTabs.labels[i]);
1282 	((XmTabsWidget)self)->xmTabs.labels = h;
1283     }
1284     if (((XmTabsWidget)self)->xmTabs.tabWidthPercentage < 0 || ((XmTabsWidget)self)->xmTabs.tabWidthPercentage > 100) {
1285 	XtAppWarning(XtWidgetToApplicationContext(self),
1286 		     "tabWidthPercentage out of range; reset to 50");
1287 	((XmTabsWidget)self)->xmTabs.tabWidthPercentage = 50;
1288     }
1289     ((XmTabsWidget)self)->xmTabs.offsets = NULL;
1290     ((XmTabsWidget)self)->xmTabs.tabwidths = NULL;
1291     compute_tabsizes(self);
1292 }
1293 /*ARGSUSED*/
1294 #if NeedFunctionPrototypes
set_values(Widget old,Widget request,Widget self,ArgList args,Cardinal * num_args)1295 static Boolean  set_values(Widget  old,Widget  request,Widget self,ArgList  args,Cardinal * num_args)
1296 #else
1297 static Boolean  set_values(old,request,self,args,num_args)Widget  old;Widget  request;Widget self;ArgList  args;Cardinal * num_args;
1298 #endif
1299 {
1300     Bool redraw = FALSE, resize_labels = FALSE;
1301     String *h;
1302     int i;
1303 
1304     if (((XmTabsWidget)self)->core.background_pixel != ((XmTabsWidget)old)->core.background_pixel
1305 	|| ((XmTabsWidget)self)->core.background_pixmap != ((XmTabsWidget)old)->core.background_pixmap
1306 	|| ((XmTabsWidget)self)->xmManager.shadow_thickness != ((XmTabsWidget)old)->xmManager.shadow_thickness) {
1307 	create_topgc(self);
1308 	create_bottomgc(self);
1309 	create_backgc(self);
1310     }
1311     if (((XmTabsWidget)self)->xmManager.foreground != ((XmTabsWidget)old)->xmManager.foreground || ((XmTabsWidget)self)->xmTabs.font != ((XmTabsWidget)old)->xmTabs.font) {
1312 	create_textgc(self);
1313 	redraw = TRUE;
1314     }
1315     if (((XmTabsWidget)self)->xmTabs.tabcolor != ((XmTabsWidget)old)->xmTabs.tabcolor) {
1316 	create_fillgc(self);
1317 	redraw = TRUE;
1318     }
1319     if ((((XmTabsWidget)self)->xmTabs.textmargin != ((XmTabsWidget)old)->xmTabs.textmargin && ((XmTabsWidget)self)->xmTabs.tabWidthPercentage == 0)
1320 	|| ((XmTabsWidget)self)->xmTabs.cornerwidth != ((XmTabsWidget)old)->xmTabs.cornerwidth
1321 	|| ((XmTabsWidget)self)->xmTabs.cornerheight != ((XmTabsWidget)old)->xmTabs.cornerheight) {
1322 	resize_labels = TRUE;
1323     }
1324     if (((XmTabsWidget)self)->xmTabs.labels != ((XmTabsWidget)old)->xmTabs.labels) {
1325 	if (((XmTabsWidget)self)->xmTabs.labels) {
1326 	    h = (String*) XtMalloc((((XmTabsWidget)self)->xmTabs.lefttabs + ((XmTabsWidget)self)->xmTabs.righttabs + 1) * sizeof(*h));
1327 	    for (i = ((XmTabsWidget)self)->xmTabs.lefttabs + ((XmTabsWidget)self)->xmTabs.righttabs; i >= 0; i--)
1328 		h[i] = XtNewString(((XmTabsWidget)self)->xmTabs.labels[i]);
1329 	    ((XmTabsWidget)self)->xmTabs.labels = h;
1330 	}
1331 	if (((XmTabsWidget)old)->xmTabs.labels) {
1332 	    for (i = ((XmTabsWidget)old)->xmTabs.lefttabs + ((XmTabsWidget)old)->xmTabs.righttabs; i >= 0; i--)
1333 		XtFree(((XmTabsWidget)old)->xmTabs.labels[i]);
1334 	    XtFree((XtPointer) ((XmTabsWidget)old)->xmTabs.labels);
1335 	}
1336 	resize_labels = TRUE;
1337     }
1338     if (((XmTabsWidget)self)->xmTabs.tabWidthPercentage < 0 || ((XmTabsWidget)self)->xmTabs.tabWidthPercentage > 100) {
1339 	XtAppWarning(XtWidgetToApplicationContext(self),
1340 		     "tabWidthPercentage out of range; reset to 50");
1341 	((XmTabsWidget)self)->xmTabs.tabWidthPercentage = 50;
1342     }
1343     if (((XmTabsWidget)old)->xmTabs.tabWidthPercentage != ((XmTabsWidget)self)->xmTabs.tabWidthPercentage)
1344 	resize_labels = TRUE;
1345     if (((XmTabsWidget)self)->xmTabs.lefttabs != ((XmTabsWidget)old)->xmTabs.lefttabs || ((XmTabsWidget)self)->xmTabs.righttabs != ((XmTabsWidget)old)->xmTabs.righttabs)
1346 	redraw = TRUE;
1347     if (resize_labels) {
1348 	compute_tabsizes(self);
1349 	redraw = TRUE;
1350     }
1351     return redraw;
1352 }
1353 /*ARGSUSED*/
1354 #if NeedFunctionPrototypes
realize(Widget self,XtValueMask * mask,XSetWindowAttributes * attributes)1355 static void realize(Widget self,XtValueMask * mask,XSetWindowAttributes * attributes)
1356 #else
1357 static void realize(self,mask,attributes)Widget self;XtValueMask * mask;XSetWindowAttributes * attributes;
1358 #endif
1359 {
1360     *mask |= CWBitGravity;
1361     attributes->bit_gravity = ForgetGravity;
1362     xmManagerClassRec.core_class.realize(self, mask, attributes);
1363     set_shape(self);
1364 }
1365 /*ARGSUSED*/
1366 #if NeedFunctionPrototypes
resize(Widget self)1367 static void resize(Widget self)
1368 #else
1369 static void resize(self)Widget self;
1370 #endif
1371 {
1372     if (XtIsRealized(self))
1373 	XClearArea(XtDisplay(self), XtWindow(self), 0, 0, 0, 0, True);
1374     compute_tabsizes(self);
1375     set_shape(self);
1376     if ( xmManagerClassRec.core_class.resize ) xmManagerClassRec.core_class.resize(self);
1377 }
1378 /*ARGSUSED*/
1379 #if NeedFunctionPrototypes
expose(Widget self,XEvent * event,Region region)1380 static void expose(Widget self,XEvent * event,Region  region)
1381 #else
1382 static void expose(self,event,region)Widget self;XEvent * event;Region  region;
1383 #endif
1384 {
1385     int i;
1386 
1387     if (! XtIsRealized(self)) return;
1388 
1389     switch (((XmTabsWidget)self)->xmTabs.orientation) {
1390     case XfwfUpTabs:
1391     case XfwfDownTabs:
1392 	for (i = 0; i < ((XmTabsWidget)self)->xmTabs.lefttabs; i++)
1393 	    draw_hor_tab(self, region, i);
1394 	for (i = ((XmTabsWidget)self)->xmTabs.lefttabs + ((XmTabsWidget)self)->xmTabs.righttabs; i > ((XmTabsWidget)self)->xmTabs.lefttabs; i--)
1395 	    draw_hor_tab(self, region, i);
1396 	draw_hor_tab(self, region, ((XmTabsWidget)self)->xmTabs.lefttabs);
1397 	break;
1398     case XfwfLeftTabs:
1399     case XfwfRightTabs:
1400 	for (i = 0; i < ((XmTabsWidget)self)->xmTabs.lefttabs; i++)
1401 	    draw_ver_tab(self, region, i);
1402 	for (i = ((XmTabsWidget)self)->xmTabs.lefttabs + ((XmTabsWidget)self)->xmTabs.righttabs; i > ((XmTabsWidget)self)->xmTabs.lefttabs; i--)
1403 	    draw_ver_tab(self, region, i);
1404 	draw_ver_tab(self, region, ((XmTabsWidget)self)->xmTabs.lefttabs);
1405 	break;
1406     }
1407     /* Focus highlight? */
1408 }
1409 /*ARGSUSED*/
1410 #if NeedFunctionPrototypes
border_highlight(void)1411 static void border_highlight(void)
1412 #else
1413 static void border_highlight(void)
1414 #endif
1415 {
1416 }
1417 /*ARGSUSED*/
1418 #if NeedFunctionPrototypes
border_unhighlight(void)1419 static void border_unhighlight(void)
1420 #else
1421 static void border_unhighlight(void)
1422 #endif
1423 {
1424 }
1425 /*ARGSUSED*/
1426 #if NeedFunctionPrototypes
destroy(Widget self)1427 static void destroy(Widget self)
1428 #else
1429 static void destroy(self)Widget self;
1430 #endif
1431 {
1432     int i;
1433 
1434     if (((XmTabsWidget)self)->xmTabs.labels) {
1435 	for (i = ((XmTabsWidget)self)->xmTabs.lefttabs + ((XmTabsWidget)self)->xmTabs.righttabs; i >= 0; i--)
1436 	    XtFree(((XmTabsWidget)self)->xmTabs.labels[i]);
1437 	XtFree((XtPointer) ((XmTabsWidget)self)->xmTabs.labels);
1438     }
1439     if (((XmTabsWidget)self)->xmTabs.offsets)
1440 	XtFree((XtPointer) ((XmTabsWidget)self)->xmTabs.offsets);
1441     if (((XmTabsWidget)self)->xmTabs.tabwidths)
1442 	XtFree((XtPointer) ((XmTabsWidget)self)->xmTabs.tabwidths);
1443 }
1444 
1445 
1446 /* ***********************************************************************
1447  * Routines for drawing rotated text
1448  * ***********************************************************************
1449  */
1450 
1451 /* xvertext 5.0, Copyright (c) 1993 Alan Richardson (mppa3@uk.ac.sussex.syma)
1452  *
1453  * Permission to use, copy, modify, and distribute this software and its
1454  * documentation for any purpose and without fee is hereby granted, provided
1455  * that the above copyright notice appear in all copies and that both the
1456  * copyright notice and this permission notice appear in supporting
1457  * documentation.  All work developed as a consequence of the use of
1458  * this program should duly acknowledge such use. No representations are
1459  * made about the suitability of this software for any purpose.  It is
1460  * provided "as is" without express or implied warranty.
1461  *
1462  * 8 Jun '95: [Bert Bos] added GCClipXOrigin|GCClipYOrigin|GCClipMask
1463  * when calling XCopyGC()
1464  */
1465 
1466 /* ********************************************************************** */
1467 
1468 
1469 /* BETTER: xvertext now does rotation at any angle!!
1470  *
1471  * BEWARE: function arguments have CHANGED since version 2.0!!
1472  */
1473 
1474 /* ********************************************************************** */
1475 
1476 
1477 
1478 /* ---------------------------------------------------------------------- */
1479 
1480 
1481 /* Make sure cache size is set */
1482 
1483 #ifndef CACHE_SIZE_LIMIT
1484 #define CACHE_SIZE_LIMIT 0
1485 #endif /*CACHE_SIZE_LIMIT */
1486 
1487 /* Make sure a cache method is specified */
1488 
1489 #ifndef CACHE_XIMAGES
1490 #ifndef CACHE_BITMAPS
1491 #define CACHE_BITMAPS
1492 #endif /*CACHE_BITMAPS*/
1493 #endif /*CACHE_XIMAGES*/
1494 
1495 
1496 /* ---------------------------------------------------------------------- */
1497 
1498 
1499 /* Debugging macros */
1500 
1501 #ifdef DEBUG
1502 static int debug=1;
1503 #else
1504 static int debug=0;
1505 #endif /*DEBUG*/
1506 
1507 #define DEBUG_PRINT1(a) if (debug) printf (a)
1508 #define DEBUG_PRINT2(a, b) if (debug) printf (a, b)
1509 #define DEBUG_PRINT3(a, b, c) if (debug) printf (a, b, c)
1510 #define DEBUG_PRINT4(a, b, c, d) if (debug) printf (a, b, c, d)
1511 #define DEBUG_PRINT5(a, b, c, d, e) if (debug) printf (a, b, c, d, e)
1512 
1513 
1514 /* ---------------------------------------------------------------------- */
1515 
1516 
1517 #ifndef M_PI
1518 #define M_PI 3.14159265358979323846
1519 #endif
1520 
1521 
1522 /* ---------------------------------------------------------------------- */
1523 
1524 
1525 /* A structure holding everything needed for a rotated string */
1526 
1527 typedef struct rotated_text_item_template {
1528     Pixmap bitmap;
1529     XImage *ximage;
1530 
1531     char *text;
1532     char *font_name;
1533     Font fid;
1534     float angle;
1535     int align;
1536     float magnify;
1537 
1538     int cols_in;
1539     int rows_in;
1540     int cols_out;
1541     int rows_out;
1542 
1543     int nl;
1544     int max_width;
1545     float *corners_x;
1546     float *corners_y;
1547 
1548     long int size;
1549     int cached;
1550 
1551     struct rotated_text_item_template *next;
1552 } RotatedTextItem;
1553 
1554 RotatedTextItem *first_text_item=NULL;
1555 
1556 
1557 /* ---------------------------------------------------------------------- */
1558 
1559 
1560 /* A structure holding current magnification and bounding box padding */
1561 
1562 static struct style_template {
1563     float magnify;
1564     int bbx_pad;
1565 } style={
1566     1.,
1567     0
1568     };
1569 
1570 
1571 /* ---------------------------------------------------------------------- */
1572 
1573 
1574 static char            *my_strdup(char *str);
1575 static char            *my_strtok(char *str1, char *str2);
1576 
1577 static float                   XRotVersion(char *str, int n);
1578 static void                    XRotSetMagnification(float m);
1579 static void                    XRotSetBoundingBoxPad(int p);
1580 static int                     XRotDrawString(Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *str);
1581 static int                     XRotDrawImageString(Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *str);
1582 static int                     XRotDrawAlignedString(Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *text, int align);
1583 static int                     XRotDrawAlignedImageString(Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *text, int align);
1584 static XPoint                 *XRotTextExtents(Display *dpy, XFontStruct *font, float angle, int x, int y, char *text, int align);
1585 
1586 static XImage          *MakeXImage(Display *dpy, int w, int h);
1587 static int              XRotPaintAlignedString(Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *text, int align, int bg);
1588 static int              XRotDrawHorizontalString(Display *dpy, XFontStruct *font, Drawable drawable, GC gc, int x, int y, char *text, int align, int bg);
1589 static RotatedTextItem *XRotRetrieveFromCache(Display *dpy, XFontStruct *font, float angle, char *text, int align);
1590 static RotatedTextItem *XRotCreateTextItem(Display *dpy, XFontStruct *font, float angle, char *text, int align);
1591 static void             XRotAddToLinkedList(Display *dpy, RotatedTextItem *item);
1592 static void             XRotFreeTextItem(Display *dpy, RotatedTextItem *item);
1593 static XImage          *XRotMagnifyImage(Display *dpy, XImage *ximage);
1594 
1595 
1596 /* ---------------------------------------------------------------------- */
1597 
1598 
1599 /**************************************************************************/
1600 /* Routine to mimic `strdup()' (some machines don't have it)              */
1601 /**************************************************************************/
1602 
my_strdup(char * str)1603 static char *my_strdup(char *str)
1604 {
1605     char *s;
1606 
1607     if(str==NULL)
1608 	return NULL;
1609 
1610     s=(char *)malloc((unsigned)(strlen(str)+1));
1611     if(s!=NULL)
1612 	strcpy(s, str);
1613 
1614     return s;
1615 }
1616 
1617 
1618 /* ---------------------------------------------------------------------- */
1619 
1620 
1621 /**************************************************************************/
1622 /* Routine to replace `strtok' : this one returns a zero length string if */
1623 /* it encounters two consecutive delimiters                               */
1624 /**************************************************************************/
1625 
my_strtok(char * str1,char * str2)1626 static char *my_strtok(char *str1, char *str2)
1627 {
1628     char *ret;
1629     int i, j, stop;
1630     static int start, len;
1631     static char *stext;
1632 
1633     if(str2==NULL)
1634 	return NULL;
1635 
1636     /* initialise if str1 not NULL */
1637     if(str1!=NULL) {
1638 	start=0;
1639 	stext=str1;
1640 	len=strlen(str1);
1641     }
1642 
1643     /* run out of tokens ? */
1644     if(start>=len)
1645 	return NULL;
1646 
1647     /* loop through characters */
1648     for(i=start; i<len; i++) {
1649 	/* loop through delimiters */
1650 	stop=0;
1651 	for(j=0; j<strlen(str2); j++)
1652 	    if(stext[i]==str2[j])
1653 		stop=1;
1654 
1655 	if(stop)
1656 	    break;
1657     }
1658 
1659     stext[i]='\0';
1660 
1661     ret=stext+start;
1662 
1663     start=i+1;
1664 
1665     return ret;
1666 }
1667 
1668 
1669 /* ---------------------------------------------------------------------- */
1670 
1671 
1672 /**************************************************************************/
1673 /* Return version/copyright information                                   */
1674 /**************************************************************************/
1675 static
XRotVersion(char * str,int n)1676 float XRotVersion(char *str, int n)
1677 {
1678     if(str!=NULL)
1679 	strncpy(str, XV_COPYRIGHT, n);
1680     return XV_VERSION;
1681 }
1682 
1683 
1684 /* ---------------------------------------------------------------------- */
1685 
1686 
1687 /**************************************************************************/
1688 /* Set the font magnification factor for all subsequent operations        */
1689 /**************************************************************************/
1690 static
XRotSetMagnification(float m)1691 void XRotSetMagnification(float m)
1692 {
1693     if(m>0.)
1694 	style.magnify=m;
1695 }
1696 
1697 
1698 /* ---------------------------------------------------------------------- */
1699 
1700 
1701 /**************************************************************************/
1702 /* Set the padding used when calculating bounding boxes                   */
1703 /**************************************************************************/
1704 static
XRotSetBoundingBoxPad(int p)1705 void XRotSetBoundingBoxPad(int p)
1706 {
1707     if(p>=0)
1708 	style.bbx_pad=p;
1709 }
1710 
1711 
1712 /* ---------------------------------------------------------------------- */
1713 
1714 
1715 /**************************************************************************/
1716 /*  Create an XImage structure and allocate memory for it                 */
1717 /**************************************************************************/
1718 
MakeXImage(Display * dpy,int w,int h)1719 static XImage *MakeXImage(Display *dpy, int w, int h)
1720 {
1721     XImage *I;
1722     char *data;
1723 
1724     /* reserve memory for image */
1725     data=(char *)calloc((unsigned)(((w-1)/8+1)*h), 1);
1726     if(data==NULL)
1727 	return NULL;
1728 
1729     /* create the XImage */
1730     I=XCreateImage(dpy, DefaultVisual(dpy, DefaultScreen(dpy)), 1, XYBitmap,
1731                    0, data, w, h, 8, 0);
1732     if(I==NULL)
1733 	return NULL;
1734 
1735     I->byte_order=I->bitmap_bit_order=MSBFirst;
1736     return I;
1737 }
1738 
1739 
1740 /* ---------------------------------------------------------------------- */
1741 
1742 
1743 /**************************************************************************/
1744 /*  A front end to XRotPaintAlignedString:                                */
1745 /*      -no alignment, no background                                      */
1746 /**************************************************************************/
1747 static
XRotDrawString(Display * dpy,XFontStruct * font,float angle,Drawable drawable,GC gc,int x,int y,char * str)1748 int XRotDrawString(Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *str)
1749 {
1750     return (XRotPaintAlignedString(dpy, font, angle, drawable, gc,
1751 				   x, y, str, NONE, 0));
1752 }
1753 
1754 
1755 /* ---------------------------------------------------------------------- */
1756 
1757 
1758 /**************************************************************************/
1759 /*  A front end to XRotPaintAlignedString:                                */
1760 /*      -no alignment, paints background                                  */
1761 /**************************************************************************/
1762 static
XRotDrawImageString(Display * dpy,XFontStruct * font,float angle,Drawable drawable,GC gc,int x,int y,char * str)1763 int XRotDrawImageString(Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *str)
1764 {
1765     return(XRotPaintAlignedString(dpy, font, angle, drawable, gc,
1766 				  x, y, str, NONE, 1));
1767 }
1768 
1769 
1770 /* ---------------------------------------------------------------------- */
1771 
1772 
1773 /**************************************************************************/
1774 /*  A front end to XRotPaintAlignedString:                                */
1775 /*      -does alignment, no background                                    */
1776 /**************************************************************************/
1777 static
XRotDrawAlignedString(Display * dpy,XFontStruct * font,float angle,Drawable drawable,GC gc,int x,int y,char * text,int align)1778 int XRotDrawAlignedString(Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *text, int align)
1779 {
1780     return(XRotPaintAlignedString(dpy, font, angle, drawable, gc,
1781 				  x, y, text, align, 0));
1782 }
1783 
1784 
1785 /* ---------------------------------------------------------------------- */
1786 
1787 
1788 /**************************************************************************/
1789 /*  A front end to XRotPaintAlignedString:                                */
1790 /*      -does alignment, paints background                                */
1791 /**************************************************************************/
1792 static
XRotDrawAlignedImageString(Display * dpy,XFontStruct * font,float angle,Drawable drawable,GC gc,int x,int y,char * text,int align)1793 int XRotDrawAlignedImageString(Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *text, int align)
1794 {
1795     return(XRotPaintAlignedString(dpy, font, angle, drawable, gc,
1796 				  x, y, text, align, 1));
1797 }
1798 
1799 
1800 /* ---------------------------------------------------------------------- */
1801 
1802 
1803 /**************************************************************************/
1804 /*  Aligns and paints a rotated string                                    */
1805 /**************************************************************************/
1806 
XRotPaintAlignedString(Display * dpy,XFontStruct * font,float angle,Drawable drawable,GC gc,int x,int y,char * text,int align,int bg)1807 static int XRotPaintAlignedString(Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *text, int align, int bg)
1808 {
1809     int i;
1810     GC my_gc;
1811     int xp, yp;
1812     float hot_x, hot_y;
1813     float hot_xp, hot_yp;
1814     float sin_angle, cos_angle;
1815     RotatedTextItem *item;
1816     Pixmap bitmap_to_paint;
1817 
1818     /* return early for NULL/empty strings */
1819     if(text==NULL)
1820         return 0;
1821 
1822     if(strlen(text)==0)
1823 	return 0;
1824 
1825     /* manipulate angle to 0<=angle<360 degrees */
1826     while(angle<0)
1827         angle+=360;
1828 
1829     while(angle>=360)
1830         angle-=360;
1831 
1832     angle*=M_PI/180;
1833 
1834     /* horizontal text made easy */
1835     if(angle==0. && style.magnify==1.)
1836 	return(XRotDrawHorizontalString(dpy, font, drawable, gc, x, y,
1837 					text, align, bg));
1838 
1839     /* get a rotated bitmap */
1840     item=XRotRetrieveFromCache(dpy, font, angle, text, align);
1841     if(item==NULL)
1842 	return NULL;
1843 
1844     /* this gc has similar properties to the user's gc */
1845     my_gc=XCreateGC(dpy, drawable, NULL, 0);
1846     XCopyGC(dpy, gc, GCForeground|GCBackground|GCFunction|GCPlaneMask
1847 	    |GCClipXOrigin|GCClipYOrigin|GCClipMask, my_gc);
1848 
1849     /* alignment : which point (hot_x, hot_y) relative to bitmap centre
1850        coincides with user's specified point? */
1851 
1852     /* y position */
1853     if(align==TLEFT || align==TCENTRE || align==TRIGHT)
1854         hot_y=(float)item->rows_in/2*style.magnify;
1855     else if(align==MLEFT || align==MCENTRE || align==MRIGHT)
1856 	hot_y=0;
1857     else if(align==BLEFT || align==BCENTRE || align==BRIGHT)
1858 	hot_y = -(float)item->rows_in/2*style.magnify;
1859     else
1860 	hot_y = -((float)item->rows_in/2-(float)font->descent)*style.magnify;
1861 
1862     /* x position */
1863     if(align==TLEFT || align==MLEFT || align==BLEFT || align==NONE)
1864 	hot_x = -(float)item->max_width/2*style.magnify;
1865     else if(align==TCENTRE || align==MCENTRE || align==BCENTRE)
1866 	hot_x=0;
1867     else
1868         hot_x=(float)item->max_width/2*style.magnify;
1869 
1870     /* pre-calculate sin and cos */
1871     sin_angle=sin(angle);
1872     cos_angle=cos(angle);
1873 
1874     /* rotate hot_x and hot_y around bitmap centre */
1875     hot_xp= hot_x*cos_angle - hot_y*sin_angle;
1876     hot_yp= hot_x*sin_angle + hot_y*cos_angle;
1877 
1878     /* text background will be drawn using XFillPolygon */
1879     if(bg) {
1880 	GC depth_one_gc;
1881 	XPoint *xpoints;
1882 	Pixmap empty_stipple;
1883 
1884 	/* reserve space for XPoints */
1885 	xpoints=(XPoint *)malloc((unsigned)(4*item->nl*sizeof(XPoint)));
1886 	if(!xpoints)
1887 	    return 1;
1888 
1889 	/* rotate corner positions */
1890 	for(i=0; i<4*item->nl; i++) {
1891 	    xpoints[i].x=(float)x + ( (item->corners_x[i]-hot_x)*cos_angle +
1892 				      (item->corners_y[i]+hot_y)*sin_angle);
1893 	    xpoints[i].y=(float)y + (-(item->corners_x[i]-hot_x)*sin_angle +
1894 				      (item->corners_y[i]+hot_y)*cos_angle);
1895 	}
1896 
1897 	/* we want to swap foreground and background colors here;
1898 	   XGetGCValues() is only available in R4+ */
1899 
1900 	empty_stipple=XCreatePixmap(dpy, drawable, 1, 1, 1);
1901 
1902 	depth_one_gc=XCreateGC(dpy, empty_stipple, NULL, 0);
1903 	XSetForeground(dpy, depth_one_gc, 0);
1904 	XFillRectangle(dpy, empty_stipple, depth_one_gc, 0, 0, 2, 2);
1905 
1906 	XSetStipple(dpy, my_gc, empty_stipple);
1907 	XSetFillStyle(dpy, my_gc, FillOpaqueStippled);
1908 
1909 	XFillPolygon(dpy, drawable, my_gc, xpoints, 4*item->nl, Nonconvex,
1910 		     CoordModeOrigin);
1911 
1912 	/* free our resources */
1913 	free((char *)xpoints);
1914 	XFreeGC(dpy, depth_one_gc);
1915 	XFreePixmap(dpy, empty_stipple);
1916     }
1917 
1918     /* where should top left corner of bitmap go ? */
1919     xp=(float)x-((float)item->cols_out/2 +hot_xp);
1920     yp=(float)y-((float)item->rows_out/2 -hot_yp);
1921 
1922     /* by default we draw the rotated bitmap, solid */
1923     bitmap_to_paint=item->bitmap;
1924 
1925     /* handle user stippling */
1926 #ifndef X11R3
1927     {
1928 	GC depth_one_gc;
1929 	XGCValues values;
1930 	Pixmap new_bitmap, inverse;
1931 
1932 	/* try and get some GC properties */
1933 	if(XGetGCValues(dpy, gc,
1934 			GCStipple|GCFillStyle|GCForeground|GCBackground|
1935 			GCTileStipXOrigin|GCTileStipYOrigin,
1936 			&values)) {
1937 
1938 	    /* only do this if stippling requested */
1939 	    if((values.fill_style==FillStippled ||
1940 		values.fill_style==FillOpaqueStippled) && !bg) {
1941 
1942 		/* opaque stipple: draw rotated text in background colour */
1943 		if(values.fill_style==FillOpaqueStippled) {
1944 		    XSetForeground(dpy, my_gc, values.background);
1945 		    XSetFillStyle(dpy, my_gc, FillStippled);
1946 		    XSetStipple(dpy, my_gc, item->bitmap);
1947 		    XSetTSOrigin(dpy, my_gc, xp, yp);
1948 		    XFillRectangle(dpy, drawable, my_gc, xp, yp,
1949 				   item->cols_out, item->rows_out);
1950 		    XSetForeground(dpy, my_gc, values.foreground);
1951 		}
1952 
1953 		/* this will merge the rotated text and the user's stipple */
1954 		new_bitmap=XCreatePixmap(dpy, drawable,
1955 					 item->cols_out, item->rows_out, 1);
1956 
1957 		/* create a GC */
1958 		depth_one_gc=XCreateGC(dpy, new_bitmap, NULL, 0);
1959 		XSetForeground(dpy, depth_one_gc, 1);
1960 		XSetBackground(dpy, depth_one_gc, 0);
1961 
1962 		/* set the relative stipple origin */
1963 		XSetTSOrigin(dpy, depth_one_gc,
1964 			     values.ts_x_origin-xp, values.ts_y_origin-yp);
1965 
1966 		/* fill the whole bitmap with the user's stipple */
1967 		XSetStipple(dpy, depth_one_gc, values.stipple);
1968 		XSetFillStyle(dpy, depth_one_gc, FillOpaqueStippled);
1969 		XFillRectangle(dpy, new_bitmap, depth_one_gc,
1970 			       0, 0, item->cols_out, item->rows_out);
1971 
1972 		/* set stipple origin back to normal */
1973 		XSetTSOrigin(dpy, depth_one_gc, 0, 0);
1974 
1975 		/* this will contain an inverse copy of the rotated text */
1976 		inverse=XCreatePixmap(dpy, drawable,
1977 				      item->cols_out, item->rows_out, 1);
1978 
1979 		/* invert text */
1980 		XSetFillStyle(dpy, depth_one_gc, FillSolid);
1981 		XSetFunction(dpy, depth_one_gc, GXcopyInverted);
1982 		XCopyArea(dpy, item->bitmap, inverse, depth_one_gc,
1983 			  0, 0, item->cols_out, item->rows_out, 0, 0);
1984 
1985 		/* now delete user's stipple everywhere EXCEPT on text */
1986                 XSetForeground(dpy, depth_one_gc, 0);
1987                 XSetBackground(dpy, depth_one_gc, 1);
1988 		XSetStipple(dpy, depth_one_gc, inverse);
1989 		XSetFillStyle(dpy, depth_one_gc, FillStippled);
1990 		XSetFunction(dpy, depth_one_gc, GXcopy);
1991 		XFillRectangle(dpy, new_bitmap, depth_one_gc,
1992                                0, 0, item->cols_out, item->rows_out);
1993 
1994 		/* free resources */
1995 		XFreePixmap(dpy, inverse);
1996 		XFreeGC(dpy, depth_one_gc);
1997 
1998 		/* this is the new bitmap */
1999 		bitmap_to_paint=new_bitmap;
2000 	    }
2001 	}
2002     }
2003 #endif /*X11R3*/
2004 
2005     /* paint text using stipple technique */
2006     XSetFillStyle(dpy, my_gc, FillStippled);
2007     XSetStipple(dpy, my_gc, bitmap_to_paint);
2008     XSetTSOrigin(dpy, my_gc, xp, yp);
2009     XFillRectangle(dpy, drawable, my_gc, xp, yp,
2010 		   item->cols_out, item->rows_out);
2011 
2012     /* free our resources */
2013     XFreeGC(dpy, my_gc);
2014 
2015     /* stippled bitmap no longer needed */
2016     if(bitmap_to_paint!=item->bitmap)
2017 	XFreePixmap(dpy, bitmap_to_paint);
2018 
2019 #ifdef CACHE_XIMAGES
2020     XFreePixmap(dpy, item->bitmap);
2021 #endif /*CACHE_XIMAGES*/
2022 
2023     /* if item isn't cached, destroy it completely */
2024     if(!item->cached)
2025 	XRotFreeTextItem(dpy,item);
2026 
2027     /* we got to the end OK! */
2028     return 0;
2029 }
2030 
2031 
2032 /* ---------------------------------------------------------------------- */
2033 
2034 
2035 /**************************************************************************/
2036 /*  Draw a horizontal string in a quick fashion                           */
2037 /**************************************************************************/
2038 
XRotDrawHorizontalString(Display * dpy,XFontStruct * font,Drawable drawable,GC gc,int x,int y,char * text,int align,int bg)2039 static int XRotDrawHorizontalString(Display *dpy, XFontStruct *font, Drawable drawable, GC gc, int x, int y, char *text, int align, int bg)
2040 {
2041     GC my_gc;
2042     int nl=1, i;
2043     int height;
2044     int xp, yp;
2045     char *str1, *str2, *str3;
2046     char *str2_a="\0", *str2_b="\n\0";
2047     int dir, asc, desc;
2048     XCharStruct overall;
2049 
2050     DEBUG_PRINT1("**\nHorizontal text.\n");
2051 
2052     /* this gc has similar properties to the user's gc (including stipple) */
2053     my_gc=XCreateGC(dpy, drawable, NULL, 0);
2054     XCopyGC(dpy, gc,
2055 	    GCForeground|GCBackground|GCFunction|GCStipple|GCFillStyle|
2056 	    GCTileStipXOrigin|GCTileStipYOrigin|GCPlaneMask|
2057 	    GCClipXOrigin|GCClipYOrigin|GCClipMask, my_gc);
2058     XSetFont(dpy, my_gc, font->fid);
2059 
2060     /* count number of sections in string */
2061     if(align!=NONE)
2062 	for(i=0; i<strlen(text)-1; i++)
2063 	    if(text[i]=='\n')
2064 		nl++;
2065 
2066     /* ignore newline characters if not doing alignment */
2067     if(align==NONE)
2068 	str2=str2_a;
2069     else
2070 	str2=str2_b;
2071 
2072     /* overall font height */
2073     height=font->ascent+font->descent;
2074 
2075     /* y position */
2076     if(align==TLEFT || align==TCENTRE || align==TRIGHT)
2077 	yp=y+font->ascent;
2078     else if(align==MLEFT || align==MCENTRE || align==MRIGHT)
2079 	yp=y-nl*height/2+font->ascent;
2080     else if(align==BLEFT || align==BCENTRE || align==BRIGHT)
2081 	yp=y-nl*height+font->ascent;
2082     else
2083 	yp=y;
2084 
2085     str1=my_strdup(text);
2086     if(str1==NULL)
2087 	return 1;
2088 
2089     str3=my_strtok(str1, str2);
2090 
2091     /* loop through each section in the string */
2092     do {
2093         XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
2094                      &overall);
2095 
2096 	/* where to draw section in x ? */
2097 	if(align==TLEFT || align==MLEFT || align==BLEFT || align==NONE)
2098 	    xp=x;
2099 	else if(align==TCENTRE || align==MCENTRE || align==BCENTRE)
2100 	    xp=x-overall.rbearing/2;
2101 	else
2102 	    xp=x-overall.rbearing;
2103 
2104 	/* draw string onto bitmap */
2105 	if(!bg)
2106 	    XDrawString(dpy, drawable, my_gc, xp, yp, str3, strlen(str3));
2107 	else
2108 	    XDrawImageString(dpy, drawable, my_gc, xp, yp, str3, strlen(str3));
2109 
2110 	/* move to next line */
2111 	yp+=height;
2112 
2113 	str3=my_strtok((char *)NULL, str2);
2114     }
2115     while(str3!=NULL);
2116 
2117     free(str1);
2118     XFreeGC(dpy, my_gc);
2119 
2120     return 0;
2121 }
2122 
2123 
2124 /* ---------------------------------------------------------------------- */
2125 
2126 
2127 /**************************************************************************/
2128 /*   Query cache for a match with this font/text/angle/alignment          */
2129 /*       request, otherwise arrange for its creation                      */
2130 /**************************************************************************/
2131 
XRotRetrieveFromCache(Display * dpy,XFontStruct * font,float angle,char * text,int align)2132 static RotatedTextItem *XRotRetrieveFromCache(Display *dpy, XFontStruct *font, float angle, char *text, int align)
2133 {
2134     Font fid;
2135     char *font_name=NULL;
2136     unsigned long name_value;
2137     RotatedTextItem *item=NULL;
2138     RotatedTextItem *i1=first_text_item;
2139 
2140     /* get font name, if it exists */
2141     if(XGetFontProperty(font, XA_FONT, &name_value)) {
2142 	DEBUG_PRINT1("got font name OK\n");
2143 	font_name=XGetAtomName(dpy, name_value);
2144 	fid=0;
2145     }
2146 #ifdef CACHE_FID
2147     /* otherwise rely (unreliably?) on font ID */
2148     else {
2149 	DEBUG_PRINT1("can't get fontname, caching FID\n");
2150 	font_name=NULL;
2151 	fid=font->fid;
2152     }
2153 #else
2154     /* not allowed to cache font ID's */
2155     else {
2156 	DEBUG_PRINT1("can't get fontname, can't cache\n");
2157 	font_name=NULL;
2158 	fid=0;
2159     }
2160 #endif /*CACHE_FID*/
2161 
2162     /* look for a match in cache */
2163 
2164     /* matching formula:
2165        identical text;
2166        identical fontname (if defined, font ID's if not);
2167        angles close enough (<0.00001 here, could be smaller);
2168        HORIZONTAL alignment matches, OR it's a one line string;
2169        magnifications the same */
2170 
2171     while(i1 && !item) {
2172 	/* match everything EXCEPT fontname/ID */
2173 	if(strcmp(text, i1->text)==0 &&
2174 	   fabs(angle-i1->angle)<0.00001 &&
2175 	   style.magnify==i1->magnify &&
2176 	   (i1->nl==1 ||
2177 	    ((align==0)?9:(align-1))%3==
2178 	      ((i1->align==0)?9:(i1->align-1))%3)) {
2179 
2180 	    /* now match fontname/ID */
2181 	    if(font_name!=NULL && i1->font_name!=NULL) {
2182 		if(strcmp(font_name, i1->font_name)==0) {
2183 		    item=i1;
2184 		    DEBUG_PRINT1("Matched against font names\n");
2185 		}
2186 		else
2187 		    i1=i1->next;
2188 	    }
2189 #ifdef CACHE_FID
2190 	    else if(font_name==NULL && i1->font_name==NULL) {
2191 		if(fid==i1->fid) {
2192 		    item=i1;
2193 		    DEBUG_PRINT1("Matched against FID's\n");
2194                 }
2195 		else
2196                     i1=i1->next;
2197 	    }
2198 #endif /*CACHE_FID*/
2199 	    else
2200 		i1=i1->next;
2201 	}
2202 	else
2203 	    i1=i1->next;
2204     }
2205 
2206     if(item)
2207 	DEBUG_PRINT1("**\nFound target in cache.\n");
2208     if(!item)
2209 	DEBUG_PRINT1("**\nNo match in cache.\n");
2210 
2211     /* no match */
2212     if(!item) {
2213 	/* create new item */
2214 	item=XRotCreateTextItem(dpy, font, angle, text, align);
2215 	if(!item)
2216 	    return NULL;
2217 
2218 	/* record what it shows */
2219 	item->text=my_strdup(text);
2220 
2221 	/* fontname or ID */
2222 	if(font_name!=NULL) {
2223 	    item->font_name=my_strdup(font_name);
2224 	    item->fid=0;
2225 	}
2226 	else {
2227 	    item->font_name=NULL;
2228 	    item->fid=fid;
2229 	}
2230 
2231 	item->angle=angle;
2232 	item->align=align;
2233 	item->magnify=style.magnify;
2234 
2235 	/* cache it */
2236 	XRotAddToLinkedList(dpy, item);
2237     }
2238 
2239     if(font_name)
2240 	XFree(font_name);
2241 
2242     /* if XImage is cached, need to recreate the bitmap */
2243 
2244 #ifdef CACHE_XIMAGES
2245     {
2246 	GC depth_one_gc;
2247 
2248 	/* create bitmap to hold rotated text */
2249 	item->bitmap=XCreatePixmap(dpy, DefaultRootWindow(dpy),
2250 				   item->cols_out, item->rows_out, 1);
2251 
2252 	/* depth one gc */
2253 	depth_one_gc=XCreateGC(dpy, item->bitmap, NULL, 0);
2254 	XSetBackground(dpy, depth_one_gc, 0);
2255 	XSetForeground(dpy, depth_one_gc, 1);
2256 
2257 	/* make the text bitmap from XImage */
2258 	XPutImage(dpy, item->bitmap, depth_one_gc, item->ximage, 0, 0, 0, 0,
2259 		  item->cols_out, item->rows_out);
2260 
2261 	XFreeGC(dpy, depth_one_gc);
2262     }
2263 #endif /*CACHE_XIMAGES*/
2264 
2265     return item;
2266 }
2267 
2268 
2269 /* ---------------------------------------------------------------------- */
2270 
2271 
2272 /**************************************************************************/
2273 /*  Create a rotated text item                                            */
2274 /**************************************************************************/
2275 
XRotCreateTextItem(Display * dpy,XFontStruct * font,float angle,char * text,int align)2276 static RotatedTextItem *XRotCreateTextItem(Display *dpy, XFontStruct *font, float angle, char *text, int align)
2277 {
2278     RotatedTextItem *item=NULL;
2279     Pixmap canvas;
2280     GC font_gc;
2281     XImage *I_in;
2282     register int i, j;
2283     char *str1, *str2, *str3;
2284     char *str2_a="\0", *str2_b="\n\0";
2285     int height;
2286     int byte_w_in, byte_w_out;
2287     int xp, yp;
2288     float sin_angle, cos_angle;
2289     int it, jt;
2290     float di, dj;
2291     int ic=0;
2292     float xl, xr, xinc;
2293     int byte_out;
2294     int dir, asc, desc;
2295     XCharStruct overall;
2296     int old_cols_in=0, old_rows_in=0;
2297 
2298     /* allocate memory */
2299     item=(RotatedTextItem *)malloc((unsigned)sizeof(RotatedTextItem));
2300     if(!item)
2301 	return NULL;
2302 
2303     /* count number of sections in string */
2304     item->nl=1;
2305     if(align!=NONE)
2306 	for(i=0; i<strlen(text)-1; i++)
2307 	    if(text[i]=='\n')
2308 		item->nl++;
2309 
2310     /* ignore newline characters if not doing alignment */
2311     if(align==NONE)
2312 	str2=str2_a;
2313     else
2314 	str2=str2_b;
2315 
2316     /* find width of longest section */
2317     str1=my_strdup(text);
2318     if(str1==NULL)
2319 	return NULL;
2320 
2321     str3=my_strtok(str1, str2);
2322 
2323     XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
2324 		 &overall);
2325 
2326     item->max_width=overall.rbearing;
2327 
2328     /* loop through each section */
2329     do {
2330 	str3=my_strtok((char *)NULL, str2);
2331 
2332 	if(str3!=NULL) {
2333 	    XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
2334 			 &overall);
2335 
2336 	    if(overall.rbearing>item->max_width)
2337 		item->max_width=overall.rbearing;
2338 	}
2339     }
2340     while(str3!=NULL);
2341 
2342     free(str1);
2343 
2344     /* overall font height */
2345     height=font->ascent+font->descent;
2346 
2347     /* dimensions horizontal text will have */
2348     item->cols_in=item->max_width;
2349     item->rows_in=item->nl*height;
2350 
2351     /* bitmap for drawing on */
2352     canvas=XCreatePixmap(dpy, DefaultRootWindow(dpy),
2353 			 item->cols_in, item->rows_in, 1);
2354 
2355     /* create a GC for the bitmap */
2356     font_gc=XCreateGC(dpy, canvas, NULL, 0);
2357     XSetBackground(dpy, font_gc, 0);
2358     XSetFont(dpy, font_gc, font->fid);
2359 
2360     /* make sure the bitmap is blank */
2361     XSetForeground(dpy, font_gc, 0);
2362     XFillRectangle(dpy, canvas, font_gc, 0, 0,
2363 		   item->cols_in+1, item->rows_in+1);
2364     XSetForeground(dpy, font_gc, 1);
2365 
2366     /* pre-calculate sin and cos */
2367     sin_angle=sin(angle);
2368     cos_angle=cos(angle);
2369 
2370     /* text background will be drawn using XFillPolygon */
2371     item->corners_x=
2372 	(float *)malloc((unsigned)(4*item->nl*sizeof(float)));
2373     if(!item->corners_x)
2374 	return NULL;
2375 
2376     item->corners_y=
2377 	(float *)malloc((unsigned)(4*item->nl*sizeof(float)));
2378     if(!item->corners_y)
2379 	return NULL;
2380 
2381     /* draw text horizontally */
2382 
2383     /* start at top of bitmap */
2384     yp=font->ascent;
2385 
2386     str1=my_strdup(text);
2387     if(str1==NULL)
2388 	return NULL;
2389 
2390     str3=my_strtok(str1, str2);
2391 
2392     /* loop through each section in the string */
2393     do {
2394 	XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
2395 		&overall);
2396 
2397 	/* where to draw section in x ? */
2398 	if(align==TLEFT || align==MLEFT || align==BLEFT || align==NONE)
2399 	    xp=0;
2400 	else if(align==TCENTRE || align==MCENTRE || align==BCENTRE)
2401 	    xp=(item->max_width-overall.rbearing)/2;
2402 	else
2403             xp=item->max_width-overall.rbearing;
2404 
2405 	/* draw string onto bitmap */
2406 	XDrawString(dpy, canvas, font_gc, xp, yp, str3, strlen(str3));
2407 
2408 	/* keep a note of corner positions of this string */
2409 	item->corners_x[ic]=((float)xp-(float)item->cols_in/2)*style.magnify;
2410 	item->corners_y[ic]=((float)(yp-font->ascent)-(float)item->rows_in/2)
2411 	    *style.magnify;
2412 	item->corners_x[ic+1]=item->corners_x[ic];
2413 	item->corners_y[ic+1]=item->corners_y[ic]+(float)height*style.magnify;
2414 	item->corners_x[item->nl*4-1-ic]=item->corners_x[ic]+
2415 	    (float)overall.rbearing*style.magnify;
2416 	item->corners_y[item->nl*4-1-ic]=item->corners_y[ic];
2417 	item->corners_x[item->nl*4-2-ic]=
2418 	    item->corners_x[item->nl*4-1-ic];
2419 	item->corners_y[item->nl*4-2-ic]=item->corners_y[ic+1];
2420 
2421 	ic+=2;
2422 
2423 	/* move to next line */
2424 	yp+=height;
2425 
2426 	str3=my_strtok((char *)NULL, str2);
2427     }
2428     while(str3!=NULL);
2429 
2430     free(str1);
2431 
2432     /* create image to hold horizontal text */
2433     I_in=MakeXImage(dpy, item->cols_in, item->rows_in);
2434     if(I_in==NULL)
2435 	return NULL;
2436 
2437     /* extract horizontal text */
2438     XGetSubImage(dpy, canvas, 0, 0, item->cols_in, item->rows_in,
2439 		 1, XYPixmap, I_in, 0, 0);
2440     I_in->format=XYBitmap;
2441 
2442     /* magnify horizontal text */
2443     if(style.magnify!=1.) {
2444 	I_in=XRotMagnifyImage(dpy, I_in);
2445 
2446 	old_cols_in=item->cols_in;
2447 	old_rows_in=item->rows_in;
2448 	item->cols_in=(float)item->cols_in*style.magnify;
2449 	item->rows_in=(float)item->rows_in*style.magnify;
2450     }
2451 
2452     /* how big will rotated text be ? */
2453     item->cols_out=fabs((float)item->rows_in*sin_angle) +
2454 	fabs((float)item->cols_in*cos_angle) +0.99999 +2;
2455 
2456     item->rows_out=fabs((float)item->rows_in*cos_angle) +
2457 	fabs((float)item->cols_in*sin_angle) +0.99999 +2;
2458 
2459     if(item->cols_out%2==0)
2460 	item->cols_out++;
2461 
2462     if(item->rows_out%2==0)
2463 	item->rows_out++;
2464 
2465     /* create image to hold rotated text */
2466     item->ximage=MakeXImage(dpy, item->cols_out, item->rows_out);
2467     if(item->ximage==NULL)
2468 	return NULL;
2469 
2470     byte_w_in=(item->cols_in-1)/8+1;
2471     byte_w_out=(item->cols_out-1)/8+1;
2472 
2473     /* we try to make this bit as fast as possible - which is why it looks
2474        a bit over-the-top */
2475 
2476     /* vertical distance from centre */
2477     dj=0.5-(float)item->rows_out/2;
2478 
2479     /* where abouts does text actually lie in rotated image? */
2480     if(angle==0 || angle==M_PI/2 ||
2481        angle==M_PI || angle==3*M_PI/2) {
2482 	xl=0;
2483 	xr=(float)item->cols_out;
2484 	xinc=0;
2485     }
2486     else if(angle<M_PI) {
2487 	xl=(float)item->cols_out/2+
2488 	    (dj-(float)item->rows_in/(2*cos_angle))/
2489 		tan(angle)-2;
2490 	xr=(float)item->cols_out/2+
2491 	    (dj+(float)item->rows_in/(2*cos_angle))/
2492 		tan(angle)+2;
2493 	xinc=1./tan(angle);
2494     }
2495     else {
2496 	xl=(float)item->cols_out/2+
2497 	    (dj+(float)item->rows_in/(2*cos_angle))/
2498 		tan(angle)-2;
2499 	xr=(float)item->cols_out/2+
2500 	    (dj-(float)item->rows_in/(2*cos_angle))/
2501 		tan(angle)+2;
2502 
2503 	xinc=1./tan(angle);
2504     }
2505 
2506     /* loop through all relevent bits in rotated image */
2507     for(j=0; j<item->rows_out; j++) {
2508 
2509 	/* no point re-calculating these every pass */
2510 	di=(float)((xl<0)?0:(int)xl)+0.5-(float)item->cols_out/2;
2511 	byte_out=(item->rows_out-j-1)*byte_w_out;
2512 
2513 	/* loop through meaningful columns */
2514 	for(i=((xl<0)?0:(int)xl);
2515 	    i<((xr>=item->cols_out)?item->cols_out:(int)xr); i++) {
2516 
2517 	    /* rotate coordinates */
2518 	    it=(float)item->cols_in/2 + ( di*cos_angle + dj*sin_angle);
2519 	    jt=(float)item->rows_in/2 - (-di*sin_angle + dj*cos_angle);
2520 
2521             /* set pixel if required */
2522             if(it>=0 && it<item->cols_in && jt>=0 && jt<item->rows_in)
2523                 if((I_in->data[jt*byte_w_in+it/8] & 128>>(it%8))>0)
2524                     item->ximage->data[byte_out+i/8]|=128>>i%8;
2525 
2526 	    di+=1;
2527 	}
2528 	dj+=1;
2529 	xl+=xinc;
2530 	xr+=xinc;
2531     }
2532     XDestroyImage(I_in);
2533 
2534     if(style.magnify!=1.) {
2535 	item->cols_in=old_cols_in;
2536 	item->rows_in=old_rows_in;
2537     }
2538 
2539 
2540 #ifdef CACHE_BITMAPS
2541 
2542     /* create a bitmap to hold rotated text */
2543     item->bitmap=XCreatePixmap(dpy, DefaultRootWindow(dpy),
2544 			       item->cols_out, item->rows_out, 1);
2545 
2546     /* make the text bitmap from XImage */
2547     XPutImage(dpy, item->bitmap, font_gc, item->ximage, 0, 0, 0, 0,
2548 	      item->cols_out, item->rows_out);
2549 
2550     XDestroyImage(item->ximage);
2551 
2552 #endif /*CACHE_BITMAPS*/
2553 
2554     XFreeGC(dpy, font_gc);
2555     XFreePixmap(dpy, canvas);
2556 
2557     return item;
2558 }
2559 
2560 
2561 /* ---------------------------------------------------------------------- */
2562 
2563 
2564 /**************************************************************************/
2565 /*  Adds a text item to the end of the cache, removing as many items      */
2566 /*      from the front as required to keep cache size below limit         */
2567 /**************************************************************************/
2568 
XRotAddToLinkedList(Display * dpy,RotatedTextItem * item)2569 static void XRotAddToLinkedList(Display *dpy, RotatedTextItem *item)
2570 {
2571 
2572     static long int current_size=0;
2573     static RotatedTextItem *last=NULL;
2574     RotatedTextItem *i1=first_text_item, *i2=NULL;
2575 
2576 #ifdef CACHE_BITMAPS
2577 
2578     /* I don't know how much memory a pixmap takes in the server -
2579            probably this + a bit more we can't account for */
2580 
2581     item->size=((item->cols_out-1)/8+1)*item->rows_out;
2582 
2583 #else
2584 
2585     /* this is pretty much the size of a RotatedTextItem */
2586 
2587     item->size=((item->cols_out-1)/8+1)*item->rows_out +
2588 	sizeof(XImage) + strlen(item->text) +
2589 	    item->nl*8*sizeof(float) + sizeof(RotatedTextItem);
2590 
2591     if(item->font_name!=NULL)
2592 	item->size+=strlen(item->font_name);
2593     else
2594 	item->size+=sizeof(Font);
2595 
2596 #endif /*CACHE_BITMAPS */
2597 
2598 #ifdef DEBUG
2599     /* count number of items in cache, for debugging */
2600     {
2601 	int i=0;
2602 
2603 	while(i1) {
2604 	    i++;
2605 	    i1=i1->next;
2606 	}
2607 	DEBUG_PRINT2("Cache has %d items.\n", i);
2608 	i1=first_text_item;
2609     }
2610 #endif
2611 
2612     DEBUG_PRINT4("current cache size=%ld, new item=%ld, limit=%ld\n",
2613 		 current_size, item->size, CACHE_SIZE_LIMIT*1024);
2614 
2615     /* if this item is bigger than whole cache, forget it */
2616     if(item->size>CACHE_SIZE_LIMIT*1024) {
2617 	DEBUG_PRINT1("Too big to cache\n\n");
2618 	item->cached=0;
2619 	return;
2620     }
2621 
2622     /* remove elements from cache as needed */
2623     while(i1 && current_size+item->size>CACHE_SIZE_LIMIT*1024) {
2624 
2625 	DEBUG_PRINT2("Removed %d bytes\n", i1->size);
2626 
2627 	if(i1->font_name!=NULL)
2628 	    DEBUG_PRINT5("  (`%s'\n   %s\n   angle=%f align=%d)\n",
2629 			 i1->text, i1->font_name, i1->angle, i1->align);
2630 
2631 #ifdef CACHE_FID
2632 	if(i1->font_name==NULL)
2633 	    DEBUG_PRINT5("  (`%s'\n  FID=%ld\n   angle=%f align=%d)\n",
2634                          i1->text, i1->fid, i1->angle, i1->align);
2635 #endif /*CACHE_FID*/
2636 
2637 	current_size-=i1->size;
2638 
2639 	i2=i1->next;
2640 
2641 	/* free resources used by the unlucky item */
2642 	XRotFreeTextItem(dpy, i1);
2643 
2644 	/* remove it from linked list */
2645 	first_text_item=i2;
2646 	i1=i2;
2647     }
2648 
2649     /* add new item to end of linked list */
2650     if(first_text_item==NULL) {
2651 	item->next=NULL;
2652 	first_text_item=item;
2653 	last=item;
2654     }
2655     else {
2656 	item->next=NULL;
2657 	last->next=item;
2658 	last=item;
2659     }
2660 
2661     /* new cache size */
2662     current_size+=item->size;
2663 
2664     item->cached=1;
2665 
2666     DEBUG_PRINT1("Added item to cache.\n");
2667 }
2668 
2669 
2670 /* ---------------------------------------------------------------------- */
2671 
2672 
2673 /**************************************************************************/
2674 /*  Free the resources used by a text item                                */
2675 /**************************************************************************/
2676 
XRotFreeTextItem(Display * dpy,RotatedTextItem * item)2677 static void XRotFreeTextItem(Display *dpy, RotatedTextItem *item)
2678 {
2679     free(item->text);
2680 
2681     if(item->font_name!=NULL)
2682 	free(item->font_name);
2683 
2684     free((char *)item->corners_x);
2685     free((char *)item->corners_y);
2686 
2687 #ifdef CACHE_BITMAPS
2688     XFreePixmap(dpy, item->bitmap);
2689 #else
2690     XDestroyImage(item->ximage);
2691 #endif /* CACHE_BITMAPS */
2692 
2693     free((char *)item);
2694 }
2695 
2696 
2697 /* ---------------------------------------------------------------------- */
2698 
2699 
2700 /**************************************************************************/
2701 /* Magnify an XImage using bilinear interpolation                         */
2702 /**************************************************************************/
2703 
XRotMagnifyImage(Display * dpy,XImage * ximage)2704 static XImage *XRotMagnifyImage(Display *dpy, XImage *ximage)
2705 {
2706     int i, j;
2707     float x, y;
2708     float u,t;
2709     XImage *I_out;
2710     int cols_in, rows_in;
2711     int cols_out, rows_out;
2712     register int i2, j2;
2713     float z1, z2, z3, z4;
2714     int byte_width_in, byte_width_out;
2715     float mag_inv;
2716 
2717     /* size of input image */
2718     cols_in=ximage->width;
2719     rows_in=ximage->height;
2720 
2721     /* size of final image */
2722     cols_out=(float)cols_in*style.magnify;
2723     rows_out=(float)rows_in*style.magnify;
2724 
2725     /* this will hold final image */
2726     I_out=MakeXImage(dpy, cols_out, rows_out);
2727     if(I_out==NULL)
2728 	return NULL;
2729 
2730     /* width in bytes of input, output images */
2731     byte_width_in=(cols_in-1)/8+1;
2732     byte_width_out=(cols_out-1)/8+1;
2733 
2734     /* for speed */
2735     mag_inv=1./style.magnify;
2736 
2737     y=0.;
2738 
2739     /* loop over magnified image */
2740     for(j2=0; j2<rows_out; j2++) {
2741 	x=0;
2742 	j=y;
2743 
2744 	for(i2=0; i2<cols_out; i2++) {
2745 	    i=x;
2746 
2747 	    /* bilinear interpolation - where are we on bitmap ? */
2748 	    /* right edge */
2749 	    if(i==cols_in-1 && j!=rows_in-1) {
2750 		t=0;
2751 		u=y-(float)j;
2752 
2753 		z1=(ximage->data[j*byte_width_in+i/8] & 128>>(i%8))>0;
2754 		z2=z1;
2755 		z3=(ximage->data[(j+1)*byte_width_in+i/8] & 128>>(i%8))>0;
2756 		z4=z3;
2757 	    }
2758 	    /* top edge */
2759 	    else if(i!=cols_in-1 && j==rows_in-1) {
2760 		t=x-(float)i;
2761 		u=0;
2762 
2763 		z1=(ximage->data[j*byte_width_in+i/8] & 128>>(i%8))>0;
2764 		z2=(ximage->data[j*byte_width_in+(i+1)/8] & 128>>((i+1)%8))>0;
2765 		z3=z2;
2766 		z4=z1;
2767 	    }
2768 	    /* top right corner */
2769 	    else if(i==cols_in-1 && j==rows_in-1) {
2770 		u=0;
2771 		t=0;
2772 
2773 		z1=(ximage->data[j*byte_width_in+i/8] & 128>>(i%8))>0;
2774 		z2=z1;
2775 		z3=z1;
2776 		z4=z1;
2777 	    }
2778 	    /* somewhere `safe' */
2779 	    else {
2780 		t=x-(float)i;
2781 		u=y-(float)j;
2782 
2783 		z1=(ximage->data[j*byte_width_in+i/8] & 128>>(i%8))>0;
2784 		z2=(ximage->data[j*byte_width_in+(i+1)/8] & 128>>((i+1)%8))>0;
2785 		z3=(ximage->data[(j+1)*byte_width_in+(i+1)/8] &
2786 		    128>>((i+1)%8))>0;
2787 		z4=(ximage->data[(j+1)*byte_width_in+i/8] & 128>>(i%8))>0;
2788 	    }
2789 
2790 	    /* if interpolated value is greater than 0.5, set bit */
2791 	    if(((1-t)*(1-u)*z1 + t*(1-u)*z2 + t*u*z3 + (1-t)*u*z4)>0.5)
2792 		I_out->data[j2*byte_width_out+i2/8]|=128>>i2%8;
2793 
2794 	    x+=mag_inv;
2795 	}
2796 	y+=mag_inv;
2797     }
2798 
2799     /* destroy original */
2800     XDestroyImage(ximage);
2801 
2802     /* return big image */
2803     return I_out;
2804 }
2805 
2806 
2807 
2808 /* ---------------------------------------------------------------------- */
2809 
2810 
2811 /**************************************************************************/
2812 /* Calculate the bounding box some text will have when painted            */
2813 /**************************************************************************/
2814 static
XRotTextExtents(Display * dpy,XFontStruct * font,float angle,int x,int y,char * text,int align)2815 XPoint *XRotTextExtents(Display *dpy, XFontStruct *font, float angle, int x, int y, char *text, int align)
2816 {
2817     register int i;
2818     char *str1, *str2, *str3;
2819     char *str2_a="\0", *str2_b="\n\0";
2820     int height;
2821     float sin_angle, cos_angle;
2822     int nl, max_width;
2823     int cols_in, rows_in;
2824     float hot_x, hot_y;
2825     XPoint *xp_in, *xp_out;
2826     int dir, asc, desc;
2827     XCharStruct overall;
2828 
2829     /* manipulate angle to 0<=angle<360 degrees */
2830     while(angle<0)
2831         angle+=360;
2832 
2833     while(angle>360)
2834         angle-=360;
2835 
2836     angle*=M_PI/180;
2837 
2838     /* count number of sections in string */
2839     nl=1;
2840     if(align!=NONE)
2841 	for(i=0; i<strlen(text)-1; i++)
2842 	    if(text[i]=='\n')
2843 		nl++;
2844 
2845     /* ignore newline characters if not doing alignment */
2846     if(align==NONE)
2847 	str2=str2_a;
2848     else
2849 	str2=str2_b;
2850 
2851     /* find width of longest section */
2852     str1=my_strdup(text);
2853     if(str1==NULL)
2854 	return NULL;
2855 
2856     str3=my_strtok(str1, str2);
2857 
2858     XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
2859 		 &overall);
2860 
2861     max_width=overall.rbearing;
2862 
2863     /* loop through each section */
2864     do {
2865 	str3=my_strtok((char *)NULL, str2);
2866 
2867 	if(str3!=NULL) {
2868 	    XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
2869 			 &overall);
2870 
2871 	    if(overall.rbearing>max_width)
2872 		max_width=overall.rbearing;
2873 	}
2874     }
2875     while(str3!=NULL);
2876 
2877     free(str1);
2878 
2879     /* overall font height */
2880     height=font->ascent+font->descent;
2881 
2882     /* dimensions horizontal text will have */
2883     cols_in=max_width;
2884     rows_in=nl*height;
2885 
2886     /* pre-calculate sin and cos */
2887     sin_angle=sin(angle);
2888     cos_angle=cos(angle);
2889 
2890     /* y position */
2891     if(align==TLEFT || align==TCENTRE || align==TRIGHT)
2892         hot_y=(float)rows_in/2*style.magnify;
2893     else if(align==MLEFT || align==MCENTRE || align==MRIGHT)
2894 	hot_y=0;
2895     else if(align==BLEFT || align==BCENTRE || align==BRIGHT)
2896 	hot_y = -(float)rows_in/2*style.magnify;
2897     else
2898 	hot_y = -((float)rows_in/2-(float)font->descent)*style.magnify;
2899 
2900     /* x position */
2901     if(align==TLEFT || align==MLEFT || align==BLEFT || align==NONE)
2902 	hot_x = -(float)max_width/2*style.magnify;
2903     else if(align==TCENTRE || align==MCENTRE || align==BCENTRE)
2904 	hot_x=0;
2905     else
2906         hot_x=(float)max_width/2*style.magnify;
2907 
2908     /* reserve space for XPoints */
2909     xp_in=(XPoint *)malloc((unsigned)(5*sizeof(XPoint)));
2910     if(!xp_in)
2911 	return NULL;
2912 
2913     xp_out=(XPoint *)malloc((unsigned)(5*sizeof(XPoint)));
2914     if(!xp_out)
2915 	return NULL;
2916 
2917     /* bounding box when horizontal, relative to bitmap centre */
2918     xp_in[0].x = -(float)cols_in*style.magnify/2-style.bbx_pad;
2919     xp_in[0].y= (float)rows_in*style.magnify/2+style.bbx_pad;
2920     xp_in[1].x= (float)cols_in*style.magnify/2+style.bbx_pad;
2921     xp_in[1].y= (float)rows_in*style.magnify/2+style.bbx_pad;
2922     xp_in[2].x= (float)cols_in*style.magnify/2+style.bbx_pad;
2923     xp_in[2].y = -(float)rows_in*style.magnify/2-style.bbx_pad;
2924     xp_in[3].x = -(float)cols_in*style.magnify/2-style.bbx_pad;
2925     xp_in[3].y = -(float)rows_in*style.magnify/2-style.bbx_pad;
2926     xp_in[4].x=xp_in[0].x;
2927     xp_in[4].y=xp_in[0].y;
2928 
2929     /* rotate and translate bounding box */
2930     for(i=0; i<5; i++) {
2931 	xp_out[i].x=(float)x + ( ((float)xp_in[i].x-hot_x)*cos_angle +
2932 				 ((float)xp_in[i].y+hot_y)*sin_angle);
2933 	xp_out[i].y=(float)y + (-((float)xp_in[i].x-hot_x)*sin_angle +
2934 				 ((float)xp_in[i].y+hot_y)*cos_angle);
2935     }
2936 
2937     free((char *)xp_in);
2938 
2939     return xp_out;
2940 }
2941 
2942 
2943 
2944 /* ***********************************************************************
2945  * Conversion routines for the X resource manager
2946  * ***********************************************************************
2947  */
2948 
2949 #if defined(__STDC__)
2950 static
strtocard(Display * dsp,XrmValue * args,Cardinal * num_args,XrmValue * from,XrmValue * to,XtPointer * unused)2951 Boolean	strtocard(  Display *dsp,
2952 		    XrmValue *args,
2953 		    Cardinal *num_args,
2954 		    XrmValue *from,
2955 		    XrmValue *to,
2956 		    XtPointer *unused
2957 		    )
2958 #else
2959 static
2960 Boolean	strtocard(  dsp, args, num_args, from, to, unused )
2961 Display *dsp;
2962 XrmValue *args;
2963 Cardinal *num_args;
2964 XrmValue *from;
2965 XrmValue *to;
2966 XtPointer *unused;
2967 #endif
2968 {
2969     static Cardinal temp;
2970 
2971     if ( to->addr == NULL ) {
2972 	to->addr = (XtPointer) &temp;
2973 	to->size = sizeof(Cardinal);
2974     }
2975 
2976     *((Cardinal *) to->addr) = atoi( from->addr );
2977     return True;
2978 }
2979 
2980 
2981 #define done_bert(type, value) \
2982     do {\
2983 	if (to->addr != NULL) {\
2984 	    if (to->size < sizeof(type)) {\
2985 	        to->size = sizeof(type);\
2986 	        return False;\
2987 	    }\
2988 	    *(type*)(to->addr) = (value);\
2989         } else {\
2990 	    static type static_val;\
2991 	    static_val = (value);\
2992 	    to->addr = (XtPointer)&static_val;\
2993         }\
2994         to->size = sizeof(type);\
2995         return True;\
2996     } while (0)
2997 static
cvtStringToStringArray(Display * display,XrmValuePtr args,Cardinal * num_args,XrmValuePtr from,XrmValuePtr to,XtPointer * converter_data)2998 Boolean cvtStringToStringArray(Display *display, XrmValuePtr args, Cardinal *num_args, XrmValuePtr from, XrmValuePtr to, XtPointer *converter_data)
2999 {
3000     String t, s;
3001     StringArray a = NULL;
3002     Cardinal i;
3003     char delim;
3004 
3005     if (*num_args != 0)
3006 	XtAppErrorMsg(XtDisplayToApplicationContext(display),
3007 		      "cvtStringToStringArray", "wrongParameters",
3008 		      "XtToolkitError",
3009 		      "String to StringArray conversion needs no arguments",
3010 		      (String*) NULL, (Cardinal*) NULL);
3011 
3012     delim = ((String) from->addr)[0];
3013     s = XtNewString((String) from->addr + 1);
3014     i = 0;
3015     while (s && *s) {
3016 	t = strchr(s, delim);
3017         if (t) *t = '\0';
3018 	a = (StringArray) XtRealloc((String) a, (i + 1) * sizeof(*a));
3019 	a[i] = s;
3020 	i++;
3021         s = t ? t + 1 : NULL;
3022     }
3023     a = (StringArray) XtRealloc((String) a, (i + 1) * sizeof(*a));
3024     a[i] = NULL;
3025     done_bert(StringArray, a);
3026 }
3027 
3028 
3029 /* ***********************************************************************
3030  * A driver for the above in the flavor of the xt utilities module
3031  * ***********************************************************************
3032  */
3033 
3034 #define TABHT 25
3035 
3036 typedef struct tab_data {
3037     Widget	form;
3038     int		cur,
3039 		num_tabs;
3040     void	(*activate_func)();
3041 } *TabData;
3042 
3043 
3044 #if defined(__STDC__)
handle_click(Widget w,TabData td,XtPointer call_data)3045 static void handle_click( Widget w, TabData td, XtPointer call_data )
3046 #else
3047 static void handle_click(w, td, call_data)
3048     Widget w;
3049     TabData td;
3050     XtPointer call_data;
3051 #endif
3052 {
3053     int tab = (int) call_data;
3054 
3055     /* note that the tab is relative to the current tab.
3056      * if tab is 0, the user clicked on the current one.
3057      * there is nothing to do
3058      */
3059     if (tab == 0) return;
3060     td->cur += tab;
3061 
3062     /* Change tabs.  We must manually inform the UI which tab is current  */
3063     XtVaSetValues( w,
3064 		   XtNlefttabs, td->cur,
3065 		   XtNrighttabs, td->num_tabs - td->cur - 1,
3066 		   NULL
3067 		   );
3068 
3069     (*td->activate_func)( td->form, td->cur );
3070 }
3071 
3072 
3073 /*
3074  * PUBLIC: Widget __vi_CreateTabbedFolder
3075  * PUBLIC:     __P((String, Widget, String, int, void (*)(Widget, int)));
3076  */
3077 #if defined(__STDC__)
__vi_CreateTabbedFolder(String name,Widget parent,String tab_labels,int num_tabs,void (* activate_func)())3078 Widget	__vi_CreateTabbedFolder( String name,
3079 				Widget parent,
3080 				String tab_labels,
3081 				int num_tabs,
3082 				void (*activate_func)()
3083 				)
3084 #else
3085 Widget	__vi_CreateTabbedFolder( name, parent, tab_labels, num_tabs, activate_func )
3086 String	name;
3087 String	tab_labels;
3088 Widget	parent;
3089 int	num_tabs;
3090 void	(*activate_func)();
3091 #endif
3092 {
3093     Widget	tabs;
3094     TabData	td = (TabData) malloc( sizeof(struct tab_data) );
3095     int		i;
3096 
3097     XtAppSetTypeConverter(  XtDisplayToApplicationContext(XtDisplay(parent)),
3098 			    XtRString,
3099 			    XtRCardinal,
3100 			    strtocard,
3101 			    NULL,
3102 			    0,
3103 			    XtCacheNone,
3104 			    NULL
3105 			    );
3106 
3107     /* init our internal structure */
3108     td->cur		= 0;
3109     td->num_tabs	= num_tabs;
3110     td->activate_func	= activate_func;
3111 
3112     /* tabs go on the top */
3113     tabs = XtVaCreateManagedWidget( "tabs",
3114 				     xmTabsWidgetClass,
3115 				     parent,
3116 				     XtNlefttabs,	0,
3117 				     XtNrighttabs,	num_tabs-1,
3118 				     XtNorientation,	XfwfUpTabs,
3119 				     XmNtopAttachment,	XmATTACH_FORM,
3120 				     XmNleftAttachment,	XmATTACH_FORM,
3121 				     XmNleftOffset,	TABHT/4,
3122 				     XmNrightAttachment,XmATTACH_FORM,
3123 				     XmNrightOffset,	TABHT/4,
3124 				     XmNbottomAttachment,XmATTACH_OPPOSITE_FORM,
3125 				     XmNbottomOffset,	-TABHT,
3126 				     XtNlabels,		tab_labels,
3127 				     XtVaTypedArg,	XtNlabels,
3128 							XtRString,
3129 							tab_labels,
3130 							strlen(tab_labels) + 1,
3131 				     NULL
3132 				     );
3133 
3134     /* add the callback */
3135     XtAddCallback( tabs,
3136 		   XtNactivateCallback,
3137 		   (XtCallbackProc) handle_click,
3138 		   td
3139 		   );
3140 
3141     /* another form to hold the controls */
3142     td->form = XtVaCreateWidget( "form",
3143 				 xmFormWidgetClass,
3144 				 parent,
3145 				 XmNtopAttachment,	XmATTACH_WIDGET,
3146 				 XmNtopWidget,		tabs,
3147 				 XmNleftAttachment,	XmATTACH_FORM,
3148 				 XmNbottomAttachment,	XmATTACH_FORM,
3149 				 XmNrightAttachment,	XmATTACH_FORM,
3150 				 NULL
3151 				 );
3152 
3153     /* done */
3154     return td->form;
3155 }
3156