r898: Applied Bernard Jungen's latest patch:
[rox-filer.git] / ROX-Filer / src / pixmaps.c
blobf8c479ecea7983bb6a719f605730e327c36c10cb
1 /*
2 * $Id$
4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2001, the ROX-Filer team.
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 */
24 #include "config.h"
25 #define PIXMAPS_C
27 /* Remove pixmaps from the cache when they haven't been accessed for
28 * this period of time (seconds).
31 #define PIXMAP_PURGE_TIME 1200
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <errno.h>
37 #include <gtk/gtk.h>
38 #include <gdk-pixbuf/gdk-pixbuf.h>
39 #include "collection.h"
41 #include "global.h"
43 #include "fscache.h"
44 #include "support.h"
45 #include "gui_support.h"
46 #include "pixmaps.h"
47 #include "main.h"
49 GFSCache *pixmap_cache = NULL;
51 static const char * bad_xpm[] = {
52 "12 12 3 1",
53 " c #000000000000",
54 ". c #FFFF00000000",
55 "x c #FFFFFFFFFFFF",
56 " ",
57 " ..xxxxxx.. ",
58 " ...xxxx... ",
59 " x...xx...x ",
60 " xx......xx ",
61 " xxx....xxx ",
62 " xxx....xxx ",
63 " xx......xx ",
64 " x...xx...x ",
65 " ...xxxx... ",
66 " ..xxxxxx.. ",
67 " "};
69 MaskedPixmap *im_error;
70 MaskedPixmap *im_unknown;
71 MaskedPixmap *im_symlink;
73 MaskedPixmap *im_unmounted;
74 MaskedPixmap *im_mounted;
75 MaskedPixmap *im_multiple;
76 MaskedPixmap *im_exec_file;
77 MaskedPixmap *im_appdir;
79 MaskedPixmap *im_help;
81 /* Static prototypes */
83 static void load_default_pixmaps(void);
84 static MaskedPixmap *load(char *pathname, gpointer data);
85 static void ref(MaskedPixmap *mp, gpointer data);
86 static void unref(MaskedPixmap *mp, gpointer data);
87 static int getref(MaskedPixmap *mp);
88 static gint purge(gpointer data);
89 static MaskedPixmap *image_from_file(char *path);
90 static MaskedPixmap *get_bad_image(void);
91 static MaskedPixmap *image_from_pixbuf(GdkPixbuf *pixbuf);
92 static GdkPixbuf *scale_pixbuf(GdkPixbuf *src, int max_w, int max_h);
93 static GdkPixbuf *scale_pixbuf_up(GdkPixbuf *src, int max_w, int max_h);
96 /****************************************************************
97 * EXTERNAL INTERFACE *
98 ****************************************************************/
100 void pixmaps_init(void)
102 gdk_rgb_init();
103 #ifndef GTK2
104 gtk_widget_push_visual(gdk_rgb_get_visual());
105 #endif
106 gtk_widget_push_colormap(gdk_rgb_get_cmap());
108 pixmap_cache = g_fscache_new((GFSLoadFunc) load,
109 (GFSRefFunc) ref,
110 (GFSRefFunc) unref,
111 (GFSGetRefFunc) getref,
112 NULL, /* Update func */
113 NULL);
115 gtk_timeout_add(10000, purge, NULL);
117 load_default_pixmaps();
120 /* 'name' is relative to app_dir. Always returns with a valid image. */
121 MaskedPixmap *load_pixmap(char *name)
123 MaskedPixmap *retval;
125 retval = image_from_file(make_path(app_dir, name)->str);
126 if (!retval)
127 retval = get_bad_image();
128 return retval;
131 /* Load all the standard pixmaps */
132 static void load_default_pixmaps(void)
134 im_error = load_pixmap("pixmaps/error.xpm");
135 im_unknown = load_pixmap("pixmaps/unknown.xpm");
136 im_symlink = load_pixmap("pixmaps/symlink.xpm");
138 im_unmounted = load_pixmap("pixmaps/mount.xpm");
139 im_mounted = load_pixmap("pixmaps/mounted.xpm");
140 im_multiple = load_pixmap("pixmaps/multiple.xpm");
141 im_exec_file = load_pixmap("pixmaps/exec.xpm");
142 im_appdir = load_pixmap("pixmaps/application.xpm");
144 im_help = load_pixmap("pixmaps/help.xpm");
147 void pixmap_ref(MaskedPixmap *mp)
149 ref(mp, NULL);
152 void pixmap_unref(MaskedPixmap *mp)
154 unref(mp, NULL);
157 void pixmap_make_huge(MaskedPixmap *mp)
159 GdkPixbuf *hg;
161 if (mp->huge_pixmap)
162 return;
164 g_return_if_fail(mp->huge_pixbuf != NULL);
166 hg = scale_pixbuf_up(mp->huge_pixbuf,
167 HUGE_WIDTH * 0.7,
168 HUGE_HEIGHT * 0.7);
170 if (hg)
172 gdk_pixbuf_render_pixmap_and_mask(hg,
173 &mp->huge_pixmap,
174 &mp->huge_mask,
175 128);
176 mp->huge_width = gdk_pixbuf_get_width(hg);
177 mp->huge_height = gdk_pixbuf_get_height(hg);
178 gdk_pixbuf_unref(hg);
181 if (!mp->huge_pixmap)
183 gdk_pixmap_ref(mp->pixmap);
184 if (mp->mask)
185 gdk_bitmap_ref(mp->mask);
186 mp->huge_pixmap = mp->pixmap;
187 mp->huge_mask = mp->mask;
188 mp->huge_width = mp->width;
189 mp->huge_height = mp->height;
193 void pixmap_make_small(MaskedPixmap *mp)
195 GdkPixbuf *sm;
197 if (mp->sm_pixmap)
198 return;
200 g_return_if_fail(mp->huge_pixbuf != NULL);
202 sm = scale_pixbuf(mp->huge_pixbuf, SMALL_WIDTH, SMALL_HEIGHT);
204 if (sm)
206 gdk_pixbuf_render_pixmap_and_mask(sm,
207 &mp->sm_pixmap,
208 &mp->sm_mask,
209 128);
210 mp->sm_width = gdk_pixbuf_get_width(sm);
211 mp->sm_height = gdk_pixbuf_get_height(sm);
212 gdk_pixbuf_unref(sm);
215 if (mp->sm_pixmap)
216 return;
218 gdk_pixmap_ref(mp->pixmap);
219 if (mp->mask)
220 gdk_bitmap_ref(mp->mask);
221 mp->sm_pixmap = mp->pixmap;
222 mp->sm_mask = mp->mask;
223 mp->sm_width = mp->width;
224 mp->sm_height = mp->height;
227 /****************************************************************
228 * INTERNAL FUNCTIONS *
229 ****************************************************************/
231 /* Load the image 'path' and return a pointer to the resulting
232 * MaskedPixmap. NULL on failure.
234 static MaskedPixmap *image_from_file(char *path)
236 GdkPixbuf *pixbuf;
237 MaskedPixmap *image;
239 pixbuf = gdk_pixbuf_new_from_file(path
240 #ifdef GTK2
241 , NULL /* XXX: Maybe something should go here? */
242 #endif
244 if (!pixbuf)
245 return NULL;
247 image = image_from_pixbuf(pixbuf);
248 gdk_pixbuf_unref(pixbuf);
250 return image;
253 /* Scale src down to fit in max_w, max_h and return the new pixbuf.
254 * If src is small enough, then ref it and return that.
256 static GdkPixbuf *scale_pixbuf(GdkPixbuf *src, int max_w, int max_h)
258 int w, h;
260 w = gdk_pixbuf_get_width(src);
261 h = gdk_pixbuf_get_height(src);
263 if (w <= max_w && h <= max_h)
265 gdk_pixbuf_ref(src);
266 return src;
268 else
270 float scale_x = ((float) w) / max_w;
271 float scale_y = ((float) h) / max_h;
272 float scale = MAX(scale_x, scale_y);
274 return gdk_pixbuf_scale_simple(src,
275 w / scale,
276 h / scale,
277 GDK_INTERP_BILINEAR);
281 /* Scale src up to fit in max_w, max_h and return the new pixbuf.
282 * If src is that size or bigger, then ref it and return that.
284 static GdkPixbuf *scale_pixbuf_up(GdkPixbuf *src, int max_w, int max_h)
286 int w, h;
288 w = gdk_pixbuf_get_width(src);
289 h = gdk_pixbuf_get_height(src);
291 if (w == 0 || h == 0 || (w >= max_w && h >= max_h))
293 gdk_pixbuf_ref(src);
294 return src;
296 else
298 float scale_x = max_w / ((float) w);
299 float scale_y = max_h / ((float) h);
300 float scale = MIN(scale_x, scale_y);
302 return gdk_pixbuf_scale_simple(src,
303 w * scale,
304 h * scale,
305 GDK_INTERP_BILINEAR);
309 /* Turn a full-size pixbuf into a MaskedPixmap */
310 static MaskedPixmap *image_from_pixbuf(GdkPixbuf *full_size)
312 MaskedPixmap *mp;
313 GdkPixbuf *huge_pixbuf, *normal_pixbuf;
314 GdkPixmap *pixmap;
315 GdkBitmap *mask;
317 g_return_val_if_fail(full_size != NULL, NULL);
319 huge_pixbuf = scale_pixbuf(full_size, HUGE_WIDTH, HUGE_HEIGHT);
320 g_return_val_if_fail(huge_pixbuf != NULL, NULL);
322 normal_pixbuf = scale_pixbuf(huge_pixbuf, ICON_WIDTH, ICON_HEIGHT);
323 g_return_val_if_fail(normal_pixbuf != NULL, NULL);
325 gdk_pixbuf_render_pixmap_and_mask(normal_pixbuf, &pixmap, &mask, 128);
327 if (!pixmap)
329 gdk_pixbuf_unref(huge_pixbuf);
330 gdk_pixbuf_unref(normal_pixbuf);
331 return NULL;
334 mp = g_new(MaskedPixmap, 1);
335 mp->huge_pixbuf = huge_pixbuf;
336 mp->ref = 1;
338 mp->pixmap = pixmap;
339 mp->mask = mask;
340 mp->width = gdk_pixbuf_get_width(normal_pixbuf);
341 mp->height = gdk_pixbuf_get_height(normal_pixbuf);
343 gdk_pixbuf_unref(normal_pixbuf);
345 mp->huge_pixmap = NULL;
346 mp->huge_mask = NULL;
347 mp->huge_width = -1;
348 mp->huge_height = -1;
350 mp->sm_pixmap = NULL;
351 mp->sm_mask = NULL;
352 mp->sm_width = -1;
353 mp->sm_height = -1;
355 return mp;
358 /* Return a pointer to the (static) bad image. The ref counter will ensure
359 * that the image is never freed.
361 static MaskedPixmap *get_bad_image(void)
363 GdkPixbuf *bad;
364 MaskedPixmap *mp;
366 bad = gdk_pixbuf_new_from_xpm_data(bad_xpm);
367 mp = image_from_pixbuf(bad);
368 gdk_pixbuf_unref(bad);
370 return mp;
373 static MaskedPixmap *load(char *pathname, gpointer user_data)
375 return image_from_file(pathname);
378 static void ref(MaskedPixmap *mp, gpointer data)
380 /* printf("[ ref %p %d->%d ]\n", mp, mp->ref, mp->ref + 1); */
382 if (mp)
383 mp->ref++;
386 static void unref(MaskedPixmap *mp, gpointer data)
388 /* printf("[ unref %p %d->%d ]\n", mp, mp->ref, mp->ref - 1); */
390 if (mp && --mp->ref == 0)
392 if (mp->huge_pixbuf)
394 gdk_pixbuf_unref(mp->huge_pixbuf);
397 if (mp->huge_pixmap)
398 gdk_pixmap_unref(mp->huge_pixmap);
399 if (mp->huge_mask)
400 gdk_bitmap_unref(mp->huge_mask);
402 if (mp->pixmap)
403 gdk_pixmap_unref(mp->pixmap);
404 if (mp->mask)
405 gdk_bitmap_unref(mp->mask);
407 if (mp->sm_pixmap)
408 gdk_pixmap_unref(mp->sm_pixmap);
409 if (mp->sm_mask)
410 gdk_bitmap_unref(mp->sm_mask);
412 g_free(mp);
416 static int getref(MaskedPixmap *mp)
418 return mp ? mp->ref : 0;
421 /* Called now and then to clear out old pixmaps */
422 static gint purge(gpointer data)
424 g_fscache_purge(pixmap_cache, PIXMAP_PURGE_TIME);
426 return TRUE;