This patch implements support for icons in user-defined menus into Openbox
[dana/openbox.git] / openbox / imageload.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2    imageload.c for the Openbox window manager
3    by Libor Kadlcik (aka KadlSoft)
4 */
5
6 /*
7     All loaded images are cached. There's no separate cache for the images,
8     instead they are simply stored in image cache (RrImageCache) as RrImages,
9     ready to be used.
10     Every RrImage loaded from file is associated with name of the file. This is
11     done by file name table (RrImageCache.file_name_table), which is a simple
12     hash table, where file names are keys to pointers to RrImage.
13     If you request to load file that is already in image cache, nothing will be
14     loaded and you just got the RrImage from cache.
15     When RrImage is destroyed (see RrImageDestroyNotify), the file name - pointer
16     to RrImage pair is removed from the file name table.
17 */
18
19 #include "debug.h"
20 #include "menu.h"
21 #include "openbox.h"
22 #include "gettext.h"
23 #include "obrender/render.h"
24 #include "obrender/image.h"
25 #include "obrender/imagecache.h"
26 #include "imageload.h"
27 #include <Imlib2.h>
28
29
30 static void CreateFileNameTable(RrImageCache *self)
31 {
32     g_assert(self->file_name_table == NULL);
33     self->file_name_table = g_hash_table_new(&g_str_hash, &g_str_equal);
34 }
35
36 static void DestroyFileNameTable(RrImageCache *self)
37 {
38     g_assert(g_hash_table_size(self->file_name_table) == 0);
39     g_hash_table_destroy(self->file_name_table);
40     self->file_name_table = NULL;
41 }
42
43 /*! Return file name from which this image has been loaded. */
44 static gchar* GetFileName(RrImage *image)
45 {
46     GHashTableIter iter;
47     void *key, *value;
48
49     g_hash_table_iter_init(&iter, image->cache->file_name_table);
50     while (g_hash_table_iter_next(&iter, &key, &value)) {
51         if (value == image)
52             return key;
53     }
54     return NULL;
55 }
56
57 /* RrImage is about to be deleted. So remove it from file name table. */
58 static void RrImageDestroyNotify(RrImage *image)
59 {
60     gchar *file_name = GetFileName(image);
61     g_assert(file_name != NULL);
62     ob_debug("Image \"%s\" no longer needed\n", file_name);
63     g_hash_table_remove(image->cache->file_name_table, file_name);
64     g_free(file_name);
65
66     if (g_hash_table_size(image->cache->file_name_table) == 0) {
67         ob_debug("No RrImage in file_name_table, destroying\n");
68         DestroyFileNameTable(image->cache);
69     }
70 }
71
72 #if (RrDefaultAlphaOffset != 24 || RrDefaultRedOffset != 16 \
73     || RrDefaultGreenOffset != 8 || RrDefaultBlueOffset != 0)
74 #error RrImageFetchFromFile cannot handle current bit layout of RrPixel32.
75 #endif
76
77 /*! Load image from specified file and create RrImage for it (RrImage will be
78     linked into specified image cache). Reference count of the RrImage will
79     be set to 1.
80     If that image has already been loaded into the image cache, RrImage
81     from the cache will be returned and its reference count will be incremented.
82 */
83 RrImage* RrImageFetchFromFile(RrImageCache *cache, const gchar *name)
84 {
85     RrImage *rr_image, *found_rr_image;
86     gint w, h;
87     DATA32 *ro_data;
88
89     imlib_set_color_usage(128);
90
91     if (cache->file_name_table == NULL)
92         CreateFileNameTable(cache);
93
94     /* Find out if that image has already been loaded to this cache. */
95     rr_image = g_hash_table_lookup(cache->file_name_table, name);
96     if (rr_image && rr_image->cache == cache) {
97         ob_debug("\"%s\" already loaded in this image cache.\n", name);
98         RrImageRef(rr_image);
99         return rr_image;
100     }
101
102     Imlib_Image imlib_image = imlib_load_image(name);
103     if (imlib_image == NULL) {
104         g_message(_("Cannot load image from file \"%s\""), name);
105         return NULL;
106     }
107
108     /* Get data and dimensions of the image. */
109     imlib_context_set_image(imlib_image);
110     g_message("Alpha = %d\n", imlib_image_has_alpha());
111     ro_data = imlib_image_get_data_for_reading_only();
112     w = imlib_image_get_width();
113     h = imlib_image_get_height();
114     ob_debug("Loaded \"%s\", dimensions %dx%d\n", name, w, h);
115
116     /* There must not be any duplicated pictures in RrImageCache. */
117     found_rr_image = RrImageCacheFind(cache, ro_data, w, h);
118     if (found_rr_image) {
119         rr_image = found_rr_image;
120         RrImageRef(rr_image);
121         ob_debug("Image \"%s\" is duplicate\n", name);
122     }
123     else {
124         /* Create RrImage from the image and add it to file name table. */
125         rr_image = RrImageNew(cache);
126         RrImageSetDestroyFunc(rr_image, &RrImageDestroyNotify);
127         /* XXX: Is Imlib2's format of DATA32 always identical to RrPixel32? */
128         RrImageAddPicture(rr_image, ro_data, w, h);
129         g_hash_table_insert(cache->file_name_table, g_strdup(name), rr_image);
130     }
131
132     imlib_free_image();
133
134     return rr_image;
135 }