1 /*
2  * Motif
3  *
4  * Copyright (c) 1987-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 #ifdef REV_INFO
24 #ifndef lint
25 static char rcsid[] = "$TOG: ImageCache.c /main/44 1998/10/06 17:26:25 samborn $"
26 #endif
27 #endif
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 
32 
33 #include "XmI.h"
34 #include "XmosI.h"              /* for mask name API and stuff */
35 #include "BitmapsI.h"		/* for built-in images */
36 #include "ColorI.h"		/* for _XmSearchColorCache() */
37 #include "HashI.h"		/* for hash table routines. */
38 #include "ImageCachI.h"		/* for DIRECT_PIXMAP_CACHED */
39 #include "ReadImageI.h"		/* for read xbm stuff */
40 #include <Xm/AccColorT.h>       /* for new _XmGetColoredPixmap API */
41 #include <Xm/ColorObjP.h>       /* for Xme Color Obj access API */
42 #include <Xm/IconFile.h>        /* XmGetIconFileName */
43 #ifdef PRINTING_SUPPORTED
44 #include <Xm/PrintSP.h>         /* for pixmap resolution */
45 #endif
46 #include <Xm/XpmP.h>
47 #include <X11/Xresource.h>
48 #ifdef JPEG_SUPPORTED
49 #include "JpegI.h"
50 #endif
51 #ifdef PNG_SUPPORTED
52 #include "PngI.h"
53 #endif
54 
55 /* additional value for GetImage return, FALSE, TRUE and */
56 #define NOT_CACHED 2
57 
58 /* index and max size of the override_colorsarray */
59 #define NUM_SYMBOLIC_COLORS       7
60 #define SYMB_BACKGROUND           0
61 #define SYMB_FOREGROUND           1
62 #define TRANSPARENT_COLOR         2
63 #define SYMB_TOP_SHADOW_COLOR     3
64 #define SYMB_BOTTOM_SHADOW_COLOR  4
65 #define SYMB_SELECT_COLOR         5
66 #define SYMB_HIGHLIGHT_COLOR      6
67 
68 /*  Image set handling defines, structure, and global statics  */
69 
70 typedef struct _ImageData
71 {
72    int		 hot_x, hot_y;
73    XImage	 *image;
74    char		 *image_name;
75    unsigned char *builtin_data;
76 } ImageData;
77 
78 static XmHashTable image_set = NULL;
79 
80 
81 /*  Pixmap caching structure and global statics  */
82 
83 typedef struct _PixmapData
84 {
85    Screen * screen;
86    char   * image_name;
87    XmAccessColorData acc_color ;
88    Pixmap   pixmap;
89    int	    depth;
90    Dimension width ;
91    Dimension height ;
92    int      reference_count;
93    unsigned short print_resolution ;
94    Widget   print_shell ;
95    double   scaling_ratio ;
96    Pixel  * pixels;
97    int      npixels;
98 } PixmapData;
99 
100 static XmHashTable pixmap_set = NULL;
101 static XmHashTable pixmap_data_set = NULL;
102 
103 
104 /*  Color caching structure and global statics  */
105 
106 typedef struct _CachedColorStruct {
107     Display	*display;
108     Colormap 	 colormap;
109     XrmQuark 	 colorname;
110     unsigned short red, green, blue;
111     Pixel    	 pixel;
112     unsigned int num_cached;	/* reference count */
113 } CachedColor;
114 
115 typedef struct _CachedColorListStruct {
116     int          numEntries;
117     int          maxEntries;
118     CachedColor  *cache;
119 } CachedColorList;
120 
121 static CachedColorList colorCacheList;
122 
123 
124 /*  GC caching structure and global statics  */
125 
126 typedef struct _GCData
127 {
128     GC		gc;
129     Screen     *screen;
130     Widget	print_shell;
131     int		depth;
132     int		image_depth;
133     Pixel	foreground;
134     Pixel	background;
135 } GCData;
136 
137 static XmHashTable gc_set = NULL;
138 
139 
140 typedef struct _CleanKey {
141     Screen * screen ;
142     Widget shell ;
143 } CleanKey ;
144 
145 /********    Static Function Declarations    ********/
146 
147 static Boolean ComparePixmaps (XmHashKey key_1, XmHashKey key_2);
148 static Boolean ComparePixmapDatas (XmHashKey key_1, XmHashKey key_2);
149 static Boolean CompareStrings (XmHashKey key_1, XmHashKey key_2);
150 static Boolean CompareGCDatas (XmHashKey key_1, XmHashKey key_2);
151 static XmHashValue HashPixmap (XmHashKey key);
152 static XmHashValue HashPixmapData (XmHashKey key);
153 static XmHashValue HashString (XmHashKey key);
154 static XmHashValue HashGCData (XmHashKey key);
155 static void InitializeImageSet( void ) ;
156 static void InitializePixmapSets( void ) ;
157 static Boolean UninstallImageMapProc (XmHashKey key, XtPointer value,
158 			       XtPointer image);
159 static Boolean SymbolicColorUsed(String color_name,
160 				 XpmColor * xpm_colors,
161 				 unsigned int ncolors);
162 static void CompleteUnspecColors(
163 			       Screen *screen,
164 			       XpmColorSymbol *override_colors);
165 static int GetOverrideColors(
166 			    Screen *screen,
167 			    XmAccessColorData acc_color,
168 			    XpmColorSymbol *override_colors);
169 static XtEnum GetXpmImage(Screen *screen, char *image_name, char *file_name,
170                           XmAccessColorData acc_color, XImage **image,
171                           unsigned short *pixmap_resolution,
172                           Pixel **pixels, int *npixels);
173 static XtEnum GetImage(Screen *screen, char *image_name,
174 		       XmAccessColorData acc_color, XImage **image,
175 		       unsigned short * pixmap_resolution,
176 		       Pixel **pixels,	/* allocated pixels */
177 		       int *npixels);
178 static GC GetGCForPutImage(Screen *screen,
179 			   Widget print_shell,
180 			   XImage * image,
181 			   Pixmap pixmap,
182 			   int depth,
183 			   Pixel foreground,
184 			   Pixel background);
185 
186 static int GetCacheColor(Display *display, Colormap colormap,
187 			 char *colorname, XColor *color, void *data);
188 static int FreeCacheColors(Display *display, Colormap colormap,
189 			   Pixel *pixels, int npixels, void *data);
190 
191 /********    End Static Function Declarations    ********/
192 
193 
194 
195 
196 /*** IMAGE CACHE PART FIRST ***/
197 
198 
199 
200 
201 /* Compare two strings. */
202 static Boolean
CompareStrings(XmHashKey key_1,XmHashKey key_2)203 CompareStrings (XmHashKey key_1,
204 		XmHashKey key_2)
205 {
206   char *data_1 = (char *) key_1;
207   char *data_2 = (char *) key_2;
208 
209   return ((data_1 == data_2) || (strcmp(data_1, data_2) == 0));
210 }
211 
212 
213 /* Hash a string. */
214 static XmHashValue
HashString(XmHashKey key)215 HashString (XmHashKey key)
216 {
217   char *data = (char *) key;
218   unsigned int len = strlen(data);
219 
220   return (((len << 8) | data[0]) << 8) | data[len];
221 }
222 
223 /************************************************************************
224  *
225  *  InitializeImageSet
226  *	Initialize the image set.
227  *
228  ************************************************************************/
229 static void
InitializeImageSet(void)230 InitializeImageSet( void )
231 {
232   register int i;
233 
234   /* Allocate the hash table. */
235   assert (image_set == NULL);
236 
237   _XmProcessLock();
238   image_set =
239     _XmAllocHashTable (MAX_BUILTIN_IMAGES + 100, CompareStrings, HashString);
240 
241   /* Load the built-in image data.
242      Builtins have a non NULL builtin data.
243      Their image field is setdynamically at GetImage time */
244   for (i = 0; i < MAX_BUILTIN_IMAGES ; i++)
245     {
246       ImageData *entry = XtNew(ImageData);
247 
248       entry->hot_x = 0;
249       entry->hot_y = 0;
250       entry->image = NULL;
251       entry->image_name = (char*) bitmap_name_set[i];
252       entry->builtin_data = (unsigned char *) bitmaps[i];
253 
254       _XmAddHashEntry(image_set, entry->image_name, entry);
255     }
256   _XmProcessUnlock();
257 }
258 
259 /************************************************************************
260  *
261  *  _XmInstallImage
262  *
263  *		Allow a hot_spot to be specified
264  *
265  ************************************************************************/
266 Boolean
_XmInstallImage(XImage * image,char * image_name,int hot_x,int hot_y)267 _XmInstallImage(
268         XImage *image,
269         char *image_name,
270 	int hot_x,
271 	int hot_y)
272 {
273    ImageData *entry;
274 
275 
276    /*  Error checking  */
277 
278    if (image == NULL || image_name == NULL) return (False);
279 
280 
281    /*  Check for the initial allocation of the image set array  */
282 
283    if (image_set == NULL) InitializeImageSet();
284 
285 
286    /*  Verify that the image_name is not already in the image set.  */
287    _XmProcessLock();
288 
289    if (_XmGetHashEntry(image_set, image_name) != NULL) {
290      _XmProcessUnlock();
291      return (False);
292    }
293 
294 
295    /*  Initialize the image element for the new image and return True.  */
296 
297    entry = XtNew(ImageData);
298    entry->hot_x = hot_x;
299    entry->hot_y = hot_y;
300    entry->image = image;
301    entry->image_name = XtNewString(image_name);
302    entry->builtin_data = NULL;
303 
304    _XmAddHashEntry(image_set, entry->image_name, entry);
305 
306    _XmProcessUnlock();
307    return (True);
308 }
309 
310 /************************************************************************
311  *
312  *  XmInstallImage
313  *	Add the provided image for the image set and return an
314  *	id to be used for further referencing.
315  *
316  ************************************************************************/
317 Boolean
XmInstallImage(XImage * image,char * image_name)318 XmInstallImage(
319         XImage *image,
320         char *image_name )
321 {
322     Boolean	ret_val;
323 
324     _XmProcessLock();
325     ret_val = _XmInstallImage(image, image_name, 0, 0);
326     _XmProcessUnlock();
327 
328     return ret_val;
329 }
330 /* A hash table map procedure to uninstall an image. */
331 
332 /*ARGSUSED*/
333 static Boolean
UninstallImageMapProc(XmHashKey key,XtPointer value,XtPointer image)334 UninstallImageMapProc (XmHashKey key, /* unused */
335 		XtPointer value,
336 		XtPointer image)
337 {
338   ImageData *entry = (ImageData *) value;
339 
340   if (entry->image == (XImage*) image)
341     {
342       /* Can't free built-in data. */
343       if (entry->builtin_data == NULL)
344 	{
345 	  _XmProcessLock();
346 	  _XmRemoveHashEntry (image_set, entry->image_name);
347 	  _XmProcessUnlock();
348 	  XtFree(entry->image_name);
349 	  /* uninstall do not free the XImage itself */
350 	  XtFree((char*) entry);
351 	}
352 
353       return True;
354     }
355 
356   return False;
357 }
358 
359 /************************************************************************
360  *
361  *  XmUninstallImage
362  *	Remove an image from the image set.
363  *	Return a boolean (True) if the uninstall succeeded.  Return
364  *	a boolean (False) if an error condition occurs.
365  *
366  ************************************************************************/
367 Boolean
XmUninstallImage(XImage * image)368 XmUninstallImage(
369         XImage *image )
370 {
371    Cardinal old_count;
372    Boolean	ret_val;
373 
374    /*  Check for invalid conditions  */
375 
376    if ((image == NULL) || (image_set == NULL)) return (False);
377 
378    _XmProcessLock();
379    /*  Since we can't index based on the image, search the hash table */
380    /*  until the desired entry is found and then remove it.	      */
381 
382    old_count = _XmHashTableCount(image_set);
383 
384    _XmMapHashTable(image_set, UninstallImageMapProc, image);
385    ret_val = (old_count > _XmHashTableCount(image_set));
386    _XmProcessUnlock();
387 
388    return ret_val;
389 }
390 
391 
392 
393 /************************************************************************
394  *
395  * SymbolicColorUsed
396  *  Used to determine if a given color string is defined as a symbolic
397  *   color in an Xpm image. This is used for caching policy where we
398  *   don't want to cache based on irrelevant colors.
399  *  Note that we don't look if the color is actually used because it
400  *   is too expensive.
401  *
402  ************************************************************************/
403 static Boolean
SymbolicColorUsed(String color_name,XpmColor * xpm_colors,unsigned int ncolors)404 SymbolicColorUsed(String color_name,
405 		  XpmColor * xpm_colors,
406 		  unsigned int ncolors)
407 {
408     Cardinal i, j, data_size ;
409 
410     /* first look if the color is present as a symbolic in the
411        colorTable */
412     for (i = 0; i < ncolors; i++, xpm_colors++) {
413 	if (xpm_colors->symbolic &&
414 	    !strcmp(xpm_colors->symbolic, color_name))
415 	    break ;
416     }
417 
418     if (i == ncolors) return False ;
419 
420     return False ;
421 }
422 
423 
424 /************************************************************************
425  *
426  *  CompleteUnspecColors
427  *     Complete the unspecified_pixel values of an override_colors array
428  *      based on the values coming from the ColorObj or the color cache.
429  *     Does not handle highlight.
430  *     The logic here comes directly from CDE.
431  *
432  *  The above description does not fit with the actual logic of CDE where
433  *  not only the unspecified colors are set here but the whole set of
434  *  symbols! See defect CDExc17529.
435  *
436  ************************************************************************/
437 static void
CompleteUnspecColors(Screen * screen,XpmColorSymbol * override_colors)438 CompleteUnspecColors(
439 		Screen *screen,
440 		XpmColorSymbol *override_colors)
441 {
442     XmPixelSet 	pixelSets[XmCO_NUM_COLORS];
443     int 	colorUse ;
444     Boolean	bgFound = False, fgFound = False, result = False;
445     Pixel	*pixelPtr;
446     Cardinal i, j ;
447     XmAccessColorDataRec loc_acc_color;
448 
449 
450     /* Ask the color obj */
451     if (!(result = XmeGetColorObjData(screen,
452 				      &colorUse, pixelSets, XmCO_NUM_COLORS,
453 				      NULL, NULL, NULL, NULL, NULL)))
454       i = XmCO_NUM_COLORS;
455     else
456       i = 0;
457 
458     /* Look for a pixels set containing the given fg and bg,
459      * no matter whether they are actually the fg and bg of the set...
460      */
461     for ( ; i < XmCO_NUM_COLORS; i++) {
462 	bgFound = False;
463 	fgFound = False;
464 	pixelPtr = (Pixel *)&(pixelSets[i].fg);
465 	for (j = 0; j < 5; j++, pixelPtr++) {
466 	    if (*pixelPtr == override_colors[SYMB_BACKGROUND].pixel)
467 	      bgFound = True;
468 	    else if (*pixelPtr == override_colors[SYMB_FOREGROUND].pixel)
469 	      fgFound = True;
470 	}
471 	if (bgFound && fgFound)
472 	  break;
473     }
474 
475     if (i == XmCO_NUM_COLORS) {
476 	/*
477 	 * We didn't find the bg/fg tuple in any of the Dt colorsets
478 	 * or if the color server is not running, we will now try
479 	 * the color cache.
480 	 */
481 
482       XmColorData *old_colors;
483       XmColorData new_colors;
484 
485       loc_acc_color.background = override_colors[SYMB_BACKGROUND].pixel ;
486 
487       new_colors.screen = screen;
488       new_colors.color_map = DefaultColormapOfScreen(screen);
489       new_colors.background.pixel = loc_acc_color.background ;
490 
491       /* Use motif color set only if already allocated.
492        */
493       if (!result && _XmSearchColorCache(
494 		 (XmLOOK_AT_SCREEN | XmLOOK_AT_CMAP | XmLOOK_AT_BACKGROUND),
495 					 &new_colors, &old_colors)) {
496 	  XmGetColors(screen,
497 		      DefaultColormapOfScreen(screen),
498 		      loc_acc_color.background,
499 		      &loc_acc_color.foreground,
500 		      &loc_acc_color.top_shadow_color,
501 		      &loc_acc_color.bottom_shadow_color,
502 		      &loc_acc_color.select_color);
503       } else {
504 	  /* Cannot generate missing colors */
505 	  return ;
506        }
507     }
508     else {
509 	loc_acc_color.background = pixelSets[i].bg;
510 	loc_acc_color.foreground = pixelSets[i].fg;
511 	loc_acc_color.top_shadow_color = pixelSets[i].ts;
512 	loc_acc_color.bottom_shadow_color = pixelSets[i].bs;
513 	loc_acc_color.select_color = pixelSets[i].sc;
514     }
515 
516     /* Now process the setting for unspecified pixel values.
517        If we're here, all the colors but highlight are available */
518 
519     override_colors[SYMB_BACKGROUND].pixel = loc_acc_color.background ;
520 
521     override_colors[SYMB_FOREGROUND].pixel = loc_acc_color.foreground ;
522 
523     override_colors[SYMB_TOP_SHADOW_COLOR].pixel =
524 	loc_acc_color.top_shadow_color ;
525 
526     override_colors[SYMB_BOTTOM_SHADOW_COLOR].pixel =
527 	loc_acc_color.bottom_shadow_color ;
528 
529     override_colors[SYMB_SELECT_COLOR].pixel = loc_acc_color.select_color ;
530 }
531 
532 
533 /************************************************************************
534  *
535  *  GetOverrideColors
536  *   Given a set of colors in acc_color with values specified or not
537  *   this function fills up an XpmColorSymbol override_colors array to
538  *   be used by the Xpm reader.
539  *   It then calls the ColorObject aware filling proc to find values
540  *   for the still unspecified ones.
541  *   It returns the number of entries to consider in override_colors,
542  *   which can be 2 (background and foreground are always valid),
543  *   NUM_SYMBOLIC_COLORS - 1 (if everything but the highlight could
544  *   be generated), or NUM_SYMBOLIC_COLOR.
545  *
546  ************************************************************************/
547 
548 static int
GetOverrideColors(Screen * screen,XmAccessColorData acc_color,XpmColorSymbol * override_colors)549 GetOverrideColors(
550 		Screen *screen,
551 		XmAccessColorData acc_color,
552 		XpmColorSymbol *override_colors)
553 {
554     Cardinal i, n ;
555 
556     /* init the value fields */
557     for (i=0; i<NUM_SYMBOLIC_COLORS; i++) override_colors[i].value = NULL ;
558 
559     /* proceed each color in turn: acc_color might point to
560        XmUNSPECIFIED_PIXEL, but background/foreground should be valid */
561 
562     override_colors[SYMB_BACKGROUND].name = XmNbackground ;
563     override_colors[SYMB_BACKGROUND].pixel = acc_color->background ;
564 
565     override_colors[SYMB_FOREGROUND].name = XmNforeground ;
566     override_colors[SYMB_FOREGROUND].pixel = acc_color->foreground ;
567 
568     /* Set "none" color to background in case the mask is not used. */
569     override_colors[TRANSPARENT_COLOR].name = NULL ;
570     override_colors[TRANSPARENT_COLOR].value = "None" ;
571     override_colors[TRANSPARENT_COLOR].pixel = acc_color->background ;
572 
573     override_colors[SYMB_TOP_SHADOW_COLOR].name = XmNtopShadowColor ;
574     override_colors[SYMB_TOP_SHADOW_COLOR].pixel =
575 	acc_color->top_shadow_color ;
576 
577     override_colors[SYMB_BOTTOM_SHADOW_COLOR].name = XmNbottomShadowColor ;
578     override_colors[SYMB_BOTTOM_SHADOW_COLOR].pixel =
579 	acc_color->bottom_shadow_color ;
580 
581     override_colors[SYMB_SELECT_COLOR].name = XmNselectColor ;
582     override_colors[SYMB_SELECT_COLOR].pixel = acc_color->select_color ;
583     /* need to hack around selectColor which might be still
584        unspecified while highlight is not (and that woudl break our
585        ordering rule - see below). Use top_shadow color so that select
586        follows its set/unset semantics regarding overriding */
587     if (override_colors[SYMB_SELECT_COLOR].pixel == XmUNSPECIFIED_PIXEL)
588 	override_colors[SYMB_SELECT_COLOR].pixel =
589 	    override_colors[SYMB_TOP_SHADOW_COLOR].pixel ;
590 
591     override_colors[SYMB_HIGHLIGHT_COLOR].name = XmNhighlightColor ;
592     override_colors[SYMB_HIGHLIGHT_COLOR].pixel = acc_color->highlight_color ;
593 
594 
595 
596     /* now call ColorObject aware routine to give it a chance to
597        fill the remaining unspecified pixel field in override_colors */
598 
599     CompleteUnspecColors (screen, override_colors) ;
600 
601     /* Just count the number of valid pixel.
602        This makes a strong assumption on the ordering: if we find
603        5 valid pixels, the 5 first one will be used.
604        This is ok since _XmGetColoredPixmap is only used internally
605        in such a way that this happens to be true: background/foreground
606        are always here, and highlight color is the only one
607        that might be missing after CompleteUnspecColors call.
608        The day XmGetColoredPixmap is promoted public, this simple
609        logic will have to be reviewed */
610 
611     n = 0 ;
612     for (i=0; i<NUM_SYMBOLIC_COLORS; i++)
613 	if (override_colors[i].pixel != XmUNSPECIFIED_PIXEL) n++;
614 
615     return n ;
616 }
617 
618 
619 
620 #ifdef _ORIG_GET_ICON_FILE
621 
622 /******************************************************************
623  *
624  *   GetIconFileName. get a file name using XBMLANGPATH
625  *
626  *****************************************************************/
627 
628 static String
GetIconFileName(Screen * screen,char * icon_name)629 GetIconFileName(
630     Screen *screen,
631     char *icon_name)
632 {
633     char *bmPath;
634     SubstitutionRec	subs[1] ;
635     Boolean user_path ;
636     Display		*display = DisplayOfScreen(screen);
637     char *file_name;
638 
639     subs[0].substitution = icon_name;
640 
641     bmPath = _XmOSInitPath(icon_name, "XBMLANGPATH", &user_path);
642 
643     if (user_path) subs[0].match = 'B';
644     else           subs[0].match = MATCH_CHAR ;
645 
646     file_name = XtResolvePathname(display, "bitmaps", NULL,
647 				  NULL, bmPath, subs, XtNumber(subs), NULL);
648     XtFree (bmPath);
649 
650     return file_name ;
651 
652 }
653 
654 #endif
655 
656 static XtEnum
GetXpmImage(Screen * screen,char * image_name,char * file_name,XmAccessColorData acc_color,XImage ** image,unsigned short * pixmap_resolution,Pixel ** pixels,int * npixels)657 GetXpmImage(
658         Screen *screen,
659         char *image_name, /* original image file name */
660         char *file_name,
661         XmAccessColorData acc_color,
662         XImage **image,
663         unsigned short *pixmap_resolution,
664         Pixel **pixels,
665         int *npixels)
666 {
667     XpmAttributes attrib;
668     int xpmStatus;
669     Boolean useIconFileCache;
670     Boolean useMask;
671     Boolean useColor;
672     XpmColorSymbol override_colors[NUM_SYMBOLIC_COLORS]; /* max */
673     int num_override_colors;
674     XImage * mask_image = NULL ;
675     int hot_x = 0 , hot_y = 0 ;
676     register Display *display = DisplayOfScreen(screen);
677 
678     /* init so that we can call safely XpmFreeAttributes. */
679     attrib.valuemask = 0;
680 
681     /* Init the Xpm attributes to be passed to the reader */
682     attrib.closeness = 40000;
683     attrib.bitmap_format = XYBitmap;
684     attrib.alloc_color = GetCacheColor;
685     attrib.free_colors = FreeCacheColors;
686     attrib.valuemask = XpmCloseness | XpmBitmapFormat | XpmReturnColorTable
687 	| XpmAllocColor | XpmFreeColors | XpmReturnAllocPixels;
688 
689     /* if any symbolic color are defined, used them */
690     if (acc_color &&
691 	(num_override_colors = GetOverrideColors(screen,
692 						 acc_color,
693 						 override_colors)) != 0) {
694 	attrib.colorsymbols = override_colors;
695 	attrib.numsymbols = num_override_colors;
696 	attrib.valuemask |= XpmColorSymbols;
697     }
698 
699     /* ask the color object for information about the
700        use of mask or color */
701     (void)XmeGetIconControlInfo(screen,
702 				&useMask,
703 				&useColor,
704 				&useIconFileCache); /* unused */
705 
706     if (!useColor) {
707 	attrib.depth = 1;
708 	attrib.valuemask |= XpmDepth;
709     }
710 
711     *image = NULL ;
712 
713     xpmStatus = XmeXpmReadFileToImage(display,
714 			      file_name,
715 			      image,
716 			      &mask_image,
717 			      &attrib);
718     if (xpmStatus < 0)
719 	*image = NULL ;
720     else {
721 	/* store allocated colors */
722 	if (pixels) *pixels = attrib.alloc_pixels;
723 	if (npixels) *npixels = attrib.nalloc_pixels;
724 	/* and make sure they won't be free'd */
725 	attrib.alloc_pixels = NULL;
726 	attrib.nalloc_pixels = 0;
727     }
728 
729 
730     if (!(*image))
731 	*image = (XImage *) _XmReadImageAndHotSpotFromFile (display,
732 							    file_name,
733 							    &hot_x, &hot_y);
734 
735     /* get the image "design" resolution */
736     /* in the future: look in the file */
737     if (pixmap_resolution) *pixmap_resolution = 0 ;
738 
739 
740     if (*image) {
741 
742 	/* if the XPM file contained a embedded mask,
743 	   install it using our mask name scheme if the color object
744 	   tell us to do so */
745 	if (mask_image && useMask) {
746 	    char mask_name[255] ;
747 
748 	    _XmOSGenerateMaskName(image_name, mask_name);
749 	    /* if an image already exist under that
750 	       name, nothing will be done */
751 	    _XmInstallImage (mask_image, mask_name, hot_x, hot_y);
752 	}
753 
754 	/* now we have to adjust the passed acc_color */
755 	if (acc_color) {
756 	    if ((*image)->depth == 1) {
757 		/* we've loaded an xbm file, just forget about
758 		   the 'other' symbolic colors, for they
759 		   are not going to be used during pixmap
760 		   generation for depth 1 => pixmap putimage */
761 		acc_color->top_shadow_color = XmUNSPECIFIED_PIXEL;
762 		acc_color->bottom_shadow_color= XmUNSPECIFIED_PIXEL;
763 		acc_color->select_color = XmUNSPECIFIED_PIXEL;
764 		acc_color->highlight_color = XmUNSPECIFIED_PIXEL;
765 		if (acc_color->foreground == XmUNSPECIFIED_PIXEL
766 		    && acc_color->background == XmUNSPECIFIED_PIXEL) {
767 		    acc_color->foreground = 1;
768 		    acc_color->background = 0;
769 		}
770 	    } else {
771 
772 		/* we've loaded a xpm, check which symbolics
773 		   colors were actually used during the read,
774 		   we don't want to remember the unused one
775 		   for the pixmap caching */
776 
777 		if (!SymbolicColorUsed(XmNbackground,
778 				       attrib.colorTable,
779 				       attrib.ncolors))
780 		    acc_color->background = XmUNSPECIFIED_PIXEL;
781 
782 		if (!SymbolicColorUsed(XmNforeground,
783 				       attrib.colorTable,
784 				       attrib.ncolors))
785 		    acc_color->foreground = XmUNSPECIFIED_PIXEL;
786 
787 		if (!SymbolicColorUsed(XmNtopShadowColor,
788 				       attrib.colorTable,
789 				       attrib.ncolors))
790 		    acc_color->top_shadow_color = XmUNSPECIFIED_PIXEL;
791 
792 		if (!SymbolicColorUsed(XmNbottomShadowColor,
793 				       attrib.colorTable,
794 				       attrib.ncolors))
795 		    acc_color->bottom_shadow_color = XmUNSPECIFIED_PIXEL;
796 
797 		if (!SymbolicColorUsed(XmNselectColor,
798 				       attrib.colorTable,
799 				       attrib.ncolors))
800 		    acc_color->select_color = XmUNSPECIFIED_PIXEL;
801 
802 		if (!SymbolicColorUsed(XmNhighlightColor,
803 				       attrib.colorTable,
804 				       attrib.ncolors))
805 		    acc_color->highlight_color = XmUNSPECIFIED_PIXEL;
806 
807 	    }
808 	}
809 
810 
811 	/* install the XImage with that name.
812 	   We do not cache the non-depth 1 ones
813 	   for we don't want to keep them in the image
814 	   cache, since they need color lookup,
815 	   which is done one level up in the pixmap cache */
816 	if (((*image)->depth == 1)
817             && acc_color
818 	    && (acc_color->foreground == 1)
819 	    && (acc_color->background == 0)
820 	    ) {
821 	    _XmInstallImage (*image, image_name, hot_x, hot_y);
822 	    return TRUE ;
823 	} else {
824 	    if (xpmStatus >= 0)
825 		XmeXpmFreeAttributes(&attrib);
826 	    return NOT_CACHED ; /* mean the image can be destroyed
827 				   after it is used */
828 	}
829     }
830 
831     if (xpmStatus >= 0)
832 	XmeXpmFreeAttributes(&attrib);
833 
834     return FALSE;
835 }
836 
837 /************************************************************************
838  *
839  *  GetImage
840  *	Main routine of the image cache part.
841  *
842  ************************************************************************/
843 static XtEnum
GetImage(Screen * screen,char * image_name,XmAccessColorData acc_color,XImage ** image,unsigned short * pixmap_resolution,Pixel ** pixels,int * npixels)844 GetImage(
845 	 Screen *screen,
846 	 char *image_name,
847          XmAccessColorData acc_color,
848 	 XImage **image,
849 	 unsigned short * pixmap_resolution,
850 	 Pixel **pixels,	/* allocated pixels */
851 	 int *npixels)
852 {
853     static XImage  * built_in_image = NULL;
854     register Display *display = DisplayOfScreen(screen);
855     ImageData *entry;
856     char *file_name;
857     XtEnum return_value;
858 #if defined (PNG_SUPPORTED) || defined (JPEG_SUPPORTED)
859     FILE *infile;
860     int rc;
861 #endif
862 
863     /* init for when we go thru the image cache first */
864     if (pixmap_resolution) *pixmap_resolution = 0 ;
865 
866     if (pixels) *pixels = NULL;
867     if (npixels) *npixels = 0;
868 
869     /***  Check for the initial allocation of the image set array  */
870 
871     if (image_set == NULL) InitializeImageSet();
872 
873     if (!image_name) return FALSE ;
874 
875     /*** look in the XImage cache first */
876     _XmProcessLock();
877     entry = (ImageData*) _XmGetHashEntry(image_set, image_name);
878     _XmProcessUnlock();
879 
880 
881     if (entry) {
882 
883 	/*  If the image is a builtin image then get it.  */
884 
885 	if (entry->builtin_data) {
886 	    /* there is one builtin XImage shared by all builtins,
887 	       only the data part change every time a query is made */
888 	    _XmProcessLock();
889 	    if (!built_in_image) {
890 		/* update that with new R6 init image stuff when out */
891 		_XmCreateImage(built_in_image, display, NULL,
892 			       16, 16, MSBFirst);
893 	    }
894 
895 	    built_in_image->data = (char *) entry->builtin_data;
896 	    _XmProcessUnlock();
897 	    *image = built_in_image;
898 
899 	} else {
900 
901 	    /* other entry found are just fine, set the image and return  */
902 
903 	    *image = entry->image ;
904 	}
905 
906 	return TRUE;
907     }
908 
909     /*** if no entry, try to read a new file and cache it
910          only if it is a bitmap */
911 
912 #ifdef _ORIG_GET_ICON_FILE
913     file_name = GetIconFileName(screen, image_name);
914 #else
915     file_name = XmGetIconFileName(screen, NULL, image_name,
916 				  NULL, XmUNSPECIFIED_ICON_SIZE);
917 #endif
918 
919     if (!file_name) {
920         return FALSE;
921     }
922 
923 #if defined (JPEG_SUPPORTED) || defined (PNG_SUPPORTED)
924     if (!(infile = fopen(file_name, "rb"))) {
925         return FALSE;
926     }
927 
928 #ifdef JPEG_SUPPORTED
929     rc = _XmJpegGetImage(screen, infile, image);
930 #endif
931 #if defined (JPEG_SUPPORTED) && defined (PNG_SUPPORTED)
932     if (rc == 1) { /* not a jpeg file */
933 #endif
934 #ifdef PNG_SUPPORTED
935         Pixel background;
936 
937         if (acc_color)
938             background = acc_color->background;
939         else
940             background = 0;
941 
942         if (background == XmUNSPECIFIED_PIXEL)
943             background = 0; /* XXX is if OK? */
944 #endif
945 #if defined (JPEG_SUPPORTED) && defined (PNG_SUPPORTED)
946         rewind(infile);
947 #endif
948 #ifdef PNG_SUPPORTED
949         rc = _XmPngGetImage(screen, infile, background, image);
950 #endif
951 #if defined (JPEG_SUPPORTED) && defined (PNG_SUPPORTED)
952     }
953 #endif
954 
955     fclose(infile);
956 
957     if (rc > 1) {
958         return_value = FALSE;
959     } else if (rc == 0) {
960         return_value = NOT_CACHED;
961     } else {
962 #endif
963         return_value =
964             GetXpmImage(screen, image_name, file_name, acc_color,
965                     image, pixmap_resolution, pixels, npixels);
966 #if defined (JPEG_SUPPORTED) || defined (PNG_SUPPORTED)
967     }
968 #endif
969 
970     XtFree(file_name);
971 
972     return return_value;
973 }
974 
975 /*** Keep this one in here, this is the only entry point to
976      the Image cache. It can be used to duplicate them, etc */
977 Boolean
_XmGetImage(Screen * screen,char * image_name,XImage ** image)978 _XmGetImage(
979 	Screen *screen,
980 	char *image_name,
981 	XImage **image )
982 {
983     return GetImage(screen, image_name, NULL, image, NULL, NULL, NULL) ;
984 }
985 
986 
987 /************************************************************************
988 *
989 *  _XmInImageCache
990 *       Used by IconFile.c
991 *
992 ************************************************************************/
993 
994 Boolean
_XmInImageCache(String image_name)995 _XmInImageCache(
996 	String image_name)
997 {
998     XtPointer	ret_val;
999 
1000     if (!image_set) return False ;
1001     _XmProcessLock();
1002     ret_val = _XmGetHashEntry(image_set, image_name);
1003     _XmProcessUnlock();
1004 
1005     return (ret_val != NULL) ;
1006 }
1007 
1008 
1009 
1010 
1011 
1012 
1013 
1014 
1015 
1016 /*** PIXMAP CACHE NOW ***/
1017 
1018 /** static dependencies with Image part:
1019   * GetImage(), ImageData&image_set, HashString
1020   **/
1021 /** static dependencies with Color part:
1022   * FreeCacheColors()
1023   **/
1024 
1025 
1026 
1027 
1028 static Boolean
ComparePixmaps(XmHashKey key_1,XmHashKey key_2)1029 ComparePixmaps (XmHashKey key_1,
1030 		XmHashKey key_2)
1031 {
1032   PixmapData *data_1 = (PixmapData *) key_1;
1033   PixmapData *data_2 = (PixmapData *) key_2;
1034 
1035     /* Check for a matching pixmap using screen and pixmap */
1036 
1037     return
1038 	(data_1->screen == data_2->screen &&
1039 	 data_1->pixmap == data_2->pixmap) ;
1040 }
1041 
1042 static Boolean
ComparePixmapDatas(XmHashKey key_1,XmHashKey key_2)1043 ComparePixmapDatas (XmHashKey key_1,
1044 		    XmHashKey key_2)
1045 {
1046   PixmapData *data_1 = (PixmapData *) key_1;
1047   PixmapData *data_2 = (PixmapData *) key_2;
1048 
1049     /* Check for a matching pixmap using depth, screen, name and
1050        colors info + print_resolution/scaling_ratio and print_shell */
1051     /* if a negative depth is given, we must look for a matching
1052        pixmap of -depth or 1 */
1053 
1054     return
1055 	((data_2->pixmap == XmUNSPECIFIED_PIXMAP ||
1056 	  data_1->pixmap == data_2->pixmap) &&
1057 	 data_1->image_name != NULL &&
1058 	 data_2->image_name != NULL &&
1059 	 strcmp (data_1->image_name, data_2->image_name) == 0  &&
1060 
1061 	 (data_1->screen == data_2->screen) &&
1062 
1063 	 ( /* ratio == 0 means print resolution is used */
1064 	  (data_1->scaling_ratio == data_2->scaling_ratio &&
1065 	   data_1->scaling_ratio) ||
1066 	  (data_1->print_resolution == data_2->print_resolution &&
1067 	   !data_1->scaling_ratio)) &&
1068 
1069 	 (data_1->print_shell == data_2->print_shell) &&
1070 
1071 	 ((data_1->depth == data_2->depth)  ||
1072 	  (data_2->depth < 0 && data_1->depth == -data_2->depth) ||
1073 	  (data_2->depth < 0 && data_1->depth == 1)) &&
1074 
1075 	 ((data_1->acc_color->foreground == data_2->acc_color->foreground) ||
1076 	  (data_2->depth < 0 && data_1->acc_color->foreground == 1) ||
1077 	  (data_1->acc_color->foreground == XmUNSPECIFIED_PIXEL) ||
1078 	  (data_2->acc_color->foreground == XmUNSPECIFIED_PIXEL))          &&
1079 	 ((data_1->acc_color->background == data_2->acc_color->background) ||
1080 	  (data_2->depth < 0 && data_1->acc_color->background == 0) ||
1081 	  (data_1->acc_color->background == XmUNSPECIFIED_PIXEL)||
1082 	  (data_2->acc_color->background == XmUNSPECIFIED_PIXEL))          &&
1083 
1084 	 ((data_1->acc_color->top_shadow_color ==
1085 	   data_2->acc_color->top_shadow_color) ||
1086 	  (data_1->acc_color->top_shadow_color == XmUNSPECIFIED_PIXEL)||
1087 	  (data_2->acc_color->top_shadow_color == XmUNSPECIFIED_PIXEL))     &&
1088 	 ((data_1->acc_color->bottom_shadow_color
1089 	   == data_2->acc_color->bottom_shadow_color)||
1090 	  (data_1->acc_color->bottom_shadow_color == XmUNSPECIFIED_PIXEL)||
1091 	  (data_2->acc_color->bottom_shadow_color == XmUNSPECIFIED_PIXEL))  &&
1092 	 ((data_1->acc_color->select_color ==
1093 	   data_2->acc_color->select_color) ||
1094 	  (data_1->acc_color->select_color == XmUNSPECIFIED_PIXEL)||
1095 	  (data_2->acc_color->select_color == XmUNSPECIFIED_PIXEL))       &&
1096 	 ((data_1->acc_color->highlight_color ==
1097 	   data_2->acc_color->highlight_color) ||
1098 	  (data_1->acc_color->highlight_color == XmUNSPECIFIED_PIXEL) ||
1099 	  (data_2->acc_color->highlight_color == XmUNSPECIFIED_PIXEL))) ;
1100 }
1101 
1102 /* Hash a Pixmap entry. */
1103 static XmHashValue
HashPixmap(XmHashKey key)1104 HashPixmap (XmHashKey key)
1105 {
1106   PixmapData *data = (PixmapData *) key;
1107 
1108   return ((long)data->screen + data->pixmap);
1109 }
1110 
1111 /* Hash a PixmapData entry. Reuse the string hash function */
1112 static XmHashValue
HashPixmapData(XmHashKey key)1113 HashPixmapData (XmHashKey key)
1114 {
1115   PixmapData *data = (PixmapData *) key;
1116 
1117   return ((long)data->screen + HashString ((XmHashKey)data->image_name));
1118 }
1119 
1120 /************************************************************************
1121  *
1122  *  InitializePixmapSets
1123  *	Initialize the pixmap sets.
1124  *
1125  ************************************************************************/
1126 static void
InitializePixmapSets(void)1127 InitializePixmapSets( void )
1128 {
1129     /* Allocate the pixmap hash tables.
1130      One for the regular XmGetPixmap lookup, one for the
1131      XmeGetPixmapData lookup */
1132     assert (pixmap_data_set == NULL && pixmap_set == NULL);
1133 
1134     _XmProcessLock();
1135     pixmap_data_set = _XmAllocHashTable (100, ComparePixmapDatas,
1136 					 HashPixmapData);
1137 
1138     pixmap_set = _XmAllocHashTable (100, ComparePixmaps, HashPixmap);
1139     _XmProcessUnlock();
1140 
1141 }
1142 
1143 /************************************************************************
1144  *
1145  *  _XmCachePixmap
1146  *	Install a pixmap into the pixmap cache.  This is used to add
1147  *	cached pixmaps which have no XImage associated with them.
1148  *      This one you can pass depth and size info, if you don't,
1149  *      the X server will be queried: very expensive.
1150  *
1151  ************************************************************************/
1152 Boolean
_XmCachePixmap(Pixmap pixmap,Screen * screen,char * image_name,Pixel foreground,Pixel background,int depth,Dimension width,Dimension height)1153 _XmCachePixmap(
1154         Pixmap pixmap,
1155         Screen *screen,
1156         char *image_name,
1157         Pixel foreground,
1158         Pixel background,
1159         int depth,
1160         Dimension width,
1161         Dimension height)
1162 {
1163    PixmapData * pix_entry;
1164 
1165    Window root;
1166    int x,y;
1167    unsigned int loc_width, loc_height, border_width, loc_depth;
1168 
1169    /*  Error checking  */
1170    if (image_name == NULL) return (False);
1171 
1172    if (!pixmap_data_set) InitializePixmapSets() ;
1173 
1174    /* if no information was given, get it from the server */
1175    if (!(width && height && depth))
1176        XGetGeometry(DisplayOfScreen(screen), pixmap, &root, &x, &y,
1177 		    &loc_width, &loc_height, &border_width, &loc_depth);
1178    else {
1179 	   loc_width = width ;
1180 	   loc_height = height ;
1181 	   loc_depth = depth ;
1182        }
1183 
1184    /*  Allocate the cache structure and put it into the list  */
1185 
1186    pix_entry = XtNew (PixmapData);
1187 
1188    pix_entry->screen = screen;
1189    pix_entry->acc_color = XtNew(XmAccessColorDataRec);
1190    pix_entry->acc_color->foreground = foreground;
1191    pix_entry->acc_color->background = background;
1192    pix_entry->acc_color->top_shadow_color = XmUNSPECIFIED_PIXEL;
1193    pix_entry->acc_color->bottom_shadow_color = XmUNSPECIFIED_PIXEL;
1194    pix_entry->acc_color->select_color = XmUNSPECIFIED_PIXEL;
1195    pix_entry->acc_color->highlight_color = XmUNSPECIFIED_PIXEL;
1196    pix_entry->depth = loc_depth;
1197    pix_entry->width = loc_width;
1198    pix_entry->height = loc_height;
1199    pix_entry->image_name = XtNewString(image_name);
1200    pix_entry->pixmap = pixmap;
1201    pix_entry->reference_count = 1;
1202    pix_entry->print_resolution = 100 ;
1203    pix_entry->print_shell = NULL ;
1204    pix_entry->scaling_ratio = 1 ;
1205    pix_entry->pixels = NULL;
1206    pix_entry->npixels = 0;
1207 
1208    _XmProcessLock();
1209    _XmAddHashEntry(pixmap_set, (XmHashKey)pix_entry, (XtPointer)pix_entry);
1210 
1211    /* Only add pixmaps not issued from XmeGetPixmapData to the "real" table */
1212    if (0 != strcmp(image_name, DIRECT_PIXMAP_CACHED))
1213        _XmAddHashEntry(pixmap_data_set, (XmHashKey)pix_entry,
1214 		       (XtPointer)pix_entry);
1215    _XmProcessUnlock();
1216 
1217    return (True);
1218 }
1219 
1220 
1221 
1222 /********************************************************************/
1223 
1224 Boolean
_XmGetPixmapData(Screen * screen,Pixmap pixmap,char ** image_name,int * depth,Pixel * foreground,Pixel * background,int * hot_x,int * hot_y,unsigned int * width,unsigned int * height)1225 _XmGetPixmapData(
1226 		   Screen *screen,
1227 		   Pixmap pixmap,
1228 		   char **image_name,
1229 		   int *depth,
1230 		   Pixel *foreground,
1231 		   Pixel *background,
1232 		   int *hot_x,
1233 		   int *hot_y,
1234 		   unsigned int *width,
1235 		   unsigned int *height)
1236 /* no pixmap_resolution returned... */
1237 {
1238     PixmapData pix_data, *pix_entry;
1239     ImageData * entry;
1240 
1241     if (!pixmap_data_set) InitializePixmapSets() ;
1242 
1243     /*  checks for a matching screen and pixmap.            */
1244 
1245     pix_data.screen = screen ;
1246     pix_data.pixmap = pixmap ;
1247 
1248     _XmProcessLock();
1249     if ((pix_entry = (PixmapData*)
1250 	 _XmGetHashEntry(pixmap_set, (XmHashKey)&pix_data)) != NULL) {
1251 
1252 	*foreground = pix_entry->acc_color->foreground;
1253 	*background = pix_entry->acc_color->background;
1254 	*depth = pix_entry->depth;
1255 	*image_name = pix_entry->image_name;
1256 	*width = pix_entry->width;
1257 	*height = pix_entry->height;
1258 	/* try to get the hot spot data from the image cache */
1259 	if (image_set)  {
1260 	    entry = (ImageData *) _XmGetHashEntry(image_set, *image_name);
1261 	    if (entry) {
1262 		*hot_x = entry->hot_x;
1263 		*hot_y = entry->hot_y;
1264 	    }
1265 	}
1266 	_XmProcessUnlock();
1267 	return True;
1268     }
1269     _XmProcessUnlock();
1270     return False ;
1271 }
1272 
1273 
1274 
1275 /*******************************************************************/
1276 /* the real one, used by PixConv and locally too */
1277 Pixmap
_XmGetScaledPixmap(Screen * screen,Widget widget,char * image_name,XmAccessColorData acc_color,int depth,int only_if_exists,double scaling_ratio)1278 _XmGetScaledPixmap(
1279     Screen *screen,
1280     Widget widget,
1281     char *image_name,
1282     XmAccessColorData acc_color,
1283     int depth,
1284 #if NeedWidePrototypes
1285     int only_if_exists,
1286 #else
1287     Boolean only_if_exists,
1288 #endif /* NeedWidePrototypes */
1289     double scaling_ratio)
1290 {
1291     Display * display = DisplayOfScreen(screen);
1292     XImage * image;
1293     Pixmap   pixmap;
1294     GC gc ;
1295     XtEnum ret ;
1296     PixmapData pix_data, *pix_entry ;
1297     unsigned short pixmap_resolution ;
1298     Pixel *pixels;		/* allocated colors */
1299     int npixels;
1300     int old_image_format;
1301     char *old_image_data = NULL;
1302 
1303     /*  Error checking  */
1304     if (image_name == NULL) return (XmUNSPECIFIED_PIXMAP);
1305 
1306     if (!pixmap_data_set) InitializePixmapSets() ;
1307 
1308     /* if screen not provided, widget has to be! */
1309     if (!screen) screen = XtScreen(widget);
1310 
1311     /* since more than one printers can attach to one screen,
1312        we need to use the print shell in the caching */
1313     /* since resolution can be dynamic for a printer, we need
1314        to use the resolution too, when scaling is 0 */
1315     pix_data.screen = screen ;
1316     pix_data.image_name = image_name ;
1317     pix_data.depth = depth ;
1318     pix_data.acc_color = acc_color ;
1319     pix_data.print_resolution = 100 ; /* default */
1320     pix_data.scaling_ratio = scaling_ratio ;
1321 
1322     pix_data.pixmap = XmUNSPECIFIED_PIXMAP;
1323 
1324     /* find out the print shell ancestor */
1325     pix_data.print_shell = widget ;
1326     while(pix_data.print_shell && !XmIsPrintShell(pix_data.print_shell))
1327 	pix_data.print_shell = XtParent(pix_data.print_shell);
1328     /* pix_data.print_shell might be NULL here */
1329 
1330 #ifdef PRINTING_SUPPORTED
1331     /* scaling_ratio == 0 means use print_resolution and pixmap_resolution
1332        in scaling - so first find out the print_resolution, since it
1333        is used in caching */
1334     if (!scaling_ratio && pix_data.print_shell)
1335 	pix_data.print_resolution =
1336 	  ((XmPrintShellWidget)pix_data.print_shell)->print.print_resolution ;
1337 #endif
1338 
1339     /* if scaling_ratio a real number, like 1 or 1.2
1340        print_resolution still 100 and will not be used */
1341 
1342     /* look if we have a match and return it */
1343     _XmProcessLock();
1344     if ((pix_entry = (PixmapData*)
1345 	 _XmGetHashEntry(pixmap_data_set, (XmHashKey)&pix_data)) != NULL) {
1346 	pix_entry->reference_count++;
1347 	_XmProcessUnlock();
1348 	return pix_entry->pixmap ;
1349     }
1350     _XmProcessUnlock();
1351 
1352     /* The desired pixmap is not already cached.  Quit now or create it. */
1353     if (only_if_exists)
1354 	return (XmUNSPECIFIED_PIXMAP);
1355 
1356     /* no pixmap found, look for an XImage.
1357        generate a new one if needed.
1358        GetImage can return a bitmap or a pixmap XImage */
1359     /* GetImage modify the acc_color struct to update the
1360        colors that are not used during reading:
1361          - for xbm, everything but foreground and background.
1362 	 - for xpm, on a case by case basis, depending
1363 	 if the corresponding symbolic color was used. */
1364 
1365     if (!(ret = GetImage(screen, image_name, acc_color, &image,
1366 			 &pixmap_resolution, &pixels, &npixels)))
1367 	return (XmUNSPECIFIED_PIXMAP);
1368 
1369     /* now find how much we need to scale this baby */
1370 
1371     /* compute the real ratio to be used in PutImage */
1372     if (!pix_data.scaling_ratio) {
1373 	/* if scaling ratio is real, like 1.2, the pixmap resolution is
1374 	   not used, neither is the print_resolution */
1375 
1376 	if (!pixmap_resolution) {
1377 	    /* GetImage returns the resolution for which the image
1378 	       was designed. if none was provided in the file, it's 0,
1379 	       in which case, the print shell default resolution
1380 	       for pixmap is used */
1381 
1382 #ifdef PRINTING_SUPPORTED
1383 	    if (pix_data.print_shell)
1384 		pixmap_resolution =
1385 		    ((XmPrintShellWidget)pix_data.print_shell)
1386 			->print.default_pixmap_resolution ;
1387 	    else
1388 #endif /* PRINTING_SUPPORTED */
1389 		pixmap_resolution = 100 ;
1390 	}
1391 
1392 	pix_data.scaling_ratio = (double)pix_data.print_resolution /
1393 	    (double)pixmap_resolution ;
1394     }
1395 
1396 
1397     /* now we treat the -depth case: if a negative depth was given
1398        then xbm file should map into bitmap and xpm into pixmap */
1399 
1400     if (depth < 0) {
1401 	if (image->depth == 1)
1402 	  depth = 1 ;
1403 	else
1404 	  depth = -depth ;
1405     }
1406 
1407     /* now check the validity of the image depth.  XPutImage can
1408        only handle unequal depths for bitmaps. */
1409     if ((image->depth != depth) && (image->depth != 1))
1410 	return (XmUNSPECIFIED_PIXMAP);
1411 
1412     /* force the foreground/background if a Bitmap
1413        is returned. These values are going to go in the cache
1414        too, so we will have to remember this forcing for the
1415        case -depth: you ask for -depth and some
1416        foreground/background, that should match a depth 1
1417        with 1/0. Look at ComparePixmapDatas above for details */
1418 
1419     if (depth == 1) {
1420 	acc_color->foreground = 1;
1421 	acc_color->background = 0;
1422     }
1423 
1424     /* XPutImage will only deepen bitmaps -- fake it with pixmaps. */
1425     old_image_format = image->format;
1426     if (image->depth == 1) {
1427       switch(image->format)
1428 	{
1429 	case XYBitmap:
1430 	  /* XPutImage will do the right thing. */
1431 	  break;
1432 
1433 	case XYPixmap:
1434 	  /* We're going to muck with the shared image... */
1435 	  if (ret != NOT_CACHED)
1436 	    _XmProcessLock();
1437 
1438 	  /* Assume black == fg in the image. */
1439 	  if ((BlackPixelOfScreen(screen) == 0) ||
1440 	      (WhitePixelOfScreen(screen) == 1))
1441 	    {
1442 	      /* Flip the bits so fg == 1 in the image. */
1443 	      register int nbytes = image->height * image->bytes_per_line;
1444 	      register int byte;
1445 
1446 	      /* Image data may be constant, so we must copy it. */
1447 	      old_image_data = image->data;
1448 	      image->data = XtMalloc(nbytes);
1449 
1450 	      for (byte = 0; byte < nbytes; byte++)
1451 		image->data[byte] = ~old_image_data[byte];
1452 	    }
1453 
1454 	  /* In this depth-1 case the image formats are equivalent. */
1455 	  image->format = XYBitmap;
1456 	  break;
1457 
1458 	case ZPixmap:
1459 	  /* Assume the application really wants BadMatch if (depth != 1). */
1460 	  break;
1461 
1462 	default:
1463 	  assert(FALSE);
1464 	}
1465     }
1466 
1467 
1468     /*
1469      * Create a pixmap to hold the image, allocate a new pixmap
1470      * cache entry, put the cache entry in the tables.
1471      */
1472 
1473     pix_entry = XtNew (PixmapData);
1474 
1475     pix_entry->screen = screen;
1476     pix_entry->acc_color = XtNew(XmAccessColorDataRec);
1477     memcpy((void*)pix_entry->acc_color, (void*)acc_color,
1478 	   sizeof(XmAccessColorDataRec));
1479     pix_entry->depth = depth;
1480     pix_entry->image_name = XtNewString(image_name);
1481     pix_entry->print_shell = pix_data.print_shell;
1482     pix_entry->print_resolution = pix_data.print_resolution ;
1483     pix_entry->pixels = pixels;
1484     pix_entry->npixels = npixels;
1485 
1486     /* use scaling_ratio for caching: as 0, in which case the
1487        print resolution will be used, or 1, no scaling, or a real ratio.
1488        That's because when we enter this function, we don't have
1489        pixmap_resolution to cache against, and also because
1490        print_resolution might change for the same print shell */
1491     pix_entry->scaling_ratio = scaling_ratio ;
1492 
1493     /* use the pixmap scaling ratio for printing  */
1494     pix_entry->width = image->width * pix_data.scaling_ratio ;
1495     pix_entry->height = image->height * pix_data.scaling_ratio ;
1496 
1497     pixmap = XCreatePixmap (display, RootWindowOfScreen(screen),
1498 			    pix_entry->width,
1499 			    pix_entry->height,
1500 			    depth);
1501 
1502     pix_entry->pixmap = pixmap;
1503     pix_entry->reference_count = 1;
1504 
1505     /* put the new entry in both tables: the table used for
1506        this routine and the table used in XmeGetPixmapData */
1507     _XmProcessLock();
1508     _XmAddHashEntry(pixmap_set, (XmHashKey)pix_entry, (XtPointer)pix_entry);
1509     _XmAddHashEntry(pixmap_data_set, (XmHashKey)pix_entry,
1510 		    (XtPointer)pix_entry);
1511     _XmProcessUnlock();
1512 
1513     /*  Set up a gc for the image to pixmap copy, store the image  */
1514     /*  into the pixmap and return the pixmap.                     */
1515 
1516     gc = GetGCForPutImage(screen, pix_entry->print_shell,
1517 			  image, pixmap, depth,
1518 			  acc_color->foreground,
1519 			  acc_color->background);
1520 
1521     /* transfer and scale the image */
1522     _XmPutScaledImage (display, pixmap, gc, image,
1523 		       0, 0, 0, 0, image->width, image->height,
1524 		       pix_entry->width, pix_entry->height);
1525 
1526     /* Destroy non-cached XImage now that we've cached the pixmap. */
1527     if (ret == NOT_CACHED)
1528       {
1529 	XDestroyImage(image) ;
1530 	if (old_image_data)
1531 	  XtFree(image->data);
1532       }
1533     else if (image->format != old_image_format)
1534       {
1535 	/* Undo the XYPixmap to XYBitmap conversion done earlier. */
1536 	image->format = old_image_format;
1537 	assert(old_image_format == XYPixmap);
1538 
1539 	if (old_image_data)
1540 	  {
1541 	    XtFree(image->data);
1542 	    image->data = old_image_data;
1543 	  }
1544 
1545 	/* We're done mangling the image. */
1546 	_XmProcessUnlock();
1547       }
1548 
1549     return (pixmap);
1550 }
1551 
1552 
1553 /*******************************************************************
1554  *
1555  * _XmGetColoredPixmap
1556  *   a improved version of XmGetPixmapByDepth that lets the caller
1557  *   specify more color information usable during the loading
1558  *   of the pixmap file to override symbolic colors.
1559  *
1560  *   It also supports the negative depth convention where if a -depth
1561  *   is given, xbm file give Bitmap and xpm file give Pixmap, while
1562  *   with positive depth, all files give Pixmap result.
1563  *
1564  *   Now a wrapper, but still used by IconG, MessageB, and Text directly.
1565  *
1566  *******************************************************************/
1567 Pixmap
_XmGetColoredPixmap(Screen * screen,char * image_name,XmAccessColorData acc_color,int depth,int only_if_exists)1568 _XmGetColoredPixmap(Screen *screen,
1569 		    char *image_name,
1570 		    XmAccessColorData acc_color,
1571 		    int depth,
1572 #if NeedWidePrototypes
1573 		   int only_if_exists)
1574 #else
1575                    Boolean only_if_exists)
1576 #endif /* NeedWidePrototypes */
1577 {
1578     return _XmGetScaledPixmap (screen, NULL,
1579 			       image_name, acc_color, depth,
1580 			       only_if_exists, 1); /* no scaling */
1581 }
1582 
1583 Pixmap
XmGetScaledPixmap(Widget widget,char * image_name,Pixel foreground,Pixel background,int depth,double scaling_ratio)1584 XmGetScaledPixmap(
1585     Widget widget,
1586     char *image_name,
1587     Pixel foreground,
1588     Pixel background,
1589     int depth,
1590     double scaling_ratio)
1591 {
1592     XmAccessColorDataRec acc_color_rec;
1593     Pixmap ret_val;
1594     XtAppContext app = XtWidgetToApplicationContext(widget);
1595 
1596     _XmAppLock(app);
1597     _XmProcessLock();
1598     acc_color_rec.foreground = foreground ;
1599     acc_color_rec.background = background ;
1600     acc_color_rec.top_shadow_color = XmUNSPECIFIED_PIXEL ;
1601     acc_color_rec.bottom_shadow_color = XmUNSPECIFIED_PIXEL ;
1602     acc_color_rec.select_color = XmUNSPECIFIED_PIXEL ;
1603     acc_color_rec.highlight_color = XmUNSPECIFIED_PIXEL ;
1604     ret_val = _XmGetScaledPixmap(XtScreen(widget), widget, image_name,
1605 				 &acc_color_rec, depth, False,
1606 				 scaling_ratio);
1607     _XmProcessUnlock();
1608     _XmAppUnlock(app);
1609 
1610     return  ret_val;
1611 
1612 }
1613 
1614 
1615 /*******************************************************************
1616  *
1617  * XmGetPixmapByDepth.
1618  *  create a pixmap from the image_name.  foreground and background
1619  *  must be valid values. For depth 1 they should be 1 and 0
1620  *  respectively.
1621  *
1622  *******************************************************************/
1623 Pixmap
XmGetPixmapByDepth(Screen * screen,char * image_name,Pixel foreground,Pixel background,int depth)1624 XmGetPixmapByDepth(
1625     Screen *screen,
1626     char *image_name,
1627     Pixel foreground,
1628     Pixel background,
1629     int depth)
1630 {
1631     XmAccessColorDataRec acc_color_rec;
1632     Pixmap ret_val;
1633     XtAppContext app = XtDisplayToApplicationContext(
1634 				DisplayOfScreen(screen));
1635 
1636     _XmAppLock(app);
1637     _XmProcessLock();
1638     acc_color_rec.foreground = foreground ;
1639     acc_color_rec.background = background ;
1640     acc_color_rec.top_shadow_color = XmUNSPECIFIED_PIXEL ;
1641     acc_color_rec.bottom_shadow_color = XmUNSPECIFIED_PIXEL ;
1642     acc_color_rec.select_color = XmUNSPECIFIED_PIXEL ;
1643     acc_color_rec.highlight_color = XmUNSPECIFIED_PIXEL ;
1644     ret_val = _XmGetScaledPixmap(screen, NULL, image_name,
1645 				 &acc_color_rec, depth, False,
1646 				 1);
1647     _XmProcessUnlock();
1648     _XmAppUnlock(app);
1649 
1650     return  ret_val;
1651 }
1652 
1653 
1654 /************************************************************************
1655  *
1656  *  This one is deprecated, but keep it in here, it was public.
1657  *
1658  ************************************************************************/
1659 
1660 Pixmap
XmGetPixmap(Screen * screen,char * image_name,Pixel foreground,Pixel background)1661 XmGetPixmap(
1662         Screen *screen,
1663         char *image_name,
1664         Pixel foreground,
1665         Pixel background )
1666 {
1667     Pixmap	ret_val;
1668 
1669     XtAppContext app = XtDisplayToApplicationContext(
1670 				DisplayOfScreen(screen));
1671     _XmAppLock(app);
1672     ret_val = XmGetPixmapByDepth(screen, image_name, foreground, background,
1673 				 DefaultDepthOfScreen(screen));
1674     _XmAppUnlock(app);
1675 
1676     return (ret_val);
1677 }
1678 
1679 
1680 
1681 /************************************************************************
1682 *
1683 *  XmeGetMask
1684 *
1685 ************************************************************************/
1686 Pixmap
XmeGetMask(Screen * screen,char * image_name)1687 XmeGetMask(
1688         Screen *screen,
1689         char *image_name)
1690 {
1691     char 		mask_name[256];
1692     Pixmap		ret_val;
1693     XtAppContext app = XtDisplayToApplicationContext(
1694 				DisplayOfScreen(screen));
1695 
1696     _XmAppLock(app);
1697 
1698     _XmProcessLock();
1699     _XmOSGenerateMaskName(image_name, mask_name);
1700     _XmProcessUnlock();
1701 
1702     ret_val = XmGetPixmapByDepth(screen, mask_name, 1, 0, 1);
1703 
1704     _XmAppUnlock(app);
1705     return ret_val;
1706 }
1707 
1708 
1709 /************************************************************************
1710  *
1711  *  XmDestroyPixmap
1712  *	Use the pixmap table (pixmap/screen) to find the pixmap,
1713  *      then remove it from both pixmap and pixmap_data tables.
1714  *
1715  ************************************************************************/
1716 Boolean
XmDestroyPixmap(Screen * screen,Pixmap pixmap)1717 XmDestroyPixmap(
1718         Screen *screen,
1719         Pixmap pixmap )
1720 {
1721    PixmapData pix_data, *pix_entry ;
1722    XtAppContext app;
1723 
1724    /*  Check for invalid conditions  */
1725 
1726    if (screen == NULL || pixmap == 0 || pixmap_set == NULL)
1727      return (False);
1728 
1729    app = XtDisplayToApplicationContext(
1730 				DisplayOfScreen(screen));
1731 
1732    _XmAppLock(app);
1733    _XmProcessLock();
1734 
1735    pix_data.screen = screen ;
1736    pix_data.pixmap = pixmap ;
1737 
1738    if ((pix_entry = (PixmapData*)
1739 	_XmGetHashEntry(pixmap_set, (XmHashKey)&pix_data)) != NULL) {
1740       pix_entry->reference_count--;
1741       if (pix_entry->reference_count == 0) {
1742 	  _XmRemoveHashEntry (pixmap_data_set, pix_entry);
1743 	  _XmRemoveHashEntry (pixmap_set, pix_entry);
1744    	  if (0 != strcmp(pix_entry->image_name, DIRECT_PIXMAP_CACHED))
1745 	    XFreePixmap(DisplayOfScreen(pix_entry->screen), pix_entry->pixmap);
1746 	  XtFree(pix_entry->image_name);
1747 	  XtFree((char*)pix_entry->acc_color);
1748 	  if (pix_entry->pixels) {
1749 	      FreeCacheColors(DisplayOfScreen(pix_entry->screen),
1750 			      DefaultColormapOfScreen(pix_entry->screen),
1751 			      pix_entry->pixels, pix_entry->npixels, NULL);
1752 	      XmeXpmFree(pix_entry->pixels);
1753 	  }
1754 	  XtFree((char*)pix_entry);
1755       }
1756 
1757       _XmProcessUnlock();
1758       _XmAppUnlock(app);
1759       return True;
1760   }
1761 
1762   _XmProcessUnlock();
1763   _XmAppUnlock(app);
1764   return False;
1765 }
1766 
1767 
1768 /* Compare two gc entry. Only care about the colors for depth 1 */
1769 static Boolean
CompareGCDatas(XmHashKey key_1,XmHashKey key_2)1770 CompareGCDatas (XmHashKey key_1,
1771 		XmHashKey key_2)
1772 {
1773   GCData *data_1 = (GCData *) key_1;
1774   GCData *data_2 = (GCData *) key_2;
1775 
1776   return ((data_1->screen == data_2->screen) &&
1777 	  (data_1->print_shell == data_2->print_shell) &&
1778 	  (data_1->depth == data_2->depth) &&
1779 	  ((data_1->image_depth != 1) ||
1780 	   ((data_1->image_depth == 1) &&
1781 	   (data_1->foreground == data_2->foreground) &&
1782 	   (data_1->background == data_2->background)))) ;
1783 }
1784 
1785 /* Hash a GC entry. Only care about the colors for depth 1 */
1786 static XmHashValue
HashGCData(XmHashKey key)1787 HashGCData (XmHashKey key)
1788 {
1789   GCData *data = (GCData *) key;
1790   XmHashValue hv = 0 ;
1791 
1792   if (data->image_depth == 1)
1793     hv = data->foreground + data->background ;
1794 
1795   return (hv + (long)data->screen + (long)data->print_shell +
1796 	  data->depth + data->image_depth);
1797 }
1798 
1799 /***
1800  * GetGCForPutImage
1801  * Maintain a cache of GC to use for transfering the XImage to
1802  * a Pixmap depending on the screen, depth, colors.
1803  ***/
1804 static GC
GetGCForPutImage(Screen * screen,Widget print_shell,XImage * image,Pixmap pixmap,int depth,Pixel foreground,Pixel background)1805 GetGCForPutImage(Screen *screen,
1806 		 Widget print_shell,
1807 		 XImage * image,
1808 		 Pixmap pixmap,
1809 		 int depth,
1810 		 Pixel foreground,
1811 		 Pixel background)
1812 {
1813     XGCValues gcValues;
1814     GCData gc_data, *gc_entry ;
1815 
1816     /* There is a problem here: we cannot simply use the xmScreen object
1817      * to store the GCs, for the pixmap conversion can be called
1818      * at a time the xmScreen is not yet available: a conversion
1819      * for the first VendorShell on this screen, or a conversion for
1820      * the xmScreen or xmDisplay.
1821      * We can either arrange for delaying the conversion for those cases,
1822      * or not use the xmScreen here. Since we need to cache per depth
1823      * in addition to per screen, and since the Xt routine cannot be used
1824      * since there is no widget available, let's forget about using the
1825      * xmScreen object, do our own specialized caching.
1826      */
1827 
1828     /* There shouldn't be a lot of different GCs, one for
1829      * depth 1 to depth 1, foreground 1, back 0, one for
1830      * depth N to N, fore/back don't matter and some for depth 1 to
1831      * depth N, where colors matter, for backgroundPixmap resources
1832      * and regular use
1833      * of XmGetPixmapByDepth (with no -depth) issued from XBM file.
1834      */
1835 
1836     _XmProcessLock();
1837     if (gc_set == NULL)
1838 	gc_set = _XmAllocHashTable (20, CompareGCDatas, HashGCData);
1839     _XmProcessUnlock();
1840 
1841     /* set up an entry for search. We only care about the colors
1842        for image_depth 1 to pixmap depth (N or 1), since otherwise, N to N,
1843        the transfer is a plain copy */
1844     gc_data.screen = screen ;
1845     gc_data.print_shell = print_shell ;
1846     gc_data.depth = depth ;
1847     gc_data.image_depth = image->depth ;
1848     gc_data.foreground = foreground ;
1849     gc_data.background = background ;
1850 
1851     /* look if we have a match and return it */
1852     _XmProcessLock();
1853     if ((gc_entry = (GCData*)
1854 	 _XmGetHashEntry(gc_set, (XmHashKey)&gc_data)) != NULL) {
1855 	_XmProcessUnlock();
1856 	return gc_entry->gc ;
1857     }
1858     _XmProcessUnlock();
1859 
1860     /* create a new GC, cache it and return it */
1861     gc_entry = XtNew(GCData);
1862     gc_entry->screen = screen ;
1863     gc_entry->print_shell = print_shell ;
1864     gc_entry->depth = depth ;
1865     gc_entry->image_depth = image->depth ;
1866     gc_entry->foreground = foreground ;
1867     gc_entry->background = background ;
1868     _XmProcessLock();
1869     _XmAddHashEntry(gc_set, (XmHashKey)gc_entry, (XtPointer)gc_entry);
1870     _XmProcessUnlock();
1871 
1872     gcValues.foreground = foreground;
1873     gcValues.background = background;
1874     gc_entry->gc = XCreateGC (DisplayOfScreen(screen), pixmap,
1875 			     GCForeground | GCBackground, &gcValues);
1876 
1877     return gc_entry->gc ;
1878 }
1879 
1880 
1881 /************
1882  When a Screen is closed, or a PrintShell, we need to clean up the
1883  respective cache .
1884 *****/
1885 
1886 
1887 static Boolean
CleanGCMapProc(XmHashKey key,XtPointer value,XtPointer data)1888 CleanGCMapProc (XmHashKey key, /* unused */
1889 		 XtPointer value,
1890 		 XtPointer data)
1891 {
1892   GCData *entry = (GCData *) value;
1893   CleanKey * ck = (CleanKey*) data ;
1894 
1895   /* shell should be NULL for non printing screen */
1896   if (entry->print_shell == ck->shell &&
1897       entry->screen == ck->screen)
1898     {
1899 	  _XmProcessLock();
1900 	  _XmRemoveHashEntry (gc_set, entry);
1901 	  _XmProcessUnlock();
1902 	  XFreeGC(DisplayOfScreen(entry->screen), entry->gc);
1903 	  XtFree((char*) entry);
1904     }
1905 
1906   /* never return True: remove all gc keyed on this print shell */
1907   return False;
1908 }
1909 
1910 static Boolean
CleanPixmapMapProc(XmHashKey key,XtPointer value,XtPointer data)1911 CleanPixmapMapProc (XmHashKey key, /* unused */
1912 		     XtPointer value,
1913 		     XtPointer data)
1914 {
1915   PixmapData *entry = (PixmapData *) value;
1916   CleanKey * ck = (CleanKey*) data ;
1917 
1918   /* shell should be NULL for non printing screen */
1919   if (entry->print_shell == ck->shell &&
1920       entry->screen == ck->screen)
1921     {
1922 	/* this should take care of everything */
1923 	XmDestroyPixmap(entry->screen, entry->pixmap);
1924     }
1925 
1926   /* never return True: remove all pixmap keyed on this print shell */
1927   return False;
1928 }
1929 
1930 #ifdef XP_DEBUG
1931 static Boolean
PrintPixmapMapProc(XmHashKey key,XtPointer value,XtPointer data)1932 PrintPixmapMapProc (XmHashKey key, /* unused */
1933 		    XtPointer value,
1934 		    XtPointer data)
1935 {
1936   PixmapData *entry = (PixmapData *) value;
1937   CleanKey * ck = (CleanKey*) data ;
1938 
1939   printf("entry->screen %d\n", entry->screen);
1940   printf("entry->print_shell %d\n", entry->print_shell);
1941   printf("entry->image_name %s\n", entry->image_name);
1942   printf("entry->pixmap %d\n\n", entry->pixmap);
1943 
1944   return False;
1945 }
1946 
1947 static Boolean
PrintGCMapProc(XmHashKey key,XtPointer value,XtPointer data)1948 PrintGCMapProc (XmHashKey key, /* unused */
1949 		XtPointer value,
1950 		XtPointer data)
1951 {
1952   GCData *entry = (GCData *) value;
1953   CleanKey * ck = (CleanKey*) data ;
1954 
1955   printf("entry->screen %d\n", entry->screen);
1956   printf("entry->print_shell %d\n", entry->print_shell);
1957   printf("entry->gc %d\n\n", entry->gc);
1958 
1959   return False;
1960 }
1961 #endif
1962 /******
1963  This is called from PrintShell.Destroy to invalidate the
1964  GCs and Pixmap used for a given print shell and from Screen.destroy,
1965  with a NULL shell, to remove the GCs and Pixmap used for a
1966  given screen. So in the case of PrintShell, this is call twice
1967  in a row, where the second time (from Screen) takes care of
1968  the Screen (non print shell) specific pixmaps abd GCs.
1969 *******/
1970 void
_XmCleanPixmapCache(Screen * screen,Widget shell)1971 _XmCleanPixmapCache(Screen * screen, Widget shell)
1972 {
1973     CleanKey ck ;
1974 
1975     ck.screen = screen;
1976     ck.shell = shell ;
1977 
1978     _XmMapHashTable(gc_set, CleanGCMapProc, &ck);
1979     _XmMapHashTable(pixmap_set, CleanPixmapMapProc, &ck);
1980 }
1981 
1982 
1983 
1984 
1985 /************************************************************************
1986 *******************************************************************------
1987 
1988   Design notes:
1989 
1990   There is really two different caches here, an XImage cache and
1991   a Pixmap cache (+ a GC cache).
1992 
1993   The XImage cache is name based (hash key is image_name). No colors are
1994   supported, and therefore, it is only useful with depth 1 XImage.
1995 
1996   Program can directly install non-depth 1 XImage in this cache using
1997   the public API (XmInstallImage), but that's not advised, for the
1998   non-depth 1 XImage resulting from XPM file have color variations
1999   for the same image_name. If you ask for image_name Foo, foreground
2000   red and background blue, and a Foo has been installed in the image
2001   cache using different foreground & background, you don't want
2002   to get back this Foo, but a new instance of Foo, one that uses
2003   the red and blue colors.
2004 
2005   Also, the only access to the XImage reader (GetImage) is via the pixmap
2006   API, so if a XPM with no colors sensitivity (no pertinent Motif
2007   symbolic colors) is read once, it will be found by the
2008   pixmap cache first, no need to cache it in the image cache.
2009 
2010   The Pixmap cache is name/depth/colors or pixmap based, depending
2011   which API is looking up.
2012   The old XmGetPixmapByDepth() is equivalent to asking for
2013   valid foreground/background and unspecified others, which
2014   means these additional colors (shadows, select) will not be
2015   used during Xpm reading for overriding symbolic colors.
2016 
2017   Motifnext adds printing support and clean cache support.
2018 
2019 ***/
2020 
2021 
2022 #define roundint(x)                   MAX(1, (int)((x) + 0.5))
2023 
2024 typedef struct {
2025   Position *x, *y;
2026   Dimension *width, *height;
2027 } Table;
2028 
_XmPutScaledImage(Display * display,Drawable d,GC gc,XImage * src_image,int src_x,int src_y,int dest_x,int dest_y,unsigned int src_width,unsigned int src_height,unsigned int dest_width,unsigned int dest_height)2029 void _XmPutScaledImage (
2030     Display*		 display,
2031     Drawable		 d,
2032     GC			 gc,
2033     XImage*		 src_image,
2034     int			 src_x,
2035     int			 src_y,
2036     int			 dest_x,
2037     int			 dest_y,
2038     unsigned int	 src_width,
2039     unsigned int	 src_height,
2040     unsigned int	 dest_width,
2041     unsigned int	 dest_height)
2042 {
2043     XImage *dest_image;
2044     Position x, y, min_y, max_y, src_max_x;
2045     Dimension w, h, strip_height;
2046     Table table;
2047     Pixel pixel;
2048     double ratio_x, ratio_y;
2049     Bool fast8;
2050     int xp_event, xp_error;
2051 
2052     if (dest_width == src_width && dest_height == src_height) {
2053 	/* same for x and y, just send it out */
2054 	XPutImage(display, d, gc, src_image, src_x, src_y,
2055 		  dest_x, dest_y, dest_width, dest_height);
2056 	return;
2057     }
2058 
2059     ratio_x = (double)dest_width / (double)src_width;
2060     ratio_y = (double)dest_height / (double)src_height;
2061 
2062 #ifdef PRINTING_SUPPORTED
2063     /*
2064      * Check that we have uniform scaling, and that the print extension
2065      * exists.  We can't call XpGetContext first, because if the print
2066      * extension doesn't exist we'll get a warning to stderr.
2067      * It would be better if the print context was passed in directly, so
2068      * that we didn't spend a round trip when scaling for the video screen,
2069      * but it's just one round trip on just the first call per display, so
2070      * it's not that bad.
2071      */
2072     h = (double)src_height * ratio_x + 0.5;
2073     if (dest_height <= h + 1 && h <= dest_height + 1 &&
2074 	XpQueryExtension(display, &xp_event, &xp_error)) {
2075 	/*
2076 	 * We could be clever and try to get the print context first from
2077 	 * the _XmPrintScreenToShellContext and then get the resolution from
2078 	 * the print shell, but we don't have a Screen* to do the lookup.
2079 	 */
2080 	XPContext pcontext = XpGetContext(display);
2081 	if (pcontext) {
2082 	    int media_res;
2083 	    media_res = atoi(XpGetOneAttribute(display, pcontext, XPDocAttr,
2084 					       "default-printer-resolution"));
2085 	    if (media_res) {
2086 		int image_res = (double)media_res / ratio_x + 0.5;
2087 		int prev_res;
2088 		if (XpSetImageResolution(display, pcontext,
2089 					 image_res, &prev_res)) {
2090 		    XPutImage(display, d, gc, src_image, src_x, src_y,
2091 			      dest_x, dest_y, src_width, src_height);
2092 		    XpSetImageResolution(display, pcontext, prev_res, NULL);
2093 		    return;
2094 		}
2095 	    }
2096 	}
2097     }
2098 #endif /* PRINTING_SUPPORTED */
2099 
2100     src_max_x = src_x + src_width;
2101 
2102     strip_height = 65536 / roundint(ratio_x * src_image->bytes_per_line);
2103     if (strip_height == 0)
2104 	strip_height = 1;
2105     if (strip_height > dest_height)
2106 	strip_height = dest_height;
2107 
2108     h = strip_height + roundint(ratio_y);
2109     dest_image = XCreateImage(display,
2110 			      DefaultVisualOfScreen(
2111 					     DefaultScreenOfDisplay(display)),
2112 			      src_image->depth, src_image->format,
2113 			      0, NULL,
2114 			      dest_width, h,
2115 			      src_image->bitmap_pad, 0);
2116     dest_image->data = XtMalloc(dest_image->bytes_per_line * h);
2117     fast8 = (src_image->depth == 8 && src_image->bits_per_pixel == 8 &&
2118 	     dest_image->bits_per_pixel == 8 && src_image->format == ZPixmap);
2119 
2120     table.x = (Position *) XtMalloc(sizeof(Position) * (src_image->width + 1));
2121     table.y = (Position *) XtMalloc(sizeof(Position) * (src_image->height + 1));
2122     table.width = (Dimension *) XtMalloc(sizeof(Dimension) * src_image->width);
2123     table.height = (Dimension *) XtMalloc(sizeof(Dimension)*src_image->height);
2124 
2125     table.x[0] = 0;
2126     for (x = 1; x <= src_image->width; x++) {
2127 	table.x[x] = roundint(ratio_x * x);
2128 	table.width[x - 1] = table.x[x] - table.x[x - 1];
2129     }
2130 
2131     table.y[0] = 0;
2132     for (y = 1; y <= src_image->height; y++) {
2133 	table.y[y] = roundint(ratio_y * y);
2134 	table.height[y - 1] = table.y[y] - table.y[y - 1];
2135     }
2136 
2137     for (min_y = table.y[src_y]; min_y < dest_height; min_y = table.y[y]) {
2138 	max_y = min_y + strip_height;
2139 	if (max_y > dest_height) {
2140 	    strip_height = dest_height - min_y;
2141 	    max_y = dest_height;
2142 	}
2143 	for (y = src_y; table.y[y] < max_y; y++) {
2144 	    if (table.y[y] < min_y)
2145 		continue;
2146 	    if (fast8) {
2147 		for (x = src_x; x < src_max_x; x++) {
2148 		    pixel = ((unsigned char *)src_image->data)
2149 			[y * src_image->bytes_per_line + x];
2150 		    for (h = 0; h < table.height[y]; h++) {
2151 			memset(dest_image->data +
2152 			       (table.y[y] + h - min_y) *
2153 			       dest_image->bytes_per_line + table.x[x],
2154 			       pixel, table.width[x]);
2155 		    }
2156 		}
2157 	    } else {
2158 		for (x = src_x; x < src_max_x; x++) {
2159 		    pixel = XGetPixel(src_image, x, y);
2160 		    for (h = 0; h < table.height[y]; h++) {
2161 			for (w = 0; w < table.width[x]; w++)
2162 			    XPutPixel(dest_image,
2163 				      table.x[x] + w,
2164 				      table.y[y] + h - min_y,
2165 				      pixel);
2166 		    }
2167 		}
2168 	    }
2169 	}
2170 	XPutImage(display, d, gc, dest_image, dest_x, 0,
2171 		  dest_x, dest_y + min_y, dest_width, table.y[y] - min_y);
2172 	if (y >= src_image->height)
2173 	    break;
2174     }
2175 
2176     XtFree((char *)table.x);
2177     XtFree((char *)table.y);
2178     XtFree((char *)table.width);
2179     XtFree((char *)table.height);
2180 
2181     XDestroyImage(dest_image);
2182 }
2183 
2184 
2185 
2186 /*** COLOR CACHE NOW ***/
2187 
2188 
2189 static Boolean
GetCacheColorByName(Display * display,Colormap colormap,char * colorname,XColor * xcolor)2190 GetCacheColorByName( Display *display, Colormap colormap,
2191 		     char *colorname, XColor *xcolor)
2192 {
2193     static Boolean firstTime = True;
2194     XrmQuark colorname_q;
2195     int i;
2196     CachedColor *color;
2197 
2198     if (!colorname)
2199 	return False;
2200 
2201     if ( firstTime )
2202     {
2203        colorCacheList.numEntries = colorCacheList.maxEntries = 0;
2204        colorCacheList.cache = NULL;
2205        firstTime = False;
2206        return False;
2207     }
2208 
2209     colorname_q = XrmStringToQuark(colorname);
2210 
2211     for (i = 0, color = colorCacheList.cache; i < colorCacheList.numEntries;
2212 	 i++, color++)
2213     {
2214 	if (color->colorname == colorname_q &&
2215             color->colormap == colormap &&
2216             color->display == display)
2217         {
2218 	   xcolor->pixel = color->pixel;
2219 	   color->num_cached++;
2220            return True;
2221         }
2222     }
2223     return False;
2224 }
2225 
2226 static Boolean
GetCacheColorByRGB(Display * display,Colormap colormap,XColor * xcolor)2227 GetCacheColorByRGB( Display *display, Colormap colormap, XColor *xcolor)
2228 {
2229     int i;
2230     CachedColor *color;
2231 
2232     for (i = 0, color = colorCacheList.cache; i < colorCacheList.numEntries;
2233 	 i++, color++)
2234     {
2235 	if (color->colormap == colormap && color->display == display &&
2236 	    color->red == xcolor->red &&
2237 	    color->green == xcolor->green &&
2238 	    color->blue == xcolor->blue)
2239         {
2240 	   xcolor->pixel = color->pixel;
2241 	   color->num_cached++;
2242            return True;
2243         }
2244     }
2245     return False;
2246 }
2247 
2248 static Boolean
FreeCacheColor(Display * display,Colormap colormap,Pixel pixel)2249 FreeCacheColor( Display *display, Colormap colormap, Pixel pixel)
2250 {
2251     int i;
2252     CachedColor *color;
2253 
2254     for (i = 0, color = colorCacheList.cache; i < colorCacheList.numEntries;
2255 	 i++, color++)
2256     {
2257 	if (color->colormap == colormap && color->display == display &&
2258 	    color->pixel == pixel)
2259         {
2260 	    color->num_cached--;
2261 	    if (color->num_cached == 0) {
2262 		int j;
2263 		for (j = i + 1; j < colorCacheList.numEntries; i++, j++)
2264 		    colorCacheList.cache[i] = colorCacheList.cache[j];
2265 		colorCacheList.numEntries--;
2266 		XFreeColors(display, colormap, &pixel, 1, 0);
2267 		return True;
2268 	    }
2269 	}
2270     }
2271     return False;
2272 }
2273 
2274 static void
CacheColorPixel(Display * display,Colormap colormap,char * colorname,XColor * xcolor)2275 CacheColorPixel( Display *display, Colormap colormap,
2276                  char *colorname, XColor *xcolor)
2277 {
2278     int numEntries = colorCacheList.numEntries;
2279 
2280     if (numEntries == colorCacheList.maxEntries)
2281     {
2282         colorCacheList.maxEntries += 25;
2283 	colorCacheList.cache = (CachedColor *)
2284 				  XtRealloc((char *)colorCacheList.cache,
2285 					    colorCacheList.maxEntries *
2286 				            sizeof(CachedColor));
2287     }
2288 
2289     colorCacheList.cache[numEntries].display = display;
2290     colorCacheList.cache[numEntries].colormap = colormap;
2291     colorCacheList.cache[numEntries].colorname =
2292 	colorname ? XrmStringToQuark(colorname) : NULLQUARK;
2293 
2294     colorCacheList.cache[numEntries].red = xcolor->red;
2295     colorCacheList.cache[numEntries].green = xcolor->green;
2296     colorCacheList.cache[numEntries].blue = xcolor->blue;
2297     colorCacheList.cache[numEntries].pixel = xcolor->pixel;
2298     colorCacheList.cache[numEntries].num_cached = 1;
2299 
2300     colorCacheList.numEntries++;
2301 }
2302 
2303 
2304 static int
GetCacheColor(Display * display,Colormap colormap,char * colorname,XColor * xcolor,void * closure)2305 GetCacheColor(Display *display, Colormap colormap,
2306 	      char *colorname, XColor *xcolor, void *closure)
2307 {
2308     int status;
2309     if (colorname) {
2310 	/* look for the colorname in the cache */
2311 	if (!GetCacheColorByName(display, colormap, colorname, xcolor)) {
2312 	    /* when not found parse and alloc color */
2313 	    if (!XParseColor(display, colormap, colorname, xcolor))
2314 		return -1;
2315 	    if (!GetCacheColorByRGB(display, colormap, xcolor)) {
2316 		status = XAllocColor(display, colormap, xcolor);
2317 		if (status)	/* if allocation succeeded, store color */
2318 		    CacheColorPixel(display, colormap, colorname, xcolor);
2319 	    } else
2320 		status = 1;
2321 	} else
2322 	    status = 1;
2323     } else {
2324 	if (!GetCacheColorByRGB(display, colormap, xcolor)) {
2325 	    status = XAllocColor(display, colormap, xcolor);
2326 	    if (status)		/* if allocation succeeded, store color */
2327 		CacheColorPixel(display, colormap, colorname, xcolor);
2328 	} else
2329 	    status = 1;
2330     }
2331 
2332     return status != 0 ? 1 : 0;
2333 }
2334 
2335 static int
FreeCacheColors(Display * display,Colormap colormap,Pixel * pixels,int n,void * closure)2336 FreeCacheColors(Display *display, Colormap colormap,
2337 		Pixel *pixels, int n, void *closure)
2338 {
2339     int i, status;
2340     for (i = 0; i < n; i++, pixels++)
2341 	status = FreeCacheColor(display, colormap, *pixels);
2342     return 0;
2343 }
2344