Use C++ linker
[oweals/cde.git] / cde / programs / dtwm / WmGraphics.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* 
24  * (c) Copyright 1989, 1990, 1991, 1992 OPEN SOFTWARE FOUNDATION, INC. 
25  * ALL RIGHTS RESERVED 
26 */ 
27 /* 
28  * Motif Release 1.2
29 */ 
30 #ifdef REV_INFO
31 #ifndef lint
32 static char rcsid[] = "$XConsortium: WmGraphics.c /main/4 1995/11/01 11:38:53 rswiston $"
33 #endif
34 #endif
35 /*
36  * (c) Copyright 1987, 1988, 1989, 1990 HEWLETT-PACKARD COMPANY */
37
38 /*
39  * Included Files:
40  */
41
42 #include "WmGlobal.h"
43
44 #include <stdio.h>
45 #include <X11/Xlib.h>
46 #include <X11/StringDefs.h>
47 #include <X11/Xutil.h>
48 #include <X11/Intrinsic.h>
49 #include <X11/X.h>
50 #include <Xm/Xm.h>
51
52
53 #define RLIST_EXTENSION_SIZE    10
54
55 #ifndef MIN
56 #define MAX(x,y) ((x)>(y)?(x):(y))
57 #endif
58
59 /*
60  * include extern functions
61  */
62 #include "WmGraphics.h"
63 #include "WmError.h"
64
65
66
67 /*
68  * Global Variables:
69  */
70
71
72 /*
73  * Macros:
74  */
75
76 /* test if > 0 and return 1 if true, 0 if false. */
77 #define GE1(x) ((x)>0?1:0)
78
79
80 \f
81 /*************************************<->*************************************
82  *
83  *   Procedure: BevelRectangle (prTop, prBot, x, y, 
84  *                      width, height, top_wid, right_wid, bot_wid, left_wid)
85  *
86  *  Description:
87  *  -----------
88  *  Generate data for top- and bottom-shadow bevels on a box.
89  *
90  *  Inputs:
91  *  ------
92  *  prTop       - ptr to top shadow RList
93  *  prBot       - ptr to bottom shadow RList
94  *  x,y         - position of rectangle to bevel
95  *  width       - (outside) width of rectangle
96  *  height      - (outside) height of rectangle
97  *  top_wid     - width of beveling on top side of rectangle
98  *  right_wid   - width of beveling on right side of rectangle
99  *  bot_wid     - width of beveling on bottom side of rectangle
100  *  left_wid    - width of beveling on left side of rectangle
101  * 
102  *  Outputs:
103  *  -------
104  *  prTop       - top shadows for this rectangle added to list
105  *  prBot       - bottom shadows for this rectangle added to list
106  *  
107  *
108  *  Comments:
109  *  --------
110  *
111  *************************************<->***********************************/
112
113 void BevelRectangle (RList *prTop, RList *prBot, int x, int y, unsigned int width, unsigned int height, unsigned int top_wid, unsigned int right_wid, unsigned int bot_wid, unsigned int left_wid)
114 {
115     XRectangle *prect;          /* pointer to "current" rectangle */
116     register int count;         /* counter used for beveling operation */
117     int join1, join2;           /* used to compute "good" bevel joints */
118     int x1, y1, len;            /* used to compute bevel parameters */
119     int *piTop, *piBot;
120
121
122     /* build the rectangles to implement the beveling on each side */
123
124     /* top side */
125
126     if (((prTop->used + (top_wid + left_wid)) > prTop->allocated) &&
127         (!ExtendRList (prTop, MAX (top_wid+left_wid, RLIST_EXTENSION_SIZE))))
128     {
129         return;         /* not enough memory */
130     }
131
132     piTop = &(prTop->used);
133     prect = &(prTop->prect[*piTop]);
134
135     join1 = left_wid;
136     join2 = right_wid;
137     x1 = x;
138     y1 = y;
139     len = width;
140     for (count=top_wid; count>0; count--, prect++, (*piTop)++) 
141     {
142         prect->x = x1;
143         prect->y = y1;
144         prect->width = len;
145         prect->height = 1;
146         x1 += GE1(--join1);
147         y1 += 1;
148         len -= GE1(join1) + GE1(--join2);
149     }
150
151     /* left side */
152
153     join1 = top_wid;
154     join2 = bot_wid;
155     x1 = x;
156     y1 = y+GE1(join1);
157     len = height-GE1(join1);
158     for (count=left_wid; count >0; count--, prect++, (*piTop)++) 
159     {   
160         prect->x = x1;
161         prect->y = y1;
162         prect->width = 1;
163         prect->height = len;
164         x1 += 1;
165         y1 += GE1(--join1);
166         len -= GE1(join1) + GE1(--join2);
167     }
168
169
170     /* bottom side */
171
172     if (((prBot->used + (bot_wid + right_wid)) > prBot->allocated) &&
173         (!ExtendRList(prBot, MAX (bot_wid+right_wid, RLIST_EXTENSION_SIZE))))
174     {
175         return;
176     }
177
178     piBot = &(prBot->used);
179     prect = &(prBot->prect[*piBot]);
180
181     join1 = left_wid;
182     join2 = right_wid;
183     x1 = x+GE1(join1);
184     y1 = y+height-1;
185     len = width-GE1(join1);
186     /* fudge fat bottom shadow to overwrite corner of skinny left shadow */
187     if (GE1(join1) && (bot_wid > left_wid)) {
188         len++;
189         x1--;
190         join1++;
191     }
192     for (count=bot_wid; count >0; count--, prect++, (*piBot)++) 
193     {
194         prect->x = x1;
195         prect->y = y1;
196         prect->width = len;
197         prect->height = 1;
198         x1 += GE1(--join1);
199         y1 -= 1;
200         len -= GE1(join1) + GE1(--join2);
201     }
202
203     /* right side */
204
205     join1 = top_wid;
206     join2 = bot_wid;
207     x1 = x+width-1;
208     y1 = y+GE1(join1);
209     len = height - GE1(join1) - GE1(join2);
210     /* fudge fat right shadow to overwrite corner of skinny top shadow */
211     if (GE1(join1) && (right_wid > top_wid)) {
212         len++;
213         y1--;
214         join1++;
215     }
216     for (count=right_wid; count >0; count--, prect++, (*piBot)++) 
217     {
218         prect->x = x1;
219         prect->y = y1;
220         prect->width = 1;
221         prect->height = len;
222         x1 -= 1;
223         y1 += GE1(--join1);
224         len -= GE1(join1) + GE1(--join2);
225     }
226
227 } /* END OF FUNCTION BevelRectangle */
228
229
230
231 \f
232 /*************************************<->*************************************
233  *
234  *   Procedure: BevelDepressedRectangle (prTop, prBot, x, y, 
235  *                      width, height, top_wid, right_wid, bot_wid, left_wid
236  *                      in_wid)
237  *
238  *  Description:
239  *  -----------
240  *  Generate data for top- and bottom-shadow bevels on a rectangle with
241  *  the center part depressed.
242  *
243  *  Inputs:
244  *  ------
245  *  prTop       - ptr to top shadow RList
246  *  prBot       - ptr to bottom shadow RList
247  *  x,y         - position of rectangle to bevel
248  *  width       - (outside) width of rectangle
249  *  height      - (outside) height of rectangle
250  *  top_wid     - width of beveling on top side of rectangle
251  *  right_wid   - width of beveling on right side of rectangle
252  *  bot_wid     - width of beveling on bottom side of rectangle
253  *  left_wid    - width of beveling on left side of rectangle
254  *  in_wid      - width of depressed beveling inside of rectangle
255  * 
256  *  Outputs:
257  *  -------
258  *  prTop       - top shadows for this rectangle added to list
259  *  prBot       - bottom shadows for this rectangle added to list
260  *  
261  *
262  *  Comments:
263  *  --------
264  *
265  *************************************<->***********************************/
266
267 void BevelDepressedRectangle (RList *prTop, RList *prBot, int x, int y, unsigned int width, unsigned int height, unsigned int top_wid, unsigned int right_wid, unsigned int bot_wid, unsigned int left_wid, unsigned int in_wid)
268 {
269     XRectangle *prect;          /* pointer to "current" rectangle */
270     register int count;         /* counter used for beveling operation */
271     int join1, join2;           /* used to compute "good" bevel joints */
272     int x1, y1, len;            /* used to compute bevel parameters */
273     int *piTop, *piBot;
274
275
276     /* 
277      *  Build the rectangles to implement the beveling on each side 
278      *  First, guarantee that there is enough memory.
279      */
280
281
282     if (((prTop->used + (top_wid + left_wid)) > prTop->allocated) &&
283         (!ExtendRList (prTop, MAX (top_wid+left_wid, RLIST_EXTENSION_SIZE))))
284     {
285         return;         /* not enough memory */
286     }
287
288     if (((prBot->used + (bot_wid + right_wid)) > prBot->allocated) &&
289         (!ExtendRList(prBot, MAX (bot_wid+right_wid, RLIST_EXTENSION_SIZE))))
290     {
291         return;         /* not enought memory */
292     }
293
294
295
296     /* top side (normal beveling) */
297
298     piTop = &(prTop->used);
299     prect = &(prTop->prect[*piTop]);
300
301     join1 = left_wid;
302     join2 = right_wid;
303     x1 = x;
304     y1 = y;
305     len = width;
306     for (count=top_wid - in_wid; count>0; count--, prect++, (*piTop)++) 
307     {
308         prect->x = x1;
309         prect->y = y1;
310         prect->width = len;
311         prect->height = 1;
312         x1 += GE1(--join1);
313         y1 += 1;
314         len -= GE1(join1) + GE1(--join2);
315     }
316
317     /* top side (inverted beveling) */
318
319     piBot = &(prBot->used);
320     prect = &(prBot->prect[*piBot]);
321
322     for (count=in_wid; count>0; count--, prect++, (*piBot)++) 
323     {
324         prect->x = x1;
325         prect->y = y1;
326         prect->width = len;
327         prect->height = 1;
328         x1 += GE1(--join1);
329         y1 += 1;
330         len -= GE1(join1) + GE1(--join2);
331     }
332
333
334
335     /* left side (normal beveling) */
336
337     piTop = &(prTop->used);
338     prect = &(prTop->prect[*piTop]);
339
340     join1 = top_wid;
341     join2 = bot_wid;
342     x1 = x;
343     y1 = y+GE1(join1);
344     len = height-GE1(join1);
345     for (count=left_wid-in_wid; count >0; count--, prect++, (*piTop)++) 
346     {   
347         prect->x = x1;
348         prect->y = y1;
349         prect->width = 1;
350         prect->height = len;
351         x1 += 1;
352         y1 += GE1(--join1);
353         len -= GE1(join1) + GE1(--join2);
354     }
355
356     /* left side (inverted beveling) */
357
358     piBot = &(prBot->used);
359     prect = &(prBot->prect[*piBot]);
360
361     for (count=in_wid; count >0; count--, prect++, (*piBot)++) 
362     {   
363         prect->x = x1;
364         prect->y = y1;
365         prect->width = 1;
366         prect->height = len;
367         x1 += 1;
368         y1 += GE1(--join1);
369         len -= GE1(join1) + GE1(--join2);
370     }
371
372
373
374     /* bottom side (normal beveling) */
375
376     piBot = &(prBot->used);
377     prect = &(prBot->prect[*piBot]);
378
379     join1 = left_wid;
380     join2 = right_wid;
381     x1 = x+GE1(join1);
382     y1 = y+height-1;
383     len = width-GE1(join1);
384     /* fudge fat bottom shadow to overwrite corner of skinny left shadow */
385     if (GE1(join1) && (bot_wid > left_wid)) {
386         len++;
387         x1--;
388         join1++;
389     }
390     for (count=bot_wid-in_wid; count >0; count--, prect++, (*piBot)++) 
391     {
392         prect->x = x1;
393         prect->y = y1;
394         prect->width = len;
395         prect->height = 1;
396         x1 += GE1(--join1);
397         y1 -= 1;
398         len -= GE1(join1) + GE1(--join2);
399     }
400
401     /* bottom side (inverted beveling) */
402
403     piTop = &(prTop->used);
404     prect = &(prTop->prect[*piTop]);
405
406     for (count=in_wid; count >0; count--, prect++, (*piTop)++) 
407     {
408         prect->x = x1;
409         prect->y = y1;
410         prect->width = len;
411         prect->height = 1;
412         x1 += GE1(--join1);
413         y1 -= 1;
414         len -= GE1(join1) + GE1(--join2);
415     }
416
417
418
419     /* right side (normal beveling) */
420
421     piBot = &(prBot->used);
422     prect = &(prBot->prect[*piBot]);
423
424     join1 = top_wid;
425     join2 = bot_wid;
426     x1 = x+width-1;
427     y1 = y+GE1(join1);
428     len = height - GE1(join1) - GE1(join2);
429     /* fudge fat right shadow to overwrite corner of skinny top shadow */
430     if (GE1(join1) && (right_wid > top_wid)) {
431         len++;
432         y1--;
433         join1++;
434     }
435     for (count=right_wid-in_wid; count >0; count--, prect++, (*piBot)++) 
436     {
437         prect->x = x1;
438         prect->y = y1;
439         prect->width = 1;
440         prect->height = len;
441         x1 -= 1;
442         y1 += GE1(--join1);
443         len -= GE1(join1) + GE1(--join2);
444     }
445
446     /* right side (inverted beveling) */
447
448     piTop = &(prTop->used);
449     prect = &(prTop->prect[*piTop]);
450
451     for (count=in_wid; count >0; count--, prect++, (*piTop)++) 
452     {
453         prect->x = x1;
454         prect->y = y1;
455         prect->width = 1;
456         prect->height = len;
457         x1 -= 1;
458         y1 += GE1(--join1);
459         len -= GE1(join1) + GE1(--join2);
460     }
461
462 } /* END OF FUNCTION BevelDepressedRectangle */
463
464
465
466 \f
467 /*************************************<->*************************************
468  *
469  *   Procedure: StretcherCorner (prTop, prBot, x, y, cnum, 
470  *                               swidth,  cwidth, cheight);
471  *
472  *  Description:
473  *  -----------
474  *  Generate data to draw a corner of the stretcher border.
475  *
476  *  Inputs:
477  *  ------
478  *  prTop       - ptr to top shadow RList
479  *  prBot       - ptr to bottom shadow RList
480  *  x,y         - position of rectangle enclosing the cornern
481  *  cnum        - corner number; which corner to draw
482  *                ASSUMES only NW, NE, SE, SW for mwm ()
483  *  swidth      - width (thickness) of border (includes bevels)
484  *  cwidth      - corner width from corner to end of horizontal run
485  *  cheight     - corner height from corner to end of vertical run
486  * 
487  *  Outputs:
488  *  -------
489  *  prTop       - array filled in for top shadows 
490  *  prBot       - array filledin for bottom shadows
491  *
492  *  Comments:
493  *  --------
494  *  o Uses only 1 pixel bevels. Beveling is hard coded.
495  *  o XFillRectangles assumed as an optimization to take
496  *    advantage of the block mover hardware.
497  *
498  *************************************<->***********************************/
499
500 void StretcherCorner (RList *prTop, RList *prBot, int x, int y, int cnum, unsigned int swidth, unsigned int cwidth, unsigned int cheight)
501 {
502     XRectangle *prect;          /* pointer to "current" rectangle */
503     int *piTop, *piBot;
504
505     switch (cnum) {
506
507         case STRETCH_NORTH_WEST:
508                 if (((prTop->used + 4) > prTop->allocated) &&
509                     (!ExtendRList (prTop, (unsigned int) RLIST_EXTENSION_SIZE)))
510                 {
511                     return;
512                 }
513
514                 piTop = &(prTop->used);
515                 prect = &(prTop->prect[*piTop]);
516
517                 prect->x = x;                   /* top (row 1) */
518                 prect->y = y;
519                 prect->width = cwidth;
520                 prect->height = 1;
521                 prect++;
522                 (*piTop)++;
523
524                 prect->x = x+1;                 /* top (row 2) */
525                 prect->y = y+1;
526                 prect->width = cwidth-2;
527                 prect->height = 1;
528                 prect++;
529                 (*piTop)++;
530
531                 prect->x = x;                   /* left (col 1) */
532                 prect->y = y+1;
533                 prect->width = 1;
534                 prect->height = cheight-1;
535                 prect++;
536                 (*piTop)++;
537
538                 prect->x = x+1;                 /* left (col 2) */
539                 prect->y = y+2;
540                 prect->width = 1;
541                 prect->height = cheight-3;
542                 (*piTop)++;
543
544                 if (((prBot->used + 4) > prBot->allocated) &&
545                     (!ExtendRList (prBot, (unsigned int) RLIST_EXTENSION_SIZE)))
546                 {
547                     return;
548                 }
549
550                 piBot = &(prBot->used);
551                 prect = &(prBot->prect[*piBot]); /* bottom shadow parts */
552
553
554                 prect->x = x+1;                 /* bottom end */
555                 prect->y = y+cheight-1;
556                 prect->width = swidth-1;
557                 prect->height = 1;
558                 prect++;
559                 (*piBot)++;
560
561                 if (wmGD.frameStyle == WmRECESSED)
562                 {
563                     prect->x = x+swidth-1;              /* right inside */
564                     prect->y = y+swidth-1;
565                     prect->width = 1;
566                     prect->height = cheight-swidth;
567                     prect++;
568                     (*piBot)++;
569
570                     prect->x = x+swidth;                /* bottom inside */
571                     prect->y = y+swidth-1;
572                     prect->width = cwidth-swidth;
573                     prect->height = 1;
574                     prect++;
575                     (*piBot)++;
576                 }
577
578                 prect->x = x+cwidth-1;          /* right end */
579                 prect->y = y+1;
580                 prect->width = 1;
581                 prect->height = swidth-1-((wmGD.frameStyle == WmSLAB)? 0 : 1);
582                 (*piBot)++;
583
584                 break;
585
586         case STRETCH_NORTH_EAST:
587                 if (((prTop->used + 4) > prTop->allocated) &&
588                     (!ExtendRList (prTop, (unsigned int) RLIST_EXTENSION_SIZE)))
589                 {
590                     return;
591                 }
592
593                 piTop = &(prTop->used);
594                 prect = &(prTop->prect[*piTop]);
595
596                 prect->x = x;                   /* top (row 1) */
597                 prect->y = y;
598                 prect->width = cwidth;
599                 prect->height = 1;
600                 prect++;
601                 (*piTop)++;
602
603                 prect->x = x+1;                 /* top (row 2) */
604                 prect->y = y+1;
605                 prect->width = cwidth-2;
606                 prect->height = 1;
607                 prect++;
608                 (*piTop)++;
609
610                 prect->x = x;                   /* left end */
611                 prect->y = y+1;
612                 prect->width = 1;
613                 prect->height = swidth-1;
614                 prect++;
615                 (*piTop)++;
616
617                 if (wmGD.frameStyle == WmRECESSED)
618                 {
619                     prect->x = x+cwidth-swidth; /* left inside (col 1) */
620                     prect->y = y+swidth;
621                     prect->width = 1;
622                     prect->height = cheight-swidth;
623                     (*piTop)++;
624                 }
625
626                 if (((prBot->used + 4) > prBot->allocated) &&
627                     (!ExtendRList (prBot, (unsigned int) RLIST_EXTENSION_SIZE)))
628                 {
629                     return;
630                 }
631
632                 piBot = &(prBot->used);
633                 prect = &(prBot->prect[*piBot]); /* bottom shadow parts */
634
635
636                 /* bottom end */
637                 prect->x = x+cwidth-swidth+((wmGD.frameStyle == WmSLAB)? 0 : 1);
638                 prect->y = y+cheight-1;
639                 prect->width = swidth-((wmGD.frameStyle == WmSLAB)? 0 : 1);
640                 prect->height = 1;
641                 prect++;
642                 (*piBot)++;
643
644                 prect->x = x+cwidth-1;          /* right (col 2) */
645                 prect->y = y+1;
646                 prect->width = 1;
647                 prect->height = cheight-2;
648                 prect++;
649                 (*piBot)++;
650
651                 prect->x = x+cwidth-2;          /* right (col 1) */
652                 prect->y = y+2;
653                 prect->width = 1;
654                 prect->height = cheight-3;
655                 prect++;
656                 (*piBot)++;
657
658                 if (wmGD.frameStyle == WmRECESSED)
659                 {
660                     prect->x = x+1;             /* bottom inside (row 2) */
661                     prect->y = y+swidth-1;
662                     prect->width = cwidth-swidth;
663                     prect->height = 1;
664                     (*piBot)++;
665                 }
666
667                 break;
668
669         case STRETCH_SOUTH_EAST:
670                 if (((prTop->used + 4) > prTop->allocated) &&
671                     (!ExtendRList (prTop, (unsigned int) RLIST_EXTENSION_SIZE)))
672                 {
673                     return;
674                 }
675
676                 piTop = &(prTop->used);
677                 prect = &(prTop->prect[*piTop]);
678
679                 if (wmGD.frameStyle == WmRECESSED)
680                 {
681                     prect->x = x;                       /* top inside */
682                     prect->y = y+cheight-swidth;
683                     prect->width = cwidth-swidth+1;
684                     prect->height = 1;
685                     prect++;
686                     (*piTop)++;
687
688                     prect->x = x+cwidth-swidth; /* left inside */
689                     prect->y = y;
690                     prect->width = 1;
691                     prect->height = cheight-swidth;
692                     prect++;
693                     (*piTop)++;
694                 }
695
696                 /* top end */
697                 prect->x = x+cwidth-swidth+
698                                 ((wmGD.frameStyle == WmSLAB)? 0 : 1);
699                 prect->y = y;
700                 prect->width = swidth-2+((wmGD.frameStyle == WmSLAB)? 1 : 0);;
701                 prect->height = 1;
702                 prect++;
703                 (*piTop)++;
704
705                 prect->x = x;                   /* left end */
706                 prect->y = y+cheight-swidth+
707                                 ((wmGD.frameStyle == WmSLAB)? 0 : 1);
708                 prect->width = 1;
709                 prect->height = swidth-2+((wmGD.frameStyle == WmSLAB)? 1 : 0);
710                 (*piTop)++;
711
712                 if (((prBot->used + 4) > prBot->allocated) &&
713                     (!ExtendRList (prBot, (unsigned int) RLIST_EXTENSION_SIZE)))
714                 {
715                     return;
716                 }
717
718                 piBot = &(prBot->used);
719                 prect = &(prBot->prect[*piBot]); /* bottom shadow parts */
720
721
722                 prect->x = x+1;                 /* bottom - row 1 */
723                 prect->y = y+cheight-2;
724                 prect->width = cwidth-1;
725                 prect->height = 1;
726                 prect++;
727                 (*piBot)++;
728
729                 prect->x = x;                   /* bottom - row 2 */
730                 prect->y = y+cheight-1;
731                 prect->width = cwidth;
732                 prect->height = 1;
733                 prect++;
734                 (*piBot)++;
735
736                 prect->x = x+cwidth-2;          /* right  - column 1 */
737                 prect->y = y+1;
738                 prect->width = 1;
739                 prect->height = cheight-3;
740                 prect++;
741                 (*piBot)++;
742
743                 prect->x = x+cwidth-1;          /* right  - column 2 */
744                 prect->y = y;
745                 prect->width = 1;
746                 prect->height = cheight-2;
747                 (*piBot)++;
748
749                 break;
750
751         case STRETCH_SOUTH_WEST:
752                 if (((prTop->used + 4) > prTop->allocated) &&
753                     (!ExtendRList (prTop, (unsigned int) RLIST_EXTENSION_SIZE)))
754                 {
755                     return;
756                 }
757
758                 piTop = &(prTop->used);
759                 prect = &(prTop->prect[*piTop]);
760
761                 prect->x = x;                   /* top end */
762                 prect->y = y;
763                 prect->width = swidth;
764                 prect->height = 1;
765                 prect++;
766                 (*piTop)++;
767
768                 prect->x = x;                   /* left (col 1) */
769                 prect->y = y+1;
770                 prect->width = 1;
771                 prect->height = cheight-1;
772                 prect++;
773                 (*piTop)++;
774
775                 prect->x = x+1;                 /* left (col 2) */
776                 prect->y = y+1;
777                 prect->width = 1;
778                 prect->height = cheight-2;
779                 prect++;
780                 (*piTop)++;
781
782                 if (wmGD.frameStyle == WmRECESSED)
783                 {
784                     prect->x = x+swidth;                /* top inside (row 2) */
785                     prect->y = y+cheight-swidth;
786                     prect->width = cwidth-swidth;
787                     prect->height = 1;
788                     (*piTop)++;
789                 }
790
791                 if (((prBot->used + 4) > prBot->allocated) &&
792                     (!ExtendRList (prBot, (unsigned int) RLIST_EXTENSION_SIZE)))
793                 {
794                     return;
795                 }
796
797                 piBot = &(prBot->used);
798                 prect = &(prBot->prect[*piBot]); /* bottom shadow parts */
799
800
801                 if (wmGD.frameStyle == WmRECESSED)
802                 {
803                     prect->x = x+swidth-1;      /* right inside (col 2) */
804                     prect->y = y+1;
805                     prect->width = 1;
806                     prect->height = cheight-swidth;
807                     prect++;
808                     (*piBot)++;
809                 }
810
811                 prect->x = x+cwidth-1;          /* right end */
812                 prect->y = y+cheight-swidth+
813                                 ((wmGD.frameStyle == WmSLAB)? 0 : 1);
814                 prect->width = 1;
815                 prect->height = swidth-((wmGD.frameStyle == WmSLAB)? 0 : 1);
816                 prect++;
817                 (*piBot)++;
818
819                 prect->x = x+2;                 /* bottom (row 1) */
820                 prect->y = y+cheight-2;
821                 prect->width = cwidth-3;
822                 prect->height = 1;
823                 prect++;
824                 (*piBot)++;
825
826                 prect->x = x+1;                 /* bottom (row 2) */
827                 prect->y = y+cheight-1;
828                 prect->width = cwidth-2;
829                 prect->height = 1;
830                 (*piBot)++;
831
832                 break;
833     }
834 } /* END OF FUNCTION StretcherCorner */
835
836
837 \f
838 /*************************************<->*************************************
839  *
840  *  DrawStringInBox (dpy, win, gc, pbox, str)
841  *
842  *
843  *  Description:
844  *  -----------
845  *  Draws a null-terminated string inside the specified box (rectangle)
846  *
847  *
848  *  Inputs:
849  *  ------
850  *  dpy         - ptr to Display
851  *  win         - an X Window
852  *  gc          - graphics context to use
853  *  pfs         - pointer to XFontStruct for the font in "gc"
854  *  pbox        - ptr to XRectangle that encloses text
855  *  str         - String to write
856  * 
857  *  Outputs:
858  *  -------
859  *  none
860  *
861  *  Comments:
862  *  --------
863  *  o Assumes 8-bit text for now.
864  *  o Algorithm:  
865  *                      get length of String
866  *                      if String is short than box width then
867  *                          draw string centered in box
868  *                      otherwise
869  *                          draw string left justified and clipped to box
870  *  o The clip_x_origin, clip_y_origin, and clip_mask are reset to None
871  *    upon exit.
872  *  o Due to bugs and / or misunderstanding, I gave up on trying to 
873  *    extract the XFontStruct from the GC. I just made it a separate 
874  *    parameter.
875  *                      
876  *************************************<->***********************************/
877 void DrawStringInBox (Display *dpy, Window win, GC gc, XFontStruct *pfs, XRectangle *pbox, String str)
878 {
879     XGCValues gcv;
880     int textWidth;
881     int xCenter;
882     XRectangle clipBox;
883
884     /* compute text position */
885     textWidth = XTextWidth(pfs, str, strlen(str));
886
887     if (textWidth < (int) pbox->width) {        /* center text if there's room */
888         xCenter = (int) pbox->x + ((int) pbox->width - textWidth) / 2 ;
889         WmDrawString(dpy, win, gc, xCenter, (pbox->y + pfs->ascent), 
890                     str, strlen(str));
891     }
892     else {                              /* left justify & clip text */
893         clipBox.x = 0;                  /* set up clip rectangle */
894         clipBox.y = 0;
895         clipBox.width = pbox->width;
896         clipBox.height = pbox->height;
897
898         XSetClipRectangles (dpy, gc, pbox->x, pbox->y,  /* put into gc */
899                             &clipBox, 1, Unsorted);
900
901         WmDrawString(dpy, win, gc, pbox->x, (pbox->y + pfs->ascent), 
902                     str, strlen(str));
903
904         gcv.clip_x_origin = 0;          /* erase clip_mask from gc */
905         gcv.clip_y_origin = 0;
906         gcv.clip_mask = None;
907         XChangeGC (dpy, gc, 
908                    GCClipXOrigin | GCClipYOrigin | GCClipMask, &gcv);
909     }
910 } /* END OF FUNCTION DrawStringInBox */
911
912
913
914 \f
915 /*************************************<->*************************************
916  *
917  *  ExtendRList (prl, amt)
918  *
919  *
920  *  Description:
921  *  -----------
922  *  Extends the size of the RList
923  *
924  *
925  *  Inputs:
926  *  ------
927  *  prl         - ptr to Display
928  *  amt         - how much to extend it by
929  * 
930  *  Outputs:
931  *  -------
932  *  Returns True if succeeded, false otherwise.
933  *
934  *  Comments:
935  *  --------
936  *                      
937  *************************************<->***********************************/
938 Boolean ExtendRList (RList *prl, unsigned int amt)
939 {
940     unsigned int total, count;
941     XRectangle *pNewRect;
942     Boolean rval;
943
944
945     total = prl->allocated + amt;
946     if ( (pNewRect = (XRectangle *) XtMalloc (total * sizeof(XRectangle))) 
947          == NULL)
948     {
949         Warning (((char *)GETMESSAGE(28, 1, "Insufficient memory for graphics data")));
950         rval = False;
951     }
952     else 
953     {
954         prl->allocated = total;
955         rval = True;
956
957         if (prl->used != 0) {           /* copy from old structure */
958             count = prl->used * sizeof(XRectangle);
959             (void) memcpy ((void *)pNewRect, (void *)prl->prect, count);
960             if (prl->prect != NULL)
961                 XtFree ((char *)prl->prect);
962             prl->prect = pNewRect;
963         }
964     }
965     return (rval);
966 } /* END OF FUNCTION ExtendRList */
967
968
969 \f
970 /*************************************<->*************************************
971  *
972  *  AllocateRList (amt)
973  *
974  *
975  *  Description:
976  *  -----------
977  *  Allocates an RList of size "amt"
978  *
979  *
980  *  Inputs:
981  *  ------
982  *  amt         - number of XRectangles to allocate in list
983  * 
984  *  Outputs:
985  *  -------
986  *  Returns ptr to new RList structure if success, returns NULL ptr otherwise
987  *
988  *  Comments:
989  *  --------
990  *                      
991  *************************************<->***********************************/
992 RList *AllocateRList (amt)
993
994     unsigned int amt;
995 {
996     RList *prl;
997
998
999     if ((prl = (RList *) XtMalloc (sizeof (RList))) != NULL) 
1000     {
1001         if ( (prl->prect = (XRectangle *) XtMalloc (amt * sizeof(XRectangle))) 
1002              == NULL)
1003         {
1004             XtFree ((char *)prl);
1005             prl = NULL;
1006         }
1007         else 
1008         {
1009             prl->allocated = amt;
1010             prl->used = 0;
1011
1012         }
1013     }
1014
1015     return (prl);
1016 } /* END OF FUNCTION AllocateRList */
1017
1018
1019 \f
1020 /*************************************<->*************************************
1021  *
1022  *  FreeRList (prl)
1023  *
1024  *
1025  *  Description:
1026  *  -----------
1027  *  Frees an RList
1028  *
1029  *
1030  *  Inputs:
1031  *  ------
1032  *  prl         - ptr to RList to free
1033  * 
1034  *  Outputs:
1035  *  -------
1036  *
1037  *  Comments:
1038  *  --------
1039  *                      
1040  *************************************<->***********************************/
1041 void FreeRList (RList *prl)
1042 {
1043     if (prl) 
1044     {
1045         if (prl->prect) 
1046             XtFree ((char *)prl->prect);
1047
1048         XtFree ((char *)prl);
1049     }
1050 }/* END OF FUNCTION FreeRList */
1051
1052 \f
1053 /*************************************<->*************************************
1054  *
1055  *  WmDrawString
1056  *
1057  *
1058  *  Description:
1059  *  -----------
1060  *  Draws a string
1061  *
1062  *
1063  *  Inputs:
1064  *  ------
1065  *  (same parameters used by XDrawString and XDrawImageString)
1066  * 
1067  *  Outputs:
1068  *  -------
1069  *
1070  *  Comments:
1071  *  --------
1072  *  o If wmGD.cleanText is True, then the text is drawn using 
1073  *    XDrawImageString. This provides some clean space around the text
1074  *    if the background area is stippled -- especially useful on 
1075  *    B/W displays.
1076  *                      
1077  *************************************<->***********************************/
1078 void WmDrawString (Display *dpy, Drawable d, GC gc, int x, int y, char *string, unsigned int length)
1079 {
1080     if (ACTIVE_PSD->cleanText)
1081     {
1082         XDrawImageString(dpy, d, gc, x, y, string, length);
1083     }
1084     else
1085     {
1086         XDrawString(dpy, d, gc, x, y, string, length);
1087     }
1088
1089 }/* END OF FUNCTION WmDrawString */
1090
1091
1092 \f
1093 /*************************************<->*************************************
1094  *
1095  *  WmXmDrawString
1096  *
1097  *
1098  *  Description:
1099  *  -----------
1100  *  Draws a string
1101  *
1102  *
1103  *  Inputs:
1104  *  ------
1105  *  (subset of parameters used by XmStringDraw and XmStringDrawImage)
1106  * 
1107  *  Outputs:
1108  *  -------
1109  *
1110  *  Comments:
1111  *  --------
1112  *  o If wmGD.cleanText is True, then the text is drawn using 
1113  *    XmStringDrawImage. This provides some clean space around the text
1114  *    if the background area is stippled -- especially useful on 
1115  *    B/W displays.
1116  *                      
1117  *************************************<->***********************************/
1118 #ifdef WSM
1119 void WmDrawXmString (Display *dpy, Window w, XmFontList xmfontlist, 
1120                      XmString xmstring, GC gc, Position x, Position y, 
1121                      Dimension width,  XRectangle *pbox, Boolean bCenter)
1122 #else /* WSM */
1123 void WmDrawXmString (Display *dpy, Window w, XmFontList xmfontlist, 
1124                      XmString xmstring, GC gc, Position x, Position y, 
1125                      Dimension width,  XRectangle *pbox)
1126 #endif /* WSM */
1127 {
1128     Dimension textWidth;
1129 #ifdef WSM
1130     int alignment;
1131 #else /* WSM */
1132     int alignment = XmALIGNMENT_BEGINNING;
1133 #endif /* WSM */
1134     
1135
1136     textWidth = XmStringWidth(xmfontlist, xmstring);
1137
1138 #ifdef WSM
1139     alignment = bCenter ? XmALIGNMENT_CENTER : XmALIGNMENT_BEGINNING;
1140
1141     if (textWidth >= pbox->width)  /* can't center text if no room */
1142     {                              /* left justify & clip text */
1143         alignment = XmALIGNMENT_BEGINNING;
1144     }
1145 #else /* WSM */
1146     if (textWidth < pbox->width) {      /* center text if there's room */
1147         alignment = XmALIGNMENT_CENTER;
1148     }
1149     else 
1150     {                              /* left justify & clip text */
1151         alignment = XmALIGNMENT_BEGINNING;
1152     }
1153 #endif /* WSM */
1154     
1155     if (ACTIVE_PSD->cleanText)
1156     {
1157         XmStringDrawImage(dpy, w, xmfontlist, xmstring, gc, x, y, width, 
1158                           alignment, XmSTRING_DIRECTION_L_TO_R, 
1159                           pbox);
1160     }
1161     else
1162     {
1163         XmStringDraw (dpy, w, xmfontlist, xmstring, gc, x, y, width, 
1164                       alignment, XmSTRING_DIRECTION_L_TO_R, pbox);
1165     }
1166 } /* END OF FUNCTION WmDrawXmString */
1167
1168 #ifdef WSM
1169 \f
1170 /*************************************<->*************************************
1171  *
1172  *  WmInstallBitmapIntoXmCache (pchName, bitmap, width, height)
1173  *
1174  *
1175  *  Description:
1176  *  -----------
1177  *  Installs all or part of a pixmap into the Xm cache. This pixmap
1178  *  may be retrieved later by a call to XmGetPixmap.
1179  *
1180  *  Inputs:
1181  *  ------
1182  *  pchName     = pointer to name of bitmap 
1183  *  bitmap      = depth-1 pixmap
1184  *  width       = width of portion to install
1185  *  height      = height of portion to install
1186  * 
1187  *  Outputs:
1188  *  -------
1189  *  none
1190  *
1191  *  Comments:
1192  *  --------
1193  *  This always installs the Northwest corner of the passed in bitmap.
1194  *  If the width and height match the size of the bitmap, then the
1195  *  whole thing is installed in the cache.
1196  *                      
1197  *************************************<->***********************************/
1198 void WmInstallBitmapIntoXmCache (unsigned char *pchName,
1199     Pixmap bitmap, unsigned int width, unsigned int height)
1200 {
1201     XImage *pImage;
1202
1203     pImage = XGetImage (DISPLAY, bitmap, 0, 0, width, height, 1L, XYBitmap);
1204
1205     XmInstallImage (pImage, (char *)pchName);
1206 } /* END OF FUNCTION WmInstallBitmapIntoXmCache */
1207
1208
1209 \f
1210 /*************************************<->*************************************
1211  *
1212  *  WmInstallBitmapDataIntoXmCache (pSD, pchName, pData)
1213  *
1214  *
1215  *  Description:
1216  *  -----------
1217  *  Installs built-in bitmap data into the Xm Pixmap cache. The image
1218  *  may be retrieved later by a call to XmGetPixmap.
1219  *
1220  *  Inputs:
1221  *  ------
1222  *  pSD         = pointer to screen data
1223  *  pchName     = pointer to name of bitmap 
1224  *  pData       = pointer to the bitmap data
1225  * 
1226  *  Outputs:
1227  *  -------
1228  *  none
1229  *
1230  *  Comments:
1231  *  --------
1232  *  This is principally for putting built-in pixmap data into the Xm
1233  *  cache to allow for uniform access to pixmap creation.
1234  *
1235  *  ***WARNING***
1236  *  Do NOT call XmDestroyPixmap on images cached via this routine unless
1237  *  pData passed in points to malloc'ed memory. XmDestroyPixmap could 
1238  *  try to free this data.
1239  *                      
1240  *************************************<->***********************************/
1241 void WmInstallBitmapDataIntoXmCache (WmScreenData *pSD, 
1242     unsigned char *pchName, char *pData, unsigned int width,
1243     unsigned int height)
1244 {
1245     XImage *pImage;
1246
1247     if (pImage = (XImage *) XtMalloc (sizeof (XImage)))
1248     {
1249         pImage->width = width; 
1250         pImage->height = height;
1251         pImage->xoffset = 0;
1252         pImage->data = pData;
1253         pImage->format = XYBitmap;
1254         pImage->byte_order = MSBFirst;
1255         pImage->bitmap_pad = 8;
1256         pImage->bitmap_bit_order = LSBFirst;
1257         pImage->bitmap_unit = 8;
1258         pImage->depth = 1;
1259         pImage->bytes_per_line = (width/8) + ((width%8) != 0 ? 1 : 0);
1260         pImage->obdata = NULL;
1261
1262         XmInstallImage(pImage, (char *)pchName);
1263     }
1264
1265 } /* END OF FUNCTION WmInstallBitmapDataIntoXmCache */
1266 #endif /* WSM */