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