Re: patch nag: Multithreaded thumbnail loading
- From: Christian Neumair <cneumair gnome org>
- To: Alexander Larsson <alexl redhat com>
- Cc: nautilus-list <nautilus-list gnome org>
- Subject: Re: patch nag: Multithreaded thumbnail loading
- Date: Sat, 08 Sep 2007 14:20:59 +0200
Am Montag, den 03.09.2007, 13:15 +0200 schrieb Alexander Larsson:
> There is a limited amount of threads loading the thumbnails, therefore
> it makes sense to load the ones that are actually visible first. We
> might not actually use the precise code in
> nautilus_thumbnail_prioritize(), but at least it would hooks into the
> same places.
Thanks for your fruitful comments. I've implemented the relevant changes
you requested.
In my local tree, I added an async variant of
nautilus_thumbnail_load_image(). We only seem to be able to set the
priority when the thumbnail is requested, and lack a way to modify the
priority of running asyncronous GnomeVFS request ("running" as of "has a
handle", but still I/O to do).
If we have such a job run-time priorization mechanism (GVFS?), we should
be able to just change the thumbnailing priority in a function that can
be called from the _prioritize() function. Are you OK with that?
Once we have this one in, I'll try to implement user-driven thumbnailing
cancellation. I remember I once provided a patch that never made it into
trunk, for displaying status bar messages on file hovering. I'll
probably recycle the patch, and use it to notify the users that we're
loading thumbnails - otherwise users cannot be sure that the folder
itself has been loaded already.
It may be a good idea to add a status bar message priority system, to
implement notifications regarding folder operations (loading etc.). One
would would be able to push messages on a stack and pop it from it, and
give them a priority, and we can have separate priorities for basic
file/folder information (_LOW), file operations (_NORMAL) and tooltips
(_HIGH), that decide which one is actually shown. It would be some form
of gtk_statusbar_push and gtk_statusbar_pop wrapper that reorders the
messages according to their priority.
--
Christian Neumair <cneumair gnome org>
Index: libnautilus-private/nautilus-icon-factory.c
===================================================================
--- libnautilus-private/nautilus-icon-factory.c (Revision 13124)
+++ libnautilus-private/nautilus-icon-factory.c (Arbeitskopie)
@@ -29,6 +29,7 @@
#include "nautilus-icon-factory.h"
#include "nautilus-default-file-icon.h"
+#include "nautilus-directory-notify.h"
#include "nautilus-file-attributes.h"
#include "nautilus-file-private.h"
#include "nautilus-file-utilities.h"
@@ -154,6 +155,7 @@ typedef struct {
CacheIcon *fallback_icon;
GHashTable *image_mime_types;
+ GList *async_thumbnail_load_handles;
} NautilusIconFactory;
#define NAUTILUS_ICON_FACTORY(obj) \
@@ -347,6 +349,64 @@ load_thumbnail_frame (NautilusIconFactor
g_free (image_path);
}
+typedef struct {
+ NautilusFile *file;
+ char *modifier;
+ guint nominal_size;
+ gboolean force_nominal;
+} AsnycThumbnailLoadFuncData;
+
+static void
+async_thumbnail_load_func (NautilusThumbnailAsyncLoadHandle *handle,
+ const char *path,
+ GdkPixbuf *pixbuf,
+ double scale_x,
+ double scale_y,
+ gpointer user_data)
+{
+ NautilusIconFactory *factory;
+ GHashTable *hash_table;
+ CacheKey *key;
+ CacheIcon *cached_icon;
+ struct stat statbuf;
+ AsnycThumbnailLoadFuncData *data = user_data;
+
+ factory = get_icon_factory ();
+ hash_table = factory->icon_cache;
+
+ nautilus_file_set_is_thumbnailing (data->file, FALSE);
+ factory->async_thumbnail_load_handles =
+ g_list_remove (factory->async_thumbnail_load_handles, handle);
+
+ if (stat (path, &statbuf) != 0 ||
+ !S_ISREG (statbuf.st_mode)) {
+ g_message ("NautilusIconFactory: Failed to determine mtime for %s. Aborting thumbnailing request.", path);
+ goto out;
+ }
+
+ cached_icon = cache_icon_new (pixbuf, NULL, scale_x, scale_y);
+ cached_icon->mtime = statbuf.st_mtime;
+
+ if (cached_icon != NULL) {
+ key = g_new (CacheKey, 1);
+ key->name = g_strdup (path);
+ key->modifier = g_strdup (data->modifier);
+ key->nominal_size = data->nominal_size;
+ key->force_nominal = data->force_nominal;
+
+ g_hash_table_insert (hash_table, key, cached_icon);
+
+ nautilus_file_changed (data->file);
+ }
+
+out:
+ nautilus_file_unref (data->file);
+ g_free (data->modifier);
+ g_free (data);
+}
+
+
+
static void
nautilus_icon_factory_instance_init (NautilusIconFactory *factory)
{
@@ -685,12 +745,23 @@ nautilus_icon_factory_clear (void)
}
static void
+cancel_thumbnail_read_foreach (gpointer data,
+ gpointer user_data)
+{
+ NautilusThumbnailAsyncLoadHandle *handle = data;
+ nautilus_thumbnail_load_image_cancel (handle);
+}
+
+static void
nautilus_icon_factory_finalize (GObject *object)
{
NautilusIconFactory *factory;
factory = NAUTILUS_ICON_FACTORY (object);
+ g_list_foreach (factory->async_thumbnail_load_handles, cancel_thumbnail_read_foreach, NULL);
+ g_list_free (factory->async_thumbnail_load_handles);
+
if (factory->icon_cache) {
g_hash_table_destroy (factory->icon_cache);
factory->icon_cache = NULL;
@@ -1300,6 +1371,38 @@ create_normal_cache_icon (const char *ic
return cache_icon;
}
+static CacheIcon *
+lookup_icon_from_cache (const char *icon,
+ const char *modifier,
+ guint nominal_size,
+ gboolean force_nominal)
+{
+ NautilusIconFactory *factory;
+ GHashTable *hash_table;
+ CacheKey lookup_key, *key;
+ CacheIcon *value;
+
+ lookup_key.name = (char *)icon;
+ lookup_key.modifier = (char *)modifier;
+ lookup_key.nominal_size = nominal_size;
+ lookup_key.force_nominal = force_nominal;
+
+ factory = get_icon_factory ();
+ hash_table = factory->icon_cache;
+
+ if (g_hash_table_lookup_extended (hash_table, &lookup_key,
+ (gpointer *) &key, (gpointer *) &value)) {
+ /* Found it in the table. */
+ g_assert (key != NULL);
+ g_assert (value != NULL);
+ } else {
+ key = NULL;
+ value = NULL;
+ }
+
+ return value;
+}
+
/* Get the icon, handling the caching.
* If @picky is true, then only an unscaled icon is acceptable.
@@ -1316,34 +1419,17 @@ get_icon_from_cache (const char *icon,
{
NautilusIconFactory *factory;
GHashTable *hash_table;
- CacheKey lookup_key;
CacheKey *key;
CacheIcon *cached_icon;
- gpointer key_in_table, value;
struct stat statbuf;
g_return_val_if_fail (icon != NULL, NULL);
-
- key = NULL;
- cached_icon = NULL;
factory = get_icon_factory ();
hash_table = factory->icon_cache;
/* Check to see if it's already in the table. */
- lookup_key.name = (char *)icon;
- lookup_key.modifier = (char *)modifier;
- lookup_key.nominal_size = nominal_size;
- lookup_key.force_nominal = force_nominal;
-
- 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;
- cached_icon = value;
- }
+ cached_icon = lookup_icon_from_cache (icon, modifier, nominal_size, force_nominal);
/* Make sure that thumbnails and image-as-itself icons gets
reloaded when they change: */
@@ -1547,10 +1633,85 @@ nautilus_get_relative_icon_size_for_zoom
return (float)nautilus_get_icon_size_for_zoom_level (zoom_level) / NAUTILUS_ICON_SIZE_STANDARD;
}
-
-
/* Convenience cover for nautilus_icon_factory_get_icon_for_file
* and nautilus_icon_factory_get_pixbuf_for_icon.
+ *
+ * If a file has an associated thumbnail, the thumb is loaded asynchronously,
+ * a loading thumbnail image is returned
+ * and the file will receive a "changed" event once the thumbnail has been loaded.
+ *
+ * The "file" parameter is only used for thumbnailing,
+ * for the file change notification once the actual thumbnail
+ * has been loaded.
+ */
+GdkPixbuf *
+nautilus_icon_factory_get_pixbuf_for_file_with_icon (NautilusFile *file,
+ const char *icon,
+ const char *modifier,
+ guint size_in_pixels,
+ NautilusEmblemAttachPoints *attach_points,
+ GdkRectangle *embedded_text_rect,
+ gboolean force_size,
+ gboolean wants_default,
+ char **display_name)
+{
+ GdkPixbuf *pixbuf;
+ NautilusIconFactory *factory;
+ gboolean is_thumbnail;
+
+ factory = get_icon_factory ();
+
+ is_thumbnail = strstr (icon, "/.thumbnails/") != NULL;
+
+ if (is_thumbnail &&
+ !lookup_icon_from_cache (icon, modifier, size_in_pixels, force_size)) {
+ AsnycThumbnailLoadFuncData *data;
+
+ /* Asynchronous thumbnail loading.
+ *
+ * This heavily improves performance for folders containing lots of
+ * previously thumbnailed files.
+ *
+ * Note: We do not pass the additional thumbnail parameters (attach points etc.)
+ * to the thread as we don't need them for the cache. The API user may herself
+ * re-request the loaded thumbnail with the correct parameters, which will be set
+ * accordingly in nautilus_icon_factory_get_pixbuf_for_icon() on cache hit
+ * once it is filled.
+ */
+
+ data = g_new (AsnycThumbnailLoadFuncData, 1);
+ data->file = nautilus_file_ref (file);
+ data->modifier = g_strdup (modifier);
+ data->nominal_size = size_in_pixels;
+ data->force_nominal = force_size;
+
+ nautilus_file_set_is_thumbnailing (file, TRUE);
+
+ factory->async_thumbnail_load_handles = g_list_prepend (
+ factory->async_thumbnail_load_handles,
+ nautilus_thumbnail_load_image_async (icon,
+ 0, /* base_size */
+ size_in_pixels,
+ force_size,
+ async_thumbnail_load_func,
+ data));
+
+ icon = ICON_NAME_THUMBNAIL_LOADING;
+ }
+
+
+ pixbuf = nautilus_icon_factory_get_pixbuf_for_icon (icon,
+ modifier, size_in_pixels,
+ attach_points, embedded_text_rect,
+ force_size,
+ wants_default, display_name);
+
+ return pixbuf;
+}
+
+/*
+ * like nautilus_icon_factory_get_pixbuf_for_file_with_icon() but does the icon lookup itself,
+ * doesn't allow emblem and text rect fetching.
*/
GdkPixbuf *
nautilus_icon_factory_get_pixbuf_for_file (NautilusFile *file,
@@ -1558,9 +1719,11 @@ nautilus_icon_factory_get_pixbuf_for_fil
guint size_in_pixels,
gboolean force_size)
{
- char *icon;
GdkPixbuf *pixbuf;
+ NautilusIconFactory *factory;
+ char *icon;
+ factory = get_icon_factory ();
/* Get the pixbuf for this file. */
icon = nautilus_icon_factory_get_icon_for_file (file, FALSE);
@@ -1568,12 +1731,12 @@ nautilus_icon_factory_get_pixbuf_for_fil
return NULL;
}
- pixbuf = nautilus_icon_factory_get_pixbuf_for_icon (icon, modifier,
- size_in_pixels,
- NULL, NULL,
- force_size,
- TRUE, NULL);
-
+ pixbuf = nautilus_icon_factory_get_pixbuf_for_file_with_icon (file,
+ icon, modifier,
+ size_in_pixels,
+ NULL, NULL,
+ force_size,
+ TRUE, NULL);
g_free (icon);
return pixbuf;
@@ -1586,7 +1749,7 @@ nautilus_icon_factory_get_pixbuf_for_fil
{
return nautilus_icon_factory_get_pixbuf_for_file (file, modifier,
gtk_icon_size_to_nominal_size (stock_size),
- TRUE); /* force_size */
+ TRUE /* force_size */);
}
Index: libnautilus-private/nautilus-icon-factory.h
===================================================================
--- libnautilus-private/nautilus-icon-factory.h (Revision 13124)
+++ libnautilus-private/nautilus-icon-factory.h (Arbeitskopie)
@@ -151,6 +151,16 @@ GdkPixbuf *nautilus_icon_factory_get_pix
const char *modifier,
GtkIconSize stock_size);
+GdkPixbuf * nautilus_icon_factory_get_pixbuf_for_file_with_icon (NautilusFile *file,
+ const char *icon,
+ const char *modifier,
+ guint size_in_pixels,
+ NautilusEmblemAttachPoints *attach_points,
+ GdkRectangle *embedded_text_rect,
+ gboolean force_size,
+ gboolean wants_default,
+ char **display_name);
+
/* Convenience routine for getting a pixbuf from an icon name
*/
Index: libnautilus-private/nautilus-icon-container.c
===================================================================
--- libnautilus-private/nautilus-icon-container.c (Revision 13124)
+++ libnautilus-private/nautilus-icon-container.c (Arbeitskopie)
@@ -5678,6 +5678,90 @@ handle_vadjustment_changed (GtkAdjustmen
nautilus_icon_container_update_visible_icons (container);
}
+/*
+ * used to resize ICON_NAME_THUMBNAIL_LOADING to the expected thumbnail size.
+ */
+static void
+sanitize_loading_thumbnail_image_size (NautilusIconContainer *container,
+ const char *mime_type,
+ GdkPixbuf **image,
+ NautilusEmblemAttachPoints *attach_points,
+ GdkRectangle *embedded_text_rect)
+{
+ NautilusIconContainerDetails *details;
+ double pixels_per_unit;
+
+ details = container->details;
+ pixels_per_unit = (double) nautilus_get_icon_size_for_zoom_level (container->details->zoom_level)
+ / NAUTILUS_ICON_SIZE_STANDARD;
+
+ if (gdk_pixbuf_get_width (*image) < NAUTILUS_ICON_SIZE_THUMBNAIL * pixels_per_unit &&
+ gdk_pixbuf_get_height (*image) < NAUTILUS_ICON_SIZE_THUMBNAIL * pixels_per_unit) {
+ /* TODO? this only handles icons smaller than the expected thumbnail size ATM.
+ * Should not be a common problem, though */
+ GdkPixbuf *new_image;
+ double x_size;
+ double y_size;
+ double x_offset;
+ double y_offset;
+ int i;
+
+ if (g_str_has_prefix (mime_type, "video/")) {
+ /* assume 4:3 aspect ratio for videos i.e. we'll always occupy the full width. */
+ x_size = NAUTILUS_ICON_SIZE_THUMBNAIL * pixels_per_unit;
+ y_size = 3./4 * x_size;
+ } else {
+ /* scale up to the max. thumbnail size.
+ * This is correct at least in one dimension, and prevents the icons from jumping
+ * around as the thumbnail is created, if it is tall for text below icon, and if it
+ * is wide for text beside icon.
+ */
+ x_size = NAUTILUS_ICON_SIZE_THUMBNAIL * pixels_per_unit;
+ y_size = NAUTILUS_ICON_SIZE_THUMBNAIL * pixels_per_unit;
+ }
+
+ /* maybe the estimated size was smaller than the input pixbuf, so size the surrounding
+ * image up. This only seems to be relevant in the 4:3 case, for y_size.
+ */
+ x_size = MAX (x_size, gdk_pixbuf_get_width (*image));
+ y_size = MAX (y_size, gdk_pixbuf_get_height (*image));
+
+ x_offset = x_size - gdk_pixbuf_get_width (*image);
+ y_offset = y_size - gdk_pixbuf_get_height (*image);
+
+ /* center wrt "minor" dimension, i.e. horizontally for text below
+ * and vertically for text besides icon */
+ if (details->label_position == NAUTILUS_ICON_LABEL_POSITION_BESIDE)
+ y_offset /= 2;
+ else
+ x_offset /= 2;
+
+ new_image = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE,
+ gdk_pixbuf_get_bits_per_sample (*image),
+ x_size, y_size);
+
+ gdk_pixbuf_fill (new_image, 0x00000000);
+ gdk_pixbuf_copy_area (*image,
+ 0, 0,
+ gdk_pixbuf_get_width (*image),
+ gdk_pixbuf_get_height (*image),
+ new_image,
+ x_offset, y_offset);
+
+ g_object_unref (*image);
+ *image = new_image;
+
+ for (i = 0; i < attach_points->num_points; i++) {
+ attach_points->points[i].x += x_offset;
+ attach_points->points[i].y += y_offset;
+ }
+
+ embedded_text_rect->x += x_offset;
+ embedded_text_rect->y += y_offset;
+ }
+}
+
+
void
nautilus_icon_container_update_icon (NautilusIconContainer *container,
NautilusIcon *icon)
@@ -5732,15 +5816,14 @@ nautilus_icon_container_update_icon (Nau
modifier = "accept";
}
- pixbuf = nautilus_icon_factory_get_pixbuf_for_icon
- (icon_name,
+ pixbuf = nautilus_icon_factory_get_pixbuf_for_file_with_icon
+ ((NautilusFile *) icon->data,
+ icon_name,
modifier,
icon_size,
&attach_points,
&embedded_text_rect,
FALSE, TRUE, NULL);
-
- g_free (icon_name);
if (embedded_text_rect.width > MINIMUM_EMBEDDED_TEXT_RECT_WIDTH &&
embedded_text_rect.height > MINIMUM_EMBEDDED_TEXT_RECT_HEIGHT &&
@@ -5794,6 +5877,17 @@ nautilus_icon_container_update_icon (Nau
"additional_text", additional_text,
"highlighted_for_drop", icon == details->drop_target,
NULL);
+
+ if (nautilus_file_is_thumbnailing ((NautilusFile *) icon->data)) {
+ char* mime_type;
+ mime_type = nautilus_file_get_mime_type ((NautilusFile *)icon->data);
+ sanitize_loading_thumbnail_image_size (container,
+ mime_type,
+ &pixbuf,
+ &attach_points,
+ &embedded_text_rect);
+ g_free (mime_type);
+ }
nautilus_icon_canvas_item_set_image (icon->item, pixbuf);
nautilus_icon_canvas_item_set_attach_points (icon->item, &attach_points);
@@ -5807,6 +5901,8 @@ nautilus_icon_container_update_icon (Nau
g_free (editable_text);
g_free (additional_text);
+
+ g_free (icon_name);
}
static gboolean
Index: libnautilus-private/nautilus-thumbnails.c
===================================================================
--- libnautilus-private/nautilus-thumbnails.c (Revision 13124)
+++ libnautilus-private/nautilus-thumbnails.c (Arbeitskopie)
@@ -69,6 +69,16 @@ typedef struct {
time_t original_file_mtime;
} NautilusThumbnailInfo;
+struct NautilusThumbnailAsyncLoadHandle {
+ EelReadFileHandle *eel_read_handle;
+ char *file_path;
+ guint base_size;
+ guint nominal_size;
+ gboolean force_nominal;
+ NautilusThumbnailAsyncLoadFunc load_func;
+ gpointer load_func_user_data;
+};
+
/*
* Thumbnail thread state.
@@ -330,39 +340,26 @@ thumbnail_loader_area_prepared (GdkPixbu
*args->scale_y_out = (double) gdk_pixbuf_get_height (pixbuf) / args->original_height;
}
-/* routine to load an image from the passed-in path
- */
-GdkPixbuf *
-nautilus_thumbnail_load_image (const char *path,
- guint base_size,
- guint nominal_size,
- gboolean force_nominal,
- double *scale_x_out,
- double *scale_y_out)
+static GdkPixbuf *
+get_pixbuf_from_data (const unsigned char *buffer,
+ gsize buflen,
+ const char *path,
+ guint base_size,
+ guint nominal_size,
+ gboolean force_nominal,
+ double *scale_x_out,
+ double *scale_y_out)
{
- guchar *buffer;
GdkPixbufLoader *loader;
GdkPixbuf *pixbuf;
- GError *error;
- gsize buflen;
ThumbnailLoadArgs args;
-
- error = NULL;
+ GError *error;
if (thumbnail_icon_size == 0) {
eel_preferences_add_auto_integer (NAUTILUS_PREFERENCES_ICON_VIEW_THUMBNAIL_SIZE,
&thumbnail_icon_size);
}
-
- if (!g_file_get_contents (path, (gchar **) &buffer, &buflen, &error)) {
- g_message ("Failed to load %s into memory: %s", path, error->message);
-
- g_error_free (error);
-
- return NULL;
- }
-
loader = gdk_pixbuf_loader_new ();
g_signal_connect (loader, "size-prepared",
G_CALLBACK (thumbnail_loader_size_prepared),
@@ -378,17 +375,20 @@ nautilus_thumbnail_load_image (const cha
args.scale_x_out = scale_x_out;
args.scale_y_out = scale_y_out;
+ error = NULL;
+
if (!gdk_pixbuf_loader_write (loader, buffer, buflen, &error)) {
g_message ("Failed to write %s to thumbnail pixbuf loader: %s", path, error->message);
gdk_pixbuf_loader_close (loader, NULL);
g_object_unref (G_OBJECT (loader));
g_error_free (error);
- g_free (buffer);
return NULL;
}
+ error = NULL;
+
if (!gdk_pixbuf_loader_close (loader, &error) ||
/* Seems we have to check this even if it returned TRUE (#403255) */
error != NULL) {
@@ -396,7 +396,6 @@ nautilus_thumbnail_load_image (const cha
g_object_unref (G_OBJECT (loader));
g_error_free (error);
- g_free (buffer);
return NULL;
}
@@ -404,11 +403,122 @@ nautilus_thumbnail_load_image (const cha
pixbuf = g_object_ref (gdk_pixbuf_loader_get_pixbuf (loader));
g_object_unref (G_OBJECT (loader));
+
+ return pixbuf;
+}
+
+
+/* routine to load an image from the passed-in path
+ */
+GdkPixbuf *
+nautilus_thumbnail_load_image (const char *path,
+ guint base_size,
+ guint nominal_size,
+ gboolean force_nominal,
+ double *scale_x_out,
+ double *scale_y_out)
+{
+ GdkPixbuf *pixbuf;
+ guchar *buffer;
+ gsize buflen;
+ GError *error;
+
+ error = NULL;
+
+ if (!g_file_get_contents (path, (gchar **) &buffer, &buflen, &error)) {
+ g_message ("Failed to load %s into memory: %s", path, error->message);
+
+ g_error_free (error);
+
+ return NULL;
+ }
+
+ pixbuf = get_pixbuf_from_data (buffer, buflen, path,
+ base_size, nominal_size, force_nominal,
+ scale_x_out, scale_y_out);
+
g_free (buffer);
return pixbuf;
}
+static void
+async_thumbnail_read_image (GnomeVFSResult result,
+ GnomeVFSFileSize file_size,
+ char *file_contents,
+ gpointer callback_data)
+{
+ GdkPixbuf *pixbuf;
+ double scale_x, scale_y;
+
+ NautilusThumbnailAsyncLoadHandle *handle = callback_data;
+
+ pixbuf = NULL;
+ scale_x = scale_y = 1.0;
+
+ if (result == GNOME_VFS_OK) {
+ pixbuf = get_pixbuf_from_data (file_contents, file_size,
+ handle->file_path,
+ handle->base_size,
+ handle->nominal_size,
+ handle->force_nominal,
+ &scale_x, &scale_y);
+ }
+
+ handle->load_func (handle,
+ handle->file_path,
+ pixbuf, scale_x, scale_y,
+ handle->load_func_user_data);
+
+ gdk_pixbuf_unref (pixbuf);
+
+ g_free (handle->file_path);
+ g_free (handle);
+}
+
+NautilusThumbnailAsyncLoadHandle *
+nautilus_thumbnail_load_image_async (const char *path,
+ guint base_size,
+ guint nominal_size,
+ gboolean force_nominal,
+ NautilusThumbnailAsyncLoadFunc load_func,
+ gpointer load_func_user_data)
+{
+ NautilusThumbnailAsyncLoadHandle *handle;
+ char *uri;
+
+ uri = gnome_vfs_get_uri_from_local_path (path);
+ if (uri == NULL) {
+ return NULL;
+ }
+
+ handle = g_new (NautilusThumbnailAsyncLoadHandle, 1);
+ handle->eel_read_handle =
+ eel_read_entire_file_async (uri, GNOME_VFS_PRIORITY_DEFAULT,
+ (EelReadFileCallback) async_thumbnail_read_image,
+ handle);
+ handle->file_path = g_strdup (path);
+ handle->base_size = base_size;
+ handle->nominal_size = nominal_size;
+ handle->force_nominal = force_nominal;
+ handle->load_func = load_func;
+ handle->load_func_user_data = load_func_user_data;
+
+ g_free (uri);
+
+ return handle;
+}
+
+void
+nautilus_thumbnail_load_image_cancel (NautilusThumbnailAsyncLoadHandle *handle)
+{
+ g_assert (handle != NULL);
+
+ eel_read_file_cancel (handle->eel_read_handle);
+ g_free (handle->file_path);
+ g_free (handle);
+}
+
void
nautilus_thumbnail_remove_from_queue (const char *file_uri)
{
Index: libnautilus-private/nautilus-thumbnails.h
===================================================================
--- libnautilus-private/nautilus-thumbnails.h (Revision 13124)
+++ libnautilus-private/nautilus-thumbnails.h (Arbeitskopie)
@@ -28,6 +28,15 @@
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <libnautilus-private/nautilus-file.h>
+typedef struct NautilusThumbnailAsyncLoadHandle NautilusThumbnailAsyncLoadHandle;
+
+typedef void (* NautilusThumbnailAsyncLoadFunc) (NautilusThumbnailAsyncLoadHandle *handle,
+ const char *path,
+ GdkPixbuf *pixbuf,
+ double scale_x,
+ double scale_y,
+ gpointer user_data);
+
/* Returns NULL if there's no thumbnail yet. */
void nautilus_create_thumbnail (NautilusFile *file);
void nautilus_thumbnail_frame_image (GdkPixbuf **pixbuf);
@@ -37,6 +46,14 @@ GdkPixbuf *nautilus_thumbnail_load_image
gboolean force_nominal,
double *scale_x_out,
double *scale_y_out);
+NautilusThumbnailAsyncLoadHandle *
+ nautilus_thumbnail_load_image_async (const char *path,
+ guint base_size,
+ guint nominal_size,
+ gboolean force_nominal,
+ NautilusThumbnailAsyncLoadFunc load_func,
+ gpointer load_func_user_data);
+void nautilus_thumbnail_load_image_cancel (NautilusThumbnailAsyncLoadHandle *handle);
void nautilus_update_thumbnail_file_copied (const char *source_file_uri,
const char *destination_file_uri);
void nautilus_update_thumbnail_file_renamed (const char *source_file_uri,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]