http://www.jwz.org/xscreensaver/xscreensaver-5.10.tar.gz
[xscreensaver] / hacks / xpm-pixmap.c
1 /* xpm-pixmap.c --- converts XPM data to a Pixmap.
2  * xscreensaver, Copyright (c) 1998-2006 Jamie Zawinski <jwz@jwz.org>
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation.  No representations are made about the suitability of this
9  * software for any purpose.  It is provided "as is" without express or 
10  * implied warranty.
11  */
12
13 #ifdef HAVE_CONFIG_H
14 # include "config.h"
15 #endif
16
17 #include <stdlib.h>
18 #include <stdio.h>
19
20 #ifdef HAVE_COCOA
21 # include "jwxyz.h"
22 #else
23 # include <X11/Xlib.h>
24 # include <X11/Xutil.h>
25 # include "visual.h"  /* for screen_number() */
26 #endif
27
28 #include "xpm-pixmap.h"
29
30 extern char *progname;
31
32 #if defined(HAVE_GDK_PIXBUF)
33
34 # include <gdk-pixbuf/gdk-pixbuf.h>
35
36 # ifdef HAVE_GTK2
37 #  include <gdk-pixbuf-xlib/gdk-pixbuf-xlib.h>
38 # else  /* !HAVE_GTK2 */
39 #  include <gdk-pixbuf/gdk-pixbuf-xlib.h>
40 # endif /* !HAVE_GTK2 */
41
42
43 /* Returns a Pixmap structure containing the bits of the given XPM image.
44    This is the gdk_pixbuf version of this function.
45  */
46 static Pixmap
47 xpm_to_pixmap_1 (Display *dpy, Window window,
48                  int *width_ret, int *height_ret,
49                  Pixmap *mask_ret,
50                  const char *filename,
51                  /*const*/ char * const *xpm_data)
52 {
53   GdkPixbuf *pb;
54   static int initted = 0;
55   XWindowAttributes xgwa;
56 #ifdef HAVE_GTK2
57   GError *gerr = NULL;
58 #endif /* HAVE_GTK2 */
59   XGetWindowAttributes (dpy, window, &xgwa);
60
61   if (!initted)
62     {
63 #ifdef HAVE_GTK2
64       g_type_init ();
65 #endif /* HAVE_GTK2 */
66       gdk_pixbuf_xlib_init (dpy, screen_number (xgwa.screen));
67       xlib_rgb_init (dpy, xgwa.screen);
68       initted = 1;
69     }
70
71   pb = (filename
72 #ifdef HAVE_GTK2
73         ? gdk_pixbuf_new_from_file (filename, &gerr)
74 #else  /* !HAVE_GTK2 */
75         ? gdk_pixbuf_new_from_file (filename)
76 #endif /* !HAVE_GTK2 */
77         : gdk_pixbuf_new_from_xpm_data ((const char **) xpm_data));
78   if (pb)
79     {
80       int w = gdk_pixbuf_get_width (pb);
81       int h = gdk_pixbuf_get_height (pb);
82       Pixmap pixmap = 0;
83
84       /* #### Note that this always uses the default colormap!  Morons!
85               Owen says that in Gnome 2.0, I should try using
86               gdk_pixbuf_render_pixmap_and_mask_for_colormap() instead.
87               But I don't have Gnome 2.0 yet.
88        */
89       gdk_pixbuf_xlib_render_pixmap_and_mask (pb, &pixmap, mask_ret, 128);
90
91       if (!pixmap)
92         {
93           fprintf (stderr, "%s: out of memory (%d x %d)\n", progname, w, h);
94           exit (-1);
95         }
96       /* gdk_pixbuf_unref (pb);  -- #### does doing this free colors? */
97
98       if (width_ret)  *width_ret  = w;
99       if (height_ret) *height_ret = h;
100
101       return pixmap;
102     }
103   else if (filename)
104     {
105 #ifdef HAVE_GTK2
106       fprintf (stderr, "%s: %s\n", progname, gerr->message);
107       g_error_free (gerr);
108 #else /* !HAVE_GTK2 */
109       fprintf (stderr, "%s: unable to load %s\n", progname, filename);
110 #endif /* !HAVE_GTK2 */
111       exit (-1);
112     }
113   else
114     {
115       fprintf (stderr, "%s: unable to initialize built-in images\n", progname);
116       exit (-1);
117     }
118 }
119
120
121 #elif defined(HAVE_XPM)
122
123 #include <X11/Intrinsic.h>
124 #include <X11/xpm.h>
125
126 #ifdef HAVE_XMU
127 # ifndef VMS
128 #  include <X11/Xmu/Drawing.h>
129 #else  /* VMS */
130 #  include <Xmu/Drawing.h>
131 # endif /* VMS */
132 #endif
133
134 #undef countof
135 #define countof(x) (sizeof((x))/sizeof((*x)))
136
137
138 static int
139 handle_xpm_error (const char *filename, int status)
140 {
141   if (!filename) filename = "builtin";
142   switch (status)
143     {
144     case XpmSuccess:
145       return 0;
146       break;
147     case XpmColorError:
148       fprintf (stderr, "%s: %s: warning: color substitution performed\n",
149                progname, filename);
150       return 0;
151       break;
152     case XpmFileInvalid:
153       return 1;
154       break;
155     case XpmOpenFailed:
156       fprintf (stderr, "%s: %s: no such file\n", progname, filename);
157       break;
158     case XpmNoMemory:
159       fprintf (stderr, "%s: %s: out of memory\n", progname, filename);
160       break;
161     case XpmColorFailed:
162       fprintf (stderr, "%s: %s: color allocation failed\n",
163                progname, filename);
164       break;
165     default:
166       fprintf (stderr, "%s: %s: unknown XPM error %d\n", progname,
167                filename, status);
168       break;
169     }
170   exit (-1);
171 }
172
173
174 /* The libxpm version of this function...
175  */
176 static Pixmap
177 xpm_to_pixmap_1 (Display *dpy, Window window,
178                  int *width_ret, int *height_ret,
179                  Pixmap *mask_ret,
180                  const char *filename,
181                  /*const*/ char * const *xpm_data)
182 {
183   Pixmap pixmap = 0;
184   XpmAttributes xpmattrs;
185   XpmImage xpm_image;
186   XpmInfo xpm_info;
187   int status;
188   XWindowAttributes xgwa;
189   XGetWindowAttributes (dpy, window, &xgwa);
190
191   memset (&xpm_image, 0, sizeof(xpm_image));
192   memset (&xpm_info, 0, sizeof(xpm_info));
193
194   if (filename)
195     {
196       xpm_data = 0;
197       status = XpmReadFileToData ((char *) filename, &xpm_data);
198       if (handle_xpm_error (filename, status))
199         goto TRY_XBM;
200     }
201
202   xpmattrs.valuemask = 0;
203
204 # ifdef XpmCloseness
205   xpmattrs.valuemask |= XpmCloseness;
206   xpmattrs.closeness = 40000;
207 # endif
208 # ifdef XpmVisual
209   xpmattrs.valuemask |= XpmVisual;
210   xpmattrs.visual = xgwa.visual;
211 # endif
212 # ifdef XpmDepth
213   xpmattrs.valuemask |= XpmDepth;
214   xpmattrs.depth = xgwa.depth;
215 # endif
216 # ifdef XpmColormap
217   xpmattrs.valuemask |= XpmColormap;
218   xpmattrs.colormap = xgwa.colormap;
219 # endif
220
221   status = XpmCreatePixmapFromData (dpy, window, xpm_data,
222                                     &pixmap, mask_ret, &xpmattrs);
223   if (handle_xpm_error (filename, status))
224     pixmap = 0;
225   else
226     {
227       if (width_ret)  *width_ret  = xpmattrs.width;
228       if (height_ret) *height_ret = xpmattrs.height;
229     }
230
231  TRY_XBM:
232
233 #ifdef HAVE_XMU
234   if (! pixmap)
235     {
236       unsigned long fg = BlackPixelOfScreen (xgwa.screen);
237       unsigned long bg = WhitePixelOfScreen (xgwa.screen);
238       int xh, yh;
239       Pixmap b2;
240       pixmap = XmuLocateBitmapFile (xgwa.screen, filename,
241                                     0, 0, width_ret, height_ret, &xh, &yh);
242       if (! pixmap)
243         {
244           fprintf (stderr, "%s: couldn't find XBM %s\n", progname,
245                    filename);
246           exit (-1);
247         }
248       b2 = XmuCreatePixmapFromBitmap (dpy, window, pixmap,
249                                       *width_ret, *height_ret,
250                                       xgwa.depth, fg, bg);
251       XFreePixmap (dpy, pixmap);
252       pixmap = b2;
253
254       if (!pixmap)
255         {
256           fprintf (stderr, "%s: couldn't load XBM %s\n", progname, filename);
257           exit (-1);
258         }
259     }
260 #else  /* !XMU */
261     {
262       fprintf (stderr,
263                "%s: your vendor doesn't ship the standard Xmu library.\n",
264                progname);
265       fprintf (stderr, "\tWe can't load XBM files without it.\n");
266       exit (-1);
267     }
268 #endif /* !XMU */
269
270   return pixmap;
271 }
272
273 #else  /* !HAVE_XPM && !HAVE_GDK_PIXBUF */
274
275 /* If we don't have libXPM or Pixbuf, then use "minixpm".
276    This can read XPM data from memory, but can't read files.
277  */
278
279 #include "minixpm.h"
280
281 static Pixmap
282 xpm_to_pixmap_1 (Display *dpy, Window window,
283                  int *width_ret, int *height_ret,
284                  Pixmap *mask_ret,
285                  const char *filename,
286                  /*const*/ char * const *xpm_data)
287 {
288   XWindowAttributes xgwa;
289   XImage *ximage;
290   Pixmap pixmap, p2 = 0;
291   int iw, ih, npixels;
292   unsigned long *pixels = 0;
293   unsigned char *mask = 0;
294   XGCValues gcv;
295   GC gc;
296
297   if (filename)
298     {
299       fprintf(stderr, 
300               "%s: no files: not compiled with XPM or Pixbuf support.\n", 
301               progname);
302       exit (1);
303     }
304
305   if (! xpm_data) abort();
306
307   XGetWindowAttributes (dpy, window, &xgwa);
308   ximage = minixpm_to_ximage (dpy, xgwa.visual, xgwa.colormap, xgwa.depth, 
309                               BlackPixelOfScreen (xgwa.screen),
310                               (const char * const *)
311                               xpm_data, &iw, &ih, &pixels, &npixels, 
312                               (mask_ret ? &mask : 0));
313   if (pixels) free (pixels);
314
315   pixmap = XCreatePixmap (dpy, window, iw, ih, xgwa.depth);
316   gc = XCreateGC (dpy, pixmap, 0, &gcv);
317   XPutImage (dpy, pixmap, gc, ximage, 0, 0, 0, 0, iw, ih);
318   XFreeGC (dpy, gc);
319   XDestroyImage (ximage);
320
321   if (mask)
322     {
323       p2 = XCreatePixmap (dpy, window, iw, ih, 1);
324       gcv.foreground = 1;
325       gcv.background = 0;
326       gc = XCreateGC (dpy, p2, GCForeground|GCBackground, &gcv);
327       ximage = XCreateImage (dpy, xgwa.visual, 1, XYBitmap, 0, (char *) mask,
328                              iw, ih, 8, 0);
329       ximage->byte_order = ximage->bitmap_bit_order = LSBFirst;
330       if (!ximage) abort();
331       XPutImage (dpy, p2, gc, ximage, 0, 0, 0, 0, iw, ih);
332       XFreeGC (dpy, gc);
333       XDestroyImage (ximage);
334     }
335
336   if (width_ret)  *width_ret  = iw;
337   if (height_ret) *height_ret = ih;
338   if (mask_ret)   *mask_ret   = p2;
339   return pixmap;
340 }
341
342 #endif /* minixpm */
343
344
345 Pixmap
346 xpm_data_to_pixmap (Display *dpy, Window window, 
347                     /*const*/ char * const *xpm_data,
348                     int *width_ret, int *height_ret,
349                     Pixmap *mask_ret)
350 {
351   return xpm_to_pixmap_1 (dpy, window, width_ret, height_ret, mask_ret,
352                           0, xpm_data);
353 }
354
355
356 Pixmap
357 xpm_file_to_pixmap (Display *dpy, Window window, const char *filename,
358                     int *width_ret, int *height_ret,
359                     Pixmap *mask_ret)
360 {
361   return xpm_to_pixmap_1 (dpy, window, width_ret, height_ret, mask_ret,
362                           filename, 0);
363 }