summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDarin Adler <darin@src.gnome.org>2000-09-20 00:44:07 +0000
committerDarin Adler <darin@src.gnome.org>2000-09-20 00:44:07 +0000
commit1035b5ea668b2f85e6290e78e27da41948d57fb0 (patch)
tree7f88990b786139ae56f82273e7fc42f4b277d7f1
parent1a0af901905f3a2b1b97a9f7ce55678a3f2d2d23 (diff)
downloadnautilus-1035b5ea668b2f85e6290e78e27da41948d57fb0.tar.gz
Fixed bug 640 (icon cache never frees images (awaiting GdkPixbuf
fix)). Also took care of bug 3145 (zillions of 'main_loops != NULL' assertion failures when quitting) and bug 3138 (Some code in the icon factory is cut and pasted from elsewhere). And a few unrelated things that came up while I was busy working on these. * configure.in: Applied patch from Dan Winship to fix handling of CFLAGS and LDFLAGS. Fixes some missing quoting and other mistakes. * libnautilus-extensions/Makefile.am: * libnautilus-extensions/nautilus-icon-factory-private.h: * libnautilus-extensions/nautilus-thumbnails.c: * libnautilus-extensions/nautilus-thumbnails.h: Broke out the thumbnailing code into its own source file for clarity. * libnautilus-extensions/nautilus-directory.c: * libnautilus-extensions/nautilus-file-utilities.h: * libnautilus-extensions/nautilus-file-utilities.c: (nautilus_make_directory_and_parents): Moved nautilus_make_directory_and_parents into a place where the thumbnail code can share it instead of requiring its own copy. * libnautilus-extensions/nautilus-global-preferences.h: * libnautilus-extensions/nautilus-global-preferences.c: (destroy_global_prefs_dialog), (global_preferences_get_dialog), (nautilus_global_preferences_dialog_update), (nautilus_global_preferences_initialize): * libnautilus-extensions/nautilus-preferences.h: * libnautilus-extensions/nautilus-preferences.c: (preferences_initialize_if_needed), (preferences_shutdown): * src/nautilus-application.c: (nautilus_application_destroy): Changed code so that it cleans up with g_atexit instead of with an explicit shutdown call. This makes it sequence correctly with other atexit code. * libnautilus-extensions/nautilus-icon-canvas-item.h: * libnautilus-extensions/nautilus-icon-canvas-item.c: (nautilus_icon_canvas_item_destroy), (nautilus_icon_canvas_item_set_attach_points), (emblem_layout_next): * libnautilus-extensions/nautilus-icon-container.c: (nautilus_icon_container_update_icon): Added a Nautilus prefix to the EmblemAttachPoints typedef, since it's public. * libnautilus-extensions/nautilus-icon-factory.h: * libnautilus-extensions/nautilus-icon-factory.c: Changed the icon factory structure so that it will actually free pixbufs when done with them. Made some other small fixes to the icon factory in passing, including removing some redundant code and fixing the logic for getting custom icons and deleting the icon factory and g_atexit time. * src/file-manager/fm-icon-view.c: (play_file), (preview_sound): Restructured the logic for playing sound previews a little to get rid of compiler warnings and close some loopholes in the old code. * src/nautilus-main.c: (is_event_loop_needed), (quit_if_in_main_loop), (nautilus_gtk_main_quit_all), (event_loop_unregister), (nautilus_main_event_loop_register), (nautilus_main_is_event_loop_mainstay), (nautilus_main_event_loop_quit), (main): Fixed the main loop quitting logic so that it is a bit simpler and works with the gnome-vfs code that runs event handling after the last main loop is gone.
-rw-r--r--ChangeLog69
-rw-r--r--configure.in15
-rw-r--r--libnautilus-extensions/Makefile.am3
-rw-r--r--libnautilus-extensions/nautilus-directory.c38
-rw-r--r--libnautilus-extensions/nautilus-file-utilities.c36
-rw-r--r--libnautilus-extensions/nautilus-file-utilities.h9
-rw-r--r--libnautilus-extensions/nautilus-global-preferences.c37
-rw-r--r--libnautilus-extensions/nautilus-global-preferences.h1
-rw-r--r--libnautilus-extensions/nautilus-icon-canvas-item.c29
-rw-r--r--libnautilus-extensions/nautilus-icon-canvas-item.h49
-rw-r--r--libnautilus-extensions/nautilus-icon-container.c2
-rw-r--r--libnautilus-extensions/nautilus-icon-factory-private.h33
-rw-r--r--libnautilus-extensions/nautilus-icon-factory.c1816
-rw-r--r--libnautilus-extensions/nautilus-icon-factory.h84
-rw-r--r--libnautilus-extensions/nautilus-preferences.c9
-rw-r--r--libnautilus-extensions/nautilus-preferences.h2
-rw-r--r--libnautilus-extensions/nautilus-thumbnails.c505
-rw-r--r--libnautilus-extensions/nautilus-thumbnails.h33
-rw-r--r--libnautilus-private/Makefile.am3
-rw-r--r--libnautilus-private/nautilus-directory.c38
-rw-r--r--libnautilus-private/nautilus-file-utilities.c36
-rw-r--r--libnautilus-private/nautilus-file-utilities.h9
-rw-r--r--libnautilus-private/nautilus-global-preferences.c37
-rw-r--r--libnautilus-private/nautilus-global-preferences.h1
-rw-r--r--libnautilus-private/nautilus-icon-canvas-item.c29
-rw-r--r--libnautilus-private/nautilus-icon-canvas-item.h49
-rw-r--r--libnautilus-private/nautilus-icon-container.c2
-rw-r--r--libnautilus-private/nautilus-icon-factory-private.h33
-rw-r--r--libnautilus-private/nautilus-icon-factory.c1816
-rw-r--r--libnautilus-private/nautilus-icon-factory.h84
-rw-r--r--libnautilus-private/nautilus-preferences.c9
-rw-r--r--libnautilus-private/nautilus-preferences.h2
-rw-r--r--libnautilus-private/nautilus-thumbnails.c505
-rw-r--r--libnautilus-private/nautilus-thumbnails.h33
-rw-r--r--src/file-manager/fm-icon-view.c60
-rw-r--r--src/nautilus-application.c9
-rw-r--r--src/nautilus-main.c62
-rw-r--r--test/.cvsignore1
38 files changed, 3044 insertions, 2544 deletions
diff --git a/ChangeLog b/ChangeLog
index d25a215a3..fc2b97a7f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,72 @@
+2000-09-19 Darin Adler <darin@eazel.com>
+
+ Fixed bug 640 (icon cache never frees images (awaiting GdkPixbuf
+ fix)). Also took care of bug 3145 (zillions of 'main_loops !=
+ NULL' assertion failures when quitting) and bug 3138 (Some code in
+ the icon factory is cut and pasted from elsewhere). And a few
+ unrelated things that came up while I was busy working on these.
+
+ * configure.in: Applied patch from Dan Winship to fix handling of
+ CFLAGS and LDFLAGS. Fixes some missing quoting and other mistakes.
+
+ * libnautilus-extensions/Makefile.am:
+ * libnautilus-extensions/nautilus-icon-factory-private.h:
+ * libnautilus-extensions/nautilus-thumbnails.c:
+ * libnautilus-extensions/nautilus-thumbnails.h:
+ Broke out the thumbnailing code into its own source file for
+ clarity.
+
+ * libnautilus-extensions/nautilus-directory.c:
+ * libnautilus-extensions/nautilus-file-utilities.h:
+ * libnautilus-extensions/nautilus-file-utilities.c:
+ (nautilus_make_directory_and_parents):
+ Moved nautilus_make_directory_and_parents into a place where the
+ thumbnail code can share it instead of requiring its own copy.
+
+ * libnautilus-extensions/nautilus-global-preferences.h:
+ * libnautilus-extensions/nautilus-global-preferences.c:
+ (destroy_global_prefs_dialog), (global_preferences_get_dialog),
+ (nautilus_global_preferences_dialog_update),
+ (nautilus_global_preferences_initialize):
+ * libnautilus-extensions/nautilus-preferences.h:
+ * libnautilus-extensions/nautilus-preferences.c:
+ (preferences_initialize_if_needed), (preferences_shutdown):
+ * src/nautilus-application.c: (nautilus_application_destroy):
+ Changed code so that it cleans up with g_atexit instead of with an
+ explicit shutdown call. This makes it sequence correctly with
+ other atexit code.
+
+ * libnautilus-extensions/nautilus-icon-canvas-item.h:
+ * libnautilus-extensions/nautilus-icon-canvas-item.c:
+ (nautilus_icon_canvas_item_destroy),
+ (nautilus_icon_canvas_item_set_attach_points),
+ (emblem_layout_next):
+ * libnautilus-extensions/nautilus-icon-container.c:
+ (nautilus_icon_container_update_icon):
+ Added a Nautilus prefix to the EmblemAttachPoints typedef, since
+ it's public.
+
+ * libnautilus-extensions/nautilus-icon-factory.h:
+ * libnautilus-extensions/nautilus-icon-factory.c:
+ Changed the icon factory structure so that it will actually free
+ pixbufs when done with them. Made some other small fixes to the
+ icon factory in passing, including removing some redundant code
+ and fixing the logic for getting custom icons and deleting the
+ icon factory and g_atexit time.
+
+ * src/file-manager/fm-icon-view.c: (play_file), (preview_sound):
+ Restructured the logic for playing sound previews a little to get
+ rid of compiler warnings and close some loopholes in the old code.
+
+ * src/nautilus-main.c: (is_event_loop_needed),
+ (quit_if_in_main_loop), (nautilus_gtk_main_quit_all),
+ (event_loop_unregister), (nautilus_main_event_loop_register),
+ (nautilus_main_is_event_loop_mainstay),
+ (nautilus_main_event_loop_quit), (main): Fixed the main loop
+ quitting logic so that it is a bit simpler and works with the
+ gnome-vfs code that runs event handling after the last main loop
+ is gone.
+
2000-09-19 John Sullivan <sullivan@eazel.com>
Fixed bug 2519 (fix hideous queue_size_request hack)
diff --git a/configure.in b/configure.in
index cf0782378..20b714ee3 100644
--- a/configure.in
+++ b/configure.in
@@ -120,7 +120,7 @@ _save_cc="$CC"
dnl Hack flags to find the mozilla stuff
CFLAGS="$_save_cflags -I$_mozilla_include_place"
-LDFLAGS="$_save_cflags -L$_mozilla_lib_place"
+LDFLAGS="$_save_ldflags -L$_mozilla_lib_place"
dnl Check for nspr and friends
AC_CHECK_LIB(nspr4, PR_Init, [_mozilla_nspr_libs="-lnspr4"])
@@ -149,20 +149,20 @@ else
fi
dnl The next two are pure from evil
-CC=$_save_cc
+CC="$_save_cc"
dnl gtk superwin library
-LDFLAGS="$_save_cflags -L$_mozilla_lib_place $_mozilla_all_nspr_flags -lgtksuperwin"
+LDFLAGS="$_save_ldflags -L$_mozilla_lib_place $_mozilla_all_nspr_flags -lgtksuperwin"
AC_CHECK_LIB(gtksuperwin, gdk_superwin_get_type, [_mozilla_gtk_super_win_libs="-lgtksuperwin"])
dnl gtk moz embed library
-LDFLAGS="$_save_cflags -L$_mozilla_lib_place $_mozilla_all_nspr_flags -lgtkembedmoz $_mozilla_xpcom_libs"
+LDFLAGS="$_save_ldflags -L$_mozilla_lib_place $_mozilla_all_nspr_flags -lgtkembedmoz $_mozilla_xpcom_libs"
AC_CHECK_LIB(gtkembedmoz, gtk_moz_embed_get_type, [_mozilla_gtk_moz_embed_libs="-lgtkembedmoz"])
dnl Restore the flags and compiler
-CFLAGS=$_save_cflags
-LDFLAGS=$_save_ldflags
-CC=$_save_cc
+CFLAGS="$_save_cflags"
+LDFLAGS="$_save_ldflags"
+CC="$_save_cc"
dnl Now make sure all the libraries are good
AC_MSG_CHECKING(for Mozilla)
@@ -258,7 +258,6 @@ dnl =>
AC_CHECK_LIB(popt, poptParseArgvString, [rpm_libs="$rpm_libs -lpopt"])
AC_CHECK_LIB(rpm, rpmRunTransactions,[build_rpmview=true],
[build_rpmview=false],-lz $rpm_libs -ldb)
-LDFLAGS="$save_LDFLAGS"
if test "x$build_rpmview" = "xtrue" ; then
AC_DEFINE(HAVE_RPM)
RPM_LIBS="-lrpm -lz $rpm_libs -ldb"
diff --git a/libnautilus-extensions/Makefile.am b/libnautilus-extensions/Makefile.am
index f135260f6..6e1f528d3 100644
--- a/libnautilus-extensions/Makefile.am
+++ b/libnautilus-extensions/Makefile.am
@@ -117,6 +117,7 @@ libnautilus_extensions_la_SOURCES = \
nautilus-string.c \
nautilus-text-caption.c \
nautilus-theme.c \
+ nautilus-thumbnails.c \
nautilus-trash-directory.c \
nautilus-undo-context.c \
nautilus-undo-manager.c \
@@ -177,6 +178,7 @@ noinst_HEADERS = \
nautilus-icon-container.h \
nautilus-icon-dnd.h \
nautilus-icon-factory.h \
+ nautilus-icon-factory-private.h \
nautilus-icon-private.h \
nautilus-icon-text-item.h \
nautilus-image.h \
@@ -213,6 +215,7 @@ noinst_HEADERS = \
nautilus-string.h \
nautilus-text-caption.h \
nautilus-theme.h \
+ nautilus-thumbnails.h \
nautilus-trash-directory.h \
nautilus-undo-context.h \
nautilus-undo-manager.h \
diff --git a/libnautilus-extensions/nautilus-directory.c b/libnautilus-extensions/nautilus-directory.c
index f42bb8179..879940a3e 100644
--- a/libnautilus-extensions/nautilus-directory.c
+++ b/libnautilus-extensions/nautilus-directory.c
@@ -67,8 +67,6 @@ static void nautilus_directory_destroy (GtkObject *obje
static void nautilus_directory_initialize (gpointer object,
gpointer klass);
static void nautilus_directory_initialize_class (NautilusDirectoryClass *klass);
-static GnomeVFSResult nautilus_make_directory_and_parents (GnomeVFSURI *uri,
- guint permissions);
static NautilusDirectory *nautilus_directory_new (const char *uri);
static char *real_get_name_for_self_as_new_file (NautilusDirectory *directory);
@@ -343,42 +341,6 @@ nautilus_directory_get_uri (NautilusDirectory *directory)
return g_strdup (directory->details->uri);
}
-static GnomeVFSResult
-nautilus_make_directory_and_parents (GnomeVFSURI *uri, guint permissions)
-{
- GnomeVFSResult result;
- GnomeVFSURI *parent_uri;
-
- /* Make the directory, and return right away unless there's
- a possible problem with the parent.
- */
- result = gnome_vfs_make_directory_for_uri (uri, permissions);
- if (result != GNOME_VFS_ERROR_NOT_FOUND) {
- return result;
- }
-
- /* If we can't get a parent, we are done. */
- parent_uri = gnome_vfs_uri_get_parent (uri);
- if (parent_uri == NULL) {
- return result;
- }
-
- /* If we can get a parent, use a recursive call to create
- the parent and its parents.
- */
- result = nautilus_make_directory_and_parents (parent_uri, permissions);
- gnome_vfs_uri_unref (parent_uri);
- if (result != GNOME_VFS_OK) {
- return result;
- }
-
- /* A second try at making the directory after the parents
- have all been created.
- */
- result = gnome_vfs_make_directory_for_uri (uri, permissions);
- return result;
-}
-
static GnomeVFSURI *
construct_private_metafile_vfs_uri (const char *uri)
{
diff --git a/libnautilus-extensions/nautilus-file-utilities.c b/libnautilus-extensions/nautilus-file-utilities.c
index 864a16e3a..8108f66c6 100644
--- a/libnautilus-extensions/nautilus-file-utilities.c
+++ b/libnautilus-extensions/nautilus-file-utilities.c
@@ -725,6 +725,42 @@ nautilus_read_file_cancel (NautilusReadFileHandle *handle)
g_free (handle);
}
+GnomeVFSResult
+nautilus_make_directory_and_parents (GnomeVFSURI *uri, guint permissions)
+{
+ GnomeVFSResult result;
+ GnomeVFSURI *parent_uri;
+
+ /* Make the directory, and return right away unless there's
+ a possible problem with the parent.
+ */
+ result = gnome_vfs_make_directory_for_uri (uri, permissions);
+ if (result != GNOME_VFS_ERROR_NOT_FOUND) {
+ return result;
+ }
+
+ /* If we can't get a parent, we are done. */
+ parent_uri = gnome_vfs_uri_get_parent (uri);
+ if (parent_uri == NULL) {
+ return result;
+ }
+
+ /* If we can get a parent, use a recursive call to create
+ the parent and its parents.
+ */
+ result = nautilus_make_directory_and_parents (parent_uri, permissions);
+ gnome_vfs_uri_unref (parent_uri);
+ if (result != GNOME_VFS_OK) {
+ return result;
+ }
+
+ /* A second try at making the directory after the parents
+ have all been created.
+ */
+ result = gnome_vfs_make_directory_for_uri (uri, permissions);
+ return result;
+}
+
#if !defined (NAUTILUS_OMIT_SELF_CHECK)
void
diff --git a/libnautilus-extensions/nautilus-file-utilities.h b/libnautilus-extensions/nautilus-file-utilities.h
index 792df2c4a..2485d4843 100644
--- a/libnautilus-extensions/nautilus-file-utilities.h
+++ b/libnautilus-extensions/nautilus-file-utilities.h
@@ -40,9 +40,8 @@ char * nautilus_format_uri_for_display (const char
char * nautilus_make_uri_from_input (const char *location);
gboolean nautilus_uri_is_trash (const char *uri);
char * nautilus_make_uri_canonical (const char *uri);
-gboolean nautilus_uris_match (const char *uri_1,
- const char *uri_2);
-
+gboolean nautilus_uris_match (const char *uri_1,
+ const char *uri_2);
/* FIXME bugzilla.eazel.com 2424:
* This is the same as gnome-libs g_concat_dir_and_file except
* for handling path == NULL.
@@ -89,4 +88,8 @@ NautilusReadFileHandle *nautilus_read_file_async (const char
gpointer callback_data);
void nautilus_read_file_cancel (NautilusReadFileHandle *handle);
+/* gnome-vfs cover to make a directory and parents */
+GnomeVFSResult nautilus_make_directory_and_parents (GnomeVFSURI *uri,
+ guint permissions);
+
#endif /* NAUTILUS_FILE_UTILITIES_H */
diff --git a/libnautilus-extensions/nautilus-global-preferences.c b/libnautilus-extensions/nautilus-global-preferences.c
index 4ec4d8265..6802356fc 100644
--- a/libnautilus-extensions/nautilus-global-preferences.c
+++ b/libnautilus-extensions/nautilus-global-preferences.c
@@ -389,16 +389,33 @@ nautilus_global_preferences_get_disabled_sidebar_panel_view_identifiers (void)
return disabled_view_identifiers;
}
+
+static void
+destroy_global_prefs_dialog (void)
+{
+ /* Free the dialog first, cause it has refs to preferences */
+ if (global_prefs_dialog != NULL) {
+ /* Since it's a top-level window, it's OK to destroy rather than unref'ing. */
+ gtk_widget_destroy (global_prefs_dialog);
+ }
+}
+
static GtkWidget *
global_preferences_get_dialog (void)
{
+ static gboolean set_up_exit = FALSE;
+
nautilus_global_preferences_initialize ();
- if (!global_prefs_dialog)
- {
+ if (global_prefs_dialog == NULL) {
global_prefs_dialog = global_preferences_create_dialog ();
}
+ if (!set_up_exit) {
+ g_atexit (destroy_global_prefs_dialog);
+ set_up_exit = TRUE;
+ }
+
return global_prefs_dialog;
}
@@ -863,9 +880,10 @@ nautilus_global_preferences_dialog_update (void)
was_showing = GTK_WIDGET_VISIBLE (global_prefs_dialog);
gtk_widget_destroy (global_prefs_dialog);
+ global_prefs_dialog = NULL;
}
- global_prefs_dialog = global_preferences_create_dialog ();
+ global_preferences_get_dialog ();
if (was_showing) {
nautilus_global_preferences_show_dialog ();
@@ -885,16 +903,3 @@ nautilus_global_preferences_initialize (void)
initialized = TRUE;
}
-
-void
-nautilus_global_preferences_shutdown (void)
-{
- /* Free the dialog first, cause it has refs to preferences */
- if (global_prefs_dialog != NULL) {
- gtk_widget_destroy (global_prefs_dialog);
- }
-
- /* Now free the preferences tables and stuff */
- nautilus_preferences_shutdown ();
-}
-
diff --git a/libnautilus-extensions/nautilus-global-preferences.h b/libnautilus-extensions/nautilus-global-preferences.h
index fe2fdde43..f96590bbc 100644
--- a/libnautilus-extensions/nautilus-global-preferences.h
+++ b/libnautilus-extensions/nautilus-global-preferences.h
@@ -124,7 +124,6 @@ typedef enum
void nautilus_global_preferences_initialize (void);
-void nautilus_global_preferences_shutdown (void);
void nautilus_global_preferences_show_dialog (void);
void nautilus_global_preferences_hide_dialog (void);
void nautilus_global_preferences_set_dialog_title (const char *title);
diff --git a/libnautilus-extensions/nautilus-icon-canvas-item.c b/libnautilus-extensions/nautilus-icon-canvas-item.c
index f4f412a57..753199a1e 100644
--- a/libnautilus-extensions/nautilus-icon-canvas-item.c
+++ b/libnautilus-extensions/nautilus-icon-canvas-item.c
@@ -68,7 +68,7 @@ struct NautilusIconCanvasItemDetails {
char *editable_text; /* Text that can be modified by a renaming function */
char *additional_text; /* Text that cannot be modifed, such as file size, etc. */
GdkFont *font;
- EmblemAttachPoints *attach_pointer;
+ NautilusEmblemAttachPoints *attach_points;
/* Size of the text at current font. */
int text_width;
@@ -301,7 +301,7 @@ nautilus_icon_canvas_item_destroy (GtkObject *object)
nautilus_gdk_pixbuf_list_free (details->emblem_pixbufs);
g_free (details->editable_text);
g_free (details->additional_text);
- g_free (details->attach_pointer);
+ g_free (details->attach_points);
if (details->font != NULL) {
gdk_font_unref (details->font);
@@ -531,14 +531,14 @@ nautilus_icon_canvas_item_set_emblems (NautilusIconCanvasItem *item,
void
nautilus_icon_canvas_item_set_attach_points (NautilusIconCanvasItem *item,
- EmblemAttachPoints *attach_points)
+ NautilusEmblemAttachPoints *attach_points)
{
- g_free (item->details->attach_pointer);
- item->details->attach_pointer = NULL;
+ g_free (item->details->attach_points);
+ item->details->attach_points = NULL;
- if (attach_points && attach_points->has_attach_points) {
- item->details->attach_pointer = g_new0 (EmblemAttachPoints, 1);
- *item->details->attach_pointer = *attach_points;
+ if (attach_points != NULL && attach_points->num_points != 0) {
+ item->details->attach_points = g_new (NautilusEmblemAttachPoints, 1);
+ *item->details->attach_points = *attach_points;
}
}
@@ -945,7 +945,7 @@ emblem_layout_next (EmblemLayout *layout,
{
GdkPixbuf *pixbuf;
int width, height, x, y;
- EmblemAttachPoints *attach_info ;
+ NautilusEmblemAttachPoints *attach_points;
/* Check if we have layed out all of the pixbufs. */
if (layout->emblem == NULL) {
@@ -961,13 +961,14 @@ emblem_layout_next (EmblemLayout *layout,
/* Advance to the next emblem. */
layout->emblem = layout->emblem->next;
- if (layout->icon_item->details->attach_pointer) {
- if (layout->index >= MAX_ATTACH_POINTS)
+ attach_points = layout->icon_item->details->attach_points;
+ if (attach_points != NULL) {
+ if (layout->index >= attach_points->num_points) {
return FALSE;
+ }
- attach_info = layout->icon_item->details->attach_pointer;
- x = layout->icon_rect.x0 + attach_info->attach_points[layout->index].x;
- y = layout->icon_rect.y0 + attach_info->attach_points[layout->index].y;
+ x = layout->icon_rect.x0 + attach_points->points[layout->index].x;
+ y = layout->icon_rect.y0 + attach_points->points[layout->index].y;
layout->index += 1;
diff --git a/libnautilus-extensions/nautilus-icon-canvas-item.h b/libnautilus-extensions/nautilus-icon-canvas-item.h
index 06e7af69c..8de5c8f23 100644
--- a/libnautilus-extensions/nautilus-icon-canvas-item.h
+++ b/libnautilus-extensions/nautilus-icon-canvas-item.h
@@ -66,34 +66,33 @@ GtkType nautilus_icon_canvas_item_get_type (void);
/* attributes */
-void nautilus_icon_canvas_item_set_image (NautilusIconCanvasItem *item,
- GdkPixbuf *image);
-GdkPixbuf * nautilus_icon_canvas_item_get_image (NautilusIconCanvasItem *item);
-void nautilus_icon_canvas_item_set_emblems (NautilusIconCanvasItem *item,
- GList *emblem_pixbufs);
-void nautilus_icon_canvas_item_set_show_stretch_handles (NautilusIconCanvasItem *item,
- gboolean show_stretch_handles);
-void nautilus_icon_canvas_item_set_attach_points (NautilusIconCanvasItem *item,
- EmblemAttachPoints *attach_points);
-double nautilus_icon_canvas_item_get_max_text_width (NautilusIconCanvasItem *item);
-const char *nautilus_icon_canvas_item_get_editable_text (NautilusIconCanvasItem *icon_item);
-void nautilus_icon_canvas_item_set_renaming (NautilusIconCanvasItem *icon_item,
- gboolean state);
+void nautilus_icon_canvas_item_set_image (NautilusIconCanvasItem *item,
+ GdkPixbuf *image);
+GdkPixbuf * nautilus_icon_canvas_item_get_image (NautilusIconCanvasItem *item);
+void nautilus_icon_canvas_item_set_emblems (NautilusIconCanvasItem *item,
+ GList *emblem_pixbufs);
+void nautilus_icon_canvas_item_set_show_stretch_handles (NautilusIconCanvasItem *item,
+ gboolean show_stretch_handles);
+void nautilus_icon_canvas_item_set_attach_points (NautilusIconCanvasItem *item,
+ NautilusEmblemAttachPoints *attach_points);
+double nautilus_icon_canvas_item_get_max_text_width (NautilusIconCanvasItem *item);
+const char *nautilus_icon_canvas_item_get_editable_text (NautilusIconCanvasItem *icon_item);
+void nautilus_icon_canvas_item_set_renaming (NautilusIconCanvasItem *icon_item,
+ gboolean state);
/* geometry and hit testing */
-gboolean nautilus_icon_canvas_item_hit_test_rectangle (NautilusIconCanvasItem *item,
- const ArtDRect *world_rectangle);
-gboolean nautilus_icon_canvas_item_hit_test_stretch_handles (NautilusIconCanvasItem *item,
- const ArtPoint *world_point);
-void nautilus_icon_canvas_item_get_icon_rectangle (NautilusIconCanvasItem *item,
- ArtDRect *world_rectangle);
-void nautilus_icon_canvas_item_update_bounds (NautilusIconCanvasItem *item);
-void nautilus_icon_canvas_item_set_smooth_font (NautilusIconCanvasItem *item,
- NautilusScalableFont *font);
-void nautilus_icon_canvas_item_set_smooth_font_size (NautilusIconCanvasItem *item,
- guint font_size);
-
+gboolean nautilus_icon_canvas_item_hit_test_rectangle (NautilusIconCanvasItem *item,
+ const ArtDRect *world_rectangle);
+gboolean nautilus_icon_canvas_item_hit_test_stretch_handles (NautilusIconCanvasItem *item,
+ const ArtPoint *world_point);
+void nautilus_icon_canvas_item_get_icon_rectangle (NautilusIconCanvasItem *item,
+ ArtDRect *world_rectangle);
+void nautilus_icon_canvas_item_update_bounds (NautilusIconCanvasItem *item);
+void nautilus_icon_canvas_item_set_smooth_font (NautilusIconCanvasItem *item,
+ NautilusScalableFont *font);
+void nautilus_icon_canvas_item_set_smooth_font_size (NautilusIconCanvasItem *item,
+ guint font_size);
END_GNOME_DECLS
diff --git a/libnautilus-extensions/nautilus-icon-container.c b/libnautilus-extensions/nautilus-icon-container.c
index 46fba885b..a5f7be185 100644
--- a/libnautilus-extensions/nautilus-icon-container.c
+++ b/libnautilus-extensions/nautilus-icon-container.c
@@ -3209,7 +3209,7 @@ nautilus_icon_container_update_icon (NautilusIconContainer *container,
NautilusIconContainerDetails *details;
guint icon_size_x, icon_size_y, max_image_size, max_emblem_size;
NautilusScalableIcon *scalable_icon;
- EmblemAttachPoints attach_points;
+ NautilusEmblemAttachPoints attach_points;
GdkPixbuf *pixbuf, *emblem_pixbuf;
GList *emblem_scalable_icons, *emblem_pixbufs, *p;
char *editable_text, *additional_text;
diff --git a/libnautilus-extensions/nautilus-icon-factory-private.h b/libnautilus-extensions/nautilus-icon-factory-private.h
new file mode 100644
index 000000000..475758eff
--- /dev/null
+++ b/libnautilus-extensions/nautilus-icon-factory-private.h
@@ -0,0 +1,33 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
+
+ nautilus-icon-factory-private.h: Private interface for use within
+ the icon factory code.
+
+ Copyright (C) 2000 Eazel, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with this program; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Author: Darin Adler <darin@eazel.com>
+*/
+
+#ifndef NAUTILUS_ICON_FACTORY_PRIVATE_H
+#define NAUTILUS_ICON_FACTORY_PRIVATE_H
+
+#include "nautilus-icon-factory.h"
+
+void nautilus_icon_factory_remove_by_uri (const char *uri);
+
+#endif /* NAUTILUS_ICON_FACTORY_PRIVATE_H */
diff --git a/libnautilus-extensions/nautilus-icon-factory.c b/libnautilus-extensions/nautilus-icon-factory.c
index c7b0f473c..d7d31e731 100644
--- a/libnautilus-extensions/nautilus-icon-factory.c
+++ b/libnautilus-extensions/nautilus-icon-factory.c
@@ -20,49 +20,42 @@
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
- Authors: John Sullivan <sullivan@eazel.com>, Darin Adler <darin@eazel.com>,
+ Authors: John Sullivan <sullivan@eazel.com>,
+ Darin Adler <darin@eazel.com>,
Andy Hertzfeld <andy@eazel.com>
*/
#include <config.h>
#include "nautilus-icon-factory.h"
-#include <unistd.h>
-#include <string.h>
-#include <stdio.h>
-
-#include <gtk/gtkmain.h>
-#include <gtk/gtksignal.h>
-#include <gnome.h>
-
-#include <libgnomevfs/gnome-vfs-types.h>
-#include <libgnomevfs/gnome-vfs-file-info.h>
-#include <libgnomevfs/gnome-vfs-mime-info.h>
-
-#include <libnautilus-extensions/nautilus-gdk-pixbuf-extensions.h>
-
-#include <parser.h>
-#include <xmlmemory.h>
-
-#include <librsvg/rsvg.h>
-
#include "nautilus-default-file-icon.h"
-#include "nautilus-directory-notify.h"
#include "nautilus-file-attributes.h"
#include "nautilus-file-utilities.h"
#include "nautilus-gdk-extensions.h"
#include "nautilus-gdk-pixbuf-extensions.h"
#include "nautilus-glib-extensions.h"
#include "nautilus-global-preferences.h"
-#include "nautilus-graphic-effects.h"
#include "nautilus-gtk-macros.h"
+#include "nautilus-icon-factory-private.h"
#include "nautilus-lib-self-check-functions.h"
#include "nautilus-link.h"
#include "nautilus-metadata.h"
+#include "nautilus-scalable-font.h"
#include "nautilus-string.h"
#include "nautilus-theme.h"
+#include "nautilus-thumbnails.h"
#include "nautilus-xml-extensions.h"
-#include "nautilus-scalable-font.h"
+#include <gnome.h>
+#include <gtk/gtksignal.h>
+#include <libgnomevfs/gnome-vfs-file-info.h>
+#include <libgnomevfs/gnome-vfs-mime-info.h>
+#include <libgnomevfs/gnome-vfs-types.h>
+#include <libnautilus-extensions/nautilus-gdk-pixbuf-extensions.h>
+#include <librsvg/rsvg.h>
+#include <parser.h>
+#include <stdio.h>
+#include <string.h>
+#include <xmlmemory.h>
/* List of suffixes to search when looking for an icon file. */
static const char *icon_file_name_suffixes[] =
@@ -75,6 +68,7 @@ static const char *icon_file_name_suffixes[] =
".gif",
".GIF"
};
+
#define ICON_NAME_DIRECTORY "i-directory"
#define ICON_NAME_DIRECTORY_CLOSED "i-dirclosed"
#define ICON_NAME_EXECUTABLE "i-executable"
@@ -123,9 +117,16 @@ struct NautilusCircularList {
/* maximum size for either dimension at the standard zoom level */
#define MAXIMUM_ICON_SIZE 96
-/* permissions for thumbnail directory */
-
-#define THUMBNAIL_DIR_PERMISSIONS (GNOME_VFS_PERM_USER_ALL | GNOME_VFS_PERM_GROUP_ALL | GNOME_VFS_PERM_OTHER_ALL)
+/* FIXME bugzilla.eazel.com 1102: Embedded text should use preferences
+ * to determine what font it uses.
+ */
+#define EMBEDDED_TEXT_FONT_FAMILY _("helvetica")
+#define EMBEDDED_TEXT_FONT_WEIGHT _("medium")
+#define EMBEDDED_TEXT_FONT_SLANT NULL
+#define EMBEDDED_TEXT_FONT_SET_WIDTH NULL
+#define EMBEDDED_TEXT_FONT_SIZE 9
+#define EMBEDDED_TEXT_LINE_OFFSET 1
+#define EMBEDDED_TEXT_EMPTY_LINE_HEIGHT 4
/* The icon factory.
* These are just globals, but they're in an object so we can
@@ -143,24 +144,24 @@ typedef struct {
*/
GHashTable *scalable_icons;
- /* A hash table that contains a cache of actual images.
- * A circular list of the most recently used images is kept
- * around, and we don't let them go when we sweep the cache.
+ /* A hash table so we can find a cached icon's data structure
+ * from the pixbuf.
+ */
+ GHashTable *cache_icons;
+
+ /* A hash table that contains the icons. A circular list of
+ * the most recently used icons is kept around, and we don't
+ * let them go when we sweep the cache.
*/
GHashTable *icon_cache;
NautilusCircularList recently_used_dummy_head;
guint recently_used_count;
guint sweep_timer;
-
- /* thumbnail task state */
- GList *thumbnails;
- char *new_thumbnail_path;
- gboolean thumbnail_in_progress;
-
- /* id of timeout task for making thumbnails */
- int timeout_task_id;
} NautilusIconFactory;
+#define NAUTILUS_ICON_FACTORY(obj) \
+ GTK_CHECK_CAST (obj, nautilus_icon_factory_get_type (), NautilusIconFactory)
+
typedef struct {
GtkObjectClass parent_class;
} NautilusIconFactoryClass;
@@ -172,7 +173,7 @@ enum {
static guint signals[LAST_SIGNAL];
/* A scalable icon, which is basically the name and path of an icon,
- * before we load the actual pixels of the icons's image.
+ * before we load the actual pixels of the icons's pixbuf.
*/
struct NautilusScalableIcon {
guint ref_count;
@@ -192,92 +193,94 @@ typedef struct {
guint maximum_height;
} IconSizeRequest;
-/* A structure to hold the icon meta-info, like the text rectangle and emblem attach points */
-
typedef struct {
ArtIRect text_rect;
- gboolean has_attach_points;
- GdkPoint attach_points[MAX_ATTACH_POINTS];
-} IconInfo;
+ NautilusEmblemAttachPoints attach_points;
+} IconDetails;
-/* The key to a hash table that holds the scaled icons as pixbufs.
- * In a way, it's not really completely a key, because part of the
- * data is stored in here, including the LRU chain.
- */
+/* The key to a hash table that holds the scaled icons as pixbufs. */
typedef struct {
NautilusScalableIcon *scalable_icon;
IconSizeRequest size;
+} CacheKey;
+
+/* The value in the same table. */
+typedef struct {
+ GdkPixbuf *pixbuf;
+ IconDetails details;
+ /* If true, outside clients have refs to the pixbuf. */
+ gboolean outstanding;
+
+ /* Number of internal clients with refs to the pixbuf. */
+ guint internal_ref_count;
+
+ /* Used to decide when to kick icons out of the cache. */
NautilusCircularList recently_used_node;
- time_t cache_time;
- gboolean aa_mode;
+
+ /* Used to know when to make a new thumbnail. */
+ time_t cache_time;
+
+ /* Type of icon. */
gboolean custom;
gboolean scaled;
- IconInfo icon_info;
-} IconCacheKey;
+} CacheIcon;
#define MINIMUM_EMBEDDED_TEXT_RECT_WIDTH 20.0
#define MINIMUM_EMBEDDED_TEXT_RECT_HEIGHT 20.0
+static CacheIcon *fallback_icon;
+
/* forward declarations */
-static void icon_theme_changed_callback (gpointer user_data);
-static GtkType nautilus_icon_factory_get_type (void);
-static void nautilus_icon_factory_initialize_class (NautilusIconFactoryClass *class);
-static void nautilus_icon_factory_initialize (NautilusIconFactory *factory);
-static NautilusIconFactory * nautilus_get_current_icon_factory (void);
-static char * nautilus_icon_factory_get_thumbnail_uri (NautilusFile *file,
- gboolean anti_aliased);
-static NautilusIconFactory * nautilus_icon_factory_new (const char *theme_name);
-static void nautilus_icon_factory_set_theme (const char *theme_name);
-static guint nautilus_scalable_icon_hash (gconstpointer p);
-static gboolean nautilus_scalable_icon_equal (gconstpointer a,
- gconstpointer b);
-static void icon_cache_key_destroy (IconCacheKey *key);
-static guint icon_cache_key_hash (gconstpointer p);
-static gboolean icon_cache_key_equal (gconstpointer a,
- gconstpointer b);
-static gboolean vfs_file_exists (const char *file_name);
-static GdkPixbuf * get_image_from_cache (NautilusScalableIcon *scalable_icon,
- const IconSizeRequest *size,
- gboolean picky,
- gboolean custom,
- IconInfo *icon_info);
-static gboolean check_for_thumbnails (NautilusIconFactory *factory);
-static int nautilus_icon_factory_make_thumbnails (gpointer data);
-static GdkPixbuf * load_image_with_embedded_text (NautilusScalableIcon *scalable_icon,
- const IconSizeRequest *size);
-
-NAUTILUS_DEFINE_CLASS_BOILERPLATE (NautilusIconFactory, nautilus_icon_factory, GTK_TYPE_OBJECT)
+static guint nautilus_icon_factory_get_type (void);
+static void nautilus_icon_factory_initialize_class (NautilusIconFactoryClass *class);
+static void nautilus_icon_factory_initialize (NautilusIconFactory *factory);
+static void nautilus_icon_factory_destroy (GtkObject *object);
+static void icon_theme_changed_callback (gpointer user_data);
+static guint nautilus_scalable_icon_hash (gconstpointer p);
+static gboolean nautilus_scalable_icon_equal (gconstpointer a,
+ gconstpointer b);
+static guint cache_key_hash (gconstpointer p);
+static gboolean cache_key_equal (gconstpointer a,
+ gconstpointer b);
+static CacheIcon *get_icon_from_cache (NautilusScalableIcon *scalable_icon,
+ const IconSizeRequest *size,
+ gboolean picky,
+ gboolean custom);
+static CacheIcon *load_icon_with_embedded_text (NautilusScalableIcon *scalable_icon,
+ const IconSizeRequest *size);
+
+NAUTILUS_DEFINE_CLASS_BOILERPLATE (NautilusIconFactory,
+ nautilus_icon_factory,
+ GTK_TYPE_OBJECT)
+
+static NautilusIconFactory *global_icon_factory = NULL;
+
+static void
+destroy_icon_factory (void)
+{
+ nautilus_preferences_remove_callback (NAUTILUS_PREFERENCES_THEME,
+ icon_theme_changed_callback,
+ NULL);
+ gtk_object_unref (GTK_OBJECT (global_icon_factory));
+}
/* Return a pointer to the single global icon factory. */
static NautilusIconFactory *
-nautilus_get_current_icon_factory (void)
+get_icon_factory (void)
{
- static NautilusIconFactory *global_icon_factory = NULL;
if (global_icon_factory == NULL) {
- char *theme_preference, *icon_theme;
+ global_icon_factory = NAUTILUS_ICON_FACTORY
+ (gtk_object_new (nautilus_icon_factory_get_type (), NULL));
- theme_preference = nautilus_preferences_get (NAUTILUS_PREFERENCES_THEME,
- DEFAULT_ICON_THEME);
- g_assert (theme_preference != NULL);
-
- /* give the theme a chance to redirect the icons */
- icon_theme = nautilus_theme_get_theme_data ("icons", "ICON_THEME");
-
- if (icon_theme != NULL) {
- global_icon_factory = nautilus_icon_factory_new (icon_theme);
- } else {
- global_icon_factory = nautilus_icon_factory_new (theme_preference);
- }
-
- g_free (theme_preference);
- g_free (icon_theme);
-
+ /* Update to match the theme. */
+ icon_theme_changed_callback (NULL);
nautilus_preferences_add_callback (NAUTILUS_PREFERENCES_THEME,
icon_theme_changed_callback,
- NULL);
-
+ NULL);
+
+ g_atexit (destroy_icon_factory);
}
return global_icon_factory;
}
@@ -285,20 +288,38 @@ nautilus_get_current_icon_factory (void)
GtkObject *
nautilus_icon_factory_get (void)
{
- return GTK_OBJECT (nautilus_get_current_icon_factory ());
+ return GTK_OBJECT (get_icon_factory ());
}
-/* Create the icon factory. */
-static NautilusIconFactory *
-nautilus_icon_factory_new (const char *theme_name)
+static void
+check_recently_used_list (void)
{
- NautilusIconFactory *factory;
-
- factory = (NautilusIconFactory *) gtk_object_new (nautilus_icon_factory_get_type (), NULL);
+ NautilusIconFactory *factory;
+ NautilusCircularList *head, *node, *next;
+ int count;
- factory->theme_name = g_strdup (theme_name);
+ factory = get_icon_factory ();
+
+ head = &factory->recently_used_dummy_head;
+
+ count = 0;
+
+ node = head;
+ while (1) {
+ next = node->next;
+ g_assert (next != NULL);
+ g_assert (next->prev == node);
+
+ if (next == head) {
+ break;
+ }
+
+ count += 1;
+
+ node = next;
+ }
- return factory;
+ g_assert (count == factory->recently_used_count);
}
static void
@@ -306,8 +327,10 @@ nautilus_icon_factory_initialize (NautilusIconFactory *factory)
{
factory->scalable_icons = g_hash_table_new (nautilus_scalable_icon_hash,
nautilus_scalable_icon_equal);
- factory->icon_cache = g_hash_table_new (icon_cache_key_hash,
- icon_cache_key_equal);
+ factory->cache_icons = g_hash_table_new (g_direct_hash,
+ g_direct_equal);
+ factory->icon_cache = g_hash_table_new (cache_key_hash,
+ cache_key_equal);
/* Empty out the recently-used list. */
factory->recently_used_dummy_head.next = &factory->recently_used_dummy_head;
@@ -330,127 +353,241 @@ nautilus_icon_factory_initialize_class (NautilusIconFactoryClass *class)
GTK_TYPE_NONE, 0);
gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL);
+
+ object_class->destroy = nautilus_icon_factory_destroy;
+}
+
+static void
+cache_key_destroy (CacheKey *key)
+{
+ nautilus_scalable_icon_unref (key->scalable_icon);
+ g_free (key);
+}
+
+static void
+mark_icon_not_outstanding (GdkPixbuf *pixbuf, gpointer callback_data)
+{
+ NautilusIconFactory *factory;
+ CacheIcon *icon;
+
+ g_assert (callback_data == NULL);
+
+ factory = get_icon_factory ();
+
+ icon = g_hash_table_lookup (factory->cache_icons, pixbuf);
+ g_return_if_fail (icon != NULL);
+ g_return_if_fail (icon->pixbuf == pixbuf);
+ g_return_if_fail (icon->outstanding);
+
+ icon->outstanding = FALSE;
+}
+
+static CacheIcon *
+cache_icon_new (GdkPixbuf *pixbuf,
+ gboolean custom,
+ gboolean scaled,
+ const IconDetails *details)
+{
+ NautilusIconFactory *factory;
+ CacheIcon *icon;
+
+ factory = get_icon_factory ();
+
+ /* Just a check to see this is not reusing a pixbuf. */
+ g_assert (g_hash_table_lookup (factory->cache_icons, pixbuf) == NULL);
+
+ /* Grab the pixbuf since we are keeping it. */
+ gdk_pixbuf_ref (pixbuf);
+ gdk_pixbuf_set_last_unref_handler
+ (pixbuf, mark_icon_not_outstanding, NULL);
+
+ /* Make the icon. */
+ icon = g_new0 (CacheIcon, 1);
+ icon->pixbuf = pixbuf;
+ icon->internal_ref_count = 1;
+ icon->custom = custom;
+ icon->scaled = scaled;
+ icon->details = *details;
+
+ /* Put it into the hash table. */
+ g_hash_table_insert (factory->cache_icons, pixbuf, icon);
+ return icon;
+}
+
+static void
+cache_icon_ref (CacheIcon *icon)
+{
+ NautilusIconFactory *factory;
+
+ factory = get_icon_factory ();
+
+ g_assert (icon != NULL);
+ g_assert (icon->internal_ref_count >= 1);
+ g_assert (g_hash_table_lookup (factory->cache_icons, icon->pixbuf) == icon);
+
+ icon->internal_ref_count++;
+}
+
+static void
+cache_icon_unref (CacheIcon *icon)
+{
+ NautilusIconFactory *factory;
+ NautilusCircularList *node;
+
+ factory = get_icon_factory ();
+
+ g_assert (icon != NULL);
+ g_assert (icon->internal_ref_count >= 1);
+ g_assert (g_hash_table_lookup (factory->cache_icons, icon->pixbuf) == icon);
+
+ if (icon->internal_ref_count > 1) {
+ icon->internal_ref_count--;
+ return;
+ }
+
+ check_recently_used_list ();
+
+ /* If it's in the recently used list, free it from there */
+ node = &icon->recently_used_node;
+ if (node->next != NULL) {
+ g_assert (factory->recently_used_count >= 1);
+
+ g_assert (node->next->prev == node);
+ g_assert (node->prev->next == node);
+ g_assert (node->next != node);
+ g_assert (node->prev != node);
+
+ node->next->prev = node->prev;
+ node->prev->next = node->next;
+
+ factory->recently_used_count -= 1;
+ }
+
+ check_recently_used_list ();
+
+
+ /* Remove from the cache icons table. */
+ g_hash_table_remove (factory->cache_icons, icon->pixbuf);
+
+ /* Since it's no longer in the cache, we don't need to notice the last unref. */
+ gdk_pixbuf_set_last_unref_handler (icon->pixbuf, NULL, NULL);
+
+ /* Let go of the pixbuf if we were holding a reference to it.
+ * If it was still outstanding, we didn't have a reference to it,
+ * and we were counting on the unref handler to catch it.
+ */
+ if (!icon->outstanding) {
+ gdk_pixbuf_unref (icon->pixbuf);
+ }
+
+ g_free (icon);
}
-/* Destroy one image in the cache. */
+/* Destroy one pixbuf in the cache. */
static gboolean
-nautilus_icon_factory_destroy_cached_image (gpointer key, gpointer value, gpointer user_data)
+nautilus_icon_factory_destroy_cached_icon (gpointer key, gpointer value, gpointer user_data)
{
- icon_cache_key_destroy (key);
- gdk_pixbuf_unref (value);
+ cache_key_destroy (key);
+ cache_icon_unref (value);
+
+ /* Tell the caller to remove the hash table entry. */
return TRUE;
}
-
/* Reset the cache to the default state. */
static void
nautilus_icon_factory_clear (void)
{
NautilusIconFactory *factory;
+ NautilusCircularList *head;
- factory = nautilus_get_current_icon_factory ();
+ factory = get_icon_factory ();
g_hash_table_foreach_remove (factory->icon_cache,
- nautilus_icon_factory_destroy_cached_image,
+ nautilus_icon_factory_destroy_cached_icon,
NULL);
/* Empty out the recently-used list. */
- factory->recently_used_dummy_head.next = &factory->recently_used_dummy_head;
- factory->recently_used_dummy_head.prev = &factory->recently_used_dummy_head;
- factory->recently_used_count = 0;
+ head = &factory->recently_used_dummy_head;
+ g_assert (factory->recently_used_count == 0);
+ g_assert (head->next == head);
+ g_assert (head->prev == head);
}
-#if 0
-
-/* No one ever destroys the icon factory.
- * There's no public API for doing so.
- * If they did, we'd have to get this right.
- */
-
static void
-nautilus_icon_factory_destroy (NautilusIconFactory *factory)
+nautilus_icon_factory_destroy (GtkObject *object)
{
- nautilus_preferences_remove_callback (NAUTILUS_PREFERENCES_THEME,
- icon_theme_changed_callback,
- NULL);
+ NautilusIconFactory *factory;
+
+ factory = NAUTILUS_ICON_FACTORY (object);
nautilus_icon_factory_clear ();
+
+ if (g_hash_table_size (factory->scalable_icons) != 0) {
+ g_warning ("%d scalable icons still left when destroying icon factory",
+ g_hash_table_size (factory->scalable_icons));
+ }
+ if (g_hash_table_size (factory->icon_cache) != 0) {
+ g_warning ("%d icon cache entries still left when destroying icon factory",
+ g_hash_table_size (factory->icon_cache));
+ }
+
+ g_hash_table_destroy (factory->scalable_icons);
g_hash_table_destroy (factory->icon_cache);
g_free (factory->theme_name);
- g_free (factory);
+
+ NAUTILUS_CALL_PARENT_CLASS (GTK_OBJECT_CLASS, destroy, (object));
}
-#endif
-
static gboolean
-nautilus_icon_factory_possibly_free_cached_image (gpointer key,
+nautilus_icon_factory_possibly_free_cached_icon (gpointer key,
gpointer value,
gpointer user_data)
{
- IconCacheKey *icon_key;
- GdkPixbuf *image;
+ CacheIcon *icon;
+
+ icon = value;
/* Don't free a cache entry that is in the recently used list. */
- icon_key = key;
- if (icon_key->recently_used_node.next != NULL) {
+ if (icon->recently_used_node.next != NULL) {
return FALSE;
}
- /* Don't free a cache entry if the image is still in use. */
- image = value;
-
- /* FIXME bugzilla.eazel.com 640:
- * We treat all entries as "in use", until we get a hook we can use
- * in GdkPixbuf. We are waiting for the "final" hook right now. The
- * one that's in there is not approved of by the Gtk maintainers.
- */
- return FALSE;
-#if 0
- if (image->ref_count > 1) {
+ /* Don't free a cache entry if the pixbuf is still in use. */
+ if (icon->outstanding) {
return FALSE;
}
/* Free the item. */
- return nautilus_icon_factory_destroy_cached_image (key, value, NULL);
-#endif
+ return nautilus_icon_factory_destroy_cached_icon (key, value, NULL);
}
-/* remove images whose uri field matches the passed-in uri */
-
+/* Remove icons whose URI field matches the passed-in URI. */
static gboolean
-nautilus_icon_factory_remove_image_uri (gpointer key,
- gpointer value,
- gpointer user_data)
+nautilus_icon_factory_remove_if_uri_matches (gpointer key,
+ gpointer value,
+ gpointer user_data)
{
char *image_uri;
- IconCacheKey *icon_key;
- NautilusCircularList *node;
- NautilusIconFactory *factory;
+ CacheKey *cache_key;
+ CacheIcon *icon;
- icon_key = key;
+ cache_key = key;
+ icon = value;
image_uri = user_data;
- /* see if the the uri's match - if not, just return */
- if (icon_key->scalable_icon->uri && strcmp(icon_key->scalable_icon->uri, image_uri)) {
+ /* See if the the uri's match - if not, just return. */
+ if (cache_key->scalable_icon->uri != NULL
+ && strcmp (cache_key->scalable_icon->uri, image_uri)) {
return FALSE;
}
- /* if it's in the recently used list, free it from there */
- node = &icon_key->recently_used_node;
- if (node->next != NULL) {
- node->next->prev = node->prev;
- node->prev->next = node->next;
-
- factory = nautilus_get_current_icon_factory ();
- factory->recently_used_count -= 1;
- }
-
/* Free the item. */
- return nautilus_icon_factory_destroy_cached_image (key, value, NULL);
+ return nautilus_icon_factory_destroy_cached_icon (key, value, NULL);
}
-/* Sweep the cache, freeing any images that are not in use and are
+/* Sweep the cache, freeing any icons that are not in use and are
* also not recently used.
*/
static gboolean
@@ -461,7 +598,7 @@ nautilus_icon_factory_sweep (gpointer user_data)
factory = user_data;
g_hash_table_foreach_remove (factory->icon_cache,
- nautilus_icon_factory_possibly_free_cached_image,
+ nautilus_icon_factory_possibly_free_cached_icon,
NULL);
factory->sweep_timer = 0;
@@ -475,7 +612,7 @@ nautilus_icon_factory_schedule_sweep (void)
{
NautilusIconFactory *factory;
- factory = nautilus_get_current_icon_factory ();
+ factory = get_icon_factory ();
if (factory->sweep_timer != 0) {
return;
@@ -486,28 +623,38 @@ nautilus_icon_factory_schedule_sweep (void)
factory);
}
-/* clear a specific image from the cache */
-
-static void
-nautilus_icon_factory_clear_image(const char *image_uri)
+/* Clear a specific icon from the cache. */
+void
+nautilus_icon_factory_remove_by_uri (const char *image_uri)
{
NautilusIconFactory *factory;
/* build the key and look it up in the icon cache */
- factory = nautilus_get_current_icon_factory ();
+ factory = get_icon_factory ();
g_hash_table_foreach_remove (factory->icon_cache,
- nautilus_icon_factory_remove_image_uri,
+ nautilus_icon_factory_remove_if_uri_matches,
(gpointer) image_uri);
}
/* Change the theme. */
-void
-nautilus_icon_factory_set_theme (const char *theme_name)
+static void
+set_theme (const char *theme_name)
{
NautilusIconFactory *factory;
- factory = nautilus_get_current_icon_factory ();
+ if (factory->theme_name == NULL) {
+ if (theme_name == NULL) {
+ return;
+ }
+ } else {
+ if (theme_name != NULL
+ && strcmp (theme_name, factory->theme_name) != 0) {
+ return;
+ }
+ }
+
+ factory = get_icon_factory ();
nautilus_icon_factory_clear ();
@@ -619,24 +766,31 @@ make_full_icon_path (const char *path, const char *suffix)
/* utility routine to parse the attach points string to set up the array in icon_info */
static void
-parse_attach_points (IconInfo *icon_info, const char* attach_point_string)
+parse_attach_points (NautilusEmblemAttachPoints *attach_points, const char *attach_point_string)
{
- char *text_piece;
char **point_array;
- int index, x_offset, y_offset;
-
- /* split the attach point string into a string array, then process
- each point with sscanf in a loop */
+ int i, x_offset, y_offset;
+
+ attach_points->num_points = 0;
+ if (attach_point_string == NULL) {
+ return;
+ }
+
+ /* Split the attach point string into a string array, then process
+ * each point with sscanf in a loop.
+ */
point_array = g_strsplit (attach_point_string, "|", MAX_ATTACH_POINTS);
- for (index = 0; (text_piece = point_array[index]) != NULL; index++) {
- if (sscanf (text_piece, " %d , %d , %*s", &x_offset, &y_offset) == 2) {
- icon_info->attach_points[index].x = x_offset;
- icon_info->attach_points[index].y = y_offset;
+ for (i = 0; point_array[i] != NULL; i++) {
+ if (sscanf (point_array[i], " %d , %d , %*s", &x_offset, &y_offset) == 2) {
+ attach_points->points[attach_points->num_points].x = x_offset;
+ attach_points->points[attach_points->num_points].y = y_offset;
+ attach_points->num_points++;
} else {
- g_warning ("bad attach point specification: %s", text_piece);
- }
+ g_warning ("bad attach point specification: %s", point_array[i]);
+ }
}
+
g_strfreev (point_array);
}
@@ -647,8 +801,8 @@ static char *
get_themed_icon_file_path (const char *theme_name,
const char *icon_name,
guint icon_size,
- IconInfo *icon_info,
- gboolean aa_mode)
+ gboolean aa_mode,
+ IconDetails *details)
{
int i;
gboolean include_size;
@@ -658,6 +812,7 @@ get_themed_icon_file_path (const char *theme_name,
char *size_as_string, *property;
ArtIRect parsed_rect;
NautilusIconFactory *factory;
+ char *user_directory;
g_assert (icon_name != NULL);
@@ -667,16 +822,11 @@ get_themed_icon_file_path (const char *theme_name,
themed_icon_name = g_strconcat (theme_name, "/", icon_name, NULL);
}
- if (icon_info != NULL) {
- icon_info->has_attach_points = FALSE;
- }
-
include_size = icon_size != NAUTILUS_ICON_SIZE_STANDARD;
- factory = (NautilusIconFactory*) nautilus_icon_factory_get();
+ factory = get_icon_factory ();
/* Try each suffix. */
for (i = 0; i < NAUTILUS_N_ELEMENTS (icon_file_name_suffixes); i++) {
-
if (include_size && strcasecmp(icon_file_name_suffixes[i], ".svg")) {
/* Build a path for this icon. */
partial_path = g_strdup_printf ("%s-%u",
@@ -688,9 +838,9 @@ get_themed_icon_file_path (const char *theme_name,
/* if we're in anti-aliased mode, try for an optimized one first */
if (aa_mode) {
- aa_path = g_strdup_printf ("%s-aa", partial_path);
+ aa_path = g_strconcat (partial_path, "-aa", NULL);
path = make_full_icon_path (aa_path,
- icon_file_name_suffixes[i]);
+ icon_file_name_suffixes[i]);
g_free (aa_path);
/* Return the path if the file exists. */
@@ -715,8 +865,8 @@ get_themed_icon_file_path (const char *theme_name,
}
/* Open the XML file to get the text rectangle and emblem attach points */
- if (path != NULL && icon_info != NULL) {
- memset (&icon_info->text_rect, 0, sizeof (icon_info->text_rect));
+ if (path != NULL && details != NULL) {
+ memset (&details->text_rect, 0, sizeof (details->text_rect));
xml_path = make_full_icon_path (themed_icon_name, ".xml");
@@ -737,30 +887,24 @@ get_themed_icon_file_path (const char *theme_name,
&parsed_rect.y0,
&parsed_rect.x1,
&parsed_rect.y1) == 4) {
- icon_info->text_rect = parsed_rect;
+ details->text_rect = parsed_rect;
}
xmlFree (property);
}
property = xmlGetProp (node, "ATTACH_POINTS");
- if (property != NULL) {
- icon_info->has_attach_points = TRUE;
- parse_attach_points (icon_info, property);
- xmlFree (property);
- } else {
- icon_info->has_attach_points = FALSE;
- }
+ parse_attach_points (&details->attach_points, property);
+ xmlFree (property);
xmlFreeDoc (doc);
}
- /* if we still haven't found anything, and we're looking for an emblem,
- check out the user's home directory, since it might be an emblem
- that they've added there */
-
+ /* If we still haven't found anything, and we're looking for an emblem,
+ * check out the user's home directory, since it might be an emblem
+ * that they've added there.
+ */
if (path == NULL && nautilus_str_has_prefix (icon_name, "emblem-")) {
for (i = 0; i < NAUTILUS_N_ELEMENTS (icon_file_name_suffixes); i++) {
- char *user_directory;
user_directory = nautilus_get_user_directory ();
path = g_strdup_printf ("%s/emblems/%s%s",
user_directory,
@@ -781,24 +925,28 @@ get_themed_icon_file_path (const char *theme_name,
return path;
}
-/* Choose the file name to load, taking into account theme vs. non-theme icons. */
+/* Choose the file name to load, taking into account theme
+ * vs. non-theme icons. Also fill in info in the icon structure based
+ * on what's found in the XML file.
+ */
static char *
get_icon_file_path (const char *name,
- const char* modifier,
+ const char *modifier,
guint size_in_pixels,
- IconInfo *icon_info,
- gboolean aa_mode)
+ gboolean aa_mode,
+ IconDetails *details)
{
gboolean use_theme_icon;
const char *theme_name;
char *path;
+ char *name_with_modifier;
if (name == NULL) {
return NULL;
}
use_theme_icon = FALSE;
- theme_name = nautilus_get_current_icon_factory ()->theme_name;
+ theme_name = get_icon_factory ()->theme_name;
/* Check and see if there is a theme icon to use.
* This decision must be based on whether there's a non-size-
@@ -808,8 +956,8 @@ get_icon_file_path (const char *name,
path = get_themed_icon_file_path (theme_name,
name,
NAUTILUS_ICON_SIZE_STANDARD,
- NULL,
- aa_mode);
+ aa_mode,
+ details);
if (path != NULL) {
use_theme_icon = TRUE;
g_free (path);
@@ -817,26 +965,26 @@ get_icon_file_path (const char *name,
}
/* Now we know whether or not to use the theme. */
- /* if there's a modifier, try using that first */
-
+
+ /* If there's a modifier, try the modified icon first. */
if (modifier && modifier[0] != '\0') {
- char* modified_name = g_strdup_printf ("%s-%s", name, modifier);
+ name_with_modifier = g_strconcat (name, "-", modifier, NULL);
path = get_themed_icon_file_path (use_theme_icon ? theme_name : NULL,
- modified_name,
+ name_with_modifier,
size_in_pixels,
- icon_info,
- aa_mode);
- g_free (modified_name);
+ aa_mode,
+ details);
+ g_free (name_with_modifier);
if (path != NULL) {
- return path;
+ return path;
}
}
return get_themed_icon_file_path (use_theme_icon ? theme_name : NULL,
name,
size_in_pixels,
- icon_info,
- aa_mode);
+ aa_mode,
+ details);
}
static void
@@ -844,19 +992,14 @@ icon_theme_changed_callback (gpointer user_data)
{
char *theme_preference, *icon_theme;
- theme_preference = nautilus_preferences_get (NAUTILUS_PREFERENCES_THEME,
- DEFAULT_ICON_THEME);
-
- g_assert (theme_preference != NULL);
-
- /* give the theme a chance to redirect the icons */
+ /* Consult the user preference and the Nautilus theme. In the
+ * long run, we sould just get rid of the user preference.
+ */
+ theme_preference = nautilus_preferences_get
+ (NAUTILUS_PREFERENCES_THEME, DEFAULT_ICON_THEME);
icon_theme = nautilus_theme_get_theme_data ("icons", "ICON_THEME");
- if (icon_theme != NULL) {
- nautilus_icon_factory_set_theme (icon_theme);
- } else {
- nautilus_icon_factory_set_theme (theme_preference);
- }
+ set_theme (icon_theme == NULL ? theme_preference : icon_theme);
g_free (theme_preference);
g_free (icon_theme);
@@ -895,10 +1038,10 @@ nautilus_scalable_icon_new_from_text_pieces (const char *uri,
gboolean anti_aliased)
{
GHashTable *hash_table;
- NautilusScalableIcon icon_key, *icon;
+ NautilusScalableIcon cache_key, *icon;
NautilusIconFactory *factory;
- factory = (NautilusIconFactory*) nautilus_icon_factory_get ();
+ factory = get_icon_factory ();
/* Make empty strings canonical. */
if (uri != NULL && uri[0] == '\0') {
uri = NULL;
@@ -914,16 +1057,16 @@ nautilus_scalable_icon_new_from_text_pieces (const char *uri,
}
/* Get at the hash table. */
- hash_table = nautilus_get_current_icon_factory ()->scalable_icons;
+ hash_table = get_icon_factory ()->scalable_icons;
/* Check to see if it's already in the table. */
- icon_key.uri = (char *) uri;
- icon_key.name = (char *) name;
- icon_key.modifier = (char *) modifier;
- icon_key.embedded_text = (char *) embedded_text;
- icon_key.aa_mode = anti_aliased;
+ cache_key.uri = (char *) uri;
+ cache_key.name = (char *) name;
+ cache_key.modifier = (char *) modifier;
+ cache_key.embedded_text = (char *) embedded_text;
+ cache_key.aa_mode = anti_aliased;
- icon = g_hash_table_lookup (hash_table, &icon_key);
+ icon = g_hash_table_lookup (hash_table, &cache_key);
if (icon == NULL) {
/* Not in the table, so create it and put it in. */
icon = g_new0 (NautilusScalableIcon, 1);
@@ -960,7 +1103,7 @@ nautilus_scalable_icon_unref (NautilusScalableIcon *icon)
return;
}
- hash_table = nautilus_get_current_icon_factory ()->scalable_icons;
+ hash_table = get_icon_factory ()->scalable_icons;
g_hash_table_remove (hash_table, icon);
g_free (icon->uri);
@@ -1068,8 +1211,13 @@ nautilus_icon_factory_get_icon_for_file (NautilusFile *file, const char* modifie
if (nautilus_istr_has_prefix (mime_type, "image/") && should_display_image_file_as_itself (file)) {
if (nautilus_file_get_size (file) < SELF_THUMBNAIL_SIZE_THRESHOLD) {
uri = nautilus_file_get_uri (file);
- } else if (strstr(file_uri, "/.thumbnails/") == NULL) {
- uri = nautilus_icon_factory_get_thumbnail_uri (file, anti_aliased);
+ } else if (strstr (file_uri, "/.thumbnails/") == NULL) {
+ uri = nautilus_get_thumbnail_uri (file, anti_aliased);
+ if (uri == NULL) {
+ get_icon_file_path
+ (ICON_NAME_THUMBNAIL_LOADING, NULL,
+ NAUTILUS_ICON_SIZE_STANDARD, FALSE, NULL);
+ }
}
}
g_free (mime_type);
@@ -1198,336 +1346,6 @@ nautilus_icon_factory_get_emblem_icons_for_file (NautilusFile *file, gboolean an
return g_list_reverse (icons);
}
-/* utility to test whether a file exists using vfs */
-static gboolean
-vfs_file_exists (const char *file_uri)
-{
- GnomeVFSResult result;
- GnomeVFSFileInfo *file_info;
-
- file_info = gnome_vfs_file_info_new ();
-
- /* FIXME bugzilla.eazel.com 3137: the synchronous I/O here means this call is
- unsuitable for use on anything that might be remote. */
-
- result = gnome_vfs_get_file_info (file_uri, file_info, 0);
- gnome_vfs_file_info_unref (file_info);
- return result == GNOME_VFS_OK;
-}
-
-/* FIXME bugzilla.eazel.com 3138: why is this call cut and pasted instead
- of putting it in a common place? */
-
-/* utility copied from Nautilus directory */
-static GnomeVFSResult
-nautilus_make_directory_and_parents (GnomeVFSURI *uri, guint permissions)
-{
- GnomeVFSResult result;
- GnomeVFSURI *parent_uri;
-
- /* FIXME bugzilla.eazel.com 3137: the synchronous I/O in this
- call means it's unsuitable for calling on a URI that might
- be remote. */
-
- /* Make the directory, and return right away unless there's
- a possible problem with the parent.
- */
- result = gnome_vfs_make_directory_for_uri (uri, permissions);
- if (result != GNOME_VFS_ERROR_NOT_FOUND) {
- return result;
- }
-
- /* If we can't get a parent, we are done. */
- parent_uri = gnome_vfs_uri_get_parent (uri);
- if (parent_uri == NULL) {
- return result;
- }
-
- /* If we can get a parent, use a recursive call to create
- the parent and its parents.
- */
- result = nautilus_make_directory_and_parents (parent_uri, permissions);
- gnome_vfs_uri_unref (parent_uri);
- if (result != GNOME_VFS_OK) {
- return result;
- }
-
- /* A second try at making the directory after the parents
- have all been created.
- */
- result = gnome_vfs_make_directory_for_uri (uri, permissions);
- return result;
-}
-
-/* utility routine that, given the uri of an image, constructs the uri to the corresponding thumbnail */
-
-static char *
-make_thumbnail_path (const char *image_uri, gboolean directory_only, gboolean use_local_directory, gboolean anti_aliased)
-{
- char *thumbnail_uri, *thumbnail_path;
- char *directory_name = g_strdup (image_uri);
- char *last_slash = strrchr (directory_name, '/');
- char *dot_pos;
-
- *last_slash = '\0';
-
- /* either use the local directory or one in the user's home directory, as selected by the passed in flag */
- if (use_local_directory)
- thumbnail_uri = g_strdup_printf ("%s/.thumbnails", directory_name);
- else {
- GnomeVFSResult result;
- GnomeVFSURI *thumbnail_directory_uri;
-
- char *escaped_uri = gnome_vfs_escape_slashes (directory_name);
- thumbnail_path = g_strdup_printf ("%s/.nautilus/thumbnails/%s", g_get_home_dir(), escaped_uri);
- thumbnail_uri = gnome_vfs_get_uri_from_local_path (thumbnail_path);
- g_free (thumbnail_path);
- g_free(escaped_uri);
-
- /* we must create the directory if it doesnt exist */
-
- thumbnail_directory_uri = gnome_vfs_uri_new (thumbnail_uri);
-
- /* FIXME bugzilla.eazel.com 3137: synchronous I/O - it
- looks like the URI will be local-only, but best to
- make sure. */
-
- result = nautilus_make_directory_and_parents (thumbnail_directory_uri, THUMBNAIL_DIR_PERMISSIONS);
- gnome_vfs_uri_unref (thumbnail_directory_uri);
- }
-
- /* append the file name if necessary */
- if (!directory_only) {
- char* old_uri = thumbnail_uri;
- thumbnail_uri = g_strdup_printf ("%s/%s", thumbnail_uri, last_slash + 1);
- g_free(old_uri);
-
- /* append the anti-aliased suffix if necessary */
- if (anti_aliased) {
- char *old_uri = thumbnail_uri;
- dot_pos = strrchr (thumbnail_uri, '.');
- if (dot_pos) {
- *dot_pos = '\0';
- thumbnail_uri = g_strdup_printf ("%s.aa.%s", old_uri, dot_pos + 1);
- } else {
- thumbnail_uri = g_strconcat (old_uri, ".aa", NULL);
- }
- g_free (old_uri);
- }
-
- /* append an image suffix if the correct one isn't already present */
- if (!nautilus_istr_has_suffix (image_uri, ".png")) {
- char* old_uri = thumbnail_uri;
- thumbnail_uri = g_strdup_printf ("%s.png", thumbnail_uri);
- g_free(old_uri);
- }
- }
-
- g_free (directory_name);
- return thumbnail_uri;
-}
-
-/* utility routine that takes two uris and returns true if the first file has been modified later than the second */
-/* FIXME bugzilla.eazel.com 2565: it makes synchronous file info calls, so for now, it returns FALSE if either of the uri's are non-local */
-static gboolean
-first_file_more_recent(const char* file_uri, const char* other_file_uri)
-{
- GnomeVFSURI *vfs_uri, *other_vfs_uri;
- gboolean more_recent, is_local;
-
- GnomeVFSFileInfo file_info, other_file_info;
-
- /* if either file is remote, return FALSE. Eventually we'll make this async to fix this */
- vfs_uri = gnome_vfs_uri_new(file_uri);
- other_vfs_uri = gnome_vfs_uri_new(other_file_uri);
- is_local = gnome_vfs_uri_is_local (vfs_uri) && gnome_vfs_uri_is_local (other_vfs_uri);
- gnome_vfs_uri_unref(vfs_uri);
- gnome_vfs_uri_unref(other_vfs_uri);
-
- if (!is_local) {
- return FALSE;
- }
-
- /* gather the info and then compare modification times */
- gnome_vfs_file_info_init (&file_info);
- gnome_vfs_get_file_info (file_uri, &file_info, GNOME_VFS_FILE_INFO_DEFAULT);
-
- gnome_vfs_file_info_init (&other_file_info);
- gnome_vfs_get_file_info (other_file_uri, &other_file_info, GNOME_VFS_FILE_INFO_DEFAULT);
-
- more_recent = file_info.mtime > other_file_info.mtime;
-
- gnome_vfs_file_info_clear (&file_info);
- gnome_vfs_file_info_clear (&other_file_info);
-
- return more_recent;
-}
-
-/* structure used for making thumbnails, associating a uri with where the thumbnail is to be stored */
-
-typedef struct {
- char *thumbnail_uri;
- gboolean is_local;
- gboolean anti_aliased;
-} NautilusThumbnailInfo;
-
-/* GCompareFunc-style function for comparing NautilusThumbnailInfos.
- * Returns 0 if they refer to the same uri.
- */
-static int
-compare_thumbnail_info (gconstpointer a, gconstpointer b)
-{
- NautilusThumbnailInfo *info_a;
- NautilusThumbnailInfo *info_b;
-
- info_a = (NautilusThumbnailInfo *)a;
- info_b = (NautilusThumbnailInfo *)b;
-
- return strcmp (info_a->thumbnail_uri, info_b->thumbnail_uri) != 0;
-}
-
-/* routine that takes a uri of a large image file and returns the uri of its corresponding thumbnail.
- If no thumbnail is available, put the image on the thumbnail queue so one is eventually made. */
-/* FIXME bugzilla.eazel.com 642:
- * Most of this thumbnail machinery belongs in NautilusFile, not here.
- */
-
-static char *
-nautilus_icon_factory_get_thumbnail_uri (NautilusFile *file, gboolean anti_aliased)
-{
- NautilusIconFactory *factory;
- GnomeVFSResult result;
- char *thumbnail_uri;
- char *file_uri;
- gboolean local_flag = TRUE;
- gboolean remake_thumbnail = FALSE;
-
- file_uri = nautilus_file_get_uri (file);
-
- /* compose the uri for the thumbnail locally */
- thumbnail_uri = make_thumbnail_path (file_uri, FALSE, TRUE, anti_aliased);
-
- /* if the thumbnail file already exists locally, simply return the uri */
-
- /* FIXME bugzilla.eazel.com 3137: this synchronous I/O is a
- disaster when loading remote locations. It blocks the UI
- when trying to load a slow remote image over http for
- instance. The fact that we must do this potentially slow
- operation implies the IconFactory interface needs to be
- asynchronous! Either that, or thumbnail existence is
- somthing we need to be able to monitor/call_when_ready on,
- on a NautilusFile. */
-
- if (vfs_file_exists (thumbnail_uri)) {
-
- /* see if the file changed since it was thumbnailed by comparing the modification time */
- remake_thumbnail = first_file_more_recent(file_uri, thumbnail_uri);
-
- /* if the file hasn't changed, return the thumbnail uri */
- if (!remake_thumbnail) {
- g_free (file_uri);
- return thumbnail_uri;
- } else {
- nautilus_icon_factory_clear_image(thumbnail_uri);
-
-
- /* FIXME bugzilla.eazel.com 3137: more potentially
- losing synch I/O. */
-
- gnome_vfs_unlink(thumbnail_uri);
- }
- }
-
- /* now try it globally */
- if (!remake_thumbnail) {
- g_free (thumbnail_uri);
- thumbnail_uri = make_thumbnail_path (file_uri, FALSE, FALSE, anti_aliased);
-
- /* if the thumbnail file already exists in the common area, return that uri */
-
- /* FIXME bugzilla.eazel.com 3137: more potentially losing
- synch I/O - this should be guaranteed local, so
- perhaps not as bad (unless you have an NFS homedir,
- say... */
-
- if (vfs_file_exists (thumbnail_uri)) {
-
- /* see if the file changed since it was thumbnailed by comparing the modification time */
- remake_thumbnail = first_file_more_recent(file_uri, thumbnail_uri);
-
- /* if the file hasn't changed, return the thumbnail uri */
- if (!remake_thumbnail) {
- g_free (file_uri);
- return thumbnail_uri;
- } else {
- nautilus_icon_factory_clear_image(thumbnail_uri);
- /* FIXME bugzilla.eazel.com 3137: more potentially losing
- synch I/O - this should be guaranteed local, so
- perhaps not as bad (unless you have an NFS homedir,
- say... */
- gnome_vfs_unlink(thumbnail_uri);
- }
- }
- }
-
- /* make the thumbnail directory if necessary, at first try it locally */
- g_free (thumbnail_uri);
- local_flag = TRUE;
- thumbnail_uri = make_thumbnail_path (file_uri, TRUE, local_flag, anti_aliased);
-
-
- /* FIXME bugzilla.eazel.com 3137: more potentially losing
- synch I/O - this could be remote */
-
- result = gnome_vfs_make_directory (thumbnail_uri, THUMBNAIL_DIR_PERMISSIONS);
-
- /* if we can't make if locally, try it in the global place */
- if (result != GNOME_VFS_OK && result != GNOME_VFS_ERROR_FILE_EXISTS) {
- g_free (thumbnail_uri);
- local_flag = FALSE;
- thumbnail_uri = make_thumbnail_path (file_uri, TRUE, local_flag, anti_aliased);
- /* FIXME bugzilla.eazel.com 3137: more potentially
- losing synch I/O - this is probably local? */
-
- result = gnome_vfs_make_directory (thumbnail_uri, THUMBNAIL_DIR_PERMISSIONS);
- }
-
- /* the thumbnail needs to be created (or recreated), so add an entry to the thumbnail list */
-
- if (result != GNOME_VFS_OK && result != GNOME_VFS_ERROR_FILE_EXISTS) {
-
- g_warning ("error when making thumbnail directory %d, for %s", result, thumbnail_uri);
- } else {
- NautilusThumbnailInfo *info = g_new0 (NautilusThumbnailInfo, 1);
- info->thumbnail_uri = file_uri;
- info->is_local = local_flag;
- info->anti_aliased = anti_aliased;
-
- factory = nautilus_get_current_icon_factory ();
- if (factory->thumbnails) {
- if (g_list_find_custom (factory->thumbnails, info, compare_thumbnail_info) == NULL) {
- factory->thumbnails = g_list_prepend (factory->thumbnails, info);
- }
- } else {
- factory->thumbnails = g_list_alloc ();
- factory->thumbnails->data = info;
- }
-
- if (factory->timeout_task_id == 0) {
- factory->timeout_task_id = gtk_timeout_add (400, (GtkFunction) nautilus_icon_factory_make_thumbnails, NULL);
- }
- }
-
- g_free (thumbnail_uri);
-
- /* return the uri to the "loading image" icon */
- return get_icon_file_path (ICON_NAME_THUMBNAIL_LOADING,
- NULL,
- NAUTILUS_ICON_SIZE_STANDARD,
- NULL,
- FALSE);
-}
-
static guint
get_larger_icon_size (guint size)
{
@@ -1615,20 +1433,19 @@ get_next_icon_size_to_try (guint target_size, guint *current_size)
/* This loads an SVG image, scaling it to the appropriate size. */
static GdkPixbuf *
-load_specific_image_svg (const char *path, guint size_in_pixels)
+load_pixbuf_svg (const char *path, guint size_in_pixels)
{
FILE *f;
- GdkPixbuf *result;
-
+ GdkPixbuf *pixbuf;
+
f = fopen (path, "rb");
if (f == NULL) {
return NULL;
}
- result = rsvg_render_file (f, size_in_pixels *
- (1.0 / NAUTILUS_ICON_SIZE_STANDARD));
+ pixbuf = rsvg_render_file (f, ((double) size_in_pixels) / NAUTILUS_ICON_SIZE_STANDARD);
fclose (f);
-
- return result;
+
+ return pixbuf;
}
static gboolean
@@ -1653,75 +1470,76 @@ path_represents_svg_image (const char *path)
return is_svg;
}
-/* This load function returns NULL if the icon is not available at this size. */
-static GdkPixbuf *
-load_specific_image (NautilusScalableIcon *scalable_icon,
- guint size_in_pixels,
- gboolean custom,
- IconInfo *icon_info)
+/* This load function returns NULL if the icon is not available at
+ * this size.
+ */
+static CacheIcon *
+load_specific_icon (NautilusScalableIcon *scalable_icon,
+ guint size_in_pixels,
+ gboolean custom)
{
- char *image_path;
+ IconDetails details;
GdkPixbuf *pixbuf;
-
- g_assert (icon_info != NULL);
+ char *path;
+ CacheIcon *icon;
- if (custom) {
- /* Custom icon. */
+ memset (&details, 0, sizeof (details));
+ pixbuf = NULL;
- memset (&icon_info->text_rect, 0, sizeof (icon_info->text_rect));
- icon_info->has_attach_points = FALSE;
-
- /* we use the suffix instead of mime-type here since it may be non-local */
- if (nautilus_istr_has_suffix (scalable_icon->uri, ".svg")) {
- image_path = gnome_vfs_get_local_path_from_uri (scalable_icon->uri);
- pixbuf = load_specific_image_svg (image_path, size_in_pixels);
- g_free (image_path);
- return pixbuf;
- }
-
- if (size_in_pixels == NAUTILUS_ICON_SIZE_STANDARD && scalable_icon->uri != NULL) {
- return nautilus_gdk_pixbuf_load (scalable_icon->uri);
- }
-
- return NULL;
+ /* Get the path. */
+ if (custom) {
+ /* We don't support custom icons that are not local here. */
+ path = gnome_vfs_get_local_path_from_uri (scalable_icon->uri);
} else {
- /* Standard icon. */
- char *path;
- GdkPixbuf *image;
-
path = get_icon_file_path (scalable_icon->name,
scalable_icon->modifier,
size_in_pixels,
- icon_info,
- scalable_icon->aa_mode);
-
- if (path == NULL) {
- return NULL;
- }
+ scalable_icon->aa_mode,
+ &details);
+ }
+ /* Get the icon. */
+ if (path != NULL) {
if (path_represents_svg_image (path)) {
- image = load_specific_image_svg (path, size_in_pixels);
+ pixbuf = load_pixbuf_svg (path, size_in_pixels);
} else {
- image = gdk_pixbuf_new_from_file (path);
+ /* Custom non-svg icons exist at one size.
+ * Non-custom icons have their size encoded in their path.
+ */
+ if (!(custom && size_in_pixels != NAUTILUS_ICON_SIZE_STANDARD)) {
+ pixbuf = gdk_pixbuf_new_from_file (path);
+ }
}
-
+
g_free (path);
- return image;
}
+
+ /* If we got nothing, we can free the icon. */
+ if (pixbuf == NULL) {
+ return NULL;
+ }
+
+ /* Since we got something, we can create a cache icon. */
+ icon = cache_icon_new (pixbuf, custom, FALSE, &details);
+ gdk_pixbuf_unref (pixbuf);
+ return icon;
+}
+
+static void
+destroy_fallback_icon (void)
+{
+ cache_icon_unref (fallback_icon);
}
/* This load function is not allowed to return NULL. */
-static GdkPixbuf *
-load_image_for_scaling (NautilusScalableIcon *scalable_icon,
- guint requested_size,
- guint *actual_size_result,
- gboolean *custom,
- IconInfo *icon_info)
+static CacheIcon *
+load_icon_for_scaling (NautilusScalableIcon *scalable_icon,
+ guint requested_size,
+ guint *actual_size_result)
{
- GdkPixbuf *image;
+ CacheIcon *icon;
guint actual_size;
IconSizeRequest size_request;
- static GdkPixbuf *fallback_image;
size_request.maximum_width = MAXIMUM_ICON_SIZE * requested_size / NAUTILUS_ZOOM_LEVEL_STANDARD;
size_request.maximum_height = size_request.maximum_width;
@@ -1732,15 +1550,11 @@ load_image_for_scaling (NautilusScalableIcon *scalable_icon,
size_request.nominal_width = actual_size;
size_request.nominal_height = actual_size;
- image = get_image_from_cache (scalable_icon,
- &size_request,
- TRUE,
- TRUE,
- icon_info);
- if (image != NULL) {
+ icon = get_icon_from_cache
+ (scalable_icon, &size_request, TRUE, TRUE);
+ if (icon != NULL) {
*actual_size_result = actual_size;
- *custom = TRUE;
- return image;
+ return icon;
}
}
@@ -1750,21 +1564,18 @@ load_image_for_scaling (NautilusScalableIcon *scalable_icon,
size_request.nominal_width = actual_size;
size_request.nominal_height = actual_size;
- image = get_image_from_cache (scalable_icon,
- &size_request,
- TRUE,
- FALSE,
- icon_info);
- if (image != NULL) {
+ icon = get_icon_from_cache
+ (scalable_icon, &size_request, TRUE, FALSE);
+ if (icon != NULL) {
*actual_size_result = actual_size;
- *custom = FALSE;
- return image;
+ return icon;
}
}
/* Finally, fall back on the hard-coded image. */
- if (fallback_image == NULL) {
- fallback_image = gdk_pixbuf_new_from_data
+ if (fallback_icon == NULL) {
+ fallback_icon = g_new0 (CacheIcon, 1);
+ fallback_icon->pixbuf = gdk_pixbuf_new_from_data
(nautilus_default_file_icon,
GDK_COLORSPACE_RGB,
TRUE,
@@ -1774,36 +1585,38 @@ load_image_for_scaling (NautilusScalableIcon *scalable_icon,
nautilus_default_file_icon_width * 4, /* stride */
NULL, /* don't destroy data */
NULL);
+ g_atexit (destroy_fallback_icon);
}
- gdk_pixbuf_ref (fallback_image);
+ cache_icon_ref (fallback_icon);
- memset (&icon_info->text_rect, 0, sizeof (icon_info->text_rect));
*actual_size_result = NAUTILUS_ICON_SIZE_STANDARD;
- *custom = FALSE;
- return fallback_image;
+ return fallback_icon;
}
-/* Consumes the image and returns a scaled one if the image is too big.
- * Note that this does an unref on the image and returns a new one.
+/* Consumes the icon and returns a scaled one if the pixbuf is too big.
+ * Note that this does an unref on the icon and returns a new one.
*/
-static GdkPixbuf *
-scale_image_and_info (GdkPixbuf *image,
- IconInfo *icon_info,
- double scale_x,
- double scale_y)
+static CacheIcon *
+scale_icon (CacheIcon *icon,
+ double scale_x,
+ double scale_y)
{
int width, height;
int rect_width, rect_height;
- int index;
- GdkPixbuf *scaled_image;
+ int i, num_points;
+ GdkPixbuf *scaled_pixbuf;
+ IconDetails scaled_details;
+ CacheIcon *scaled_icon;
- width = gdk_pixbuf_get_width (image);
- height = gdk_pixbuf_get_height (image);
+ g_assert (!icon->scaled);
+
+ width = gdk_pixbuf_get_width (icon->pixbuf);
+ height = gdk_pixbuf_get_height (icon->pixbuf);
/* Check for no-scaling case. */
if ((int) (width * scale_x) == width
&& (int) (height * scale_y) == height) {
- return gdk_pixbuf_ref (image);
+ return NULL;
}
width *= scale_x;
@@ -1815,30 +1628,34 @@ scale_image_and_info (GdkPixbuf *image,
height = 1;
}
- rect_width = (icon_info->text_rect.x1 - icon_info->text_rect.x0) * scale_x;
- rect_height = (icon_info->text_rect.y1 - icon_info->text_rect.y0) * scale_y;
+ scaled_pixbuf = gdk_pixbuf_scale_simple
+ (icon->pixbuf, width, height, GDK_INTERP_BILINEAR);
+
+ rect_width = (icon->details.text_rect.x1 - icon->details.text_rect.x0) * scale_x;
+ rect_height = (icon->details.text_rect.y1 - icon->details.text_rect.y0) * scale_y;
- scaled_image = gdk_pixbuf_scale_simple
- (image, width, height, GDK_INTERP_BILINEAR);
- gdk_pixbuf_unref (image);
-
- icon_info->text_rect.x0 *= scale_x;
- icon_info->text_rect.y0 *= scale_y;
- icon_info->text_rect.x1 = icon_info->text_rect.x0 + rect_width;
- icon_info->text_rect.y1 = icon_info->text_rect.y0 + rect_height;
-
- if (icon_info->has_attach_points) {
- for (index = 0; index < MAX_ATTACH_POINTS; index++) {
- icon_info->attach_points[index].x *= scale_x;
- icon_info->attach_points[index].y *= scale_y;
- }
+ scaled_details.text_rect.x0 = icon->details.text_rect.x0 * scale_x;
+ scaled_details.text_rect.y0 = icon->details.text_rect.x0 * scale_y;
+ scaled_details.text_rect.x1 = scaled_details.text_rect.x0 + rect_width;
+ scaled_details.text_rect.y1 = scaled_details.text_rect.y0 + rect_height;
+
+ num_points = icon->details.attach_points.num_points;
+ scaled_details.attach_points.num_points = num_points;
+ for (i = 0; i < num_points; i++) {
+ scaled_details.attach_points.points[i].x = icon->details.attach_points.points[i].x * scale_x;
+ scaled_details.attach_points.points[i].y = icon->details.attach_points.points[i].y * scale_y;
}
- return scaled_image;
+ scaled_icon = cache_icon_new (scaled_pixbuf,
+ icon->custom,
+ TRUE,
+ &scaled_details);
+ gdk_pixbuf_unref (scaled_pixbuf);
+ return scaled_icon;
}
static void
-revise_scale_factors_if_too_big (GdkPixbuf *image,
+revise_scale_factors_if_too_big (GdkPixbuf *pixbuf,
const IconSizeRequest *size,
double *scale_x,
double *scale_y)
@@ -1846,8 +1663,8 @@ revise_scale_factors_if_too_big (GdkPixbuf *image,
int width, height;
double y_distortion;
- width = gdk_pixbuf_get_width (image);
- height = gdk_pixbuf_get_height (image);
+ width = gdk_pixbuf_get_width (pixbuf);
+ height = gdk_pixbuf_get_height (pixbuf);
if ((int) (width * *scale_x) <= size->maximum_width
&& (int) (height * *scale_y) <= size->maximum_height) {
@@ -1861,49 +1678,46 @@ revise_scale_factors_if_too_big (GdkPixbuf *image,
*scale_y = *scale_x * y_distortion;
}
-/* Consumes the image and returns a scaled one if the image is too big.
- * Note that this does an unref on the image and returns a new one.
- */
-static GdkPixbuf *
-scale_image_down_if_too_big (GdkPixbuf *image,
- const IconSizeRequest *size,
- IconInfo *icon_info)
+/* Returns a scaled icon if this one is too big. */
+static CacheIcon *
+scale_down_if_too_big (CacheIcon *icon,
+ const IconSizeRequest *size)
{
double scale_x, scale_y;
scale_x = 1.0;
scale_y = 1.0;
- revise_scale_factors_if_too_big (image, size, &scale_x, &scale_y);
- return scale_image_and_info (image, icon_info, scale_x, scale_y);
+ revise_scale_factors_if_too_big (icon->pixbuf, size, &scale_x, &scale_y);
+ return scale_icon (icon, scale_x, scale_y);
}
/* This load function is not allowed to return NULL. */
-static GdkPixbuf *
-load_image_scale_if_necessary (NautilusScalableIcon *scalable_icon,
- const IconSizeRequest *size,
- gboolean *scaled,
- gboolean *custom,
- IconInfo *icon_info)
+static CacheIcon *
+load_icon_scale_if_necessary (NautilusScalableIcon *scalable_icon,
+ const IconSizeRequest *size)
{
- GdkPixbuf *image;
+ CacheIcon *icon, *scaled_icon;
guint nominal_actual_size;
double scale_x, scale_y;
- /* Load the image for the icon that's closest in size to what we want. */
- image = load_image_for_scaling (scalable_icon, size->nominal_width,
- &nominal_actual_size, custom, icon_info);
- if (size->nominal_width == nominal_actual_size
- && size->nominal_height == nominal_actual_size) {
- *scaled = FALSE;
- return scale_image_down_if_too_big (image, size, icon_info);
- }
+ /* Load the icon that's closest in size to what we want. */
+ icon = load_icon_for_scaling (scalable_icon,
+ size->nominal_width,
+ &nominal_actual_size);
- /* Scale the image to the size we want. */
- *scaled = TRUE;
+ /* Scale the pixbuf to the size we want. */
scale_x = (double) size->nominal_width / nominal_actual_size;
scale_y = (double) size->nominal_height / nominal_actual_size;
- revise_scale_factors_if_too_big (image, size, &scale_x, &scale_y);
- return scale_image_and_info (image, icon_info, scale_x, scale_y);
+ revise_scale_factors_if_too_big (icon->pixbuf, size, &scale_x, &scale_y);
+ scaled_icon = scale_icon (icon, scale_x, scale_y);
+ if (scaled_icon == NULL) {
+ return icon;
+ }
+
+ /* Mark this icon as scaled, too. */
+ cache_icon_unref (icon);
+ g_assert (scaled_icon->scaled);
+ return scaled_icon;
}
/* Move this item to the head of the recently-used list,
@@ -1915,7 +1729,9 @@ mark_recently_used (NautilusCircularList *node)
NautilusIconFactory *factory;
NautilusCircularList *head, *last_node;
- factory = nautilus_get_current_icon_factory ();
+ check_recently_used_list ();
+
+ factory = get_icon_factory ();
head = &factory->recently_used_dummy_head;
/* Move the node to the start of the list. */
@@ -1928,9 +1744,9 @@ mark_recently_used (NautilusCircularList *node)
/* Node was not already in the list, so add it.
* If the list is already full, remove the last node.
*/
- if (factory->recently_used_count < ICON_CACHE_COUNT)
- factory->recently_used_count++;
- else {
+ if (factory->recently_used_count < ICON_CACHE_COUNT) {
+ factory->recently_used_count += 1;
+ } else {
/* Remove the last node. */
last_node = head->prev;
@@ -1951,101 +1767,104 @@ mark_recently_used (NautilusCircularList *node)
node->next->prev = node;
head->next = node;
}
+
+ check_recently_used_list ();
}
-/* utility routine that checks if a cached image has changed since it was cached.
- * It returns TRUE if the image is still valid, and removes it from the cache if it's not */
-
- static gboolean
- cached_image_still_valid (const char *file_uri, time_t cached_time)
- {
+/* Utility routine that checks if a cached icon has changed since it
+ * was cached. It returns TRUE if the icon is still valid, and
+ * removes it from the cache if it's not.
+ */
+static gboolean
+cached_icon_still_valid (const char *file_uri, time_t cached_time)
+{
GnomeVFSURI *vfs_uri;
GnomeVFSFileInfo file_info;
+ GnomeVFSResult result;
gboolean is_local, is_valid;
- /* if there's no specific file, simply return TRUE */
- if (file_uri == NULL)
+ /* If there's no specific file, simply return TRUE. */
+ if (file_uri == NULL) {
return TRUE;
+ }
- /* FIXME bugzilla.eazel.com 2566: if the URI is remote, assume it's valid to avoid delay of testing. Eventually we'll make this async to fix this */
- vfs_uri = gnome_vfs_uri_new(file_uri);
+ /* FIXME bugzilla.eazel.com 2566: if the URI is remote, assume
+ * it's valid to avoid delay of testing. Eventually we'll have
+ * to make this async to fix this.
+ */
+ vfs_uri = gnome_vfs_uri_new (file_uri);
is_local = gnome_vfs_uri_is_local (vfs_uri);
- gnome_vfs_uri_unref(vfs_uri);
+ gnome_vfs_uri_unref (vfs_uri);
if (!is_local) {
return TRUE;
}
- /* gather the info and then compare modification times */
+ /* Gather the info and then compare modification times. */
gnome_vfs_file_info_init (&file_info);
- gnome_vfs_get_file_info (file_uri, &file_info, GNOME_VFS_FILE_INFO_DEFAULT);
-
- is_valid = file_info.mtime <= cached_time;
+ result = gnome_vfs_get_file_info (file_uri, &file_info, GNOME_VFS_FILE_INFO_DEFAULT);
+ is_valid = result == GNOME_VFS_OK && file_info.mtime <= cached_time;
gnome_vfs_file_info_clear (&file_info);
/* if it's not valid, remove it from the cache */
if (!is_valid) {
- nautilus_icon_factory_clear_image (file_uri);
+ nautilus_icon_factory_remove_by_uri (file_uri);
}
return is_valid;
- }
-
-/* Get the image for icon, handling the caching.
+}
+
+/* Get the icon, handling the caching.
* If @picky is true, then only an unscaled icon is acceptable.
* Also, if @picky is true, the icon must be a custom icon if
* @custom is true or a standard icon is @custom is false.
*/
-static GdkPixbuf *
-get_image_from_cache (NautilusScalableIcon *scalable_icon,
- const IconSizeRequest *size,
- gboolean picky,
- gboolean custom,
- IconInfo *icon_info)
+static CacheIcon *
+get_icon_from_cache (NautilusScalableIcon *scalable_icon,
+ const IconSizeRequest *size,
+ gboolean picky,
+ gboolean custom)
{
NautilusIconFactory *factory;
GHashTable *hash_table;
- IconCacheKey lookup_key, *key;
- GdkPixbuf *image;
+ CacheKey lookup_key, *key;
+ CacheIcon *icon, *scaled_icon;
gpointer key_in_table, value;
- gboolean found_image;
g_return_val_if_fail (scalable_icon != NULL, NULL);
key = NULL;
- image = NULL;
+ icon = NULL;
- factory = nautilus_get_current_icon_factory ();
+ factory = get_icon_factory ();
hash_table = factory->icon_cache;
/* Check to see if it's already in the table. */
lookup_key.scalable_icon = scalable_icon;
lookup_key.size = *size;
- found_image = FALSE;
if (g_hash_table_lookup_extended (hash_table, &lookup_key,
&key_in_table, &value)) {
/* Found it in the table. */
+ g_assert (key_in_table != NULL);
+ g_assert (value != NULL);
key = key_in_table;
+ icon = value;
/* If we're going to be picky, then don't accept anything
* other than exactly what we are looking for.
*/
- if (picky && (key->scaled || custom != key->custom)) {
+ if (picky && (icon->scaled || custom != icon->custom)) {
return NULL;
}
- image = value;
- found_image = cached_image_still_valid (scalable_icon->uri, key->cache_time);
- g_assert (image != NULL);
+ /* Check if the cached image is good before using it. */
+ if (!cached_icon_still_valid (scalable_icon->uri,
+ icon->cache_time)) {
+ icon = NULL;
+ }
}
- if (!found_image) {
- gboolean got_scaled_image;
- gboolean got_custom_image;
- IconInfo key_icon_info;
-
- key_icon_info.has_attach_points = FALSE;
-
+ if (icon == NULL) {
/* Not in the table, so load the image. */
/* If we're picky, then we want the image only if this exact
* nominal size is available.
@@ -2054,80 +1873,59 @@ get_image_from_cache (NautilusScalableIcon *scalable_icon,
g_assert (scalable_icon->embedded_text == NULL);
/* Actual icons have nominal sizes that are square! */
- if (size->nominal_width
- != size->nominal_height) {
+ if (size->nominal_width != size->nominal_height) {
return NULL;
}
/* Get the image. */
- image = load_specific_image (scalable_icon,
- size->nominal_width,
- custom,
- &key_icon_info);
- if (image == NULL) {
+ icon = load_specific_icon (scalable_icon,
+ size->nominal_width,
+ custom);
+ if (icon == NULL) {
return NULL;
}
- /* Now we have the image, but is it bigger than
- * the maximum size? If so we scale it, even but we don't
- * call it "scaled" for caching purposese.
+ /* Now we have the image, but is it bigger
+ * than the maximum size? If so we scale it,
+ * but we don't call it "scaled" for caching
+ * purposese.
*/
- image = scale_image_down_if_too_big (image, size, &key_icon_info);
-
- got_scaled_image = FALSE;
- got_custom_image = custom;
+ scaled_icon = scale_down_if_too_big (icon, size);
+ if (scaled_icon != NULL) {
+ scaled_icon->scaled = FALSE;
+ cache_icon_unref (icon);
+ icon = scaled_icon;
+ }
} else {
if (scalable_icon->embedded_text != NULL) {
- image = load_image_with_embedded_text (scalable_icon, size);
-
- /* None of these matters for an icon with text already embedded.
- * So we fill in with arbitrary values.
- */
- got_scaled_image = FALSE;
- got_custom_image = FALSE;
- memset (&key_icon_info.text_rect, 0, sizeof (key_icon_info.text_rect));
+ icon = load_icon_with_embedded_text (scalable_icon, size);
} else {
- image = load_image_scale_if_necessary
- (scalable_icon,
- size,
- &got_scaled_image,
- &got_custom_image,
- &key_icon_info);
+ icon = load_icon_scale_if_necessary (scalable_icon, size);
}
- g_assert (image != NULL);
+ g_assert (icon != NULL);
}
- /* Add the embedded text. */
-
- /* Create the key for the table. */
- key = g_new0 (IconCacheKey, 1);
+ /* Create the key and icon for the hash table. */
+ key = g_new (CacheKey, 1);
nautilus_scalable_icon_ref (scalable_icon);
key->scalable_icon = scalable_icon;
key->size = *size;
- key->scaled = got_scaled_image;
- key->custom = got_custom_image;
- key->icon_info = key_icon_info;
- key->cache_time = time(NULL);
/* Add the item to the hash table. */
- g_hash_table_insert (hash_table, key, image);
+ g_assert (g_hash_table_lookup (hash_table, key) == NULL);
+ g_hash_table_insert (hash_table, key, icon);
}
- /* Return the icon info if the caller asked for it. */
- if (icon_info != NULL) {
- *icon_info = key->icon_info;
- }
+ /* Hand back a ref to the caller. */
+ cache_icon_ref (icon);
/* Since this item was used, keep it in the cache longer. */
- mark_recently_used (&key->recently_used_node);
+ mark_recently_used (&icon->recently_used_node);
/* Come back later and sweep the cache. */
nautilus_icon_factory_schedule_sweep ();
- /* Grab a ref for the caller. */
- g_assert (image != NULL);
- gdk_pixbuf_ref (image);
- return image;
+ return icon;
}
GdkPixbuf *
@@ -2136,41 +1934,42 @@ nautilus_icon_factory_get_pixbuf_for_icon (NautilusScalableIcon *scalable_icon,
guint nominal_height,
guint maximum_width,
guint maximum_height,
- EmblemAttachPoints *attach_data)
+ NautilusEmblemAttachPoints *attach_points)
{
IconSizeRequest size;
- IconInfo icon_info;
+ CacheIcon *icon;
GdkPixbuf *pixbuf;
- int index;
size.nominal_width = nominal_width;
size.nominal_height = nominal_width;
size.maximum_width = maximum_width;
size.maximum_height = maximum_height;
- pixbuf = get_image_from_cache (scalable_icon, &size,
- FALSE, scalable_icon->uri != NULL,
- &icon_info);
- if (attach_data != NULL) {
- attach_data->has_attach_points = icon_info.has_attach_points;
- for (index = 0; index < MAX_ATTACH_POINTS; index++) {
- attach_data->attach_points[index] = icon_info.attach_points[index];
- }
+ icon = get_icon_from_cache (scalable_icon, &size,
+ FALSE, scalable_icon->uri != NULL);
+
+ if (attach_points != NULL) {
+ *attach_points = icon->details.attach_points;
}
- return pixbuf;
-}
-
+ /* The first time we hand out an icon we just leave it with a
+ * single ref (we'll get called back for the unref), but
+ * subsequent times we add additional refs.
+ */
+ pixbuf = icon->pixbuf;
+ if (!icon->outstanding) {
+ icon->outstanding = TRUE;
+ } else {
+ gdk_pixbuf_ref (pixbuf);
+ }
+ cache_icon_unref (icon);
-static void
-icon_cache_key_destroy (IconCacheKey *key)
-{
- nautilus_scalable_icon_unref (key->scalable_icon);
+ return pixbuf;
}
static guint
-icon_cache_key_hash (gconstpointer p)
+cache_key_hash (gconstpointer p)
{
- const IconCacheKey *key;
+ const CacheKey *key;
key = p;
return (((((((GPOINTER_TO_UINT (key->scalable_icon) << 4)
@@ -2181,9 +1980,9 @@ icon_cache_key_hash (gconstpointer p)
}
static gboolean
-icon_cache_key_equal (gconstpointer a, gconstpointer b)
+cache_key_equal (gconstpointer a, gconstpointer b)
{
- const IconCacheKey *key_a, *key_b;
+ const CacheKey *key_a, *key_b;
key_a = a;
key_b = b;
@@ -2305,290 +2104,117 @@ embed_text (GdkPixbuf *pixbuf_without_text,
const ArtIRect *embedded_text_rect,
const char *text)
{
- if (smooth_graphics) {
- GdkPixbuf *pixbuf_with_text = NULL;
- NautilusScalableFont *font;
- const guint font_size = 9;
- const guint line_offset = 1;
- const guint empty_line_height = font_size / 2;
-
- /* Quick out for the case where there's no place to embed the
- * text or the place is too small or there's no text.
- */
- if (!embedded_text_rect_usable (embedded_text_rect) || nautilus_strlen (text) == 0) {
- return gdk_pixbuf_ref (pixbuf_without_text);
- }
-
- /* FIXME bugzilla.eazel.com 1102: Embedded text should use preferences to determine
- * the font it uses
- */
- font = NAUTILUS_SCALABLE_FONT (nautilus_scalable_font_new ("helvetica", "medium", NULL, NULL));
-
- pixbuf_with_text = gdk_pixbuf_copy (pixbuf_without_text);
-
- nautilus_scalable_font_draw_text_lines (font,
- pixbuf_with_text,
- embedded_text_rect->x0,
- embedded_text_rect->y0,
- embedded_text_rect,
- font_size,
- font_size,
- text,
- GTK_JUSTIFY_LEFT,
- line_offset,
- empty_line_height,
- NAUTILUS_RGB_COLOR_BLACK,
- 255,
- FALSE);
-
- gtk_object_unref (GTK_OBJECT (font));
-
- return pixbuf_with_text;
+ NautilusScalableFont *smooth_font;
+ static GdkFont *font;
+ GdkPixbuf *pixbuf_with_text;
+
+ g_return_val_if_fail (pixbuf_without_text != NULL, NULL);
+ g_return_val_if_fail (embedded_text_rect != NULL, NULL);
+
+ /* Quick out for the case where there's no place to embed the
+ * text or the place is too small or there's no text.
+ */
+ if (!embedded_text_rect_usable (embedded_text_rect) || nautilus_strlen (text) == 0) {
+ return NULL;
}
- else {
- static GdkFont *font;
- GdkPixbuf *pixbuf_with_text;
+ pixbuf_with_text = gdk_pixbuf_copy (pixbuf_without_text);
- g_return_val_if_fail (pixbuf_without_text != NULL, NULL);
- g_return_val_if_fail (embedded_text_rect != NULL, gdk_pixbuf_ref (pixbuf_without_text));
+ if (smooth_graphics) {
+ smooth_font = NAUTILUS_SCALABLE_FONT
+ (nautilus_scalable_font_new
+ (EMBEDDED_TEXT_FONT_FAMILY,
+ EMBEDDED_TEXT_FONT_WEIGHT,
+ EMBEDDED_TEXT_FONT_SLANT,
+ EMBEDDED_TEXT_FONT_SET_WIDTH));
+
+ nautilus_scalable_font_draw_text_lines
+ (smooth_font,
+ pixbuf_with_text,
+ embedded_text_rect->x0,
+ embedded_text_rect->y0,
+ embedded_text_rect,
+ EMBEDDED_TEXT_FONT_SIZE,
+ EMBEDDED_TEXT_FONT_SIZE,
+ text,
+ GTK_JUSTIFY_LEFT,
+ EMBEDDED_TEXT_LINE_OFFSET,
+ EMBEDDED_TEXT_EMPTY_LINE_HEIGHT,
+ NAUTILUS_RGB_COLOR_BLACK,
+ 255,
+ FALSE);
+ gtk_object_unref (GTK_OBJECT (smooth_font));
+ } else {
/* Get the font the first time through. */
if (font == NULL) {
/* FIXME bugzilla.eazel.com 1102: Embedded text should use preferences to determine
* the font it uses
*/
-
- /* for anti-aliased text, we choose a large font and scale it down */
- font = gdk_font_load ("-*-helvetica-medium-r-normal-*-10-*-*-*-*-*-*-*");
- g_return_val_if_fail (font != NULL, gdk_pixbuf_ref (pixbuf_without_text));
+ font = gdk_font_load (_("-*-helvetica-medium-r-normal-*-10-*-*-*-*-*-*-*"));
+ g_return_val_if_fail (font != NULL, NULL);
}
- /* Quick out for the case where there's no place to embed the
- * text or the place is too small or there's no text.
- */
- if (!embedded_text_rect_usable (embedded_text_rect) || nautilus_strlen (text) == 0) {
- return gdk_pixbuf_ref (pixbuf_without_text);
- }
-
- pixbuf_with_text = gdk_pixbuf_copy (pixbuf_without_text);
-
- nautilus_gdk_pixbuf_draw_text (pixbuf_with_text, font, 1.0, embedded_text_rect,
- text, NAUTILUS_RGB_COLOR_BLACK, 0xFF);
- return pixbuf_with_text;
+ nautilus_gdk_pixbuf_draw_text
+ (pixbuf_with_text, font, 1.0, embedded_text_rect,
+ text, NAUTILUS_RGB_COLOR_BLACK, 0xFF);
}
+
+ return pixbuf_with_text;
}
-static GdkPixbuf *
-load_image_with_embedded_text (NautilusScalableIcon *scalable_icon,
- const IconSizeRequest *size)
+static CacheIcon *
+load_icon_with_embedded_text (NautilusScalableIcon *scalable_icon,
+ const IconSizeRequest *size)
{
NautilusScalableIcon *scalable_icon_without_text;
- GdkPixbuf *pixbuf_without_text, *pixbuf;
- IconInfo icon_info;
+ CacheIcon *icon_without_text, *icon_with_text;
+ GdkPixbuf *pixbuf_with_text;
+ IconDetails details;
g_assert (scalable_icon->embedded_text != NULL);
-
+
+ /* Get the icon without text. */
scalable_icon_without_text = nautilus_scalable_icon_new_from_text_pieces
(scalable_icon->uri,
scalable_icon->name,
scalable_icon->modifier,
NULL,
scalable_icon->aa_mode);
-
- pixbuf_without_text = get_image_from_cache
+ icon_without_text = get_icon_from_cache
(scalable_icon_without_text, size,
- FALSE, FALSE, &icon_info);
+ FALSE, FALSE);
nautilus_scalable_icon_unref (scalable_icon_without_text);
- pixbuf = embed_text (pixbuf_without_text,
- &icon_info. text_rect,
- scalable_icon->embedded_text);
- gdk_pixbuf_unref (pixbuf_without_text);
+ /* Create a pixbuf with the text in it. */
+ pixbuf_with_text = embed_text (icon_without_text->pixbuf,
+ &icon_without_text->details.text_rect,
+ scalable_icon->embedded_text);
+ if (pixbuf_with_text == NULL) {
+ return icon_without_text;
+ }
- return pixbuf;
+ /* Create an icon from the new pixbuf. */
+ details = icon_without_text->details;
+ memset (&details.text_rect, 0, sizeof (details.text_rect));
+ icon_with_text = cache_icon_new (pixbuf_with_text,
+ icon_without_text->custom,
+ icon_without_text->scaled,
+ &details);
+ cache_icon_unref (icon_without_text);
+ gdk_pixbuf_unref (pixbuf_with_text);
+
+ return icon_with_text;
}
/* Convenience function for unrefing and then freeing an entire list. */
void
nautilus_scalable_icon_list_free (GList *icon_list)
{
- nautilus_g_list_free_deep_custom (icon_list, (GFunc) nautilus_scalable_icon_unref, NULL);
-}
-
-/* check_for_thumbnails is a utility that checks to see if any of the thumbnails in the pending
- list have been created yet. If it finds one, it removes the elements from the queue and
- returns true, otherwise it returns false */
-static gboolean
-check_for_thumbnails (NautilusIconFactory *factory)
-{
- char *current_thumbnail;
- NautilusThumbnailInfo *info;
- GList *stop_element;
- GList *next_thumbnail;
- NautilusFile *file;
-
- for (next_thumbnail = factory->thumbnails;
- next_thumbnail != NULL;
- next_thumbnail = next_thumbnail->next) {
- info = (NautilusThumbnailInfo*) next_thumbnail->data;
- current_thumbnail = make_thumbnail_path (info->thumbnail_uri, FALSE, info->is_local, info->anti_aliased);
- /* FIXME bugzilla.eazel.com 3137: synchronous I/O */
- if (vfs_file_exists (current_thumbnail)) {
- /* we found one, so update the icon and remove all of the elements up to and including
- this one from the pending list. */
- g_free (current_thumbnail);
- file = nautilus_file_get (info->thumbnail_uri);
-
- if (file != NULL) {
- nautilus_file_changed (file);
- nautilus_file_unref (file);
- }
-
- stop_element = next_thumbnail->next;
- while (factory->thumbnails != stop_element) {
- info = (NautilusThumbnailInfo *) factory->thumbnails->data;
- g_free (info->thumbnail_uri);
- g_free (info);
- factory->thumbnails = g_list_remove_link (factory->thumbnails, factory->thumbnails);
- }
- return TRUE;
- }
-
- g_free (current_thumbnail);
- }
-
- return FALSE;
-}
-
-/* make_thumbnails is invoked periodically as a timer task to launch a task to make thumbnails */
-
-static GdkPixbuf*
-load_thumbnail_frame (gboolean anti_aliased)
-{
- char *image_path;
- GdkPixbuf *frame_image;
-
- /* load the thumbnail frame */
- image_path = nautilus_theme_get_image_path (anti_aliased ? "thumbnail_frame.aa.png" : "thumbnail_frame.png");
- frame_image = gdk_pixbuf_new_from_file (image_path);
- g_free (image_path);
- return frame_image;
-}
-
-static int
-nautilus_icon_factory_make_thumbnails (gpointer data)
-{
- pid_t thumbnail_pid;
- NautilusThumbnailInfo *info;
- NautilusIconFactory *factory = nautilus_get_current_icon_factory();
- GList *next_thumbnail = factory->thumbnails;
- GdkPixbuf *scaled_image, *framed_image, *thumbnail_image_frame;
- char *frame_offset_str;
- int left_offset, top_offset, right_offset, bottom_offset;
-
- /* if the queue is empty, there's nothing more to do */
- if (next_thumbnail == NULL) {
- gtk_timeout_remove (factory->timeout_task_id);
- factory->timeout_task_id = 0;
- return FALSE;
- }
-
- info = (NautilusThumbnailInfo *) next_thumbnail->data;
-
- /* see which state we're in. If a thumbnail isn't in progress, start one up. Otherwise,
- check if the pending one is completed. */
- if (factory->thumbnail_in_progress) {
- if (check_for_thumbnails(factory)) {
- factory->thumbnail_in_progress = FALSE;
- }
- }
- else {
- /* start up a task to make the thumbnail corresponding to the queue element. */
-
- /* First, compute the path name of the target thumbnail */
- g_free (factory->new_thumbnail_path);
- factory->new_thumbnail_path = make_thumbnail_path (info->thumbnail_uri, FALSE, info->is_local, info->anti_aliased);
-
- /* fork a task to make the thumbnail, using gdk-pixbuf to do the scaling */
- if (!(thumbnail_pid = fork())) {
- GdkPixbuf* full_size_image;
- NautilusFile *file;
- char *thumbnail_path;
-
- file = nautilus_file_get (info->thumbnail_uri);
- full_size_image = NULL;
-
- if (nautilus_file_is_mime_type (file, "image/svg")) {
- thumbnail_path = gnome_vfs_get_local_path_from_uri (info->thumbnail_uri);
- if (thumbnail_path != NULL) {
- FILE *f = fopen (thumbnail_path, "rb");
- if (f != NULL) {
- full_size_image = rsvg_render_file (f, 1.0);
- fclose (f);
- }
- }
- } else {
- if (info->thumbnail_uri != NULL)
- full_size_image = nautilus_gdk_pixbuf_load (info->thumbnail_uri);
- }
- nautilus_file_unref (file);
-
- if (full_size_image != NULL) {
- thumbnail_image_frame = load_thumbnail_frame (info->anti_aliased);
-
- /* scale the content image as necessary */
- scaled_image = nautilus_gdk_pixbuf_scale_down_to_fit(full_size_image, 96, 96);
- gdk_pixbuf_unref (full_size_image);
-
- /* embed the content image in the frame */
- frame_offset_str = nautilus_theme_get_theme_data ("thumbnails", "FRAME_OFFSETS");
- if (frame_offset_str != NULL) {
- sscanf (frame_offset_str," %d , %d , %d , %d %*s", &left_offset, &top_offset, &right_offset, &bottom_offset);
- } else {
- /* use nominal values since the info in the theme couldn't be found */
- left_offset = 3; top_offset = 3;
- right_offset = 6; bottom_offset = 6;
- }
-
- framed_image = nautilus_embed_image_in_frame (scaled_image, thumbnail_image_frame,
- left_offset, top_offset, right_offset, bottom_offset);
- g_free (frame_offset_str);
-
- gdk_pixbuf_unref (scaled_image);
- gdk_pixbuf_unref (thumbnail_image_frame);
-
- thumbnail_path = gnome_vfs_get_local_path_from_uri (factory->new_thumbnail_path);
- if (!nautilus_gdk_pixbuf_save_to_file (framed_image, thumbnail_path)) {
- g_warning ("error saving thumbnail %s", thumbnail_path);
- }
- g_free (thumbnail_path);
- gdk_pixbuf_unref (framed_image);
- }
- else {
- /* gdk-pixbuf couldn't load the image, so trying using ImageMagick */
- char *temp_str;
- thumbnail_path = gnome_vfs_get_local_path_from_uri (factory->new_thumbnail_path);
- temp_str = g_strdup_printf ("png:%s", thumbnail_path);
- g_free (thumbnail_path);
-
- thumbnail_path = gnome_vfs_get_local_path_from_uri (info->thumbnail_uri);
-
- /* scale the image */
- execlp ("convert", "convert", "-geometry", "96x96", thumbnail_path, temp_str, NULL);
-
- /* we don't come back from this call, so no point in freeing anything up */
- }
-
- _exit(0);
- }
- factory->thumbnail_in_progress = TRUE;
- }
-
- return TRUE; /* we're not done yet */
+ nautilus_g_list_free_deep_custom
+ (icon_list, (GFunc) nautilus_scalable_icon_unref, NULL);
}
-
#if ! defined (NAUTILUS_OMIT_SELF_CHECK)
static char *
diff --git a/libnautilus-extensions/nautilus-icon-factory.h b/libnautilus-extensions/nautilus-icon-factory.h
index 857d78d55..1742e3d4b 100644
--- a/libnautilus-extensions/nautilus-icon-factory.h
+++ b/libnautilus-extensions/nautilus-icon-factory.h
@@ -82,9 +82,9 @@ typedef struct NautilusScalableIcon NautilusScalableIcon;
#define MAX_ATTACH_POINTS 8
typedef struct {
- gboolean has_attach_points;
- GdkPoint attach_points[MAX_ATTACH_POINTS];
-} EmblemAttachPoints;
+ int num_points;
+ GdkPoint points[MAX_ATTACH_POINTS];
+} NautilusEmblemAttachPoints;
/* Instead of a class declaration here, I will just document
* the signals.
@@ -98,19 +98,19 @@ typedef struct {
GtkObject * nautilus_icon_factory_get (void);
/* Relationship between zoom levels and icons sizes. */
-guint nautilus_get_icon_size_for_zoom_level (NautilusZoomLevel zoom_level);
+guint nautilus_get_icon_size_for_zoom_level (NautilusZoomLevel zoom_level);
/* Choose the appropriate icon, but don't render it yet. */
-NautilusScalableIcon *nautilus_icon_factory_get_icon_for_file (NautilusFile *file,
- const char *modifier,
- gboolean anti_aliased);
-gboolean nautilus_icon_factory_is_icon_ready_for_file (NautilusFile *file);
-GList * nautilus_icon_factory_get_required_file_attributes (void);
-GList * nautilus_icon_factory_get_emblem_icons_for_file (NautilusFile *file,
- gboolean anti_aliased,
- NautilusStringList *exclude);
-NautilusScalableIcon *nautilus_icon_factory_get_emblem_icon_by_name (const char *emblem_name,
- gboolean anti_aliased);
+NautilusScalableIcon *nautilus_icon_factory_get_icon_for_file (NautilusFile *file,
+ const char *modifier,
+ gboolean anti_aliased);
+gboolean nautilus_icon_factory_is_icon_ready_for_file (NautilusFile *file);
+GList * nautilus_icon_factory_get_required_file_attributes (void);
+GList * nautilus_icon_factory_get_emblem_icons_for_file (NautilusFile *file,
+ gboolean anti_aliased,
+ NautilusStringList *exclude);
+NautilusScalableIcon *nautilus_icon_factory_get_emblem_icon_by_name (const char *emblem_name,
+ gboolean anti_aliased);
/* Render an icon to a particular size.
* Ownership of a ref. count in this pixbuf comes with the deal.
@@ -118,59 +118,59 @@ NautilusScalableIcon *nautilus_icon_factory_get_emblem_icon_by_name (const cha
* that X and Y scaling are the same. Optionally, we also pass
* back an array of emblem attach points, if the pointer is non-null
*/
-GdkPixbuf * nautilus_icon_factory_get_pixbuf_for_icon (NautilusScalableIcon *scalable_icon,
- guint nominal_size_in_pixels_x,
- guint nominal_size_in_pixels_y,
- guint maximum_size_in_pixels_x,
- guint maximum_size_in_pixels_y,
- EmblemAttachPoints *attach_points);
+GdkPixbuf * nautilus_icon_factory_get_pixbuf_for_icon (NautilusScalableIcon *scalable_icon,
+ guint nominal_size_in_pixels_x,
+ guint nominal_size_in_pixels_y,
+ guint maximum_size_in_pixels_x,
+ guint maximum_size_in_pixels_y,
+ NautilusEmblemAttachPoints *attach_points);
/* Convenience functions for the common case where you want to choose
* and render the icon into a pixbuf all at once.
*/
-GdkPixbuf * nautilus_icon_factory_get_pixbuf_for_file (NautilusFile *file,
- const char *modifer,
- guint size_in_pixels,
- gboolean anti_aliased);
+GdkPixbuf * nautilus_icon_factory_get_pixbuf_for_file (NautilusFile *file,
+ const char *modifer,
+ guint size_in_pixels,
+ gboolean anti_aliased);
/* Convenience functions for legacy interfaces that require a pixmap and
* bitmap. Maybe we can get rid of these one day.
*/
-void nautilus_icon_factory_get_pixmap_and_mask_for_file (NautilusFile *file,
- const char *modifer,
- guint size_in_pixels,
- GdkPixmap **pixmap,
- GdkBitmap **mask);
+void nautilus_icon_factory_get_pixmap_and_mask_for_file (NautilusFile *file,
+ const char *modifer,
+ guint size_in_pixels,
+ GdkPixmap **pixmap,
+ GdkBitmap **mask);
/* Manage a scalable icon.
* Since the factory always passes out references to the same scalable
* icon, you can compare two scalable icons to see if they are the same
* with ==.
*/
-void nautilus_scalable_icon_ref (NautilusScalableIcon *scalable_icon);
-void nautilus_scalable_icon_unref (NautilusScalableIcon *scalable_icon);
+void nautilus_scalable_icon_ref (NautilusScalableIcon *scalable_icon);
+void nautilus_scalable_icon_unref (NautilusScalableIcon *scalable_icon);
/* A scalable icon can be decomposed into text and reconstituted later
* using nautilus_scalable_icon_new_from_text_pieces. This is the way
* to store scalable icons in metadata or other files.
*/
-void nautilus_scalable_icon_get_text_pieces (NautilusScalableIcon *scalable_icon,
- char **uri_return,
- char **name_return,
- char **modifier_return,
- char **embedded_text_return);
+void nautilus_scalable_icon_get_text_pieces (NautilusScalableIcon *scalable_icon,
+ char **uri_return,
+ char **name_return,
+ char **modifier_return,
+ char **embedded_text_return);
/* Get a scalable icon using the earlier results of
* nautilus_scalable_icon_get_text_pieces.
*/
-NautilusScalableIcon *nautilus_scalable_icon_new_from_text_pieces (const char *uri,
- const char *name,
- const char *modifier,
- const char *embedded_text,
- gboolean anti_aliased);
+NautilusScalableIcon *nautilus_scalable_icon_new_from_text_pieces (const char *uri,
+ const char *name,
+ const char *modifier,
+ const char *embedded_text,
+ gboolean anti_aliased);
/* Convenience function for freeing a list of scalable icons.
* Unrefs all the icons before freeing the list.
*/
-void nautilus_scalable_icon_list_free (GList *scalable_icon_list);
+void nautilus_scalable_icon_list_free (GList *scalable_icon_list);
#endif /* NAUTILUS_ICON_FACTORY_H */
diff --git a/libnautilus-extensions/nautilus-preferences.c b/libnautilus-extensions/nautilus-preferences.c
index 8dd5f0482..f17f57b9f 100644
--- a/libnautilus-extensions/nautilus-preferences.c
+++ b/libnautilus-extensions/nautilus-preferences.c
@@ -121,6 +121,7 @@ static void preferences_hash_node_remove_callback
static PreferencesHashNode * preferences_hash_node_lookup (const char *name);
static void preferences_register (const char *name);
static gboolean preferences_initialize_if_needed (void);
+static void preferences_shutdown (void);
static char * preferences_make_make_gconf_key (const char *preference_name);
/* GConf callbacks */
@@ -130,7 +131,7 @@ static void preferences_gconf_by_user_level_callback
GConfValue *value,
gboolean is_default,
gpointer user_data);
-static void preferences_gconf_callback (GConfClient *client,
+static void preferences_gconf_callback (GConfClient *client,
guint cnxn_id,
const gchar *key,
GConfValue *value,
@@ -737,6 +738,8 @@ preferences_initialize_if_needed (void)
user_level_changed_callback,
NULL);
+ g_atexit (preferences_shutdown);
+
return TRUE;
}
@@ -1048,8 +1051,8 @@ nautilus_preferences_get (const char *name,
return value;
}
-void
-nautilus_preferences_shutdown (void)
+static void
+preferences_shutdown (void)
{
if (GLOBAL.preference_table == NULL && GLOBAL.gconf_client == NULL) {
return;
diff --git a/libnautilus-extensions/nautilus-preferences.h b/libnautilus-extensions/nautilus-preferences.h
index b9368210c..56632462b 100644
--- a/libnautilus-extensions/nautilus-preferences.h
+++ b/libnautilus-extensions/nautilus-preferences.h
@@ -89,8 +89,6 @@ void nautilus_preferences_set (const char
const char *value);
char * nautilus_preferences_get (const char *name,
const gchar *default_value);
-void nautilus_preferences_shutdown (void);
-
END_GNOME_DECLS
diff --git a/libnautilus-extensions/nautilus-thumbnails.c b/libnautilus-extensions/nautilus-thumbnails.c
new file mode 100644
index 000000000..a4a7be26d
--- /dev/null
+++ b/libnautilus-extensions/nautilus-thumbnails.c
@@ -0,0 +1,505 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
+
+ nautilus-thumbnails.h: Thumbnail code for icon factory.
+
+ Copyright (C) 2000 Eazel, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with this program; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Author: Andy Hertzfeld <andy@eazel.com>
+*/
+
+#include <config.h>
+#include "nautilus-thumbnails.h"
+
+#include <libgnomevfs/gnome-vfs-file-info.h>
+#include <string.h>
+#include "nautilus-file-utilities.h"
+#include "nautilus-string.h"
+#include <gtk/gtkmain.h>
+#include "nautilus-icon-factory-private.h"
+#include "nautilus-directory-notify.h"
+#include "nautilus-theme.h"
+#include <stdio.h>
+#include "nautilus-gdk-pixbuf-extensions.h"
+#include <unistd.h>
+#include <librsvg/rsvg.h>
+#include "nautilus-graphic-effects.h"
+
+/* permissions for thumbnail directory */
+#define THUMBNAIL_DIR_PERMISSIONS (GNOME_VFS_PERM_USER_ALL \
+ | GNOME_VFS_PERM_GROUP_ALL \
+ | GNOME_VFS_PERM_OTHER_ALL)
+
+/* thumbnail task state */
+static GList *thumbnails;
+static char *new_thumbnail_path;
+static gboolean thumbnail_in_progress;
+
+/* id of timeout task for making thumbnails */
+static int thumbnail_timeout_id;
+
+static int make_thumbnails (gpointer data);
+
+/* utility to test whether a file exists using vfs */
+static gboolean
+vfs_file_exists (const char *file_uri)
+{
+ GnomeVFSResult result;
+ GnomeVFSFileInfo *file_info;
+
+ file_info = gnome_vfs_file_info_new ();
+
+ /* FIXME bugzilla.eazel.com 3137: the synchronous I/O here means this call is
+ unsuitable for use on anything that might be remote. */
+
+ result = gnome_vfs_get_file_info (file_uri, file_info, 0);
+ gnome_vfs_file_info_unref (file_info);
+ return result == GNOME_VFS_OK;
+}
+
+/* utility routine that, given the uri of an image, constructs the uri to the corresponding thumbnail */
+
+static char *
+make_thumbnail_path (const char *image_uri, gboolean directory_only, gboolean use_local_directory, gboolean anti_aliased)
+{
+ char *thumbnail_uri, *thumbnail_path;
+ char *directory_name = g_strdup (image_uri);
+ char *last_slash = strrchr (directory_name, '/');
+ char *dot_pos;
+
+ *last_slash = '\0';
+
+ /* either use the local directory or one in the user's home directory, as selected by the passed in flag */
+ if (use_local_directory) {
+ thumbnail_uri = g_strdup_printf ("%s/.thumbnails", directory_name);
+ } else {
+ GnomeVFSResult result;
+ GnomeVFSURI *thumbnail_directory_uri;
+
+ char *escaped_uri = gnome_vfs_escape_slashes (directory_name);
+ thumbnail_path = g_strdup_printf ("%s/.nautilus/thumbnails/%s", g_get_home_dir(), escaped_uri);
+ thumbnail_uri = gnome_vfs_get_uri_from_local_path (thumbnail_path);
+ g_free (thumbnail_path);
+ g_free(escaped_uri);
+
+ /* we must create the directory if it doesnt exist */
+
+ thumbnail_directory_uri = gnome_vfs_uri_new (thumbnail_uri);
+
+ /* FIXME bugzilla.eazel.com 3137: synchronous I/O - it
+ looks like the URI will be local-only, but best to
+ make sure. */
+
+ result = nautilus_make_directory_and_parents (thumbnail_directory_uri, THUMBNAIL_DIR_PERMISSIONS);
+ gnome_vfs_uri_unref (thumbnail_directory_uri);
+ }
+
+ /* append the file name if necessary */
+ if (!directory_only) {
+ char* old_uri = thumbnail_uri;
+ thumbnail_uri = g_strdup_printf ("%s/%s", thumbnail_uri, last_slash + 1);
+ g_free(old_uri);
+
+ /* append the anti-aliased suffix if necessary */
+ if (anti_aliased) {
+ char *old_uri = thumbnail_uri;
+ dot_pos = strrchr (thumbnail_uri, '.');
+ if (dot_pos) {
+ *dot_pos = '\0';
+ thumbnail_uri = g_strdup_printf ("%s.aa.%s", old_uri, dot_pos + 1);
+ } else {
+ thumbnail_uri = g_strconcat (old_uri, ".aa", NULL);
+ }
+ g_free (old_uri);
+ }
+
+ /* append an image suffix if the correct one isn't already present */
+ if (!nautilus_istr_has_suffix (image_uri, ".png")) {
+ char* old_uri = thumbnail_uri;
+ thumbnail_uri = g_strdup_printf ("%s.png", thumbnail_uri);
+ g_free(old_uri);
+ }
+ }
+
+ g_free (directory_name);
+ return thumbnail_uri;
+}
+
+/* utility routine that takes two uris and returns true if the first file has been modified later than the second */
+/* FIXME bugzilla.eazel.com 2565: it makes synchronous file info calls, so for now, it returns FALSE if either of the uri's are non-local */
+static gboolean
+first_file_more_recent(const char* file_uri, const char* other_file_uri)
+{
+ GnomeVFSURI *vfs_uri, *other_vfs_uri;
+ gboolean more_recent, is_local;
+
+ GnomeVFSFileInfo file_info, other_file_info;
+
+ /* if either file is remote, return FALSE. Eventually we'll make this async to fix this */
+ vfs_uri = gnome_vfs_uri_new(file_uri);
+ other_vfs_uri = gnome_vfs_uri_new(other_file_uri);
+ is_local = gnome_vfs_uri_is_local (vfs_uri) && gnome_vfs_uri_is_local (other_vfs_uri);
+ gnome_vfs_uri_unref(vfs_uri);
+ gnome_vfs_uri_unref(other_vfs_uri);
+
+ if (!is_local) {
+ return FALSE;
+ }
+
+ /* gather the info and then compare modification times */
+ gnome_vfs_file_info_init (&file_info);
+ gnome_vfs_get_file_info (file_uri, &file_info, GNOME_VFS_FILE_INFO_DEFAULT);
+
+ gnome_vfs_file_info_init (&other_file_info);
+ gnome_vfs_get_file_info (other_file_uri, &other_file_info, GNOME_VFS_FILE_INFO_DEFAULT);
+
+ more_recent = file_info.mtime > other_file_info.mtime;
+
+ gnome_vfs_file_info_clear (&file_info);
+ gnome_vfs_file_info_clear (&other_file_info);
+
+ return more_recent;
+}
+
+/* structure used for making thumbnails, associating a uri with where the thumbnail is to be stored */
+
+typedef struct {
+ char *thumbnail_uri;
+ gboolean is_local;
+ gboolean anti_aliased;
+} NautilusThumbnailInfo;
+
+/* GCompareFunc-style function for comparing NautilusThumbnailInfos.
+ * Returns 0 if they refer to the same uri.
+ */
+static int
+compare_thumbnail_info (gconstpointer a, gconstpointer b)
+{
+ NautilusThumbnailInfo *info_a;
+ NautilusThumbnailInfo *info_b;
+
+ info_a = (NautilusThumbnailInfo *)a;
+ info_b = (NautilusThumbnailInfo *)b;
+
+ return strcmp (info_a->thumbnail_uri, info_b->thumbnail_uri) != 0;
+}
+
+/* routine that takes a uri of a large image file and returns the uri of its corresponding thumbnail.
+ If no thumbnail is available, put the image on the thumbnail queue so one is eventually made. */
+/* FIXME bugzilla.eazel.com 642:
+ * Most of this thumbnail machinery belongs in NautilusFile, not here.
+ */
+
+char *
+nautilus_get_thumbnail_uri (NautilusFile *file, gboolean anti_aliased)
+{
+ GnomeVFSResult result;
+ char *thumbnail_uri;
+ char *file_uri;
+ gboolean local_flag = TRUE;
+ gboolean remake_thumbnail = FALSE;
+
+ file_uri = nautilus_file_get_uri (file);
+
+ /* compose the uri for the thumbnail locally */
+ thumbnail_uri = make_thumbnail_path (file_uri, FALSE, TRUE, anti_aliased);
+
+ /* if the thumbnail file already exists locally, simply return the uri */
+
+ /* FIXME bugzilla.eazel.com 3137: this synchronous I/O is a
+ disaster when loading remote locations. It blocks the UI
+ when trying to load a slow remote image over http for
+ instance. The fact that we must do this potentially slow
+ operation implies the IconFactory interface needs to be
+ asynchronous! Either that, or thumbnail existence is
+ somthing we need to be able to monitor/call_when_ready on,
+ on a NautilusFile. */
+
+ if (vfs_file_exists (thumbnail_uri)) {
+
+ /* see if the file changed since it was thumbnailed by comparing the modification time */
+ remake_thumbnail = first_file_more_recent (file_uri, thumbnail_uri);
+
+ /* if the file hasn't changed, return the thumbnail uri */
+ if (!remake_thumbnail) {
+ g_free (file_uri);
+ return thumbnail_uri;
+ } else {
+ nautilus_icon_factory_remove_by_uri (thumbnail_uri);
+
+ /* FIXME bugzilla.eazel.com 3137: more potentially
+ losing synch I/O. */
+ gnome_vfs_unlink (thumbnail_uri);
+ }
+ }
+
+ /* now try it globally */
+ if (!remake_thumbnail) {
+ g_free (thumbnail_uri);
+ thumbnail_uri = make_thumbnail_path (file_uri, FALSE, FALSE, anti_aliased);
+
+ /* if the thumbnail file already exists in the common area, return that uri */
+
+ /* FIXME bugzilla.eazel.com 3137: more potentially losing
+ synch I/O - this should be guaranteed local, so
+ perhaps not as bad (unless you have an NFS homedir,
+ say... */
+
+ if (vfs_file_exists (thumbnail_uri)) {
+
+ /* see if the file changed since it was thumbnailed by comparing the modification time */
+ remake_thumbnail = first_file_more_recent(file_uri, thumbnail_uri);
+
+ /* if the file hasn't changed, return the thumbnail uri */
+ if (!remake_thumbnail) {
+ g_free (file_uri);
+ return thumbnail_uri;
+ } else {
+ nautilus_icon_factory_remove_by_uri (thumbnail_uri);
+
+ /* FIXME bugzilla.eazel.com 3137: more potentially losing
+ synch I/O - this should be guaranteed local, so
+ perhaps not as bad (unless you have an NFS homedir,
+ say... */
+ gnome_vfs_unlink (thumbnail_uri);
+ }
+ }
+ }
+
+ /* make the thumbnail directory if necessary, at first try it locally */
+ g_free (thumbnail_uri);
+ local_flag = TRUE;
+ thumbnail_uri = make_thumbnail_path (file_uri, TRUE, local_flag, anti_aliased);
+
+
+ /* FIXME bugzilla.eazel.com 3137: more potentially losing
+ synch I/O - this could be remote */
+
+ result = gnome_vfs_make_directory (thumbnail_uri, THUMBNAIL_DIR_PERMISSIONS);
+
+ /* if we can't make if locally, try it in the global place */
+ if (result != GNOME_VFS_OK && result != GNOME_VFS_ERROR_FILE_EXISTS) {
+ g_free (thumbnail_uri);
+ local_flag = FALSE;
+ thumbnail_uri = make_thumbnail_path (file_uri, TRUE, local_flag, anti_aliased);
+ /* FIXME bugzilla.eazel.com 3137: more potentially
+ losing synch I/O - this is probably local? */
+
+ result = gnome_vfs_make_directory (thumbnail_uri, THUMBNAIL_DIR_PERMISSIONS);
+ }
+
+ /* the thumbnail needs to be created (or recreated), so add an entry to the thumbnail list */
+
+ if (result != GNOME_VFS_OK && result != GNOME_VFS_ERROR_FILE_EXISTS) {
+
+ g_warning ("error when making thumbnail directory %d, for %s", result, thumbnail_uri);
+ } else {
+ NautilusThumbnailInfo *info = g_new0 (NautilusThumbnailInfo, 1);
+ info->thumbnail_uri = file_uri;
+ info->is_local = local_flag;
+ info->anti_aliased = anti_aliased;
+
+ if (thumbnails != NULL) {
+ if (g_list_find_custom (thumbnails, info, compare_thumbnail_info) == NULL) {
+ thumbnails = g_list_prepend (thumbnails, info);
+ }
+ } else {
+ thumbnails = g_list_alloc ();
+ thumbnails->data = info;
+ }
+
+ if (thumbnail_timeout_id == 0) {
+ thumbnail_timeout_id = gtk_timeout_add
+ (400, make_thumbnails, NULL);
+ }
+ }
+
+ g_free (thumbnail_uri);
+
+ /* Return NULL to indicate the thumbnail is loading. */
+ return NULL;
+}
+
+/* check_for_thumbnails is a utility that checks to see if any of the thumbnails in the pending
+ list have been created yet. If it finds one, it removes the elements from the queue and
+ returns true, otherwise it returns false
+*/
+static gboolean
+check_for_thumbnails (void)
+{
+ char *current_thumbnail;
+ NautilusThumbnailInfo *info;
+ GList *stop_element;
+ GList *next_thumbnail;
+ NautilusFile *file;
+
+ for (next_thumbnail = thumbnails;
+ next_thumbnail != NULL;
+ next_thumbnail = next_thumbnail->next) {
+ info = (NautilusThumbnailInfo*) next_thumbnail->data;
+ current_thumbnail = make_thumbnail_path (info->thumbnail_uri, FALSE, info->is_local, info->anti_aliased);
+ /* FIXME bugzilla.eazel.com 3137: synchronous I/O */
+ if (vfs_file_exists (current_thumbnail)) {
+ /* we found one, so update the icon and remove all of the elements up to and including
+ this one from the pending list. */
+ g_free (current_thumbnail);
+ file = nautilus_file_get (info->thumbnail_uri);
+
+ if (file != NULL) {
+ nautilus_file_changed (file);
+ nautilus_file_unref (file);
+ }
+
+ stop_element = next_thumbnail->next;
+ while (thumbnails != stop_element) {
+ info = (NautilusThumbnailInfo *) thumbnails->data;
+ g_free (info->thumbnail_uri);
+ g_free (info);
+ thumbnails = g_list_remove_link (thumbnails, thumbnails);
+ }
+ return TRUE;
+ }
+
+ g_free (current_thumbnail);
+ }
+
+ return FALSE;
+}
+
+/* make_thumbnails is invoked periodically as a timer task to launch a task to make thumbnails */
+
+static GdkPixbuf*
+load_thumbnail_frame (gboolean anti_aliased)
+{
+ char *image_path;
+ GdkPixbuf *frame_image;
+
+ /* load the thumbnail frame */
+ image_path = nautilus_theme_get_image_path (anti_aliased ? "thumbnail_frame.aa.png" : "thumbnail_frame.png");
+ frame_image = gdk_pixbuf_new_from_file (image_path);
+ g_free (image_path);
+ return frame_image;
+}
+
+static int
+make_thumbnails (gpointer data)
+{
+ pid_t thumbnail_pid;
+ NautilusThumbnailInfo *info;
+ GList *next_thumbnail = thumbnails;
+ GdkPixbuf *scaled_image, *framed_image, *thumbnail_image_frame;
+ char *frame_offset_str;
+ int left_offset, top_offset, right_offset, bottom_offset;
+
+ /* if the queue is empty, there's nothing more to do */
+ if (next_thumbnail == NULL) {
+ gtk_timeout_remove (thumbnail_timeout_id);
+ thumbnail_timeout_id = 0;
+ return FALSE;
+ }
+
+ info = (NautilusThumbnailInfo *) next_thumbnail->data;
+
+ /* see which state we're in. If a thumbnail isn't in progress, start one up. Otherwise,
+ check if the pending one is completed. */
+ if (thumbnail_in_progress) {
+ if (check_for_thumbnails ()) {
+ thumbnail_in_progress = FALSE;
+ }
+ } else {
+ /* start up a task to make the thumbnail corresponding to the queue element. */
+
+ /* First, compute the path name of the target thumbnail */
+ g_free (new_thumbnail_path);
+ new_thumbnail_path = make_thumbnail_path (info->thumbnail_uri, FALSE, info->is_local, info->anti_aliased);
+
+ /* fork a task to make the thumbnail, using gdk-pixbuf to do the scaling */
+ if (!(thumbnail_pid = fork())) {
+ GdkPixbuf* full_size_image;
+ NautilusFile *file;
+ char *thumbnail_path;
+
+ file = nautilus_file_get (info->thumbnail_uri);
+ full_size_image = NULL;
+
+ if (nautilus_file_is_mime_type (file, "image/svg")) {
+ thumbnail_path = gnome_vfs_get_local_path_from_uri (info->thumbnail_uri);
+ if (thumbnail_path != NULL) {
+ FILE *f = fopen (thumbnail_path, "rb");
+ if (f != NULL) {
+ full_size_image = rsvg_render_file (f, 1.0);
+ fclose (f);
+ }
+ }
+ } else {
+ if (info->thumbnail_uri != NULL)
+ full_size_image = nautilus_gdk_pixbuf_load (info->thumbnail_uri);
+ }
+ nautilus_file_unref (file);
+
+ if (full_size_image != NULL) {
+ thumbnail_image_frame = load_thumbnail_frame (info->anti_aliased);
+
+ /* scale the content image as necessary */
+ scaled_image = nautilus_gdk_pixbuf_scale_down_to_fit(full_size_image, 96, 96);
+ gdk_pixbuf_unref (full_size_image);
+
+ /* embed the content image in the frame */
+ frame_offset_str = nautilus_theme_get_theme_data ("thumbnails", "FRAME_OFFSETS");
+ if (frame_offset_str != NULL) {
+ sscanf (frame_offset_str," %d , %d , %d , %d %*s", &left_offset, &top_offset, &right_offset, &bottom_offset);
+ } else {
+ /* use nominal values since the info in the theme couldn't be found */
+ left_offset = 3; top_offset = 3;
+ right_offset = 6; bottom_offset = 6;
+ }
+
+ framed_image = nautilus_embed_image_in_frame (scaled_image, thumbnail_image_frame,
+ left_offset, top_offset, right_offset, bottom_offset);
+ g_free (frame_offset_str);
+
+ gdk_pixbuf_unref (scaled_image);
+ gdk_pixbuf_unref (thumbnail_image_frame);
+
+ thumbnail_path = gnome_vfs_get_local_path_from_uri (new_thumbnail_path);
+ if (!nautilus_gdk_pixbuf_save_to_file (framed_image, thumbnail_path)) {
+ g_warning ("error saving thumbnail %s", thumbnail_path);
+ }
+ g_free (thumbnail_path);
+ gdk_pixbuf_unref (framed_image);
+ } else {
+ /* gdk-pixbuf couldn't load the image, so trying using ImageMagick */
+ char *temp_str;
+ thumbnail_path = gnome_vfs_get_local_path_from_uri (new_thumbnail_path);
+ temp_str = g_strdup_printf ("png:%s", thumbnail_path);
+ g_free (thumbnail_path);
+
+ thumbnail_path = gnome_vfs_get_local_path_from_uri (info->thumbnail_uri);
+
+ /* scale the image */
+ execlp ("convert", "convert", "-geometry", "96x96", thumbnail_path, temp_str, NULL);
+
+ /* we don't come back from this call, so no point in freeing anything up */
+ }
+
+ _exit(0);
+ }
+ thumbnail_in_progress = TRUE;
+ }
+
+ return TRUE; /* we're not done yet */
+}
diff --git a/libnautilus-extensions/nautilus-thumbnails.h b/libnautilus-extensions/nautilus-thumbnails.h
new file mode 100644
index 000000000..32f61bf09
--- /dev/null
+++ b/libnautilus-extensions/nautilus-thumbnails.h
@@ -0,0 +1,33 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
+
+ nautilus-thumbnails.h: Thumbnail code for icon factory.
+
+ Copyright (C) 2000 Eazel, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with this program; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Author: Andy Hertzfeld <andy@eazel.com>
+*/
+
+#ifndef NAUTILUS_THUMBNAILS_H
+#define NAUTILUS_THUMBNAILS_H
+
+#include "nautilus-file.h"
+
+/* Returns NULL if there's no thumbnail yet. */
+char *nautilus_get_thumbnail_uri (NautilusFile *file, gboolean anti_aliased);
+
+#endif /* NAUTILUS_THUMBNAILS_H */
diff --git a/libnautilus-private/Makefile.am b/libnautilus-private/Makefile.am
index f135260f6..6e1f528d3 100644
--- a/libnautilus-private/Makefile.am
+++ b/libnautilus-private/Makefile.am
@@ -117,6 +117,7 @@ libnautilus_extensions_la_SOURCES = \
nautilus-string.c \
nautilus-text-caption.c \
nautilus-theme.c \
+ nautilus-thumbnails.c \
nautilus-trash-directory.c \
nautilus-undo-context.c \
nautilus-undo-manager.c \
@@ -177,6 +178,7 @@ noinst_HEADERS = \
nautilus-icon-container.h \
nautilus-icon-dnd.h \
nautilus-icon-factory.h \
+ nautilus-icon-factory-private.h \
nautilus-icon-private.h \
nautilus-icon-text-item.h \
nautilus-image.h \
@@ -213,6 +215,7 @@ noinst_HEADERS = \
nautilus-string.h \
nautilus-text-caption.h \
nautilus-theme.h \
+ nautilus-thumbnails.h \
nautilus-trash-directory.h \
nautilus-undo-context.h \
nautilus-undo-manager.h \
diff --git a/libnautilus-private/nautilus-directory.c b/libnautilus-private/nautilus-directory.c
index f42bb8179..879940a3e 100644
--- a/libnautilus-private/nautilus-directory.c
+++ b/libnautilus-private/nautilus-directory.c
@@ -67,8 +67,6 @@ static void nautilus_directory_destroy (GtkObject *obje
static void nautilus_directory_initialize (gpointer object,
gpointer klass);
static void nautilus_directory_initialize_class (NautilusDirectoryClass *klass);
-static GnomeVFSResult nautilus_make_directory_and_parents (GnomeVFSURI *uri,
- guint permissions);
static NautilusDirectory *nautilus_directory_new (const char *uri);
static char *real_get_name_for_self_as_new_file (NautilusDirectory *directory);
@@ -343,42 +341,6 @@ nautilus_directory_get_uri (NautilusDirectory *directory)
return g_strdup (directory->details->uri);
}
-static GnomeVFSResult
-nautilus_make_directory_and_parents (GnomeVFSURI *uri, guint permissions)
-{
- GnomeVFSResult result;
- GnomeVFSURI *parent_uri;
-
- /* Make the directory, and return right away unless there's
- a possible problem with the parent.
- */
- result = gnome_vfs_make_directory_for_uri (uri, permissions);
- if (result != GNOME_VFS_ERROR_NOT_FOUND) {
- return result;
- }
-
- /* If we can't get a parent, we are done. */
- parent_uri = gnome_vfs_uri_get_parent (uri);
- if (parent_uri == NULL) {
- return result;
- }
-
- /* If we can get a parent, use a recursive call to create
- the parent and its parents.
- */
- result = nautilus_make_directory_and_parents (parent_uri, permissions);
- gnome_vfs_uri_unref (parent_uri);
- if (result != GNOME_VFS_OK) {
- return result;
- }
-
- /* A second try at making the directory after the parents
- have all been created.
- */
- result = gnome_vfs_make_directory_for_uri (uri, permissions);
- return result;
-}
-
static GnomeVFSURI *
construct_private_metafile_vfs_uri (const char *uri)
{
diff --git a/libnautilus-private/nautilus-file-utilities.c b/libnautilus-private/nautilus-file-utilities.c
index 864a16e3a..8108f66c6 100644
--- a/libnautilus-private/nautilus-file-utilities.c
+++ b/libnautilus-private/nautilus-file-utilities.c
@@ -725,6 +725,42 @@ nautilus_read_file_cancel (NautilusReadFileHandle *handle)
g_free (handle);
}
+GnomeVFSResult
+nautilus_make_directory_and_parents (GnomeVFSURI *uri, guint permissions)
+{
+ GnomeVFSResult result;
+ GnomeVFSURI *parent_uri;
+
+ /* Make the directory, and return right away unless there's
+ a possible problem with the parent.
+ */
+ result = gnome_vfs_make_directory_for_uri (uri, permissions);
+ if (result != GNOME_VFS_ERROR_NOT_FOUND) {
+ return result;
+ }
+
+ /* If we can't get a parent, we are done. */
+ parent_uri = gnome_vfs_uri_get_parent (uri);
+ if (parent_uri == NULL) {
+ return result;
+ }
+
+ /* If we can get a parent, use a recursive call to create
+ the parent and its parents.
+ */
+ result = nautilus_make_directory_and_parents (parent_uri, permissions);
+ gnome_vfs_uri_unref (parent_uri);
+ if (result != GNOME_VFS_OK) {
+ return result;
+ }
+
+ /* A second try at making the directory after the parents
+ have all been created.
+ */
+ result = gnome_vfs_make_directory_for_uri (uri, permissions);
+ return result;
+}
+
#if !defined (NAUTILUS_OMIT_SELF_CHECK)
void
diff --git a/libnautilus-private/nautilus-file-utilities.h b/libnautilus-private/nautilus-file-utilities.h
index 792df2c4a..2485d4843 100644
--- a/libnautilus-private/nautilus-file-utilities.h
+++ b/libnautilus-private/nautilus-file-utilities.h
@@ -40,9 +40,8 @@ char * nautilus_format_uri_for_display (const char
char * nautilus_make_uri_from_input (const char *location);
gboolean nautilus_uri_is_trash (const char *uri);
char * nautilus_make_uri_canonical (const char *uri);
-gboolean nautilus_uris_match (const char *uri_1,
- const char *uri_2);
-
+gboolean nautilus_uris_match (const char *uri_1,
+ const char *uri_2);
/* FIXME bugzilla.eazel.com 2424:
* This is the same as gnome-libs g_concat_dir_and_file except
* for handling path == NULL.
@@ -89,4 +88,8 @@ NautilusReadFileHandle *nautilus_read_file_async (const char
gpointer callback_data);
void nautilus_read_file_cancel (NautilusReadFileHandle *handle);
+/* gnome-vfs cover to make a directory and parents */
+GnomeVFSResult nautilus_make_directory_and_parents (GnomeVFSURI *uri,
+ guint permissions);
+
#endif /* NAUTILUS_FILE_UTILITIES_H */
diff --git a/libnautilus-private/nautilus-global-preferences.c b/libnautilus-private/nautilus-global-preferences.c
index 4ec4d8265..6802356fc 100644
--- a/libnautilus-private/nautilus-global-preferences.c
+++ b/libnautilus-private/nautilus-global-preferences.c
@@ -389,16 +389,33 @@ nautilus_global_preferences_get_disabled_sidebar_panel_view_identifiers (void)
return disabled_view_identifiers;
}
+
+static void
+destroy_global_prefs_dialog (void)
+{
+ /* Free the dialog first, cause it has refs to preferences */
+ if (global_prefs_dialog != NULL) {
+ /* Since it's a top-level window, it's OK to destroy rather than unref'ing. */
+ gtk_widget_destroy (global_prefs_dialog);
+ }
+}
+
static GtkWidget *
global_preferences_get_dialog (void)
{
+ static gboolean set_up_exit = FALSE;
+
nautilus_global_preferences_initialize ();
- if (!global_prefs_dialog)
- {
+ if (global_prefs_dialog == NULL) {
global_prefs_dialog = global_preferences_create_dialog ();
}
+ if (!set_up_exit) {
+ g_atexit (destroy_global_prefs_dialog);
+ set_up_exit = TRUE;
+ }
+
return global_prefs_dialog;
}
@@ -863,9 +880,10 @@ nautilus_global_preferences_dialog_update (void)
was_showing = GTK_WIDGET_VISIBLE (global_prefs_dialog);
gtk_widget_destroy (global_prefs_dialog);
+ global_prefs_dialog = NULL;
}
- global_prefs_dialog = global_preferences_create_dialog ();
+ global_preferences_get_dialog ();
if (was_showing) {
nautilus_global_preferences_show_dialog ();
@@ -885,16 +903,3 @@ nautilus_global_preferences_initialize (void)
initialized = TRUE;
}
-
-void
-nautilus_global_preferences_shutdown (void)
-{
- /* Free the dialog first, cause it has refs to preferences */
- if (global_prefs_dialog != NULL) {
- gtk_widget_destroy (global_prefs_dialog);
- }
-
- /* Now free the preferences tables and stuff */
- nautilus_preferences_shutdown ();
-}
-
diff --git a/libnautilus-private/nautilus-global-preferences.h b/libnautilus-private/nautilus-global-preferences.h
index fe2fdde43..f96590bbc 100644
--- a/libnautilus-private/nautilus-global-preferences.h
+++ b/libnautilus-private/nautilus-global-preferences.h
@@ -124,7 +124,6 @@ typedef enum
void nautilus_global_preferences_initialize (void);
-void nautilus_global_preferences_shutdown (void);
void nautilus_global_preferences_show_dialog (void);
void nautilus_global_preferences_hide_dialog (void);
void nautilus_global_preferences_set_dialog_title (const char *title);
diff --git a/libnautilus-private/nautilus-icon-canvas-item.c b/libnautilus-private/nautilus-icon-canvas-item.c
index f4f412a57..753199a1e 100644
--- a/libnautilus-private/nautilus-icon-canvas-item.c
+++ b/libnautilus-private/nautilus-icon-canvas-item.c
@@ -68,7 +68,7 @@ struct NautilusIconCanvasItemDetails {
char *editable_text; /* Text that can be modified by a renaming function */
char *additional_text; /* Text that cannot be modifed, such as file size, etc. */
GdkFont *font;
- EmblemAttachPoints *attach_pointer;
+ NautilusEmblemAttachPoints *attach_points;
/* Size of the text at current font. */
int text_width;
@@ -301,7 +301,7 @@ nautilus_icon_canvas_item_destroy (GtkObject *object)
nautilus_gdk_pixbuf_list_free (details->emblem_pixbufs);
g_free (details->editable_text);
g_free (details->additional_text);
- g_free (details->attach_pointer);
+ g_free (details->attach_points);
if (details->font != NULL) {
gdk_font_unref (details->font);
@@ -531,14 +531,14 @@ nautilus_icon_canvas_item_set_emblems (NautilusIconCanvasItem *item,
void
nautilus_icon_canvas_item_set_attach_points (NautilusIconCanvasItem *item,
- EmblemAttachPoints *attach_points)
+ NautilusEmblemAttachPoints *attach_points)
{
- g_free (item->details->attach_pointer);
- item->details->attach_pointer = NULL;
+ g_free (item->details->attach_points);
+ item->details->attach_points = NULL;
- if (attach_points && attach_points->has_attach_points) {
- item->details->attach_pointer = g_new0 (EmblemAttachPoints, 1);
- *item->details->attach_pointer = *attach_points;
+ if (attach_points != NULL && attach_points->num_points != 0) {
+ item->details->attach_points = g_new (NautilusEmblemAttachPoints, 1);
+ *item->details->attach_points = *attach_points;
}
}
@@ -945,7 +945,7 @@ emblem_layout_next (EmblemLayout *layout,
{
GdkPixbuf *pixbuf;
int width, height, x, y;
- EmblemAttachPoints *attach_info ;
+ NautilusEmblemAttachPoints *attach_points;
/* Check if we have layed out all of the pixbufs. */
if (layout->emblem == NULL) {
@@ -961,13 +961,14 @@ emblem_layout_next (EmblemLayout *layout,
/* Advance to the next emblem. */
layout->emblem = layout->emblem->next;
- if (layout->icon_item->details->attach_pointer) {
- if (layout->index >= MAX_ATTACH_POINTS)
+ attach_points = layout->icon_item->details->attach_points;
+ if (attach_points != NULL) {
+ if (layout->index >= attach_points->num_points) {
return FALSE;
+ }
- attach_info = layout->icon_item->details->attach_pointer;
- x = layout->icon_rect.x0 + attach_info->attach_points[layout->index].x;
- y = layout->icon_rect.y0 + attach_info->attach_points[layout->index].y;
+ x = layout->icon_rect.x0 + attach_points->points[layout->index].x;
+ y = layout->icon_rect.y0 + attach_points->points[layout->index].y;
layout->index += 1;
diff --git a/libnautilus-private/nautilus-icon-canvas-item.h b/libnautilus-private/nautilus-icon-canvas-item.h
index 06e7af69c..8de5c8f23 100644
--- a/libnautilus-private/nautilus-icon-canvas-item.h
+++ b/libnautilus-private/nautilus-icon-canvas-item.h
@@ -66,34 +66,33 @@ GtkType nautilus_icon_canvas_item_get_type (void);
/* attributes */
-void nautilus_icon_canvas_item_set_image (NautilusIconCanvasItem *item,
- GdkPixbuf *image);
-GdkPixbuf * nautilus_icon_canvas_item_get_image (NautilusIconCanvasItem *item);
-void nautilus_icon_canvas_item_set_emblems (NautilusIconCanvasItem *item,
- GList *emblem_pixbufs);
-void nautilus_icon_canvas_item_set_show_stretch_handles (NautilusIconCanvasItem *item,
- gboolean show_stretch_handles);
-void nautilus_icon_canvas_item_set_attach_points (NautilusIconCanvasItem *item,
- EmblemAttachPoints *attach_points);
-double nautilus_icon_canvas_item_get_max_text_width (NautilusIconCanvasItem *item);
-const char *nautilus_icon_canvas_item_get_editable_text (NautilusIconCanvasItem *icon_item);
-void nautilus_icon_canvas_item_set_renaming (NautilusIconCanvasItem *icon_item,
- gboolean state);
+void nautilus_icon_canvas_item_set_image (NautilusIconCanvasItem *item,
+ GdkPixbuf *image);
+GdkPixbuf * nautilus_icon_canvas_item_get_image (NautilusIconCanvasItem *item);
+void nautilus_icon_canvas_item_set_emblems (NautilusIconCanvasItem *item,
+ GList *emblem_pixbufs);
+void nautilus_icon_canvas_item_set_show_stretch_handles (NautilusIconCanvasItem *item,
+ gboolean show_stretch_handles);
+void nautilus_icon_canvas_item_set_attach_points (NautilusIconCanvasItem *item,
+ NautilusEmblemAttachPoints *attach_points);
+double nautilus_icon_canvas_item_get_max_text_width (NautilusIconCanvasItem *item);
+const char *nautilus_icon_canvas_item_get_editable_text (NautilusIconCanvasItem *icon_item);
+void nautilus_icon_canvas_item_set_renaming (NautilusIconCanvasItem *icon_item,
+ gboolean state);
/* geometry and hit testing */
-gboolean nautilus_icon_canvas_item_hit_test_rectangle (NautilusIconCanvasItem *item,
- const ArtDRect *world_rectangle);
-gboolean nautilus_icon_canvas_item_hit_test_stretch_handles (NautilusIconCanvasItem *item,
- const ArtPoint *world_point);
-void nautilus_icon_canvas_item_get_icon_rectangle (NautilusIconCanvasItem *item,
- ArtDRect *world_rectangle);
-void nautilus_icon_canvas_item_update_bounds (NautilusIconCanvasItem *item);
-void nautilus_icon_canvas_item_set_smooth_font (NautilusIconCanvasItem *item,
- NautilusScalableFont *font);
-void nautilus_icon_canvas_item_set_smooth_font_size (NautilusIconCanvasItem *item,
- guint font_size);
-
+gboolean nautilus_icon_canvas_item_hit_test_rectangle (NautilusIconCanvasItem *item,
+ const ArtDRect *world_rectangle);
+gboolean nautilus_icon_canvas_item_hit_test_stretch_handles (NautilusIconCanvasItem *item,
+ const ArtPoint *world_point);
+void nautilus_icon_canvas_item_get_icon_rectangle (NautilusIconCanvasItem *item,
+ ArtDRect *world_rectangle);
+void nautilus_icon_canvas_item_update_bounds (NautilusIconCanvasItem *item);
+void nautilus_icon_canvas_item_set_smooth_font (NautilusIconCanvasItem *item,
+ NautilusScalableFont *font);
+void nautilus_icon_canvas_item_set_smooth_font_size (NautilusIconCanvasItem *item,
+ guint font_size);
END_GNOME_DECLS
diff --git a/libnautilus-private/nautilus-icon-container.c b/libnautilus-private/nautilus-icon-container.c
index 46fba885b..a5f7be185 100644
--- a/libnautilus-private/nautilus-icon-container.c
+++ b/libnautilus-private/nautilus-icon-container.c
@@ -3209,7 +3209,7 @@ nautilus_icon_container_update_icon (NautilusIconContainer *container,
NautilusIconContainerDetails *details;
guint icon_size_x, icon_size_y, max_image_size, max_emblem_size;
NautilusScalableIcon *scalable_icon;
- EmblemAttachPoints attach_points;
+ NautilusEmblemAttachPoints attach_points;
GdkPixbuf *pixbuf, *emblem_pixbuf;
GList *emblem_scalable_icons, *emblem_pixbufs, *p;
char *editable_text, *additional_text;
diff --git a/libnautilus-private/nautilus-icon-factory-private.h b/libnautilus-private/nautilus-icon-factory-private.h
new file mode 100644
index 000000000..475758eff
--- /dev/null
+++ b/libnautilus-private/nautilus-icon-factory-private.h
@@ -0,0 +1,33 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
+
+ nautilus-icon-factory-private.h: Private interface for use within
+ the icon factory code.
+
+ Copyright (C) 2000 Eazel, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with this program; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Author: Darin Adler <darin@eazel.com>
+*/
+
+#ifndef NAUTILUS_ICON_FACTORY_PRIVATE_H
+#define NAUTILUS_ICON_FACTORY_PRIVATE_H
+
+#include "nautilus-icon-factory.h"
+
+void nautilus_icon_factory_remove_by_uri (const char *uri);
+
+#endif /* NAUTILUS_ICON_FACTORY_PRIVATE_H */
diff --git a/libnautilus-private/nautilus-icon-factory.c b/libnautilus-private/nautilus-icon-factory.c
index c7b0f473c..d7d31e731 100644
--- a/libnautilus-private/nautilus-icon-factory.c
+++ b/libnautilus-private/nautilus-icon-factory.c
@@ -20,49 +20,42 @@
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
- Authors: John Sullivan <sullivan@eazel.com>, Darin Adler <darin@eazel.com>,
+ Authors: John Sullivan <sullivan@eazel.com>,
+ Darin Adler <darin@eazel.com>,
Andy Hertzfeld <andy@eazel.com>
*/
#include <config.h>
#include "nautilus-icon-factory.h"
-#include <unistd.h>
-#include <string.h>
-#include <stdio.h>
-
-#include <gtk/gtkmain.h>
-#include <gtk/gtksignal.h>
-#include <gnome.h>
-
-#include <libgnomevfs/gnome-vfs-types.h>
-#include <libgnomevfs/gnome-vfs-file-info.h>
-#include <libgnomevfs/gnome-vfs-mime-info.h>
-
-#include <libnautilus-extensions/nautilus-gdk-pixbuf-extensions.h>
-
-#include <parser.h>
-#include <xmlmemory.h>
-
-#include <librsvg/rsvg.h>
-
#include "nautilus-default-file-icon.h"
-#include "nautilus-directory-notify.h"
#include "nautilus-file-attributes.h"
#include "nautilus-file-utilities.h"
#include "nautilus-gdk-extensions.h"
#include "nautilus-gdk-pixbuf-extensions.h"
#include "nautilus-glib-extensions.h"
#include "nautilus-global-preferences.h"
-#include "nautilus-graphic-effects.h"
#include "nautilus-gtk-macros.h"
+#include "nautilus-icon-factory-private.h"
#include "nautilus-lib-self-check-functions.h"
#include "nautilus-link.h"
#include "nautilus-metadata.h"
+#include "nautilus-scalable-font.h"
#include "nautilus-string.h"
#include "nautilus-theme.h"
+#include "nautilus-thumbnails.h"
#include "nautilus-xml-extensions.h"
-#include "nautilus-scalable-font.h"
+#include <gnome.h>
+#include <gtk/gtksignal.h>
+#include <libgnomevfs/gnome-vfs-file-info.h>
+#include <libgnomevfs/gnome-vfs-mime-info.h>
+#include <libgnomevfs/gnome-vfs-types.h>
+#include <libnautilus-extensions/nautilus-gdk-pixbuf-extensions.h>
+#include <librsvg/rsvg.h>
+#include <parser.h>
+#include <stdio.h>
+#include <string.h>
+#include <xmlmemory.h>
/* List of suffixes to search when looking for an icon file. */
static const char *icon_file_name_suffixes[] =
@@ -75,6 +68,7 @@ static const char *icon_file_name_suffixes[] =
".gif",
".GIF"
};
+
#define ICON_NAME_DIRECTORY "i-directory"
#define ICON_NAME_DIRECTORY_CLOSED "i-dirclosed"
#define ICON_NAME_EXECUTABLE "i-executable"
@@ -123,9 +117,16 @@ struct NautilusCircularList {
/* maximum size for either dimension at the standard zoom level */
#define MAXIMUM_ICON_SIZE 96
-/* permissions for thumbnail directory */
-
-#define THUMBNAIL_DIR_PERMISSIONS (GNOME_VFS_PERM_USER_ALL | GNOME_VFS_PERM_GROUP_ALL | GNOME_VFS_PERM_OTHER_ALL)
+/* FIXME bugzilla.eazel.com 1102: Embedded text should use preferences
+ * to determine what font it uses.
+ */
+#define EMBEDDED_TEXT_FONT_FAMILY _("helvetica")
+#define EMBEDDED_TEXT_FONT_WEIGHT _("medium")
+#define EMBEDDED_TEXT_FONT_SLANT NULL
+#define EMBEDDED_TEXT_FONT_SET_WIDTH NULL
+#define EMBEDDED_TEXT_FONT_SIZE 9
+#define EMBEDDED_TEXT_LINE_OFFSET 1
+#define EMBEDDED_TEXT_EMPTY_LINE_HEIGHT 4
/* The icon factory.
* These are just globals, but they're in an object so we can
@@ -143,24 +144,24 @@ typedef struct {
*/
GHashTable *scalable_icons;
- /* A hash table that contains a cache of actual images.
- * A circular list of the most recently used images is kept
- * around, and we don't let them go when we sweep the cache.
+ /* A hash table so we can find a cached icon's data structure
+ * from the pixbuf.
+ */
+ GHashTable *cache_icons;
+
+ /* A hash table that contains the icons. A circular list of
+ * the most recently used icons is kept around, and we don't
+ * let them go when we sweep the cache.
*/
GHashTable *icon_cache;
NautilusCircularList recently_used_dummy_head;
guint recently_used_count;
guint sweep_timer;
-
- /* thumbnail task state */
- GList *thumbnails;
- char *new_thumbnail_path;
- gboolean thumbnail_in_progress;
-
- /* id of timeout task for making thumbnails */
- int timeout_task_id;
} NautilusIconFactory;
+#define NAUTILUS_ICON_FACTORY(obj) \
+ GTK_CHECK_CAST (obj, nautilus_icon_factory_get_type (), NautilusIconFactory)
+
typedef struct {
GtkObjectClass parent_class;
} NautilusIconFactoryClass;
@@ -172,7 +173,7 @@ enum {
static guint signals[LAST_SIGNAL];
/* A scalable icon, which is basically the name and path of an icon,
- * before we load the actual pixels of the icons's image.
+ * before we load the actual pixels of the icons's pixbuf.
*/
struct NautilusScalableIcon {
guint ref_count;
@@ -192,92 +193,94 @@ typedef struct {
guint maximum_height;
} IconSizeRequest;
-/* A structure to hold the icon meta-info, like the text rectangle and emblem attach points */
-
typedef struct {
ArtIRect text_rect;
- gboolean has_attach_points;
- GdkPoint attach_points[MAX_ATTACH_POINTS];
-} IconInfo;
+ NautilusEmblemAttachPoints attach_points;
+} IconDetails;
-/* The key to a hash table that holds the scaled icons as pixbufs.
- * In a way, it's not really completely a key, because part of the
- * data is stored in here, including the LRU chain.
- */
+/* The key to a hash table that holds the scaled icons as pixbufs. */
typedef struct {
NautilusScalableIcon *scalable_icon;
IconSizeRequest size;
+} CacheKey;
+
+/* The value in the same table. */
+typedef struct {
+ GdkPixbuf *pixbuf;
+ IconDetails details;
+ /* If true, outside clients have refs to the pixbuf. */
+ gboolean outstanding;
+
+ /* Number of internal clients with refs to the pixbuf. */
+ guint internal_ref_count;
+
+ /* Used to decide when to kick icons out of the cache. */
NautilusCircularList recently_used_node;
- time_t cache_time;
- gboolean aa_mode;
+
+ /* Used to know when to make a new thumbnail. */
+ time_t cache_time;
+
+ /* Type of icon. */
gboolean custom;
gboolean scaled;
- IconInfo icon_info;
-} IconCacheKey;
+} CacheIcon;
#define MINIMUM_EMBEDDED_TEXT_RECT_WIDTH 20.0
#define MINIMUM_EMBEDDED_TEXT_RECT_HEIGHT 20.0
+static CacheIcon *fallback_icon;
+
/* forward declarations */
-static void icon_theme_changed_callback (gpointer user_data);
-static GtkType nautilus_icon_factory_get_type (void);
-static void nautilus_icon_factory_initialize_class (NautilusIconFactoryClass *class);
-static void nautilus_icon_factory_initialize (NautilusIconFactory *factory);
-static NautilusIconFactory * nautilus_get_current_icon_factory (void);
-static char * nautilus_icon_factory_get_thumbnail_uri (NautilusFile *file,
- gboolean anti_aliased);
-static NautilusIconFactory * nautilus_icon_factory_new (const char *theme_name);
-static void nautilus_icon_factory_set_theme (const char *theme_name);
-static guint nautilus_scalable_icon_hash (gconstpointer p);
-static gboolean nautilus_scalable_icon_equal (gconstpointer a,
- gconstpointer b);
-static void icon_cache_key_destroy (IconCacheKey *key);
-static guint icon_cache_key_hash (gconstpointer p);
-static gboolean icon_cache_key_equal (gconstpointer a,
- gconstpointer b);
-static gboolean vfs_file_exists (const char *file_name);
-static GdkPixbuf * get_image_from_cache (NautilusScalableIcon *scalable_icon,
- const IconSizeRequest *size,
- gboolean picky,
- gboolean custom,
- IconInfo *icon_info);
-static gboolean check_for_thumbnails (NautilusIconFactory *factory);
-static int nautilus_icon_factory_make_thumbnails (gpointer data);
-static GdkPixbuf * load_image_with_embedded_text (NautilusScalableIcon *scalable_icon,
- const IconSizeRequest *size);
-
-NAUTILUS_DEFINE_CLASS_BOILERPLATE (NautilusIconFactory, nautilus_icon_factory, GTK_TYPE_OBJECT)
+static guint nautilus_icon_factory_get_type (void);
+static void nautilus_icon_factory_initialize_class (NautilusIconFactoryClass *class);
+static void nautilus_icon_factory_initialize (NautilusIconFactory *factory);
+static void nautilus_icon_factory_destroy (GtkObject *object);
+static void icon_theme_changed_callback (gpointer user_data);
+static guint nautilus_scalable_icon_hash (gconstpointer p);
+static gboolean nautilus_scalable_icon_equal (gconstpointer a,
+ gconstpointer b);
+static guint cache_key_hash (gconstpointer p);
+static gboolean cache_key_equal (gconstpointer a,
+ gconstpointer b);
+static CacheIcon *get_icon_from_cache (NautilusScalableIcon *scalable_icon,
+ const IconSizeRequest *size,
+ gboolean picky,
+ gboolean custom);
+static CacheIcon *load_icon_with_embedded_text (NautilusScalableIcon *scalable_icon,
+ const IconSizeRequest *size);
+
+NAUTILUS_DEFINE_CLASS_BOILERPLATE (NautilusIconFactory,
+ nautilus_icon_factory,
+ GTK_TYPE_OBJECT)
+
+static NautilusIconFactory *global_icon_factory = NULL;
+
+static void
+destroy_icon_factory (void)
+{
+ nautilus_preferences_remove_callback (NAUTILUS_PREFERENCES_THEME,
+ icon_theme_changed_callback,
+ NULL);
+ gtk_object_unref (GTK_OBJECT (global_icon_factory));
+}
/* Return a pointer to the single global icon factory. */
static NautilusIconFactory *
-nautilus_get_current_icon_factory (void)
+get_icon_factory (void)
{
- static NautilusIconFactory *global_icon_factory = NULL;
if (global_icon_factory == NULL) {
- char *theme_preference, *icon_theme;
+ global_icon_factory = NAUTILUS_ICON_FACTORY
+ (gtk_object_new (nautilus_icon_factory_get_type (), NULL));
- theme_preference = nautilus_preferences_get (NAUTILUS_PREFERENCES_THEME,
- DEFAULT_ICON_THEME);
- g_assert (theme_preference != NULL);
-
- /* give the theme a chance to redirect the icons */
- icon_theme = nautilus_theme_get_theme_data ("icons", "ICON_THEME");
-
- if (icon_theme != NULL) {
- global_icon_factory = nautilus_icon_factory_new (icon_theme);
- } else {
- global_icon_factory = nautilus_icon_factory_new (theme_preference);
- }
-
- g_free (theme_preference);
- g_free (icon_theme);
-
+ /* Update to match the theme. */
+ icon_theme_changed_callback (NULL);
nautilus_preferences_add_callback (NAUTILUS_PREFERENCES_THEME,
icon_theme_changed_callback,
- NULL);
-
+ NULL);
+
+ g_atexit (destroy_icon_factory);
}
return global_icon_factory;
}
@@ -285,20 +288,38 @@ nautilus_get_current_icon_factory (void)
GtkObject *
nautilus_icon_factory_get (void)
{
- return GTK_OBJECT (nautilus_get_current_icon_factory ());
+ return GTK_OBJECT (get_icon_factory ());
}
-/* Create the icon factory. */
-static NautilusIconFactory *
-nautilus_icon_factory_new (const char *theme_name)
+static void
+check_recently_used_list (void)
{
- NautilusIconFactory *factory;
-
- factory = (NautilusIconFactory *) gtk_object_new (nautilus_icon_factory_get_type (), NULL);
+ NautilusIconFactory *factory;
+ NautilusCircularList *head, *node, *next;
+ int count;
- factory->theme_name = g_strdup (theme_name);
+ factory = get_icon_factory ();
+
+ head = &factory->recently_used_dummy_head;
+
+ count = 0;
+
+ node = head;
+ while (1) {
+ next = node->next;
+ g_assert (next != NULL);
+ g_assert (next->prev == node);
+
+ if (next == head) {
+ break;
+ }
+
+ count += 1;
+
+ node = next;
+ }
- return factory;
+ g_assert (count == factory->recently_used_count);
}
static void
@@ -306,8 +327,10 @@ nautilus_icon_factory_initialize (NautilusIconFactory *factory)
{
factory->scalable_icons = g_hash_table_new (nautilus_scalable_icon_hash,
nautilus_scalable_icon_equal);
- factory->icon_cache = g_hash_table_new (icon_cache_key_hash,
- icon_cache_key_equal);
+ factory->cache_icons = g_hash_table_new (g_direct_hash,
+ g_direct_equal);
+ factory->icon_cache = g_hash_table_new (cache_key_hash,
+ cache_key_equal);
/* Empty out the recently-used list. */
factory->recently_used_dummy_head.next = &factory->recently_used_dummy_head;
@@ -330,127 +353,241 @@ nautilus_icon_factory_initialize_class (NautilusIconFactoryClass *class)
GTK_TYPE_NONE, 0);
gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL);
+
+ object_class->destroy = nautilus_icon_factory_destroy;
+}
+
+static void
+cache_key_destroy (CacheKey *key)
+{
+ nautilus_scalable_icon_unref (key->scalable_icon);
+ g_free (key);
+}
+
+static void
+mark_icon_not_outstanding (GdkPixbuf *pixbuf, gpointer callback_data)
+{
+ NautilusIconFactory *factory;
+ CacheIcon *icon;
+
+ g_assert (callback_data == NULL);
+
+ factory = get_icon_factory ();
+
+ icon = g_hash_table_lookup (factory->cache_icons, pixbuf);
+ g_return_if_fail (icon != NULL);
+ g_return_if_fail (icon->pixbuf == pixbuf);
+ g_return_if_fail (icon->outstanding);
+
+ icon->outstanding = FALSE;
+}
+
+static CacheIcon *
+cache_icon_new (GdkPixbuf *pixbuf,
+ gboolean custom,
+ gboolean scaled,
+ const IconDetails *details)
+{
+ NautilusIconFactory *factory;
+ CacheIcon *icon;
+
+ factory = get_icon_factory ();
+
+ /* Just a check to see this is not reusing a pixbuf. */
+ g_assert (g_hash_table_lookup (factory->cache_icons, pixbuf) == NULL);
+
+ /* Grab the pixbuf since we are keeping it. */
+ gdk_pixbuf_ref (pixbuf);
+ gdk_pixbuf_set_last_unref_handler
+ (pixbuf, mark_icon_not_outstanding, NULL);
+
+ /* Make the icon. */
+ icon = g_new0 (CacheIcon, 1);
+ icon->pixbuf = pixbuf;
+ icon->internal_ref_count = 1;
+ icon->custom = custom;
+ icon->scaled = scaled;
+ icon->details = *details;
+
+ /* Put it into the hash table. */
+ g_hash_table_insert (factory->cache_icons, pixbuf, icon);
+ return icon;
+}
+
+static void
+cache_icon_ref (CacheIcon *icon)
+{
+ NautilusIconFactory *factory;
+
+ factory = get_icon_factory ();
+
+ g_assert (icon != NULL);
+ g_assert (icon->internal_ref_count >= 1);
+ g_assert (g_hash_table_lookup (factory->cache_icons, icon->pixbuf) == icon);
+
+ icon->internal_ref_count++;
+}
+
+static void
+cache_icon_unref (CacheIcon *icon)
+{
+ NautilusIconFactory *factory;
+ NautilusCircularList *node;
+
+ factory = get_icon_factory ();
+
+ g_assert (icon != NULL);
+ g_assert (icon->internal_ref_count >= 1);
+ g_assert (g_hash_table_lookup (factory->cache_icons, icon->pixbuf) == icon);
+
+ if (icon->internal_ref_count > 1) {
+ icon->internal_ref_count--;
+ return;
+ }
+
+ check_recently_used_list ();
+
+ /* If it's in the recently used list, free it from there */
+ node = &icon->recently_used_node;
+ if (node->next != NULL) {
+ g_assert (factory->recently_used_count >= 1);
+
+ g_assert (node->next->prev == node);
+ g_assert (node->prev->next == node);
+ g_assert (node->next != node);
+ g_assert (node->prev != node);
+
+ node->next->prev = node->prev;
+ node->prev->next = node->next;
+
+ factory->recently_used_count -= 1;
+ }
+
+ check_recently_used_list ();
+
+
+ /* Remove from the cache icons table. */
+ g_hash_table_remove (factory->cache_icons, icon->pixbuf);
+
+ /* Since it's no longer in the cache, we don't need to notice the last unref. */
+ gdk_pixbuf_set_last_unref_handler (icon->pixbuf, NULL, NULL);
+
+ /* Let go of the pixbuf if we were holding a reference to it.
+ * If it was still outstanding, we didn't have a reference to it,
+ * and we were counting on the unref handler to catch it.
+ */
+ if (!icon->outstanding) {
+ gdk_pixbuf_unref (icon->pixbuf);
+ }
+
+ g_free (icon);
}
-/* Destroy one image in the cache. */
+/* Destroy one pixbuf in the cache. */
static gboolean
-nautilus_icon_factory_destroy_cached_image (gpointer key, gpointer value, gpointer user_data)
+nautilus_icon_factory_destroy_cached_icon (gpointer key, gpointer value, gpointer user_data)
{
- icon_cache_key_destroy (key);
- gdk_pixbuf_unref (value);
+ cache_key_destroy (key);
+ cache_icon_unref (value);
+
+ /* Tell the caller to remove the hash table entry. */
return TRUE;
}
-
/* Reset the cache to the default state. */
static void
nautilus_icon_factory_clear (void)
{
NautilusIconFactory *factory;
+ NautilusCircularList *head;
- factory = nautilus_get_current_icon_factory ();
+ factory = get_icon_factory ();
g_hash_table_foreach_remove (factory->icon_cache,
- nautilus_icon_factory_destroy_cached_image,
+ nautilus_icon_factory_destroy_cached_icon,
NULL);
/* Empty out the recently-used list. */
- factory->recently_used_dummy_head.next = &factory->recently_used_dummy_head;
- factory->recently_used_dummy_head.prev = &factory->recently_used_dummy_head;
- factory->recently_used_count = 0;
+ head = &factory->recently_used_dummy_head;
+ g_assert (factory->recently_used_count == 0);
+ g_assert (head->next == head);
+ g_assert (head->prev == head);
}
-#if 0
-
-/* No one ever destroys the icon factory.
- * There's no public API for doing so.
- * If they did, we'd have to get this right.
- */
-
static void
-nautilus_icon_factory_destroy (NautilusIconFactory *factory)
+nautilus_icon_factory_destroy (GtkObject *object)
{
- nautilus_preferences_remove_callback (NAUTILUS_PREFERENCES_THEME,
- icon_theme_changed_callback,
- NULL);
+ NautilusIconFactory *factory;
+
+ factory = NAUTILUS_ICON_FACTORY (object);
nautilus_icon_factory_clear ();
+
+ if (g_hash_table_size (factory->scalable_icons) != 0) {
+ g_warning ("%d scalable icons still left when destroying icon factory",
+ g_hash_table_size (factory->scalable_icons));
+ }
+ if (g_hash_table_size (factory->icon_cache) != 0) {
+ g_warning ("%d icon cache entries still left when destroying icon factory",
+ g_hash_table_size (factory->icon_cache));
+ }
+
+ g_hash_table_destroy (factory->scalable_icons);
g_hash_table_destroy (factory->icon_cache);
g_free (factory->theme_name);
- g_free (factory);
+
+ NAUTILUS_CALL_PARENT_CLASS (GTK_OBJECT_CLASS, destroy, (object));
}
-#endif
-
static gboolean
-nautilus_icon_factory_possibly_free_cached_image (gpointer key,
+nautilus_icon_factory_possibly_free_cached_icon (gpointer key,
gpointer value,
gpointer user_data)
{
- IconCacheKey *icon_key;
- GdkPixbuf *image;
+ CacheIcon *icon;
+
+ icon = value;
/* Don't free a cache entry that is in the recently used list. */
- icon_key = key;
- if (icon_key->recently_used_node.next != NULL) {
+ if (icon->recently_used_node.next != NULL) {
return FALSE;
}
- /* Don't free a cache entry if the image is still in use. */
- image = value;
-
- /* FIXME bugzilla.eazel.com 640:
- * We treat all entries as "in use", until we get a hook we can use
- * in GdkPixbuf. We are waiting for the "final" hook right now. The
- * one that's in there is not approved of by the Gtk maintainers.
- */
- return FALSE;
-#if 0
- if (image->ref_count > 1) {
+ /* Don't free a cache entry if the pixbuf is still in use. */
+ if (icon->outstanding) {
return FALSE;
}
/* Free the item. */
- return nautilus_icon_factory_destroy_cached_image (key, value, NULL);
-#endif
+ return nautilus_icon_factory_destroy_cached_icon (key, value, NULL);
}
-/* remove images whose uri field matches the passed-in uri */
-
+/* Remove icons whose URI field matches the passed-in URI. */
static gboolean
-nautilus_icon_factory_remove_image_uri (gpointer key,
- gpointer value,
- gpointer user_data)
+nautilus_icon_factory_remove_if_uri_matches (gpointer key,
+ gpointer value,
+ gpointer user_data)
{
char *image_uri;
- IconCacheKey *icon_key;
- NautilusCircularList *node;
- NautilusIconFactory *factory;
+ CacheKey *cache_key;
+ CacheIcon *icon;
- icon_key = key;
+ cache_key = key;
+ icon = value;
image_uri = user_data;
- /* see if the the uri's match - if not, just return */
- if (icon_key->scalable_icon->uri && strcmp(icon_key->scalable_icon->uri, image_uri)) {
+ /* See if the the uri's match - if not, just return. */
+ if (cache_key->scalable_icon->uri != NULL
+ && strcmp (cache_key->scalable_icon->uri, image_uri)) {
return FALSE;
}
- /* if it's in the recently used list, free it from there */
- node = &icon_key->recently_used_node;
- if (node->next != NULL) {
- node->next->prev = node->prev;
- node->prev->next = node->next;
-
- factory = nautilus_get_current_icon_factory ();
- factory->recently_used_count -= 1;
- }
-
/* Free the item. */
- return nautilus_icon_factory_destroy_cached_image (key, value, NULL);
+ return nautilus_icon_factory_destroy_cached_icon (key, value, NULL);
}
-/* Sweep the cache, freeing any images that are not in use and are
+/* Sweep the cache, freeing any icons that are not in use and are
* also not recently used.
*/
static gboolean
@@ -461,7 +598,7 @@ nautilus_icon_factory_sweep (gpointer user_data)
factory = user_data;
g_hash_table_foreach_remove (factory->icon_cache,
- nautilus_icon_factory_possibly_free_cached_image,
+ nautilus_icon_factory_possibly_free_cached_icon,
NULL);
factory->sweep_timer = 0;
@@ -475,7 +612,7 @@ nautilus_icon_factory_schedule_sweep (void)
{
NautilusIconFactory *factory;
- factory = nautilus_get_current_icon_factory ();
+ factory = get_icon_factory ();
if (factory->sweep_timer != 0) {
return;
@@ -486,28 +623,38 @@ nautilus_icon_factory_schedule_sweep (void)
factory);
}
-/* clear a specific image from the cache */
-
-static void
-nautilus_icon_factory_clear_image(const char *image_uri)
+/* Clear a specific icon from the cache. */
+void
+nautilus_icon_factory_remove_by_uri (const char *image_uri)
{
NautilusIconFactory *factory;
/* build the key and look it up in the icon cache */
- factory = nautilus_get_current_icon_factory ();
+ factory = get_icon_factory ();
g_hash_table_foreach_remove (factory->icon_cache,
- nautilus_icon_factory_remove_image_uri,
+ nautilus_icon_factory_remove_if_uri_matches,
(gpointer) image_uri);
}
/* Change the theme. */
-void
-nautilus_icon_factory_set_theme (const char *theme_name)
+static void
+set_theme (const char *theme_name)
{
NautilusIconFactory *factory;
- factory = nautilus_get_current_icon_factory ();
+ if (factory->theme_name == NULL) {
+ if (theme_name == NULL) {
+ return;
+ }
+ } else {
+ if (theme_name != NULL
+ && strcmp (theme_name, factory->theme_name) != 0) {
+ return;
+ }
+ }
+
+ factory = get_icon_factory ();
nautilus_icon_factory_clear ();
@@ -619,24 +766,31 @@ make_full_icon_path (const char *path, const char *suffix)
/* utility routine to parse the attach points string to set up the array in icon_info */
static void
-parse_attach_points (IconInfo *icon_info, const char* attach_point_string)
+parse_attach_points (NautilusEmblemAttachPoints *attach_points, const char *attach_point_string)
{
- char *text_piece;
char **point_array;
- int index, x_offset, y_offset;
-
- /* split the attach point string into a string array, then process
- each point with sscanf in a loop */
+ int i, x_offset, y_offset;
+
+ attach_points->num_points = 0;
+ if (attach_point_string == NULL) {
+ return;
+ }
+
+ /* Split the attach point string into a string array, then process
+ * each point with sscanf in a loop.
+ */
point_array = g_strsplit (attach_point_string, "|", MAX_ATTACH_POINTS);
- for (index = 0; (text_piece = point_array[index]) != NULL; index++) {
- if (sscanf (text_piece, " %d , %d , %*s", &x_offset, &y_offset) == 2) {
- icon_info->attach_points[index].x = x_offset;
- icon_info->attach_points[index].y = y_offset;
+ for (i = 0; point_array[i] != NULL; i++) {
+ if (sscanf (point_array[i], " %d , %d , %*s", &x_offset, &y_offset) == 2) {
+ attach_points->points[attach_points->num_points].x = x_offset;
+ attach_points->points[attach_points->num_points].y = y_offset;
+ attach_points->num_points++;
} else {
- g_warning ("bad attach point specification: %s", text_piece);
- }
+ g_warning ("bad attach point specification: %s", point_array[i]);
+ }
}
+
g_strfreev (point_array);
}
@@ -647,8 +801,8 @@ static char *
get_themed_icon_file_path (const char *theme_name,
const char *icon_name,
guint icon_size,
- IconInfo *icon_info,
- gboolean aa_mode)
+ gboolean aa_mode,
+ IconDetails *details)
{
int i;
gboolean include_size;
@@ -658,6 +812,7 @@ get_themed_icon_file_path (const char *theme_name,
char *size_as_string, *property;
ArtIRect parsed_rect;
NautilusIconFactory *factory;
+ char *user_directory;
g_assert (icon_name != NULL);
@@ -667,16 +822,11 @@ get_themed_icon_file_path (const char *theme_name,
themed_icon_name = g_strconcat (theme_name, "/", icon_name, NULL);
}
- if (icon_info != NULL) {
- icon_info->has_attach_points = FALSE;
- }
-
include_size = icon_size != NAUTILUS_ICON_SIZE_STANDARD;
- factory = (NautilusIconFactory*) nautilus_icon_factory_get();
+ factory = get_icon_factory ();
/* Try each suffix. */
for (i = 0; i < NAUTILUS_N_ELEMENTS (icon_file_name_suffixes); i++) {
-
if (include_size && strcasecmp(icon_file_name_suffixes[i], ".svg")) {
/* Build a path for this icon. */
partial_path = g_strdup_printf ("%s-%u",
@@ -688,9 +838,9 @@ get_themed_icon_file_path (const char *theme_name,
/* if we're in anti-aliased mode, try for an optimized one first */
if (aa_mode) {
- aa_path = g_strdup_printf ("%s-aa", partial_path);
+ aa_path = g_strconcat (partial_path, "-aa", NULL);
path = make_full_icon_path (aa_path,
- icon_file_name_suffixes[i]);
+ icon_file_name_suffixes[i]);
g_free (aa_path);
/* Return the path if the file exists. */
@@ -715,8 +865,8 @@ get_themed_icon_file_path (const char *theme_name,
}
/* Open the XML file to get the text rectangle and emblem attach points */
- if (path != NULL && icon_info != NULL) {
- memset (&icon_info->text_rect, 0, sizeof (icon_info->text_rect));
+ if (path != NULL && details != NULL) {
+ memset (&details->text_rect, 0, sizeof (details->text_rect));
xml_path = make_full_icon_path (themed_icon_name, ".xml");
@@ -737,30 +887,24 @@ get_themed_icon_file_path (const char *theme_name,
&parsed_rect.y0,
&parsed_rect.x1,
&parsed_rect.y1) == 4) {
- icon_info->text_rect = parsed_rect;
+ details->text_rect = parsed_rect;
}
xmlFree (property);
}
property = xmlGetProp (node, "ATTACH_POINTS");
- if (property != NULL) {
- icon_info->has_attach_points = TRUE;
- parse_attach_points (icon_info, property);
- xmlFree (property);
- } else {
- icon_info->has_attach_points = FALSE;
- }
+ parse_attach_points (&details->attach_points, property);
+ xmlFree (property);
xmlFreeDoc (doc);
}
- /* if we still haven't found anything, and we're looking for an emblem,
- check out the user's home directory, since it might be an emblem
- that they've added there */
-
+ /* If we still haven't found anything, and we're looking for an emblem,
+ * check out the user's home directory, since it might be an emblem
+ * that they've added there.
+ */
if (path == NULL && nautilus_str_has_prefix (icon_name, "emblem-")) {
for (i = 0; i < NAUTILUS_N_ELEMENTS (icon_file_name_suffixes); i++) {
- char *user_directory;
user_directory = nautilus_get_user_directory ();
path = g_strdup_printf ("%s/emblems/%s%s",
user_directory,
@@ -781,24 +925,28 @@ get_themed_icon_file_path (const char *theme_name,
return path;
}
-/* Choose the file name to load, taking into account theme vs. non-theme icons. */
+/* Choose the file name to load, taking into account theme
+ * vs. non-theme icons. Also fill in info in the icon structure based
+ * on what's found in the XML file.
+ */
static char *
get_icon_file_path (const char *name,
- const char* modifier,
+ const char *modifier,
guint size_in_pixels,
- IconInfo *icon_info,
- gboolean aa_mode)
+ gboolean aa_mode,
+ IconDetails *details)
{
gboolean use_theme_icon;
const char *theme_name;
char *path;
+ char *name_with_modifier;
if (name == NULL) {
return NULL;
}
use_theme_icon = FALSE;
- theme_name = nautilus_get_current_icon_factory ()->theme_name;
+ theme_name = get_icon_factory ()->theme_name;
/* Check and see if there is a theme icon to use.
* This decision must be based on whether there's a non-size-
@@ -808,8 +956,8 @@ get_icon_file_path (const char *name,
path = get_themed_icon_file_path (theme_name,
name,
NAUTILUS_ICON_SIZE_STANDARD,
- NULL,
- aa_mode);
+ aa_mode,
+ details);
if (path != NULL) {
use_theme_icon = TRUE;
g_free (path);
@@ -817,26 +965,26 @@ get_icon_file_path (const char *name,
}
/* Now we know whether or not to use the theme. */
- /* if there's a modifier, try using that first */
-
+
+ /* If there's a modifier, try the modified icon first. */
if (modifier && modifier[0] != '\0') {
- char* modified_name = g_strdup_printf ("%s-%s", name, modifier);
+ name_with_modifier = g_strconcat (name, "-", modifier, NULL);
path = get_themed_icon_file_path (use_theme_icon ? theme_name : NULL,
- modified_name,
+ name_with_modifier,
size_in_pixels,
- icon_info,
- aa_mode);
- g_free (modified_name);
+ aa_mode,
+ details);
+ g_free (name_with_modifier);
if (path != NULL) {
- return path;
+ return path;
}
}
return get_themed_icon_file_path (use_theme_icon ? theme_name : NULL,
name,
size_in_pixels,
- icon_info,
- aa_mode);
+ aa_mode,
+ details);
}
static void
@@ -844,19 +992,14 @@ icon_theme_changed_callback (gpointer user_data)
{
char *theme_preference, *icon_theme;
- theme_preference = nautilus_preferences_get (NAUTILUS_PREFERENCES_THEME,
- DEFAULT_ICON_THEME);
-
- g_assert (theme_preference != NULL);
-
- /* give the theme a chance to redirect the icons */
+ /* Consult the user preference and the Nautilus theme. In the
+ * long run, we sould just get rid of the user preference.
+ */
+ theme_preference = nautilus_preferences_get
+ (NAUTILUS_PREFERENCES_THEME, DEFAULT_ICON_THEME);
icon_theme = nautilus_theme_get_theme_data ("icons", "ICON_THEME");
- if (icon_theme != NULL) {
- nautilus_icon_factory_set_theme (icon_theme);
- } else {
- nautilus_icon_factory_set_theme (theme_preference);
- }
+ set_theme (icon_theme == NULL ? theme_preference : icon_theme);
g_free (theme_preference);
g_free (icon_theme);
@@ -895,10 +1038,10 @@ nautilus_scalable_icon_new_from_text_pieces (const char *uri,
gboolean anti_aliased)
{
GHashTable *hash_table;
- NautilusScalableIcon icon_key, *icon;
+ NautilusScalableIcon cache_key, *icon;
NautilusIconFactory *factory;
- factory = (NautilusIconFactory*) nautilus_icon_factory_get ();
+ factory = get_icon_factory ();
/* Make empty strings canonical. */
if (uri != NULL && uri[0] == '\0') {
uri = NULL;
@@ -914,16 +1057,16 @@ nautilus_scalable_icon_new_from_text_pieces (const char *uri,
}
/* Get at the hash table. */
- hash_table = nautilus_get_current_icon_factory ()->scalable_icons;
+ hash_table = get_icon_factory ()->scalable_icons;
/* Check to see if it's already in the table. */
- icon_key.uri = (char *) uri;
- icon_key.name = (char *) name;
- icon_key.modifier = (char *) modifier;
- icon_key.embedded_text = (char *) embedded_text;
- icon_key.aa_mode = anti_aliased;
+ cache_key.uri = (char *) uri;
+ cache_key.name = (char *) name;
+ cache_key.modifier = (char *) modifier;
+ cache_key.embedded_text = (char *) embedded_text;
+ cache_key.aa_mode = anti_aliased;
- icon = g_hash_table_lookup (hash_table, &icon_key);
+ icon = g_hash_table_lookup (hash_table, &cache_key);
if (icon == NULL) {
/* Not in the table, so create it and put it in. */
icon = g_new0 (NautilusScalableIcon, 1);
@@ -960,7 +1103,7 @@ nautilus_scalable_icon_unref (NautilusScalableIcon *icon)
return;
}
- hash_table = nautilus_get_current_icon_factory ()->scalable_icons;
+ hash_table = get_icon_factory ()->scalable_icons;
g_hash_table_remove (hash_table, icon);
g_free (icon->uri);
@@ -1068,8 +1211,13 @@ nautilus_icon_factory_get_icon_for_file (NautilusFile *file, const char* modifie
if (nautilus_istr_has_prefix (mime_type, "image/") && should_display_image_file_as_itself (file)) {
if (nautilus_file_get_size (file) < SELF_THUMBNAIL_SIZE_THRESHOLD) {
uri = nautilus_file_get_uri (file);
- } else if (strstr(file_uri, "/.thumbnails/") == NULL) {
- uri = nautilus_icon_factory_get_thumbnail_uri (file, anti_aliased);
+ } else if (strstr (file_uri, "/.thumbnails/") == NULL) {
+ uri = nautilus_get_thumbnail_uri (file, anti_aliased);
+ if (uri == NULL) {
+ get_icon_file_path
+ (ICON_NAME_THUMBNAIL_LOADING, NULL,
+ NAUTILUS_ICON_SIZE_STANDARD, FALSE, NULL);
+ }
}
}
g_free (mime_type);
@@ -1198,336 +1346,6 @@ nautilus_icon_factory_get_emblem_icons_for_file (NautilusFile *file, gboolean an
return g_list_reverse (icons);
}
-/* utility to test whether a file exists using vfs */
-static gboolean
-vfs_file_exists (const char *file_uri)
-{
- GnomeVFSResult result;
- GnomeVFSFileInfo *file_info;
-
- file_info = gnome_vfs_file_info_new ();
-
- /* FIXME bugzilla.eazel.com 3137: the synchronous I/O here means this call is
- unsuitable for use on anything that might be remote. */
-
- result = gnome_vfs_get_file_info (file_uri, file_info, 0);
- gnome_vfs_file_info_unref (file_info);
- return result == GNOME_VFS_OK;
-}
-
-/* FIXME bugzilla.eazel.com 3138: why is this call cut and pasted instead
- of putting it in a common place? */
-
-/* utility copied from Nautilus directory */
-static GnomeVFSResult
-nautilus_make_directory_and_parents (GnomeVFSURI *uri, guint permissions)
-{
- GnomeVFSResult result;
- GnomeVFSURI *parent_uri;
-
- /* FIXME bugzilla.eazel.com 3137: the synchronous I/O in this
- call means it's unsuitable for calling on a URI that might
- be remote. */
-
- /* Make the directory, and return right away unless there's
- a possible problem with the parent.
- */
- result = gnome_vfs_make_directory_for_uri (uri, permissions);
- if (result != GNOME_VFS_ERROR_NOT_FOUND) {
- return result;
- }
-
- /* If we can't get a parent, we are done. */
- parent_uri = gnome_vfs_uri_get_parent (uri);
- if (parent_uri == NULL) {
- return result;
- }
-
- /* If we can get a parent, use a recursive call to create
- the parent and its parents.
- */
- result = nautilus_make_directory_and_parents (parent_uri, permissions);
- gnome_vfs_uri_unref (parent_uri);
- if (result != GNOME_VFS_OK) {
- return result;
- }
-
- /* A second try at making the directory after the parents
- have all been created.
- */
- result = gnome_vfs_make_directory_for_uri (uri, permissions);
- return result;
-}
-
-/* utility routine that, given the uri of an image, constructs the uri to the corresponding thumbnail */
-
-static char *
-make_thumbnail_path (const char *image_uri, gboolean directory_only, gboolean use_local_directory, gboolean anti_aliased)
-{
- char *thumbnail_uri, *thumbnail_path;
- char *directory_name = g_strdup (image_uri);
- char *last_slash = strrchr (directory_name, '/');
- char *dot_pos;
-
- *last_slash = '\0';
-
- /* either use the local directory or one in the user's home directory, as selected by the passed in flag */
- if (use_local_directory)
- thumbnail_uri = g_strdup_printf ("%s/.thumbnails", directory_name);
- else {
- GnomeVFSResult result;
- GnomeVFSURI *thumbnail_directory_uri;
-
- char *escaped_uri = gnome_vfs_escape_slashes (directory_name);
- thumbnail_path = g_strdup_printf ("%s/.nautilus/thumbnails/%s", g_get_home_dir(), escaped_uri);
- thumbnail_uri = gnome_vfs_get_uri_from_local_path (thumbnail_path);
- g_free (thumbnail_path);
- g_free(escaped_uri);
-
- /* we must create the directory if it doesnt exist */
-
- thumbnail_directory_uri = gnome_vfs_uri_new (thumbnail_uri);
-
- /* FIXME bugzilla.eazel.com 3137: synchronous I/O - it
- looks like the URI will be local-only, but best to
- make sure. */
-
- result = nautilus_make_directory_and_parents (thumbnail_directory_uri, THUMBNAIL_DIR_PERMISSIONS);
- gnome_vfs_uri_unref (thumbnail_directory_uri);
- }
-
- /* append the file name if necessary */
- if (!directory_only) {
- char* old_uri = thumbnail_uri;
- thumbnail_uri = g_strdup_printf ("%s/%s", thumbnail_uri, last_slash + 1);
- g_free(old_uri);
-
- /* append the anti-aliased suffix if necessary */
- if (anti_aliased) {
- char *old_uri = thumbnail_uri;
- dot_pos = strrchr (thumbnail_uri, '.');
- if (dot_pos) {
- *dot_pos = '\0';
- thumbnail_uri = g_strdup_printf ("%s.aa.%s", old_uri, dot_pos + 1);
- } else {
- thumbnail_uri = g_strconcat (old_uri, ".aa", NULL);
- }
- g_free (old_uri);
- }
-
- /* append an image suffix if the correct one isn't already present */
- if (!nautilus_istr_has_suffix (image_uri, ".png")) {
- char* old_uri = thumbnail_uri;
- thumbnail_uri = g_strdup_printf ("%s.png", thumbnail_uri);
- g_free(old_uri);
- }
- }
-
- g_free (directory_name);
- return thumbnail_uri;
-}
-
-/* utility routine that takes two uris and returns true if the first file has been modified later than the second */
-/* FIXME bugzilla.eazel.com 2565: it makes synchronous file info calls, so for now, it returns FALSE if either of the uri's are non-local */
-static gboolean
-first_file_more_recent(const char* file_uri, const char* other_file_uri)
-{
- GnomeVFSURI *vfs_uri, *other_vfs_uri;
- gboolean more_recent, is_local;
-
- GnomeVFSFileInfo file_info, other_file_info;
-
- /* if either file is remote, return FALSE. Eventually we'll make this async to fix this */
- vfs_uri = gnome_vfs_uri_new(file_uri);
- other_vfs_uri = gnome_vfs_uri_new(other_file_uri);
- is_local = gnome_vfs_uri_is_local (vfs_uri) && gnome_vfs_uri_is_local (other_vfs_uri);
- gnome_vfs_uri_unref(vfs_uri);
- gnome_vfs_uri_unref(other_vfs_uri);
-
- if (!is_local) {
- return FALSE;
- }
-
- /* gather the info and then compare modification times */
- gnome_vfs_file_info_init (&file_info);
- gnome_vfs_get_file_info (file_uri, &file_info, GNOME_VFS_FILE_INFO_DEFAULT);
-
- gnome_vfs_file_info_init (&other_file_info);
- gnome_vfs_get_file_info (other_file_uri, &other_file_info, GNOME_VFS_FILE_INFO_DEFAULT);
-
- more_recent = file_info.mtime > other_file_info.mtime;
-
- gnome_vfs_file_info_clear (&file_info);
- gnome_vfs_file_info_clear (&other_file_info);
-
- return more_recent;
-}
-
-/* structure used for making thumbnails, associating a uri with where the thumbnail is to be stored */
-
-typedef struct {
- char *thumbnail_uri;
- gboolean is_local;
- gboolean anti_aliased;
-} NautilusThumbnailInfo;
-
-/* GCompareFunc-style function for comparing NautilusThumbnailInfos.
- * Returns 0 if they refer to the same uri.
- */
-static int
-compare_thumbnail_info (gconstpointer a, gconstpointer b)
-{
- NautilusThumbnailInfo *info_a;
- NautilusThumbnailInfo *info_b;
-
- info_a = (NautilusThumbnailInfo *)a;
- info_b = (NautilusThumbnailInfo *)b;
-
- return strcmp (info_a->thumbnail_uri, info_b->thumbnail_uri) != 0;
-}
-
-/* routine that takes a uri of a large image file and returns the uri of its corresponding thumbnail.
- If no thumbnail is available, put the image on the thumbnail queue so one is eventually made. */
-/* FIXME bugzilla.eazel.com 642:
- * Most of this thumbnail machinery belongs in NautilusFile, not here.
- */
-
-static char *
-nautilus_icon_factory_get_thumbnail_uri (NautilusFile *file, gboolean anti_aliased)
-{
- NautilusIconFactory *factory;
- GnomeVFSResult result;
- char *thumbnail_uri;
- char *file_uri;
- gboolean local_flag = TRUE;
- gboolean remake_thumbnail = FALSE;
-
- file_uri = nautilus_file_get_uri (file);
-
- /* compose the uri for the thumbnail locally */
- thumbnail_uri = make_thumbnail_path (file_uri, FALSE, TRUE, anti_aliased);
-
- /* if the thumbnail file already exists locally, simply return the uri */
-
- /* FIXME bugzilla.eazel.com 3137: this synchronous I/O is a
- disaster when loading remote locations. It blocks the UI
- when trying to load a slow remote image over http for
- instance. The fact that we must do this potentially slow
- operation implies the IconFactory interface needs to be
- asynchronous! Either that, or thumbnail existence is
- somthing we need to be able to monitor/call_when_ready on,
- on a NautilusFile. */
-
- if (vfs_file_exists (thumbnail_uri)) {
-
- /* see if the file changed since it was thumbnailed by comparing the modification time */
- remake_thumbnail = first_file_more_recent(file_uri, thumbnail_uri);
-
- /* if the file hasn't changed, return the thumbnail uri */
- if (!remake_thumbnail) {
- g_free (file_uri);
- return thumbnail_uri;
- } else {
- nautilus_icon_factory_clear_image(thumbnail_uri);
-
-
- /* FIXME bugzilla.eazel.com 3137: more potentially
- losing synch I/O. */
-
- gnome_vfs_unlink(thumbnail_uri);
- }
- }
-
- /* now try it globally */
- if (!remake_thumbnail) {
- g_free (thumbnail_uri);
- thumbnail_uri = make_thumbnail_path (file_uri, FALSE, FALSE, anti_aliased);
-
- /* if the thumbnail file already exists in the common area, return that uri */
-
- /* FIXME bugzilla.eazel.com 3137: more potentially losing
- synch I/O - this should be guaranteed local, so
- perhaps not as bad (unless you have an NFS homedir,
- say... */
-
- if (vfs_file_exists (thumbnail_uri)) {
-
- /* see if the file changed since it was thumbnailed by comparing the modification time */
- remake_thumbnail = first_file_more_recent(file_uri, thumbnail_uri);
-
- /* if the file hasn't changed, return the thumbnail uri */
- if (!remake_thumbnail) {
- g_free (file_uri);
- return thumbnail_uri;
- } else {
- nautilus_icon_factory_clear_image(thumbnail_uri);
- /* FIXME bugzilla.eazel.com 3137: more potentially losing
- synch I/O - this should be guaranteed local, so
- perhaps not as bad (unless you have an NFS homedir,
- say... */
- gnome_vfs_unlink(thumbnail_uri);
- }
- }
- }
-
- /* make the thumbnail directory if necessary, at first try it locally */
- g_free (thumbnail_uri);
- local_flag = TRUE;
- thumbnail_uri = make_thumbnail_path (file_uri, TRUE, local_flag, anti_aliased);
-
-
- /* FIXME bugzilla.eazel.com 3137: more potentially losing
- synch I/O - this could be remote */
-
- result = gnome_vfs_make_directory (thumbnail_uri, THUMBNAIL_DIR_PERMISSIONS);
-
- /* if we can't make if locally, try it in the global place */
- if (result != GNOME_VFS_OK && result != GNOME_VFS_ERROR_FILE_EXISTS) {
- g_free (thumbnail_uri);
- local_flag = FALSE;
- thumbnail_uri = make_thumbnail_path (file_uri, TRUE, local_flag, anti_aliased);
- /* FIXME bugzilla.eazel.com 3137: more potentially
- losing synch I/O - this is probably local? */
-
- result = gnome_vfs_make_directory (thumbnail_uri, THUMBNAIL_DIR_PERMISSIONS);
- }
-
- /* the thumbnail needs to be created (or recreated), so add an entry to the thumbnail list */
-
- if (result != GNOME_VFS_OK && result != GNOME_VFS_ERROR_FILE_EXISTS) {
-
- g_warning ("error when making thumbnail directory %d, for %s", result, thumbnail_uri);
- } else {
- NautilusThumbnailInfo *info = g_new0 (NautilusThumbnailInfo, 1);
- info->thumbnail_uri = file_uri;
- info->is_local = local_flag;
- info->anti_aliased = anti_aliased;
-
- factory = nautilus_get_current_icon_factory ();
- if (factory->thumbnails) {
- if (g_list_find_custom (factory->thumbnails, info, compare_thumbnail_info) == NULL) {
- factory->thumbnails = g_list_prepend (factory->thumbnails, info);
- }
- } else {
- factory->thumbnails = g_list_alloc ();
- factory->thumbnails->data = info;
- }
-
- if (factory->timeout_task_id == 0) {
- factory->timeout_task_id = gtk_timeout_add (400, (GtkFunction) nautilus_icon_factory_make_thumbnails, NULL);
- }
- }
-
- g_free (thumbnail_uri);
-
- /* return the uri to the "loading image" icon */
- return get_icon_file_path (ICON_NAME_THUMBNAIL_LOADING,
- NULL,
- NAUTILUS_ICON_SIZE_STANDARD,
- NULL,
- FALSE);
-}
-
static guint
get_larger_icon_size (guint size)
{
@@ -1615,20 +1433,19 @@ get_next_icon_size_to_try (guint target_size, guint *current_size)
/* This loads an SVG image, scaling it to the appropriate size. */
static GdkPixbuf *
-load_specific_image_svg (const char *path, guint size_in_pixels)
+load_pixbuf_svg (const char *path, guint size_in_pixels)
{
FILE *f;
- GdkPixbuf *result;
-
+ GdkPixbuf *pixbuf;
+
f = fopen (path, "rb");
if (f == NULL) {
return NULL;
}
- result = rsvg_render_file (f, size_in_pixels *
- (1.0 / NAUTILUS_ICON_SIZE_STANDARD));
+ pixbuf = rsvg_render_file (f, ((double) size_in_pixels) / NAUTILUS_ICON_SIZE_STANDARD);
fclose (f);
-
- return result;
+
+ return pixbuf;
}
static gboolean
@@ -1653,75 +1470,76 @@ path_represents_svg_image (const char *path)
return is_svg;
}
-/* This load function returns NULL if the icon is not available at this size. */
-static GdkPixbuf *
-load_specific_image (NautilusScalableIcon *scalable_icon,
- guint size_in_pixels,
- gboolean custom,
- IconInfo *icon_info)
+/* This load function returns NULL if the icon is not available at
+ * this size.
+ */
+static CacheIcon *
+load_specific_icon (NautilusScalableIcon *scalable_icon,
+ guint size_in_pixels,
+ gboolean custom)
{
- char *image_path;
+ IconDetails details;
GdkPixbuf *pixbuf;
-
- g_assert (icon_info != NULL);
+ char *path;
+ CacheIcon *icon;
- if (custom) {
- /* Custom icon. */
+ memset (&details, 0, sizeof (details));
+ pixbuf = NULL;
- memset (&icon_info->text_rect, 0, sizeof (icon_info->text_rect));
- icon_info->has_attach_points = FALSE;
-
- /* we use the suffix instead of mime-type here since it may be non-local */
- if (nautilus_istr_has_suffix (scalable_icon->uri, ".svg")) {
- image_path = gnome_vfs_get_local_path_from_uri (scalable_icon->uri);
- pixbuf = load_specific_image_svg (image_path, size_in_pixels);
- g_free (image_path);
- return pixbuf;
- }
-
- if (size_in_pixels == NAUTILUS_ICON_SIZE_STANDARD && scalable_icon->uri != NULL) {
- return nautilus_gdk_pixbuf_load (scalable_icon->uri);
- }
-
- return NULL;
+ /* Get the path. */
+ if (custom) {
+ /* We don't support custom icons that are not local here. */
+ path = gnome_vfs_get_local_path_from_uri (scalable_icon->uri);
} else {
- /* Standard icon. */
- char *path;
- GdkPixbuf *image;
-
path = get_icon_file_path (scalable_icon->name,
scalable_icon->modifier,
size_in_pixels,
- icon_info,
- scalable_icon->aa_mode);
-
- if (path == NULL) {
- return NULL;
- }
+ scalable_icon->aa_mode,
+ &details);
+ }
+ /* Get the icon. */
+ if (path != NULL) {
if (path_represents_svg_image (path)) {
- image = load_specific_image_svg (path, size_in_pixels);
+ pixbuf = load_pixbuf_svg (path, size_in_pixels);
} else {
- image = gdk_pixbuf_new_from_file (path);
+ /* Custom non-svg icons exist at one size.
+ * Non-custom icons have their size encoded in their path.
+ */
+ if (!(custom && size_in_pixels != NAUTILUS_ICON_SIZE_STANDARD)) {
+ pixbuf = gdk_pixbuf_new_from_file (path);
+ }
}
-
+
g_free (path);
- return image;
}
+
+ /* If we got nothing, we can free the icon. */
+ if (pixbuf == NULL) {
+ return NULL;
+ }
+
+ /* Since we got something, we can create a cache icon. */
+ icon = cache_icon_new (pixbuf, custom, FALSE, &details);
+ gdk_pixbuf_unref (pixbuf);
+ return icon;
+}
+
+static void
+destroy_fallback_icon (void)
+{
+ cache_icon_unref (fallback_icon);
}
/* This load function is not allowed to return NULL. */
-static GdkPixbuf *
-load_image_for_scaling (NautilusScalableIcon *scalable_icon,
- guint requested_size,
- guint *actual_size_result,
- gboolean *custom,
- IconInfo *icon_info)
+static CacheIcon *
+load_icon_for_scaling (NautilusScalableIcon *scalable_icon,
+ guint requested_size,
+ guint *actual_size_result)
{
- GdkPixbuf *image;
+ CacheIcon *icon;
guint actual_size;
IconSizeRequest size_request;
- static GdkPixbuf *fallback_image;
size_request.maximum_width = MAXIMUM_ICON_SIZE * requested_size / NAUTILUS_ZOOM_LEVEL_STANDARD;
size_request.maximum_height = size_request.maximum_width;
@@ -1732,15 +1550,11 @@ load_image_for_scaling (NautilusScalableIcon *scalable_icon,
size_request.nominal_width = actual_size;
size_request.nominal_height = actual_size;
- image = get_image_from_cache (scalable_icon,
- &size_request,
- TRUE,
- TRUE,
- icon_info);
- if (image != NULL) {
+ icon = get_icon_from_cache
+ (scalable_icon, &size_request, TRUE, TRUE);
+ if (icon != NULL) {
*actual_size_result = actual_size;
- *custom = TRUE;
- return image;
+ return icon;
}
}
@@ -1750,21 +1564,18 @@ load_image_for_scaling (NautilusScalableIcon *scalable_icon,
size_request.nominal_width = actual_size;
size_request.nominal_height = actual_size;
- image = get_image_from_cache (scalable_icon,
- &size_request,
- TRUE,
- FALSE,
- icon_info);
- if (image != NULL) {
+ icon = get_icon_from_cache
+ (scalable_icon, &size_request, TRUE, FALSE);
+ if (icon != NULL) {
*actual_size_result = actual_size;
- *custom = FALSE;
- return image;
+ return icon;
}
}
/* Finally, fall back on the hard-coded image. */
- if (fallback_image == NULL) {
- fallback_image = gdk_pixbuf_new_from_data
+ if (fallback_icon == NULL) {
+ fallback_icon = g_new0 (CacheIcon, 1);
+ fallback_icon->pixbuf = gdk_pixbuf_new_from_data
(nautilus_default_file_icon,
GDK_COLORSPACE_RGB,
TRUE,
@@ -1774,36 +1585,38 @@ load_image_for_scaling (NautilusScalableIcon *scalable_icon,
nautilus_default_file_icon_width * 4, /* stride */
NULL, /* don't destroy data */
NULL);
+ g_atexit (destroy_fallback_icon);
}
- gdk_pixbuf_ref (fallback_image);
+ cache_icon_ref (fallback_icon);
- memset (&icon_info->text_rect, 0, sizeof (icon_info->text_rect));
*actual_size_result = NAUTILUS_ICON_SIZE_STANDARD;
- *custom = FALSE;
- return fallback_image;
+ return fallback_icon;
}
-/* Consumes the image and returns a scaled one if the image is too big.
- * Note that this does an unref on the image and returns a new one.
+/* Consumes the icon and returns a scaled one if the pixbuf is too big.
+ * Note that this does an unref on the icon and returns a new one.
*/
-static GdkPixbuf *
-scale_image_and_info (GdkPixbuf *image,
- IconInfo *icon_info,
- double scale_x,
- double scale_y)
+static CacheIcon *
+scale_icon (CacheIcon *icon,
+ double scale_x,
+ double scale_y)
{
int width, height;
int rect_width, rect_height;
- int index;
- GdkPixbuf *scaled_image;
+ int i, num_points;
+ GdkPixbuf *scaled_pixbuf;
+ IconDetails scaled_details;
+ CacheIcon *scaled_icon;
- width = gdk_pixbuf_get_width (image);
- height = gdk_pixbuf_get_height (image);
+ g_assert (!icon->scaled);
+
+ width = gdk_pixbuf_get_width (icon->pixbuf);
+ height = gdk_pixbuf_get_height (icon->pixbuf);
/* Check for no-scaling case. */
if ((int) (width * scale_x) == width
&& (int) (height * scale_y) == height) {
- return gdk_pixbuf_ref (image);
+ return NULL;
}
width *= scale_x;
@@ -1815,30 +1628,34 @@ scale_image_and_info (GdkPixbuf *image,
height = 1;
}
- rect_width = (icon_info->text_rect.x1 - icon_info->text_rect.x0) * scale_x;
- rect_height = (icon_info->text_rect.y1 - icon_info->text_rect.y0) * scale_y;
+ scaled_pixbuf = gdk_pixbuf_scale_simple
+ (icon->pixbuf, width, height, GDK_INTERP_BILINEAR);
+
+ rect_width = (icon->details.text_rect.x1 - icon->details.text_rect.x0) * scale_x;
+ rect_height = (icon->details.text_rect.y1 - icon->details.text_rect.y0) * scale_y;
- scaled_image = gdk_pixbuf_scale_simple
- (image, width, height, GDK_INTERP_BILINEAR);
- gdk_pixbuf_unref (image);
-
- icon_info->text_rect.x0 *= scale_x;
- icon_info->text_rect.y0 *= scale_y;
- icon_info->text_rect.x1 = icon_info->text_rect.x0 + rect_width;
- icon_info->text_rect.y1 = icon_info->text_rect.y0 + rect_height;
-
- if (icon_info->has_attach_points) {
- for (index = 0; index < MAX_ATTACH_POINTS; index++) {
- icon_info->attach_points[index].x *= scale_x;
- icon_info->attach_points[index].y *= scale_y;
- }
+ scaled_details.text_rect.x0 = icon->details.text_rect.x0 * scale_x;
+ scaled_details.text_rect.y0 = icon->details.text_rect.x0 * scale_y;
+ scaled_details.text_rect.x1 = scaled_details.text_rect.x0 + rect_width;
+ scaled_details.text_rect.y1 = scaled_details.text_rect.y0 + rect_height;
+
+ num_points = icon->details.attach_points.num_points;
+ scaled_details.attach_points.num_points = num_points;
+ for (i = 0; i < num_points; i++) {
+ scaled_details.attach_points.points[i].x = icon->details.attach_points.points[i].x * scale_x;
+ scaled_details.attach_points.points[i].y = icon->details.attach_points.points[i].y * scale_y;
}
- return scaled_image;
+ scaled_icon = cache_icon_new (scaled_pixbuf,
+ icon->custom,
+ TRUE,
+ &scaled_details);
+ gdk_pixbuf_unref (scaled_pixbuf);
+ return scaled_icon;
}
static void
-revise_scale_factors_if_too_big (GdkPixbuf *image,
+revise_scale_factors_if_too_big (GdkPixbuf *pixbuf,
const IconSizeRequest *size,
double *scale_x,
double *scale_y)
@@ -1846,8 +1663,8 @@ revise_scale_factors_if_too_big (GdkPixbuf *image,
int width, height;
double y_distortion;
- width = gdk_pixbuf_get_width (image);
- height = gdk_pixbuf_get_height (image);
+ width = gdk_pixbuf_get_width (pixbuf);
+ height = gdk_pixbuf_get_height (pixbuf);
if ((int) (width * *scale_x) <= size->maximum_width
&& (int) (height * *scale_y) <= size->maximum_height) {
@@ -1861,49 +1678,46 @@ revise_scale_factors_if_too_big (GdkPixbuf *image,
*scale_y = *scale_x * y_distortion;
}
-/* Consumes the image and returns a scaled one if the image is too big.
- * Note that this does an unref on the image and returns a new one.
- */
-static GdkPixbuf *
-scale_image_down_if_too_big (GdkPixbuf *image,
- const IconSizeRequest *size,
- IconInfo *icon_info)
+/* Returns a scaled icon if this one is too big. */
+static CacheIcon *
+scale_down_if_too_big (CacheIcon *icon,
+ const IconSizeRequest *size)
{
double scale_x, scale_y;
scale_x = 1.0;
scale_y = 1.0;
- revise_scale_factors_if_too_big (image, size, &scale_x, &scale_y);
- return scale_image_and_info (image, icon_info, scale_x, scale_y);
+ revise_scale_factors_if_too_big (icon->pixbuf, size, &scale_x, &scale_y);
+ return scale_icon (icon, scale_x, scale_y);
}
/* This load function is not allowed to return NULL. */
-static GdkPixbuf *
-load_image_scale_if_necessary (NautilusScalableIcon *scalable_icon,
- const IconSizeRequest *size,
- gboolean *scaled,
- gboolean *custom,
- IconInfo *icon_info)
+static CacheIcon *
+load_icon_scale_if_necessary (NautilusScalableIcon *scalable_icon,
+ const IconSizeRequest *size)
{
- GdkPixbuf *image;
+ CacheIcon *icon, *scaled_icon;
guint nominal_actual_size;
double scale_x, scale_y;
- /* Load the image for the icon that's closest in size to what we want. */
- image = load_image_for_scaling (scalable_icon, size->nominal_width,
- &nominal_actual_size, custom, icon_info);
- if (size->nominal_width == nominal_actual_size
- && size->nominal_height == nominal_actual_size) {
- *scaled = FALSE;
- return scale_image_down_if_too_big (image, size, icon_info);
- }
+ /* Load the icon that's closest in size to what we want. */
+ icon = load_icon_for_scaling (scalable_icon,
+ size->nominal_width,
+ &nominal_actual_size);
- /* Scale the image to the size we want. */
- *scaled = TRUE;
+ /* Scale the pixbuf to the size we want. */
scale_x = (double) size->nominal_width / nominal_actual_size;
scale_y = (double) size->nominal_height / nominal_actual_size;
- revise_scale_factors_if_too_big (image, size, &scale_x, &scale_y);
- return scale_image_and_info (image, icon_info, scale_x, scale_y);
+ revise_scale_factors_if_too_big (icon->pixbuf, size, &scale_x, &scale_y);
+ scaled_icon = scale_icon (icon, scale_x, scale_y);
+ if (scaled_icon == NULL) {
+ return icon;
+ }
+
+ /* Mark this icon as scaled, too. */
+ cache_icon_unref (icon);
+ g_assert (scaled_icon->scaled);
+ return scaled_icon;
}
/* Move this item to the head of the recently-used list,
@@ -1915,7 +1729,9 @@ mark_recently_used (NautilusCircularList *node)
NautilusIconFactory *factory;
NautilusCircularList *head, *last_node;
- factory = nautilus_get_current_icon_factory ();
+ check_recently_used_list ();
+
+ factory = get_icon_factory ();
head = &factory->recently_used_dummy_head;
/* Move the node to the start of the list. */
@@ -1928,9 +1744,9 @@ mark_recently_used (NautilusCircularList *node)
/* Node was not already in the list, so add it.
* If the list is already full, remove the last node.
*/
- if (factory->recently_used_count < ICON_CACHE_COUNT)
- factory->recently_used_count++;
- else {
+ if (factory->recently_used_count < ICON_CACHE_COUNT) {
+ factory->recently_used_count += 1;
+ } else {
/* Remove the last node. */
last_node = head->prev;
@@ -1951,101 +1767,104 @@ mark_recently_used (NautilusCircularList *node)
node->next->prev = node;
head->next = node;
}
+
+ check_recently_used_list ();
}
-/* utility routine that checks if a cached image has changed since it was cached.
- * It returns TRUE if the image is still valid, and removes it from the cache if it's not */
-
- static gboolean
- cached_image_still_valid (const char *file_uri, time_t cached_time)
- {
+/* Utility routine that checks if a cached icon has changed since it
+ * was cached. It returns TRUE if the icon is still valid, and
+ * removes it from the cache if it's not.
+ */
+static gboolean
+cached_icon_still_valid (const char *file_uri, time_t cached_time)
+{
GnomeVFSURI *vfs_uri;
GnomeVFSFileInfo file_info;
+ GnomeVFSResult result;
gboolean is_local, is_valid;
- /* if there's no specific file, simply return TRUE */
- if (file_uri == NULL)
+ /* If there's no specific file, simply return TRUE. */
+ if (file_uri == NULL) {
return TRUE;
+ }
- /* FIXME bugzilla.eazel.com 2566: if the URI is remote, assume it's valid to avoid delay of testing. Eventually we'll make this async to fix this */
- vfs_uri = gnome_vfs_uri_new(file_uri);
+ /* FIXME bugzilla.eazel.com 2566: if the URI is remote, assume
+ * it's valid to avoid delay of testing. Eventually we'll have
+ * to make this async to fix this.
+ */
+ vfs_uri = gnome_vfs_uri_new (file_uri);
is_local = gnome_vfs_uri_is_local (vfs_uri);
- gnome_vfs_uri_unref(vfs_uri);
+ gnome_vfs_uri_unref (vfs_uri);
if (!is_local) {
return TRUE;
}
- /* gather the info and then compare modification times */
+ /* Gather the info and then compare modification times. */
gnome_vfs_file_info_init (&file_info);
- gnome_vfs_get_file_info (file_uri, &file_info, GNOME_VFS_FILE_INFO_DEFAULT);
-
- is_valid = file_info.mtime <= cached_time;
+ result = gnome_vfs_get_file_info (file_uri, &file_info, GNOME_VFS_FILE_INFO_DEFAULT);
+ is_valid = result == GNOME_VFS_OK && file_info.mtime <= cached_time;
gnome_vfs_file_info_clear (&file_info);
/* if it's not valid, remove it from the cache */
if (!is_valid) {
- nautilus_icon_factory_clear_image (file_uri);
+ nautilus_icon_factory_remove_by_uri (file_uri);
}
return is_valid;
- }
-
-/* Get the image for icon, handling the caching.
+}
+
+/* Get the icon, handling the caching.
* If @picky is true, then only an unscaled icon is acceptable.
* Also, if @picky is true, the icon must be a custom icon if
* @custom is true or a standard icon is @custom is false.
*/
-static GdkPixbuf *
-get_image_from_cache (NautilusScalableIcon *scalable_icon,
- const IconSizeRequest *size,
- gboolean picky,
- gboolean custom,
- IconInfo *icon_info)
+static CacheIcon *
+get_icon_from_cache (NautilusScalableIcon *scalable_icon,
+ const IconSizeRequest *size,
+ gboolean picky,
+ gboolean custom)
{
NautilusIconFactory *factory;
GHashTable *hash_table;
- IconCacheKey lookup_key, *key;
- GdkPixbuf *image;
+ CacheKey lookup_key, *key;
+ CacheIcon *icon, *scaled_icon;
gpointer key_in_table, value;
- gboolean found_image;
g_return_val_if_fail (scalable_icon != NULL, NULL);
key = NULL;
- image = NULL;
+ icon = NULL;
- factory = nautilus_get_current_icon_factory ();
+ factory = get_icon_factory ();
hash_table = factory->icon_cache;
/* Check to see if it's already in the table. */
lookup_key.scalable_icon = scalable_icon;
lookup_key.size = *size;
- found_image = FALSE;
if (g_hash_table_lookup_extended (hash_table, &lookup_key,
&key_in_table, &value)) {
/* Found it in the table. */
+ g_assert (key_in_table != NULL);
+ g_assert (value != NULL);
key = key_in_table;
+ icon = value;
/* If we're going to be picky, then don't accept anything
* other than exactly what we are looking for.
*/
- if (picky && (key->scaled || custom != key->custom)) {
+ if (picky && (icon->scaled || custom != icon->custom)) {
return NULL;
}
- image = value;
- found_image = cached_image_still_valid (scalable_icon->uri, key->cache_time);
- g_assert (image != NULL);
+ /* Check if the cached image is good before using it. */
+ if (!cached_icon_still_valid (scalable_icon->uri,
+ icon->cache_time)) {
+ icon = NULL;
+ }
}
- if (!found_image) {
- gboolean got_scaled_image;
- gboolean got_custom_image;
- IconInfo key_icon_info;
-
- key_icon_info.has_attach_points = FALSE;
-
+ if (icon == NULL) {
/* Not in the table, so load the image. */
/* If we're picky, then we want the image only if this exact
* nominal size is available.
@@ -2054,80 +1873,59 @@ get_image_from_cache (NautilusScalableIcon *scalable_icon,
g_assert (scalable_icon->embedded_text == NULL);
/* Actual icons have nominal sizes that are square! */
- if (size->nominal_width
- != size->nominal_height) {
+ if (size->nominal_width != size->nominal_height) {
return NULL;
}
/* Get the image. */
- image = load_specific_image (scalable_icon,
- size->nominal_width,
- custom,
- &key_icon_info);
- if (image == NULL) {
+ icon = load_specific_icon (scalable_icon,
+ size->nominal_width,
+ custom);
+ if (icon == NULL) {
return NULL;
}
- /* Now we have the image, but is it bigger than
- * the maximum size? If so we scale it, even but we don't
- * call it "scaled" for caching purposese.
+ /* Now we have the image, but is it bigger
+ * than the maximum size? If so we scale it,
+ * but we don't call it "scaled" for caching
+ * purposese.
*/
- image = scale_image_down_if_too_big (image, size, &key_icon_info);
-
- got_scaled_image = FALSE;
- got_custom_image = custom;
+ scaled_icon = scale_down_if_too_big (icon, size);
+ if (scaled_icon != NULL) {
+ scaled_icon->scaled = FALSE;
+ cache_icon_unref (icon);
+ icon = scaled_icon;
+ }
} else {
if (scalable_icon->embedded_text != NULL) {
- image = load_image_with_embedded_text (scalable_icon, size);
-
- /* None of these matters for an icon with text already embedded.
- * So we fill in with arbitrary values.
- */
- got_scaled_image = FALSE;
- got_custom_image = FALSE;
- memset (&key_icon_info.text_rect, 0, sizeof (key_icon_info.text_rect));
+ icon = load_icon_with_embedded_text (scalable_icon, size);
} else {
- image = load_image_scale_if_necessary
- (scalable_icon,
- size,
- &got_scaled_image,
- &got_custom_image,
- &key_icon_info);
+ icon = load_icon_scale_if_necessary (scalable_icon, size);
}
- g_assert (image != NULL);
+ g_assert (icon != NULL);
}
- /* Add the embedded text. */
-
- /* Create the key for the table. */
- key = g_new0 (IconCacheKey, 1);
+ /* Create the key and icon for the hash table. */
+ key = g_new (CacheKey, 1);
nautilus_scalable_icon_ref (scalable_icon);
key->scalable_icon = scalable_icon;
key->size = *size;
- key->scaled = got_scaled_image;
- key->custom = got_custom_image;
- key->icon_info = key_icon_info;
- key->cache_time = time(NULL);
/* Add the item to the hash table. */
- g_hash_table_insert (hash_table, key, image);
+ g_assert (g_hash_table_lookup (hash_table, key) == NULL);
+ g_hash_table_insert (hash_table, key, icon);
}
- /* Return the icon info if the caller asked for it. */
- if (icon_info != NULL) {
- *icon_info = key->icon_info;
- }
+ /* Hand back a ref to the caller. */
+ cache_icon_ref (icon);
/* Since this item was used, keep it in the cache longer. */
- mark_recently_used (&key->recently_used_node);
+ mark_recently_used (&icon->recently_used_node);
/* Come back later and sweep the cache. */
nautilus_icon_factory_schedule_sweep ();
- /* Grab a ref for the caller. */
- g_assert (image != NULL);
- gdk_pixbuf_ref (image);
- return image;
+ return icon;
}
GdkPixbuf *
@@ -2136,41 +1934,42 @@ nautilus_icon_factory_get_pixbuf_for_icon (NautilusScalableIcon *scalable_icon,
guint nominal_height,
guint maximum_width,
guint maximum_height,
- EmblemAttachPoints *attach_data)
+ NautilusEmblemAttachPoints *attach_points)
{
IconSizeRequest size;
- IconInfo icon_info;
+ CacheIcon *icon;
GdkPixbuf *pixbuf;
- int index;
size.nominal_width = nominal_width;
size.nominal_height = nominal_width;
size.maximum_width = maximum_width;
size.maximum_height = maximum_height;
- pixbuf = get_image_from_cache (scalable_icon, &size,
- FALSE, scalable_icon->uri != NULL,
- &icon_info);
- if (attach_data != NULL) {
- attach_data->has_attach_points = icon_info.has_attach_points;
- for (index = 0; index < MAX_ATTACH_POINTS; index++) {
- attach_data->attach_points[index] = icon_info.attach_points[index];
- }
+ icon = get_icon_from_cache (scalable_icon, &size,
+ FALSE, scalable_icon->uri != NULL);
+
+ if (attach_points != NULL) {
+ *attach_points = icon->details.attach_points;
}
- return pixbuf;
-}
-
+ /* The first time we hand out an icon we just leave it with a
+ * single ref (we'll get called back for the unref), but
+ * subsequent times we add additional refs.
+ */
+ pixbuf = icon->pixbuf;
+ if (!icon->outstanding) {
+ icon->outstanding = TRUE;
+ } else {
+ gdk_pixbuf_ref (pixbuf);
+ }
+ cache_icon_unref (icon);
-static void
-icon_cache_key_destroy (IconCacheKey *key)
-{
- nautilus_scalable_icon_unref (key->scalable_icon);
+ return pixbuf;
}
static guint
-icon_cache_key_hash (gconstpointer p)
+cache_key_hash (gconstpointer p)
{
- const IconCacheKey *key;
+ const CacheKey *key;
key = p;
return (((((((GPOINTER_TO_UINT (key->scalable_icon) << 4)
@@ -2181,9 +1980,9 @@ icon_cache_key_hash (gconstpointer p)
}
static gboolean
-icon_cache_key_equal (gconstpointer a, gconstpointer b)
+cache_key_equal (gconstpointer a, gconstpointer b)
{
- const IconCacheKey *key_a, *key_b;
+ const CacheKey *key_a, *key_b;
key_a = a;
key_b = b;
@@ -2305,290 +2104,117 @@ embed_text (GdkPixbuf *pixbuf_without_text,
const ArtIRect *embedded_text_rect,
const char *text)
{
- if (smooth_graphics) {
- GdkPixbuf *pixbuf_with_text = NULL;
- NautilusScalableFont *font;
- const guint font_size = 9;
- const guint line_offset = 1;
- const guint empty_line_height = font_size / 2;
-
- /* Quick out for the case where there's no place to embed the
- * text or the place is too small or there's no text.
- */
- if (!embedded_text_rect_usable (embedded_text_rect) || nautilus_strlen (text) == 0) {
- return gdk_pixbuf_ref (pixbuf_without_text);
- }
-
- /* FIXME bugzilla.eazel.com 1102: Embedded text should use preferences to determine
- * the font it uses
- */
- font = NAUTILUS_SCALABLE_FONT (nautilus_scalable_font_new ("helvetica", "medium", NULL, NULL));
-
- pixbuf_with_text = gdk_pixbuf_copy (pixbuf_without_text);
-
- nautilus_scalable_font_draw_text_lines (font,
- pixbuf_with_text,
- embedded_text_rect->x0,
- embedded_text_rect->y0,
- embedded_text_rect,
- font_size,
- font_size,
- text,
- GTK_JUSTIFY_LEFT,
- line_offset,
- empty_line_height,
- NAUTILUS_RGB_COLOR_BLACK,
- 255,
- FALSE);
-
- gtk_object_unref (GTK_OBJECT (font));
-
- return pixbuf_with_text;
+ NautilusScalableFont *smooth_font;
+ static GdkFont *font;
+ GdkPixbuf *pixbuf_with_text;
+
+ g_return_val_if_fail (pixbuf_without_text != NULL, NULL);
+ g_return_val_if_fail (embedded_text_rect != NULL, NULL);
+
+ /* Quick out for the case where there's no place to embed the
+ * text or the place is too small or there's no text.
+ */
+ if (!embedded_text_rect_usable (embedded_text_rect) || nautilus_strlen (text) == 0) {
+ return NULL;
}
- else {
- static GdkFont *font;
- GdkPixbuf *pixbuf_with_text;
+ pixbuf_with_text = gdk_pixbuf_copy (pixbuf_without_text);
- g_return_val_if_fail (pixbuf_without_text != NULL, NULL);
- g_return_val_if_fail (embedded_text_rect != NULL, gdk_pixbuf_ref (pixbuf_without_text));
+ if (smooth_graphics) {
+ smooth_font = NAUTILUS_SCALABLE_FONT
+ (nautilus_scalable_font_new
+ (EMBEDDED_TEXT_FONT_FAMILY,
+ EMBEDDED_TEXT_FONT_WEIGHT,
+ EMBEDDED_TEXT_FONT_SLANT,
+ EMBEDDED_TEXT_FONT_SET_WIDTH));
+
+ nautilus_scalable_font_draw_text_lines
+ (smooth_font,
+ pixbuf_with_text,
+ embedded_text_rect->x0,
+ embedded_text_rect->y0,
+ embedded_text_rect,
+ EMBEDDED_TEXT_FONT_SIZE,
+ EMBEDDED_TEXT_FONT_SIZE,
+ text,
+ GTK_JUSTIFY_LEFT,
+ EMBEDDED_TEXT_LINE_OFFSET,
+ EMBEDDED_TEXT_EMPTY_LINE_HEIGHT,
+ NAUTILUS_RGB_COLOR_BLACK,
+ 255,
+ FALSE);
+ gtk_object_unref (GTK_OBJECT (smooth_font));
+ } else {
/* Get the font the first time through. */
if (font == NULL) {
/* FIXME bugzilla.eazel.com 1102: Embedded text should use preferences to determine
* the font it uses
*/
-
- /* for anti-aliased text, we choose a large font and scale it down */
- font = gdk_font_load ("-*-helvetica-medium-r-normal-*-10-*-*-*-*-*-*-*");
- g_return_val_if_fail (font != NULL, gdk_pixbuf_ref (pixbuf_without_text));
+ font = gdk_font_load (_("-*-helvetica-medium-r-normal-*-10-*-*-*-*-*-*-*"));
+ g_return_val_if_fail (font != NULL, NULL);
}
- /* Quick out for the case where there's no place to embed the
- * text or the place is too small or there's no text.
- */
- if (!embedded_text_rect_usable (embedded_text_rect) || nautilus_strlen (text) == 0) {
- return gdk_pixbuf_ref (pixbuf_without_text);
- }
-
- pixbuf_with_text = gdk_pixbuf_copy (pixbuf_without_text);
-
- nautilus_gdk_pixbuf_draw_text (pixbuf_with_text, font, 1.0, embedded_text_rect,
- text, NAUTILUS_RGB_COLOR_BLACK, 0xFF);
- return pixbuf_with_text;
+ nautilus_gdk_pixbuf_draw_text
+ (pixbuf_with_text, font, 1.0, embedded_text_rect,
+ text, NAUTILUS_RGB_COLOR_BLACK, 0xFF);
}
+
+ return pixbuf_with_text;
}
-static GdkPixbuf *
-load_image_with_embedded_text (NautilusScalableIcon *scalable_icon,
- const IconSizeRequest *size)
+static CacheIcon *
+load_icon_with_embedded_text (NautilusScalableIcon *scalable_icon,
+ const IconSizeRequest *size)
{
NautilusScalableIcon *scalable_icon_without_text;
- GdkPixbuf *pixbuf_without_text, *pixbuf;
- IconInfo icon_info;
+ CacheIcon *icon_without_text, *icon_with_text;
+ GdkPixbuf *pixbuf_with_text;
+ IconDetails details;
g_assert (scalable_icon->embedded_text != NULL);
-
+
+ /* Get the icon without text. */
scalable_icon_without_text = nautilus_scalable_icon_new_from_text_pieces
(scalable_icon->uri,
scalable_icon->name,
scalable_icon->modifier,
NULL,
scalable_icon->aa_mode);
-
- pixbuf_without_text = get_image_from_cache
+ icon_without_text = get_icon_from_cache
(scalable_icon_without_text, size,
- FALSE, FALSE, &icon_info);
+ FALSE, FALSE);
nautilus_scalable_icon_unref (scalable_icon_without_text);
- pixbuf = embed_text (pixbuf_without_text,
- &icon_info. text_rect,
- scalable_icon->embedded_text);
- gdk_pixbuf_unref (pixbuf_without_text);
+ /* Create a pixbuf with the text in it. */
+ pixbuf_with_text = embed_text (icon_without_text->pixbuf,
+ &icon_without_text->details.text_rect,
+ scalable_icon->embedded_text);
+ if (pixbuf_with_text == NULL) {
+ return icon_without_text;
+ }
- return pixbuf;
+ /* Create an icon from the new pixbuf. */
+ details = icon_without_text->details;
+ memset (&details.text_rect, 0, sizeof (details.text_rect));
+ icon_with_text = cache_icon_new (pixbuf_with_text,
+ icon_without_text->custom,
+ icon_without_text->scaled,
+ &details);
+ cache_icon_unref (icon_without_text);
+ gdk_pixbuf_unref (pixbuf_with_text);
+
+ return icon_with_text;
}
/* Convenience function for unrefing and then freeing an entire list. */
void
nautilus_scalable_icon_list_free (GList *icon_list)
{
- nautilus_g_list_free_deep_custom (icon_list, (GFunc) nautilus_scalable_icon_unref, NULL);
-}
-
-/* check_for_thumbnails is a utility that checks to see if any of the thumbnails in the pending
- list have been created yet. If it finds one, it removes the elements from the queue and
- returns true, otherwise it returns false */
-static gboolean
-check_for_thumbnails (NautilusIconFactory *factory)
-{
- char *current_thumbnail;
- NautilusThumbnailInfo *info;
- GList *stop_element;
- GList *next_thumbnail;
- NautilusFile *file;
-
- for (next_thumbnail = factory->thumbnails;
- next_thumbnail != NULL;
- next_thumbnail = next_thumbnail->next) {
- info = (NautilusThumbnailInfo*) next_thumbnail->data;
- current_thumbnail = make_thumbnail_path (info->thumbnail_uri, FALSE, info->is_local, info->anti_aliased);
- /* FIXME bugzilla.eazel.com 3137: synchronous I/O */
- if (vfs_file_exists (current_thumbnail)) {
- /* we found one, so update the icon and remove all of the elements up to and including
- this one from the pending list. */
- g_free (current_thumbnail);
- file = nautilus_file_get (info->thumbnail_uri);
-
- if (file != NULL) {
- nautilus_file_changed (file);
- nautilus_file_unref (file);
- }
-
- stop_element = next_thumbnail->next;
- while (factory->thumbnails != stop_element) {
- info = (NautilusThumbnailInfo *) factory->thumbnails->data;
- g_free (info->thumbnail_uri);
- g_free (info);
- factory->thumbnails = g_list_remove_link (factory->thumbnails, factory->thumbnails);
- }
- return TRUE;
- }
-
- g_free (current_thumbnail);
- }
-
- return FALSE;
-}
-
-/* make_thumbnails is invoked periodically as a timer task to launch a task to make thumbnails */
-
-static GdkPixbuf*
-load_thumbnail_frame (gboolean anti_aliased)
-{
- char *image_path;
- GdkPixbuf *frame_image;
-
- /* load the thumbnail frame */
- image_path = nautilus_theme_get_image_path (anti_aliased ? "thumbnail_frame.aa.png" : "thumbnail_frame.png");
- frame_image = gdk_pixbuf_new_from_file (image_path);
- g_free (image_path);
- return frame_image;
-}
-
-static int
-nautilus_icon_factory_make_thumbnails (gpointer data)
-{
- pid_t thumbnail_pid;
- NautilusThumbnailInfo *info;
- NautilusIconFactory *factory = nautilus_get_current_icon_factory();
- GList *next_thumbnail = factory->thumbnails;
- GdkPixbuf *scaled_image, *framed_image, *thumbnail_image_frame;
- char *frame_offset_str;
- int left_offset, top_offset, right_offset, bottom_offset;
-
- /* if the queue is empty, there's nothing more to do */
- if (next_thumbnail == NULL) {
- gtk_timeout_remove (factory->timeout_task_id);
- factory->timeout_task_id = 0;
- return FALSE;
- }
-
- info = (NautilusThumbnailInfo *) next_thumbnail->data;
-
- /* see which state we're in. If a thumbnail isn't in progress, start one up. Otherwise,
- check if the pending one is completed. */
- if (factory->thumbnail_in_progress) {
- if (check_for_thumbnails(factory)) {
- factory->thumbnail_in_progress = FALSE;
- }
- }
- else {
- /* start up a task to make the thumbnail corresponding to the queue element. */
-
- /* First, compute the path name of the target thumbnail */
- g_free (factory->new_thumbnail_path);
- factory->new_thumbnail_path = make_thumbnail_path (info->thumbnail_uri, FALSE, info->is_local, info->anti_aliased);
-
- /* fork a task to make the thumbnail, using gdk-pixbuf to do the scaling */
- if (!(thumbnail_pid = fork())) {
- GdkPixbuf* full_size_image;
- NautilusFile *file;
- char *thumbnail_path;
-
- file = nautilus_file_get (info->thumbnail_uri);
- full_size_image = NULL;
-
- if (nautilus_file_is_mime_type (file, "image/svg")) {
- thumbnail_path = gnome_vfs_get_local_path_from_uri (info->thumbnail_uri);
- if (thumbnail_path != NULL) {
- FILE *f = fopen (thumbnail_path, "rb");
- if (f != NULL) {
- full_size_image = rsvg_render_file (f, 1.0);
- fclose (f);
- }
- }
- } else {
- if (info->thumbnail_uri != NULL)
- full_size_image = nautilus_gdk_pixbuf_load (info->thumbnail_uri);
- }
- nautilus_file_unref (file);
-
- if (full_size_image != NULL) {
- thumbnail_image_frame = load_thumbnail_frame (info->anti_aliased);
-
- /* scale the content image as necessary */
- scaled_image = nautilus_gdk_pixbuf_scale_down_to_fit(full_size_image, 96, 96);
- gdk_pixbuf_unref (full_size_image);
-
- /* embed the content image in the frame */
- frame_offset_str = nautilus_theme_get_theme_data ("thumbnails", "FRAME_OFFSETS");
- if (frame_offset_str != NULL) {
- sscanf (frame_offset_str," %d , %d , %d , %d %*s", &left_offset, &top_offset, &right_offset, &bottom_offset);
- } else {
- /* use nominal values since the info in the theme couldn't be found */
- left_offset = 3; top_offset = 3;
- right_offset = 6; bottom_offset = 6;
- }
-
- framed_image = nautilus_embed_image_in_frame (scaled_image, thumbnail_image_frame,
- left_offset, top_offset, right_offset, bottom_offset);
- g_free (frame_offset_str);
-
- gdk_pixbuf_unref (scaled_image);
- gdk_pixbuf_unref (thumbnail_image_frame);
-
- thumbnail_path = gnome_vfs_get_local_path_from_uri (factory->new_thumbnail_path);
- if (!nautilus_gdk_pixbuf_save_to_file (framed_image, thumbnail_path)) {
- g_warning ("error saving thumbnail %s", thumbnail_path);
- }
- g_free (thumbnail_path);
- gdk_pixbuf_unref (framed_image);
- }
- else {
- /* gdk-pixbuf couldn't load the image, so trying using ImageMagick */
- char *temp_str;
- thumbnail_path = gnome_vfs_get_local_path_from_uri (factory->new_thumbnail_path);
- temp_str = g_strdup_printf ("png:%s", thumbnail_path);
- g_free (thumbnail_path);
-
- thumbnail_path = gnome_vfs_get_local_path_from_uri (info->thumbnail_uri);
-
- /* scale the image */
- execlp ("convert", "convert", "-geometry", "96x96", thumbnail_path, temp_str, NULL);
-
- /* we don't come back from this call, so no point in freeing anything up */
- }
-
- _exit(0);
- }
- factory->thumbnail_in_progress = TRUE;
- }
-
- return TRUE; /* we're not done yet */
+ nautilus_g_list_free_deep_custom
+ (icon_list, (GFunc) nautilus_scalable_icon_unref, NULL);
}
-
#if ! defined (NAUTILUS_OMIT_SELF_CHECK)
static char *
diff --git a/libnautilus-private/nautilus-icon-factory.h b/libnautilus-private/nautilus-icon-factory.h
index 857d78d55..1742e3d4b 100644
--- a/libnautilus-private/nautilus-icon-factory.h
+++ b/libnautilus-private/nautilus-icon-factory.h
@@ -82,9 +82,9 @@ typedef struct NautilusScalableIcon NautilusScalableIcon;
#define MAX_ATTACH_POINTS 8
typedef struct {
- gboolean has_attach_points;
- GdkPoint attach_points[MAX_ATTACH_POINTS];
-} EmblemAttachPoints;
+ int num_points;
+ GdkPoint points[MAX_ATTACH_POINTS];
+} NautilusEmblemAttachPoints;
/* Instead of a class declaration here, I will just document
* the signals.
@@ -98,19 +98,19 @@ typedef struct {
GtkObject * nautilus_icon_factory_get (void);
/* Relationship between zoom levels and icons sizes. */
-guint nautilus_get_icon_size_for_zoom_level (NautilusZoomLevel zoom_level);
+guint nautilus_get_icon_size_for_zoom_level (NautilusZoomLevel zoom_level);
/* Choose the appropriate icon, but don't render it yet. */
-NautilusScalableIcon *nautilus_icon_factory_get_icon_for_file (NautilusFile *file,
- const char *modifier,
- gboolean anti_aliased);
-gboolean nautilus_icon_factory_is_icon_ready_for_file (NautilusFile *file);
-GList * nautilus_icon_factory_get_required_file_attributes (void);
-GList * nautilus_icon_factory_get_emblem_icons_for_file (NautilusFile *file,
- gboolean anti_aliased,
- NautilusStringList *exclude);
-NautilusScalableIcon *nautilus_icon_factory_get_emblem_icon_by_name (const char *emblem_name,
- gboolean anti_aliased);
+NautilusScalableIcon *nautilus_icon_factory_get_icon_for_file (NautilusFile *file,
+ const char *modifier,
+ gboolean anti_aliased);
+gboolean nautilus_icon_factory_is_icon_ready_for_file (NautilusFile *file);
+GList * nautilus_icon_factory_get_required_file_attributes (void);
+GList * nautilus_icon_factory_get_emblem_icons_for_file (NautilusFile *file,
+ gboolean anti_aliased,
+ NautilusStringList *exclude);
+NautilusScalableIcon *nautilus_icon_factory_get_emblem_icon_by_name (const char *emblem_name,
+ gboolean anti_aliased);
/* Render an icon to a particular size.
* Ownership of a ref. count in this pixbuf comes with the deal.
@@ -118,59 +118,59 @@ NautilusScalableIcon *nautilus_icon_factory_get_emblem_icon_by_name (const cha
* that X and Y scaling are the same. Optionally, we also pass
* back an array of emblem attach points, if the pointer is non-null
*/
-GdkPixbuf * nautilus_icon_factory_get_pixbuf_for_icon (NautilusScalableIcon *scalable_icon,
- guint nominal_size_in_pixels_x,
- guint nominal_size_in_pixels_y,
- guint maximum_size_in_pixels_x,
- guint maximum_size_in_pixels_y,
- EmblemAttachPoints *attach_points);
+GdkPixbuf * nautilus_icon_factory_get_pixbuf_for_icon (NautilusScalableIcon *scalable_icon,
+ guint nominal_size_in_pixels_x,
+ guint nominal_size_in_pixels_y,
+ guint maximum_size_in_pixels_x,
+ guint maximum_size_in_pixels_y,
+ NautilusEmblemAttachPoints *attach_points);
/* Convenience functions for the common case where you want to choose
* and render the icon into a pixbuf all at once.
*/
-GdkPixbuf * nautilus_icon_factory_get_pixbuf_for_file (NautilusFile *file,
- const char *modifer,
- guint size_in_pixels,
- gboolean anti_aliased);
+GdkPixbuf * nautilus_icon_factory_get_pixbuf_for_file (NautilusFile *file,
+ const char *modifer,
+ guint size_in_pixels,
+ gboolean anti_aliased);
/* Convenience functions for legacy interfaces that require a pixmap and
* bitmap. Maybe we can get rid of these one day.
*/
-void nautilus_icon_factory_get_pixmap_and_mask_for_file (NautilusFile *file,
- const char *modifer,
- guint size_in_pixels,
- GdkPixmap **pixmap,
- GdkBitmap **mask);
+void nautilus_icon_factory_get_pixmap_and_mask_for_file (NautilusFile *file,
+ const char *modifer,
+ guint size_in_pixels,
+ GdkPixmap **pixmap,
+ GdkBitmap **mask);
/* Manage a scalable icon.
* Since the factory always passes out references to the same scalable
* icon, you can compare two scalable icons to see if they are the same
* with ==.
*/
-void nautilus_scalable_icon_ref (NautilusScalableIcon *scalable_icon);
-void nautilus_scalable_icon_unref (NautilusScalableIcon *scalable_icon);
+void nautilus_scalable_icon_ref (NautilusScalableIcon *scalable_icon);
+void nautilus_scalable_icon_unref (NautilusScalableIcon *scalable_icon);
/* A scalable icon can be decomposed into text and reconstituted later
* using nautilus_scalable_icon_new_from_text_pieces. This is the way
* to store scalable icons in metadata or other files.
*/
-void nautilus_scalable_icon_get_text_pieces (NautilusScalableIcon *scalable_icon,
- char **uri_return,
- char **name_return,
- char **modifier_return,
- char **embedded_text_return);
+void nautilus_scalable_icon_get_text_pieces (NautilusScalableIcon *scalable_icon,
+ char **uri_return,
+ char **name_return,
+ char **modifier_return,
+ char **embedded_text_return);
/* Get a scalable icon using the earlier results of
* nautilus_scalable_icon_get_text_pieces.
*/
-NautilusScalableIcon *nautilus_scalable_icon_new_from_text_pieces (const char *uri,
- const char *name,
- const char *modifier,
- const char *embedded_text,
- gboolean anti_aliased);
+NautilusScalableIcon *nautilus_scalable_icon_new_from_text_pieces (const char *uri,
+ const char *name,
+ const char *modifier,
+ const char *embedded_text,
+ gboolean anti_aliased);
/* Convenience function for freeing a list of scalable icons.
* Unrefs all the icons before freeing the list.
*/
-void nautilus_scalable_icon_list_free (GList *scalable_icon_list);
+void nautilus_scalable_icon_list_free (GList *scalable_icon_list);
#endif /* NAUTILUS_ICON_FACTORY_H */
diff --git a/libnautilus-private/nautilus-preferences.c b/libnautilus-private/nautilus-preferences.c
index 8dd5f0482..f17f57b9f 100644
--- a/libnautilus-private/nautilus-preferences.c
+++ b/libnautilus-private/nautilus-preferences.c
@@ -121,6 +121,7 @@ static void preferences_hash_node_remove_callback
static PreferencesHashNode * preferences_hash_node_lookup (const char *name);
static void preferences_register (const char *name);
static gboolean preferences_initialize_if_needed (void);
+static void preferences_shutdown (void);
static char * preferences_make_make_gconf_key (const char *preference_name);
/* GConf callbacks */
@@ -130,7 +131,7 @@ static void preferences_gconf_by_user_level_callback
GConfValue *value,
gboolean is_default,
gpointer user_data);
-static void preferences_gconf_callback (GConfClient *client,
+static void preferences_gconf_callback (GConfClient *client,
guint cnxn_id,
const gchar *key,
GConfValue *value,
@@ -737,6 +738,8 @@ preferences_initialize_if_needed (void)
user_level_changed_callback,
NULL);
+ g_atexit (preferences_shutdown);
+
return TRUE;
}
@@ -1048,8 +1051,8 @@ nautilus_preferences_get (const char *name,
return value;
}
-void
-nautilus_preferences_shutdown (void)
+static void
+preferences_shutdown (void)
{
if (GLOBAL.preference_table == NULL && GLOBAL.gconf_client == NULL) {
return;
diff --git a/libnautilus-private/nautilus-preferences.h b/libnautilus-private/nautilus-preferences.h
index b9368210c..56632462b 100644
--- a/libnautilus-private/nautilus-preferences.h
+++ b/libnautilus-private/nautilus-preferences.h
@@ -89,8 +89,6 @@ void nautilus_preferences_set (const char
const char *value);
char * nautilus_preferences_get (const char *name,
const gchar *default_value);
-void nautilus_preferences_shutdown (void);
-
END_GNOME_DECLS
diff --git a/libnautilus-private/nautilus-thumbnails.c b/libnautilus-private/nautilus-thumbnails.c
new file mode 100644
index 000000000..a4a7be26d
--- /dev/null
+++ b/libnautilus-private/nautilus-thumbnails.c
@@ -0,0 +1,505 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
+
+ nautilus-thumbnails.h: Thumbnail code for icon factory.
+
+ Copyright (C) 2000 Eazel, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with this program; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Author: Andy Hertzfeld <andy@eazel.com>
+*/
+
+#include <config.h>
+#include "nautilus-thumbnails.h"
+
+#include <libgnomevfs/gnome-vfs-file-info.h>
+#include <string.h>
+#include "nautilus-file-utilities.h"
+#include "nautilus-string.h"
+#include <gtk/gtkmain.h>
+#include "nautilus-icon-factory-private.h"
+#include "nautilus-directory-notify.h"
+#include "nautilus-theme.h"
+#include <stdio.h>
+#include "nautilus-gdk-pixbuf-extensions.h"
+#include <unistd.h>
+#include <librsvg/rsvg.h>
+#include "nautilus-graphic-effects.h"
+
+/* permissions for thumbnail directory */
+#define THUMBNAIL_DIR_PERMISSIONS (GNOME_VFS_PERM_USER_ALL \
+ | GNOME_VFS_PERM_GROUP_ALL \
+ | GNOME_VFS_PERM_OTHER_ALL)
+
+/* thumbnail task state */
+static GList *thumbnails;
+static char *new_thumbnail_path;
+static gboolean thumbnail_in_progress;
+
+/* id of timeout task for making thumbnails */
+static int thumbnail_timeout_id;
+
+static int make_thumbnails (gpointer data);
+
+/* utility to test whether a file exists using vfs */
+static gboolean
+vfs_file_exists (const char *file_uri)
+{
+ GnomeVFSResult result;
+ GnomeVFSFileInfo *file_info;
+
+ file_info = gnome_vfs_file_info_new ();
+
+ /* FIXME bugzilla.eazel.com 3137: the synchronous I/O here means this call is
+ unsuitable for use on anything that might be remote. */
+
+ result = gnome_vfs_get_file_info (file_uri, file_info, 0);
+ gnome_vfs_file_info_unref (file_info);
+ return result == GNOME_VFS_OK;
+}
+
+/* utility routine that, given the uri of an image, constructs the uri to the corresponding thumbnail */
+
+static char *
+make_thumbnail_path (const char *image_uri, gboolean directory_only, gboolean use_local_directory, gboolean anti_aliased)
+{
+ char *thumbnail_uri, *thumbnail_path;
+ char *directory_name = g_strdup (image_uri);
+ char *last_slash = strrchr (directory_name, '/');
+ char *dot_pos;
+
+ *last_slash = '\0';
+
+ /* either use the local directory or one in the user's home directory, as selected by the passed in flag */
+ if (use_local_directory) {
+ thumbnail_uri = g_strdup_printf ("%s/.thumbnails", directory_name);
+ } else {
+ GnomeVFSResult result;
+ GnomeVFSURI *thumbnail_directory_uri;
+
+ char *escaped_uri = gnome_vfs_escape_slashes (directory_name);
+ thumbnail_path = g_strdup_printf ("%s/.nautilus/thumbnails/%s", g_get_home_dir(), escaped_uri);
+ thumbnail_uri = gnome_vfs_get_uri_from_local_path (thumbnail_path);
+ g_free (thumbnail_path);
+ g_free(escaped_uri);
+
+ /* we must create the directory if it doesnt exist */
+
+ thumbnail_directory_uri = gnome_vfs_uri_new (thumbnail_uri);
+
+ /* FIXME bugzilla.eazel.com 3137: synchronous I/O - it
+ looks like the URI will be local-only, but best to
+ make sure. */
+
+ result = nautilus_make_directory_and_parents (thumbnail_directory_uri, THUMBNAIL_DIR_PERMISSIONS);
+ gnome_vfs_uri_unref (thumbnail_directory_uri);
+ }
+
+ /* append the file name if necessary */
+ if (!directory_only) {
+ char* old_uri = thumbnail_uri;
+ thumbnail_uri = g_strdup_printf ("%s/%s", thumbnail_uri, last_slash + 1);
+ g_free(old_uri);
+
+ /* append the anti-aliased suffix if necessary */
+ if (anti_aliased) {
+ char *old_uri = thumbnail_uri;
+ dot_pos = strrchr (thumbnail_uri, '.');
+ if (dot_pos) {
+ *dot_pos = '\0';
+ thumbnail_uri = g_strdup_printf ("%s.aa.%s", old_uri, dot_pos + 1);
+ } else {
+ thumbnail_uri = g_strconcat (old_uri, ".aa", NULL);
+ }
+ g_free (old_uri);
+ }
+
+ /* append an image suffix if the correct one isn't already present */
+ if (!nautilus_istr_has_suffix (image_uri, ".png")) {
+ char* old_uri = thumbnail_uri;
+ thumbnail_uri = g_strdup_printf ("%s.png", thumbnail_uri);
+ g_free(old_uri);
+ }
+ }
+
+ g_free (directory_name);
+ return thumbnail_uri;
+}
+
+/* utility routine that takes two uris and returns true if the first file has been modified later than the second */
+/* FIXME bugzilla.eazel.com 2565: it makes synchronous file info calls, so for now, it returns FALSE if either of the uri's are non-local */
+static gboolean
+first_file_more_recent(const char* file_uri, const char* other_file_uri)
+{
+ GnomeVFSURI *vfs_uri, *other_vfs_uri;
+ gboolean more_recent, is_local;
+
+ GnomeVFSFileInfo file_info, other_file_info;
+
+ /* if either file is remote, return FALSE. Eventually we'll make this async to fix this */
+ vfs_uri = gnome_vfs_uri_new(file_uri);
+ other_vfs_uri = gnome_vfs_uri_new(other_file_uri);
+ is_local = gnome_vfs_uri_is_local (vfs_uri) && gnome_vfs_uri_is_local (other_vfs_uri);
+ gnome_vfs_uri_unref(vfs_uri);
+ gnome_vfs_uri_unref(other_vfs_uri);
+
+ if (!is_local) {
+ return FALSE;
+ }
+
+ /* gather the info and then compare modification times */
+ gnome_vfs_file_info_init (&file_info);
+ gnome_vfs_get_file_info (file_uri, &file_info, GNOME_VFS_FILE_INFO_DEFAULT);
+
+ gnome_vfs_file_info_init (&other_file_info);
+ gnome_vfs_get_file_info (other_file_uri, &other_file_info, GNOME_VFS_FILE_INFO_DEFAULT);
+
+ more_recent = file_info.mtime > other_file_info.mtime;
+
+ gnome_vfs_file_info_clear (&file_info);
+ gnome_vfs_file_info_clear (&other_file_info);
+
+ return more_recent;
+}
+
+/* structure used for making thumbnails, associating a uri with where the thumbnail is to be stored */
+
+typedef struct {
+ char *thumbnail_uri;
+ gboolean is_local;
+ gboolean anti_aliased;
+} NautilusThumbnailInfo;
+
+/* GCompareFunc-style function for comparing NautilusThumbnailInfos.
+ * Returns 0 if they refer to the same uri.
+ */
+static int
+compare_thumbnail_info (gconstpointer a, gconstpointer b)
+{
+ NautilusThumbnailInfo *info_a;
+ NautilusThumbnailInfo *info_b;
+
+ info_a = (NautilusThumbnailInfo *)a;
+ info_b = (NautilusThumbnailInfo *)b;
+
+ return strcmp (info_a->thumbnail_uri, info_b->thumbnail_uri) != 0;
+}
+
+/* routine that takes a uri of a large image file and returns the uri of its corresponding thumbnail.
+ If no thumbnail is available, put the image on the thumbnail queue so one is eventually made. */
+/* FIXME bugzilla.eazel.com 642:
+ * Most of this thumbnail machinery belongs in NautilusFile, not here.
+ */
+
+char *
+nautilus_get_thumbnail_uri (NautilusFile *file, gboolean anti_aliased)
+{
+ GnomeVFSResult result;
+ char *thumbnail_uri;
+ char *file_uri;
+ gboolean local_flag = TRUE;
+ gboolean remake_thumbnail = FALSE;
+
+ file_uri = nautilus_file_get_uri (file);
+
+ /* compose the uri for the thumbnail locally */
+ thumbnail_uri = make_thumbnail_path (file_uri, FALSE, TRUE, anti_aliased);
+
+ /* if the thumbnail file already exists locally, simply return the uri */
+
+ /* FIXME bugzilla.eazel.com 3137: this synchronous I/O is a
+ disaster when loading remote locations. It blocks the UI
+ when trying to load a slow remote image over http for
+ instance. The fact that we must do this potentially slow
+ operation implies the IconFactory interface needs to be
+ asynchronous! Either that, or thumbnail existence is
+ somthing we need to be able to monitor/call_when_ready on,
+ on a NautilusFile. */
+
+ if (vfs_file_exists (thumbnail_uri)) {
+
+ /* see if the file changed since it was thumbnailed by comparing the modification time */
+ remake_thumbnail = first_file_more_recent (file_uri, thumbnail_uri);
+
+ /* if the file hasn't changed, return the thumbnail uri */
+ if (!remake_thumbnail) {
+ g_free (file_uri);
+ return thumbnail_uri;
+ } else {
+ nautilus_icon_factory_remove_by_uri (thumbnail_uri);
+
+ /* FIXME bugzilla.eazel.com 3137: more potentially
+ losing synch I/O. */
+ gnome_vfs_unlink (thumbnail_uri);
+ }
+ }
+
+ /* now try it globally */
+ if (!remake_thumbnail) {
+ g_free (thumbnail_uri);
+ thumbnail_uri = make_thumbnail_path (file_uri, FALSE, FALSE, anti_aliased);
+
+ /* if the thumbnail file already exists in the common area, return that uri */
+
+ /* FIXME bugzilla.eazel.com 3137: more potentially losing
+ synch I/O - this should be guaranteed local, so
+ perhaps not as bad (unless you have an NFS homedir,
+ say... */
+
+ if (vfs_file_exists (thumbnail_uri)) {
+
+ /* see if the file changed since it was thumbnailed by comparing the modification time */
+ remake_thumbnail = first_file_more_recent(file_uri, thumbnail_uri);
+
+ /* if the file hasn't changed, return the thumbnail uri */
+ if (!remake_thumbnail) {
+ g_free (file_uri);
+ return thumbnail_uri;
+ } else {
+ nautilus_icon_factory_remove_by_uri (thumbnail_uri);
+
+ /* FIXME bugzilla.eazel.com 3137: more potentially losing
+ synch I/O - this should be guaranteed local, so
+ perhaps not as bad (unless you have an NFS homedir,
+ say... */
+ gnome_vfs_unlink (thumbnail_uri);
+ }
+ }
+ }
+
+ /* make the thumbnail directory if necessary, at first try it locally */
+ g_free (thumbnail_uri);
+ local_flag = TRUE;
+ thumbnail_uri = make_thumbnail_path (file_uri, TRUE, local_flag, anti_aliased);
+
+
+ /* FIXME bugzilla.eazel.com 3137: more potentially losing
+ synch I/O - this could be remote */
+
+ result = gnome_vfs_make_directory (thumbnail_uri, THUMBNAIL_DIR_PERMISSIONS);
+
+ /* if we can't make if locally, try it in the global place */
+ if (result != GNOME_VFS_OK && result != GNOME_VFS_ERROR_FILE_EXISTS) {
+ g_free (thumbnail_uri);
+ local_flag = FALSE;
+ thumbnail_uri = make_thumbnail_path (file_uri, TRUE, local_flag, anti_aliased);
+ /* FIXME bugzilla.eazel.com 3137: more potentially
+ losing synch I/O - this is probably local? */
+
+ result = gnome_vfs_make_directory (thumbnail_uri, THUMBNAIL_DIR_PERMISSIONS);
+ }
+
+ /* the thumbnail needs to be created (or recreated), so add an entry to the thumbnail list */
+
+ if (result != GNOME_VFS_OK && result != GNOME_VFS_ERROR_FILE_EXISTS) {
+
+ g_warning ("error when making thumbnail directory %d, for %s", result, thumbnail_uri);
+ } else {
+ NautilusThumbnailInfo *info = g_new0 (NautilusThumbnailInfo, 1);
+ info->thumbnail_uri = file_uri;
+ info->is_local = local_flag;
+ info->anti_aliased = anti_aliased;
+
+ if (thumbnails != NULL) {
+ if (g_list_find_custom (thumbnails, info, compare_thumbnail_info) == NULL) {
+ thumbnails = g_list_prepend (thumbnails, info);
+ }
+ } else {
+ thumbnails = g_list_alloc ();
+ thumbnails->data = info;
+ }
+
+ if (thumbnail_timeout_id == 0) {
+ thumbnail_timeout_id = gtk_timeout_add
+ (400, make_thumbnails, NULL);
+ }
+ }
+
+ g_free (thumbnail_uri);
+
+ /* Return NULL to indicate the thumbnail is loading. */
+ return NULL;
+}
+
+/* check_for_thumbnails is a utility that checks to see if any of the thumbnails in the pending
+ list have been created yet. If it finds one, it removes the elements from the queue and
+ returns true, otherwise it returns false
+*/
+static gboolean
+check_for_thumbnails (void)
+{
+ char *current_thumbnail;
+ NautilusThumbnailInfo *info;
+ GList *stop_element;
+ GList *next_thumbnail;
+ NautilusFile *file;
+
+ for (next_thumbnail = thumbnails;
+ next_thumbnail != NULL;
+ next_thumbnail = next_thumbnail->next) {
+ info = (NautilusThumbnailInfo*) next_thumbnail->data;
+ current_thumbnail = make_thumbnail_path (info->thumbnail_uri, FALSE, info->is_local, info->anti_aliased);
+ /* FIXME bugzilla.eazel.com 3137: synchronous I/O */
+ if (vfs_file_exists (current_thumbnail)) {
+ /* we found one, so update the icon and remove all of the elements up to and including
+ this one from the pending list. */
+ g_free (current_thumbnail);
+ file = nautilus_file_get (info->thumbnail_uri);
+
+ if (file != NULL) {
+ nautilus_file_changed (file);
+ nautilus_file_unref (file);
+ }
+
+ stop_element = next_thumbnail->next;
+ while (thumbnails != stop_element) {
+ info = (NautilusThumbnailInfo *) thumbnails->data;
+ g_free (info->thumbnail_uri);
+ g_free (info);
+ thumbnails = g_list_remove_link (thumbnails, thumbnails);
+ }
+ return TRUE;
+ }
+
+ g_free (current_thumbnail);
+ }
+
+ return FALSE;
+}
+
+/* make_thumbnails is invoked periodically as a timer task to launch a task to make thumbnails */
+
+static GdkPixbuf*
+load_thumbnail_frame (gboolean anti_aliased)
+{
+ char *image_path;
+ GdkPixbuf *frame_image;
+
+ /* load the thumbnail frame */
+ image_path = nautilus_theme_get_image_path (anti_aliased ? "thumbnail_frame.aa.png" : "thumbnail_frame.png");
+ frame_image = gdk_pixbuf_new_from_file (image_path);
+ g_free (image_path);
+ return frame_image;
+}
+
+static int
+make_thumbnails (gpointer data)
+{
+ pid_t thumbnail_pid;
+ NautilusThumbnailInfo *info;
+ GList *next_thumbnail = thumbnails;
+ GdkPixbuf *scaled_image, *framed_image, *thumbnail_image_frame;
+ char *frame_offset_str;
+ int left_offset, top_offset, right_offset, bottom_offset;
+
+ /* if the queue is empty, there's nothing more to do */
+ if (next_thumbnail == NULL) {
+ gtk_timeout_remove (thumbnail_timeout_id);
+ thumbnail_timeout_id = 0;
+ return FALSE;
+ }
+
+ info = (NautilusThumbnailInfo *) next_thumbnail->data;
+
+ /* see which state we're in. If a thumbnail isn't in progress, start one up. Otherwise,
+ check if the pending one is completed. */
+ if (thumbnail_in_progress) {
+ if (check_for_thumbnails ()) {
+ thumbnail_in_progress = FALSE;
+ }
+ } else {
+ /* start up a task to make the thumbnail corresponding to the queue element. */
+
+ /* First, compute the path name of the target thumbnail */
+ g_free (new_thumbnail_path);
+ new_thumbnail_path = make_thumbnail_path (info->thumbnail_uri, FALSE, info->is_local, info->anti_aliased);
+
+ /* fork a task to make the thumbnail, using gdk-pixbuf to do the scaling */
+ if (!(thumbnail_pid = fork())) {
+ GdkPixbuf* full_size_image;
+ NautilusFile *file;
+ char *thumbnail_path;
+
+ file = nautilus_file_get (info->thumbnail_uri);
+ full_size_image = NULL;
+
+ if (nautilus_file_is_mime_type (file, "image/svg")) {
+ thumbnail_path = gnome_vfs_get_local_path_from_uri (info->thumbnail_uri);
+ if (thumbnail_path != NULL) {
+ FILE *f = fopen (thumbnail_path, "rb");
+ if (f != NULL) {
+ full_size_image = rsvg_render_file (f, 1.0);
+ fclose (f);
+ }
+ }
+ } else {
+ if (info->thumbnail_uri != NULL)
+ full_size_image = nautilus_gdk_pixbuf_load (info->thumbnail_uri);
+ }
+ nautilus_file_unref (file);
+
+ if (full_size_image != NULL) {
+ thumbnail_image_frame = load_thumbnail_frame (info->anti_aliased);
+
+ /* scale the content image as necessary */
+ scaled_image = nautilus_gdk_pixbuf_scale_down_to_fit(full_size_image, 96, 96);
+ gdk_pixbuf_unref (full_size_image);
+
+ /* embed the content image in the frame */
+ frame_offset_str = nautilus_theme_get_theme_data ("thumbnails", "FRAME_OFFSETS");
+ if (frame_offset_str != NULL) {
+ sscanf (frame_offset_str," %d , %d , %d , %d %*s", &left_offset, &top_offset, &right_offset, &bottom_offset);
+ } else {
+ /* use nominal values since the info in the theme couldn't be found */
+ left_offset = 3; top_offset = 3;
+ right_offset = 6; bottom_offset = 6;
+ }
+
+ framed_image = nautilus_embed_image_in_frame (scaled_image, thumbnail_image_frame,
+ left_offset, top_offset, right_offset, bottom_offset);
+ g_free (frame_offset_str);
+
+ gdk_pixbuf_unref (scaled_image);
+ gdk_pixbuf_unref (thumbnail_image_frame);
+
+ thumbnail_path = gnome_vfs_get_local_path_from_uri (new_thumbnail_path);
+ if (!nautilus_gdk_pixbuf_save_to_file (framed_image, thumbnail_path)) {
+ g_warning ("error saving thumbnail %s", thumbnail_path);
+ }
+ g_free (thumbnail_path);
+ gdk_pixbuf_unref (framed_image);
+ } else {
+ /* gdk-pixbuf couldn't load the image, so trying using ImageMagick */
+ char *temp_str;
+ thumbnail_path = gnome_vfs_get_local_path_from_uri (new_thumbnail_path);
+ temp_str = g_strdup_printf ("png:%s", thumbnail_path);
+ g_free (thumbnail_path);
+
+ thumbnail_path = gnome_vfs_get_local_path_from_uri (info->thumbnail_uri);
+
+ /* scale the image */
+ execlp ("convert", "convert", "-geometry", "96x96", thumbnail_path, temp_str, NULL);
+
+ /* we don't come back from this call, so no point in freeing anything up */
+ }
+
+ _exit(0);
+ }
+ thumbnail_in_progress = TRUE;
+ }
+
+ return TRUE; /* we're not done yet */
+}
diff --git a/libnautilus-private/nautilus-thumbnails.h b/libnautilus-private/nautilus-thumbnails.h
new file mode 100644
index 000000000..32f61bf09
--- /dev/null
+++ b/libnautilus-private/nautilus-thumbnails.h
@@ -0,0 +1,33 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
+
+ nautilus-thumbnails.h: Thumbnail code for icon factory.
+
+ Copyright (C) 2000 Eazel, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with this program; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Author: Andy Hertzfeld <andy@eazel.com>
+*/
+
+#ifndef NAUTILUS_THUMBNAILS_H
+#define NAUTILUS_THUMBNAILS_H
+
+#include "nautilus-file.h"
+
+/* Returns NULL if there's no thumbnail yet. */
+char *nautilus_get_thumbnail_uri (NautilusFile *file, gboolean anti_aliased);
+
+#endif /* NAUTILUS_THUMBNAILS_H */
diff --git a/src/file-manager/fm-icon-view.c b/src/file-manager/fm-icon-view.c
index 9186c203b..e07e9b793 100644
--- a/src/file-manager/fm-icon-view.c
+++ b/src/file-manager/fm-icon-view.c
@@ -1731,36 +1731,40 @@ band_select_ended_callback (NautilusIconContainer *container,
/* here's the timer task that actually plays the file using mpg123. */
/* FIXME bugzilla.eazel.com 1258: we should get the application from our mime-type stuff */
-static gint
-play_file (NautilusFile *file)
+static int
+play_file (gpointer callback_data)
{
+ NautilusFile *file;
char *file_uri;
char *file_path, *mime_type;
-
- mp3_pid = fork ();
- if (mp3_pid == (pid_t) 0) {
- file_uri = nautilus_file_get_uri (file);
- file_path = gnome_vfs_get_local_path_from_uri (file_uri);
-
- if (file_path != NULL) {
- mime_type = nautilus_file_get_mime_type (file);
+ gboolean is_mp3;
- /* set the group (session) id to this process for future killing */
+ file = NAUTILUS_FILE (callback_data);
+ file_uri = nautilus_file_get_uri (file);
+ file_path = gnome_vfs_get_local_path_from_uri (file_uri);
+ mime_type = nautilus_file_get_mime_type (file);
+ is_mp3 = nautilus_strcasecmp (mime_type, "audio/x-mp3") == 0;
+
+ if (file_path != NULL) {
+ mp3_pid = fork ();
+ if (mp3_pid == (pid_t) 0) {
+ /* Set the group (session) id to this process for future killing. */
setsid();
- if (nautilus_strcasecmp (mime_type, "audio/x-mp3") == 0) {
+ if (is_mp3) {
execlp ("mpg123", "mpg123", "-y", "-q", file_path, NULL);
} else {
execlp ("play", "play", file_path, NULL);
}
-
+
+ /* Who cares about storage leaks in the fork? */
+ _exit (0);
}
- g_free (file_path);
- g_free (mime_type);
- g_free (file_uri);
-
- _exit (0);
}
+ g_free (file_path);
+ g_free (file_uri);
+ g_free (mime_type);
+
timeout = -1;
return 0;
@@ -1777,19 +1781,17 @@ play_file (NautilusFile *file)
static void
preview_sound (NautilusFile *file, gboolean start_flag)
{
+ if (mp3_pid) {
+ kill (-mp3_pid, SIGTERM);
+ mp3_pid = 0;
+ }
+ if (timeout >= 0) {
+ gtk_timeout_remove (timeout);
+ timeout = -1;
+ }
if (start_flag) {
- timeout = gtk_timeout_add (1000, (GtkFunction) play_file, file);
- } else {
- if (mp3_pid) {
- kill (-mp3_pid, SIGTERM);
- mp3_pid = 0;
- }
- if (timeout >= 0) {
- gtk_timeout_remove (timeout);
- timeout = -1;
- }
+ timeout = gtk_timeout_add (1000, play_file, file);
}
-
}
static int
diff --git a/src/nautilus-application.c b/src/nautilus-application.c
index a13c89f8a..3327de0ec 100644
--- a/src/nautilus-application.c
+++ b/src/nautilus-application.c
@@ -188,15 +188,6 @@ nautilus_application_new (void)
static void
nautilus_application_destroy (GtkObject *object)
{
- /* Shut down preferences. This is needed so that the global
- * preferences object and all its allocations are freed. Not
- * calling this function would NOT cause the user to lose
- * preferences. The only effect would be to leak those
- * objects - which would be collected at exit() time anyway,
- * but it adds noise to memory profile tool runs.
- */
- nautilus_global_preferences_shutdown ();
-
nautilus_bookmarks_exiting ();
NAUTILUS_CALL_PARENT_CLASS (GTK_OBJECT_CLASS, destroy, (object));
diff --git a/src/nautilus-main.c b/src/nautilus-main.c
index fb873d0b9..bdb1cda1d 100644
--- a/src/nautilus-main.c
+++ b/src/nautilus-main.c
@@ -49,46 +49,72 @@
#include <stdlib.h>
/* Keeps track of everyone who wants the main event loop kept active */
-static GSList *nautilus_main_event_loop_registrants;
+static GSList *event_loop_registrants;
static gboolean
-nautilus_main_is_event_loop_needed (void)
+is_event_loop_needed (void)
{
- return nautilus_main_event_loop_registrants != NULL;
+ return event_loop_registrants != NULL;
+}
+
+static int
+quit_if_in_main_loop (gpointer callback_data)
+{
+ guint level;
+
+ g_assert (callback_data == NULL);
+
+ level = gtk_main_level ();
+
+ /* We can be called even outside the main loop by gnome_vfs_shutdown,
+ * so check that we are in a loop before calling quit.
+ */
+ if (level != 0) {
+ gtk_main_quit ();
+ }
+
+ /* We need to be called again if we quit a nested loop. */
+ return level > 1;
}
static void
-nautilus_main_event_loop_unregister (GtkObject* object)
+nautilus_gtk_main_quit_all (void)
{
- g_assert (g_slist_find (nautilus_main_event_loop_registrants, object) != NULL);
- nautilus_main_event_loop_registrants = g_slist_remove (nautilus_main_event_loop_registrants, object);
- if (!nautilus_main_is_event_loop_needed ()) {
- /* Calling gtk_main_quit directly only kills the current/top event loop.
- * This idler will be run by the current event loop, killing it, and then
- * by the next event loop, ...
- */
- gtk_idle_add ((GtkFunction) gtk_main_quit, NULL);
+ /* Calling gtk_main_quit directly only kills the current/top event loop.
+ * This idler will be run by the current event loop, killing it, and then
+ * by the next event loop, ...
+ */
+ gtk_idle_add (quit_if_in_main_loop, NULL);
+}
+
+static void
+event_loop_unregister (GtkObject* object)
+{
+ g_assert (g_slist_find (event_loop_registrants, object) != NULL);
+ event_loop_registrants = g_slist_remove (event_loop_registrants, object);
+ if (!is_event_loop_needed ()) {
+ nautilus_gtk_main_quit_all ();
}
}
void
nautilus_main_event_loop_register (GtkObject* object)
{
- gtk_signal_connect (object, "destroy", nautilus_main_event_loop_unregister, NULL);
- nautilus_main_event_loop_registrants = g_slist_prepend (nautilus_main_event_loop_registrants, object);
+ gtk_signal_connect (object, "destroy", event_loop_unregister, NULL);
+ event_loop_registrants = g_slist_prepend (event_loop_registrants, object);
}
gboolean
nautilus_main_is_event_loop_mainstay (GtkObject* object)
{
- return g_slist_length (nautilus_main_event_loop_registrants) == 1 && nautilus_main_event_loop_registrants->data == object;
+ return g_slist_length (event_loop_registrants) == 1 && event_loop_registrants->data == object;
}
void
nautilus_main_event_loop_quit (void)
{
- while (nautilus_main_event_loop_registrants != NULL) {
- gtk_object_destroy (nautilus_main_event_loop_registrants->data);
+ while (event_loop_registrants != NULL) {
+ gtk_object_destroy (event_loop_registrants->data);
}
}
@@ -203,7 +229,7 @@ main (int argc, char *argv[])
kill_shell, restart_shell,
stop_desktop, start_desktop,
args);
- if (nautilus_main_is_event_loop_needed ()) {
+ if (is_event_loop_needed ()) {
bonobo_main ();
}
bonobo_object_unref (BONOBO_OBJECT (application));
diff --git a/test/.cvsignore b/test/.cvsignore
index d3cfac69f..42f07e5ca 100644
--- a/test/.cvsignore
+++ b/test/.cvsignore
@@ -4,6 +4,7 @@
*.lo
Makefile
Makefile.in
+test-nautilus-background
test-nautilus-font
test-nautilus-font-picker
test-nautilus-image