summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am7
-rw-r--r--configure.ac28
-rw-r--r--obrender/image.c8
-rw-r--r--obrender/imagecache.c2
-rw-r--r--obrender/imagecache.h4
-rw-r--r--obrender/render.h6
-rw-r--r--openbox/config.c10
-rw-r--r--openbox/config.h2
-rw-r--r--openbox/imageload.c135
-rw-r--r--openbox/imageload.h11
-rw-r--r--openbox/menu.c24
-rw-r--r--openbox/translate.h2
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