r569: New display style 'Huge Icons' to make viewing thumbnails easier.
[rox-filer.git] / ROX-Filer / src / pixmaps.c
blob2133fad986e9ef83144791f9f5c45967544d774d
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 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);
95 /****************************************************************
96 * EXTERNAL INTERFACE *
97 ****************************************************************/
99 void pixmaps_init(void)
101 gdk_rgb_init();
102 gtk_widget_push_visual(gdk_rgb_get_visual());
103 gtk_widget_push_colormap(gdk_rgb_get_cmap());
105 pixmap_cache = g_fscache_new((GFSLoadFunc) load,
106 (GFSRefFunc) ref,
107 (GFSRefFunc) unref,
108 (GFSGetRefFunc) getref,
109 NULL, /* Update func */
110 NULL);
112 gtk_timeout_add(10000, purge, NULL);
114 load_default_pixmaps();
117 /* 'name' is relative to app_dir. Always returns with a valid image. */
118 MaskedPixmap *load_pixmap(char *name)
120 MaskedPixmap *retval;
122 retval = image_from_file(make_path(app_dir, name)->str);
123 if (!retval)
124 retval = get_bad_image();
125 return retval;
128 /* Load all the standard pixmaps */
129 static void load_default_pixmaps(void)
131 im_error = load_pixmap("pixmaps/error.xpm");
132 im_unknown = load_pixmap("pixmaps/unknown.xpm");
133 im_symlink = load_pixmap("pixmaps/symlink.xpm");
135 im_unmounted = load_pixmap("pixmaps/mount.xpm");
136 im_mounted = load_pixmap("pixmaps/mounted.xpm");
137 im_multiple = load_pixmap("pixmaps/multiple.xpm");
138 im_exec_file = load_pixmap("pixmaps/exec.xpm");
139 im_appdir = load_pixmap("pixmaps/application.xpm");
141 im_help = load_pixmap("pixmaps/help.xpm");
144 void pixmap_ref(MaskedPixmap *mp)
146 ref(mp, NULL);
149 void pixmap_unref(MaskedPixmap *mp)
151 unref(mp, NULL);
154 void pixmap_make_huge(MaskedPixmap *mp)
156 if (mp->huge_pixmap)
157 return;
159 if (mp->huge_pixbuf)
161 gdk_pixbuf_render_pixmap_and_mask(mp->huge_pixbuf,
162 &mp->huge_pixmap,
163 &mp->huge_mask,
164 128);
166 if (mp->huge_pixmap)
167 return;
170 gdk_pixmap_ref(mp->pixmap);
171 if (mp->mask)
172 gdk_bitmap_ref(mp->mask);
173 mp->huge_pixmap = mp->pixmap;
174 mp->huge_mask = mp->mask;
177 void pixmap_make_small(MaskedPixmap *mp)
179 if (mp->sm_pixmap)
180 return;
182 if (mp->huge_pixbuf)
184 GdkPixbuf *sm;
186 sm = scale_pixbuf(mp->huge_pixbuf, SMALL_WIDTH, SMALL_HEIGHT);
188 if (sm)
190 gdk_pixbuf_render_pixmap_and_mask(sm,
191 &mp->sm_pixmap,
192 &mp->sm_mask,
193 128);
194 gdk_pixbuf_unref(sm);
197 if (mp->sm_pixmap)
198 return;
201 gdk_pixmap_ref(mp->pixmap);
202 if (mp->mask)
203 gdk_bitmap_ref(mp->mask);
204 mp->sm_pixmap = mp->pixmap;
205 mp->sm_mask = mp->mask;
208 /****************************************************************
209 * INTERNAL FUNCTIONS *
210 ****************************************************************/
212 /* Load the image 'path' and return a pointer to the resulting
213 * MaskedPixmap. NULL on failure.
215 static MaskedPixmap *image_from_file(char *path)
217 GdkPixbuf *pixbuf;
218 MaskedPixmap *image;
220 pixbuf = gdk_pixbuf_new_from_file(path);
221 if (!pixbuf)
222 return NULL;
224 image = image_from_pixbuf(pixbuf);
225 gdk_pixbuf_unref(pixbuf);
227 return image;
230 /* Scale src down to fit in max_w, max_h and return the new pixbuf.
231 * If src is small enough, then ref it and return that.
233 static GdkPixbuf *scale_pixbuf(GdkPixbuf *src, int max_w, int max_h)
235 int w, h;
237 w = gdk_pixbuf_get_width(src);
238 h = gdk_pixbuf_get_height(src);
240 if (w <= max_w && h <= max_h)
242 gdk_pixbuf_ref(src);
243 return src;
245 else
247 float scale_x = ((float) w) / max_w;
248 float scale_y = ((float) h) / max_h;
249 float scale = MAX(scale_x, scale_y);
251 return gdk_pixbuf_scale_simple(src,
252 w / scale,
253 h / scale,
254 GDK_INTERP_BILINEAR);
258 /* Turn a full-size pixbuf into a MaskedPixmap */
259 static MaskedPixmap *image_from_pixbuf(GdkPixbuf *full_size)
261 MaskedPixmap *mp;
262 GdkPixbuf *huge_pixbuf, *normal_pixbuf;
263 GdkPixmap *pixmap;
264 GdkBitmap *mask;
266 g_return_val_if_fail(full_size != NULL, NULL);
268 huge_pixbuf = scale_pixbuf(full_size, HUGE_WIDTH, HUGE_HEIGHT);
269 g_return_val_if_fail(huge_pixbuf != NULL, NULL);
270 normal_pixbuf = scale_pixbuf(huge_pixbuf, ICON_WIDTH, ICON_HEIGHT);
271 g_return_val_if_fail(normal_pixbuf != NULL, NULL);
273 gdk_pixbuf_render_pixmap_and_mask(normal_pixbuf, &pixmap, &mask, 128);
274 gdk_pixbuf_unref(normal_pixbuf);
276 if (!pixmap)
278 gdk_pixbuf_unref(huge_pixbuf);
279 return NULL;
282 mp = g_new(MaskedPixmap, 1);
283 mp->ref = 1;
284 mp->pixmap = pixmap;
285 mp->mask = mask;
286 mp->huge_pixbuf = huge_pixbuf;
288 mp->huge_pixmap = NULL;
289 mp->huge_mask = NULL;
291 mp->sm_pixmap = NULL;
292 mp->sm_mask = NULL;
294 return mp;
297 /* Return a pointer to the (static) bad image. The ref counter will ensure
298 * that the image is never freed.
300 static MaskedPixmap *get_bad_image(void)
302 static MaskedPixmap *image = NULL;
304 if (!image)
306 image = g_new(MaskedPixmap, 1);
307 image->ref = 1;
309 image->pixmap= gdk_pixmap_colormap_create_from_xpm_d(NULL,
310 gtk_widget_get_default_colormap(),
311 &image->mask, NULL, bad_xpm);
312 image->huge_pixbuf = NULL;
314 image->huge_pixmap = NULL;
315 image->huge_mask = NULL;
316 image->sm_pixmap = NULL;
317 image->sm_mask = NULL;
320 image->ref++;
322 return image;
325 static MaskedPixmap *load(char *pathname, gpointer user_data)
327 MaskedPixmap *retval;
329 retval = image_from_file(pathname);
331 return retval ? retval : get_bad_image();
334 static void ref(MaskedPixmap *mp, gpointer data)
336 /* printf("[ ref %p %d->%d ]\n", mp, mp->ref, mp->ref + 1); */
338 if (mp)
339 mp->ref++;
342 static void unref(MaskedPixmap *mp, gpointer data)
344 /* printf("[ unref %p %d->%d ]\n", mp, mp->ref, mp->ref - 1); */
346 if (mp && --mp->ref == 0)
348 if (mp->huge_pixbuf)
350 gdk_pixbuf_unref(mp->huge_pixbuf);
353 if (mp->huge_pixmap)
354 gdk_pixmap_unref(mp->huge_pixmap);
355 if (mp->huge_mask)
356 gdk_bitmap_unref(mp->huge_mask);
358 if (mp->pixmap)
359 gdk_pixmap_unref(mp->pixmap);
360 if (mp->mask)
361 gdk_bitmap_unref(mp->mask);
363 if (mp->sm_pixmap)
364 gdk_pixmap_unref(mp->sm_pixmap);
365 if (mp->sm_mask)
366 gdk_bitmap_unref(mp->sm_mask);
368 g_free(mp);
372 static int getref(MaskedPixmap *mp)
374 return mp ? mp->ref : 0;
377 /* Called now and then to clear out old pixmaps */
378 static gint purge(gpointer data)
380 g_fscache_purge(pixmap_cache, PIXMAP_PURGE_TIME);
382 return TRUE;