aboutsummaryrefslogtreecommitdiffstats
path: root/e-util/e-icon-factory.c
diff options
context:
space:
mode:
Diffstat (limited to 'e-util/e-icon-factory.c')
-rw-r--r--e-util/e-icon-factory.c265
1 files changed, 167 insertions, 98 deletions
diff --git a/e-util/e-icon-factory.c b/e-util/e-icon-factory.c
index 715a18295d..26b3a80e19 100644
--- a/e-util/e-icon-factory.c
+++ b/e-util/e-icon-factory.c
@@ -1,36 +1,44 @@
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
-/* e-icon-factory.c - Icon factory for the Evolution components.
+/*
+ * Authors: Jeffrey Stedfast <fejj@novell.com>
*
- * Copyright (C) 2002 Ximian, Inc.
+ * Copyright 2004 Novell, Inc. (www.novell.com)
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
*
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
*
- * Author: Ettore Perazzoli <ettore@ximian.com>, Michael Terry <mterry@fastmail.fm>
*/
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
+#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+
#include <pthread.h>
#include <libgnomeui/gnome-icon-theme.h>
#include <e-util/e-icon-factory.h>
-#include "art/empty.xpm"
+#include "art/broken-image-16.xpm"
+#include "art/broken-image-24.xpm"
static int sizes[E_ICON_NUM_SIZES] = {
16, /* menu */
@@ -44,32 +52,26 @@ static int sizes[E_ICON_NUM_SIZES] = {
typedef struct {
char *name;
- GdkPixbuf *pixbuf[E_ICON_NUM_SIZES];
+ GdkPixbuf *pixbuf;
} Icon;
-/* Hash of all the icons. */
-static GHashTable *name_to_icon = NULL;
-static GnomeIconTheme *icon_theme = NULL;
-static GdkPixbuf *empty_pixbuf = NULL;
-static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+static GdkPixbuf *broken16_pixbuf = NULL;
+static GdkPixbuf *broken24_pixbuf = NULL;
+static GHashTable *name_to_icon = NULL;
+static GnomeIconTheme *icon_theme = NULL;
+static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
-/* Creating and destroying icons. */
/* Note: takes ownership of the pixbufs (eg. does not ref them) */
static Icon *
-icon_new (const char *name, GdkPixbuf **pixbufs)
+icon_new (const char *name, GdkPixbuf *pixbuf)
{
Icon *icon;
- int i;
icon = g_malloc0 (sizeof (Icon));
icon->name = g_strdup (name);
-
- if (pixbufs != NULL) {
- for (i = 0; i < E_ICON_NUM_SIZES; i++)
- icon->pixbuf[i] = pixbufs[i];
- }
+ icon->pixbuf = pixbuf;
return icon;
}
@@ -77,54 +79,81 @@ icon_new (const char *name, GdkPixbuf **pixbufs)
static void
icon_free (Icon *icon)
{
- int i;
-
g_free (icon->name);
-
- for (i = 0; i < E_ICON_NUM_SIZES; i++) {
- if (icon->pixbuf[i] != NULL)
- g_object_unref (icon->pixbuf[i]);
- }
-
+ if (icon->pixbuf)
+ g_object_unref (icon->pixbuf);
g_free (icon);
}
-/* Loading icons. */
-
static Icon *
-load_icon (const char *icon_name)
+load_icon (const char *icon_name, int size, int scale)
{
- GdkPixbuf *pixbufs[E_ICON_NUM_SIZES];
- char *filename;
- int i, j;
-
- for (i = 0; i < E_ICON_NUM_SIZES; i++) {
- GdkPixbuf *unscaled;
- int size = sizes[i];
-
- if (!(filename = gnome_icon_theme_lookup_icon (icon_theme, icon_name, size, NULL, NULL)))
- filename = g_strdup (icon_name);
-
- unscaled = gdk_pixbuf_new_from_file (filename, NULL);
- if (!unscaled)
- goto exception;
- pixbufs[i] = gdk_pixbuf_scale_simple (unscaled, size, size, GDK_INTERP_BILINEAR);
- g_object_unref (unscaled);
- g_free (filename);
+ GdkPixbuf *pixbuf, *unscaled = NULL;
+ char *filename = NULL;
+
+ filename = gnome_icon_theme_lookup_icon (icon_theme, icon_name, size, NULL, NULL);
+ if (!filename || !(unscaled = gdk_pixbuf_new_from_file (filename, NULL))) {
+ if (scale) {
+ struct dirent *dent;
+ int width, height;
+ size_t baselen;
+ GString *path;
+ DIR *dir;
+ char *x;
+
+ path = g_string_new (EVOLUTION_ICONSDIR);
+ if (path->str[path->len - 1] != '/')
+ g_string_append_c (path, '/');
+
+ baselen = path->len;
+
+ if (!(dir = opendir (path->str))) {
+ g_string_free (path, TRUE);
+ goto done;
+ }
+
+ /* scan icon directories looking for an icon with a size >= the size we need. */
+ while ((dent = readdir (dir))) {
+ if (!(dent->d_name[0] >= '1' && dent->d_name[0] <= '9'))
+ continue;
+
+ if (((width = strtol (dent->d_name, &x, 10)) < size) || *x != 'x')
+ continue;
+
+ if (((height = strtol (x + 1, &x, 10)) != width) || *x != '\0')
+ continue;
+
+ /* if the icon exists in this directory, we can [use/scale] it */
+ g_string_truncate (path, baselen);
+ g_string_append_printf (path, "%s/%s", dent->d_name, icon_name);
+ if ((unscaled = gdk_pixbuf_new_from_file (path->str, NULL)))
+ break;
+ }
+
+ g_string_free (path, TRUE);
+ closedir (dir);
+ } else {
+ g_free (filename);
+ filename = g_strdup_printf (EVOLUTION_ICONSDIR "/%dx%d/%s", size, size, icon_name);
+ unscaled = gdk_pixbuf_new_from_file (filename, NULL);
+ }
}
- return icon_new (icon_name, pixbufs);
+ done:
- exception:
-
- for (j = 0; j < i; j++)
- g_object_unref (pixbufs[j]);
+ g_free (filename);
+ if (unscaled != NULL) {
+ pixbuf = gdk_pixbuf_scale_simple (unscaled, size, size, GDK_INTERP_BILINEAR);
+ g_object_unref (unscaled);
+ } else {
+ pixbuf = NULL;
+ }
- return NULL;
+ return icon_new (icon_name, pixbuf);
}
-/* termporary workaround for code that has not yet been ported to the new icon_size API */
+/* temporary workaround for code that has not yet been ported to the new icon_size API */
static int
pixel_size_to_icon_size (int pixel_size)
{
@@ -140,17 +169,23 @@ pixel_size_to_icon_size (int pixel_size)
return icon_size;
}
-/* Public API. */
+/**
+ * e_icon_factory_init:
+ *
+ * Initialises the icon factory.
+ **/
void
e_icon_factory_init (void)
{
if (name_to_icon != NULL)
return;
+ icon_theme = gnome_icon_theme_new ();
name_to_icon = g_hash_table_new (g_str_hash, g_str_equal);
- icon_theme = gnome_icon_theme_new ();
- empty_pixbuf = gdk_pixbuf_new_from_xpm_data ((const char **) empty_xpm);
+
+ broken16_pixbuf = gdk_pixbuf_new_from_xpm_data ((const char **) broken_image_16_xpm);
+ broken24_pixbuf = gdk_pixbuf_new_from_xpm_data ((const char **) broken_image_24_xpm);
}
@@ -161,6 +196,11 @@ icon_foreach_free (gpointer key, gpointer value, gpointer user_data)
}
+/**
+ * e_icon_factory_shutdown:
+ *
+ * Shuts down the icon factory (cleans up all cached icons, etc).
+ **/
void
e_icon_factory_shutdown (void)
{
@@ -169,7 +209,8 @@ e_icon_factory_shutdown (void)
g_hash_table_foreach (name_to_icon, (GHFunc) icon_foreach_free, NULL);
g_hash_table_destroy (name_to_icon);
- g_object_unref (empty_pixbuf);
+ g_object_unref (broken16_pixbuf);
+ g_object_unref (broken24_pixbuf);
g_object_unref (icon_theme);
name_to_icon = NULL;
}
@@ -193,6 +234,7 @@ e_icon_factory_get_icon_filename (const char *icon_name, int icon_size)
g_return_val_if_fail (strcmp (icon_name, ""), NULL);
if (icon_size >= E_ICON_NUM_SIZES) {
+ g_warning ("calling e_icon_factory_get_icon_filename with unknown icon_size value (%d)", icon_size);
if ((icon_size = pixel_size_to_icon_size (icon_size)) == -1)
return NULL;
}
@@ -204,45 +246,70 @@ e_icon_factory_get_icon_filename (const char *icon_name, int icon_size)
return filename;
}
-/* Loads the themed version of the icon name at the appropriate size.
- The returned icon is guaranteed to be the requested size and exist. If
- the themed icon cannot be found, an empty icon is returned. */
+
+/**
+ * e_icon_factory_get_icon:
+ * @icon_name: name of the icon
+ * @icon_size: size of the icon (one of the E_ICON_SIZE_* enum values)
+ *
+ * Returns the specified icon of the requested size (may perform
+ * scaling to achieve this) for the user's current icon theme. If the
+ * icon cannot be found, it falls back to loading the requested icon
+ * from Evolution's icon set installed from the art/ srcdir. If even
+ * that fails to find the requested icon, then a "broken-image" icon
+ * is returned.
+ **/
GdkPixbuf *
e_icon_factory_get_icon (const char *icon_name, int icon_size)
{
GdkPixbuf *pixbuf;
+ char *icon_key;
Icon *icon;
int size;
if (icon_size >= E_ICON_NUM_SIZES) {
+ g_warning ("calling e_icon_factory_get_icon with unknown icon_size value (%d)", icon_size);
if ((icon_size = pixel_size_to_icon_size (icon_size)) == -1)
return NULL;
}
+ size = sizes[icon_size];
+
if (icon_name == NULL || !strcmp (icon_name, "")) {
- size = sizes[icon_size];
- return gdk_pixbuf_scale_simple (empty_pixbuf, size, size, GDK_INTERP_NEAREST);
+ if (size >= 24)
+ return gdk_pixbuf_scale_simple (broken24_pixbuf, size, size, GDK_INTERP_NEAREST);
+ else
+ return gdk_pixbuf_scale_simple (broken16_pixbuf, size, size, GDK_INTERP_NEAREST);
}
+ icon_key = g_alloca (strlen (icon_name) + 7);
+ sprintf (icon_key, "%dx%d/%s", size, size, icon_name);
+
pthread_mutex_lock (&lock);
- if (!(icon = g_hash_table_lookup (name_to_icon, icon_name))) {
- if (!(icon = load_icon (icon_name))) {
+ if (!(icon = g_hash_table_lookup (name_to_icon, icon_key))) {
+ if (!(icon = load_icon (icon_name, size, TRUE))) {
g_warning ("Icon not found -- %s", icon_name);
/* Create an empty icon so that we don't keep spitting
out the same warning over and over, every time this
icon is requested. */
- icon = icon_new (icon_name, NULL);
+ icon = icon_new (icon_key, NULL);
g_hash_table_insert (name_to_icon, icon->name, icon);
} else {
g_hash_table_insert (name_to_icon, icon->name, icon);
}
}
- if ((pixbuf = icon->pixbuf[icon_size]))
+ if ((pixbuf = icon->pixbuf)) {
g_object_ref (pixbuf);
+ } else {
+ if (size >= 24)
+ pixbuf = gdk_pixbuf_scale_simple (broken24_pixbuf, size, size, GDK_INTERP_NEAREST);
+ else
+ pixbuf = gdk_pixbuf_scale_simple (broken16_pixbuf, size, size, GDK_INTERP_NEAREST);
+ }
pthread_mutex_unlock (&lock);
@@ -250,39 +317,41 @@ e_icon_factory_get_icon (const char *icon_name, int icon_size)
}
+/**
+ * e_icon_factory_get_icon_list:
+ * @icon_name: name of the icon
+ *
+ * Returns a list of GdkPixbufs of the requested name suitable for
+ * gtk_window_set_icon_list().
+ **/
GList *
e_icon_factory_get_icon_list (const char *icon_name)
{
+ static int icon_list_sizes[] = { 128, 64, 48, 32, 16 };
GList *list = NULL;
+ char *icon_key;
Icon *icon;
- int i;
+ int size, i;
if (!icon_name || !strcmp (icon_name, ""))
return NULL;
pthread_mutex_lock (&lock);
- if (!(icon = g_hash_table_lookup (name_to_icon, icon_name))) {
- if (!(icon = load_icon (icon_name))) {
- g_warning ("Icon not found -- %s", icon_name);
-
- /* Create an empty icon so that we don't keep spitting
- out the same warning over and over, every time this
- icon is requested. */
-
- icon = icon_new (icon_name, NULL);
- g_hash_table_insert (name_to_icon, icon->name, icon);
- pthread_mutex_unlock(&lock);
- return NULL;
- } else {
- g_hash_table_insert (name_to_icon, icon->name, icon);
- }
- }
+ icon_key = g_alloca (strlen (icon_name) + 9);
- for (i = 0; i < E_ICON_NUM_SIZES; i++) {
- if (icon->pixbuf[i]) {
- list = g_list_prepend (list, icon->pixbuf[i]);
- g_object_ref (icon->pixbuf[i]);
+ for (i = 0; i < G_N_ELEMENTS (icon_list_sizes); i++) {
+ size = icon_list_sizes[i];
+ sprintf (icon_key, "%dx%d/%s", size, size, icon_name);
+
+ if (!(icon = g_hash_table_lookup (name_to_icon, icon_key))) {
+ if ((icon = load_icon (icon_name, size, FALSE)))
+ g_hash_table_insert (name_to_icon, icon->name, icon);
+ }
+
+ if (icon && icon->pixbuf) {
+ list = g_list_prepend (list, icon->pixbuf);
+ g_object_ref (icon->pixbuf);
}
}