r339: The menu key bindings are now only saved if they actually changed.
[rox-filer.git] / ROX-Filer / src / pixmaps.c
blob7ce03c708f62a0c8ddcb0058035afe924a82ae1b
1 /*
2 * $Id$
4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2000, Thomas Leonard, <tal197@users.sourceforge.net>.
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 * Place, Suite 330, Boston, MA 02111-1307 USA
22 /* pixmaps.c - code for handling pixmaps */
25 * 2000/04/11 Imlib support added
26 * Christiansen Merel <c.merel@wanadoo.fr>
29 #include "config.h"
30 #define PIXMAPS_C
32 /* Remove pixmaps from the cache when they haven't been accessed for
33 * this period of time (seconds).
36 #define PIXMAP_PURGE_TIME 1200
38 #include <stdlib.h>
39 #include <stdio.h>
40 #include <errno.h>
42 #include <gtk/gtk.h>
43 #include <gdk/gdkprivate.h> /* XXX - find another way to do this */
44 #include "collection.h"
45 #ifdef HAVE_IMLIB
46 # include <gdk_imlib.h>
47 #endif
49 #include "global.h"
51 #include "fscache.h"
52 #include "support.h"
53 #include "gui_support.h"
54 #include "pixmaps.h"
55 #include "main.h"
57 GFSCache *pixmap_cache = NULL;
59 static char * bad_xpm[] = {
60 "12 12 3 1",
61 " c #000000000000",
62 ". c #FFFF00000000",
63 "X c #FFFFFFFFFFFF",
64 " ",
65 " ..XXXXXX.. ",
66 " ...XXXX... ",
67 " X...XX...X ",
68 " XX......XX ",
69 " XXX....XXX ",
70 " XXX....XXX ",
71 " XX......XX ",
72 " X...XX...X ",
73 " ...XXXX... ",
74 " ..XXXXXX.. ",
75 " "};
77 MaskedPixmap *im_error;
78 MaskedPixmap *im_unknown;
79 MaskedPixmap *im_symlink;
81 MaskedPixmap *im_unmounted;
82 MaskedPixmap *im_mounted;
83 MaskedPixmap *im_multiple;
84 MaskedPixmap *im_exec_file;
85 MaskedPixmap *im_appdir;
87 MaskedPixmap *im_up_icon;
88 MaskedPixmap *im_home_icon;
89 MaskedPixmap *im_refresh_icon;
90 MaskedPixmap *im_help;
92 /* Static prototypes */
94 static MaskedPixmap *load_pixmap(char *name);
95 static void load_default_pixmaps(void);
96 static MaskedPixmap *load(char *pathname, gpointer data);
97 static void ref(MaskedPixmap *mp, gpointer data);
98 static void unref(MaskedPixmap *mp, gpointer data);
99 static int getref(MaskedPixmap *mp);
100 static gint purge(gpointer data);
101 static MaskedPixmap *image_from_file(char *path);
102 static MaskedPixmap *get_bad_image(void);
103 #ifdef HAVE_IMLIB
104 static GdkImlibImage *make_half_size(GdkImlibImage *big);
105 #endif
108 /****************************************************************
109 * EXTERNAL INTERFACE *
110 ****************************************************************/
112 void pixmaps_init(void)
114 #ifdef HAVE_IMLIB
115 gdk_imlib_init();
117 gtk_widget_push_visual(gdk_imlib_get_visual());
118 gtk_widget_push_colormap(gdk_imlib_get_colormap());
119 #endif
121 pixmap_cache = g_fscache_new((GFSLoadFunc) load,
122 (GFSRefFunc) ref,
123 (GFSRefFunc) unref,
124 (GFSGetRefFunc) getref,
125 NULL, /* Update func */
126 NULL);
128 gtk_timeout_add(10000, purge, NULL);
130 load_default_pixmaps();
133 /* 'name' is relative to app_dir. Always returns with a valid image. */
134 MaskedPixmap *load_pixmap(char *name)
136 MaskedPixmap *retval;
138 retval = image_from_file(make_path(app_dir, name)->str);
139 if (!retval)
140 retval = get_bad_image();
141 return retval;
144 /* Load all the standard pixmaps */
145 static void load_default_pixmaps(void)
147 im_error = load_pixmap("pixmaps/error.xpm");
148 im_unknown = load_pixmap("pixmaps/unknown.xpm");
149 im_symlink = load_pixmap("pixmaps/symlink.xpm");
151 im_unmounted = load_pixmap("pixmaps/mount.xpm");
152 im_mounted = load_pixmap("pixmaps/mounted.xpm");
153 im_multiple = load_pixmap("pixmaps/multiple.xpm");
154 im_exec_file = load_pixmap("pixmaps/exec.xpm");
155 im_appdir = load_pixmap("pixmaps/application.xpm");
157 im_up_icon = load_pixmap("pixmaps/up.xpm");
158 im_home_icon = load_pixmap("pixmaps/home.xpm");
159 im_refresh_icon = load_pixmap("pixmaps/refresh.xpm");
160 im_help = load_pixmap("pixmaps/help.xpm");
163 void pixmap_ref(MaskedPixmap *mp)
165 ref(mp, pixmap_cache->user_data);
168 void pixmap_unref(MaskedPixmap *mp)
170 unref(mp, pixmap_cache->user_data);
173 void pixmap_make_small(MaskedPixmap *mp)
175 if (mp->sm_pixmap)
176 return;
178 #ifdef HAVE_IMLIB
179 if (mp->image)
181 GdkImlibImage *small;
183 small = make_half_size(mp->image);
185 if (small && gdk_imlib_render(small,
186 small->rgb_width, small->rgb_height))
188 mp->sm_pixmap = gdk_imlib_move_image(small);
189 mp->sm_mask = gdk_imlib_move_mask(small);
190 mp->sm_width = small->width;
191 mp->sm_height = small->height;
194 if (small)
195 gdk_imlib_kill_image(small);
196 if (mp->sm_pixmap)
197 return;
199 #endif
200 gdk_pixmap_ref(mp->pixmap);
201 if (mp->mask)
202 gdk_bitmap_ref(mp->mask);
203 mp->sm_pixmap = mp->pixmap;
204 mp->sm_mask = mp->mask;
205 mp->sm_width = mp->width;
206 mp->sm_height = mp->height;
209 /****************************************************************
210 * INTERNAL FUNCTIONS *
211 ****************************************************************/
213 /* Load the image 'path' and return a pointer to the resulting
214 * MaskedPixmap. NULL on failure.
216 static MaskedPixmap *image_from_file(char *path)
218 MaskedPixmap *mp;
219 GdkPixmap *pixmap;
220 GdkBitmap *mask;
221 int width;
222 int height;
223 #ifdef HAVE_IMLIB
224 GdkImlibImage *image;
226 image = gdk_imlib_load_image(path);
227 if (!image)
228 return NULL;
230 /* Avoid ImLib cache - ours is better! */
231 gdk_imlib_changed_image(image);
233 if (!gdk_imlib_render(image, image->rgb_width, image->rgb_height))
235 gdk_imlib_kill_image(image);
236 return NULL;
239 pixmap = image->pixmap;
240 mask = image->shape_mask;
241 width = image->width;
242 height = image->height;
243 #else
244 pixmap = gdk_pixmap_colormap_create_from_xpm(NULL,
245 gtk_widget_get_default_colormap(),
246 &mask,
248 path);
250 if (!pixmap)
251 return NULL;
252 width = ((GdkPixmapPrivate *) pixmap)->width;
253 height = ((GdkPixmapPrivate *) pixmap)->height;
254 #endif
256 mp = g_new(MaskedPixmap, 1);
257 mp->ref = 1;
258 mp->pixmap = pixmap;
259 mp->mask = mask;
260 mp->width = width;
261 mp->height = height;
262 #ifdef HAVE_IMLIB
263 mp->image = image;
264 #endif
265 mp->sm_pixmap = NULL;
266 mp->sm_mask = NULL;
268 return mp;
271 /* Return a pointer to the (static) bad image. The ref counter will ensure
272 * that the image is never freed.
274 static MaskedPixmap *get_bad_image(void)
276 static MaskedPixmap *image = NULL;
278 if (!image)
280 image = g_new(MaskedPixmap, 1);
281 image->ref = 1;
283 image->pixmap= gdk_pixmap_colormap_create_from_xpm_d(NULL,
284 gtk_widget_get_default_colormap(),
285 &image->mask, NULL, bad_xpm);
286 #ifdef HAVE_IMLIB
287 image->image = NULL;
288 #endif
290 image->sm_pixmap = NULL;
291 image->sm_mask = NULL;
294 image->ref++;
295 image->width = ((GdkPixmapPrivate *) image->pixmap)->width;
296 image->height = ((GdkPixmapPrivate *) image->pixmap)->height;
298 return image;
301 static MaskedPixmap *load(char *pathname, gpointer user_data)
303 return image_from_file(pathname);
306 static void ref(MaskedPixmap *mp, gpointer data)
308 /* printf("[ ref %p %d->%d ]\n", mp, mp->ref, mp->ref + 1); */
310 if (mp)
311 mp->ref++;
314 static void unref(MaskedPixmap *mp, gpointer data)
316 /* printf("[ unref %p %d->%d ]\n", mp, mp->ref, mp->ref - 1); */
318 if (mp && --mp->ref == 0)
320 #ifdef HAVE_IMLIB
321 if (mp->image)
323 gdk_imlib_kill_image(mp->image);
325 else
326 #endif
328 gdk_pixmap_unref(mp->pixmap);
329 if (mp->mask)
330 gdk_bitmap_unref(mp->mask);
332 if (mp->sm_pixmap)
333 gdk_pixmap_unref(mp->sm_pixmap);
334 if (mp->sm_mask)
335 gdk_bitmap_unref(mp->sm_mask);
336 g_free(mp);
340 static int getref(MaskedPixmap *mp)
342 return mp->ref;
345 /* Called now and then to clear out old pixmaps */
346 static gint purge(gpointer data)
348 g_fscache_purge(pixmap_cache, PIXMAP_PURGE_TIME);
350 return TRUE;
353 #ifdef HAVE_IMLIB
355 /* Returns data to make an 1/4 size image of 'big'. g_free() the result. */
356 static GdkImlibImage *make_half_size(GdkImlibImage *big)
358 int line_size = big->width * 3;
359 int sw = big->width >> 1;
360 int sh = big->height >> 1;
361 GdkImlibColor tr; /* Mask colour */
362 unsigned char *small_data, *in, *out;
363 GdkImlibImage *small;
364 int x, y;
365 GtkStyle *style = gtk_widget_get_default_style();
366 GdkColor *bg = &style->bg[GTK_STATE_INSENSITIVE];
368 gdk_imlib_get_image_shape(big, &tr);
369 small_data = g_malloc(sw * sh * 3);
371 out = small_data;
373 for (y = 0; y < sh; y++)
375 in = big->rgb_data + y * line_size * 2;
377 for (x = 0; x < sw; x++)
379 int r1 = in[0], r2 = in[3];
380 int r3 = in[0 + line_size], r4 = in[3 + line_size];
381 int g1 = in[1], g2 = in[4];
382 int g3 = in[1 + line_size], g4 = in[4 + line_size];
383 int b1 = in[2], b2 = in[5];
384 int b3 = in[2 + line_size], b4 = in[5 + line_size];
385 int m = 0; /* No. trans pixels */
387 if (r1 == tr.r && g1 == tr.g && b1 == tr.b)
389 r1 = bg->red;
390 g1 = bg->green;
391 b1 = bg->blue;
392 m++;
394 if (r2 == tr.r && g2 == tr.g && b2 == tr.b)
396 r2 = bg->red;
397 g2 = bg->green;
398 b2 = bg->blue;
399 m++;
401 if (r3 == tr.r && g3 == tr.g && b3 == tr.b)
403 r3 = bg->red;
404 g3 = bg->green;
405 b3 = bg->blue;
406 m++;
408 if (r4 == tr.r && g4 == tr.g && b4 == tr.b)
410 r4 = bg->red;
411 g4 = bg->green;
412 b4 = bg->blue;
413 m++;
416 if (m < 3)
418 out[0] = (r1 + r2 + r3 + r4) >> 2;
419 out[1] = (g1 + g2 + g3 + g4) >> 2;
420 out[2] = (b1 + b2 + b3 + b4) >> 2;
422 else
424 out[0] = tr.r;
425 out[1] = tr.g;
426 out[2] = tr.b;
429 in += 6;
430 out += 3;
434 small = gdk_imlib_create_image_from_data(small_data, NULL, sw, sh);
435 g_free(small_data);
437 if (small)
438 gdk_imlib_set_image_shape(small, &tr);
440 return small;
442 #endif