Re: autorun.inf and .xdg-volume-info
- From: David Zeuthen <david fubar dk>
- To: gvfs-list gnome org
- Subject: Re: autorun.inf and .xdg-volume-info
- Date: Sun, 01 Mar 2009 23:00:17 -0500
On Thu, 2009-02-26 at 19:37 -0500, David Zeuthen wrote:
> Attached is an updated patch that fixes up the error handling in
> on_autorun_loaded(). It also adds two TODO items to mark two strings for
> translation (and explains that these strings are not currently used by
> anyone).
And here is another updated version that
- uses "Name" and "Icon" instead of "name" and "icon" for the key
names (same as .desktop files)
- allows either Name or Icon or both (or none of them) to be set
in the .xdg-volume-info file; the previous patch required both
of them to be set
David
Index: common/Makefile.am
===================================================================
--- common/Makefile.am (revision 2261)
+++ common/Makefile.am (working copy)
@@ -17,6 +17,7 @@
gmounttracker.c gmounttracker.h \
gvfsdaemonprotocol.c gvfsdaemonprotocol.h \
gvfsicon.h gvfsicon.c \
+ gvfsmountinfo.h gvfsmountinfo.c \
gvfsfileinfo.c gvfsfileinfo.h \
$(NULL)
--- /dev/null 2009-03-01 18:05:34.057025741 -0500
+++ common/gvfsmountinfo.h 2009-02-26 16:44:37.000000000 -0500
@@ -0,0 +1,52 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#ifndef __G_VFS_MOUNT_INFO_H__
+#define __G_VFS_MOUNT_INFO_H__
+
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+void g_vfs_mount_info_query_autorun_info (GFile *directory,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+GIcon *g_vfs_mount_info_query_autorun_info_finish (GFile *directory,
+ GAsyncResult *res,
+ GError **error);
+
+void g_vfs_mount_info_query_xdg_volume_info (GFile *directory,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+GIcon *g_vfs_mount_info_query_xdg_volume_info_finish (GFile *directory,
+ GAsyncResult *res,
+ gchar **out_name,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* __G_VFS_MOUNT_INFO_H__ */
--- /dev/null 2009-03-01 18:05:34.057025741 -0500
+++ common/gvfsmountinfo.c 2009-03-01 22:52:07.000000000 -0500
@@ -0,0 +1,712 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#include <config.h>
+#include <string.h>
+#include <glib/gi18n-lib.h>
+
+#include "gvfsmountinfo.h"
+
+static GFile *
+_g_find_file_insensitive_finish (GFile *parent,
+ GAsyncResult *result,
+ GError **error);
+
+static void
+_g_find_file_insensitive_async (GFile *parent,
+ const gchar *name,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+static void
+on_icon_file_located (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
+ GFile *icon_file;
+ GError *error;
+
+ error = NULL;
+ icon_file = _g_find_file_insensitive_finish (G_FILE (source_object),
+ res,
+ &error);
+ if (icon_file != NULL)
+ {
+ g_simple_async_result_set_op_res_gpointer (simple, g_file_icon_new (icon_file), NULL);
+ g_object_unref (icon_file);
+ }
+ else
+ {
+ g_simple_async_result_set_from_error (simple, error);
+ g_error_free (error);
+ }
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+}
+
+static void
+on_autorun_loaded (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
+ GFile *autorun_file;
+ gchar *content;
+ gchar *relative_icon_path;
+ gsize content_length;
+ GError *error;
+
+ relative_icon_path = NULL;
+
+ autorun_file = G_FILE (source_object);
+
+ error = NULL;
+ if (g_file_load_contents_finish (autorun_file,
+ res,
+ &content,
+ &content_length,
+ NULL,
+ &error))
+ {
+ /* Scan through for an "icon=" line. Can't use GKeyFile,
+ * because .inf files aren't always valid key files
+ **/
+ GRegex *icon_regex;
+ GMatchInfo *match_info;
+
+ /* [^,] is because sometimes the icon= line
+ * has a comma at the end
+ **/
+ icon_regex = g_regex_new ("icon=([^,\\r\\n]+)",
+ G_REGEX_CASELESS, 0, NULL);
+ g_regex_match (icon_regex, content, 0,
+ &match_info);
+
+ /* Even if there are multiple matches, pick only the
+ * first.
+ **/
+ if (g_match_info_matches (match_info))
+ {
+ gchar *chr;
+ gchar *word = g_match_info_fetch (match_info, 1);
+
+ /* Replace '\' with '/' */
+ while ((chr = strchr (word, '\\')) != NULL)
+ *chr = '/';
+
+ /* If the file name's not valid UTF-8,
+ * don't even try to load it
+ **/
+ if (g_utf8_validate (word, -1, NULL))
+ {
+ relative_icon_path = word;
+ }
+ else
+ {
+ /* TODO: mark for translatation. Strictly, this isn't very important; this string
+ * will never be displayed since all current users of g_vfs_mount_info_query_autorun_info()
+ * passes NULL for the GError**.
+ */
+ error = g_error_new_literal (G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ "Icon name is not valid UTF-8");
+ g_free (word);
+ }
+ }
+
+ g_match_info_free (match_info);
+
+ g_regex_unref (icon_regex);
+ g_free (content);
+ }
+
+ /* some autorun.in points to the .exe file for the icon; make sure we avoid using that */
+ if (relative_icon_path != NULL)
+ {
+ if (!g_str_has_suffix (relative_icon_path, ".exe"))
+ {
+ GFile *root;
+
+ root = g_file_get_parent (autorun_file);
+
+ _g_find_file_insensitive_async (root,
+ relative_icon_path,
+ NULL,
+ on_icon_file_located,
+ simple);
+
+ g_object_unref (root);
+ }
+ else
+ {
+ /* TODO: mark for translatation. Strictly, this isn't very important; this string
+ * will never be displayed since all current users of g_vfs_mount_info_query_autorun_info()
+ * passes NULL for the GError**.
+ */
+ error = g_error_new_literal (G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ "Icon is an .exe file");
+ }
+ }
+
+ if (error != NULL)
+ {
+ g_simple_async_result_set_from_error (simple, error);
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+ g_error_free (error);
+ }
+
+ g_free (relative_icon_path);
+}
+
+static void
+on_autorun_located (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
+ GFile *autorun_path;
+ GError *error;
+
+ error = NULL;
+ autorun_path = _g_find_file_insensitive_finish (G_FILE (source_object),
+ res,
+ &error);
+ if (error != NULL)
+ {
+ g_simple_async_result_set_from_error (simple, error);
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+ g_error_free (error);
+ }
+ else
+ {
+ g_file_load_contents_async (autorun_path,
+ g_object_get_data (G_OBJECT (simple), "cancellable"),
+ on_autorun_loaded,
+ simple);
+ g_object_unref (autorun_path);
+ }
+}
+
+void
+g_vfs_mount_info_query_autorun_info (GFile *directory,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple;
+
+ simple = g_simple_async_result_new (G_OBJECT (directory),
+ callback,
+ user_data,
+ g_vfs_mount_info_query_autorun_info);
+
+ if (cancellable != NULL)
+ g_object_set_data_full (G_OBJECT (simple), "cancellable", g_object_ref (cancellable), g_object_unref);
+
+ _g_find_file_insensitive_async (directory,
+ "autorun.inf",
+ cancellable,
+ on_autorun_located,
+ simple);
+}
+
+GIcon *
+g_vfs_mount_info_query_autorun_info_finish (GFile *directory,
+ GAsyncResult *res,
+ GError **error)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
+ GIcon *ret;
+
+ g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_vfs_mount_info_query_autorun_info);
+
+ ret = NULL;
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ goto out;
+
+ ret = g_simple_async_result_get_op_res_gpointer (simple);
+
+ out:
+ return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+on_xdg_volume_info_loaded (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
+ GFile *xdg_volume_info_file;
+ gchar *content;
+ gsize content_length;
+ GError *error;
+ GKeyFile *key_file;
+ gchar *name;
+ gchar *icon_name;
+ GIcon *icon;
+
+ content = NULL;
+ key_file = NULL;
+ name = NULL;
+ icon_name = NULL;
+
+ xdg_volume_info_file = G_FILE (source_object);
+
+ error = NULL;
+ if (g_file_load_contents_finish (xdg_volume_info_file,
+ res,
+ &content,
+ &content_length,
+ NULL,
+ &error))
+ {
+ key_file = g_key_file_new ();
+ if (!g_key_file_load_from_data (key_file,
+ content,
+ content_length,
+ G_KEY_FILE_NONE,
+ &error))
+ goto out;
+
+
+ name = g_key_file_get_locale_string (key_file,
+ "XDG Volume Info",
+ "Name",
+ NULL,
+ NULL);
+
+ icon_name = g_key_file_get_locale_string (key_file,
+ "XDG Volume Info",
+ "Icon",
+ NULL,
+ NULL);
+
+ if (icon_name != NULL)
+ {
+ icon = g_themed_icon_new (icon_name);
+ g_themed_icon_append_name (G_THEMED_ICON (icon), "drive-removable-media");
+ g_themed_icon_append_name (G_THEMED_ICON (icon), "drive-removable");
+ g_themed_icon_append_name (G_THEMED_ICON (icon), "drive");
+ }
+ else
+ {
+ icon = NULL;
+ }
+
+ g_simple_async_result_set_op_res_gpointer (simple, icon, NULL);
+ g_object_set_data_full (G_OBJECT (simple), "name", name, g_free);
+ name = NULL; /* steals name */
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+ }
+
+ out:
+
+ if (key_file != NULL)
+ g_key_file_free (key_file);
+
+ if (error != NULL)
+ {
+ g_simple_async_result_set_from_error (simple, error);
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+ g_error_free (error);
+ }
+
+ g_free (name);
+ g_free (icon_name);
+ g_free (content);
+}
+
+void
+g_vfs_mount_info_query_xdg_volume_info (GFile *directory,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple;
+ GFile *file;
+
+ simple = g_simple_async_result_new (G_OBJECT (directory),
+ callback,
+ user_data,
+ g_vfs_mount_info_query_xdg_volume_info);
+
+ file = g_file_resolve_relative_path (directory, ".xdg-volume-info");
+ g_file_load_contents_async (file,
+ cancellable,
+ on_xdg_volume_info_loaded,
+ simple);
+ g_object_unref (file);
+}
+
+GIcon *g_vfs_mount_info_query_xdg_volume_info_finish (GFile *directory,
+ GAsyncResult *res,
+ gchar **out_name,
+ GError **error)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
+ GIcon *ret;
+
+ g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_vfs_mount_info_query_xdg_volume_info);
+
+ ret = NULL;
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ goto out;
+
+ ret = g_simple_async_result_get_op_res_gpointer (simple);
+
+ if (out_name != NULL)
+ *out_name = g_strdup (g_object_get_data (G_OBJECT (simple), "name"));
+
+ out:
+ return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+#define INSENSITIVE_SEARCH_ITEMS_PER_CALLBACK 100
+
+static void
+enumerated_children_callback (GObject *source_object, GAsyncResult *res,
+ gpointer user_data);
+
+static void
+more_files_callback (GObject *source_object, GAsyncResult *res,
+ gpointer user_data);
+
+static void
+find_file_insensitive_exists_callback (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data);
+
+typedef struct _InsensitiveFileSearchData
+{
+ GFile *root;
+ gchar *original_path;
+ gchar **split_path;
+ gint index;
+ GFileEnumerator *enumerator;
+ GFile *current_file;
+
+ GCancellable *cancellable;
+ GAsyncReadyCallback callback;
+ gpointer user_data;
+} InsensitiveFileSearchData;
+
+static void
+_g_find_file_insensitive_async (GFile *parent,
+ const gchar *name,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ InsensitiveFileSearchData *data;
+ GFile *direct_file = g_file_get_child (parent, name);
+
+ data = g_new0 (InsensitiveFileSearchData, 1);
+ data->cancellable = cancellable;
+ data->callback = callback;
+ data->user_data = user_data;
+ data->root = g_object_ref (parent);
+ data->original_path = g_strdup (name);
+
+ g_file_query_info_async (direct_file, G_FILE_ATTRIBUTE_STANDARD_TYPE,
+ G_FILE_QUERY_INFO_NONE, G_PRIORITY_DEFAULT,
+ cancellable,
+ find_file_insensitive_exists_callback, data);
+
+
+}
+
+static void
+clear_find_file_insensitive_state (InsensitiveFileSearchData *data)
+{
+ if (data->root)
+ g_object_unref (data->root);
+ g_free (data->original_path);
+ if (data->split_path)
+ g_strfreev (data->split_path);
+ if (data->enumerator)
+ g_object_unref (data->enumerator);
+ if (data->current_file)
+ g_object_unref (data->current_file);
+ g_free (data);
+}
+
+static void
+find_file_insensitive_exists_callback (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GFileInfo *info;
+ InsensitiveFileSearchData *data = (InsensitiveFileSearchData *) (user_data);
+
+ /* The file exists and can be found with the given path, no need to search. */
+ if ((info = g_file_query_info_finish (G_FILE (source_object), res, NULL)))
+ {
+ GSimpleAsyncResult *simple;
+
+ simple = g_simple_async_result_new (G_OBJECT (data->root),
+ data->callback,
+ data->user_data,
+ _g_find_file_insensitive_async);
+
+ g_simple_async_result_set_op_res_gpointer (simple, g_object_ref (source_object), g_object_unref);
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+ clear_find_file_insensitive_state (data);
+ }
+
+ else
+ {
+ data->split_path = g_strsplit (data->original_path, G_DIR_SEPARATOR_S, -1);
+ data->index = 0;
+ data->enumerator = NULL;
+ data->current_file = g_object_ref (data->root);
+
+ /* Skip any empty components due to multiple slashes */
+ while (data->split_path[data->index] != NULL &&
+ *data->split_path[data->index] == 0)
+ data->index++;
+
+ g_file_enumerate_children_async (data->current_file,
+ G_FILE_ATTRIBUTE_STANDARD_NAME,
+ 0, G_PRIORITY_DEFAULT,
+ data->cancellable,
+ enumerated_children_callback, data);
+ }
+
+ g_object_unref (source_object);
+}
+
+static void
+enumerated_children_callback (GObject *source_object, GAsyncResult *res,
+ gpointer user_data)
+{
+ GFileEnumerator *enumerator;
+ InsensitiveFileSearchData *data = (InsensitiveFileSearchData *) (user_data);
+
+ enumerator = g_file_enumerate_children_finish (G_FILE (source_object),
+ res, NULL);
+
+ if (enumerator == NULL)
+ {
+ GSimpleAsyncResult *simple;
+ GFile *file;
+
+ simple = g_simple_async_result_new (G_OBJECT (data->root),
+ data->callback,
+ data->user_data,
+ _g_find_file_insensitive_async);
+
+ file = g_file_get_child (data->root, data->original_path);
+
+ g_simple_async_result_set_op_res_gpointer (simple, g_object_ref (file), g_object_unref);
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+ clear_find_file_insensitive_state (data);
+ return;
+ }
+
+ data->enumerator = enumerator;
+ g_file_enumerator_next_files_async (enumerator,
+ INSENSITIVE_SEARCH_ITEMS_PER_CALLBACK,
+ G_PRIORITY_DEFAULT,
+ data->cancellable,
+ more_files_callback,
+ data);
+}
+
+static void
+more_files_callback (GObject *source_object, GAsyncResult *res,
+ gpointer user_data)
+{
+ InsensitiveFileSearchData *data = (InsensitiveFileSearchData *) (user_data);
+ GList *files, *l;
+ gchar *filename = NULL, *component, *case_folded_name,
+ *name_collation_key;
+ gboolean end_of_files, is_utf8;
+
+ files = g_file_enumerator_next_files_finish (data->enumerator,
+ res, NULL);
+
+ end_of_files = files == NULL;
+
+ component = data->split_path[data->index];
+ g_return_if_fail (component != NULL);
+
+ is_utf8 = (g_utf8_validate (component, -1, NULL));
+ if (is_utf8)
+ {
+ case_folded_name = g_utf8_casefold (component, -1);
+ name_collation_key = g_utf8_collate_key (case_folded_name, -1);
+ g_free (case_folded_name);
+ }
+
+ else
+ {
+ name_collation_key = g_ascii_strdown (component, -1);
+ }
+
+ for (l = files; l != NULL; l = l->next)
+ {
+ GFileInfo *info;
+ const gchar *this_name;
+ gchar *key;
+
+ info = l->data;
+ this_name = g_file_info_get_name (info);
+
+ if (is_utf8 && g_utf8_validate (this_name, -1, NULL))
+ {
+ gchar *case_folded;
+ case_folded = g_utf8_casefold (this_name, -1);
+ key = g_utf8_collate_key (case_folded, -1);
+ g_free (case_folded);
+ }
+ else
+ {
+ key = g_ascii_strdown (this_name, -1);
+ }
+
+ if (strcmp (key, name_collation_key) == 0)
+ filename = g_strdup (this_name);
+ g_free (key);
+
+ if (filename)
+ break;
+ }
+
+ g_list_foreach (files, (GFunc)g_object_unref, NULL);
+ g_list_free (files);
+ g_free (name_collation_key);
+
+ if (filename)
+ {
+ GFile *next_file;
+
+ g_file_enumerator_close_async (data->enumerator,
+ G_PRIORITY_DEFAULT,
+ data->cancellable,
+ NULL, NULL);
+ g_object_unref (data->enumerator);
+ data->enumerator = NULL;
+
+ /* Set the current file and continue searching */
+ next_file = g_file_get_child (data->current_file, filename);
+ g_free (filename);
+ g_object_unref (data->current_file);
+ data->current_file = next_file;
+
+ data->index++;
+ /* Skip any empty components due to multiple slashes */
+ while (data->split_path[data->index] != NULL &&
+ *data->split_path[data->index] == 0)
+ data->index++;
+
+ if (data->split_path[data->index] == NULL)
+ {
+ /* Search is complete, file was found */
+ GSimpleAsyncResult *simple;
+
+ simple = g_simple_async_result_new (G_OBJECT (data->root),
+ data->callback,
+ data->user_data,
+ _g_find_file_insensitive_async);
+
+ g_simple_async_result_set_op_res_gpointer (simple, g_object_ref (data->current_file), g_object_unref);
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+ clear_find_file_insensitive_state (data);
+ return;
+ }
+
+ /* Continue searching down the tree */
+ g_file_enumerate_children_async (data->current_file,
+ G_FILE_ATTRIBUTE_STANDARD_NAME,
+ 0, G_PRIORITY_DEFAULT,
+ data->cancellable,
+ enumerated_children_callback,
+ data);
+ return;
+ }
+
+ if (end_of_files)
+ {
+ /* Could not find the given file, abort the search */
+ GSimpleAsyncResult *simple;
+ GFile *file;
+
+ g_object_unref (data->enumerator);
+ data->enumerator = NULL;
+
+ simple = g_simple_async_result_new (G_OBJECT (data->root),
+ data->callback,
+ data->user_data,
+ _g_find_file_insensitive_async);
+
+ file = g_file_get_child (data->root, data->original_path);
+ g_simple_async_result_set_op_res_gpointer (simple, file, g_object_unref);
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+ clear_find_file_insensitive_state (data);
+ return;
+ }
+
+ /* Continue enumerating */
+ g_file_enumerator_next_files_async (data->enumerator,
+ INSENSITIVE_SEARCH_ITEMS_PER_CALLBACK,
+ G_PRIORITY_DEFAULT,
+ data->cancellable,
+ more_files_callback,
+ data);
+}
+
+static GFile *
+_g_find_file_insensitive_finish (GFile *parent,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+ GFile *file;
+
+ g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), NULL);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return NULL;
+
+ file = G_FILE (g_simple_async_result_get_op_res_gpointer (simple));
+ return g_object_ref (file);
+}
[Date Prev][
Date Next] [Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]