aboutsummaryrefslogtreecommitdiffstats
path: root/e-util/e-icon-factory.c
diff options
context:
space:
mode:
authorJeffrey Stedfast <fejj@novell.com>2004-05-20 04:08:17 +0800
committerJeffrey Stedfast <fejj@src.gnome.org>2004-05-20 04:08:17 +0800
commitff547c91abf8d8c3da3ba83e0f89b9a58b2fb2fe (patch)
treefd2c0565dec6ba097a1626d0981c21bb4220c879 /e-util/e-icon-factory.c
parent4e1b5582d894ddbdefdae5c729788bc57f60886b (diff)
downloadgsoc2013-evolution-ff547c91abf8d8c3da3ba83e0f89b9a58b2fb2fe.tar
gsoc2013-evolution-ff547c91abf8d8c3da3ba83e0f89b9a58b2fb2fe.tar.gz
gsoc2013-evolution-ff547c91abf8d8c3da3ba83e0f89b9a58b2fb2fe.tar.bz2
gsoc2013-evolution-ff547c91abf8d8c3da3ba83e0f89b9a58b2fb2fe.tar.lz
gsoc2013-evolution-ff547c91abf8d8c3da3ba83e0f89b9a58b2fb2fe.tar.xz
gsoc2013-evolution-ff547c91abf8d8c3da3ba83e0f89b9a58b2fb2fe.tar.zst
gsoc2013-evolution-ff547c91abf8d8c3da3ba83e0f89b9a58b2fb2fe.zip
Lots of re-working action. We no longer load a pixbuf for each and every
2004-05-19 Jeffrey Stedfast <fejj@novell.com> * e-icon-factory.c: Lots of re-working action. We no longer load a pixbuf for each and every available size when requesting the icon for the first time, instead we simply load the requested icon of the requested size and cache only that. (e_icon_factory_get_icon): Always return a broken image icon if we fail to load the requested icon. (e_icon_factory_get_icon_list): Only bother with adding icons of the sizes that are suggested by ghe gtk documentation for gtk_window_set_icon_list rather than the sizes of the standard icons (since it isn't the same list of sizes). (load_icon): Fall back to EVOLUTION_ICONSDIR/WWxHH/icon_name if the icon-theme lookup fails. Also now takes a 'scale' argument which, if non-zero, allows us to look for images of the same name with a larger size in order to scale them back down to what we need. svn path=/trunk/; revision=25986
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);
}
}