[Xfce4-commits] <thunar:master> Add async file loading for ThunarFile.
Nick Schermer
noreply at xfce.org
Sat Oct 13 16:12:01 CEST 2012
Updating branch refs/heads/master
to fb21e1dfddeb8e6629fea02f5aae81b657b268f1 (commit)
from c8e4db20f9434c4dc385dba8d752b91e6be796a8 (commit)
commit fb21e1dfddeb8e6629fea02f5aae81b657b268f1
Author: Nick Schermer <nick at xfce.org>
Date: Fri Oct 5 14:35:35 2012 +0200
Add async file loading for ThunarFile.
thunar/thunar-file.c | 437 +++++++++++++++++++++++++++++++++-----------------
thunar/thunar-file.h | 16 ++
2 files changed, 302 insertions(+), 151 deletions(-)
diff --git a/thunar/thunar-file.c b/thunar/thunar-file.c
index 68df146..14ceb6c 100644
--- a/thunar/thunar-file.c
+++ b/thunar/thunar-file.c
@@ -163,6 +163,14 @@ struct _ThunarFile
guint is_mounted : 1;
};
+typedef struct
+{
+ ThunarFileGetFunc func;
+ gpointer user_data;
+ GCancellable *cancellable;
+}
+ThunarFileGetData;
+
G_DEFINE_TYPE_WITH_CODE (ThunarFile, thunar_file, G_TYPE_OBJECT,
@@ -625,130 +633,11 @@ thunar_file_set_emblem_names_ready (GObject *source_object,
-/**
- * thunar_file_get:
- * @file : a #GFile.
- * @error : return location for errors.
- *
- * Looks up the #ThunarFile referred to by @file. This function may return a
- * ThunarFile even though the file doesn't actually exist. This is the case
- * with remote URIs (like SFTP) for instance, if they are not mounted.
- *
- * The caller is responsible to call g_object_unref()
- * when done with the returned object.
- *
- * Return value: the #ThunarFile for @file or %NULL on errors.
- **/
-ThunarFile*
-thunar_file_get (GFile *gfile,
- GError **error)
-{
- ThunarFile *file;
-
- _thunar_return_val_if_fail (G_IS_FILE (gfile), NULL);
-
- /* check if we already have a cached version of that file */
- file = thunar_file_cache_lookup (gfile);
- if (G_UNLIKELY (file != NULL))
- {
- /* take a reference for the caller */
- g_object_ref (file);
- }
- else
- {
- /* allocate a new object */
- file = g_object_new (THUNAR_TYPE_FILE, NULL);
- file->gfile = g_object_ref (gfile);
-
- if (thunar_file_load (file, NULL, error))
- {
- /* insert the file into the cache */
- G_LOCK (file_cache_mutex);
- g_hash_table_insert (file_cache, g_object_ref (file->gfile), file);
- G_UNLOCK (file_cache_mutex);
- }
- else
- {
- /* failed loading, destroy the file */
- g_object_unref (file);
-
- /* make sure we return NULL */
- file = NULL;
- }
- }
-
- return file;
-}
-
-
-
-/**
- * thunar_file_get_for_uri:
- * @uri : an URI or an absolute filename.
- * @error : return location for errors or %NULL.
- *
- * Convenience wrapper function for thunar_file_get_for_path(), as its
- * often required to determine a #ThunarFile for a given @uri.
- *
- * The caller is responsible to free the returned object using
- * g_object_unref() when no longer needed.
- *
- * Return value: the #ThunarFile for the given @uri or %NULL if
- * unable to determine.
- **/
-ThunarFile*
-thunar_file_get_for_uri (const gchar *uri,
- GError **error)
-{
- ThunarFile *file;
- GFile *path;
-
- _thunar_return_val_if_fail (uri != NULL, NULL);
- _thunar_return_val_if_fail (error == NULL || *error == NULL, NULL);
-
- path = g_file_new_for_commandline_arg (uri);
- file = thunar_file_get (path, error);
- g_object_unref (path);
-
- return file;
-}
-
-
-
-/**
- * thunar_file_load:
- * @file : a #ThunarFile.
- * @cancellable : a #GCancellable.
- * @error : return location for errors or %NULL.
- *
- * Loads all information about the file. As this is a possibly
- * blocking call, it can be cancelled using @cancellable.
- *
- * If loading the file fails or the operation is cancelled,
- * @error will be set.
- *
- * Return value: %TRUE on success, %FALSE on error or interruption.
- **/
-static gboolean
-thunar_file_load (ThunarFile *file,
- GCancellable *cancellable,
- GError **error)
+static void
+thunar_file_info_clear (ThunarFile *file)
{
- const gchar *target_uri;
- GKeyFile *key_file;
- GError *err = NULL;
- GFile *thumbnail_dir;
- gchar *base_name;
- gchar *p;
- gchar *thumbnail_dir_path;
- const gchar *display_name;
- gboolean is_secure = FALSE;
- gchar *casefold;
-
- _thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE);
- _thunar_return_val_if_fail (error == NULL || *error == NULL, FALSE);
- _thunar_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
-
+ _thunar_return_if_fail (THUNAR_IS_FILE (file));
+
/* release the current file info */
if (file->info != NULL)
{
@@ -782,31 +671,35 @@ thunar_file_load (ThunarFile *file,
/* assume the file is mounted by default */
file->is_mounted = TRUE;
- /* query a new file info */
- file->info = g_file_query_info (file->gfile,
- THUNARX_FILE_INFO_NAMESPACE,
- G_FILE_QUERY_INFO_NONE,
- cancellable, &err);
+ /* set thumb state to unknown */
+ file->flags = (file->flags & ~THUNAR_FILE_THUMB_STATE_MASK) | THUNAR_FILE_THUMB_STATE_UNKNOWN;
+}
+
- if (err == NULL)
+
+static void
+thunar_file_info_reload (ThunarFile *file,
+ GCancellable *cancellable)
+{
+ const gchar *target_uri;
+ GKeyFile *key_file;
+ GFile *thumbnail_dir;
+ gchar *base_name;
+ gchar *p;
+ gchar *thumbnail_dir_path;
+ const gchar *display_name;
+ gboolean is_secure = FALSE;
+ gchar *casefold;
+
+ _thunar_return_if_fail (THUNAR_IS_FILE (file));
+ _thunar_return_if_fail (file->info == NULL || G_IS_FILE_INFO (file->info));
+
+ if (G_LIKELY (file->info != NULL))
{
if (g_file_info_get_file_type (file->info) == G_FILE_TYPE_MOUNTABLE)
{
- target_uri =
- g_file_info_get_attribute_string (file->info,
- G_FILE_ATTRIBUTE_STANDARD_TARGET_URI);
- file->is_mounted =
- (target_uri != NULL)
- && !g_file_info_get_attribute_boolean (file->info,
- G_FILE_ATTRIBUTE_MOUNTABLE_CAN_MOUNT);
- }
- }
- else
- {
- if (err->domain == G_IO_ERROR && err->code == G_IO_ERROR_NOT_MOUNTED)
- {
- file->is_mounted = FALSE;
- g_clear_error (&err);
+ target_uri = g_file_info_get_attribute_string (file->info, G_FILE_ATTRIBUTE_STANDARD_TARGET_URI);
+ file->is_mounted = (target_uri != NULL) && !g_file_info_get_attribute_boolean (file->info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_MOUNT);
}
}
@@ -825,6 +718,10 @@ thunar_file_load (ThunarFile *file,
file->custom_icon_name = g_file_get_path (file->gfile);
}
+ /* free $HOME/.thumbnails/ GFile and path */
+ g_object_unref (thumbnail_dir);
+ g_free (thumbnail_dir_path);
+
/* check if this file is a desktop entry */
if (thunar_file_is_desktop_file (file, &is_secure) && is_secure)
{
@@ -892,10 +789,6 @@ thunar_file_load (ThunarFile *file,
file->custom_icon_name = NULL;
}
- /* free $HOME/.thumbnails/ GFile and path */
- g_object_unref (thumbnail_dir);
- g_free (thumbnail_dir_path);
-
/* determine the display name */
if (file->display_name == NULL)
{
@@ -947,10 +840,117 @@ thunar_file_load (ThunarFile *file,
/* cleanup */
g_free (casefold);
+}
- /* set thumb state to unknown */
- file->flags =
- (file->flags & ~THUNAR_FILE_THUMB_STATE_MASK) | THUNAR_FILE_THUMB_STATE_UNKNOWN;
+
+
+static void
+thunar_file_get_async_finish (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ ThunarFileGetData *data = user_data;
+ ThunarFile *file;
+ GFileInfo *file_info;
+ GError *error = NULL;
+ GFile *location = G_FILE (object);
+
+ _thunar_return_if_fail (G_IS_FILE (location));
+ _thunar_return_if_fail (G_IS_ASYNC_RESULT (result));
+
+ /* finish querying the file information */
+ file_info = g_file_query_info_finish (location, result, &error);
+
+ /* allocate a new file object */
+ file = g_object_new (THUNAR_TYPE_FILE, NULL);
+ file->gfile = g_object_ref (location);
+
+ /* reset the file */
+ thunar_file_info_clear (file);
+
+ /* set the file information */
+ file->info = file_info;
+
+ /* update the file from the information */
+ thunar_file_info_reload (file, data->cancellable);
+
+ /* update the mounted info */
+ if (error != NULL
+ && error->domain == G_IO_ERROR
+ && error->code == G_IO_ERROR_NOT_MOUNTED)
+ {
+ file->is_mounted = FALSE;
+ g_clear_error (&error);
+ }
+
+ /* insert the file into the cache */
+ G_LOCK (file_cache_mutex);
+ g_hash_table_insert (file_cache, g_object_ref (file->gfile), file);
+ G_UNLOCK (file_cache_mutex);
+
+ /* pass the loaded file and possible errors to the return function */
+ (data->func) (location, file, error, data->user_data);
+
+ /* free the error, if there is any */
+ if (error != NULL)
+ g_error_free (error);
+
+ /* release the file */
+ g_object_unref (file);
+
+ /* release the get data */
+ if (data->cancellable != NULL)
+ g_object_unref (data->cancellable);
+ g_slice_free (ThunarFileGetData, data);
+}
+
+
+
+/**
+ * thunar_file_load:
+ * @file : a #ThunarFile.
+ * @cancellable : a #GCancellable.
+ * @error : return location for errors or %NULL.
+ *
+ * Loads all information about the file. As this is a possibly
+ * blocking call, it can be cancelled using @cancellable.
+ *
+ * If loading the file fails or the operation is cancelled,
+ * @error will be set.
+ *
+ * Return value: %TRUE on success, %FALSE on error or interruption.
+ **/
+static gboolean
+thunar_file_load (ThunarFile *file,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GError *err = NULL;
+
+ _thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE);
+ _thunar_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+ _thunar_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
+
+ /* reset the file */
+ thunar_file_info_clear (file);
+
+ /* query a new file info */
+ file->info = g_file_query_info (file->gfile,
+ THUNARX_FILE_INFO_NAMESPACE,
+ G_FILE_QUERY_INFO_NONE,
+ cancellable, &err);
+
+ /* update the file from the information */
+ thunar_file_info_reload (file, cancellable);
+
+ /* update the mounted info */
+ if (err != NULL
+ && err->domain == G_IO_ERROR
+ && err->code == G_IO_ERROR_NOT_MOUNTED)
+ {
+ file->is_mounted = FALSE;
+ g_clear_error (&err);
+ }
if (err != NULL)
{
@@ -964,6 +964,141 @@ thunar_file_load (ThunarFile *file,
}
+
+/**
+ * thunar_file_get:
+ * @file : a #GFile.
+ * @error : return location for errors.
+ *
+ * Looks up the #ThunarFile referred to by @file. This function may return a
+ * ThunarFile even though the file doesn't actually exist. This is the case
+ * with remote URIs (like SFTP) for instance, if they are not mounted.
+ *
+ * The caller is responsible to call g_object_unref()
+ * when done with the returned object.
+ *
+ * Return value: the #ThunarFile for @file or %NULL on errors.
+ **/
+ThunarFile*
+thunar_file_get (GFile *gfile,
+ GError **error)
+{
+ ThunarFile *file;
+
+ _thunar_return_val_if_fail (G_IS_FILE (gfile), NULL);
+
+ /* check if we already have a cached version of that file */
+ file = thunar_file_cache_lookup (gfile);
+ if (G_UNLIKELY (file != NULL))
+ {
+ /* take a reference for the caller */
+ g_object_ref (file);
+ }
+ else
+ {
+ /* allocate a new object */
+ file = g_object_new (THUNAR_TYPE_FILE, NULL);
+ file->gfile = g_object_ref (gfile);
+
+ if (thunar_file_load (file, NULL, error))
+ {
+ /* insert the file into the cache */
+ G_LOCK (file_cache_mutex);
+ g_hash_table_insert (file_cache, g_object_ref (file->gfile), file);
+ G_UNLOCK (file_cache_mutex);
+ }
+ else
+ {
+ /* failed loading, destroy the file */
+ g_object_unref (file);
+
+ /* make sure we return NULL */
+ file = NULL;
+ }
+ }
+
+ return file;
+}
+
+
+
+/**
+ * thunar_file_get_async:
+ **/
+void
+thunar_file_get_async (GFile *location,
+ GCancellable *cancellable,
+ ThunarFileGetFunc func,
+ gpointer user_data)
+{
+ ThunarFile *file;
+ ThunarFileGetData *data;
+
+ _thunar_return_if_fail (G_IS_FILE (location));
+ _thunar_return_if_fail (func != NULL);
+
+ /* check if we already have a cached version of that file */
+ file = thunar_file_cache_lookup (location);
+ if (G_UNLIKELY (file != NULL))
+ {
+ /* call the return function with the file from the cache */
+ (func) (location, file, NULL, user_data);
+ }
+ else
+ {
+ /* allocate get data */
+ data = g_slice_new0 (ThunarFileGetData);
+ data->user_data = user_data;
+ data->func = func;
+ if (cancellable != NULL)
+ data->cancellable = g_object_ref (cancellable);
+
+ /* load the file information asynchronously */
+ g_file_query_info_async (location,
+ THUNARX_FILE_INFO_NAMESPACE,
+ G_FILE_QUERY_INFO_NONE,
+ G_PRIORITY_DEFAULT,
+ cancellable,
+ thunar_file_get_async_finish,
+ data);
+ }
+}
+
+
+
+/**
+ * thunar_file_get_for_uri:
+ * @uri : an URI or an absolute filename.
+ * @error : return location for errors or %NULL.
+ *
+ * Convenience wrapper function for thunar_file_get_for_path(), as its
+ * often required to determine a #ThunarFile for a given @uri.
+ *
+ * The caller is responsible to free the returned object using
+ * g_object_unref() when no longer needed.
+ *
+ * Return value: the #ThunarFile for the given @uri or %NULL if
+ * unable to determine.
+ **/
+ThunarFile*
+thunar_file_get_for_uri (const gchar *uri,
+ GError **error)
+{
+ ThunarFile *file;
+ GFile *path;
+
+ _thunar_return_val_if_fail (uri != NULL, NULL);
+ _thunar_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ path = g_file_new_for_commandline_arg (uri);
+ file = thunar_file_get (path, error);
+ g_object_unref (path);
+
+ return file;
+}
+
+
+
/**
* thunar_file_get_file:
* @file : a #ThunarFile instance.
diff --git a/thunar/thunar-file.h b/thunar/thunar-file.h
index 52c7407..a17325e 100644
--- a/thunar/thunar-file.h
+++ b/thunar/thunar-file.h
@@ -100,12 +100,28 @@ typedef enum /*< flags >*/
+/**
+ * ThunarFileGetFunc:
+ *
+ * Callback type for loading #ThunarFile<!---->s asynchronously.
+ **/
+typedef void (*ThunarFileGetFunc) (GFile *location,
+ ThunarFile *file,
+ GError *error,
+ gpointer user_data);
+
+
+
GType thunar_file_get_type (void) G_GNUC_CONST;
ThunarFile *thunar_file_get (GFile *file,
GError **error);
ThunarFile *thunar_file_get_for_uri (const gchar *uri,
GError **error);
+void thunar_file_get_async (GFile *location,
+ GCancellable *cancellable,
+ ThunarFileGetFunc func,
+ gpointer user_data);
GFile *thunar_file_get_file (const ThunarFile *file) G_GNUC_PURE;
More information about the Xfce4-commits
mailing list