r284: Moved most of the icons from pixmaps to MIME-icons (outside ROX-Filer).
[rox-filer.git] / ROX-Filer / src / pixmaps.c
blobff75ad555407559a100f488c6341288aa102baf0
1 /*
2 * $Id$
4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2000, Thomas Leonard, <tal197@ecs.soton.ac.uk>.
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 "fscache.h"
50 #include "support.h"
51 #include "gui_support.h"
52 #include "pixmaps.h"
54 GFSCache *pixmap_cache = NULL;
56 static char * bad_xpm[] = {
57 "12 12 3 1",
58 " c #000000000000",
59 ". c #FFFF00000000",
60 "X c #FFFFFFFFFFFF",
61 " ",
62 " ..XXXXXX.. ",
63 " ...XXXX... ",
64 " X...XX...X ",
65 " XX......XX ",
66 " XXX....XXX ",
67 " XXX....XXX ",
68 " XX......XX ",
69 " X...XX...X ",
70 " ...XXXX... ",
71 " ..XXXXXX.. ",
72 " "};
74 MaskedPixmap *default_pixmap[LAST_DEFAULT_PIXMAP];
76 /* Static prototypes */
78 static MaskedPixmap *load_pixmap(char *name);
79 static void load_default_pixmaps(void);
80 static MaskedPixmap *load(char *pathname, gpointer data);
81 static void ref(MaskedPixmap *mp, gpointer data);
82 static void unref(MaskedPixmap *mp, gpointer data);
83 static int getref(MaskedPixmap *mp);
84 static gint purge(gpointer data);
85 static MaskedPixmap *image_from_file(char *path);
86 static MaskedPixmap *get_bad_image(void);
87 #ifdef HAVE_IMLIB
88 static GdkImlibImage *make_half_size(GdkImlibImage *big);
89 #endif
92 /****************************************************************
93 * EXTERNAL INTERFACE *
94 ****************************************************************/
96 void pixmaps_init(void)
98 #ifdef HAVE_IMLIB
99 gdk_imlib_init();
100 #endif
102 pixmap_cache = g_fscache_new((GFSLoadFunc) load,
103 (GFSRefFunc) ref,
104 (GFSRefFunc) unref,
105 (GFSGetRefFunc) getref,
106 NULL, /* Update func */
107 NULL);
109 gtk_timeout_add(10000, purge, NULL);
111 load_default_pixmaps();
114 /* 'name' is relative to APP_DIR. Always returns with a valid image. */
115 MaskedPixmap *load_pixmap(char *name)
117 MaskedPixmap *retval;
119 retval = image_from_file(make_path(getenv("APP_DIR"), name)->str);
120 if (!retval)
121 retval = get_bad_image();
122 return retval;
125 /* Load all the standard pixmaps */
126 static void load_default_pixmaps(void)
128 default_pixmap[TYPE_ERROR] = load_pixmap("pixmaps/error.xpm");
129 default_pixmap[TYPE_UNKNOWN] = load_pixmap("pixmaps/unknown.xpm");
130 default_pixmap[TYPE_SYMLINK] = load_pixmap("pixmaps/symlink.xpm");
132 default_pixmap[TYPE_UNMOUNTED] = load_pixmap("pixmaps/mount.xpm");
133 default_pixmap[TYPE_MOUNTED] = load_pixmap("pixmaps/mounted.xpm");
134 default_pixmap[TYPE_MULTIPLE] = load_pixmap("pixmaps/multiple.xpm");
135 default_pixmap[TYPE_EXEC_FILE] = load_pixmap("pixmaps/exec.xpm");
136 default_pixmap[TYPE_APPDIR] = load_pixmap("pixmaps/application.xpm");
138 default_pixmap[TOOLBAR_UP_ICON] = load_pixmap("pixmaps/up.xpm");
139 default_pixmap[TOOLBAR_HOME_ICON] = load_pixmap("pixmaps/home.xpm");
140 default_pixmap[TOOLBAR_REFRESH_ICON] =
141 load_pixmap("pixmaps/refresh.xpm");
144 void pixmap_ref(MaskedPixmap *mp)
146 ref(mp, pixmap_cache->user_data);
149 void pixmap_unref(MaskedPixmap *mp)
151 unref(mp, pixmap_cache->user_data);
154 void pixmap_make_small(MaskedPixmap *mp)
156 if (mp->sm_pixmap)
157 return;
159 #ifdef HAVE_IMLIB
160 if (mp->image)
162 GdkImlibImage *small;
164 small = make_half_size(mp->image);
166 if (small && gdk_imlib_render(small,
167 small->rgb_width, small->rgb_height))
169 mp->sm_pixmap = gdk_imlib_move_image(small);
170 mp->sm_mask = gdk_imlib_move_mask(small);
171 mp->sm_width = small->width;
172 mp->sm_height = small->height;
175 if (small)
176 gdk_imlib_kill_image(small);
177 if (mp->sm_pixmap)
178 return;
180 #endif
181 gdk_pixmap_ref(mp->pixmap);
182 if (mp->mask)
183 gdk_bitmap_ref(mp->mask);
184 mp->sm_pixmap = mp->pixmap;
185 mp->sm_mask = mp->mask;
186 mp->sm_width = mp->width;
187 mp->sm_height = mp->height;
190 /****************************************************************
191 * INTERNAL FUNCTIONS *
192 ****************************************************************/
194 /* Load the image 'path' and return a pointer to the resulting
195 * MaskedPixmap. NULL on failure.
197 static MaskedPixmap *image_from_file(char *path)
199 MaskedPixmap *mp;
200 GdkPixmap *pixmap;
201 GdkBitmap *mask;
202 int width;
203 int height;
204 #ifdef HAVE_IMLIB
205 GdkImlibImage *image;
207 image = gdk_imlib_load_image(path);
208 if (!image)
209 return NULL;
211 /* Avoid ImLib cache - ours is better! */
212 gdk_imlib_changed_image(image);
214 if (!gdk_imlib_render(image, image->rgb_width, image->rgb_height))
216 gdk_imlib_kill_image(image);
217 return NULL;
220 pixmap = image->pixmap;
221 mask = image->shape_mask;
222 width = image->width;
223 height = image->height;
224 #else
225 pixmap = gdk_pixmap_colormap_create_from_xpm(NULL,
226 gtk_widget_get_default_colormap(),
227 &mask,
229 path);
231 if (!pixmap)
232 return NULL;
233 width = ((GdkPixmapPrivate *) pixmap)->width;
234 height = ((GdkPixmapPrivate *) pixmap)->height;
235 #endif
237 mp = g_new(MaskedPixmap, 1);
238 mp->ref = 1;
239 mp->pixmap = pixmap;
240 mp->mask = mask;
241 mp->width = width;
242 mp->height = height;
243 #ifdef HAVE_IMLIB
244 mp->image = image;
245 #endif
246 mp->sm_pixmap = NULL;
247 mp->sm_mask = NULL;
249 return mp;
252 /* Return a pointer to the (static) bad image. The ref counter will ensure
253 * that the image is never freed.
255 static MaskedPixmap *get_bad_image(void)
257 static MaskedPixmap *image = NULL;
259 if (!image)
261 image = g_new(MaskedPixmap, 1);
262 image->ref = 1;
264 image->pixmap= gdk_pixmap_colormap_create_from_xpm_d(NULL,
265 gtk_widget_get_default_colormap(),
266 &image->mask, NULL, bad_xpm);
267 #ifdef HAVE_IMLIB
268 image->image = NULL;
269 #endif
272 image->ref++;
273 image->width = ((GdkPixmapPrivate *) image->pixmap)->width;
274 image->height = ((GdkPixmapPrivate *) image->pixmap)->height;
276 return image;
279 static MaskedPixmap *load(char *pathname, gpointer user_data)
281 return image_from_file(pathname);
284 static void ref(MaskedPixmap *mp, gpointer data)
286 /* printf("[ ref %p %d->%d ]\n", mp, mp->ref, mp->ref + 1); */
288 if (mp)
289 mp->ref++;
292 static void unref(MaskedPixmap *mp, gpointer data)
294 /* printf("[ unref %p %d->%d ]\n", mp, mp->ref, mp->ref - 1); */
296 if (mp && --mp->ref == 0)
298 #ifdef HAVE_IMLIB
299 if (mp->image)
301 gdk_imlib_kill_image(mp->image);
303 else
304 #endif
306 gdk_pixmap_unref(mp->pixmap);
307 if (mp->mask)
308 gdk_bitmap_unref(mp->mask);
310 if (mp->sm_pixmap)
311 gdk_pixmap_unref(mp->sm_pixmap);
312 if (mp->sm_mask)
313 gdk_bitmap_unref(mp->sm_mask);
314 g_free(mp);
318 static int getref(MaskedPixmap *mp)
320 return mp->ref;
323 /* Called now and then to clear out old pixmaps */
324 static gint purge(gpointer data)
326 g_fscache_purge(pixmap_cache, PIXMAP_PURGE_TIME);
328 return TRUE;
331 #ifdef HAVE_IMLIB
333 #define GREY_BG 0xd8
335 /* Returns data to make an 1/4 size image of 'big'. g_free() the result. */
336 static GdkImlibImage *make_half_size(GdkImlibImage *big)
338 int line_size = big->width * 3;
339 int sw = big->width >> 1;
340 int sh = big->height >> 1;
341 GdkImlibColor tr; /* Mask colour */
342 unsigned char *small_data, *in, *out;
343 GdkImlibImage *small;
344 int x, y;
346 gdk_imlib_get_image_shape(big, &tr);
347 small_data = g_malloc(sw * sh * 3);
349 out = small_data;
351 for (y = 0; y < sh; y++)
353 in = big->rgb_data + y * line_size * 2;
355 for (x = 0; x < sw; x++)
357 int r1 = in[0], r2 = in[3];
358 int r3 = in[0 + line_size], r4 = in[3 + line_size];
359 int g1 = in[1], g2 = in[4];
360 int g3 = in[1 + line_size], g4 = in[4 + line_size];
361 int b1 = in[2], b2 = in[5];
362 int b3 = in[2 + line_size], b4 = in[5 + line_size];
363 int m = 0; /* No. trans pixels */
365 if (r1 == tr.r && g1 == tr.g && b1 == tr.b)
366 r1 = g1 = b1 = GREY_BG, m++;
367 if (r2 == tr.r && g2 == tr.g && b2 == tr.b)
368 r2 = g2 = b2 = GREY_BG, m++;
369 if (r3 == tr.r && g3 == tr.g && b3 == tr.b)
370 r3 = g3 = b3 = GREY_BG, m++;
371 if (r4 == tr.r && g4 == tr.g && b4 == tr.b)
372 r4 = g4 = b4 = GREY_BG, m++;
374 if (m < 3)
376 out[0] = (r1 + r2 + r3 + r4) >> 2;
377 out[1] = (g1 + g2 + g3 + g4) >> 2;
378 out[2] = (b1 + b2 + b3 + b4) >> 2;
380 else
382 out[0] = tr.r;
383 out[1] = tr.g;
384 out[2] = tr.b;
387 in += 6;
388 out += 3;
392 small = gdk_imlib_create_image_from_data(small_data, NULL, sw, sh);
393 g_free(small_data);
395 if (small)
396 gdk_imlib_set_image_shape(small, &tr);
398 return small;
400 #endif