summaryrefslogtreecommitdiff
path: root/libnautilus-private/nautilus-icon-factory.c
diff options
context:
space:
mode:
Diffstat (limited to 'libnautilus-private/nautilus-icon-factory.c')
-rw-r--r--libnautilus-private/nautilus-icon-factory.c1816
1 files changed, 721 insertions, 1095 deletions
diff --git a/libnautilus-private/nautilus-icon-factory.c b/libnautilus-private/nautilus-icon-factory.c
index c7b0f473c..d7d31e731 100644
--- a/libnautilus-private/nautilus-icon-factory.c
+++ b/libnautilus-private/nautilus-icon-factory.c
@@ -20,49 +20,42 @@
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
- Authors: John Sullivan <sullivan@eazel.com>, Darin Adler <darin@eazel.com>,
+ Authors: John Sullivan <sullivan@eazel.com>,
+ Darin Adler <darin@eazel.com>,
Andy Hertzfeld <andy@eazel.com>
*/
#include <config.h>
#include "nautilus-icon-factory.h"
-#include <unistd.h>
-#include <string.h>
-#include <stdio.h>
-
-#include <gtk/gtkmain.h>
-#include <gtk/gtksignal.h>
-#include <gnome.h>
-
-#include <libgnomevfs/gnome-vfs-types.h>
-#include <libgnomevfs/gnome-vfs-file-info.h>
-#include <libgnomevfs/gnome-vfs-mime-info.h>
-
-#include <libnautilus-extensions/nautilus-gdk-pixbuf-extensions.h>
-
-#include <parser.h>
-#include <xmlmemory.h>
-
-#include <librsvg/rsvg.h>
-
#include "nautilus-default-file-icon.h"
-#include "nautilus-directory-notify.h"
#include "nautilus-file-attributes.h"
#include "nautilus-file-utilities.h"
#include "nautilus-gdk-extensions.h"
#include "nautilus-gdk-pixbuf-extensions.h"
#include "nautilus-glib-extensions.h"
#include "nautilus-global-preferences.h"
-#include "nautilus-graphic-effects.h"
#include "nautilus-gtk-macros.h"
+#include "nautilus-icon-factory-private.h"
#include "nautilus-lib-self-check-functions.h"
#include "nautilus-link.h"
#include "nautilus-metadata.h"
+#include "nautilus-scalable-font.h"
#include "nautilus-string.h"
#include "nautilus-theme.h"
+#include "nautilus-thumbnails.h"
#include "nautilus-xml-extensions.h"
-#include "nautilus-scalable-font.h"
+#include <gnome.h>
+#include <gtk/gtksignal.h>
+#include <libgnomevfs/gnome-vfs-file-info.h>
+#include <libgnomevfs/gnome-vfs-mime-info.h>
+#include <libgnomevfs/gnome-vfs-types.h>
+#include <libnautilus-extensions/nautilus-gdk-pixbuf-extensions.h>
+#include <librsvg/rsvg.h>
+#include <parser.h>
+#include <stdio.h>
+#include <string.h>
+#include <xmlmemory.h>
/* List of suffixes to search when looking for an icon file. */
static const char *icon_file_name_suffixes[] =
@@ -75,6 +68,7 @@ static const char *icon_file_name_suffixes[] =
".gif",
".GIF"
};
+
#define ICON_NAME_DIRECTORY "i-directory"
#define ICON_NAME_DIRECTORY_CLOSED "i-dirclosed"
#define ICON_NAME_EXECUTABLE "i-executable"
@@ -123,9 +117,16 @@ struct NautilusCircularList {
/* maximum size for either dimension at the standard zoom level */
#define MAXIMUM_ICON_SIZE 96
-/* permissions for thumbnail directory */
-
-#define THUMBNAIL_DIR_PERMISSIONS (GNOME_VFS_PERM_USER_ALL | GNOME_VFS_PERM_GROUP_ALL | GNOME_VFS_PERM_OTHER_ALL)
+/* FIXME bugzilla.eazel.com 1102: Embedded text should use preferences
+ * to determine what font it uses.
+ */
+#define EMBEDDED_TEXT_FONT_FAMILY _("helvetica")
+#define EMBEDDED_TEXT_FONT_WEIGHT _("medium")
+#define EMBEDDED_TEXT_FONT_SLANT NULL
+#define EMBEDDED_TEXT_FONT_SET_WIDTH NULL
+#define EMBEDDED_TEXT_FONT_SIZE 9
+#define EMBEDDED_TEXT_LINE_OFFSET 1
+#define EMBEDDED_TEXT_EMPTY_LINE_HEIGHT 4
/* The icon factory.
* These are just globals, but they're in an object so we can
@@ -143,24 +144,24 @@ typedef struct {
*/
GHashTable *scalable_icons;
- /* A hash table that contains a cache of actual images.
- * A circular list of the most recently used images is kept
- * around, and we don't let them go when we sweep the cache.
+ /* A hash table so we can find a cached icon's data structure
+ * from the pixbuf.
+ */
+ GHashTable *cache_icons;
+
+ /* A hash table that contains the icons. A circular list of
+ * the most recently used icons is kept around, and we don't
+ * let them go when we sweep the cache.
*/
GHashTable *icon_cache;
NautilusCircularList recently_used_dummy_head;
guint recently_used_count;
guint sweep_timer;
-
- /* thumbnail task state */
- GList *thumbnails;
- char *new_thumbnail_path;
- gboolean thumbnail_in_progress;
-
- /* id of timeout task for making thumbnails */
- int timeout_task_id;
} NautilusIconFactory;
+#define NAUTILUS_ICON_FACTORY(obj) \
+ GTK_CHECK_CAST (obj, nautilus_icon_factory_get_type (), NautilusIconFactory)
+
typedef struct {
GtkObjectClass parent_class;
} NautilusIconFactoryClass;
@@ -172,7 +173,7 @@ enum {
static guint signals[LAST_SIGNAL];
/* A scalable icon, which is basically the name and path of an icon,
- * before we load the actual pixels of the icons's image.
+ * before we load the actual pixels of the icons's pixbuf.
*/
struct NautilusScalableIcon {
guint ref_count;
@@ -192,92 +193,94 @@ typedef struct {
guint maximum_height;
} IconSizeRequest;
-/* A structure to hold the icon meta-info, like the text rectangle and emblem attach points */
-
typedef struct {
ArtIRect text_rect;
- gboolean has_attach_points;
- GdkPoint attach_points[MAX_ATTACH_POINTS];
-} IconInfo;
+ NautilusEmblemAttachPoints attach_points;
+} IconDetails;
-/* The key to a hash table that holds the scaled icons as pixbufs.
- * In a way, it's not really completely a key, because part of the
- * data is stored in here, including the LRU chain.
- */
+/* The key to a hash table that holds the scaled icons as pixbufs. */
typedef struct {
NautilusScalableIcon *scalable_icon;
IconSizeRequest size;
+} CacheKey;
+
+/* The value in the same table. */
+typedef struct {
+ GdkPixbuf *pixbuf;
+ IconDetails details;
+ /* If true, outside clients have refs to the pixbuf. */
+ gboolean outstanding;
+
+ /* Number of internal clients with refs to the pixbuf. */
+ guint internal_ref_count;
+
+ /* Used to decide when to kick icons out of the cache. */
NautilusCircularList recently_used_node;
- time_t cache_time;
- gboolean aa_mode;
+
+ /* Used to know when to make a new thumbnail. */
+ time_t cache_time;
+
+ /* Type of icon. */
gboolean custom;
gboolean scaled;
- IconInfo icon_info;
-} IconCacheKey;
+} CacheIcon;
#define MINIMUM_EMBEDDED_TEXT_RECT_WIDTH 20.0
#define MINIMUM_EMBEDDED_TEXT_RECT_HEIGHT 20.0
+static CacheIcon *fallback_icon;
+
/* forward declarations */
-static void icon_theme_changed_callback (gpointer user_data);
-static GtkType nautilus_icon_factory_get_type (void);
-static void nautilus_icon_factory_initialize_class (NautilusIconFactoryClass *class);
-static void nautilus_icon_factory_initialize (NautilusIconFactory *factory);
-static NautilusIconFactory * nautilus_get_current_icon_factory (void);
-static char * nautilus_icon_factory_get_thumbnail_uri (NautilusFile *file,
- gboolean anti_aliased);
-static NautilusIconFactory * nautilus_icon_factory_new (const char *theme_name);
-static void nautilus_icon_factory_set_theme (const char *theme_name);
-static guint nautilus_scalable_icon_hash (gconstpointer p);
-static gboolean nautilus_scalable_icon_equal (gconstpointer a,
- gconstpointer b);
-static void icon_cache_key_destroy (IconCacheKey *key);
-static guint icon_cache_key_hash (gconstpointer p);
-static gboolean icon_cache_key_equal (gconstpointer a,
- gconstpointer b);
-static gboolean vfs_file_exists (const char *file_name);
-static GdkPixbuf * get_image_from_cache (NautilusScalableIcon *scalable_icon,
- const IconSizeRequest *size,
- gboolean picky,
- gboolean custom,
- IconInfo *icon_info);
-static gboolean check_for_thumbnails (NautilusIconFactory *factory);
-static int nautilus_icon_factory_make_thumbnails (gpointer data);
-static GdkPixbuf * load_image_with_embedded_text (NautilusScalableIcon *scalable_icon,
- const IconSizeRequest *size);
-
-NAUTILUS_DEFINE_CLASS_BOILERPLATE (NautilusIconFactory, nautilus_icon_factory, GTK_TYPE_OBJECT)
+static guint nautilus_icon_factory_get_type (void);
+static void nautilus_icon_factory_initialize_class (NautilusIconFactoryClass *class);
+static void nautilus_icon_factory_initialize (NautilusIconFactory *factory);
+static void nautilus_icon_factory_destroy (GtkObject *object);
+static void icon_theme_changed_callback (gpointer user_data);
+static guint nautilus_scalable_icon_hash (gconstpointer p);
+static gboolean nautilus_scalable_icon_equal (gconstpointer a,
+ gconstpointer b);
+static guint cache_key_hash (gconstpointer p);
+static gboolean cache_key_equal (gconstpointer a,
+ gconstpointer b);
+static CacheIcon *get_icon_from_cache (NautilusScalableIcon *scalable_icon,
+ const IconSizeRequest *size,
+ gboolean picky,
+ gboolean custom);
+static CacheIcon *load_icon_with_embedded_text (NautilusScalableIcon *scalable_icon,
+ const IconSizeRequest *size);
+
+NAUTILUS_DEFINE_CLASS_BOILERPLATE (NautilusIconFactory,
+ nautilus_icon_factory,
+ GTK_TYPE_OBJECT)
+
+static NautilusIconFactory *global_icon_factory = NULL;
+
+static void
+destroy_icon_factory (void)
+{
+ nautilus_preferences_remove_callback (NAUTILUS_PREFERENCES_THEME,
+ icon_theme_changed_callback,
+ NULL);
+ gtk_object_unref (GTK_OBJECT (global_icon_factory));
+}
/* Return a pointer to the single global icon factory. */
static NautilusIconFactory *
-nautilus_get_current_icon_factory (void)
+get_icon_factory (void)
{
- static NautilusIconFactory *global_icon_factory = NULL;
if (global_icon_factory == NULL) {
- char *theme_preference, *icon_theme;
+ global_icon_factory = NAUTILUS_ICON_FACTORY
+ (gtk_object_new (nautilus_icon_factory_get_type (), NULL));
- theme_preference = nautilus_preferences_get (NAUTILUS_PREFERENCES_THEME,
- DEFAULT_ICON_THEME);
- g_assert (theme_preference != NULL);
-
- /* give the theme a chance to redirect the icons */
- icon_theme = nautilus_theme_get_theme_data ("icons", "ICON_THEME");
-
- if (icon_theme != NULL) {
- global_icon_factory = nautilus_icon_factory_new (icon_theme);
- } else {
- global_icon_factory = nautilus_icon_factory_new (theme_preference);
- }
-
- g_free (theme_preference);
- g_free (icon_theme);
-
+ /* Update to match the theme. */
+ icon_theme_changed_callback (NULL);
nautilus_preferences_add_callback (NAUTILUS_PREFERENCES_THEME,
icon_theme_changed_callback,
- NULL);
-
+ NULL);
+
+ g_atexit (destroy_icon_factory);
}
return global_icon_factory;
}
@@ -285,20 +288,38 @@ nautilus_get_current_icon_factory (void)
GtkObject *
nautilus_icon_factory_get (void)
{
- return GTK_OBJECT (nautilus_get_current_icon_factory ());
+ return GTK_OBJECT (get_icon_factory ());
}
-/* Create the icon factory. */
-static NautilusIconFactory *
-nautilus_icon_factory_new (const char *theme_name)
+static void
+check_recently_used_list (void)
{
- NautilusIconFactory *factory;
-
- factory = (NautilusIconFactory *) gtk_object_new (nautilus_icon_factory_get_type (), NULL);
+ NautilusIconFactory *factory;
+ NautilusCircularList *head, *node, *next;
+ int count;
- factory->theme_name = g_strdup (theme_name);
+ factory = get_icon_factory ();
+
+ head = &factory->recently_used_dummy_head;
+
+ count = 0;
+
+ node = head;
+ while (1) {
+ next = node->next;
+ g_assert (next != NULL);
+ g_assert (next->prev == node);
+
+ if (next == head) {
+ break;
+ }
+
+ count += 1;
+
+ node = next;
+ }
- return factory;
+ g_assert (count == factory->recently_used_count);
}
static void
@@ -306,8 +327,10 @@ nautilus_icon_factory_initialize (NautilusIconFactory *factory)
{
factory->scalable_icons = g_hash_table_new (nautilus_scalable_icon_hash,
nautilus_scalable_icon_equal);
- factory->icon_cache = g_hash_table_new (icon_cache_key_hash,
- icon_cache_key_equal);
+ factory->cache_icons = g_hash_table_new (g_direct_hash,
+ g_direct_equal);
+ factory->icon_cache = g_hash_table_new (cache_key_hash,
+ cache_key_equal);
/* Empty out the recently-used list. */
factory->recently_used_dummy_head.next = &factory->recently_used_dummy_head;
@@ -330,127 +353,241 @@ nautilus_icon_factory_initialize_class (NautilusIconFactoryClass *class)
GTK_TYPE_NONE, 0);
gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL);
+
+ object_class->destroy = nautilus_icon_factory_destroy;
+}
+
+static void
+cache_key_destroy (CacheKey *key)
+{
+ nautilus_scalable_icon_unref (key->scalable_icon);
+ g_free (key);
+}
+
+static void
+mark_icon_not_outstanding (GdkPixbuf *pixbuf, gpointer callback_data)
+{
+ NautilusIconFactory *factory;
+ CacheIcon *icon;
+
+ g_assert (callback_data == NULL);
+
+ factory = get_icon_factory ();
+
+ icon = g_hash_table_lookup (factory->cache_icons, pixbuf);
+ g_return_if_fail (icon != NULL);
+ g_return_if_fail (icon->pixbuf == pixbuf);
+ g_return_if_fail (icon->outstanding);
+
+ icon->outstanding = FALSE;
+}
+
+static CacheIcon *
+cache_icon_new (GdkPixbuf *pixbuf,
+ gboolean custom,
+ gboolean scaled,
+ const IconDetails *details)
+{
+ NautilusIconFactory *factory;
+ CacheIcon *icon;
+
+ factory = get_icon_factory ();
+
+ /* Just a check to see this is not reusing a pixbuf. */
+ g_assert (g_hash_table_lookup (factory->cache_icons, pixbuf) == NULL);
+
+ /* Grab the pixbuf since we are keeping it. */
+ gdk_pixbuf_ref (pixbuf);
+ gdk_pixbuf_set_last_unref_handler
+ (pixbuf, mark_icon_not_outstanding, NULL);
+
+ /* Make the icon. */
+ icon = g_new0 (CacheIcon, 1);
+ icon->pixbuf = pixbuf;
+ icon->internal_ref_count = 1;
+ icon->custom = custom;
+ icon->scaled = scaled;
+ icon->details = *details;
+
+ /* Put it into the hash table. */
+ g_hash_table_insert (factory->cache_icons, pixbuf, icon);
+ return icon;
+}
+
+static void
+cache_icon_ref (CacheIcon *icon)
+{
+ NautilusIconFactory *factory;
+
+ factory = get_icon_factory ();
+
+ g_assert (icon != NULL);
+ g_assert (icon->internal_ref_count >= 1);
+ g_assert (g_hash_table_lookup (factory->cache_icons, icon->pixbuf) == icon);
+
+ icon->internal_ref_count++;
+}
+
+static void
+cache_icon_unref (CacheIcon *icon)
+{
+ NautilusIconFactory *factory;
+ NautilusCircularList *node;
+
+ factory = get_icon_factory ();
+
+ g_assert (icon != NULL);
+ g_assert (icon->internal_ref_count >= 1);
+ g_assert (g_hash_table_lookup (factory->cache_icons, icon->pixbuf) == icon);
+
+ if (icon->internal_ref_count > 1) {
+ icon->internal_ref_count--;
+ return;
+ }
+
+ check_recently_used_list ();
+
+ /* If it's in the recently used list, free it from there */
+ node = &icon->recently_used_node;
+ if (node->next != NULL) {
+ g_assert (factory->recently_used_count >= 1);
+
+ g_assert (node->next->prev == node);
+ g_assert (node->prev->next == node);
+ g_assert (node->next != node);
+ g_assert (node->prev != node);
+
+ node->next->prev = node->prev;
+ node->prev->next = node->next;
+
+ factory->recently_used_count -= 1;
+ }
+
+ check_recently_used_list ();
+
+
+ /* Remove from the cache icons table. */
+ g_hash_table_remove (factory->cache_icons, icon->pixbuf);
+
+ /* Since it's no longer in the cache, we don't need to notice the last unref. */
+ gdk_pixbuf_set_last_unref_handler (icon->pixbuf, NULL, NULL);
+
+ /* Let go of the pixbuf if we were holding a reference to it.
+ * If it was still outstanding, we didn't have a reference to it,
+ * and we were counting on the unref handler to catch it.
+ */
+ if (!icon->outstanding) {
+ gdk_pixbuf_unref (icon->pixbuf);
+ }
+
+ g_free (icon);
}
-/* Destroy one image in the cache. */
+/* Destroy one pixbuf in the cache. */
static gboolean
-nautilus_icon_factory_destroy_cached_image (gpointer key, gpointer value, gpointer user_data)
+nautilus_icon_factory_destroy_cached_icon (gpointer key, gpointer value, gpointer user_data)
{
- icon_cache_key_destroy (key);
- gdk_pixbuf_unref (value);
+ cache_key_destroy (key);
+ cache_icon_unref (value);
+
+ /* Tell the caller to remove the hash table entry. */
return TRUE;
}
-
/* Reset the cache to the default state. */
static void
nautilus_icon_factory_clear (void)
{
NautilusIconFactory *factory;
+ NautilusCircularList *head;
- factory = nautilus_get_current_icon_factory ();
+ factory = get_icon_factory ();
g_hash_table_foreach_remove (factory->icon_cache,
- nautilus_icon_factory_destroy_cached_image,
+ nautilus_icon_factory_destroy_cached_icon,
NULL);
/* Empty out the recently-used list. */
- factory->recently_used_dummy_head.next = &factory->recently_used_dummy_head;
- factory->recently_used_dummy_head.prev = &factory->recently_used_dummy_head;
- factory->recently_used_count = 0;
+ head = &factory->recently_used_dummy_head;
+ g_assert (factory->recently_used_count == 0);
+ g_assert (head->next == head);
+ g_assert (head->prev == head);
}
-#if 0
-
-/* No one ever destroys the icon factory.
- * There's no public API for doing so.
- * If they did, we'd have to get this right.
- */
-
static void
-nautilus_icon_factory_destroy (NautilusIconFactory *factory)
+nautilus_icon_factory_destroy (GtkObject *object)
{
- nautilus_preferences_remove_callback (NAUTILUS_PREFERENCES_THEME,
- icon_theme_changed_callback,
- NULL);
+ NautilusIconFactory *factory;
+
+ factory = NAUTILUS_ICON_FACTORY (object);
nautilus_icon_factory_clear ();
+
+ if (g_hash_table_size (factory->scalable_icons) != 0) {
+ g_warning ("%d scalable icons still left when destroying icon factory",
+ g_hash_table_size (factory->scalable_icons));
+ }
+ if (g_hash_table_size (factory->icon_cache) != 0) {
+ g_warning ("%d icon cache entries still left when destroying icon factory",
+ g_hash_table_size (factory->icon_cache));
+ }
+
+ g_hash_table_destroy (factory->scalable_icons);
g_hash_table_destroy (factory->icon_cache);
g_free (factory->theme_name);
- g_free (factory);
+
+ NAUTILUS_CALL_PARENT_CLASS (GTK_OBJECT_CLASS, destroy, (object));
}
-#endif
-
static gboolean
-nautilus_icon_factory_possibly_free_cached_image (gpointer key,
+nautilus_icon_factory_possibly_free_cached_icon (gpointer key,
gpointer value,
gpointer user_data)
{
- IconCacheKey *icon_key;
- GdkPixbuf *image;
+ CacheIcon *icon;
+
+ icon = value;
/* Don't free a cache entry that is in the recently used list. */
- icon_key = key;
- if (icon_key->recently_used_node.next != NULL) {
+ if (icon->recently_used_node.next != NULL) {
return FALSE;
}
- /* Don't free a cache entry if the image is still in use. */
- image = value;
-
- /* FIXME bugzilla.eazel.com 640:
- * We treat all entries as "in use", until we get a hook we can use
- * in GdkPixbuf. We are waiting for the "final" hook right now. The
- * one that's in there is not approved of by the Gtk maintainers.
- */
- return FALSE;
-#if 0
- if (image->ref_count > 1) {
+ /* Don't free a cache entry if the pixbuf is still in use. */
+ if (icon->outstanding) {
return FALSE;
}
/* Free the item. */
- return nautilus_icon_factory_destroy_cached_image (key, value, NULL);
-#endif
+ return nautilus_icon_factory_destroy_cached_icon (key, value, NULL);
}
-/* remove images whose uri field matches the passed-in uri */
-
+/* Remove icons whose URI field matches the passed-in URI. */
static gboolean
-nautilus_icon_factory_remove_image_uri (gpointer key,
- gpointer value,
- gpointer user_data)
+nautilus_icon_factory_remove_if_uri_matches (gpointer key,
+ gpointer value,
+ gpointer user_data)
{
char *image_uri;
- IconCacheKey *icon_key;
- NautilusCircularList *node;
- NautilusIconFactory *factory;
+ CacheKey *cache_key;
+ CacheIcon *icon;
- icon_key = key;
+ cache_key = key;
+ icon = value;
image_uri = user_data;
- /* see if the the uri's match - if not, just return */
- if (icon_key->scalable_icon->uri && strcmp(icon_key->scalable_icon->uri, image_uri)) {
+ /* See if the the uri's match - if not, just return. */
+ if (cache_key->scalable_icon->uri != NULL
+ && strcmp (cache_key->scalable_icon->uri, image_uri)) {
return FALSE;
}
- /* if it's in the recently used list, free it from there */
- node = &icon_key->recently_used_node;
- if (node->next != NULL) {
- node->next->prev = node->prev;
- node->prev->next = node->next;
-
- factory = nautilus_get_current_icon_factory ();
- factory->recently_used_count -= 1;
- }
-
/* Free the item. */
- return nautilus_icon_factory_destroy_cached_image (key, value, NULL);
+ return nautilus_icon_factory_destroy_cached_icon (key, value, NULL);
}
-/* Sweep the cache, freeing any images that are not in use and are
+/* Sweep the cache, freeing any icons that are not in use and are
* also not recently used.
*/
static gboolean
@@ -461,7 +598,7 @@ nautilus_icon_factory_sweep (gpointer user_data)
factory = user_data;
g_hash_table_foreach_remove (factory->icon_cache,
- nautilus_icon_factory_possibly_free_cached_image,
+ nautilus_icon_factory_possibly_free_cached_icon,
NULL);
factory->sweep_timer = 0;
@@ -475,7 +612,7 @@ nautilus_icon_factory_schedule_sweep (void)
{
NautilusIconFactory *factory;
- factory = nautilus_get_current_icon_factory ();
+ factory = get_icon_factory ();
if (factory->sweep_timer != 0) {
return;
@@ -486,28 +623,38 @@ nautilus_icon_factory_schedule_sweep (void)
factory);
}
-/* clear a specific image from the cache */
-
-static void
-nautilus_icon_factory_clear_image(const char *image_uri)
+/* Clear a specific icon from the cache. */
+void
+nautilus_icon_factory_remove_by_uri (const char *image_uri)
{
NautilusIconFactory *factory;
/* build the key and look it up in the icon cache */
- factory = nautilus_get_current_icon_factory ();
+ factory = get_icon_factory ();
g_hash_table_foreach_remove (factory->icon_cache,
- nautilus_icon_factory_remove_image_uri,
+ nautilus_icon_factory_remove_if_uri_matches,
(gpointer) image_uri);
}
/* Change the theme. */
-void
-nautilus_icon_factory_set_theme (const char *theme_name)
+static void
+set_theme (const char *theme_name)
{
NautilusIconFactory *factory;
- factory = nautilus_get_current_icon_factory ();
+ if (factory->theme_name == NULL) {
+ if (theme_name == NULL) {
+ return;
+ }
+ } else {
+ if (theme_name != NULL
+ && strcmp (theme_name, factory->theme_name) != 0) {
+ return;
+ }
+ }
+
+ factory = get_icon_factory ();
nautilus_icon_factory_clear ();
@@ -619,24 +766,31 @@ make_full_icon_path (const char *path, const char *suffix)
/* utility routine to parse the attach points string to set up the array in icon_info */
static void
-parse_attach_points (IconInfo *icon_info, const char* attach_point_string)
+parse_attach_points (NautilusEmblemAttachPoints *attach_points, const char *attach_point_string)
{
- char *text_piece;
char **point_array;
- int index, x_offset, y_offset;
-
- /* split the attach point string into a string array, then process
- each point with sscanf in a loop */
+ int i, x_offset, y_offset;
+
+ attach_points->num_points = 0;
+ if (attach_point_string == NULL) {
+ return;
+ }
+
+ /* Split the attach point string into a string array, then process
+ * each point with sscanf in a loop.
+ */
point_array = g_strsplit (attach_point_string, "|", MAX_ATTACH_POINTS);
- for (index = 0; (text_piece = point_array[index]) != NULL; index++) {
- if (sscanf (text_piece, " %d , %d , %*s", &x_offset, &y_offset) == 2) {
- icon_info->attach_points[index].x = x_offset;
- icon_info->attach_points[index].y = y_offset;
+ for (i = 0; point_array[i] != NULL; i++) {
+ if (sscanf (point_array[i], " %d , %d , %*s", &x_offset, &y_offset) == 2) {
+ attach_points->points[attach_points->num_points].x = x_offset;
+ attach_points->points[attach_points->num_points].y = y_offset;
+ attach_points->num_points++;
} else {
- g_warning ("bad attach point specification: %s", text_piece);
- }
+ g_warning ("bad attach point specification: %s", point_array[i]);
+ }
}
+
g_strfreev (point_array);
}
@@ -647,8 +801,8 @@ static char *
get_themed_icon_file_path (const char *theme_name,
const char *icon_name,
guint icon_size,
- IconInfo *icon_info,
- gboolean aa_mode)
+ gboolean aa_mode,
+ IconDetails *details)
{
int i;
gboolean include_size;
@@ -658,6 +812,7 @@ get_themed_icon_file_path (const char *theme_name,
char *size_as_string, *property;
ArtIRect parsed_rect;
NautilusIconFactory *factory;
+ char *user_directory;
g_assert (icon_name != NULL);
@@ -667,16 +822,11 @@ get_themed_icon_file_path (const char *theme_name,
themed_icon_name = g_strconcat (theme_name, "/", icon_name, NULL);
}
- if (icon_info != NULL) {
- icon_info->has_attach_points = FALSE;
- }
-
include_size = icon_size != NAUTILUS_ICON_SIZE_STANDARD;
- factory = (NautilusIconFactory*) nautilus_icon_factory_get();
+ factory = get_icon_factory ();
/* Try each suffix. */
for (i = 0; i < NAUTILUS_N_ELEMENTS (icon_file_name_suffixes); i++) {
-
if (include_size && strcasecmp(icon_file_name_suffixes[i], ".svg")) {
/* Build a path for this icon. */
partial_path = g_strdup_printf ("%s-%u",
@@ -688,9 +838,9 @@ get_themed_icon_file_path (const char *theme_name,
/* if we're in anti-aliased mode, try for an optimized one first */
if (aa_mode) {
- aa_path = g_strdup_printf ("%s-aa", partial_path);
+ aa_path = g_strconcat (partial_path, "-aa", NULL);
path = make_full_icon_path (aa_path,
- icon_file_name_suffixes[i]);
+ icon_file_name_suffixes[i]);
g_free (aa_path);
/* Return the path if the file exists. */
@@ -715,8 +865,8 @@ get_themed_icon_file_path (const char *theme_name,
}
/* Open the XML file to get the text rectangle and emblem attach points */
- if (path != NULL && icon_info != NULL) {
- memset (&icon_info->text_rect, 0, sizeof (icon_info->text_rect));
+ if (path != NULL && details != NULL) {
+ memset (&details->text_rect, 0, sizeof (details->text_rect));
xml_path = make_full_icon_path (themed_icon_name, ".xml");
@@ -737,30 +887,24 @@ get_themed_icon_file_path (const char *theme_name,
&parsed_rect.y0,
&parsed_rect.x1,
&parsed_rect.y1) == 4) {
- icon_info->text_rect = parsed_rect;
+ details->text_rect = parsed_rect;
}
xmlFree (property);
}
property = xmlGetProp (node, "ATTACH_POINTS");
- if (property != NULL) {
- icon_info->has_attach_points = TRUE;
- parse_attach_points (icon_info, property);
- xmlFree (property);
- } else {
- icon_info->has_attach_points = FALSE;
- }
+ parse_attach_points (&details->attach_points, property);
+ xmlFree (property);
xmlFreeDoc (doc);
}
- /* if we still haven't found anything, and we're looking for an emblem,
- check out the user's home directory, since it might be an emblem
- that they've added there */
-
+ /* If we still haven't found anything, and we're looking for an emblem,
+ * check out the user's home directory, since it might be an emblem
+ * that they've added there.
+ */
if (path == NULL && nautilus_str_has_prefix (icon_name, "emblem-")) {
for (i = 0; i < NAUTILUS_N_ELEMENTS (icon_file_name_suffixes); i++) {
- char *user_directory;
user_directory = nautilus_get_user_directory ();
path = g_strdup_printf ("%s/emblems/%s%s",
user_directory,
@@ -781,24 +925,28 @@ get_themed_icon_file_path (const char *theme_name,
return path;
}
-/* Choose the file name to load, taking into account theme vs. non-theme icons. */
+/* Choose the file name to load, taking into account theme
+ * vs. non-theme icons. Also fill in info in the icon structure based
+ * on what's found in the XML file.
+ */
static char *
get_icon_file_path (const char *name,
- const char* modifier,
+ const char *modifier,
guint size_in_pixels,
- IconInfo *icon_info,
- gboolean aa_mode)
+ gboolean aa_mode,
+ IconDetails *details)
{
gboolean use_theme_icon;
const char *theme_name;
char *path;
+ char *name_with_modifier;
if (name == NULL) {
return NULL;
}
use_theme_icon = FALSE;
- theme_name = nautilus_get_current_icon_factory ()->theme_name;
+ theme_name = get_icon_factory ()->theme_name;
/* Check and see if there is a theme icon to use.
* This decision must be based on whether there's a non-size-
@@ -808,8 +956,8 @@ get_icon_file_path (const char *name,
path = get_themed_icon_file_path (theme_name,
name,
NAUTILUS_ICON_SIZE_STANDARD,
- NULL,
- aa_mode);
+ aa_mode,
+ details);
if (path != NULL) {
use_theme_icon = TRUE;
g_free (path);
@@ -817,26 +965,26 @@ get_icon_file_path (const char *name,
}
/* Now we know whether or not to use the theme. */
- /* if there's a modifier, try using that first */
-
+
+ /* If there's a modifier, try the modified icon first. */
if (modifier && modifier[0] != '\0') {
- char* modified_name = g_strdup_printf ("%s-%s", name, modifier);
+ name_with_modifier = g_strconcat (name, "-", modifier, NULL);
path = get_themed_icon_file_path (use_theme_icon ? theme_name : NULL,
- modified_name,
+ name_with_modifier,
size_in_pixels,
- icon_info,
- aa_mode);
- g_free (modified_name);
+ aa_mode,
+ details);
+ g_free (name_with_modifier);
if (path != NULL) {
- return path;
+ return path;
}
}
return get_themed_icon_file_path (use_theme_icon ? theme_name : NULL,
name,
size_in_pixels,
- icon_info,
- aa_mode);
+ aa_mode,
+ details);
}
static void
@@ -844,19 +992,14 @@ icon_theme_changed_callback (gpointer user_data)
{
char *theme_preference, *icon_theme;
- theme_preference = nautilus_preferences_get (NAUTILUS_PREFERENCES_THEME,
- DEFAULT_ICON_THEME);
-
- g_assert (theme_preference != NULL);
-
- /* give the theme a chance to redirect the icons */
+ /* Consult the user preference and the Nautilus theme. In the
+ * long run, we sould just get rid of the user preference.
+ */
+ theme_preference = nautilus_preferences_get
+ (NAUTILUS_PREFERENCES_THEME, DEFAULT_ICON_THEME);
icon_theme = nautilus_theme_get_theme_data ("icons", "ICON_THEME");
- if (icon_theme != NULL) {
- nautilus_icon_factory_set_theme (icon_theme);
- } else {
- nautilus_icon_factory_set_theme (theme_preference);
- }
+ set_theme (icon_theme == NULL ? theme_preference : icon_theme);
g_free (theme_preference);
g_free (icon_theme);
@@ -895,10 +1038,10 @@ nautilus_scalable_icon_new_from_text_pieces (const char *uri,
gboolean anti_aliased)
{
GHashTable *hash_table;
- NautilusScalableIcon icon_key, *icon;
+ NautilusScalableIcon cache_key, *icon;
NautilusIconFactory *factory;
- factory = (NautilusIconFactory*) nautilus_icon_factory_get ();
+ factory = get_icon_factory ();
/* Make empty strings canonical. */
if (uri != NULL && uri[0] == '\0') {
uri = NULL;
@@ -914,16 +1057,16 @@ nautilus_scalable_icon_new_from_text_pieces (const char *uri,
}
/* Get at the hash table. */
- hash_table = nautilus_get_current_icon_factory ()->scalable_icons;
+ hash_table = get_icon_factory ()->scalable_icons;
/* Check to see if it's already in the table. */
- icon_key.uri = (char *) uri;
- icon_key.name = (char *) name;
- icon_key.modifier = (char *) modifier;
- icon_key.embedded_text = (char *) embedded_text;
- icon_key.aa_mode = anti_aliased;
+ cache_key.uri = (char *) uri;
+ cache_key.name = (char *) name;
+ cache_key.modifier = (char *) modifier;
+ cache_key.embedded_text = (char *) embedded_text;
+ cache_key.aa_mode = anti_aliased;
- icon = g_hash_table_lookup (hash_table, &icon_key);
+ icon = g_hash_table_lookup (hash_table, &cache_key);
if (icon == NULL) {
/* Not in the table, so create it and put it in. */
icon = g_new0 (NautilusScalableIcon, 1);
@@ -960,7 +1103,7 @@ nautilus_scalable_icon_unref (NautilusScalableIcon *icon)
return;
}
- hash_table = nautilus_get_current_icon_factory ()->scalable_icons;
+ hash_table = get_icon_factory ()->scalable_icons;
g_hash_table_remove (hash_table, icon);
g_free (icon->uri);
@@ -1068,8 +1211,13 @@ nautilus_icon_factory_get_icon_for_file (NautilusFile *file, const char* modifie
if (nautilus_istr_has_prefix (mime_type, "image/") && should_display_image_file_as_itself (file)) {
if (nautilus_file_get_size (file) < SELF_THUMBNAIL_SIZE_THRESHOLD) {
uri = nautilus_file_get_uri (file);
- } else if (strstr(file_uri, "/.thumbnails/") == NULL) {
- uri = nautilus_icon_factory_get_thumbnail_uri (file, anti_aliased);
+ } else if (strstr (file_uri, "/.thumbnails/") == NULL) {
+ uri = nautilus_get_thumbnail_uri (file, anti_aliased);
+ if (uri == NULL) {
+ get_icon_file_path
+ (ICON_NAME_THUMBNAIL_LOADING, NULL,
+ NAUTILUS_ICON_SIZE_STANDARD, FALSE, NULL);
+ }
}
}
g_free (mime_type);
@@ -1198,336 +1346,6 @@ nautilus_icon_factory_get_emblem_icons_for_file (NautilusFile *file, gboolean an
return g_list_reverse (icons);
}
-/* utility to test whether a file exists using vfs */
-static gboolean
-vfs_file_exists (const char *file_uri)
-{
- GnomeVFSResult result;
- GnomeVFSFileInfo *file_info;
-
- file_info = gnome_vfs_file_info_new ();
-
- /* FIXME bugzilla.eazel.com 3137: the synchronous I/O here means this call is
- unsuitable for use on anything that might be remote. */
-
- result = gnome_vfs_get_file_info (file_uri, file_info, 0);
- gnome_vfs_file_info_unref (file_info);
- return result == GNOME_VFS_OK;
-}
-
-/* FIXME bugzilla.eazel.com 3138: why is this call cut and pasted instead
- of putting it in a common place? */
-
-/* utility copied from Nautilus directory */
-static GnomeVFSResult
-nautilus_make_directory_and_parents (GnomeVFSURI *uri, guint permissions)
-{
- GnomeVFSResult result;
- GnomeVFSURI *parent_uri;
-
- /* FIXME bugzilla.eazel.com 3137: the synchronous I/O in this
- call means it's unsuitable for calling on a URI that might
- be remote. */
-
- /* Make the directory, and return right away unless there's
- a possible problem with the parent.
- */
- result = gnome_vfs_make_directory_for_uri (uri, permissions);
- if (result != GNOME_VFS_ERROR_NOT_FOUND) {
- return result;
- }
-
- /* If we can't get a parent, we are done. */
- parent_uri = gnome_vfs_uri_get_parent (uri);
- if (parent_uri == NULL) {
- return result;
- }
-
- /* If we can get a parent, use a recursive call to create
- the parent and its parents.
- */
- result = nautilus_make_directory_and_parents (parent_uri, permissions);
- gnome_vfs_uri_unref (parent_uri);
- if (result != GNOME_VFS_OK) {
- return result;
- }
-
- /* A second try at making the directory after the parents
- have all been created.
- */
- result = gnome_vfs_make_directory_for_uri (uri, permissions);
- return result;
-}
-
-/* utility routine that, given the uri of an image, constructs the uri to the corresponding thumbnail */
-
-static char *
-make_thumbnail_path (const char *image_uri, gboolean directory_only, gboolean use_local_directory, gboolean anti_aliased)
-{
- char *thumbnail_uri, *thumbnail_path;
- char *directory_name = g_strdup (image_uri);
- char *last_slash = strrchr (directory_name, '/');
- char *dot_pos;
-
- *last_slash = '\0';
-
- /* either use the local directory or one in the user's home directory, as selected by the passed in flag */
- if (use_local_directory)
- thumbnail_uri = g_strdup_printf ("%s/.thumbnails", directory_name);
- else {
- GnomeVFSResult result;
- GnomeVFSURI *thumbnail_directory_uri;
-
- char *escaped_uri = gnome_vfs_escape_slashes (directory_name);
- thumbnail_path = g_strdup_printf ("%s/.nautilus/thumbnails/%s", g_get_home_dir(), escaped_uri);
- thumbnail_uri = gnome_vfs_get_uri_from_local_path (thumbnail_path);
- g_free (thumbnail_path);
- g_free(escaped_uri);
-
- /* we must create the directory if it doesnt exist */
-
- thumbnail_directory_uri = gnome_vfs_uri_new (thumbnail_uri);
-
- /* FIXME bugzilla.eazel.com 3137: synchronous I/O - it
- looks like the URI will be local-only, but best to
- make sure. */
-
- result = nautilus_make_directory_and_parents (thumbnail_directory_uri, THUMBNAIL_DIR_PERMISSIONS);
- gnome_vfs_uri_unref (thumbnail_directory_uri);
- }
-
- /* append the file name if necessary */
- if (!directory_only) {
- char* old_uri = thumbnail_uri;
- thumbnail_uri = g_strdup_printf ("%s/%s", thumbnail_uri, last_slash + 1);
- g_free(old_uri);
-
- /* append the anti-aliased suffix if necessary */
- if (anti_aliased) {
- char *old_uri = thumbnail_uri;
- dot_pos = strrchr (thumbnail_uri, '.');
- if (dot_pos) {
- *dot_pos = '\0';
- thumbnail_uri = g_strdup_printf ("%s.aa.%s", old_uri, dot_pos + 1);
- } else {
- thumbnail_uri = g_strconcat (old_uri, ".aa", NULL);
- }
- g_free (old_uri);
- }
-
- /* append an image suffix if the correct one isn't already present */
- if (!nautilus_istr_has_suffix (image_uri, ".png")) {
- char* old_uri = thumbnail_uri;
- thumbnail_uri = g_strdup_printf ("%s.png", thumbnail_uri);
- g_free(old_uri);
- }
- }
-
- g_free (directory_name);
- return thumbnail_uri;
-}
-
-/* utility routine that takes two uris and returns true if the first file has been modified later than the second */
-/* FIXME bugzilla.eazel.com 2565: it makes synchronous file info calls, so for now, it returns FALSE if either of the uri's are non-local */
-static gboolean
-first_file_more_recent(const char* file_uri, const char* other_file_uri)
-{
- GnomeVFSURI *vfs_uri, *other_vfs_uri;
- gboolean more_recent, is_local;
-
- GnomeVFSFileInfo file_info, other_file_info;
-
- /* if either file is remote, return FALSE. Eventually we'll make this async to fix this */
- vfs_uri = gnome_vfs_uri_new(file_uri);
- other_vfs_uri = gnome_vfs_uri_new(other_file_uri);
- is_local = gnome_vfs_uri_is_local (vfs_uri) && gnome_vfs_uri_is_local (other_vfs_uri);
- gnome_vfs_uri_unref(vfs_uri);
- gnome_vfs_uri_unref(other_vfs_uri);
-
- if (!is_local) {
- return FALSE;
- }
-
- /* gather the info and then compare modification times */
- gnome_vfs_file_info_init (&file_info);
- gnome_vfs_get_file_info (file_uri, &file_info, GNOME_VFS_FILE_INFO_DEFAULT);
-
- gnome_vfs_file_info_init (&other_file_info);
- gnome_vfs_get_file_info (other_file_uri, &other_file_info, GNOME_VFS_FILE_INFO_DEFAULT);
-
- more_recent = file_info.mtime > other_file_info.mtime;
-
- gnome_vfs_file_info_clear (&file_info);
- gnome_vfs_file_info_clear (&other_file_info);
-
- return more_recent;
-}
-
-/* structure used for making thumbnails, associating a uri with where the thumbnail is to be stored */
-
-typedef struct {
- char *thumbnail_uri;
- gboolean is_local;
- gboolean anti_aliased;
-} NautilusThumbnailInfo;
-
-/* GCompareFunc-style function for comparing NautilusThumbnailInfos.
- * Returns 0 if they refer to the same uri.
- */
-static int
-compare_thumbnail_info (gconstpointer a, gconstpointer b)
-{
- NautilusThumbnailInfo *info_a;
- NautilusThumbnailInfo *info_b;
-
- info_a = (NautilusThumbnailInfo *)a;
- info_b = (NautilusThumbnailInfo *)b;
-
- return strcmp (info_a->thumbnail_uri, info_b->thumbnail_uri) != 0;
-}
-
-/* routine that takes a uri of a large image file and returns the uri of its corresponding thumbnail.
- If no thumbnail is available, put the image on the thumbnail queue so one is eventually made. */
-/* FIXME bugzilla.eazel.com 642:
- * Most of this thumbnail machinery belongs in NautilusFile, not here.
- */
-
-static char *
-nautilus_icon_factory_get_thumbnail_uri (NautilusFile *file, gboolean anti_aliased)
-{
- NautilusIconFactory *factory;
- GnomeVFSResult result;
- char *thumbnail_uri;
- char *file_uri;
- gboolean local_flag = TRUE;
- gboolean remake_thumbnail = FALSE;
-
- file_uri = nautilus_file_get_uri (file);
-
- /* compose the uri for the thumbnail locally */
- thumbnail_uri = make_thumbnail_path (file_uri, FALSE, TRUE, anti_aliased);
-
- /* if the thumbnail file already exists locally, simply return the uri */
-
- /* FIXME bugzilla.eazel.com 3137: this synchronous I/O is a
- disaster when loading remote locations. It blocks the UI
- when trying to load a slow remote image over http for
- instance. The fact that we must do this potentially slow
- operation implies the IconFactory interface needs to be
- asynchronous! Either that, or thumbnail existence is
- somthing we need to be able to monitor/call_when_ready on,
- on a NautilusFile. */
-
- if (vfs_file_exists (thumbnail_uri)) {
-
- /* see if the file changed since it was thumbnailed by comparing the modification time */
- remake_thumbnail = first_file_more_recent(file_uri, thumbnail_uri);
-
- /* if the file hasn't changed, return the thumbnail uri */
- if (!remake_thumbnail) {
- g_free (file_uri);
- return thumbnail_uri;
- } else {
- nautilus_icon_factory_clear_image(thumbnail_uri);
-
-
- /* FIXME bugzilla.eazel.com 3137: more potentially
- losing synch I/O. */
-
- gnome_vfs_unlink(thumbnail_uri);
- }
- }
-
- /* now try it globally */
- if (!remake_thumbnail) {
- g_free (thumbnail_uri);
- thumbnail_uri = make_thumbnail_path (file_uri, FALSE, FALSE, anti_aliased);
-
- /* if the thumbnail file already exists in the common area, return that uri */
-
- /* FIXME bugzilla.eazel.com 3137: more potentially losing
- synch I/O - this should be guaranteed local, so
- perhaps not as bad (unless you have an NFS homedir,
- say... */
-
- if (vfs_file_exists (thumbnail_uri)) {
-
- /* see if the file changed since it was thumbnailed by comparing the modification time */
- remake_thumbnail = first_file_more_recent(file_uri, thumbnail_uri);
-
- /* if the file hasn't changed, return the thumbnail uri */
- if (!remake_thumbnail) {
- g_free (file_uri);
- return thumbnail_uri;
- } else {
- nautilus_icon_factory_clear_image(thumbnail_uri);
- /* FIXME bugzilla.eazel.com 3137: more potentially losing
- synch I/O - this should be guaranteed local, so
- perhaps not as bad (unless you have an NFS homedir,
- say... */
- gnome_vfs_unlink(thumbnail_uri);
- }
- }
- }
-
- /* make the thumbnail directory if necessary, at first try it locally */
- g_free (thumbnail_uri);
- local_flag = TRUE;
- thumbnail_uri = make_thumbnail_path (file_uri, TRUE, local_flag, anti_aliased);
-
-
- /* FIXME bugzilla.eazel.com 3137: more potentially losing
- synch I/O - this could be remote */
-
- result = gnome_vfs_make_directory (thumbnail_uri, THUMBNAIL_DIR_PERMISSIONS);
-
- /* if we can't make if locally, try it in the global place */
- if (result != GNOME_VFS_OK && result != GNOME_VFS_ERROR_FILE_EXISTS) {
- g_free (thumbnail_uri);
- local_flag = FALSE;
- thumbnail_uri = make_thumbnail_path (file_uri, TRUE, local_flag, anti_aliased);
- /* FIXME bugzilla.eazel.com 3137: more potentially
- losing synch I/O - this is probably local? */
-
- result = gnome_vfs_make_directory (thumbnail_uri, THUMBNAIL_DIR_PERMISSIONS);
- }
-
- /* the thumbnail needs to be created (or recreated), so add an entry to the thumbnail list */
-
- if (result != GNOME_VFS_OK && result != GNOME_VFS_ERROR_FILE_EXISTS) {
-
- g_warning ("error when making thumbnail directory %d, for %s", result, thumbnail_uri);
- } else {
- NautilusThumbnailInfo *info = g_new0 (NautilusThumbnailInfo, 1);
- info->thumbnail_uri = file_uri;
- info->is_local = local_flag;
- info->anti_aliased = anti_aliased;
-
- factory = nautilus_get_current_icon_factory ();
- if (factory->thumbnails) {
- if (g_list_find_custom (factory->thumbnails, info, compare_thumbnail_info) == NULL) {
- factory->thumbnails = g_list_prepend (factory->thumbnails, info);
- }
- } else {
- factory->thumbnails = g_list_alloc ();
- factory->thumbnails->data = info;
- }
-
- if (factory->timeout_task_id == 0) {
- factory->timeout_task_id = gtk_timeout_add (400, (GtkFunction) nautilus_icon_factory_make_thumbnails, NULL);
- }
- }
-
- g_free (thumbnail_uri);
-
- /* return the uri to the "loading image" icon */
- return get_icon_file_path (ICON_NAME_THUMBNAIL_LOADING,
- NULL,
- NAUTILUS_ICON_SIZE_STANDARD,
- NULL,
- FALSE);
-}
-
static guint
get_larger_icon_size (guint size)
{
@@ -1615,20 +1433,19 @@ get_next_icon_size_to_try (guint target_size, guint *current_size)
/* This loads an SVG image, scaling it to the appropriate size. */
static GdkPixbuf *
-load_specific_image_svg (const char *path, guint size_in_pixels)
+load_pixbuf_svg (const char *path, guint size_in_pixels)
{
FILE *f;
- GdkPixbuf *result;
-
+ GdkPixbuf *pixbuf;
+
f = fopen (path, "rb");
if (f == NULL) {
return NULL;
}
- result = rsvg_render_file (f, size_in_pixels *
- (1.0 / NAUTILUS_ICON_SIZE_STANDARD));
+ pixbuf = rsvg_render_file (f, ((double) size_in_pixels) / NAUTILUS_ICON_SIZE_STANDARD);
fclose (f);
-
- return result;
+
+ return pixbuf;
}
static gboolean
@@ -1653,75 +1470,76 @@ path_represents_svg_image (const char *path)
return is_svg;
}
-/* This load function returns NULL if the icon is not available at this size. */
-static GdkPixbuf *
-load_specific_image (NautilusScalableIcon *scalable_icon,
- guint size_in_pixels,
- gboolean custom,
- IconInfo *icon_info)
+/* This load function returns NULL if the icon is not available at
+ * this size.
+ */
+static CacheIcon *
+load_specific_icon (NautilusScalableIcon *scalable_icon,
+ guint size_in_pixels,
+ gboolean custom)
{
- char *image_path;
+ IconDetails details;
GdkPixbuf *pixbuf;
-
- g_assert (icon_info != NULL);
+ char *path;
+ CacheIcon *icon;
- if (custom) {
- /* Custom icon. */
+ memset (&details, 0, sizeof (details));
+ pixbuf = NULL;
- memset (&icon_info->text_rect, 0, sizeof (icon_info->text_rect));
- icon_info->has_attach_points = FALSE;
-
- /* we use the suffix instead of mime-type here since it may be non-local */
- if (nautilus_istr_has_suffix (scalable_icon->uri, ".svg")) {
- image_path = gnome_vfs_get_local_path_from_uri (scalable_icon->uri);
- pixbuf = load_specific_image_svg (image_path, size_in_pixels);
- g_free (image_path);
- return pixbuf;
- }
-
- if (size_in_pixels == NAUTILUS_ICON_SIZE_STANDARD && scalable_icon->uri != NULL) {
- return nautilus_gdk_pixbuf_load (scalable_icon->uri);
- }
-
- return NULL;
+ /* Get the path. */
+ if (custom) {
+ /* We don't support custom icons that are not local here. */
+ path = gnome_vfs_get_local_path_from_uri (scalable_icon->uri);
} else {
- /* Standard icon. */
- char *path;
- GdkPixbuf *image;
-
path = get_icon_file_path (scalable_icon->name,
scalable_icon->modifier,
size_in_pixels,
- icon_info,
- scalable_icon->aa_mode);
-
- if (path == NULL) {
- return NULL;
- }
+ scalable_icon->aa_mode,
+ &details);
+ }
+ /* Get the icon. */
+ if (path != NULL) {
if (path_represents_svg_image (path)) {
- image = load_specific_image_svg (path, size_in_pixels);
+ pixbuf = load_pixbuf_svg (path, size_in_pixels);
} else {
- image = gdk_pixbuf_new_from_file (path);
+ /* Custom non-svg icons exist at one size.
+ * Non-custom icons have their size encoded in their path.
+ */
+ if (!(custom && size_in_pixels != NAUTILUS_ICON_SIZE_STANDARD)) {
+ pixbuf = gdk_pixbuf_new_from_file (path);
+ }
}
-
+
g_free (path);
- return image;
}
+
+ /* If we got nothing, we can free the icon. */
+ if (pixbuf == NULL) {
+ return NULL;
+ }
+
+ /* Since we got something, we can create a cache icon. */
+ icon = cache_icon_new (pixbuf, custom, FALSE, &details);
+ gdk_pixbuf_unref (pixbuf);
+ return icon;
+}
+
+static void
+destroy_fallback_icon (void)
+{
+ cache_icon_unref (fallback_icon);
}
/* This load function is not allowed to return NULL. */
-static GdkPixbuf *
-load_image_for_scaling (NautilusScalableIcon *scalable_icon,
- guint requested_size,
- guint *actual_size_result,
- gboolean *custom,
- IconInfo *icon_info)
+static CacheIcon *
+load_icon_for_scaling (NautilusScalableIcon *scalable_icon,
+ guint requested_size,
+ guint *actual_size_result)
{
- GdkPixbuf *image;
+ CacheIcon *icon;
guint actual_size;
IconSizeRequest size_request;
- static GdkPixbuf *fallback_image;
size_request.maximum_width = MAXIMUM_ICON_SIZE * requested_size / NAUTILUS_ZOOM_LEVEL_STANDARD;
size_request.maximum_height = size_request.maximum_width;
@@ -1732,15 +1550,11 @@ load_image_for_scaling (NautilusScalableIcon *scalable_icon,
size_request.nominal_width = actual_size;
size_request.nominal_height = actual_size;
- image = get_image_from_cache (scalable_icon,
- &size_request,
- TRUE,
- TRUE,
- icon_info);
- if (image != NULL) {
+ icon = get_icon_from_cache
+ (scalable_icon, &size_request, TRUE, TRUE);
+ if (icon != NULL) {
*actual_size_result = actual_size;
- *custom = TRUE;
- return image;
+ return icon;
}
}
@@ -1750,21 +1564,18 @@ load_image_for_scaling (NautilusScalableIcon *scalable_icon,
size_request.nominal_width = actual_size;
size_request.nominal_height = actual_size;
- image = get_image_from_cache (scalable_icon,
- &size_request,
- TRUE,
- FALSE,
- icon_info);
- if (image != NULL) {
+ icon = get_icon_from_cache
+ (scalable_icon, &size_request, TRUE, FALSE);
+ if (icon != NULL) {
*actual_size_result = actual_size;
- *custom = FALSE;
- return image;
+ return icon;
}
}
/* Finally, fall back on the hard-coded image. */
- if (fallback_image == NULL) {
- fallback_image = gdk_pixbuf_new_from_data
+ if (fallback_icon == NULL) {
+ fallback_icon = g_new0 (CacheIcon, 1);
+ fallback_icon->pixbuf = gdk_pixbuf_new_from_data
(nautilus_default_file_icon,
GDK_COLORSPACE_RGB,
TRUE,
@@ -1774,36 +1585,38 @@ load_image_for_scaling (NautilusScalableIcon *scalable_icon,
nautilus_default_file_icon_width * 4, /* stride */
NULL, /* don't destroy data */
NULL);
+ g_atexit (destroy_fallback_icon);
}
- gdk_pixbuf_ref (fallback_image);
+ cache_icon_ref (fallback_icon);
- memset (&icon_info->text_rect, 0, sizeof (icon_info->text_rect));
*actual_size_result = NAUTILUS_ICON_SIZE_STANDARD;
- *custom = FALSE;
- return fallback_image;
+ return fallback_icon;
}
-/* Consumes the image and returns a scaled one if the image is too big.
- * Note that this does an unref on the image and returns a new one.
+/* Consumes the icon and returns a scaled one if the pixbuf is too big.
+ * Note that this does an unref on the icon and returns a new one.
*/
-static GdkPixbuf *
-scale_image_and_info (GdkPixbuf *image,
- IconInfo *icon_info,
- double scale_x,
- double scale_y)
+static CacheIcon *
+scale_icon (CacheIcon *icon,
+ double scale_x,
+ double scale_y)
{
int width, height;
int rect_width, rect_height;
- int index;
- GdkPixbuf *scaled_image;
+ int i, num_points;
+ GdkPixbuf *scaled_pixbuf;
+ IconDetails scaled_details;
+ CacheIcon *scaled_icon;
- width = gdk_pixbuf_get_width (image);
- height = gdk_pixbuf_get_height (image);
+ g_assert (!icon->scaled);
+
+ width = gdk_pixbuf_get_width (icon->pixbuf);
+ height = gdk_pixbuf_get_height (icon->pixbuf);
/* Check for no-scaling case. */
if ((int) (width * scale_x) == width
&& (int) (height * scale_y) == height) {
- return gdk_pixbuf_ref (image);
+ return NULL;
}
width *= scale_x;
@@ -1815,30 +1628,34 @@ scale_image_and_info (GdkPixbuf *image,
height = 1;
}
- rect_width = (icon_info->text_rect.x1 - icon_info->text_rect.x0) * scale_x;
- rect_height = (icon_info->text_rect.y1 - icon_info->text_rect.y0) * scale_y;
+ scaled_pixbuf = gdk_pixbuf_scale_simple
+ (icon->pixbuf, width, height, GDK_INTERP_BILINEAR);
+
+ rect_width = (icon->details.text_rect.x1 - icon->details.text_rect.x0) * scale_x;
+ rect_height = (icon->details.text_rect.y1 - icon->details.text_rect.y0) * scale_y;
- scaled_image = gdk_pixbuf_scale_simple
- (image, width, height, GDK_INTERP_BILINEAR);
- gdk_pixbuf_unref (image);
-
- icon_info->text_rect.x0 *= scale_x;
- icon_info->text_rect.y0 *= scale_y;
- icon_info->text_rect.x1 = icon_info->text_rect.x0 + rect_width;
- icon_info->text_rect.y1 = icon_info->text_rect.y0 + rect_height;
-
- if (icon_info->has_attach_points) {
- for (index = 0; index < MAX_ATTACH_POINTS; index++) {
- icon_info->attach_points[index].x *= scale_x;
- icon_info->attach_points[index].y *= scale_y;
- }
+ scaled_details.text_rect.x0 = icon->details.text_rect.x0 * scale_x;
+ scaled_details.text_rect.y0 = icon->details.text_rect.x0 * scale_y;
+ scaled_details.text_rect.x1 = scaled_details.text_rect.x0 + rect_width;
+ scaled_details.text_rect.y1 = scaled_details.text_rect.y0 + rect_height;
+
+ num_points = icon->details.attach_points.num_points;
+ scaled_details.attach_points.num_points = num_points;
+ for (i = 0; i < num_points; i++) {
+ scaled_details.attach_points.points[i].x = icon->details.attach_points.points[i].x * scale_x;
+ scaled_details.attach_points.points[i].y = icon->details.attach_points.points[i].y * scale_y;
}
- return scaled_image;
+ scaled_icon = cache_icon_new (scaled_pixbuf,
+ icon->custom,
+ TRUE,
+ &scaled_details);
+ gdk_pixbuf_unref (scaled_pixbuf);
+ return scaled_icon;
}
static void
-revise_scale_factors_if_too_big (GdkPixbuf *image,
+revise_scale_factors_if_too_big (GdkPixbuf *pixbuf,
const IconSizeRequest *size,
double *scale_x,
double *scale_y)
@@ -1846,8 +1663,8 @@ revise_scale_factors_if_too_big (GdkPixbuf *image,
int width, height;
double y_distortion;
- width = gdk_pixbuf_get_width (image);
- height = gdk_pixbuf_get_height (image);
+ width = gdk_pixbuf_get_width (pixbuf);
+ height = gdk_pixbuf_get_height (pixbuf);
if ((int) (width * *scale_x) <= size->maximum_width
&& (int) (height * *scale_y) <= size->maximum_height) {
@@ -1861,49 +1678,46 @@ revise_scale_factors_if_too_big (GdkPixbuf *image,
*scale_y = *scale_x * y_distortion;
}
-/* Consumes the image and returns a scaled one if the image is too big.
- * Note that this does an unref on the image and returns a new one.
- */
-static GdkPixbuf *
-scale_image_down_if_too_big (GdkPixbuf *image,
- const IconSizeRequest *size,
- IconInfo *icon_info)
+/* Returns a scaled icon if this one is too big. */
+static CacheIcon *
+scale_down_if_too_big (CacheIcon *icon,
+ const IconSizeRequest *size)
{
double scale_x, scale_y;
scale_x = 1.0;
scale_y = 1.0;
- revise_scale_factors_if_too_big (image, size, &scale_x, &scale_y);
- return scale_image_and_info (image, icon_info, scale_x, scale_y);
+ revise_scale_factors_if_too_big (icon->pixbuf, size, &scale_x, &scale_y);
+ return scale_icon (icon, scale_x, scale_y);
}
/* This load function is not allowed to return NULL. */
-static GdkPixbuf *
-load_image_scale_if_necessary (NautilusScalableIcon *scalable_icon,
- const IconSizeRequest *size,
- gboolean *scaled,
- gboolean *custom,
- IconInfo *icon_info)
+static CacheIcon *
+load_icon_scale_if_necessary (NautilusScalableIcon *scalable_icon,
+ const IconSizeRequest *size)
{
- GdkPixbuf *image;
+ CacheIcon *icon, *scaled_icon;
guint nominal_actual_size;
double scale_x, scale_y;
- /* Load the image for the icon that's closest in size to what we want. */
- image = load_image_for_scaling (scalable_icon, size->nominal_width,
- &nominal_actual_size, custom, icon_info);
- if (size->nominal_width == nominal_actual_size
- && size->nominal_height == nominal_actual_size) {
- *scaled = FALSE;
- return scale_image_down_if_too_big (image, size, icon_info);
- }
+ /* Load the icon that's closest in size to what we want. */
+ icon = load_icon_for_scaling (scalable_icon,
+ size->nominal_width,
+ &nominal_actual_size);
- /* Scale the image to the size we want. */
- *scaled = TRUE;
+ /* Scale the pixbuf to the size we want. */
scale_x = (double) size->nominal_width / nominal_actual_size;
scale_y = (double) size->nominal_height / nominal_actual_size;
- revise_scale_factors_if_too_big (image, size, &scale_x, &scale_y);
- return scale_image_and_info (image, icon_info, scale_x, scale_y);
+ revise_scale_factors_if_too_big (icon->pixbuf, size, &scale_x, &scale_y);
+ scaled_icon = scale_icon (icon, scale_x, scale_y);
+ if (scaled_icon == NULL) {
+ return icon;
+ }
+
+ /* Mark this icon as scaled, too. */
+ cache_icon_unref (icon);
+ g_assert (scaled_icon->scaled);
+ return scaled_icon;
}
/* Move this item to the head of the recently-used list,
@@ -1915,7 +1729,9 @@ mark_recently_used (NautilusCircularList *node)
NautilusIconFactory *factory;
NautilusCircularList *head, *last_node;
- factory = nautilus_get_current_icon_factory ();
+ check_recently_used_list ();
+
+ factory = get_icon_factory ();
head = &factory->recently_used_dummy_head;
/* Move the node to the start of the list. */
@@ -1928,9 +1744,9 @@ mark_recently_used (NautilusCircularList *node)
/* Node was not already in the list, so add it.
* If the list is already full, remove the last node.
*/
- if (factory->recently_used_count < ICON_CACHE_COUNT)
- factory->recently_used_count++;
- else {
+ if (factory->recently_used_count < ICON_CACHE_COUNT) {
+ factory->recently_used_count += 1;
+ } else {
/* Remove the last node. */
last_node = head->prev;
@@ -1951,101 +1767,104 @@ mark_recently_used (NautilusCircularList *node)
node->next->prev = node;
head->next = node;
}
+
+ check_recently_used_list ();
}
-/* utility routine that checks if a cached image has changed since it was cached.
- * It returns TRUE if the image is still valid, and removes it from the cache if it's not */
-
- static gboolean
- cached_image_still_valid (const char *file_uri, time_t cached_time)
- {
+/* Utility routine that checks if a cached icon has changed since it
+ * was cached. It returns TRUE if the icon is still valid, and
+ * removes it from the cache if it's not.
+ */
+static gboolean
+cached_icon_still_valid (const char *file_uri, time_t cached_time)
+{
GnomeVFSURI *vfs_uri;
GnomeVFSFileInfo file_info;
+ GnomeVFSResult result;
gboolean is_local, is_valid;
- /* if there's no specific file, simply return TRUE */
- if (file_uri == NULL)
+ /* If there's no specific file, simply return TRUE. */
+ if (file_uri == NULL) {
return TRUE;
+ }
- /* FIXME bugzilla.eazel.com 2566: if the URI is remote, assume it's valid to avoid delay of testing. Eventually we'll make this async to fix this */
- vfs_uri = gnome_vfs_uri_new(file_uri);
+ /* FIXME bugzilla.eazel.com 2566: if the URI is remote, assume
+ * it's valid to avoid delay of testing. Eventually we'll have
+ * to make this async to fix this.
+ */
+ vfs_uri = gnome_vfs_uri_new (file_uri);
is_local = gnome_vfs_uri_is_local (vfs_uri);
- gnome_vfs_uri_unref(vfs_uri);
+ gnome_vfs_uri_unref (vfs_uri);
if (!is_local) {
return TRUE;
}
- /* gather the info and then compare modification times */
+ /* Gather the info and then compare modification times. */
gnome_vfs_file_info_init (&file_info);
- gnome_vfs_get_file_info (file_uri, &file_info, GNOME_VFS_FILE_INFO_DEFAULT);
-
- is_valid = file_info.mtime <= cached_time;
+ result = gnome_vfs_get_file_info (file_uri, &file_info, GNOME_VFS_FILE_INFO_DEFAULT);
+ is_valid = result == GNOME_VFS_OK && file_info.mtime <= cached_time;
gnome_vfs_file_info_clear (&file_info);
/* if it's not valid, remove it from the cache */
if (!is_valid) {
- nautilus_icon_factory_clear_image (file_uri);
+ nautilus_icon_factory_remove_by_uri (file_uri);
}
return is_valid;
- }
-
-/* Get the image for icon, handling the caching.
+}
+
+/* Get the icon, handling the caching.
* If @picky is true, then only an unscaled icon is acceptable.
* Also, if @picky is true, the icon must be a custom icon if
* @custom is true or a standard icon is @custom is false.
*/
-static GdkPixbuf *
-get_image_from_cache (NautilusScalableIcon *scalable_icon,
- const IconSizeRequest *size,
- gboolean picky,
- gboolean custom,
- IconInfo *icon_info)
+static CacheIcon *
+get_icon_from_cache (NautilusScalableIcon *scalable_icon,
+ const IconSizeRequest *size,
+ gboolean picky,
+ gboolean custom)
{
NautilusIconFactory *factory;
GHashTable *hash_table;
- IconCacheKey lookup_key, *key;
- GdkPixbuf *image;
+ CacheKey lookup_key, *key;
+ CacheIcon *icon, *scaled_icon;
gpointer key_in_table, value;
- gboolean found_image;
g_return_val_if_fail (scalable_icon != NULL, NULL);
key = NULL;
- image = NULL;
+ icon = NULL;
- factory = nautilus_get_current_icon_factory ();
+ factory = get_icon_factory ();
hash_table = factory->icon_cache;
/* Check to see if it's already in the table. */
lookup_key.scalable_icon = scalable_icon;
lookup_key.size = *size;
- found_image = FALSE;
if (g_hash_table_lookup_extended (hash_table, &lookup_key,
&key_in_table, &value)) {
/* Found it in the table. */
+ g_assert (key_in_table != NULL);
+ g_assert (value != NULL);
key = key_in_table;
+ icon = value;
/* If we're going to be picky, then don't accept anything
* other than exactly what we are looking for.
*/
- if (picky && (key->scaled || custom != key->custom)) {
+ if (picky && (icon->scaled || custom != icon->custom)) {
return NULL;
}
- image = value;
- found_image = cached_image_still_valid (scalable_icon->uri, key->cache_time);
- g_assert (image != NULL);
+ /* Check if the cached image is good before using it. */
+ if (!cached_icon_still_valid (scalable_icon->uri,
+ icon->cache_time)) {
+ icon = NULL;
+ }
}
- if (!found_image) {
- gboolean got_scaled_image;
- gboolean got_custom_image;
- IconInfo key_icon_info;
-
- key_icon_info.has_attach_points = FALSE;
-
+ if (icon == NULL) {
/* Not in the table, so load the image. */
/* If we're picky, then we want the image only if this exact
* nominal size is available.
@@ -2054,80 +1873,59 @@ get_image_from_cache (NautilusScalableIcon *scalable_icon,
g_assert (scalable_icon->embedded_text == NULL);
/* Actual icons have nominal sizes that are square! */
- if (size->nominal_width
- != size->nominal_height) {
+ if (size->nominal_width != size->nominal_height) {
return NULL;
}
/* Get the image. */
- image = load_specific_image (scalable_icon,
- size->nominal_width,
- custom,
- &key_icon_info);
- if (image == NULL) {
+ icon = load_specific_icon (scalable_icon,
+ size->nominal_width,
+ custom);
+ if (icon == NULL) {
return NULL;
}
- /* Now we have the image, but is it bigger than
- * the maximum size? If so we scale it, even but we don't
- * call it "scaled" for caching purposese.
+ /* Now we have the image, but is it bigger
+ * than the maximum size? If so we scale it,
+ * but we don't call it "scaled" for caching
+ * purposese.
*/
- image = scale_image_down_if_too_big (image, size, &key_icon_info);
-
- got_scaled_image = FALSE;
- got_custom_image = custom;
+ scaled_icon = scale_down_if_too_big (icon, size);
+ if (scaled_icon != NULL) {
+ scaled_icon->scaled = FALSE;
+ cache_icon_unref (icon);
+ icon = scaled_icon;
+ }
} else {
if (scalable_icon->embedded_text != NULL) {
- image = load_image_with_embedded_text (scalable_icon, size);
-
- /* None of these matters for an icon with text already embedded.
- * So we fill in with arbitrary values.
- */
- got_scaled_image = FALSE;
- got_custom_image = FALSE;
- memset (&key_icon_info.text_rect, 0, sizeof (key_icon_info.text_rect));
+ icon = load_icon_with_embedded_text (scalable_icon, size);
} else {
- image = load_image_scale_if_necessary
- (scalable_icon,
- size,
- &got_scaled_image,
- &got_custom_image,
- &key_icon_info);
+ icon = load_icon_scale_if_necessary (scalable_icon, size);
}
- g_assert (image != NULL);
+ g_assert (icon != NULL);
}
- /* Add the embedded text. */
-
- /* Create the key for the table. */
- key = g_new0 (IconCacheKey, 1);
+ /* Create the key and icon for the hash table. */
+ key = g_new (CacheKey, 1);
nautilus_scalable_icon_ref (scalable_icon);
key->scalable_icon = scalable_icon;
key->size = *size;
- key->scaled = got_scaled_image;
- key->custom = got_custom_image;
- key->icon_info = key_icon_info;
- key->cache_time = time(NULL);
/* Add the item to the hash table. */
- g_hash_table_insert (hash_table, key, image);
+ g_assert (g_hash_table_lookup (hash_table, key) == NULL);
+ g_hash_table_insert (hash_table, key, icon);
}
- /* Return the icon info if the caller asked for it. */
- if (icon_info != NULL) {
- *icon_info = key->icon_info;
- }
+ /* Hand back a ref to the caller. */
+ cache_icon_ref (icon);
/* Since this item was used, keep it in the cache longer. */
- mark_recently_used (&key->recently_used_node);
+ mark_recently_used (&icon->recently_used_node);
/* Come back later and sweep the cache. */
nautilus_icon_factory_schedule_sweep ();
- /* Grab a ref for the caller. */
- g_assert (image != NULL);
- gdk_pixbuf_ref (image);
- return image;
+ return icon;
}
GdkPixbuf *
@@ -2136,41 +1934,42 @@ nautilus_icon_factory_get_pixbuf_for_icon (NautilusScalableIcon *scalable_icon,
guint nominal_height,
guint maximum_width,
guint maximum_height,
- EmblemAttachPoints *attach_data)
+ NautilusEmblemAttachPoints *attach_points)
{
IconSizeRequest size;
- IconInfo icon_info;
+ CacheIcon *icon;
GdkPixbuf *pixbuf;
- int index;
size.nominal_width = nominal_width;
size.nominal_height = nominal_width;
size.maximum_width = maximum_width;
size.maximum_height = maximum_height;
- pixbuf = get_image_from_cache (scalable_icon, &size,
- FALSE, scalable_icon->uri != NULL,
- &icon_info);
- if (attach_data != NULL) {
- attach_data->has_attach_points = icon_info.has_attach_points;
- for (index = 0; index < MAX_ATTACH_POINTS; index++) {
- attach_data->attach_points[index] = icon_info.attach_points[index];
- }
+ icon = get_icon_from_cache (scalable_icon, &size,
+ FALSE, scalable_icon->uri != NULL);
+
+ if (attach_points != NULL) {
+ *attach_points = icon->details.attach_points;
}
- return pixbuf;
-}
-
+ /* The first time we hand out an icon we just leave it with a
+ * single ref (we'll get called back for the unref), but
+ * subsequent times we add additional refs.
+ */
+ pixbuf = icon->pixbuf;
+ if (!icon->outstanding) {
+ icon->outstanding = TRUE;
+ } else {
+ gdk_pixbuf_ref (pixbuf);
+ }
+ cache_icon_unref (icon);
-static void
-icon_cache_key_destroy (IconCacheKey *key)
-{
- nautilus_scalable_icon_unref (key->scalable_icon);
+ return pixbuf;
}
static guint
-icon_cache_key_hash (gconstpointer p)
+cache_key_hash (gconstpointer p)
{
- const IconCacheKey *key;
+ const CacheKey *key;
key = p;
return (((((((GPOINTER_TO_UINT (key->scalable_icon) << 4)
@@ -2181,9 +1980,9 @@ icon_cache_key_hash (gconstpointer p)
}
static gboolean
-icon_cache_key_equal (gconstpointer a, gconstpointer b)
+cache_key_equal (gconstpointer a, gconstpointer b)
{
- const IconCacheKey *key_a, *key_b;
+ const CacheKey *key_a, *key_b;
key_a = a;
key_b = b;
@@ -2305,290 +2104,117 @@ embed_text (GdkPixbuf *pixbuf_without_text,
const ArtIRect *embedded_text_rect,
const char *text)
{
- if (smooth_graphics) {
- GdkPixbuf *pixbuf_with_text = NULL;
- NautilusScalableFont *font;
- const guint font_size = 9;
- const guint line_offset = 1;
- const guint empty_line_height = font_size / 2;
-
- /* Quick out for the case where there's no place to embed the
- * text or the place is too small or there's no text.
- */
- if (!embedded_text_rect_usable (embedded_text_rect) || nautilus_strlen (text) == 0) {
- return gdk_pixbuf_ref (pixbuf_without_text);
- }
-
- /* FIXME bugzilla.eazel.com 1102: Embedded text should use preferences to determine
- * the font it uses
- */
- font = NAUTILUS_SCALABLE_FONT (nautilus_scalable_font_new ("helvetica", "medium", NULL, NULL));
-
- pixbuf_with_text = gdk_pixbuf_copy (pixbuf_without_text);
-
- nautilus_scalable_font_draw_text_lines (font,
- pixbuf_with_text,
- embedded_text_rect->x0,
- embedded_text_rect->y0,
- embedded_text_rect,
- font_size,
- font_size,
- text,
- GTK_JUSTIFY_LEFT,
- line_offset,
- empty_line_height,
- NAUTILUS_RGB_COLOR_BLACK,
- 255,
- FALSE);
-
- gtk_object_unref (GTK_OBJECT (font));
-
- return pixbuf_with_text;
+ NautilusScalableFont *smooth_font;
+ static GdkFont *font;
+ GdkPixbuf *pixbuf_with_text;
+
+ g_return_val_if_fail (pixbuf_without_text != NULL, NULL);
+ g_return_val_if_fail (embedded_text_rect != NULL, NULL);
+
+ /* Quick out for the case where there's no place to embed the
+ * text or the place is too small or there's no text.
+ */
+ if (!embedded_text_rect_usable (embedded_text_rect) || nautilus_strlen (text) == 0) {
+ return NULL;
}
- else {
- static GdkFont *font;
- GdkPixbuf *pixbuf_with_text;
+ pixbuf_with_text = gdk_pixbuf_copy (pixbuf_without_text);
- g_return_val_if_fail (pixbuf_without_text != NULL, NULL);
- g_return_val_if_fail (embedded_text_rect != NULL, gdk_pixbuf_ref (pixbuf_without_text));
+ if (smooth_graphics) {
+ smooth_font = NAUTILUS_SCALABLE_FONT
+ (nautilus_scalable_font_new
+ (EMBEDDED_TEXT_FONT_FAMILY,
+ EMBEDDED_TEXT_FONT_WEIGHT,
+ EMBEDDED_TEXT_FONT_SLANT,
+ EMBEDDED_TEXT_FONT_SET_WIDTH));
+
+ nautilus_scalable_font_draw_text_lines
+ (smooth_font,
+ pixbuf_with_text,
+ embedded_text_rect->x0,
+ embedded_text_rect->y0,
+ embedded_text_rect,
+ EMBEDDED_TEXT_FONT_SIZE,
+ EMBEDDED_TEXT_FONT_SIZE,
+ text,
+ GTK_JUSTIFY_LEFT,
+ EMBEDDED_TEXT_LINE_OFFSET,
+ EMBEDDED_TEXT_EMPTY_LINE_HEIGHT,
+ NAUTILUS_RGB_COLOR_BLACK,
+ 255,
+ FALSE);
+ gtk_object_unref (GTK_OBJECT (smooth_font));
+ } else {
/* Get the font the first time through. */
if (font == NULL) {
/* FIXME bugzilla.eazel.com 1102: Embedded text should use preferences to determine
* the font it uses
*/
-
- /* for anti-aliased text, we choose a large font and scale it down */
- font = gdk_font_load ("-*-helvetica-medium-r-normal-*-10-*-*-*-*-*-*-*");
- g_return_val_if_fail (font != NULL, gdk_pixbuf_ref (pixbuf_without_text));
+ font = gdk_font_load (_("-*-helvetica-medium-r-normal-*-10-*-*-*-*-*-*-*"));
+ g_return_val_if_fail (font != NULL, NULL);
}
- /* Quick out for the case where there's no place to embed the
- * text or the place is too small or there's no text.
- */
- if (!embedded_text_rect_usable (embedded_text_rect) || nautilus_strlen (text) == 0) {
- return gdk_pixbuf_ref (pixbuf_without_text);
- }
-
- pixbuf_with_text = gdk_pixbuf_copy (pixbuf_without_text);
-
- nautilus_gdk_pixbuf_draw_text (pixbuf_with_text, font, 1.0, embedded_text_rect,
- text, NAUTILUS_RGB_COLOR_BLACK, 0xFF);
- return pixbuf_with_text;
+ nautilus_gdk_pixbuf_draw_text
+ (pixbuf_with_text, font, 1.0, embedded_text_rect,
+ text, NAUTILUS_RGB_COLOR_BLACK, 0xFF);
}
+
+ return pixbuf_with_text;
}
-static GdkPixbuf *
-load_image_with_embedded_text (NautilusScalableIcon *scalable_icon,
- const IconSizeRequest *size)
+static CacheIcon *
+load_icon_with_embedded_text (NautilusScalableIcon *scalable_icon,
+ const IconSizeRequest *size)
{
NautilusScalableIcon *scalable_icon_without_text;
- GdkPixbuf *pixbuf_without_text, *pixbuf;
- IconInfo icon_info;
+ CacheIcon *icon_without_text, *icon_with_text;
+ GdkPixbuf *pixbuf_with_text;
+ IconDetails details;
g_assert (scalable_icon->embedded_text != NULL);
-
+
+ /* Get the icon without text. */
scalable_icon_without_text = nautilus_scalable_icon_new_from_text_pieces
(scalable_icon->uri,
scalable_icon->name,
scalable_icon->modifier,
NULL,
scalable_icon->aa_mode);
-
- pixbuf_without_text = get_image_from_cache
+ icon_without_text = get_icon_from_cache
(scalable_icon_without_text, size,
- FALSE, FALSE, &icon_info);
+ FALSE, FALSE);
nautilus_scalable_icon_unref (scalable_icon_without_text);
- pixbuf = embed_text (pixbuf_without_text,
- &icon_info. text_rect,
- scalable_icon->embedded_text);
- gdk_pixbuf_unref (pixbuf_without_text);
+ /* Create a pixbuf with the text in it. */
+ pixbuf_with_text = embed_text (icon_without_text->pixbuf,
+ &icon_without_text->details.text_rect,
+ scalable_icon->embedded_text);
+ if (pixbuf_with_text == NULL) {
+ return icon_without_text;
+ }
- return pixbuf;
+ /* Create an icon from the new pixbuf. */
+ details = icon_without_text->details;
+ memset (&details.text_rect, 0, sizeof (details.text_rect));
+ icon_with_text = cache_icon_new (pixbuf_with_text,
+ icon_without_text->custom,
+ icon_without_text->scaled,
+ &details);
+ cache_icon_unref (icon_without_text);
+ gdk_pixbuf_unref (pixbuf_with_text);
+
+ return icon_with_text;
}
/* Convenience function for unrefing and then freeing an entire list. */
void
nautilus_scalable_icon_list_free (GList *icon_list)
{
- nautilus_g_list_free_deep_custom (icon_list, (GFunc) nautilus_scalable_icon_unref, NULL);
-}
-
-/* check_for_thumbnails is a utility that checks to see if any of the thumbnails in the pending
- list have been created yet. If it finds one, it removes the elements from the queue and
- returns true, otherwise it returns false */
-static gboolean
-check_for_thumbnails (NautilusIconFactory *factory)
-{
- char *current_thumbnail;
- NautilusThumbnailInfo *info;
- GList *stop_element;
- GList *next_thumbnail;
- NautilusFile *file;
-
- for (next_thumbnail = factory->thumbnails;
- next_thumbnail != NULL;
- next_thumbnail = next_thumbnail->next) {
- info = (NautilusThumbnailInfo*) next_thumbnail->data;
- current_thumbnail = make_thumbnail_path (info->thumbnail_uri, FALSE, info->is_local, info->anti_aliased);
- /* FIXME bugzilla.eazel.com 3137: synchronous I/O */
- if (vfs_file_exists (current_thumbnail)) {
- /* we found one, so update the icon and remove all of the elements up to and including
- this one from the pending list. */
- g_free (current_thumbnail);
- file = nautilus_file_get (info->thumbnail_uri);
-
- if (file != NULL) {
- nautilus_file_changed (file);
- nautilus_file_unref (file);
- }
-
- stop_element = next_thumbnail->next;
- while (factory->thumbnails != stop_element) {
- info = (NautilusThumbnailInfo *) factory->thumbnails->data;
- g_free (info->thumbnail_uri);
- g_free (info);
- factory->thumbnails = g_list_remove_link (factory->thumbnails, factory->thumbnails);
- }
- return TRUE;
- }
-
- g_free (current_thumbnail);
- }
-
- return FALSE;
-}
-
-/* make_thumbnails is invoked periodically as a timer task to launch a task to make thumbnails */
-
-static GdkPixbuf*
-load_thumbnail_frame (gboolean anti_aliased)
-{
- char *image_path;
- GdkPixbuf *frame_image;
-
- /* load the thumbnail frame */
- image_path = nautilus_theme_get_image_path (anti_aliased ? "thumbnail_frame.aa.png" : "thumbnail_frame.png");
- frame_image = gdk_pixbuf_new_from_file (image_path);
- g_free (image_path);
- return frame_image;
-}
-
-static int
-nautilus_icon_factory_make_thumbnails (gpointer data)
-{
- pid_t thumbnail_pid;
- NautilusThumbnailInfo *info;
- NautilusIconFactory *factory = nautilus_get_current_icon_factory();
- GList *next_thumbnail = factory->thumbnails;
- GdkPixbuf *scaled_image, *framed_image, *thumbnail_image_frame;
- char *frame_offset_str;
- int left_offset, top_offset, right_offset, bottom_offset;
-
- /* if the queue is empty, there's nothing more to do */
- if (next_thumbnail == NULL) {
- gtk_timeout_remove (factory->timeout_task_id);
- factory->timeout_task_id = 0;
- return FALSE;
- }
-
- info = (NautilusThumbnailInfo *) next_thumbnail->data;
-
- /* see which state we're in. If a thumbnail isn't in progress, start one up. Otherwise,
- check if the pending one is completed. */
- if (factory->thumbnail_in_progress) {
- if (check_for_thumbnails(factory)) {
- factory->thumbnail_in_progress = FALSE;
- }
- }
- else {
- /* start up a task to make the thumbnail corresponding to the queue element. */
-
- /* First, compute the path name of the target thumbnail */
- g_free (factory->new_thumbnail_path);
- factory->new_thumbnail_path = make_thumbnail_path (info->thumbnail_uri, FALSE, info->is_local, info->anti_aliased);
-
- /* fork a task to make the thumbnail, using gdk-pixbuf to do the scaling */
- if (!(thumbnail_pid = fork())) {
- GdkPixbuf* full_size_image;
- NautilusFile *file;
- char *thumbnail_path;
-
- file = nautilus_file_get (info->thumbnail_uri);
- full_size_image = NULL;
-
- if (nautilus_file_is_mime_type (file, "image/svg")) {
- thumbnail_path = gnome_vfs_get_local_path_from_uri (info->thumbnail_uri);
- if (thumbnail_path != NULL) {
- FILE *f = fopen (thumbnail_path, "rb");
- if (f != NULL) {
- full_size_image = rsvg_render_file (f, 1.0);
- fclose (f);
- }
- }
- } else {
- if (info->thumbnail_uri != NULL)
- full_size_image = nautilus_gdk_pixbuf_load (info->thumbnail_uri);
- }
- nautilus_file_unref (file);
-
- if (full_size_image != NULL) {
- thumbnail_image_frame = load_thumbnail_frame (info->anti_aliased);
-
- /* scale the content image as necessary */
- scaled_image = nautilus_gdk_pixbuf_scale_down_to_fit(full_size_image, 96, 96);
- gdk_pixbuf_unref (full_size_image);
-
- /* embed the content image in the frame */
- frame_offset_str = nautilus_theme_get_theme_data ("thumbnails", "FRAME_OFFSETS");
- if (frame_offset_str != NULL) {
- sscanf (frame_offset_str," %d , %d , %d , %d %*s", &left_offset, &top_offset, &right_offset, &bottom_offset);
- } else {
- /* use nominal values since the info in the theme couldn't be found */
- left_offset = 3; top_offset = 3;
- right_offset = 6; bottom_offset = 6;
- }
-
- framed_image = nautilus_embed_image_in_frame (scaled_image, thumbnail_image_frame,
- left_offset, top_offset, right_offset, bottom_offset);
- g_free (frame_offset_str);
-
- gdk_pixbuf_unref (scaled_image);
- gdk_pixbuf_unref (thumbnail_image_frame);
-
- thumbnail_path = gnome_vfs_get_local_path_from_uri (factory->new_thumbnail_path);
- if (!nautilus_gdk_pixbuf_save_to_file (framed_image, thumbnail_path)) {
- g_warning ("error saving thumbnail %s", thumbnail_path);
- }
- g_free (thumbnail_path);
- gdk_pixbuf_unref (framed_image);
- }
- else {
- /* gdk-pixbuf couldn't load the image, so trying using ImageMagick */
- char *temp_str;
- thumbnail_path = gnome_vfs_get_local_path_from_uri (factory->new_thumbnail_path);
- temp_str = g_strdup_printf ("png:%s", thumbnail_path);
- g_free (thumbnail_path);
-
- thumbnail_path = gnome_vfs_get_local_path_from_uri (info->thumbnail_uri);
-
- /* scale the image */
- execlp ("convert", "convert", "-geometry", "96x96", thumbnail_path, temp_str, NULL);
-
- /* we don't come back from this call, so no point in freeing anything up */
- }
-
- _exit(0);
- }
- factory->thumbnail_in_progress = TRUE;
- }
-
- return TRUE; /* we're not done yet */
+ nautilus_g_list_free_deep_custom
+ (icon_list, (GFunc) nautilus_scalable_icon_unref, NULL);
}
-
#if ! defined (NAUTILUS_OMIT_SELF_CHECK)
static char *