diff options
| -rw-r--r-- | Makefile.am | 7 | ||||
| -rw-r--r-- | configure.ac | 28 | ||||
| -rw-r--r-- | obrender/image.c | 8 | ||||
| -rw-r--r-- | obrender/imagecache.c | 2 | ||||
| -rw-r--r-- | obrender/imagecache.h | 4 | ||||
| -rw-r--r-- | obrender/render.h | 6 | ||||
| -rw-r--r-- | openbox/config.c | 10 | ||||
| -rw-r--r-- | openbox/config.h | 2 | ||||
| -rw-r--r-- | openbox/imageload.c | 135 | ||||
| -rw-r--r-- | openbox/imageload.h | 11 | ||||
| -rw-r--r-- | openbox/menu.c | 24 | ||||
| -rw-r--r-- | openbox/translate.h | 2 |
12 files changed, 239 insertions, 0 deletions
diff --git a/Makefile.am b/Makefile.am index 9617a1ca..f13d52ac 100644 --- a/Makefile.am +++ b/Makefile.am @@ -150,6 +150,7 @@ openbox_openbox_CPPFLAGS = \ $(GLIB_CFLAGS) \ $(LIBSN_CFLAGS) \ $(XML_CFLAGS) \ + $(IMLIB2_CFLAGS) \ -DLOCALEDIR=\"$(localedir)\" \ -DDATADIR=\"$(datadir)\" \ -DCONFIGDIR=\"$(configdir)\" \ @@ -163,6 +164,7 @@ openbox_openbox_LDADD = \ $(XML_LIBS) \ $(EFENCE_LIBS) \ $(LIBINTL) \ + $(IMLIB2_LIBS) \ obrender/libobrender.la \ obt/libobt.la openbox_openbox_LDFLAGS = -export-dynamic @@ -242,6 +244,7 @@ openbox_openbox_SOURCES = \ openbox/grab.h \ openbox/group.c \ openbox/group.h \ + openbox/imageload.h \ openbox/keyboard.c \ openbox/keyboard.h \ openbox/keytree.c \ @@ -281,6 +284,10 @@ openbox_openbox_SOURCES = \ openbox/window.c \ openbox/window.h +if USE_IMLIB2 + openbox_openbox_SOURCES += openbox/imageload.c +endif + ## gnome-panel-control ## tools_gnome_panel_control_gnome_panel_control_CPPFLAGS = \ diff --git a/configure.ac b/configure.ac index aa575657..99b416a5 100644 --- a/configure.ac +++ b/configure.ac @@ -157,6 +157,33 @@ else xcursor_found=no fi +AC_ARG_ENABLE(imlib2, + AC_HELP_STRING( + [--disable-imlib2], + [disable use of Imlib2 image library for loading icons. [[default=enabled]]] + ), + [enable_imlib2=$enableeval], + [enable_imlib2=yes] +) + +if test "$enable_imlib2" = yes; then +PKG_CHECK_MODULES(IMLIB2, [imlib2], + [ + AC_DEFINE(USE_IMLIB2, [1], [Use Imlib2 image library]) + AC_SUBST(IMLIB2_CFLAGS) + AC_SUBST(IMLIB2_LIBS) + imlib2_found=yes + ], + [ + imlib2_found=no + ] +) +else + imlib2_found=no +fi + +AM_CONDITIONAL(USE_IMLIB2, [test $imlib2_found = yes]) + dnl Check for session management X11_SM @@ -193,5 +220,6 @@ AC_MSG_RESULT([Compiling with these options: Startup Notification... $sn_found X Cursor Library... $xcursor_found Session Management... $SM + Imlib2 library... $imlib2_found ]) AC_MSG_RESULT([configure complete, now type "make"]) diff --git a/obrender/image.c b/obrender/image.c index 924504fd..c65cd2a5 100644 --- a/obrender/image.c +++ b/obrender/image.c @@ -325,6 +325,12 @@ RrImage* RrImageNew(RrImageCache *cache) return self; } +/*! Set function that will be called just before RrImage is destroyed. */ +void RrImageSetDestroyFunc(RrImage *image, RrImageDestroyFunc func) +{ + image->destroy_func = func; +} + void RrImageRef(RrImage *self) { ++self->ref; @@ -339,6 +345,8 @@ void RrImageUnref(RrImage *self) "Image 0x%lx", (gulong)self); #endif */ + if (self->destroy_func) + self->destroy_func(self); while (self->n_original > 0) RemovePicture(self, &self->original, 0, &self->n_original); while (self->n_resized > 0) diff --git a/obrender/imagecache.c b/obrender/imagecache.c index 9c605f9d..fde1e7a0 100644 --- a/obrender/imagecache.c +++ b/obrender/imagecache.c @@ -34,6 +34,7 @@ RrImageCache* RrImageCacheNew(gint max_resized_saved) self->max_resized_saved = max_resized_saved; self->table = g_hash_table_new((GHashFunc)RrImagePicHash, (GEqualFunc)RrImagePicEqual); + self->file_name_table = NULL; return self; } @@ -46,6 +47,7 @@ void RrImageCacheUnref(RrImageCache *self) { if (self && --self->ref == 0) { g_assert(g_hash_table_size(self->table) == 0); + g_assert(self->file_name_table == NULL); g_hash_table_unref(self->table); g_free(self); diff --git a/obrender/imagecache.h b/obrender/imagecache.h index 4ad2deae..a61fae67 100644 --- a/obrender/imagecache.h +++ b/obrender/imagecache.h @@ -46,6 +46,10 @@ struct _RrImageCache { gint max_resized_saved; GHashTable *table; + + /* Used to find out if an image file has already been loaded. + Quick file_name -> RrImage lookup. */ + GHashTable *file_name_table; }; #endif diff --git a/obrender/render.h b/obrender/render.h index 7bea1b54..7aa9d698 100644 --- a/obrender/render.h +++ b/obrender/render.h @@ -232,6 +232,8 @@ struct _RrImagePic { gint sum; }; +typedef void (*RrImageDestroyFunc)(RrImage *image); + /*! An RrImage is a sort of meta-image. It can contain multiple versions of an image at different sizes, which may or may not be completely different pictures */ @@ -250,6 +252,10 @@ struct _RrImage { RrImage. */ RrImagePic **resized; gint n_resized; + + /* This function (if not NULL) will be called just before destroying + RrImage. */ + RrImageDestroyFunc destroy_func; }; /* these are the same on all endian machines because it seems to be dependant diff --git a/openbox/config.c b/openbox/config.c index 0241e3f4..304079c9 100644 --- a/openbox/config.c +++ b/openbox/config.c @@ -96,6 +96,7 @@ guint config_submenu_show_delay; guint config_submenu_hide_delay; gboolean config_menu_client_list_icons; gboolean config_menu_manage_desktops; +gboolean config_menu_user_show_icons; GSList *config_menu_files; @@ -820,6 +821,14 @@ static void parse_menu(xmlNodePtr node, gpointer d) config_menu_client_list_icons = obt_xml_node_bool(n); if ((n = obt_xml_find_node(node, "manageDesktops"))) config_menu_manage_desktops = obt_xml_node_bool(n); + if ((n = obt_xml_find_node(node, "showIcons"))) { + config_menu_user_show_icons = obt_xml_node_bool(n); + #ifndef USE_IMLIB2 + if (config_menu_user_show_icons) + g_message(_("Openbox was compiled without Imlib2." + " Icons in user-defined menus will NOT be loaded.")); + #endif + } while ((node = obt_xml_find_node(node, "file"))) { gchar *c = obt_xml_node_string(node); @@ -1025,6 +1034,7 @@ void config_startup(ObtXmlInst *i) config_menu_client_list_icons = TRUE; config_menu_manage_desktops = TRUE; config_menu_files = NULL; + config_menu_user_show_icons = TRUE; obt_xml_register(i, "menu", parse_menu, NULL); diff --git a/openbox/config.h b/openbox/config.h index 89c4c6f6..1825f477 100644 --- a/openbox/config.h +++ b/openbox/config.h @@ -197,6 +197,8 @@ extern guint config_submenu_hide_delay; extern gboolean config_menu_client_list_icons; /*! Show manage desktops in client_list_menu */ extern gboolean config_menu_manage_desktops; +/*! Load & show icons in user-defined menus */ +extern gboolean config_menu_user_show_icons; /*! User-specified menu files */ extern GSList *config_menu_files; /*! Per app settings */ diff --git a/openbox/imageload.c b/openbox/imageload.c new file mode 100644 index 00000000..c80aa134 --- /dev/null +++ b/openbox/imageload.c @@ -0,0 +1,135 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*- + imageload.c for the Openbox window manager + by Libor Kadlcik (aka KadlSoft) +*/ + +/* + All loaded images are cached. There's no separate cache for the images, + instead they are simply stored in image cache (RrImageCache) as RrImages, + ready to be used. + Every RrImage loaded from file is associated with name of the file. This is + done by file name table (RrImageCache.file_name_table), which is a simple + hash table, where file names are keys to pointers to RrImage. + If you request to load file that is already in image cache, nothing will be + loaded and you just got the RrImage from cache. + When RrImage is destroyed (see RrImageDestroyNotify), the file name - pointer + to RrImage pair is removed from the file name table. +*/ + +#include "debug.h" +#include "menu.h" +#include "openbox.h" +#include "gettext.h" +#include "obrender/render.h" +#include "obrender/image.h" +#include "obrender/imagecache.h" +#include "imageload.h" +#include <Imlib2.h> + + +static void CreateFileNameTable(RrImageCache *self) +{ + g_assert(self->file_name_table == NULL); + self->file_name_table = g_hash_table_new(&g_str_hash, &g_str_equal); +} + +static void DestroyFileNameTable(RrImageCache *self) +{ + g_assert(g_hash_table_size(self->file_name_table) == 0); + g_hash_table_destroy(self->file_name_table); + self->file_name_table = NULL; +} + +/*! Return file name from which this image has been loaded. */ +static gchar* GetFileName(RrImage *image) +{ + GHashTableIter iter; + void *key, *value; + + g_hash_table_iter_init(&iter, image->cache->file_name_table); + while (g_hash_table_iter_next(&iter, &key, &value)) { + if (value == image) + return key; + } + return NULL; +} + +/* RrImage is about to be deleted. So remove it from file name table. */ +static void RrImageDestroyNotify(RrImage *image) +{ + gchar *file_name = GetFileName(image); + g_assert(file_name != NULL); + ob_debug("Image \"%s\" no longer needed\n", file_name); + g_hash_table_remove(image->cache->file_name_table, file_name); + g_free(file_name); + + if (g_hash_table_size(image->cache->file_name_table) == 0) { + ob_debug("No RrImage in file_name_table, destroying\n"); + DestroyFileNameTable(image->cache); + } +} + +#if (RrDefaultAlphaOffset != 24 || RrDefaultRedOffset != 16 \ + || RrDefaultGreenOffset != 8 || RrDefaultBlueOffset != 0) +#error RrImageFetchFromFile cannot handle current bit layout of RrPixel32. +#endif + +/*! Load image from specified file and create RrImage for it (RrImage will be + linked into specified image cache). Reference count of the RrImage will + be set to 1. + If that image has already been loaded into the image cache, RrImage + from the cache will be returned and its reference count will be incremented. +*/ +RrImage* RrImageFetchFromFile(RrImageCache *cache, const gchar *name) +{ + RrImage *rr_image, *found_rr_image; + gint w, h; + DATA32 *ro_data; + + imlib_set_color_usage(128); + + if (cache->file_name_table == NULL) + CreateFileNameTable(cache); + + /* Find out if that image has already been loaded to this cache. */ + rr_image = g_hash_table_lookup(cache->file_name_table, name); + if (rr_image && rr_image->cache == cache) { + ob_debug("\"%s\" already loaded in this image cache.\n", name); + RrImageRef(rr_image); + return rr_image; + } + + Imlib_Image imlib_image = imlib_load_image(name); + if (imlib_image == NULL) { + g_message(_("Cannot load image from file \"%s\""), name); + return NULL; + } + + /* Get data and dimensions of the image. */ + imlib_context_set_image(imlib_image); + g_message("Alpha = %d\n", imlib_image_has_alpha()); + ro_data = imlib_image_get_data_for_reading_only(); + w = imlib_image_get_width(); + h = imlib_image_get_height(); + ob_debug("Loaded \"%s\", dimensions %dx%d\n", name, w, h); + + /* There must not be any duplicated pictures in RrImageCache. */ + found_rr_image = RrImageCacheFind(cache, ro_data, w, h); + if (found_rr_image) { + rr_image = found_rr_image; + RrImageRef(rr_image); + ob_debug("Image \"%s\" is duplicate\n", name); + } + else { + /* Create RrImage from the image and add it to file name table. */ + rr_image = RrImageNew(cache); + RrImageSetDestroyFunc(rr_image, &RrImageDestroyNotify); + /* XXX: Is Imlib2's format of DATA32 always identical to RrPixel32? */ + RrImageAddPicture(rr_image, ro_data, w, h); + g_hash_table_insert(cache->file_name_table, g_strdup(name), rr_image); + } + + imlib_free_image(); + + return rr_image; +} diff --git a/openbox/imageload.h b/openbox/imageload.h new file mode 100644 index 00000000..1c7addf3 --- /dev/null +++ b/openbox/imageload.h @@ -0,0 +1,11 @@ +#ifndef __imageload_h +#define __imageload_h + +#ifdef USE_IMLIB2 +#include "obrender/render.h" +RrImage* RrImageFetchFromFile(RrImageCache *cache, const gchar *name); +#else +#define RrImageFetchFromFile(cache, name) NULL +#endif + +#endif diff --git a/openbox/menu.c b/openbox/menu.c index fcf5d168..f53e4f0b 100644 --- a/openbox/menu.c +++ b/openbox/menu.c @@ -36,6 +36,7 @@ #include "gettext.h" #include "obt/xml.h" #include "obt/paths.h" +#include "imageload.h" typedef struct _ObMenuParseState ObMenuParseState; @@ -269,8 +270,20 @@ static void parse_menu_item(xmlNodePtr node, gpointer data) { ObMenuParseState *state = data; gchar *label; + #ifdef USE_IMLIB2 + gchar *icon; + #endif + ObMenuEntry *e; if (state->parent) { + #ifdef USE_IMLIB2 + /* Don't try to extract "icon" attribute if icons in user-defined + menus are not enabled. */ + if (!(config_menu_user_show_icons && + obt_xml_attr_string(node, "icon", &icon))) + icon = NULL; + #endif + if (obt_xml_attr_string(node, "label", &label)) { GSList *acts = NULL; @@ -281,8 +294,19 @@ static void parse_menu_item(xmlNodePtr node, gpointer data) acts = g_slist_append(acts, action); node = obt_xml_find_node(node->next, "action"); } + e = menu_add_normal(state->parent, -1, label, acts, TRUE); + + #ifdef USE_IMLIB2 + if (icon) { /* Icon will be used. */ + e->data.normal.icon = RrImageFetchFromFile(ob_rr_icons, icon); + if (e->data.normal.icon) { + e->data.normal.icon_alpha = 0xff; + } + g_free(icon); + } menu_add_normal(state->parent, -1, label, acts, TRUE); + #endif g_free(label); } } diff --git a/openbox/translate.h b/openbox/translate.h index 8249514e..bffdc9b8 100644 --- a/openbox/translate.h +++ b/openbox/translate.h @@ -24,4 +24,6 @@ gboolean translate_button(const gchar *str, guint *state, guint *keycode); gboolean translate_key(const gchar *str, guint *state, guint *keycode); +void RrImageSetDestroyFunc(RrImage *image, RrImageDestroyFunc func); + #endif |
