diff options
29 files changed, 1393 insertions, 356 deletions
diff --git a/ChangeLog-20000414 b/ChangeLog-20000414 index 8d0a2a5db..10277a45c 100644 --- a/ChangeLog-20000414 +++ b/ChangeLog-20000414 @@ -1,3 +1,76 @@ +2000-02-17 Darin Adler <darin@eazel.com> + + Hand tuned icons for multiple resolutions. + So for example you can have an icon designed for the 96x96 + size, which is called i-directory-96.png, and it will be + loaded instead of loading i-directory.png and scaling it. + + * libnautilus/nautilus-icon-factory.c: + (nautilus_icon_factory_get_icon_name_for_regular_file), + (add_size_to_icon_name), (nautilus_icon_factory_load_icon), + (nautilus_icon_factory_create_image_for_item), + (get_larger_icon_size), (get_smaller_icon_size), + (get_next_icon_size_to_try), (load_specific_image), + (load_image_for_scaling), (load_image_scale_if_necessary), + (nautilus_icon_factory_mark_recently_used), (mark_recently_used), + (nautilus_icon_factory_get_pixbuf_for_icon), + (get_image_from_cache), (nautilus_icon_factory_scale): Changed the + icon factory so it will look for icons of multiple resolutions and + scale the nearest. Also made other improvements including sharing + a single fallback icon instead of making multiple ones, using the + "core-dump" icon for files named "core", adding some additional + g_return_if_fail. + + * libnautilus/nautilus-icon-factory.c: + (self_test_next_icon_size_to_try), + (nautilus_self_check_icon_factory): + * libnautilus/nautilus-lib-self-check-functions.h: + The new code needed a bit of self-check code, so I added it. + + * libnautilus/nautilus-directory.c: + (nautilus_directory_try_to_read_metafile), + (nautilus_directory_construct_alternate_metafile_uri): + Since "make check" was failing, I checked to see what was wrong. + The code that was respecting the new "valid_fields" part of + GnomeVFSFileInfo was looking at the wrong field (flags instead + of valid_fields), which caused all metafile reading to fail. + While debugging this, I noticed that the alternate metafiles + had particularly bad long names, so I fixed that too. + + * libnautilus/nautilus-directory.c: (nautilus_file_ref): + * libnautilus/nautilus-glib-extensions.c: + (nautilus_strdup_strftime): + * libnautilus/nautilus-string.c: (nautilus_string_to_int): + Switched from using <limits.h> constants to the ones from + <glib.h>. I have no idea why I made this change. All hail + glib! C Standard be damned! + + * fm-directory-view.c: + (use_eazel_theme_icons_cb), (add_menu_item), + (fm_directory_view_real_append_background_context_menu_items): + Started on a user interface to switch to the Eazel theme + icons so you can see the multiple-resolution icons, but + I wanted to check in, so I stopped before it was done. + + * src/nautilus-index-title.c: + Reindented Andy's new code to match the emacs mode header. + + * configure.in: + * icons/Makefile.am: + * icons/eazel/.cvsignore: + * icons/eazel/Makefile.am: + * icons/eazel/i-directory-24.png: + * icons/eazel/i-directory-36.png: + * icons/eazel/i-directory-72.png: + * icons/eazel/i-directory-96.png: + * icons/eazel/i-directory.png: + I needed some variable-size icons to demonstrate the multiple + resolution support in the icon factory, so I added a few + directory icons from gnomad. Since these don't match the other + icons, I made them part of an "eazel" icons theme. + + * RENAMING: Some new name ideas. + 2000-02-17 Jonathan Blandford <jrb@redhat.com> * src/nautilus-index-title.c (nautilus_index_title_set_up_label): @@ -11,3 +11,6 @@ GtkFList -> NautilusList FMDirectoryViewIcons -> FMDirectoryIconView FMDirectoryViewList -> FMDirectoryListView + +NautilusBookmarklist -> NautilusBookmarkList +nautilus-bookmarklist* -> nautilus-bookmark-list* diff --git a/configure.in b/configure.in index 6e3cd9ae6..3967c7d2c 100644 --- a/configure.in +++ b/configure.in @@ -99,6 +99,7 @@ AC_C_CONST AC_OUTPUT([ Makefile icons/Makefile +icons/eazel/Makefile idl/Makefile libnautilus/Makefile src/Makefile diff --git a/icons/Makefile.am b/icons/Makefile.am index 2a98096bc..f01e312cd 100644 --- a/icons/Makefile.am +++ b/icons/Makefile.am @@ -1,3 +1,5 @@ +SUBDIRS = eazel + icondir = $(datadir)/pixmaps/nautilus icon_DATA = \ diff --git a/icons/eazel/.cvsignore b/icons/eazel/.cvsignore new file mode 100644 index 000000000..282522db0 --- /dev/null +++ b/icons/eazel/.cvsignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in diff --git a/icons/eazel/Makefile.am b/icons/eazel/Makefile.am new file mode 100644 index 000000000..a945c4c6b --- /dev/null +++ b/icons/eazel/Makefile.am @@ -0,0 +1,10 @@ +eazeldir = $(datadir)/pixmaps/nautilus/eazel + +eazel_DATA = \ + i-directory.png \ + i-directory-24.png \ + i-directory-36.png \ + i-directory-72.png \ + i-directory-96.png + +EXTRA_DIST = $(eazel_DATA) diff --git a/icons/eazel/i-directory-24.png b/icons/eazel/i-directory-24.png Binary files differnew file mode 100644 index 000000000..cdac4d043 --- /dev/null +++ b/icons/eazel/i-directory-24.png diff --git a/icons/eazel/i-directory-36.png b/icons/eazel/i-directory-36.png Binary files differnew file mode 100644 index 000000000..843bbc687 --- /dev/null +++ b/icons/eazel/i-directory-36.png diff --git a/icons/eazel/i-directory-72.png b/icons/eazel/i-directory-72.png Binary files differnew file mode 100644 index 000000000..a5022b29d --- /dev/null +++ b/icons/eazel/i-directory-72.png diff --git a/icons/eazel/i-directory-96.png b/icons/eazel/i-directory-96.png Binary files differnew file mode 100644 index 000000000..23973bdc9 --- /dev/null +++ b/icons/eazel/i-directory-96.png diff --git a/icons/eazel/i-directory.png b/icons/eazel/i-directory.png Binary files differnew file mode 100644 index 000000000..20c411dc4 --- /dev/null +++ b/icons/eazel/i-directory.png diff --git a/libnautilus-extensions/nautilus-directory.c b/libnautilus-extensions/nautilus-directory.c index 703ce6032..56a028efd 100644 --- a/libnautilus-extensions/nautilus-directory.c +++ b/libnautilus-extensions/nautilus-directory.c @@ -296,7 +296,7 @@ nautilus_directory_try_to_read_metafile (NautilusDirectory *directory, GnomeVFSU if (result == GNOME_VFS_OK) { /* Check for the case where the info doesn't give the file size. */ - if ((metafile_info.flags & GNOME_VFS_FILE_INFO_FIELDS_SIZE) == 0) + if ((metafile_info.valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) == 0) result = GNOME_VFS_ERROR_GENERIC; } @@ -534,7 +534,7 @@ nautilus_make_directory_and_parents (GnomeVFSURI *uri, guint permissions) } static GnomeVFSURI * -nautilus_directory_construct_alternate_metafile_uri (GnomeVFSURI *metafile_uri) +nautilus_directory_construct_alternate_metafile_uri (GnomeVFSURI *uri) { GnomeVFSResult result; GnomeVFSURI *home_uri, *nautilus_directory_uri, *metafiles_directory_uri, *alternate_uri; @@ -553,8 +553,7 @@ nautilus_directory_construct_alternate_metafile_uri (GnomeVFSURI *metafile_uri) } /* Construct a file name from the URI. */ - uri_as_string = gnome_vfs_uri_to_string (metafile_uri, - GNOME_VFS_URI_HIDE_NONE); + uri_as_string = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_NONE); escaped_uri = nautilus_directory_escape_slashes (uri_as_string); g_free (uri_as_string); file_name = g_strconcat (escaped_uri, ".xml", NULL); @@ -594,7 +593,7 @@ nautilus_directory_new (const char* uri) return NULL; metafile_uri = gnome_vfs_uri_append_path (vfs_uri, METAFILE_NAME); - alternate_metafile_uri = nautilus_directory_construct_alternate_metafile_uri (metafile_uri); + alternate_metafile_uri = nautilus_directory_construct_alternate_metafile_uri (vfs_uri); directory = gtk_type_new (NAUTILUS_TYPE_DIRECTORY); @@ -1155,7 +1154,7 @@ nautilus_file_ref (NautilusFile *file) { g_return_if_fail (file != NULL); - g_assert (file->ref_count < UINT_MAX); + g_assert (file->ref_count < G_MAXINT); g_assert (file->directory != NULL); /* Increment the ref count. */ diff --git a/libnautilus-extensions/nautilus-glib-extensions.c b/libnautilus-extensions/nautilus-glib-extensions.c index c17cc3aa6..7a3a019be 100644 --- a/libnautilus-extensions/nautilus-glib-extensions.c +++ b/libnautilus-extensions/nautilus-glib-extensions.c @@ -68,7 +68,7 @@ nautilus_strdup_strftime (const char *format, struct tm *time_pieces) char *result; size_t string_length; - string_length = strftime (NULL, UINT_MAX, format, time_pieces); + string_length = strftime (NULL, G_MAXINT, format, time_pieces); result = g_malloc (string_length + 1); strftime (result, string_length + 1, format, time_pieces); diff --git a/libnautilus-extensions/nautilus-icon-factory.c b/libnautilus-extensions/nautilus-icon-factory.c index 39341f54b..f046b1329 100644 --- a/libnautilus-extensions/nautilus-icon-factory.c +++ b/libnautilus-extensions/nautilus-icon-factory.c @@ -36,6 +36,7 @@ #include "nautilus-string.h" #include "nautilus-default-file-icon.h" #include "nautilus-metadata.h" +#include "nautilus-lib-self-check-functions.h" #define ICON_NAME_DIRECTORY "i-directory.png" #define ICON_NAME_DIRECTORY_CLOSED "i-dirclosed.png" @@ -94,7 +95,7 @@ typedef struct { * A circular list of the most recently used images is kept * around, and we don't let them go when we sweep the cache. */ - GHashTable *icon_cache; + GHashTable *icon_cache; NautilusCircularList recently_used_dummy_head; guint recently_used_count; guint sweep_timer; @@ -118,20 +119,23 @@ struct _NautilusScalableIcon { }; /* 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. */ typedef struct { NautilusScalableIcon *scalable_icon; guint size_in_pixels; NautilusCircularList recently_used_node; + + gboolean custom; + gboolean scaled; } NautilusIconCacheKey; /* forward declarations */ static NautilusIconFactory * nautilus_get_current_icon_factory (void); static NautilusIconFactory * nautilus_icon_factory_new (const char *theme_name); -static GdkPixbuf * nautilus_icon_factory_scale (GdkPixbuf *standard_sized_image, - guint size_in_pixels); static NautilusScalableIcon *nautilus_scalable_icon_get (const char *uri, const char *name, gboolean is_symbolic_link); @@ -142,6 +146,10 @@ static void nautilus_icon_cache_key_destroy (NautilusIconCach static guint nautilus_icon_cache_key_hash (gconstpointer p); static gboolean nautilus_icon_cache_key_equal (gconstpointer a, gconstpointer b); +static GdkPixbuf * get_image_from_cache (NautilusScalableIcon *scalable_icon, + guint size_in_pixels, + gboolean picky, + gboolean custom); /* Return a pointer to the single global icon factory. */ NautilusIconFactory * @@ -295,19 +303,30 @@ nautilus_icon_factory_set_theme (const char *theme_name) static const char * nautilus_icon_factory_get_icon_name_for_regular_file (NautilusFile *file) { + char *file_name; + gboolean is_core; const char *mime_type; const char *icon_name; + file_name = nautilus_file_get_name (file); + is_core = strcmp (file_name, "core") == 0; + g_free (file_name); + if (is_core) { + return ICON_NAME_CORE; + } + mime_type = nautilus_file_get_mime_type (file); if (mime_type != NULL) { icon_name = gnome_mime_get_value (mime_type, "icon-filename"); - if (icon_name != NULL) + if (icon_name != NULL) { return icon_name; + } } /* GNOME didn't give us a file name, so we have to fall back on special icon sets. */ - if (nautilus_file_is_executable (file)) + if (nautilus_file_is_executable (file)) { return ICON_NAME_EXECUTABLE; + } return ICON_NAME_REGULAR; } @@ -377,6 +396,24 @@ nautilus_icon_factory_load_file (const char *name) return image; } +/* Remove the suffix, add a size, and re-add the suffix. */ +static char * +add_size_to_image_name (const char *name, guint size) +{ + const char *suffix; + char *name_without_suffix; + char *name_with_size; + + suffix = strrchr (name, '.'); + if (suffix == NULL) + return g_strdup_printf ("%s-%u", name, size); + + name_without_suffix = g_strndup (name, suffix - name); + name_with_size = g_strdup_printf ("%s-%u%s", name_without_suffix, size, suffix); + g_free (name_without_suffix); + return name_with_size; +} + /* Splats one on top of the other, putting the src image * in the lower left corner of the dest image. */ @@ -405,15 +442,7 @@ nautilus_icon_factory_load_icon (const char *name, gboolean is_symbolic_link) /* Load the image. */ image = nautilus_icon_factory_load_file (name); if (image == NULL) - /* This is the fallback icon. */ - image = gdk_pixbuf_new_from_data (nautilus_default_file_icon, - ART_PIX_RGB, - nautilus_default_file_icon_has_alpha, - nautilus_default_file_icon_width, - nautilus_default_file_icon_height, - nautilus_default_file_icon_width * 4, /* stride */ - NULL, /* don't destroy data */ - NULL); + return NULL; /* Overlay the symbolic link symbol on top of the image. */ if (is_symbolic_link) { @@ -561,51 +590,211 @@ nautilus_icon_factory_get_icon_for_file (NautilusFile *file) return scalable_icon; } +static guint +get_larger_icon_size (guint size) +{ + if (size < NAUTILUS_ICON_SIZE_SMALLEST) { + return NAUTILUS_ICON_SIZE_SMALLEST; + } + if (size < NAUTILUS_ICON_SIZE_SMALLER) { + return NAUTILUS_ICON_SIZE_SMALLER; + } + if (size < NAUTILUS_ICON_SIZE_SMALL) { + return NAUTILUS_ICON_SIZE_SMALL; + } + if (size < NAUTILUS_ICON_SIZE_STANDARD) { + return NAUTILUS_ICON_SIZE_STANDARD; + } + if (size < NAUTILUS_ICON_SIZE_LARGE) { + return NAUTILUS_ICON_SIZE_LARGE; + } + if (size < NAUTILUS_ICON_SIZE_LARGER) { + return NAUTILUS_ICON_SIZE_LARGER; + } + return NAUTILUS_ICON_SIZE_LARGEST; +} + +static guint +get_smaller_icon_size (guint size) +{ + if (size > NAUTILUS_ICON_SIZE_LARGEST) { + return NAUTILUS_ICON_SIZE_LARGEST; + } + if (size > NAUTILUS_ICON_SIZE_LARGER) { + return NAUTILUS_ICON_SIZE_LARGER; + } + if (size > NAUTILUS_ICON_SIZE_LARGE) { + return NAUTILUS_ICON_SIZE_LARGE; + } + if (size > NAUTILUS_ICON_SIZE_STANDARD) { + return NAUTILUS_ICON_SIZE_STANDARD; + } + if (size > NAUTILUS_ICON_SIZE_SMALL) { + return NAUTILUS_ICON_SIZE_SMALL; + } + if (size > NAUTILUS_ICON_SIZE_SMALLER) { + return NAUTILUS_ICON_SIZE_SMALLER; + } + return NAUTILUS_ICON_SIZE_SMALLEST; +} + +/* Return true if there is another size to try. + * Set the size pointed to by @current_size to 0 to start. + */ +static gboolean +get_next_icon_size_to_try (guint target_size, guint *current_size) +{ + guint size; + + /* Get next larger size. */ + size = *current_size; + if (size == 0 || size >= target_size) { + if (size == 0 && target_size != 0) { + size = target_size - 1; + } + if (size < NAUTILUS_ICON_SIZE_LARGEST) { + *current_size = get_larger_icon_size (size); + return TRUE; + } + size = target_size; + } + + /* Already hit the largest size, get the next smaller size instead. */ + if (size > NAUTILUS_ICON_SIZE_SMALLEST) { + *current_size = get_smaller_icon_size (size); + return TRUE; + } + + /* Tried them all. */ + return FALSE; +} + +/* This load function returns NULL if the icon is not available at this size. */ static GdkPixbuf * -nautilus_icon_factory_create_image_for_icon (NautilusScalableIcon *scalable_icon, - guint size_in_pixels) +load_specific_image (NautilusScalableIcon *scalable_icon, + guint size_in_pixels, + gboolean custom) { - NautilusIconFactory *factory; - GdkPixbuf *image, *standard_size_image; - - /* First cut at handling multiple sizes. If size is other than standard, - * scale the pixbuf here. Eventually we'll read in icon files at multiple - * sizes rather than relying on scaling in every case (though we'll still - * need scaling as a fallback). - */ - if (size_in_pixels != NAUTILUS_ICON_SIZE_STANDARD) - { - standard_size_image = nautilus_icon_factory_get_pixbuf_for_icon - (scalable_icon, NAUTILUS_ICON_SIZE_STANDARD); - image = nautilus_icon_factory_scale - (standard_size_image, size_in_pixels); - gdk_pixbuf_unref (standard_size_image); - return image; - } - - factory = nautilus_get_current_icon_factory (); + if (custom) { + /* Custom image. */ + if (size_in_pixels != NAUTILUS_ICON_SIZE_STANDARD) { + return NULL; + } - /* FIXME: This works only with file:// images, because there's - * no convenience function for loading an image with gnome-vfs - * and gdk-pixbuf. - */ - image = NULL; - if (nautilus_has_prefix (scalable_icon->uri, "file://")) - image = gdk_pixbuf_new_from_file (scalable_icon->uri + 7); - - /* If there was no suitable custom icon URI, then use the icon set. */ - if (image == NULL) + /* FIXME: This works only with file:// images, because there's + * no convenience function for loading an image with gnome-vfs + * and gdk-pixbuf. + */ + if (!nautilus_has_prefix (scalable_icon->uri, "file://")) { + return NULL; + } + + return gdk_pixbuf_new_from_file (scalable_icon->uri + 7); + } else { + char *name; + GdkPixbuf *image; + + /* Standard image at a particular size. */ + name = add_size_to_image_name (scalable_icon->name, size_in_pixels); image = nautilus_icon_factory_load_icon + (name, scalable_icon->is_symbolic_link); + if (image != NULL) + return image; + + /* Standard image at standard size. */ + if (size_in_pixels != NAUTILUS_ICON_SIZE_STANDARD) { + return NULL; + } + return nautilus_icon_factory_load_icon (scalable_icon->name, scalable_icon->is_symbolic_link); + } +} + +/* 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) +{ + GdkPixbuf *image; + guint actual_size; + static GdkPixbuf *fallback_image; + + /* First check for a custom image. */ + actual_size = 0; + while (get_next_icon_size_to_try (requested_size, &actual_size)) { + image = get_image_from_cache (scalable_icon, actual_size, TRUE, TRUE); + if (image != NULL) { + *actual_size_result = actual_size; + *custom = TRUE; + return image; + } + } - return image; + /* Next, go for the normal image. */ + actual_size = 0; + while (get_next_icon_size_to_try (requested_size, &actual_size)) { + image = get_image_from_cache (scalable_icon, actual_size, TRUE, FALSE); + if (image != NULL) { + *actual_size_result = actual_size; + *custom = FALSE; + return image; + } + } + + /* Finally, fall back on the hard-coded image. */ + if (fallback_image == NULL) + fallback_image = gdk_pixbuf_new_from_data + (nautilus_default_file_icon, + ART_PIX_RGB, + nautilus_default_file_icon_has_alpha, + nautilus_default_file_icon_width, + nautilus_default_file_icon_height, + nautilus_default_file_icon_width * 4, /* stride */ + NULL, /* don't destroy data */ + NULL); + gdk_pixbuf_ref (fallback_image); + *actual_size_result = NAUTILUS_ICON_SIZE_STANDARD; + *custom = FALSE; + return fallback_image; +} + +/* This load function is not allowed to return NULL. */ +static GdkPixbuf * +load_image_scale_if_necessary (NautilusScalableIcon *scalable_icon, + guint requested_size, + gboolean *scaled, + gboolean *custom) +{ + GdkPixbuf *image, *scaled_image; + guint actual_size; + int scaled_width, scaled_height; + + /* Load the image for the icon that's closest in size to what we want. */ + image = load_image_for_scaling (scalable_icon, requested_size, + &actual_size, custom); + if (requested_size == actual_size) { + *scaled = FALSE; + return image; + } + + /* Scale the image to the size we want. */ + scaled_width = (gdk_pixbuf_get_width (image) * requested_size) / actual_size; + scaled_height = (gdk_pixbuf_get_height (image) * requested_size) / actual_size; + scaled_image = gdk_pixbuf_scale_simple + (image, scaled_width, scaled_height, ART_FILTER_BILINEAR); + + gdk_pixbuf_unref (image); + *scaled = TRUE; + return scaled_image; } /* Move this item to the head of the recently-used list, * bumping the last item off that list if necessary. */ static void -nautilus_icon_factory_mark_recently_used (NautilusCircularList *node) +mark_recently_used (NautilusCircularList *node) { NautilusIconFactory *factory; NautilusCircularList *head, *last_node; @@ -648,9 +837,16 @@ nautilus_icon_factory_mark_recently_used (NautilusCircularList *node) } } -GdkPixbuf * -nautilus_icon_factory_get_pixbuf_for_icon (NautilusScalableIcon *scalable_icon, - guint size_in_pixels) +/* Get the image for 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, + guint size_in_pixels, + gboolean picky, + gboolean custom) { NautilusIconFactory *factory; GHashTable *hash_table; @@ -658,7 +854,7 @@ nautilus_icon_factory_get_pixbuf_for_icon (NautilusScalableIcon *scalable_icon, GdkPixbuf *image; gpointer key_in_table, value; - g_return_val_if_fail(scalable_icon, NULL); + g_return_val_if_fail (scalable_icon != NULL, NULL); factory = nautilus_get_current_icon_factory (); hash_table = factory->icon_cache; @@ -666,27 +862,52 @@ nautilus_icon_factory_get_pixbuf_for_icon (NautilusScalableIcon *scalable_icon, /* Check to see if it's already in the table. */ lookup_key.scalable_icon = scalable_icon; lookup_key.size_in_pixels = size_in_pixels; - if (g_hash_table_lookup_extended (hash_table, &lookup_key, &key_in_table, &value)) { + if (g_hash_table_lookup_extended (hash_table, &lookup_key, + &key_in_table, &value)) { /* Found it in the table. */ key = key_in_table; image = value; + g_assert (image != NULL); + + /* 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)) + return NULL; } else { - /* Not in the table, so create the image and put it in. */ - image = nautilus_icon_factory_create_image_for_icon - (scalable_icon, size_in_pixels); + gboolean got_scaled_image; + gboolean got_custom_image; + + /* Not in the table, so load the image. */ + if (picky) { + image = load_specific_image (scalable_icon, size_in_pixels, custom); + if (image == NULL) { + return NULL; + } + + got_scaled_image = FALSE; + got_custom_image = custom; + } else { + image = load_image_scale_if_necessary (scalable_icon, size_in_pixels, + &got_scaled_image, + &got_custom_image); + g_assert (image != NULL); + } /* Create the key for the table. */ key = g_new0 (NautilusIconCacheKey, 1); nautilus_scalable_icon_ref (scalable_icon); key->scalable_icon = scalable_icon; key->size_in_pixels = size_in_pixels; - + key->scaled = got_scaled_image; + key->custom = got_custom_image; + /* Add the item to the hash table. */ g_hash_table_insert (hash_table, key, image); } /* Since this item was used, keep it in the cache longer. */ - nautilus_icon_factory_mark_recently_used (&key->recently_used_node); + mark_recently_used (&key->recently_used_node); /* Come back later and sweep the cache. */ nautilus_icon_factory_schedule_sweep (); @@ -696,6 +917,14 @@ nautilus_icon_factory_get_pixbuf_for_icon (NautilusScalableIcon *scalable_icon, return image; } +GdkPixbuf * +nautilus_icon_factory_get_pixbuf_for_icon (NautilusScalableIcon *scalable_icon, + guint size_in_pixels) +{ + return get_image_from_cache (scalable_icon, size_in_pixels, + FALSE, FALSE); +} + static void nautilus_icon_cache_key_destroy (NautilusIconCacheKey *key) { @@ -723,24 +952,6 @@ nautilus_icon_cache_key_equal (gconstpointer a, gconstpointer b) && key_a->size_in_pixels == key_b->size_in_pixels; } -static GdkPixbuf * -nautilus_icon_factory_scale (GdkPixbuf *standard_sized_image, - guint size_in_pixels) -{ - int old_width, old_height, new_width, new_height; - - old_width = gdk_pixbuf_get_width (standard_sized_image); - old_height = gdk_pixbuf_get_height (standard_sized_image); - - new_width = (old_width * size_in_pixels) / NAUTILUS_ICON_SIZE_STANDARD; - new_height = (old_height * size_in_pixels) / NAUTILUS_ICON_SIZE_STANDARD; - - return gdk_pixbuf_scale_simple (standard_sized_image, - new_width, - new_height, - ART_FILTER_BILINEAR); -} - /* Return nominal icon size for given zoom level. * @zoom_level: zoom level for which to find matching icon size. * @@ -781,6 +992,8 @@ nautilus_icon_factory_get_pixbuf_for_file (NautilusFile *file, NautilusScalableIcon *icon; GdkPixbuf *pixbuf; + g_return_val_if_fail (file != NULL, NULL); + icon = nautilus_icon_factory_get_icon_for_file (file); pixbuf = nautilus_icon_factory_get_pixbuf_for_icon (icon, size_in_pixels); nautilus_scalable_icon_unref (icon); @@ -799,13 +1012,117 @@ nautilus_icon_factory_get_pixmap_and_mask_for_file (NautilusFile *file, { GdkPixbuf *pixbuf; - if(!file) { - *pixmap = NULL; - *mask = NULL; - } - g_return_if_fail(file); + g_return_if_fail (pixmap != NULL); + g_return_if_fail (mask != NULL); + + *pixmap = NULL; + *mask = NULL; + + g_return_if_fail (file != NULL); pixbuf = nautilus_icon_factory_get_pixbuf_for_file (file, size_in_pixels); gdk_pixbuf_render_pixmap_and_mask (pixbuf, pixmap, mask, 128); gdk_pixbuf_unref (pixbuf); } + +#if ! defined (NAUTILUS_OMIT_SELF_CHECK) + +static char * +self_test_next_icon_size_to_try (guint start_size, guint current_size) +{ + gboolean got_next_size; + + got_next_size = get_next_icon_size_to_try (start_size, ¤t_size); + return g_strdup_printf ("%s,%d", got_next_size ? "TRUE" : "FALSE", current_size); +} + +void +nautilus_self_check_icon_factory (void) +{ + NAUTILUS_CHECK_INTEGER_RESULT (nautilus_get_icon_size_for_zoom_level (0), 12); + NAUTILUS_CHECK_INTEGER_RESULT (nautilus_get_icon_size_for_zoom_level (1), 24); + NAUTILUS_CHECK_INTEGER_RESULT (nautilus_get_icon_size_for_zoom_level (2), 36); + NAUTILUS_CHECK_INTEGER_RESULT (nautilus_get_icon_size_for_zoom_level (3), 48); + NAUTILUS_CHECK_INTEGER_RESULT (nautilus_get_icon_size_for_zoom_level (4), 72); + NAUTILUS_CHECK_INTEGER_RESULT (nautilus_get_icon_size_for_zoom_level (5), 96); + NAUTILUS_CHECK_INTEGER_RESULT (nautilus_get_icon_size_for_zoom_level (6), 192); + + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (0), 12); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (1), 12); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (11), 12); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (12), 24); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (23), 24); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (24), 36); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (35), 36); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (36), 48); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (47), 48); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (48), 72); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (71), 72); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (72), 96); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (95), 96); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (96), 192); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (191), 192); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (192), 192); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (0xFFFFFFFF), 192); + + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (0), 12); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (1), 12); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (11), 12); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (12), 12); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (24), 12); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (25), 24); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (36), 24); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (37), 36); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (48), 36); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (49), 48); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (72), 48); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (73), 72); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (96), 72); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (97), 96); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (192), 96); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (193), 192); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (0xFFFFFFFF), 192); + + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0, 0), "TRUE,12"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0, 12), "TRUE,24"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0, 24), "TRUE,36"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0, 36), "TRUE,48"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0, 48), "TRUE,72"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0, 72), "TRUE,96"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0, 96), "TRUE,192"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0, 192), "FALSE,192"); + + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (36, 0), "TRUE,36"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (36, 36), "TRUE,48"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (36, 48), "TRUE,72"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (36, 72), "TRUE,96"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (36, 96), "TRUE,192"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (36, 192), "TRUE,24"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (36, 24), "TRUE,12"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (36, 12), "FALSE,12"); + + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (37, 0), "TRUE,48"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (37, 48), "TRUE,72"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (37, 72), "TRUE,96"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (37, 96), "TRUE,192"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (37, 192), "TRUE,36"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (37, 36), "TRUE,24"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (37, 24), "TRUE,12"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (37, 12), "FALSE,12"); + + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0xFFFFFFFF, 0), "TRUE,192"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0xFFFFFFFF, 192), "TRUE,96"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0xFFFFFFFF, 96), "TRUE,72"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0xFFFFFFFF, 72), "TRUE,48"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0xFFFFFFFF, 48), "TRUE,36"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0xFFFFFFFF, 36), "TRUE,24"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0xFFFFFFFF, 24), "TRUE,12"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0xFFFFFFFF, 12), "FALSE,12"); + + NAUTILUS_CHECK_STRING_RESULT (add_size_to_image_name ("", 0), "-0"); + NAUTILUS_CHECK_STRING_RESULT (add_size_to_image_name (".", 0), "-0."); + NAUTILUS_CHECK_STRING_RESULT (add_size_to_image_name ("a", 12), "a-12"); + NAUTILUS_CHECK_STRING_RESULT (add_size_to_image_name ("a.png", 12), "a-12.png"); +} + +#endif /* ! NAUTILUS_OMIT_SELF_CHECK */ diff --git a/libnautilus-extensions/nautilus-lib-self-check-functions.h b/libnautilus-extensions/nautilus-lib-self-check-functions.h index 4a51d24df..287479c00 100644 --- a/libnautilus-extensions/nautilus-lib-self-check-functions.h +++ b/libnautilus-extensions/nautilus-lib-self-check-functions.h @@ -44,6 +44,7 @@ void nautilus_run_lib_self_checks (void); macro (nautilus_self_check_gdk_extensions) \ macro (nautilus_self_check_glib_extensions) \ macro (nautilus_self_check_gnome_icon_container) \ + macro (nautilus_self_check_icon_factory) \ macro (nautilus_self_check_string) \ /* Add new self-check functions to the list above this line. */ diff --git a/libnautilus-extensions/nautilus-string.c b/libnautilus-extensions/nautilus-string.c index 281eea2d1..9b403cada 100644 --- a/libnautilus-extensions/nautilus-string.c +++ b/libnautilus-extensions/nautilus-string.c @@ -92,9 +92,9 @@ nautilus_string_to_int (const char *string, int *integer) result = strtol (string, &parse_end, 0); /* Check that the result is in range. */ - if ((result == LONG_MIN || result == LONG_MAX) && errno == ERANGE) + if ((result == G_MINLONG || result == G_MAXLONG) && errno == ERANGE) return FALSE; - if (result < INT_MIN || result > INT_MAX) + if (result < G_MININT || result > G_MAXINT) return FALSE; /* Check that all the trailing characters are spaces. */ diff --git a/libnautilus-private/nautilus-directory.c b/libnautilus-private/nautilus-directory.c index 703ce6032..56a028efd 100644 --- a/libnautilus-private/nautilus-directory.c +++ b/libnautilus-private/nautilus-directory.c @@ -296,7 +296,7 @@ nautilus_directory_try_to_read_metafile (NautilusDirectory *directory, GnomeVFSU if (result == GNOME_VFS_OK) { /* Check for the case where the info doesn't give the file size. */ - if ((metafile_info.flags & GNOME_VFS_FILE_INFO_FIELDS_SIZE) == 0) + if ((metafile_info.valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) == 0) result = GNOME_VFS_ERROR_GENERIC; } @@ -534,7 +534,7 @@ nautilus_make_directory_and_parents (GnomeVFSURI *uri, guint permissions) } static GnomeVFSURI * -nautilus_directory_construct_alternate_metafile_uri (GnomeVFSURI *metafile_uri) +nautilus_directory_construct_alternate_metafile_uri (GnomeVFSURI *uri) { GnomeVFSResult result; GnomeVFSURI *home_uri, *nautilus_directory_uri, *metafiles_directory_uri, *alternate_uri; @@ -553,8 +553,7 @@ nautilus_directory_construct_alternate_metafile_uri (GnomeVFSURI *metafile_uri) } /* Construct a file name from the URI. */ - uri_as_string = gnome_vfs_uri_to_string (metafile_uri, - GNOME_VFS_URI_HIDE_NONE); + uri_as_string = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_NONE); escaped_uri = nautilus_directory_escape_slashes (uri_as_string); g_free (uri_as_string); file_name = g_strconcat (escaped_uri, ".xml", NULL); @@ -594,7 +593,7 @@ nautilus_directory_new (const char* uri) return NULL; metafile_uri = gnome_vfs_uri_append_path (vfs_uri, METAFILE_NAME); - alternate_metafile_uri = nautilus_directory_construct_alternate_metafile_uri (metafile_uri); + alternate_metafile_uri = nautilus_directory_construct_alternate_metafile_uri (vfs_uri); directory = gtk_type_new (NAUTILUS_TYPE_DIRECTORY); @@ -1155,7 +1154,7 @@ nautilus_file_ref (NautilusFile *file) { g_return_if_fail (file != NULL); - g_assert (file->ref_count < UINT_MAX); + g_assert (file->ref_count < G_MAXINT); g_assert (file->directory != NULL); /* Increment the ref count. */ diff --git a/libnautilus-private/nautilus-glib-extensions.c b/libnautilus-private/nautilus-glib-extensions.c index c17cc3aa6..7a3a019be 100644 --- a/libnautilus-private/nautilus-glib-extensions.c +++ b/libnautilus-private/nautilus-glib-extensions.c @@ -68,7 +68,7 @@ nautilus_strdup_strftime (const char *format, struct tm *time_pieces) char *result; size_t string_length; - string_length = strftime (NULL, UINT_MAX, format, time_pieces); + string_length = strftime (NULL, G_MAXINT, format, time_pieces); result = g_malloc (string_length + 1); strftime (result, string_length + 1, format, time_pieces); diff --git a/libnautilus-private/nautilus-icon-factory.c b/libnautilus-private/nautilus-icon-factory.c index 39341f54b..f046b1329 100644 --- a/libnautilus-private/nautilus-icon-factory.c +++ b/libnautilus-private/nautilus-icon-factory.c @@ -36,6 +36,7 @@ #include "nautilus-string.h" #include "nautilus-default-file-icon.h" #include "nautilus-metadata.h" +#include "nautilus-lib-self-check-functions.h" #define ICON_NAME_DIRECTORY "i-directory.png" #define ICON_NAME_DIRECTORY_CLOSED "i-dirclosed.png" @@ -94,7 +95,7 @@ typedef struct { * A circular list of the most recently used images is kept * around, and we don't let them go when we sweep the cache. */ - GHashTable *icon_cache; + GHashTable *icon_cache; NautilusCircularList recently_used_dummy_head; guint recently_used_count; guint sweep_timer; @@ -118,20 +119,23 @@ struct _NautilusScalableIcon { }; /* 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. */ typedef struct { NautilusScalableIcon *scalable_icon; guint size_in_pixels; NautilusCircularList recently_used_node; + + gboolean custom; + gboolean scaled; } NautilusIconCacheKey; /* forward declarations */ static NautilusIconFactory * nautilus_get_current_icon_factory (void); static NautilusIconFactory * nautilus_icon_factory_new (const char *theme_name); -static GdkPixbuf * nautilus_icon_factory_scale (GdkPixbuf *standard_sized_image, - guint size_in_pixels); static NautilusScalableIcon *nautilus_scalable_icon_get (const char *uri, const char *name, gboolean is_symbolic_link); @@ -142,6 +146,10 @@ static void nautilus_icon_cache_key_destroy (NautilusIconCach static guint nautilus_icon_cache_key_hash (gconstpointer p); static gboolean nautilus_icon_cache_key_equal (gconstpointer a, gconstpointer b); +static GdkPixbuf * get_image_from_cache (NautilusScalableIcon *scalable_icon, + guint size_in_pixels, + gboolean picky, + gboolean custom); /* Return a pointer to the single global icon factory. */ NautilusIconFactory * @@ -295,19 +303,30 @@ nautilus_icon_factory_set_theme (const char *theme_name) static const char * nautilus_icon_factory_get_icon_name_for_regular_file (NautilusFile *file) { + char *file_name; + gboolean is_core; const char *mime_type; const char *icon_name; + file_name = nautilus_file_get_name (file); + is_core = strcmp (file_name, "core") == 0; + g_free (file_name); + if (is_core) { + return ICON_NAME_CORE; + } + mime_type = nautilus_file_get_mime_type (file); if (mime_type != NULL) { icon_name = gnome_mime_get_value (mime_type, "icon-filename"); - if (icon_name != NULL) + if (icon_name != NULL) { return icon_name; + } } /* GNOME didn't give us a file name, so we have to fall back on special icon sets. */ - if (nautilus_file_is_executable (file)) + if (nautilus_file_is_executable (file)) { return ICON_NAME_EXECUTABLE; + } return ICON_NAME_REGULAR; } @@ -377,6 +396,24 @@ nautilus_icon_factory_load_file (const char *name) return image; } +/* Remove the suffix, add a size, and re-add the suffix. */ +static char * +add_size_to_image_name (const char *name, guint size) +{ + const char *suffix; + char *name_without_suffix; + char *name_with_size; + + suffix = strrchr (name, '.'); + if (suffix == NULL) + return g_strdup_printf ("%s-%u", name, size); + + name_without_suffix = g_strndup (name, suffix - name); + name_with_size = g_strdup_printf ("%s-%u%s", name_without_suffix, size, suffix); + g_free (name_without_suffix); + return name_with_size; +} + /* Splats one on top of the other, putting the src image * in the lower left corner of the dest image. */ @@ -405,15 +442,7 @@ nautilus_icon_factory_load_icon (const char *name, gboolean is_symbolic_link) /* Load the image. */ image = nautilus_icon_factory_load_file (name); if (image == NULL) - /* This is the fallback icon. */ - image = gdk_pixbuf_new_from_data (nautilus_default_file_icon, - ART_PIX_RGB, - nautilus_default_file_icon_has_alpha, - nautilus_default_file_icon_width, - nautilus_default_file_icon_height, - nautilus_default_file_icon_width * 4, /* stride */ - NULL, /* don't destroy data */ - NULL); + return NULL; /* Overlay the symbolic link symbol on top of the image. */ if (is_symbolic_link) { @@ -561,51 +590,211 @@ nautilus_icon_factory_get_icon_for_file (NautilusFile *file) return scalable_icon; } +static guint +get_larger_icon_size (guint size) +{ + if (size < NAUTILUS_ICON_SIZE_SMALLEST) { + return NAUTILUS_ICON_SIZE_SMALLEST; + } + if (size < NAUTILUS_ICON_SIZE_SMALLER) { + return NAUTILUS_ICON_SIZE_SMALLER; + } + if (size < NAUTILUS_ICON_SIZE_SMALL) { + return NAUTILUS_ICON_SIZE_SMALL; + } + if (size < NAUTILUS_ICON_SIZE_STANDARD) { + return NAUTILUS_ICON_SIZE_STANDARD; + } + if (size < NAUTILUS_ICON_SIZE_LARGE) { + return NAUTILUS_ICON_SIZE_LARGE; + } + if (size < NAUTILUS_ICON_SIZE_LARGER) { + return NAUTILUS_ICON_SIZE_LARGER; + } + return NAUTILUS_ICON_SIZE_LARGEST; +} + +static guint +get_smaller_icon_size (guint size) +{ + if (size > NAUTILUS_ICON_SIZE_LARGEST) { + return NAUTILUS_ICON_SIZE_LARGEST; + } + if (size > NAUTILUS_ICON_SIZE_LARGER) { + return NAUTILUS_ICON_SIZE_LARGER; + } + if (size > NAUTILUS_ICON_SIZE_LARGE) { + return NAUTILUS_ICON_SIZE_LARGE; + } + if (size > NAUTILUS_ICON_SIZE_STANDARD) { + return NAUTILUS_ICON_SIZE_STANDARD; + } + if (size > NAUTILUS_ICON_SIZE_SMALL) { + return NAUTILUS_ICON_SIZE_SMALL; + } + if (size > NAUTILUS_ICON_SIZE_SMALLER) { + return NAUTILUS_ICON_SIZE_SMALLER; + } + return NAUTILUS_ICON_SIZE_SMALLEST; +} + +/* Return true if there is another size to try. + * Set the size pointed to by @current_size to 0 to start. + */ +static gboolean +get_next_icon_size_to_try (guint target_size, guint *current_size) +{ + guint size; + + /* Get next larger size. */ + size = *current_size; + if (size == 0 || size >= target_size) { + if (size == 0 && target_size != 0) { + size = target_size - 1; + } + if (size < NAUTILUS_ICON_SIZE_LARGEST) { + *current_size = get_larger_icon_size (size); + return TRUE; + } + size = target_size; + } + + /* Already hit the largest size, get the next smaller size instead. */ + if (size > NAUTILUS_ICON_SIZE_SMALLEST) { + *current_size = get_smaller_icon_size (size); + return TRUE; + } + + /* Tried them all. */ + return FALSE; +} + +/* This load function returns NULL if the icon is not available at this size. */ static GdkPixbuf * -nautilus_icon_factory_create_image_for_icon (NautilusScalableIcon *scalable_icon, - guint size_in_pixels) +load_specific_image (NautilusScalableIcon *scalable_icon, + guint size_in_pixels, + gboolean custom) { - NautilusIconFactory *factory; - GdkPixbuf *image, *standard_size_image; - - /* First cut at handling multiple sizes. If size is other than standard, - * scale the pixbuf here. Eventually we'll read in icon files at multiple - * sizes rather than relying on scaling in every case (though we'll still - * need scaling as a fallback). - */ - if (size_in_pixels != NAUTILUS_ICON_SIZE_STANDARD) - { - standard_size_image = nautilus_icon_factory_get_pixbuf_for_icon - (scalable_icon, NAUTILUS_ICON_SIZE_STANDARD); - image = nautilus_icon_factory_scale - (standard_size_image, size_in_pixels); - gdk_pixbuf_unref (standard_size_image); - return image; - } - - factory = nautilus_get_current_icon_factory (); + if (custom) { + /* Custom image. */ + if (size_in_pixels != NAUTILUS_ICON_SIZE_STANDARD) { + return NULL; + } - /* FIXME: This works only with file:// images, because there's - * no convenience function for loading an image with gnome-vfs - * and gdk-pixbuf. - */ - image = NULL; - if (nautilus_has_prefix (scalable_icon->uri, "file://")) - image = gdk_pixbuf_new_from_file (scalable_icon->uri + 7); - - /* If there was no suitable custom icon URI, then use the icon set. */ - if (image == NULL) + /* FIXME: This works only with file:// images, because there's + * no convenience function for loading an image with gnome-vfs + * and gdk-pixbuf. + */ + if (!nautilus_has_prefix (scalable_icon->uri, "file://")) { + return NULL; + } + + return gdk_pixbuf_new_from_file (scalable_icon->uri + 7); + } else { + char *name; + GdkPixbuf *image; + + /* Standard image at a particular size. */ + name = add_size_to_image_name (scalable_icon->name, size_in_pixels); image = nautilus_icon_factory_load_icon + (name, scalable_icon->is_symbolic_link); + if (image != NULL) + return image; + + /* Standard image at standard size. */ + if (size_in_pixels != NAUTILUS_ICON_SIZE_STANDARD) { + return NULL; + } + return nautilus_icon_factory_load_icon (scalable_icon->name, scalable_icon->is_symbolic_link); + } +} + +/* 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) +{ + GdkPixbuf *image; + guint actual_size; + static GdkPixbuf *fallback_image; + + /* First check for a custom image. */ + actual_size = 0; + while (get_next_icon_size_to_try (requested_size, &actual_size)) { + image = get_image_from_cache (scalable_icon, actual_size, TRUE, TRUE); + if (image != NULL) { + *actual_size_result = actual_size; + *custom = TRUE; + return image; + } + } - return image; + /* Next, go for the normal image. */ + actual_size = 0; + while (get_next_icon_size_to_try (requested_size, &actual_size)) { + image = get_image_from_cache (scalable_icon, actual_size, TRUE, FALSE); + if (image != NULL) { + *actual_size_result = actual_size; + *custom = FALSE; + return image; + } + } + + /* Finally, fall back on the hard-coded image. */ + if (fallback_image == NULL) + fallback_image = gdk_pixbuf_new_from_data + (nautilus_default_file_icon, + ART_PIX_RGB, + nautilus_default_file_icon_has_alpha, + nautilus_default_file_icon_width, + nautilus_default_file_icon_height, + nautilus_default_file_icon_width * 4, /* stride */ + NULL, /* don't destroy data */ + NULL); + gdk_pixbuf_ref (fallback_image); + *actual_size_result = NAUTILUS_ICON_SIZE_STANDARD; + *custom = FALSE; + return fallback_image; +} + +/* This load function is not allowed to return NULL. */ +static GdkPixbuf * +load_image_scale_if_necessary (NautilusScalableIcon *scalable_icon, + guint requested_size, + gboolean *scaled, + gboolean *custom) +{ + GdkPixbuf *image, *scaled_image; + guint actual_size; + int scaled_width, scaled_height; + + /* Load the image for the icon that's closest in size to what we want. */ + image = load_image_for_scaling (scalable_icon, requested_size, + &actual_size, custom); + if (requested_size == actual_size) { + *scaled = FALSE; + return image; + } + + /* Scale the image to the size we want. */ + scaled_width = (gdk_pixbuf_get_width (image) * requested_size) / actual_size; + scaled_height = (gdk_pixbuf_get_height (image) * requested_size) / actual_size; + scaled_image = gdk_pixbuf_scale_simple + (image, scaled_width, scaled_height, ART_FILTER_BILINEAR); + + gdk_pixbuf_unref (image); + *scaled = TRUE; + return scaled_image; } /* Move this item to the head of the recently-used list, * bumping the last item off that list if necessary. */ static void -nautilus_icon_factory_mark_recently_used (NautilusCircularList *node) +mark_recently_used (NautilusCircularList *node) { NautilusIconFactory *factory; NautilusCircularList *head, *last_node; @@ -648,9 +837,16 @@ nautilus_icon_factory_mark_recently_used (NautilusCircularList *node) } } -GdkPixbuf * -nautilus_icon_factory_get_pixbuf_for_icon (NautilusScalableIcon *scalable_icon, - guint size_in_pixels) +/* Get the image for 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, + guint size_in_pixels, + gboolean picky, + gboolean custom) { NautilusIconFactory *factory; GHashTable *hash_table; @@ -658,7 +854,7 @@ nautilus_icon_factory_get_pixbuf_for_icon (NautilusScalableIcon *scalable_icon, GdkPixbuf *image; gpointer key_in_table, value; - g_return_val_if_fail(scalable_icon, NULL); + g_return_val_if_fail (scalable_icon != NULL, NULL); factory = nautilus_get_current_icon_factory (); hash_table = factory->icon_cache; @@ -666,27 +862,52 @@ nautilus_icon_factory_get_pixbuf_for_icon (NautilusScalableIcon *scalable_icon, /* Check to see if it's already in the table. */ lookup_key.scalable_icon = scalable_icon; lookup_key.size_in_pixels = size_in_pixels; - if (g_hash_table_lookup_extended (hash_table, &lookup_key, &key_in_table, &value)) { + if (g_hash_table_lookup_extended (hash_table, &lookup_key, + &key_in_table, &value)) { /* Found it in the table. */ key = key_in_table; image = value; + g_assert (image != NULL); + + /* 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)) + return NULL; } else { - /* Not in the table, so create the image and put it in. */ - image = nautilus_icon_factory_create_image_for_icon - (scalable_icon, size_in_pixels); + gboolean got_scaled_image; + gboolean got_custom_image; + + /* Not in the table, so load the image. */ + if (picky) { + image = load_specific_image (scalable_icon, size_in_pixels, custom); + if (image == NULL) { + return NULL; + } + + got_scaled_image = FALSE; + got_custom_image = custom; + } else { + image = load_image_scale_if_necessary (scalable_icon, size_in_pixels, + &got_scaled_image, + &got_custom_image); + g_assert (image != NULL); + } /* Create the key for the table. */ key = g_new0 (NautilusIconCacheKey, 1); nautilus_scalable_icon_ref (scalable_icon); key->scalable_icon = scalable_icon; key->size_in_pixels = size_in_pixels; - + key->scaled = got_scaled_image; + key->custom = got_custom_image; + /* Add the item to the hash table. */ g_hash_table_insert (hash_table, key, image); } /* Since this item was used, keep it in the cache longer. */ - nautilus_icon_factory_mark_recently_used (&key->recently_used_node); + mark_recently_used (&key->recently_used_node); /* Come back later and sweep the cache. */ nautilus_icon_factory_schedule_sweep (); @@ -696,6 +917,14 @@ nautilus_icon_factory_get_pixbuf_for_icon (NautilusScalableIcon *scalable_icon, return image; } +GdkPixbuf * +nautilus_icon_factory_get_pixbuf_for_icon (NautilusScalableIcon *scalable_icon, + guint size_in_pixels) +{ + return get_image_from_cache (scalable_icon, size_in_pixels, + FALSE, FALSE); +} + static void nautilus_icon_cache_key_destroy (NautilusIconCacheKey *key) { @@ -723,24 +952,6 @@ nautilus_icon_cache_key_equal (gconstpointer a, gconstpointer b) && key_a->size_in_pixels == key_b->size_in_pixels; } -static GdkPixbuf * -nautilus_icon_factory_scale (GdkPixbuf *standard_sized_image, - guint size_in_pixels) -{ - int old_width, old_height, new_width, new_height; - - old_width = gdk_pixbuf_get_width (standard_sized_image); - old_height = gdk_pixbuf_get_height (standard_sized_image); - - new_width = (old_width * size_in_pixels) / NAUTILUS_ICON_SIZE_STANDARD; - new_height = (old_height * size_in_pixels) / NAUTILUS_ICON_SIZE_STANDARD; - - return gdk_pixbuf_scale_simple (standard_sized_image, - new_width, - new_height, - ART_FILTER_BILINEAR); -} - /* Return nominal icon size for given zoom level. * @zoom_level: zoom level for which to find matching icon size. * @@ -781,6 +992,8 @@ nautilus_icon_factory_get_pixbuf_for_file (NautilusFile *file, NautilusScalableIcon *icon; GdkPixbuf *pixbuf; + g_return_val_if_fail (file != NULL, NULL); + icon = nautilus_icon_factory_get_icon_for_file (file); pixbuf = nautilus_icon_factory_get_pixbuf_for_icon (icon, size_in_pixels); nautilus_scalable_icon_unref (icon); @@ -799,13 +1012,117 @@ nautilus_icon_factory_get_pixmap_and_mask_for_file (NautilusFile *file, { GdkPixbuf *pixbuf; - if(!file) { - *pixmap = NULL; - *mask = NULL; - } - g_return_if_fail(file); + g_return_if_fail (pixmap != NULL); + g_return_if_fail (mask != NULL); + + *pixmap = NULL; + *mask = NULL; + + g_return_if_fail (file != NULL); pixbuf = nautilus_icon_factory_get_pixbuf_for_file (file, size_in_pixels); gdk_pixbuf_render_pixmap_and_mask (pixbuf, pixmap, mask, 128); gdk_pixbuf_unref (pixbuf); } + +#if ! defined (NAUTILUS_OMIT_SELF_CHECK) + +static char * +self_test_next_icon_size_to_try (guint start_size, guint current_size) +{ + gboolean got_next_size; + + got_next_size = get_next_icon_size_to_try (start_size, ¤t_size); + return g_strdup_printf ("%s,%d", got_next_size ? "TRUE" : "FALSE", current_size); +} + +void +nautilus_self_check_icon_factory (void) +{ + NAUTILUS_CHECK_INTEGER_RESULT (nautilus_get_icon_size_for_zoom_level (0), 12); + NAUTILUS_CHECK_INTEGER_RESULT (nautilus_get_icon_size_for_zoom_level (1), 24); + NAUTILUS_CHECK_INTEGER_RESULT (nautilus_get_icon_size_for_zoom_level (2), 36); + NAUTILUS_CHECK_INTEGER_RESULT (nautilus_get_icon_size_for_zoom_level (3), 48); + NAUTILUS_CHECK_INTEGER_RESULT (nautilus_get_icon_size_for_zoom_level (4), 72); + NAUTILUS_CHECK_INTEGER_RESULT (nautilus_get_icon_size_for_zoom_level (5), 96); + NAUTILUS_CHECK_INTEGER_RESULT (nautilus_get_icon_size_for_zoom_level (6), 192); + + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (0), 12); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (1), 12); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (11), 12); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (12), 24); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (23), 24); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (24), 36); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (35), 36); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (36), 48); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (47), 48); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (48), 72); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (71), 72); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (72), 96); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (95), 96); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (96), 192); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (191), 192); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (192), 192); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (0xFFFFFFFF), 192); + + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (0), 12); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (1), 12); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (11), 12); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (12), 12); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (24), 12); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (25), 24); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (36), 24); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (37), 36); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (48), 36); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (49), 48); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (72), 48); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (73), 72); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (96), 72); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (97), 96); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (192), 96); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (193), 192); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (0xFFFFFFFF), 192); + + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0, 0), "TRUE,12"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0, 12), "TRUE,24"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0, 24), "TRUE,36"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0, 36), "TRUE,48"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0, 48), "TRUE,72"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0, 72), "TRUE,96"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0, 96), "TRUE,192"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0, 192), "FALSE,192"); + + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (36, 0), "TRUE,36"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (36, 36), "TRUE,48"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (36, 48), "TRUE,72"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (36, 72), "TRUE,96"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (36, 96), "TRUE,192"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (36, 192), "TRUE,24"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (36, 24), "TRUE,12"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (36, 12), "FALSE,12"); + + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (37, 0), "TRUE,48"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (37, 48), "TRUE,72"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (37, 72), "TRUE,96"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (37, 96), "TRUE,192"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (37, 192), "TRUE,36"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (37, 36), "TRUE,24"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (37, 24), "TRUE,12"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (37, 12), "FALSE,12"); + + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0xFFFFFFFF, 0), "TRUE,192"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0xFFFFFFFF, 192), "TRUE,96"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0xFFFFFFFF, 96), "TRUE,72"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0xFFFFFFFF, 72), "TRUE,48"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0xFFFFFFFF, 48), "TRUE,36"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0xFFFFFFFF, 36), "TRUE,24"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0xFFFFFFFF, 24), "TRUE,12"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0xFFFFFFFF, 12), "FALSE,12"); + + NAUTILUS_CHECK_STRING_RESULT (add_size_to_image_name ("", 0), "-0"); + NAUTILUS_CHECK_STRING_RESULT (add_size_to_image_name (".", 0), "-0."); + NAUTILUS_CHECK_STRING_RESULT (add_size_to_image_name ("a", 12), "a-12"); + NAUTILUS_CHECK_STRING_RESULT (add_size_to_image_name ("a.png", 12), "a-12.png"); +} + +#endif /* ! NAUTILUS_OMIT_SELF_CHECK */ diff --git a/libnautilus-private/nautilus-lib-self-check-functions.h b/libnautilus-private/nautilus-lib-self-check-functions.h index 4a51d24df..287479c00 100644 --- a/libnautilus-private/nautilus-lib-self-check-functions.h +++ b/libnautilus-private/nautilus-lib-self-check-functions.h @@ -44,6 +44,7 @@ void nautilus_run_lib_self_checks (void); macro (nautilus_self_check_gdk_extensions) \ macro (nautilus_self_check_glib_extensions) \ macro (nautilus_self_check_gnome_icon_container) \ + macro (nautilus_self_check_icon_factory) \ macro (nautilus_self_check_string) \ /* Add new self-check functions to the list above this line. */ diff --git a/libnautilus-private/nautilus-string.c b/libnautilus-private/nautilus-string.c index 281eea2d1..9b403cada 100644 --- a/libnautilus-private/nautilus-string.c +++ b/libnautilus-private/nautilus-string.c @@ -92,9 +92,9 @@ nautilus_string_to_int (const char *string, int *integer) result = strtol (string, &parse_end, 0); /* Check that the result is in range. */ - if ((result == LONG_MIN || result == LONG_MAX) && errno == ERANGE) + if ((result == G_MINLONG || result == G_MAXLONG) && errno == ERANGE) return FALSE; - if (result < INT_MIN || result > INT_MAX) + if (result < G_MININT || result > G_MAXINT) return FALSE; /* Check that all the trailing characters are spaces. */ diff --git a/libnautilus/nautilus-directory.c b/libnautilus/nautilus-directory.c index 703ce6032..56a028efd 100644 --- a/libnautilus/nautilus-directory.c +++ b/libnautilus/nautilus-directory.c @@ -296,7 +296,7 @@ nautilus_directory_try_to_read_metafile (NautilusDirectory *directory, GnomeVFSU if (result == GNOME_VFS_OK) { /* Check for the case where the info doesn't give the file size. */ - if ((metafile_info.flags & GNOME_VFS_FILE_INFO_FIELDS_SIZE) == 0) + if ((metafile_info.valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) == 0) result = GNOME_VFS_ERROR_GENERIC; } @@ -534,7 +534,7 @@ nautilus_make_directory_and_parents (GnomeVFSURI *uri, guint permissions) } static GnomeVFSURI * -nautilus_directory_construct_alternate_metafile_uri (GnomeVFSURI *metafile_uri) +nautilus_directory_construct_alternate_metafile_uri (GnomeVFSURI *uri) { GnomeVFSResult result; GnomeVFSURI *home_uri, *nautilus_directory_uri, *metafiles_directory_uri, *alternate_uri; @@ -553,8 +553,7 @@ nautilus_directory_construct_alternate_metafile_uri (GnomeVFSURI *metafile_uri) } /* Construct a file name from the URI. */ - uri_as_string = gnome_vfs_uri_to_string (metafile_uri, - GNOME_VFS_URI_HIDE_NONE); + uri_as_string = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_NONE); escaped_uri = nautilus_directory_escape_slashes (uri_as_string); g_free (uri_as_string); file_name = g_strconcat (escaped_uri, ".xml", NULL); @@ -594,7 +593,7 @@ nautilus_directory_new (const char* uri) return NULL; metafile_uri = gnome_vfs_uri_append_path (vfs_uri, METAFILE_NAME); - alternate_metafile_uri = nautilus_directory_construct_alternate_metafile_uri (metafile_uri); + alternate_metafile_uri = nautilus_directory_construct_alternate_metafile_uri (vfs_uri); directory = gtk_type_new (NAUTILUS_TYPE_DIRECTORY); @@ -1155,7 +1154,7 @@ nautilus_file_ref (NautilusFile *file) { g_return_if_fail (file != NULL); - g_assert (file->ref_count < UINT_MAX); + g_assert (file->ref_count < G_MAXINT); g_assert (file->directory != NULL); /* Increment the ref count. */ diff --git a/libnautilus/nautilus-glib-extensions.c b/libnautilus/nautilus-glib-extensions.c index c17cc3aa6..7a3a019be 100644 --- a/libnautilus/nautilus-glib-extensions.c +++ b/libnautilus/nautilus-glib-extensions.c @@ -68,7 +68,7 @@ nautilus_strdup_strftime (const char *format, struct tm *time_pieces) char *result; size_t string_length; - string_length = strftime (NULL, UINT_MAX, format, time_pieces); + string_length = strftime (NULL, G_MAXINT, format, time_pieces); result = g_malloc (string_length + 1); strftime (result, string_length + 1, format, time_pieces); diff --git a/libnautilus/nautilus-icon-factory.c b/libnautilus/nautilus-icon-factory.c index 39341f54b..f046b1329 100644 --- a/libnautilus/nautilus-icon-factory.c +++ b/libnautilus/nautilus-icon-factory.c @@ -36,6 +36,7 @@ #include "nautilus-string.h" #include "nautilus-default-file-icon.h" #include "nautilus-metadata.h" +#include "nautilus-lib-self-check-functions.h" #define ICON_NAME_DIRECTORY "i-directory.png" #define ICON_NAME_DIRECTORY_CLOSED "i-dirclosed.png" @@ -94,7 +95,7 @@ typedef struct { * A circular list of the most recently used images is kept * around, and we don't let them go when we sweep the cache. */ - GHashTable *icon_cache; + GHashTable *icon_cache; NautilusCircularList recently_used_dummy_head; guint recently_used_count; guint sweep_timer; @@ -118,20 +119,23 @@ struct _NautilusScalableIcon { }; /* 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. */ typedef struct { NautilusScalableIcon *scalable_icon; guint size_in_pixels; NautilusCircularList recently_used_node; + + gboolean custom; + gboolean scaled; } NautilusIconCacheKey; /* forward declarations */ static NautilusIconFactory * nautilus_get_current_icon_factory (void); static NautilusIconFactory * nautilus_icon_factory_new (const char *theme_name); -static GdkPixbuf * nautilus_icon_factory_scale (GdkPixbuf *standard_sized_image, - guint size_in_pixels); static NautilusScalableIcon *nautilus_scalable_icon_get (const char *uri, const char *name, gboolean is_symbolic_link); @@ -142,6 +146,10 @@ static void nautilus_icon_cache_key_destroy (NautilusIconCach static guint nautilus_icon_cache_key_hash (gconstpointer p); static gboolean nautilus_icon_cache_key_equal (gconstpointer a, gconstpointer b); +static GdkPixbuf * get_image_from_cache (NautilusScalableIcon *scalable_icon, + guint size_in_pixels, + gboolean picky, + gboolean custom); /* Return a pointer to the single global icon factory. */ NautilusIconFactory * @@ -295,19 +303,30 @@ nautilus_icon_factory_set_theme (const char *theme_name) static const char * nautilus_icon_factory_get_icon_name_for_regular_file (NautilusFile *file) { + char *file_name; + gboolean is_core; const char *mime_type; const char *icon_name; + file_name = nautilus_file_get_name (file); + is_core = strcmp (file_name, "core") == 0; + g_free (file_name); + if (is_core) { + return ICON_NAME_CORE; + } + mime_type = nautilus_file_get_mime_type (file); if (mime_type != NULL) { icon_name = gnome_mime_get_value (mime_type, "icon-filename"); - if (icon_name != NULL) + if (icon_name != NULL) { return icon_name; + } } /* GNOME didn't give us a file name, so we have to fall back on special icon sets. */ - if (nautilus_file_is_executable (file)) + if (nautilus_file_is_executable (file)) { return ICON_NAME_EXECUTABLE; + } return ICON_NAME_REGULAR; } @@ -377,6 +396,24 @@ nautilus_icon_factory_load_file (const char *name) return image; } +/* Remove the suffix, add a size, and re-add the suffix. */ +static char * +add_size_to_image_name (const char *name, guint size) +{ + const char *suffix; + char *name_without_suffix; + char *name_with_size; + + suffix = strrchr (name, '.'); + if (suffix == NULL) + return g_strdup_printf ("%s-%u", name, size); + + name_without_suffix = g_strndup (name, suffix - name); + name_with_size = g_strdup_printf ("%s-%u%s", name_without_suffix, size, suffix); + g_free (name_without_suffix); + return name_with_size; +} + /* Splats one on top of the other, putting the src image * in the lower left corner of the dest image. */ @@ -405,15 +442,7 @@ nautilus_icon_factory_load_icon (const char *name, gboolean is_symbolic_link) /* Load the image. */ image = nautilus_icon_factory_load_file (name); if (image == NULL) - /* This is the fallback icon. */ - image = gdk_pixbuf_new_from_data (nautilus_default_file_icon, - ART_PIX_RGB, - nautilus_default_file_icon_has_alpha, - nautilus_default_file_icon_width, - nautilus_default_file_icon_height, - nautilus_default_file_icon_width * 4, /* stride */ - NULL, /* don't destroy data */ - NULL); + return NULL; /* Overlay the symbolic link symbol on top of the image. */ if (is_symbolic_link) { @@ -561,51 +590,211 @@ nautilus_icon_factory_get_icon_for_file (NautilusFile *file) return scalable_icon; } +static guint +get_larger_icon_size (guint size) +{ + if (size < NAUTILUS_ICON_SIZE_SMALLEST) { + return NAUTILUS_ICON_SIZE_SMALLEST; + } + if (size < NAUTILUS_ICON_SIZE_SMALLER) { + return NAUTILUS_ICON_SIZE_SMALLER; + } + if (size < NAUTILUS_ICON_SIZE_SMALL) { + return NAUTILUS_ICON_SIZE_SMALL; + } + if (size < NAUTILUS_ICON_SIZE_STANDARD) { + return NAUTILUS_ICON_SIZE_STANDARD; + } + if (size < NAUTILUS_ICON_SIZE_LARGE) { + return NAUTILUS_ICON_SIZE_LARGE; + } + if (size < NAUTILUS_ICON_SIZE_LARGER) { + return NAUTILUS_ICON_SIZE_LARGER; + } + return NAUTILUS_ICON_SIZE_LARGEST; +} + +static guint +get_smaller_icon_size (guint size) +{ + if (size > NAUTILUS_ICON_SIZE_LARGEST) { + return NAUTILUS_ICON_SIZE_LARGEST; + } + if (size > NAUTILUS_ICON_SIZE_LARGER) { + return NAUTILUS_ICON_SIZE_LARGER; + } + if (size > NAUTILUS_ICON_SIZE_LARGE) { + return NAUTILUS_ICON_SIZE_LARGE; + } + if (size > NAUTILUS_ICON_SIZE_STANDARD) { + return NAUTILUS_ICON_SIZE_STANDARD; + } + if (size > NAUTILUS_ICON_SIZE_SMALL) { + return NAUTILUS_ICON_SIZE_SMALL; + } + if (size > NAUTILUS_ICON_SIZE_SMALLER) { + return NAUTILUS_ICON_SIZE_SMALLER; + } + return NAUTILUS_ICON_SIZE_SMALLEST; +} + +/* Return true if there is another size to try. + * Set the size pointed to by @current_size to 0 to start. + */ +static gboolean +get_next_icon_size_to_try (guint target_size, guint *current_size) +{ + guint size; + + /* Get next larger size. */ + size = *current_size; + if (size == 0 || size >= target_size) { + if (size == 0 && target_size != 0) { + size = target_size - 1; + } + if (size < NAUTILUS_ICON_SIZE_LARGEST) { + *current_size = get_larger_icon_size (size); + return TRUE; + } + size = target_size; + } + + /* Already hit the largest size, get the next smaller size instead. */ + if (size > NAUTILUS_ICON_SIZE_SMALLEST) { + *current_size = get_smaller_icon_size (size); + return TRUE; + } + + /* Tried them all. */ + return FALSE; +} + +/* This load function returns NULL if the icon is not available at this size. */ static GdkPixbuf * -nautilus_icon_factory_create_image_for_icon (NautilusScalableIcon *scalable_icon, - guint size_in_pixels) +load_specific_image (NautilusScalableIcon *scalable_icon, + guint size_in_pixels, + gboolean custom) { - NautilusIconFactory *factory; - GdkPixbuf *image, *standard_size_image; - - /* First cut at handling multiple sizes. If size is other than standard, - * scale the pixbuf here. Eventually we'll read in icon files at multiple - * sizes rather than relying on scaling in every case (though we'll still - * need scaling as a fallback). - */ - if (size_in_pixels != NAUTILUS_ICON_SIZE_STANDARD) - { - standard_size_image = nautilus_icon_factory_get_pixbuf_for_icon - (scalable_icon, NAUTILUS_ICON_SIZE_STANDARD); - image = nautilus_icon_factory_scale - (standard_size_image, size_in_pixels); - gdk_pixbuf_unref (standard_size_image); - return image; - } - - factory = nautilus_get_current_icon_factory (); + if (custom) { + /* Custom image. */ + if (size_in_pixels != NAUTILUS_ICON_SIZE_STANDARD) { + return NULL; + } - /* FIXME: This works only with file:// images, because there's - * no convenience function for loading an image with gnome-vfs - * and gdk-pixbuf. - */ - image = NULL; - if (nautilus_has_prefix (scalable_icon->uri, "file://")) - image = gdk_pixbuf_new_from_file (scalable_icon->uri + 7); - - /* If there was no suitable custom icon URI, then use the icon set. */ - if (image == NULL) + /* FIXME: This works only with file:// images, because there's + * no convenience function for loading an image with gnome-vfs + * and gdk-pixbuf. + */ + if (!nautilus_has_prefix (scalable_icon->uri, "file://")) { + return NULL; + } + + return gdk_pixbuf_new_from_file (scalable_icon->uri + 7); + } else { + char *name; + GdkPixbuf *image; + + /* Standard image at a particular size. */ + name = add_size_to_image_name (scalable_icon->name, size_in_pixels); image = nautilus_icon_factory_load_icon + (name, scalable_icon->is_symbolic_link); + if (image != NULL) + return image; + + /* Standard image at standard size. */ + if (size_in_pixels != NAUTILUS_ICON_SIZE_STANDARD) { + return NULL; + } + return nautilus_icon_factory_load_icon (scalable_icon->name, scalable_icon->is_symbolic_link); + } +} + +/* 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) +{ + GdkPixbuf *image; + guint actual_size; + static GdkPixbuf *fallback_image; + + /* First check for a custom image. */ + actual_size = 0; + while (get_next_icon_size_to_try (requested_size, &actual_size)) { + image = get_image_from_cache (scalable_icon, actual_size, TRUE, TRUE); + if (image != NULL) { + *actual_size_result = actual_size; + *custom = TRUE; + return image; + } + } - return image; + /* Next, go for the normal image. */ + actual_size = 0; + while (get_next_icon_size_to_try (requested_size, &actual_size)) { + image = get_image_from_cache (scalable_icon, actual_size, TRUE, FALSE); + if (image != NULL) { + *actual_size_result = actual_size; + *custom = FALSE; + return image; + } + } + + /* Finally, fall back on the hard-coded image. */ + if (fallback_image == NULL) + fallback_image = gdk_pixbuf_new_from_data + (nautilus_default_file_icon, + ART_PIX_RGB, + nautilus_default_file_icon_has_alpha, + nautilus_default_file_icon_width, + nautilus_default_file_icon_height, + nautilus_default_file_icon_width * 4, /* stride */ + NULL, /* don't destroy data */ + NULL); + gdk_pixbuf_ref (fallback_image); + *actual_size_result = NAUTILUS_ICON_SIZE_STANDARD; + *custom = FALSE; + return fallback_image; +} + +/* This load function is not allowed to return NULL. */ +static GdkPixbuf * +load_image_scale_if_necessary (NautilusScalableIcon *scalable_icon, + guint requested_size, + gboolean *scaled, + gboolean *custom) +{ + GdkPixbuf *image, *scaled_image; + guint actual_size; + int scaled_width, scaled_height; + + /* Load the image for the icon that's closest in size to what we want. */ + image = load_image_for_scaling (scalable_icon, requested_size, + &actual_size, custom); + if (requested_size == actual_size) { + *scaled = FALSE; + return image; + } + + /* Scale the image to the size we want. */ + scaled_width = (gdk_pixbuf_get_width (image) * requested_size) / actual_size; + scaled_height = (gdk_pixbuf_get_height (image) * requested_size) / actual_size; + scaled_image = gdk_pixbuf_scale_simple + (image, scaled_width, scaled_height, ART_FILTER_BILINEAR); + + gdk_pixbuf_unref (image); + *scaled = TRUE; + return scaled_image; } /* Move this item to the head of the recently-used list, * bumping the last item off that list if necessary. */ static void -nautilus_icon_factory_mark_recently_used (NautilusCircularList *node) +mark_recently_used (NautilusCircularList *node) { NautilusIconFactory *factory; NautilusCircularList *head, *last_node; @@ -648,9 +837,16 @@ nautilus_icon_factory_mark_recently_used (NautilusCircularList *node) } } -GdkPixbuf * -nautilus_icon_factory_get_pixbuf_for_icon (NautilusScalableIcon *scalable_icon, - guint size_in_pixels) +/* Get the image for 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, + guint size_in_pixels, + gboolean picky, + gboolean custom) { NautilusIconFactory *factory; GHashTable *hash_table; @@ -658,7 +854,7 @@ nautilus_icon_factory_get_pixbuf_for_icon (NautilusScalableIcon *scalable_icon, GdkPixbuf *image; gpointer key_in_table, value; - g_return_val_if_fail(scalable_icon, NULL); + g_return_val_if_fail (scalable_icon != NULL, NULL); factory = nautilus_get_current_icon_factory (); hash_table = factory->icon_cache; @@ -666,27 +862,52 @@ nautilus_icon_factory_get_pixbuf_for_icon (NautilusScalableIcon *scalable_icon, /* Check to see if it's already in the table. */ lookup_key.scalable_icon = scalable_icon; lookup_key.size_in_pixels = size_in_pixels; - if (g_hash_table_lookup_extended (hash_table, &lookup_key, &key_in_table, &value)) { + if (g_hash_table_lookup_extended (hash_table, &lookup_key, + &key_in_table, &value)) { /* Found it in the table. */ key = key_in_table; image = value; + g_assert (image != NULL); + + /* 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)) + return NULL; } else { - /* Not in the table, so create the image and put it in. */ - image = nautilus_icon_factory_create_image_for_icon - (scalable_icon, size_in_pixels); + gboolean got_scaled_image; + gboolean got_custom_image; + + /* Not in the table, so load the image. */ + if (picky) { + image = load_specific_image (scalable_icon, size_in_pixels, custom); + if (image == NULL) { + return NULL; + } + + got_scaled_image = FALSE; + got_custom_image = custom; + } else { + image = load_image_scale_if_necessary (scalable_icon, size_in_pixels, + &got_scaled_image, + &got_custom_image); + g_assert (image != NULL); + } /* Create the key for the table. */ key = g_new0 (NautilusIconCacheKey, 1); nautilus_scalable_icon_ref (scalable_icon); key->scalable_icon = scalable_icon; key->size_in_pixels = size_in_pixels; - + key->scaled = got_scaled_image; + key->custom = got_custom_image; + /* Add the item to the hash table. */ g_hash_table_insert (hash_table, key, image); } /* Since this item was used, keep it in the cache longer. */ - nautilus_icon_factory_mark_recently_used (&key->recently_used_node); + mark_recently_used (&key->recently_used_node); /* Come back later and sweep the cache. */ nautilus_icon_factory_schedule_sweep (); @@ -696,6 +917,14 @@ nautilus_icon_factory_get_pixbuf_for_icon (NautilusScalableIcon *scalable_icon, return image; } +GdkPixbuf * +nautilus_icon_factory_get_pixbuf_for_icon (NautilusScalableIcon *scalable_icon, + guint size_in_pixels) +{ + return get_image_from_cache (scalable_icon, size_in_pixels, + FALSE, FALSE); +} + static void nautilus_icon_cache_key_destroy (NautilusIconCacheKey *key) { @@ -723,24 +952,6 @@ nautilus_icon_cache_key_equal (gconstpointer a, gconstpointer b) && key_a->size_in_pixels == key_b->size_in_pixels; } -static GdkPixbuf * -nautilus_icon_factory_scale (GdkPixbuf *standard_sized_image, - guint size_in_pixels) -{ - int old_width, old_height, new_width, new_height; - - old_width = gdk_pixbuf_get_width (standard_sized_image); - old_height = gdk_pixbuf_get_height (standard_sized_image); - - new_width = (old_width * size_in_pixels) / NAUTILUS_ICON_SIZE_STANDARD; - new_height = (old_height * size_in_pixels) / NAUTILUS_ICON_SIZE_STANDARD; - - return gdk_pixbuf_scale_simple (standard_sized_image, - new_width, - new_height, - ART_FILTER_BILINEAR); -} - /* Return nominal icon size for given zoom level. * @zoom_level: zoom level for which to find matching icon size. * @@ -781,6 +992,8 @@ nautilus_icon_factory_get_pixbuf_for_file (NautilusFile *file, NautilusScalableIcon *icon; GdkPixbuf *pixbuf; + g_return_val_if_fail (file != NULL, NULL); + icon = nautilus_icon_factory_get_icon_for_file (file); pixbuf = nautilus_icon_factory_get_pixbuf_for_icon (icon, size_in_pixels); nautilus_scalable_icon_unref (icon); @@ -799,13 +1012,117 @@ nautilus_icon_factory_get_pixmap_and_mask_for_file (NautilusFile *file, { GdkPixbuf *pixbuf; - if(!file) { - *pixmap = NULL; - *mask = NULL; - } - g_return_if_fail(file); + g_return_if_fail (pixmap != NULL); + g_return_if_fail (mask != NULL); + + *pixmap = NULL; + *mask = NULL; + + g_return_if_fail (file != NULL); pixbuf = nautilus_icon_factory_get_pixbuf_for_file (file, size_in_pixels); gdk_pixbuf_render_pixmap_and_mask (pixbuf, pixmap, mask, 128); gdk_pixbuf_unref (pixbuf); } + +#if ! defined (NAUTILUS_OMIT_SELF_CHECK) + +static char * +self_test_next_icon_size_to_try (guint start_size, guint current_size) +{ + gboolean got_next_size; + + got_next_size = get_next_icon_size_to_try (start_size, ¤t_size); + return g_strdup_printf ("%s,%d", got_next_size ? "TRUE" : "FALSE", current_size); +} + +void +nautilus_self_check_icon_factory (void) +{ + NAUTILUS_CHECK_INTEGER_RESULT (nautilus_get_icon_size_for_zoom_level (0), 12); + NAUTILUS_CHECK_INTEGER_RESULT (nautilus_get_icon_size_for_zoom_level (1), 24); + NAUTILUS_CHECK_INTEGER_RESULT (nautilus_get_icon_size_for_zoom_level (2), 36); + NAUTILUS_CHECK_INTEGER_RESULT (nautilus_get_icon_size_for_zoom_level (3), 48); + NAUTILUS_CHECK_INTEGER_RESULT (nautilus_get_icon_size_for_zoom_level (4), 72); + NAUTILUS_CHECK_INTEGER_RESULT (nautilus_get_icon_size_for_zoom_level (5), 96); + NAUTILUS_CHECK_INTEGER_RESULT (nautilus_get_icon_size_for_zoom_level (6), 192); + + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (0), 12); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (1), 12); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (11), 12); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (12), 24); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (23), 24); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (24), 36); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (35), 36); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (36), 48); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (47), 48); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (48), 72); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (71), 72); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (72), 96); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (95), 96); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (96), 192); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (191), 192); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (192), 192); + NAUTILUS_CHECK_INTEGER_RESULT (get_larger_icon_size (0xFFFFFFFF), 192); + + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (0), 12); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (1), 12); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (11), 12); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (12), 12); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (24), 12); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (25), 24); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (36), 24); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (37), 36); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (48), 36); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (49), 48); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (72), 48); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (73), 72); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (96), 72); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (97), 96); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (192), 96); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (193), 192); + NAUTILUS_CHECK_INTEGER_RESULT (get_smaller_icon_size (0xFFFFFFFF), 192); + + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0, 0), "TRUE,12"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0, 12), "TRUE,24"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0, 24), "TRUE,36"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0, 36), "TRUE,48"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0, 48), "TRUE,72"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0, 72), "TRUE,96"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0, 96), "TRUE,192"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0, 192), "FALSE,192"); + + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (36, 0), "TRUE,36"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (36, 36), "TRUE,48"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (36, 48), "TRUE,72"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (36, 72), "TRUE,96"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (36, 96), "TRUE,192"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (36, 192), "TRUE,24"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (36, 24), "TRUE,12"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (36, 12), "FALSE,12"); + + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (37, 0), "TRUE,48"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (37, 48), "TRUE,72"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (37, 72), "TRUE,96"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (37, 96), "TRUE,192"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (37, 192), "TRUE,36"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (37, 36), "TRUE,24"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (37, 24), "TRUE,12"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (37, 12), "FALSE,12"); + + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0xFFFFFFFF, 0), "TRUE,192"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0xFFFFFFFF, 192), "TRUE,96"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0xFFFFFFFF, 96), "TRUE,72"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0xFFFFFFFF, 72), "TRUE,48"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0xFFFFFFFF, 48), "TRUE,36"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0xFFFFFFFF, 36), "TRUE,24"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0xFFFFFFFF, 24), "TRUE,12"); + NAUTILUS_CHECK_STRING_RESULT (self_test_next_icon_size_to_try (0xFFFFFFFF, 12), "FALSE,12"); + + NAUTILUS_CHECK_STRING_RESULT (add_size_to_image_name ("", 0), "-0"); + NAUTILUS_CHECK_STRING_RESULT (add_size_to_image_name (".", 0), "-0."); + NAUTILUS_CHECK_STRING_RESULT (add_size_to_image_name ("a", 12), "a-12"); + NAUTILUS_CHECK_STRING_RESULT (add_size_to_image_name ("a.png", 12), "a-12.png"); +} + +#endif /* ! NAUTILUS_OMIT_SELF_CHECK */ diff --git a/libnautilus/nautilus-lib-self-check-functions.h b/libnautilus/nautilus-lib-self-check-functions.h index 4a51d24df..287479c00 100644 --- a/libnautilus/nautilus-lib-self-check-functions.h +++ b/libnautilus/nautilus-lib-self-check-functions.h @@ -44,6 +44,7 @@ void nautilus_run_lib_self_checks (void); macro (nautilus_self_check_gdk_extensions) \ macro (nautilus_self_check_glib_extensions) \ macro (nautilus_self_check_gnome_icon_container) \ + macro (nautilus_self_check_icon_factory) \ macro (nautilus_self_check_string) \ /* Add new self-check functions to the list above this line. */ diff --git a/libnautilus/nautilus-string.c b/libnautilus/nautilus-string.c index 281eea2d1..9b403cada 100644 --- a/libnautilus/nautilus-string.c +++ b/libnautilus/nautilus-string.c @@ -92,9 +92,9 @@ nautilus_string_to_int (const char *string, int *integer) result = strtol (string, &parse_end, 0); /* Check that the result is in range. */ - if ((result == LONG_MIN || result == LONG_MAX) && errno == ERANGE) + if ((result == G_MINLONG || result == G_MAXLONG) && errno == ERANGE) return FALSE; - if (result < INT_MIN || result > INT_MAX) + if (result < G_MININT || result > G_MAXINT) return FALSE; /* Check that all the trailing characters are spaces. */ diff --git a/src/file-manager/fm-directory-view.c b/src/file-manager/fm-directory-view.c index 9e8004e8d..210036bc7 100644 --- a/src/file-manager/fm-directory-view.c +++ b/src/file-manager/fm-directory-view.c @@ -393,17 +393,23 @@ select_all_cb(GtkMenuItem *item, FMDirectoryView *directory_view) /* handle the zoom in/out menu items */ static void -zoom_in_cb(GtkMenuItem *item, FMDirectoryView *directory_view) +zoom_in_cb (GtkMenuItem *item, FMDirectoryView *directory_view) { fm_directory_view_bump_zoom_level (directory_view, 1); } static void -zoom_out_cb(GtkMenuItem *item, FMDirectoryView *directory_view) +zoom_out_cb (GtkMenuItem *item, FMDirectoryView *directory_view) { fm_directory_view_bump_zoom_level (directory_view, -1); } +static void +use_eazel_theme_icons_cb (GtkMenuItem *item, FMDirectoryView *directory_view) +{ + /* FIXME: This isn't implemented yet. */ +} + static gboolean display_pending_files (FMDirectoryView *view) { @@ -788,36 +794,29 @@ open_in_new_window_cb (GtkMenuItem *item, NautilusFile *file) fm_directory_view_activate_entry (directory_view, file, TRUE); } - static void -fm_directory_view_real_append_background_context_menu_items (FMDirectoryView *view, - GtkMenu *menu) +add_menu_item (FMDirectoryView *view, GtkMenu *menu, const char *label, + void (*activate_handler) (GtkMenuItem *, FMDirectoryView *), + gboolean sensitive) { GtkWidget *menu_item; - menu_item = gtk_menu_item_new_with_label ("Select all"); + menu_item = gtk_menu_item_new_with_label (label); + gtk_signal_connect (GTK_OBJECT (menu_item), "activate", + GTK_SIGNAL_FUNC (activate_handler), view); + gtk_widget_set_sensitive (menu_item, sensitive); gtk_widget_show (menu_item); - gtk_signal_connect(GTK_OBJECT (menu_item), "activate", - GTK_SIGNAL_FUNC (select_all_cb), view); gtk_menu_append (menu, menu_item); +} - - menu_item = gtk_menu_item_new_with_label ("Zoom in"); - gtk_signal_connect(GTK_OBJECT (menu_item), "activate", - GTK_SIGNAL_FUNC (zoom_in_cb), view); - - gtk_widget_show (menu_item); - gtk_menu_append (menu, menu_item); - gtk_widget_set_sensitive (menu_item, fm_directory_view_can_zoom_in (view)); - - menu_item = gtk_menu_item_new_with_label ("Zoom out"); - - gtk_signal_connect(GTK_OBJECT (menu_item), "activate", - GTK_SIGNAL_FUNC (zoom_out_cb), view); - - gtk_widget_show (menu_item); - gtk_menu_append (menu, menu_item); - gtk_widget_set_sensitive (menu_item, fm_directory_view_can_zoom_out (view)); +static void +fm_directory_view_real_append_background_context_menu_items (FMDirectoryView *view, + GtkMenu *menu) +{ + add_menu_item (view, menu, _("Select All"), select_all_cb, TRUE); + add_menu_item (view, menu, _("Zoom In"), zoom_in_cb, fm_directory_view_can_zoom_in (view)); + add_menu_item (view, menu, _("Zoom Out"), zoom_out_cb, fm_directory_view_can_zoom_out (view)); + add_menu_item (view, menu, _("Use Eazel Theme Icons"), use_eazel_theme_icons_cb, FALSE); } static void diff --git a/src/nautilus-index-title.c b/src/nautilus-index-title.c index 1fab522e6..b319ef6f2 100644 --- a/src/nautilus-index-title.c +++ b/src/nautilus-index-title.c @@ -216,38 +216,36 @@ nautilus_index_title_set_up_label (NautilusIndexTitle *index_title, const char * /* split the filename into two lines if necessary */ - if (strlen(file_name) >= 16) - { - /* find an appropriate split point if we can */ - gint index; - gint mid_point = strlen(file_name) >> 1; - gint quarter_point = mid_point >> 1; - for (index = 0; index < quarter_point; index++) - { - gint split_offset = 0; - - if (!isalnum(file_name[mid_point + index])) - split_offset = mid_point + index; - else if (!isalnum(file_name[mid_point - index])) - split_offset = mid_point - index; - - if (split_offset != 0) { - char *buffer = (char *) g_malloc(strlen(file_name) + 2); - - /* build the new string, with a CR inserted, also remembering them separately for measuring */ - - memcpy(buffer, file_name, split_offset); - buffer[split_offset] = '\n'; - strcpy(&buffer[split_offset + 1], &file_name[split_offset]); - - /* free up the old string and replace it with the new one with the return inserted */ - - g_free(file_name); - file_name = buffer; - } - } - } - + if (strlen(file_name) >= 16) { + /* find an appropriate split point if we can */ + gint index; + gint mid_point = strlen(file_name) >> 1; + gint quarter_point = mid_point >> 1; + for (index = 0; index < quarter_point; index++) { + gint split_offset = 0; + + if (!isalnum(file_name[mid_point + index])) + split_offset = mid_point + index; + else if (!isalnum(file_name[mid_point - index])) + split_offset = mid_point - index; + + if (split_offset != 0) { + char *buffer = (char *) g_malloc(strlen(file_name) + 2); + + /* build the new string, with a CR inserted, also remembering them separately for measuring */ + + memcpy(buffer, file_name, split_offset); + buffer[split_offset] = '\n'; + strcpy(&buffer[split_offset + 1], &file_name[split_offset]); + + /* free up the old string and replace it with the new one with the return inserted */ + + g_free(file_name); + file_name = buffer; + } + } + } + if (index_title->details->title != NULL) gtk_label_set_text (GTK_LABEL (index_title->details->title), file_name); else { diff --git a/src/nautilus-sidebar-title.c b/src/nautilus-sidebar-title.c index 1fab522e6..b319ef6f2 100644 --- a/src/nautilus-sidebar-title.c +++ b/src/nautilus-sidebar-title.c @@ -216,38 +216,36 @@ nautilus_index_title_set_up_label (NautilusIndexTitle *index_title, const char * /* split the filename into two lines if necessary */ - if (strlen(file_name) >= 16) - { - /* find an appropriate split point if we can */ - gint index; - gint mid_point = strlen(file_name) >> 1; - gint quarter_point = mid_point >> 1; - for (index = 0; index < quarter_point; index++) - { - gint split_offset = 0; - - if (!isalnum(file_name[mid_point + index])) - split_offset = mid_point + index; - else if (!isalnum(file_name[mid_point - index])) - split_offset = mid_point - index; - - if (split_offset != 0) { - char *buffer = (char *) g_malloc(strlen(file_name) + 2); - - /* build the new string, with a CR inserted, also remembering them separately for measuring */ - - memcpy(buffer, file_name, split_offset); - buffer[split_offset] = '\n'; - strcpy(&buffer[split_offset + 1], &file_name[split_offset]); - - /* free up the old string and replace it with the new one with the return inserted */ - - g_free(file_name); - file_name = buffer; - } - } - } - + if (strlen(file_name) >= 16) { + /* find an appropriate split point if we can */ + gint index; + gint mid_point = strlen(file_name) >> 1; + gint quarter_point = mid_point >> 1; + for (index = 0; index < quarter_point; index++) { + gint split_offset = 0; + + if (!isalnum(file_name[mid_point + index])) + split_offset = mid_point + index; + else if (!isalnum(file_name[mid_point - index])) + split_offset = mid_point - index; + + if (split_offset != 0) { + char *buffer = (char *) g_malloc(strlen(file_name) + 2); + + /* build the new string, with a CR inserted, also remembering them separately for measuring */ + + memcpy(buffer, file_name, split_offset); + buffer[split_offset] = '\n'; + strcpy(&buffer[split_offset + 1], &file_name[split_offset]); + + /* free up the old string and replace it with the new one with the return inserted */ + + g_free(file_name); + file_name = buffer; + } + } + } + if (index_title->details->title != NULL) gtk_label_set_text (GTK_LABEL (index_title->details->title), file_name); else { |