Use C++ linker
[oweals/cde.git] / cde / programs / dtwm / WmImage.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, 1993 OPEN SOFTWARE FOUNDATION, INC. 
25  * ALL RIGHTS RESERVED 
26 */ 
27 /* 
28  * Motif Release 1.2.3
29 */ 
30 #ifdef REV_INFO
31 #ifndef lint
32 static char rcsid[] = "$XConsortium: WmImage.c /main/7 1996/11/14 13:50:30 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 #define MWM_NEED_IIMAGE
45 #include "WmIBitmap.h"
46
47 #ifdef MOTIF_ONE_DOT_ONE
48 #include <stdio.h>
49 #include <pwd.h>
50 #define MATCH_CHAR 'P'          /* Default match character - defined in Xmos.p */
51 #else
52 #include <Xm/XmosP.h> 
53 /* Copied from XmosI.h */
54 extern String _XmOSInitPath( 
55                         String file_name,
56                         String env_pathname,
57                         Boolean *user_path) ;
58 #endif
59 #ifdef WSM
60 #include <Xm/IconFile.h>
61 #include <Dt/GetDispRes.h>
62 #endif
63
64 #define MATCH_XBM 'B'           /* .xbm character: see XmGetPixmap */
65 #define MATCH_PATH "XBMLANGPATH"
66
67 /*
68  * include extern functions
69  */
70
71 #include "WmImage.h"
72 #include "WmGraphics.h"
73 #include "WmResource.h"
74 #include "WmResParse.h"
75 #include "WmMenu.h"
76 #include "WmError.h"
77
78 #ifdef MOTIF_ONE_DOT_ONE
79 extern char    *getenv ();
80 #endif
81
82 \f
83 /******************************<->*************************************
84  *
85  *  MakeClientIconPixmap (pCD, iconBitmap, iconMask)
86  *
87  *
88  *  Description:
89  *  -----------
90  *  This function takes a client supplied icon image pixmap and mask 
91  *  bitmap and makes it into a colored pixmap suitable for use as an 
92  *  icon image.
93  *
94  *
95  *  Inputs:
96  *  ------
97  *  pCD = pointer to client data (icon colors and tiles)
98  *
99  *  iconBitmap = icon bitmap 
100  *  iconMask   = mask bitmap
101  *
102  * 
103  *  Outputs:
104  *  -------
105  *  RETURN = icon pixmap (NULL if error)
106  *
107  ******************************<->***********************************/
108
109 Pixmap MakeClientIconPixmap (
110         ClientData *pCD, 
111         Pixmap iconBitmap, 
112         Pixmap iconMask)
113 {
114     Window root;
115     int x;
116     int y;
117     unsigned int bitmapWidth;
118     unsigned int bitmapHeight;
119     unsigned int border;
120     unsigned int depth;
121
122     
123     /*
124      * Check out the attributes of the bitmap to insure that it is usable.
125      */
126
127     if (!XGetGeometry (DISPLAY, iconBitmap, &root, &x, &y,
128              &bitmapWidth, &bitmapHeight, &border, &depth))
129     {
130         Warning (((char *)GETMESSAGE(38, 1, "Invalid icon bitmap")));
131         return ((Pixmap)NULL);
132     }
133
134     if (ROOT_FOR_CLIENT(pCD) != root)
135     {
136         /*
137          * The bitmap was not made with usable parameters.
138          */
139 #ifdef WSM
140         Warning (((char *)GETMESSAGE(38, 9, "Icon bitmap cannot be used on this screen")));
141 #else /* WSM */
142         Warning ("Invalid root for icon bitmap");
143 #endif /* WSM */
144         return ((Pixmap)NULL);
145     }
146
147 #ifdef DISALLOW_DEEP_ICONS
148     if (depth != 1)
149     {
150         Warning (((char *)GETMESSAGE(38, 10, "Color icon pixmap not supported")));
151         return ((Pixmap)NULL);
152     }
153 #endif
154
155     /*
156      * Color the bitmap, center it in a pixmap ....
157      */
158
159     return (MakeIconPixmap (pCD, iconBitmap, (Pixmap)iconMask, 
160             bitmapWidth, bitmapHeight, depth));
161
162
163 } /* END OF FUNCTION MakeClientIconPixmap */
164
165
166 \f
167 /*************************************<->*************************************
168  *
169  *  MakeNamedIconPixmap (pCD, iconName)
170  *
171  *
172  *  Description:
173  *  -----------
174  *  This function makes an icon pixmap for a particular client given the
175  *  name of a bitmap file.
176  *
177  *
178  *  Inputs:
179  *  ------
180  *  pCD      = (nonNULL) pointer to client data
181  *  iconName = pointer to the icon name (bitmap file path name or NULL)
182  *
183  * 
184  *  Outputs:
185  *  -------
186  *  RETURN = icon pixmap or NULL
187  * 
188  *************************************<->***********************************/
189
190 Pixmap MakeNamedIconPixmap (ClientData *pCD, String iconName)
191 {
192     int          bitmapIndex;
193 #ifdef WSM
194     Pixmap      pixmap, pixmap_r, mask;
195     Window      root;
196     int         x, y;
197     unsigned int        width, height, border_width, depth;
198     String      sIconFileName;
199     int         iconSizeDesired;
200 #endif /* WSM */
201
202     /*
203      * Get the bitmap cache entry (will read data from file if necessary).
204      * If unable to find the iconName file return NULL.
205      */
206
207 #ifdef WSM
208     if ((bitmapIndex = GetBitmapIndex (PSD_FOR_CLIENT(pCD), iconName,
209                         False)) < 0)
210 #else /* WSM */
211     if ((bitmapIndex = GetBitmapIndex (PSD_FOR_CLIENT(pCD), iconName)) < 0)
212 #endif /* WSM */
213     {
214 #ifdef WSM
215        if ((PSD_FOR_CLIENT(pCD)->displayResolutionType == LOW_RES_DISPLAY) ||
216            (PSD_FOR_CLIENT(pCD)->displayResolutionType == VGA_RES_DISPLAY))
217        {
218           iconSizeDesired = XmMEDIUM_ICON_SIZE;
219        }
220        else
221        {
222           iconSizeDesired = XmLARGE_ICON_SIZE;
223        }
224
225        pixmap = XmUNSPECIFIED_PIXMAP;
226
227        sIconFileName = XmGetIconFileName( 
228                         XtScreen(PSD_FOR_CLIENT(pCD)->screenTopLevelW1),
229                         NULL,
230                         iconName,
231                         NULL,
232                         iconSizeDesired);
233
234        if (sIconFileName != NULL)
235        {
236            pixmap = XmGetPixmap (
237                         XtScreen (PSD_FOR_CLIENT(pCD)->screenTopLevelW1), 
238                         sIconFileName,
239                         pCD->iconImageForeground, 
240                         pCD->iconImageBackground);
241        }
242
243        if (pixmap == XmUNSPECIFIED_PIXMAP)
244        {
245            pixmap = XmGetPixmap (
246                         XtScreen (PSD_FOR_CLIENT(pCD)->screenTopLevelW1), 
247                         iconName,
248                         pCD->iconImageForeground, 
249                         pCD->iconImageBackground);
250        }
251
252        if (pixmap == XmUNSPECIFIED_PIXMAP)
253        {
254             MWarning (((char *)GETMESSAGE(38, 7, "Unable to read bitmap file %s\n")), iconName);
255        }
256        else
257        {
258            mask = _DtGetMask (XtScreen(PSD_FOR_CLIENT(pCD)->screenTopLevelW1), 
259                         (sIconFileName == NULL) ? iconName : sIconFileName);
260            if (mask == XmUNSPECIFIED_PIXMAP) 
261            {
262                mask = (Pixmap) NULL;
263            }
264
265            if (sIconFileName != NULL)
266                XtFree(sIconFileName);
267
268            /*
269             * We need to synchronize DISPLAY1 here because the pixmap and mask 
270             * were created on that display connection, and we must ensure that 
271             * the server has processed those requests before we attempt to use 
272             * the pixmap and mask on DISPLAY.  We thus assume that the 
273             * subsequent XGetGeometry() call is successful.
274             */
275            XSync(DISPLAY1, False);      
276
277            (void) XGetGeometry (DISPLAY, pixmap, &root, &x, &y, &width,
278                        &height, &border_width, &depth);
279
280            pixmap_r = MakeIconPixmap (pCD, pixmap, mask,
281                                      width, height, depth);
282
283            XmDestroyPixmap (XtScreen (PSD_FOR_CLIENT(pCD)->screenTopLevelW1), 
284                                 pixmap);
285            if (mask)
286                XmDestroyPixmap (
287                    XtScreen (PSD_FOR_CLIENT(pCD)->screenTopLevelW1), mask);
288
289            return (pixmap_r);
290        }
291
292        if (sIconFileName != NULL)
293            XtFree (sIconFileName);
294 #endif /* WSM */
295         return ((Pixmap)NULL);
296     }
297
298     /*
299      * Color the bitmap, center it in a pixmap ....
300      */
301
302     return (MakeCachedIconPixmap (pCD, bitmapIndex, (Pixmap)NULL));
303
304 } /* END OF FUNCTION MakeNamedIconPixmap */
305
306
307
308 \f
309 /*************************************<->*************************************
310  *
311  *  Pixmap
312  *  MakeCachedIconPixmap (pCD, bitmapIndex, mask)
313  *
314  *
315  *  Description:
316  *  -----------
317  *  Convert the cached bitmap and mask into an icon pixmap.
318  *
319  *
320  *  Inputs:
321  *  ------
322  *  pCD         - (nonNULL) pointer to client data (icon colors and tiles)
323  *  bitmapIndex - bitmap cache index of image to be converted
324  *  mask        - bitmap mask, 1 for bits of "bitmap" to be kept
325  *
326  * 
327  *  Outputs:
328  *  -------
329  *  RETURN      - icon pixmap or NULL
330  *
331  *
332  *  Comments:
333  *  --------
334  *  o "mask" is not used.
335  * 
336  *************************************<->***********************************/
337 Pixmap MakeCachedIconPixmap (ClientData *pCD, int bitmapIndex, Pixmap mask)
338 {
339     BitmapCache  *bitmapc;
340     PixmapCache  *pixmapc;
341     Pixmap        pixmap = (Pixmap)NULL;
342     WmScreenData *pSD = PSD_FOR_CLIENT(pCD);
343
344     if (bitmapIndex < 0)
345     {
346         return ((Pixmap)NULL);
347     }
348     bitmapc = &(pSD->bitmapCache[bitmapIndex]);
349
350     /*
351      * Search for an icon pixmap matching the client icon colors.
352      */
353
354     pixmapc = bitmapc->pixmapCache;
355     while (pixmapc)
356     {
357         if ((pixmapc->pixmapType == ICON_PIXMAP) &&
358             (pixmapc->foreground == pCD->iconImageForeground) &&
359             (pixmapc->background == pCD->iconImageBackground))
360         {
361             pixmap = pixmapc->pixmap;
362             break;
363         }
364         pixmapc = pixmapc->next;
365     }
366
367     /* 
368      * If a matching pixmap was not found in the pixmap cache for this bitmap
369      *   then create the icon pixmap with the appropriate colors.
370      * If have sufficient memory, save the pixmap info in the pixmapCache.
371      */
372
373     if (!pixmap &&
374         (pixmap = MakeIconPixmap (pCD, bitmapc->bitmap, mask,
375                                      bitmapc->width, bitmapc->height, 1)) &&
376         (pixmapc = (PixmapCache *) XtMalloc (sizeof (PixmapCache))))
377     {
378
379         pixmapc->pixmapType = ICON_PIXMAP;
380         pixmapc->foreground = pCD->iconImageForeground;
381         pixmapc->background = pCD->iconImageBackground;
382         pixmapc->pixmap = pixmap;
383         pixmapc->next = bitmapc->pixmapCache;
384         bitmapc->pixmapCache = pixmapc;
385     }
386
387     return (pixmap);
388
389 } /* END OF FUNCTION MakeCachedIconPixmap */
390
391
392 \f
393 /*************************************<->*************************************
394  *
395  *  MakeIconPixmap (pCD, bitmap, mask, width, height, depth)
396  *
397  *
398  *  Description:
399  *  -----------
400  *  Convert the bitmap and mask into an icon pixmap.
401  *
402  *
403  *  Inputs:
404  *  ------
405  *  pCD         - pointer to client data (icon colors and tiles)
406  *  pWS         - pointer to workspace data
407  *  bitmap      - bitmap image to be converted
408  *  mask        - bitmap mask, 1 for bits of "bitmap" to be kept
409  *  width       - pixel width of bitmap
410  *  height      - pixel height of bitmap
411  *  depth       - depth of bitmap (pixmap, really)
412  *
413  * 
414  *  Outputs:
415  *  -------
416  *  RETURN      - icon pixmap or NULL
417  *
418  *
419  *  Comments:
420  *  --------
421  *  o "mask" is not used.
422  * 
423  *************************************<->***********************************/
424 Pixmap MakeIconPixmap (ClientData *pCD, Pixmap bitmap, Pixmap mask, unsigned int width, unsigned int height, unsigned int depth)
425 {
426     Pixmap       iconPixmap;
427     GC           imageGC, topGC, botGC;
428     XGCValues    gcv;
429 #ifdef WSM
430     unsigned long gc_mask;
431     XmPixelSet   *pPS = NULL;
432 #endif /* WSM */
433     unsigned int imageWidth;
434     unsigned int imageHeight;
435     int          dest_x, dest_y;
436 #ifndef NO_CLIP_CENTER
437     int          src_x, src_y;
438 #endif /* NO_CLIP_CENTER */
439     Pixel        fg;
440     Pixel        bg;
441     static RList *top_rects = NULL;
442     static RList *bot_rects = NULL;
443     WmScreenData        *pSD;
444
445     if ((top_rects == NULL) && 
446         (top_rects = AllocateRList 
447         ((unsigned)2 * ICON_INTERNAL_SHADOW_WIDTH)) == NULL)
448     {
449         /* Out of memory! */
450         Warning (((char *)GETMESSAGE(38, 3, "Insufficient memory to bevel icon image")));
451         return ((Pixmap)NULL);
452     }
453
454     if ((bot_rects == NULL) &&
455         (bot_rects = AllocateRList 
456         ((unsigned)2 * ICON_INTERNAL_SHADOW_WIDTH)) == NULL)
457     {
458         /* Out of memory! */
459         Warning (((char *)GETMESSAGE(38, 4, "Insufficient memory to bevel icon image")));
460         return ((Pixmap)NULL);
461     }
462
463     if (pCD)
464     {
465         pSD = pCD->pSD;
466     }
467     else 
468     {
469         pSD = wmGD.pActiveSD;
470     }
471
472     /* don't make icon pixmap if bitmap is too small */
473
474     if ((width < pSD->iconImageMinimum.width) ||
475         (height < pSD->iconImageMinimum.height))
476     {
477         /* bitmap is too small */
478         return ((Pixmap)NULL);
479     }
480 #ifndef NO_CLIP_CENTER
481     
482     /* copy the center of the icon if too big */
483     if (width > pSD->iconImageMaximum.width)
484     {
485         src_x = (width - pSD->iconImageMaximum.width)/2;
486     }
487     else
488     {
489         src_x = 0;
490     }
491     if (height > pSD->iconImageMaximum.height)
492     {
493         src_y = (height - pSD->iconImageMaximum.height)/2;
494     }
495     else
496     {
497         src_y = 0;
498     }
499 #endif /* NO_CLIP_CENTER */
500
501     /*
502      * SLAB frameStyle adds a single pixel of background color around
503      * the image to set it off from the beveling.
504      */
505     imageWidth = pSD->iconImageMaximum.width + 
506                   2 * ICON_INTERNAL_SHADOW_WIDTH +
507                   ((wmGD.frameStyle == WmSLAB) ? 2 : 0);
508     imageHeight = pSD->iconImageMaximum.height +
509                   2 * ICON_INTERNAL_SHADOW_WIDTH +
510                   ((wmGD.frameStyle == WmSLAB) ? 2 : 0);
511
512     /* create a pixmap (to be returned) */
513
514     iconPixmap = XCreatePixmap (DISPLAY, pSD->rootWindow, 
515                      imageWidth, imageHeight,
516                      DefaultDepth(DISPLAY, pSD->screen));
517
518     /*
519      * If a client is not specified use icon component colors, otherwise
520      * use the client-specific icon colors.
521      */
522
523     if (pCD)
524     {
525         bg = pCD->iconImageBackground;
526         fg = pCD->iconImageForeground;
527     }
528     else
529     {
530         bg = pSD->iconAppearance.background;
531         fg = pSD->iconAppearance.foreground;
532     }
533
534     /* create a GC to use */
535 #ifdef WSM
536     gc_mask = GCForeground | GCBackground | GCGraphicsExposures;
537     if (mask)
538     {
539         if (pSD->pPrimaryPixelSet != NULL)
540         {
541             pPS = pSD->pPrimaryPixelSet;
542             gcv.background = pPS->bg;
543             /* set fg to bg color to clear it first */
544             gcv.foreground = pPS->bg;
545         }
546         else
547         {
548             gcv.background = ICON_APPEARANCE(pCD).background;
549             /* set fg to bg color to clear it first */
550             gcv.foreground = ICON_APPEARANCE(pCD).background;
551         }
552     } 
553     else 
554     {
555         gcv.foreground = bg;    /* clear it first! */
556         gcv.background = bg;
557     }
558     gcv.graphics_exposures = False;
559
560     imageGC = XCreateGC (DISPLAY, iconPixmap, gc_mask, &gcv);
561 #else /* WSM */
562     gcv.foreground = bg;        /* clear it first! */
563     gcv.background = bg;
564     gcv.graphics_exposures = False;
565
566     imageGC = XCreateGC (DISPLAY, iconPixmap, (GCForeground|GCBackground),
567                   &gcv);
568 #endif /* WSM */
569
570     /*
571      * Format the image. 
572      */
573
574     /* fill in background */
575
576     XFillRectangle(DISPLAY, iconPixmap, imageGC, 0, 0, 
577                    imageWidth, imageHeight);
578
579     /* center the image */
580
581     if (width > pSD->iconImageMaximum.width)
582     {
583         width = pSD->iconImageMaximum.width;
584     }
585     if (height > pSD->iconImageMaximum.height)
586     {
587         height = pSD->iconImageMaximum.height;
588     }
589     /* center the image */
590
591     dest_x = (imageWidth - width) / 2;
592     dest_y = (imageHeight - height) / 2;
593
594 #ifdef WSM
595     if (mask)
596     {
597         if (pPS != NULL)
598         {
599             gcv.foreground = pPS->fg;
600         }
601         else
602         {
603             gcv.foreground = ICON_APPEARANCE(pCD).foreground;
604         }
605     }
606     else
607     {
608         gcv.foreground = fg;
609     }
610     gc_mask = GCForeground;
611     if (mask)
612     {
613         gcv.clip_mask = mask;
614 #ifndef NO_CLIP_CENTER
615         gcv.clip_x_origin = dest_x - src_x;
616         gcv.clip_y_origin = dest_y - src_y;
617 #else /* NO_CLIP_CENTER */
618         gcv.clip_x_origin = dest_x;
619         gcv.clip_y_origin = dest_y;
620 #endif /* NO_CLIP_CENTER */
621         gc_mask |= GCClipXOrigin | GCClipYOrigin | GCClipMask;
622     } 
623
624     XChangeGC (DISPLAY, imageGC, gc_mask, &gcv);
625 #else /* WSM */
626     /* set the foreground */
627     XSetForeground (DISPLAY, imageGC, fg);
628 #endif /* WSM */
629
630     /* copy the bitmap to the pixmap */
631 #ifndef DISALLOW_DEEP_ICONS
632     if ((depth > 1) &&
633         (depth == DefaultDepth(DISPLAY, pSD->screen)))
634     {
635 #ifndef NO_CLIP_CENTER
636         XCopyArea (DISPLAY, bitmap, iconPixmap, imageGC, src_x, src_y,
637                 width, height, dest_x, dest_y);
638 #else /* NO_CLIP_CENTER */
639         XCopyArea (DISPLAY, bitmap, iconPixmap, imageGC, 0, 0,
640                 width, height, dest_x, dest_y);
641 #endif /* NO_CLIP_CENTER */
642     }
643     else
644 #endif /* DISALLOW_DEEP_ICONS */
645 #ifndef NO_CLIP_CENTER
646     XCopyPlane (DISPLAY, bitmap, iconPixmap, imageGC, src_x, src_y, width, 
647                 height, dest_x, dest_y, 1L);
648 #else /* NO_CLIP_CENTER */
649     XCopyPlane (DISPLAY, bitmap, iconPixmap, imageGC, 0, 0, width, height, 
650                 dest_x, dest_y, 1L);
651 #endif /* NO_CLIP_CENTER */
652
653     /* free resources */
654     XFreeGC (DISPLAY, imageGC);
655
656     if (pCD)
657     {
658         /*
659          * Shadowing
660          */
661
662 #ifdef WSM
663         if (mask && (pPS != NULL))
664         {
665         topGC = GetHighlightGC (pSD, pPS->ts, pPS->bg,
666                                   pCD->iconImageTopShadowPixmap);
667
668         botGC = GetHighlightGC (pSD, pPS->bs, pPS->bg,
669                                   pCD->iconImageBottomShadowPixmap);
670         }
671         else
672         {
673 #endif /* WSM */
674         topGC = GetHighlightGC (pSD, pCD->iconImageTopShadowColor, 
675                                   pCD->iconImageBackground,
676                                   pCD->iconImageTopShadowPixmap);
677
678         botGC = GetHighlightGC (pSD, pCD->iconImageBottomShadowColor, 
679                                   pCD->iconImageBackground,
680                                   pCD->iconImageBottomShadowPixmap);
681 #ifdef WSM
682         }
683 #endif /* WSM */
684
685        /*
686         *  CR5208 - Better fix than from OSF!
687         *           Zero out the rectangle count in our
688         *           static structures so that BevelRectangle
689         *           won't extend the RList causing a memory leak.
690         *           Old fix allocated and freed rectangle structure
691         *           each time through.
692         */
693         top_rects->used = 0;    /* reset count */
694         bot_rects->used = 0;
695
696         BevelRectangle (top_rects, 
697                         bot_rects, 
698                         0, 0,
699                         imageWidth, imageHeight,
700                         ICON_INTERNAL_SHADOW_WIDTH,
701                         ICON_INTERNAL_SHADOW_WIDTH,
702                         ICON_INTERNAL_SHADOW_WIDTH,
703                         ICON_INTERNAL_SHADOW_WIDTH);
704
705         XFillRectangles (DISPLAY, iconPixmap, topGC, top_rects->prect, 
706                                                         top_rects->used);
707         XFillRectangles (DISPLAY, iconPixmap, botGC, bot_rects->prect,
708                                                         bot_rects->used);
709     }
710     return (iconPixmap);
711
712 } /* END OF FUNCTION MakeIconPixmap */
713
714
715 \f
716 /*************************************<->*************************************
717  *
718  *  Pixmap
719  *  MakeCachedLabelPixmap (pSD, menuW, bitmapIndex)
720  *
721  *
722  *  Description:
723  *  -----------
724  *  Creates and returns a label pixmap.
725  *
726  *
727  *  Inputs:
728  *  ------
729  *  pSD = pointer to screen data
730  *  menuW = menu widget (for foreground and background colors)
731  *  bitmapIndex = bitmap cache index
732  *
733  * 
734  *  Outputs:
735  *  -------
736  *  Return = label pixmap or NULL.
737  *
738  *
739  *  Comments:
740  *  --------
741  *  Assumes bitmapIndex is valid.
742  * 
743  *************************************<->***********************************/
744
745 Pixmap MakeCachedLabelPixmap (WmScreenData *pSD, Widget menuW, int bitmapIndex)
746 {
747     BitmapCache  *bitmapc;
748     PixmapCache  *pixmapc;
749     int           i;
750     Arg           args[5];
751     Pixel         fg, bg;
752     Pixmap        pixmap = (Pixmap)NULL;
753     GC            gc;
754     XGCValues     gcv;
755
756     if (bitmapIndex < 0)
757     {
758         return ((Pixmap)NULL);
759     }
760     bitmapc = &(pSD->bitmapCache[bitmapIndex]);
761
762     /*
763      * Get the foreground and background colors from the menu widget.
764      * Search for a label pixmap matching those colors.
765      */
766
767     i = 0;
768     XtSetArg (args[i], XtNforeground, &fg); i++;
769     XtSetArg (args[i], XtNbackground, &bg); i++;
770     XtGetValues (menuW, (ArgList)args, i);
771
772     pixmapc = bitmapc->pixmapCache;
773     while (pixmapc)
774     {
775         if ((pixmapc->pixmapType == LABEL_PIXMAP) &&
776             (pixmapc->foreground == fg) &&
777             (pixmapc->background == bg))
778         {
779             pixmap = pixmapc->pixmap;
780             break;
781         }
782         pixmapc = pixmapc->next;
783     }
784
785     if (!pixmap)
786     /* 
787      * A matching pixmap was not found in the pixmap cache for this bitmap.
788      * Create and save the label pixmap with appropriate colors.
789      */
790     {
791         /* 
792          * Create a pixmap of the appropriate size, root, and depth.
793          * Only BadAlloc error possible; BadDrawable and BadValue are avoided.
794          */
795
796         pixmap = XCreatePixmap (DISPLAY, pSD->rootWindow, 
797                                 bitmapc->width, bitmapc->height,
798                                 DefaultDepth (DISPLAY, pSD->screen));
799
800         /*
801          * Create a GC and copy the bitmap to the pixmap.
802          * Only BadAlloc and BadDrawable errors are possible; others are avoided
803          */
804
805         gcv.foreground = bg;
806         gcv.background = bg;
807         gcv.graphics_exposures = False;
808         gc = XCreateGC(DISPLAY, pixmap, (GCForeground|GCBackground), &gcv);
809    
810         /*
811          * Fill in the background, set the foreground, copy the bitmap to the 
812          * pixmap, and free the gc.
813          */
814
815         XFillRectangle (DISPLAY, pixmap, gc, 0, 0,
816                         bitmapc->width, bitmapc->height);
817         XSetForeground (DISPLAY, gc, fg);
818         XCopyPlane (DISPLAY, bitmapc->bitmap, pixmap, gc, 0, 0,
819                     bitmapc->width, bitmapc->height, 0, 0, 1L);
820         XFreeGC (DISPLAY, gc);
821
822         /*
823          * If have sufficient memory, save the pixmap info in the pixmapCache.
824          */
825
826         if ((pixmapc = (PixmapCache *) XtMalloc(sizeof(PixmapCache))) != NULL)
827         {
828             pixmapc->pixmapType = LABEL_PIXMAP;
829             pixmapc->foreground = fg;
830             pixmapc->background = bg;
831             pixmapc->pixmap = pixmap;
832             pixmapc->next = bitmapc->pixmapCache;
833             bitmapc->pixmapCache = pixmapc;
834         }
835     }
836
837     return (pixmap);
838
839 } /* END OF FUNCTION MakeCachedLabelPixmap */
840
841
842 \f
843 /*************************************<->*************************************
844  *
845  *  int
846  *  GetBitmapIndex (pSD, name)
847  *
848  *
849  *  Description:
850  *  -----------
851  *  Retrieve bitmap from cache.
852  *
853  *
854  *  Inputs:
855  *  ------
856  *  pSD = pointer to screen data
857  *  name = bitmap file name or NULL pointer
858  *  bitmapCache[]
859  *  bitmapCacheSize
860  *  bitmapCacheCount
861  *
862  * 
863  *  Outputs:
864  *  -------
865  *  bitmapCache[]
866  *  bitmapCacheSize
867  *  bitmapCacheCount
868  *  Return   = bitmap cache index or -1
869  *
870  *
871  *  Comments:
872  *  --------
873  *  None
874  * 
875  *************************************<->***********************************/
876
877 #define BITMAP_CACHE_INC 5
878
879 #ifdef WSM
880 int GetBitmapIndex (WmScreenData *pSD, char *name, Boolean bReportError)
881 #else /* WSM */
882 int GetBitmapIndex (WmScreenData *pSD, char *name)
883 #endif /* WSM */
884 {
885     char         *path;
886     BitmapCache  *bitmapc;
887     unsigned int  n;
888     int           x, y;
889
890     /*
891      * Search a nonempty bitmap cache for a pathname match.
892      */
893     path = BitmapPathName (name);
894     for (n = 0, bitmapc = pSD->bitmapCache;
895          n < pSD->bitmapCacheCount;
896          n++, bitmapc++)
897     {
898         if ((!path && !bitmapc->path) ||
899             (path && bitmapc->path && 
900              !strcmp (path, bitmapc->path)))
901         {
902             return (n);
903         }
904     }
905
906     /*
907      * The bitmap path name was not found in bitmapCache.
908      * Find the next BitmapCache entry, creating or enlarging bitmapCache if 
909      * necessary.
910      */
911     if (pSD->bitmapCacheSize == 0)
912     /* create */
913     {
914         pSD->bitmapCacheSize = BITMAP_CACHE_INC;
915         pSD->bitmapCache =
916             (BitmapCache *) XtMalloc (BITMAP_CACHE_INC * sizeof (BitmapCache));
917     }
918     else if (pSD->bitmapCacheCount == pSD->bitmapCacheSize)
919     /* enlarge */
920     {
921         pSD->bitmapCacheSize += BITMAP_CACHE_INC;
922         pSD->bitmapCache = (BitmapCache *) 
923             XtRealloc ((char*)pSD->bitmapCache, 
924                      pSD->bitmapCacheSize * sizeof (BitmapCache));
925     }
926
927     if (pSD->bitmapCache == NULL)
928     {
929         MWarning (((char *)GETMESSAGE(38, 5, "Insufficient memory for bitmap %s\n")), name);
930         pSD->bitmapCacheSize = 0;
931         pSD->bitmapCacheCount = 0;
932         return (-1);
933     }
934
935     bitmapc = &(pSD->bitmapCache[pSD->bitmapCacheCount]);
936
937     /*
938      * Fill the entry with the bitmap info.
939      * A NULL path indicates the builtin icon bitmap.
940      * Indicate that no pixmapCache exists yet.
941      */
942
943     if (path)
944     {
945         if ((bitmapc->path = (String)
946                  XtMalloc ((unsigned int)(strlen (path) + 1))) == NULL)
947         {
948             MWarning (((char *)GETMESSAGE(38, 6, "Insufficient memory for bitmap %s\n")), name);
949             return (-1);
950         }
951         strcpy (bitmapc->path, path);
952
953         if (XReadBitmapFile (DISPLAY, pSD->rootWindow, path, 
954                              &bitmapc->width, &bitmapc->height, 
955                              &bitmapc->bitmap, &x, &y)
956             != BitmapSuccess)
957         {
958 #ifdef WSM
959           if (bReportError)
960 #endif /* WSM */
961             MWarning (((char *)GETMESSAGE(38, 7, "Unable to read bitmap file %s\n")), path);
962             XtFree ((char *)bitmapc->path);
963             return (-1);
964         }
965
966         if (bitmapc->width == 0 || bitmapc->height == 0)
967         {
968 #ifdef WSM
969           if (bReportError)
970 #endif /* WSM */
971             MWarning (((char *)GETMESSAGE(38, 8, "Invalid bitmap file %s\n")), path);
972             XtFree ((char *)bitmapc->path);
973             return (-1);
974         }
975     }
976     else
977     /* builtin icon bitmap */
978     {
979         bitmapc->path   = NULL;
980         bitmapc->bitmap = pSD->builtinIconPixmap;
981         bitmapc->width  = iImage_width;
982         bitmapc->height = iImage_height;
983     }
984
985     bitmapc->pixmapCache = NULL;
986
987     return (pSD->bitmapCacheCount++);
988
989 } /* END OF FUNCTION GetBitmapIndex */
990
991
992 \f
993 /*************************************<->*************************************
994  *
995  *  BitmapPathName (string)
996  *
997  *
998  *  Description:
999  *  -----------
1000  *  Constructs a bitmap file pathname from the bitmap file name and the
1001  *  bitmapDirectory resource value.
1002  *
1003  *
1004  *  Inputs:
1005  *  ------
1006  *  string = bitmap file name or NULL
1007  *  wmGD.bitmapDirectory = bitmapDirectory resource value
1008  *  HOME = environment variable for home directory
1009  *  XBMLANGPATH
1010  *  XAPPLRESDIR
1011  *
1012  * 
1013  *  Outputs:
1014  *  -------
1015  *  Return = string containing the bitmap file pathname or NULL.
1016  *
1017  *
1018  *  Comments:
1019  *  --------
1020  *  If the bitmap file does not exist, searches using XBMLANGPATH.
1021  *  Returns NULL path name for a NULL file name.
1022  * 
1023  *************************************<->***********************************/
1024
1025 char *BitmapPathName (string)
1026     char *string;
1027
1028 {
1029     static char  fileName[MAXWMPATH+1];
1030     char *retname;
1031     SubstitutionRec subs[1];
1032 #ifndef MOTIF_ONE_DOT_ONE
1033     char *homeDir = XmeGetHomeDirName();
1034 #endif
1035
1036     if (!string || !*string)
1037     {
1038         return (NULL);
1039     }
1040
1041     /*
1042      * Interpret "~/.." as relative to the user's home directory.
1043      * Interpret "/.." as an absolute pathname.
1044      * If the bitmapDirectory resource is nonNULL, interpret path as relative
1045      *   to it.
1046      * Else, or if bitmapDirectory has no such file, use a XBMLANGPATH lookup.
1047      */
1048
1049     if ((string[0] == '~') && (string[1] == '/'))
1050     /* 
1051      * Handle "~/.." 
1052      */
1053     {
1054 #ifdef MOTIF_ONE_DOT_ONE
1055         GetHomeDirName(fileName);
1056 #else
1057         strcpy (fileName, homeDir);
1058 #endif
1059         strncat (fileName, &(string[1]), MAXWMPATH - strlen (fileName));
1060         return (fileName);
1061     }
1062
1063     if (string[0] == '/')
1064     {
1065       return(string);
1066     }
1067
1068     if (wmGD.bitmapDirectory && *wmGD.bitmapDirectory)
1069     /*
1070      * Relative to nonNULL bitmapDirectory (which may have relative to HOME)
1071      */
1072     {
1073         if ((wmGD.bitmapDirectory[0] == '~') &&
1074             (wmGD.bitmapDirectory[1] == '/'))
1075         {
1076 #ifdef MOTIF_ONE_DOT_ONE
1077             GetHomeDirName(fileName);
1078 #else
1079             strcpy (fileName, homeDir);
1080 #endif
1081             strncat (fileName, &wmGD.bitmapDirectory[1],
1082                      MAXWMPATH - strlen (fileName));
1083         } else {
1084             strcpy (fileName, wmGD.bitmapDirectory);
1085         }
1086         strncat (fileName, "/", MAXWMPATH - strlen (fileName));
1087         strncat (fileName, string, MAXWMPATH - strlen (fileName));
1088
1089 /* Test file for existence. */
1090
1091         subs[0].substitution = "";
1092         if ((retname = XtFindFile(fileName, subs, 0,
1093                                   (XtFilePredicate) NULL)) != NULL) {
1094           XtFree(retname);
1095           return (fileName);
1096         }
1097     }
1098
1099     /* Fall back on a path search */
1100
1101 #ifdef MOTIF_ONE_DOT_ONE
1102     return (NULL);
1103 #else
1104     {
1105         char *search_path;
1106         Boolean user_path;
1107
1108         search_path = _XmOSInitPath(string, MATCH_PATH, &user_path);
1109         subs[0].match = user_path ? MATCH_XBM : MATCH_CHAR;
1110         subs[0].substitution = string;
1111         retname = XtResolvePathname(DISPLAY, "bitmaps", NULL, NULL,
1112                                     search_path, subs, XtNumber(subs), 
1113                                         (XtFilePredicate)NULL);
1114         XtFree(search_path);
1115
1116         if (!retname)
1117           return (string);
1118
1119         strncpy(fileName, retname, MAXWMPATH);
1120         XtFree(retname);
1121         return (fileName);
1122     }
1123 #endif
1124
1125 } /* END OF FUNCTION BitmapPathName */
1126
1127 #ifdef WSM
1128 /****************************   eof    ***************************/
1129 #endif /* WSM */