1 /*
2  * Motif Tools Library, Version 3.1
3  * $Id: GetPixmap.c,v 1.2 2001/09/19 02:57:18 grmcdorman Exp $
4  *
5  * Written by David Flanagan.
6  * Copyright (c) 1992-2001 by David Flanagan.
7  * All Rights Reserved.  See the file COPYRIGHT for details.
8  * This is open source software.  See the file LICENSE for details.
9  * There is no warranty for this software.  See NO_WARRANTY for details.
10  *
11  * $Log: GetPixmap.c,v $
12  * Revision 1.2  2001/09/19 02:57:18  grmcdorman
13  * This change makes the following modifications:
14  *   A new program, printConfig, is provided. This is built by a
15  *   simple rule in the Makefile and not installed. It prints
16  *   significant defines from Xmt.tmpl.
17  *
18  *   XmtP.h is now generated from XmtP.h.in using printConfig. As
19  *   a result, code compiled outside of the Xmt Imakefiles will
20  *   have all of the Xmt.tmpl defines.
21  *
22  *   Source files are modified to use XmtP.h instead of Xmt.h.
23  *
24  *   WorkingBox.c is modified to use the new Progress widget.
25  *   It can be compiled in the old style if WORKINGBOX_USE_SCALE is
26  *   defined at compile time.
27  *
28  *   Because XmtP.h is generated dynamically, it is removed from CVS
29  *   with this check-in.
30  *
31  * Revision 1.1.1.1  2001/02/10 13:42:46  motiftools
32  * Initial import of Xmt310 to CVS
33  *
34  *
35  */
36 
37 #include <stdio.h>
38 #include <ctype.h>
39 #include <Xmt/XmtP.h>
40 #include <Xmt/Pixmap.h>
41 #include <Xmt/Xpm.h>
42 #include <Xmt/Xbm.h>
43 #include <Xmt/Color.h>
44 #include <Xmt/AppResP.h>
45 #include <Xmt/ConvertersP.h>
46 #include <Xmt/LookupP.h>
47 #include <X11/IntrinsicP.h>
48 
49 #if NeedFunctionPrototypes
GetPixmap(Widget object,StringConst str,XmtColorTable table,Boolean get_bitmap)50 static Pixmap GetPixmap(Widget object, StringConst str, XmtColorTable table,
51 			Boolean get_bitmap)
52 #else
53 static Pixmap GetPixmap(object, str, table, get_bitmap)
54 Widget object;
55 StringConst str;
56 XmtColorTable table;
57 Boolean get_bitmap;
58 #endif
59 {
60     Widget w, shell;
61     Display *display;
62     Screen *screen;
63     Visual *visual;
64     Colormap colormap;
65     unsigned int depth;
66     XmtAppResources *app;
67     XmtImage *xmtimage = NULL;
68     struct {
69 	char *bits;
70 	int width, height, hot_x, hot_y;
71     } xbmdata;
72     Pixmap pixmap = None;
73     String name = NULL;
74     String table_string;
75     String filename = NULL;
76     String path = NULL;
77     Boolean pixmap_file = False;
78     Boolean bitmap_file = False;
79     XtCacheRef color_table_cache_ref;
80     XtCacheRef refs[2];
81     Boolean free_color_table = False;
82     static int unique_image_number;
83     extern char *getenv();
84 
85     for(w=object; !XtIsWidget(w); w = XtParent(w));
86     shell = XmtGetShell(w);
87 
88     app = XmtGetApplicationResources(shell);
89     screen = XtScreen(w);
90     display = DisplayOfScreen(screen);
91     visual = XmtGetVisual(shell);
92     colormap = w->core.colormap;
93     depth = w->core.depth;
94     if (!table) table = app->colortable;
95 
96     /*
97      * see if it is a literal XPM file
98      */
99     if (!get_bitmap && strncmp(str, "/* XPM */", 9) == 0) {
100 	xmtimage = XmtParseXpmString(str);
101 	if (xmtimage) {
102 	    name = XtMalloc(8);
103 	    sprintf(name, "_%d_", unique_image_number++);
104 	    goto found;
105 	}
106 	else return None;
107     }
108 
109     /*
110      * see if it is a literal XBM file
111      */
112     xbmdata.bits = NULL;
113     if (strncmp(str, "#define", 7) == 0) {
114 	if (XmtParseXbmString(str, &xbmdata.bits,
115 			      &xbmdata.width, &xbmdata.height,
116 			      &xbmdata.hot_x, &xbmdata.hot_y)) {
117 	    name = XtMalloc(16);
118 	    sprintf(name, "_Xmt%d", unique_image_number++);
119 	    goto found;
120 	}
121 	else
122 	    return None;
123     }
124 
125     /*
126      * Otherwise it is a single name, optionally followed by a color table.
127      * If there is a colon, parse the color table, and get a null-terminated
128      * copy of the single name.
129      * In either case, name is set to the image name.
130      * if (name != str) then name must be freed later.
131      */
132     table_string = strchr(str, ':');
133     if (table_string) {
134 	register int i;
135 
136 	table_string++; /* points to first char after colon */
137 	if (!get_bitmap) {
138 	    if (_XmtColorTableConverter != NULL) {
139 		XrmValue from, to;
140 		XrmValue color_table_args[2];
141 		XmtColorTable parent_table;
142 		Boolean status;
143 
144 		parent_table = table;
145 		from.addr = table_string;
146 		from.size = strlen(table_string);
147 		to.addr = (XPointer)&table;
148 		to.size = sizeof(XmtColorTable);
149 		color_table_args[0].addr = (XPointer)&parent_table;
150 		color_table_args[0].size = sizeof(XmtColorTable);
151 		color_table_args[1].addr = (XPointer)&screen;
152 		color_table_args[1].size = sizeof(Screen *);
153 		status = XtCallConverter(display, _XmtColorTableConverter,
154 					 color_table_args, 2,
155 					 &from, &to, &color_table_cache_ref);
156 		if (!status)
157 		    XmtWarningMsg("XmtGetPixmap", "badColor",
158 				  "continuing with default color table.");
159 		else
160 		    free_color_table = True;
161 	    }
162 	    else {
163 		XmtWarningMsg("XmtGetPixmap", "noColor",
164 			      "No XmtColorTable converter registered.\n\tSee XmtRegisterColorTableConverter();");
165 	    }
166 	}
167 	else {
168 	    XmtWarningMsg("XmtGetBitmap", "table",
169 		    "color table specification unused in bitmap conversion.");
170 	}
171 
172 	table_string -= 2;  /* points to char before colon */
173 	for(; isspace(*table_string); table_string--);  /* skip over blanks*/
174 	i = (table_string - str) + 1;
175 	name = strncpy(XtMalloc(i+1), str, i);
176 	name[i] = '\0';
177     }
178     else
179 	name = (String) str;
180 
181     /*
182      * see if name is defined in the image cache
183      */
184     if (get_bitmap)
185 	pixmap = XmtLookupBitmap(w, name);
186     else
187 	pixmap = XmtLookupPixmap(w, visual, colormap, depth, table, name);
188 
189     if (pixmap) goto end;
190     else {
191 	/*
192 	 * If it is not in the image cache, check if it is the name of a
193 	 * resource under _Pixmaps_ or _Bitmaps_.  We lookup the image
194 	 * as:
195 	 *    _Pixmaps_.visual.depth.resolution.language.territory.codeset.name
196 	 * For backward compatibility with Xmt 1.2, we also do just:
197 	 *    _Pixmaps_.name
198 	 * because in 1.2 '.name' was more common than '*name'
199 	 *
200 	 * For bitmaps, we use _Bitmaps_, and omit the visual and depth.
201 	 */
202 	String value;
203 
204 	if (!get_bitmap) {
205 	    value = _XmtLookupResource(screen, "PVDZltc", name);
206 	    if (value) {
207 		if ((xmtimage = XmtParseXpmString(value))) goto found;
208 		else goto end;
209 	    }
210 	}
211 
212 	value = _XmtLookupResource(screen, "BZltc", name);
213 	if (value) {
214 	    if (XmtParseXbmString(value, &xbmdata.bits,
215 				  &xbmdata.width, &xbmdata.height,
216 				  &xbmdata.hot_x, &xbmdata.hot_y))
217 		goto found;
218 	    else goto end;
219 	}
220 
221 	/* if still not found, look up the old way, for compatibility */
222 	if (!get_bitmap) {
223 	    value = _XmtLookupResource(screen, "P", name);
224 	    if (value) {
225 		if ((xmtimage = XmtParseXpmString(value))) goto found;
226 		else goto end;
227 	    }
228 	}
229 
230 	value = _XmtLookupResource(screen, "B", name);
231 	if (value) {
232 	    if (XmtParseXbmString(value, &xbmdata.bits,
233 				  &xbmdata.width, &xbmdata.height,
234 				  &xbmdata.hot_x, &xbmdata.hot_y))
235 		goto found;
236 	    else goto end;
237 	}
238     }
239 
240     /*
241      * if we still haven't found a pixmap, name must be a filename
242      */
243     if (pixmap == None) {
244 	/*
245 	 * handle absolute and relative filenames
246 	 */
247 	if ((name[0] == '/') ||
248 	    ((name[0] == '.') && (name[1] == '/')) ||
249 	    ((name[0] == '.') && (name[1] == '.') && (name[2] == '/')))
250 	    filename = name;
251 
252  	/*
253 	 * check relative to an environment variable, if defined
254 	 * Note that since we don't know the path, we don't know for
255 	 * sure that it uses the supplied type and suffix, so we don't
256 	 * know what type of file is being found
257 	 */
258 	if (!get_bitmap && !filename && (path = getenv("XPMLANGPATH"))) {
259 	    filename = XmtFindFile(shell, "pixmaps", name, ".xpm",
260 				   NULL, path, XmtSearchPathOnly);
261 	    if (filename) pixmap_file = True;
262 	}
263 
264 	if (!filename && (path = getenv("XBMLANGPATH"))) {
265 	    filename = XmtFindFile(shell, "bitmaps", name, ".xbm",
266 				   NULL, path, XmtSearchPathOnly);
267 	    if (filename) bitmap_file = True;
268 	}
269 
270 	/* next check the user, app, and system pixmap and bitmap paths */
271 	if (!filename) {
272 	    if (!get_bitmap) {
273 		filename = XmtFindFile(shell, "pixmaps", name, ".xpm",
274 				       NULL, app->pixmap_file_path,
275 				       XmtSearchEverywhere);
276 		if (filename)
277 		    pixmap_file = True;
278 	    }
279 	    if (!filename) {
280 		filename = XmtFindFile(shell, "bitmaps", name, ".xbm",
281 				       NULL, app->bitmap_file_path,
282 				       XmtSearchEverywhere);
283 		if (filename)
284 		    bitmap_file = True;
285 	    }
286 	}
287 
288 	/*
289 	 * if we found a file, read the first few bytes to determine the
290 	 * type.  Read it as appropriate.  Register the resulting
291 	 * pixmap in the cache using the filename as the key.
292 	 */
293 	if (filename) {
294 	    FILE *f;
295 	    char buf[10];
296 
297 	    if (!pixmap_file && !bitmap_file) {
298 		if (get_bitmap) bitmap_file = True;
299 		else if ((f = fopen(filename, "r")) != NULL) {
300 		    (void)fgets(buf, 10, f);
301 		    if (strncmp(buf, "/* XPM */", 9) == 0)
302 			pixmap_file = True;
303 		    else if (strncmp(buf, "#define", 7) == 0)
304 			bitmap_file = True;
305 		    (void)fclose(f);
306 		}
307 	    }
308 
309 	    if (pixmap_file || (!pixmap_file && !bitmap_file)) {
310 		xmtimage = XmtParseXpmFile(filename);
311 		if (xmtimage) goto found;
312 	    }
313 
314 	    if (bitmap_file || (!pixmap_file && !bitmap_file)) {
315 		if (XmtParseXbmFile(filename, &xbmdata.bits,
316 				    &xbmdata.width, &xbmdata.height,
317 				    &xbmdata.hot_x, &xbmdata.hot_y))
318 		    goto found;
319 	    }
320 	}
321     }
322 
323  found:
324     /*
325      * register the xpm or xbm data, and then get a pixmap for it.
326      * we jump here when we successfully parse a xpm or xbm file or string.
327      */
328     if (xmtimage)
329 	XmtRegisterImage(name, xmtimage);
330     else if (xbmdata.bits)
331 	XmtRegisterXbmData(name, xbmdata.bits, NULL,
332 			   xbmdata.width, xbmdata.height,
333 			   xbmdata.hot_x, xbmdata.hot_y);
334 
335     if (xmtimage || xbmdata.bits) {
336 	if (get_bitmap)
337 	    pixmap = XmtLookupBitmap(w, name);
338 	else
339 	    pixmap = XmtLookupPixmap(w, visual, colormap,
340 				     depth, table, name);
341     }
342 
343  end:
344     /*
345      * free what we need to and return.
346      * we jump here if the pixmap is already cached, or on error.
347      */
348     if (filename && filename != name) XtFree(filename);
349     if (name && name != str) XtFree(name);
350     if (free_color_table) {
351 	refs[0] = color_table_cache_ref;
352 	refs[1] = NULL;
353 	XtAppReleaseCacheRefs(XtWidgetToApplicationContext(w), refs);
354     }
355     return pixmap;
356 }
357 
358 #if NeedFunctionPrototypes
XmtGetBitmap(Widget object,StringConst str)359 Pixmap XmtGetBitmap(Widget object, StringConst str)
360 #else
361 Pixmap XmtGetBitmap(object, str)
362 Widget object;
363 StringConst str;
364 #endif
365 {
366     return GetPixmap(object, str, NULL, True);
367 }
368 
369 #if NeedFunctionPrototypes
XmtGetPixmap(Widget object,XmtColorTable table,StringConst str)370 Pixmap XmtGetPixmap(Widget object, XmtColorTable table, StringConst str)
371 #else
372 Pixmap XmtGetPixmap(object, table, str)
373 Widget object;
374 XmtColorTable table;
375 StringConst str;
376 #endif
377 {
378     return GetPixmap(object, str, table, False);
379 }
380