summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Larsson <alexl@redhat.com>2008-10-21 12:58:45 +0000
committerAlexander Larsson <alexl@src.gnome.org>2008-10-21 12:58:45 +0000
commitd73422735a1d60d1b014cf40b273e7391389e678 (patch)
tree63c01910d1ef0d30b1084209c90e21144ee4710b
parent1078f20f47debb00d0a0f6966b6680ad0473e32f (diff)
downloadgvfs-d73422735a1d60d1b014cf40b273e7391389e678.tar.gz
Patch from David Zeuthen
2008-10-21 Alexander Larsson <alexl@redhat.com> Patch from David Zeuthen * common/Makefile.am: * common/gvfsicon.[ch]: Added GVfsIcon object for GVfs backend specific icons. * common/gmountspec.[ch]: Make sure to/from string works correctly to roundtrip GMountSpec:s Make GMountSpec a boxed type * common/gvfsdaemonprotocol.h: Add OpenIconForRead operation * client/Makefile.am: * client/gvfsiconloadable.[ch]: In gvfs client side, implement GLoadableIcon for GVfsIcon type. * client/gdaemonvfs.c: Make sure that we add the GLoadableIcon interface for GVfsIcon on load * daemon/Makefile.am: * daemon/gvfsbackend.[ch]: * daemon/gvfsjobopeniconforread.[ch]: Add new job type for OpenIconForRead op * daemon/gvfsbackendgphoto2.c: Implement OpenIconForRead for icon previews. svn path=/trunk/; revision=2070
-rw-r--r--ChangeLog30
-rw-r--r--client/Makefile.am1
-rw-r--r--client/gdaemonvfs.c6
-rw-r--r--client/gvfsiconloadable.c431
-rw-r--r--client/gvfsiconloadable.h35
-rw-r--r--common/Makefile.am1
-rw-r--r--common/gmountspec.c107
-rw-r--r--common/gmountspec.h8
-rw-r--r--common/gvfsdaemonprotocol.h1
-rw-r--r--common/gvfsicon.c282
-rw-r--r--common/gvfsicon.h69
-rw-r--r--daemon/Makefile.am1
-rw-r--r--daemon/gvfsbackend.c5
-rw-r--r--daemon/gvfsbackend.h7
-rw-r--r--daemon/gvfsbackendgphoto2.c72
-rw-r--r--daemon/gvfsjobopeniconforread.c142
-rw-r--r--daemon/gvfsjobopeniconforread.h63
17 files changed, 1251 insertions, 10 deletions
diff --git a/ChangeLog b/ChangeLog
index edb7997c..8aad53e4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,35 @@
2008-10-21 Alexander Larsson <alexl@redhat.com>
+ Patch from David Zeuthen
+
+ * common/Makefile.am:
+ * common/gvfsicon.[ch]:
+ Added GVfsIcon object for GVfs backend specific icons.
+
+ * common/gmountspec.[ch]:
+ Make sure to/from string works correctly to roundtrip GMountSpec:s
+ Make GMountSpec a boxed type
+
+ * common/gvfsdaemonprotocol.h:
+ Add OpenIconForRead operation
+
+ * client/Makefile.am:
+ * client/gvfsiconloadable.[ch]:
+ In gvfs client side, implement GLoadableIcon for GVfsIcon type.
+
+ * client/gdaemonvfs.c:
+ Make sure that we add the GLoadableIcon interface for GVfsIcon on load
+
+ * daemon/Makefile.am:
+ * daemon/gvfsbackend.[ch]:
+ * daemon/gvfsjobopeniconforread.[ch]:
+ Add new job type for OpenIconForRead op
+
+ * daemon/gvfsbackendgphoto2.c:
+ Implement OpenIconForRead for icon previews.
+
+2008-10-21 Alexander Larsson <alexl@redhat.com>
+
* configure.ac:
Require glib 2.19.1 for GIcon serialization support
diff --git a/client/Makefile.am b/client/Makefile.am
index 274d9fd3..b2aea25d 100644
--- a/client/Makefile.am
+++ b/client/Makefile.am
@@ -33,6 +33,7 @@ vfssources = \
gdaemonfileenumerator.c gdaemonfileenumerator.h \
gdaemonfilemonitor.c gdaemonfilemonitor.h \
gvfsdaemondbus.c gvfsdaemondbus.h \
+ gvfsiconloadable.c gvfsiconloadable.h \
gvfsuriutils.c gvfsuriutils.h \
gvfsurimapper.c gvfsurimapper.h \
$(URI_PARSER_SOURCES) \
diff --git a/client/gdaemonvfs.c b/client/gdaemonvfs.c
index 6d99c299..94f7e9ba 100644
--- a/client/gdaemonvfs.c
+++ b/client/gdaemonvfs.c
@@ -36,6 +36,8 @@
#include "gmountspec.h"
#include "gvfsurimapper.h"
#include "gdaemonvolumemonitor.h"
+#include "gvfsicon.h"
+#include "gvfsiconloadable.h"
#include <glib/gi18n-lib.h>
typedef struct {
@@ -1129,6 +1131,10 @@ g_io_module_load (GIOModule *module)
g_daemon_vfs_register_type (G_TYPE_MODULE (module));
g_daemon_volume_monitor_register_types (G_TYPE_MODULE (module));
+
+ /* We implement GLoadableIcon only on client side.
+ see comment in common/giconvfs.c */
+ _g_vfs_icon_add_loadable_interface ();
g_io_extension_point_implement (G_VFS_EXTENSION_POINT_NAME,
G_TYPE_DAEMON_VFS,
diff --git a/client/gvfsiconloadable.c b/client/gvfsiconloadable.c
new file mode 100644
index 00000000..1c6d54b4
--- /dev/null
+++ b/client/gvfsiconloadable.c
@@ -0,0 +1,431 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2008 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 "gvfsicon.h"
+#include "gvfsiconloadable.h"
+#include "gmounttracker.h"
+#include "gvfsdaemondbus.h"
+#include "gdaemonvfs.h"
+#include "gdaemonfileinputstream.h"
+#include "gvfsdaemonprotocol.h"
+#include "gdbusutils.h"
+
+/* see comment in common/giconvfs.c for why the GLoadableIcon interface is here */
+
+static DBusMessage *
+create_empty_message (GVfsIcon *vfs_icon,
+ const char *op,
+ GMountInfo **mount_info_out,
+ GError **error)
+{
+ DBusMessage *message;
+ GMountInfo *mount_info;
+
+ mount_info = _g_daemon_vfs_get_mount_info_sync (vfs_icon->mount_spec,
+ "/",
+ error);
+
+ if (mount_info == NULL)
+ return NULL;
+
+ if (mount_info_out)
+ *mount_info_out = g_mount_info_ref (mount_info);
+
+ message =
+ dbus_message_new_method_call (mount_info->dbus_id,
+ mount_info->object_path,
+ G_VFS_DBUS_MOUNT_INTERFACE,
+ op);
+
+ _g_dbus_message_append_args (message, G_DBUS_TYPE_CSTRING, &(vfs_icon->icon_id), 0);
+
+ g_mount_info_unref (mount_info);
+ return message;
+}
+
+static DBusMessage *
+do_sync_path_call (GVfsIcon *vfs_icon,
+ const char *op,
+ GMountInfo **mount_info_out,
+ DBusConnection **connection_out,
+ GCancellable *cancellable,
+ GError **error,
+ int first_arg_type,
+ ...)
+{
+ DBusMessage *message, *reply;
+ va_list var_args;
+ GError *my_error;
+
+ retry:
+ message = create_empty_message (vfs_icon, op, mount_info_out, error);
+ if (!message)
+ return NULL;
+
+ va_start (var_args, first_arg_type);
+ _g_dbus_message_append_args_valist (message,
+ first_arg_type,
+ var_args);
+ va_end (var_args);
+
+
+ my_error = NULL;
+ reply = _g_vfs_daemon_call_sync (message,
+ connection_out,
+ NULL, NULL, NULL,
+ cancellable, &my_error);
+ dbus_message_unref (message);
+
+ if (reply == NULL)
+ {
+ if (g_error_matches (my_error, G_VFS_ERROR, G_VFS_ERROR_RETRY))
+ {
+ g_error_free (my_error);
+ goto retry;
+ }
+ g_propagate_error (error, my_error);
+ }
+
+ return reply;
+}
+
+static GInputStream *
+g_vfs_icon_load (GLoadableIcon *icon,
+ int size,
+ char **type,
+ GCancellable *cancellable,
+ GError **error)
+{
+ DBusConnection *connection;
+ int fd;
+ DBusMessage *reply;
+ guint32 fd_id;
+ dbus_bool_t can_seek;
+
+ reply = do_sync_path_call (G_VFS_ICON (icon),
+ G_VFS_DBUS_MOUNT_OP_OPEN_ICON_FOR_READ,
+ NULL,
+ &connection,
+ cancellable,
+ error,
+ 0);
+ if (reply == NULL)
+ return NULL;
+
+ if (!dbus_message_get_args (reply, NULL,
+ DBUS_TYPE_UINT32, &fd_id,
+ DBUS_TYPE_BOOLEAN, &can_seek,
+ DBUS_TYPE_INVALID))
+ {
+ dbus_message_unref (reply);
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("Invalid return value from open_icon_for_read"));
+ return NULL;
+ }
+
+ dbus_message_unref (reply);
+
+ fd = _g_dbus_connection_get_fd_sync (connection, fd_id);
+ if (fd == -1)
+ {
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("Didn't get stream file descriptor"));
+ return NULL;
+ }
+
+ return G_INPUT_STREAM (g_daemon_file_input_stream_new (fd, can_seek));
+}
+
+
+typedef void (*AsyncPathCallCallback) (DBusMessage *reply,
+ DBusConnection *connection,
+ GSimpleAsyncResult *result,
+ GCancellable *cancellable,
+ gpointer callback_data);
+
+
+typedef struct {
+ GSimpleAsyncResult *result;
+ GVfsIcon *vfs_icon;
+ char *op;
+ GCancellable *cancellable;
+ DBusMessage *args;
+ AsyncPathCallCallback callback;
+ gpointer callback_data;
+ GDestroyNotify notify;
+} AsyncPathCall;
+
+
+static void
+async_path_call_free (AsyncPathCall *data)
+{
+ if (data->notify)
+ data->notify (data->callback_data);
+
+ if (data->result)
+ g_object_unref (data->result);
+ g_object_unref (data->vfs_icon);
+ g_free (data->op);
+ if (data->cancellable)
+ g_object_unref (data->cancellable);
+ if (data->args)
+ dbus_message_unref (data->args);
+ g_free (data);
+}
+
+static void
+async_path_call_done (DBusMessage *reply,
+ DBusConnection *connection,
+ GError *io_error,
+ gpointer _data)
+{
+ AsyncPathCall *data = _data;
+ GSimpleAsyncResult *result;
+
+ if (io_error != NULL)
+ {
+ g_simple_async_result_set_from_error (data->result, io_error);
+ g_simple_async_result_complete (data->result);
+ async_path_call_free (data);
+ }
+ else
+ {
+ result = data->result;
+ g_object_weak_ref (G_OBJECT (result), (GWeakNotify)async_path_call_free, data);
+ data->result = NULL;
+
+ data->callback (reply, connection,
+ result,
+ data->cancellable,
+ data->callback_data);
+
+ /* Free data here, or later if callback ref:ed the result */
+ g_object_unref (result);
+ }
+}
+
+static void
+do_async_path_call_callback (GMountInfo *mount_info,
+ gpointer _data,
+ GError *error)
+{
+ AsyncPathCall *data = _data;
+ DBusMessage *message;
+ DBusMessageIter arg_source, arg_dest;
+
+ if (error != NULL)
+ {
+ g_simple_async_result_set_from_error (data->result, error);
+ g_simple_async_result_complete (data->result);
+ async_path_call_free (data);
+ return;
+ }
+
+ message =
+ dbus_message_new_method_call (mount_info->dbus_id,
+ mount_info->object_path,
+ G_VFS_DBUS_MOUNT_INTERFACE,
+ data->op);
+
+ _g_dbus_message_append_args (message, G_DBUS_TYPE_CSTRING, &(data->vfs_icon->icon_id), 0);
+
+ /* Append more args from data->args */
+
+ if (data->args)
+ {
+ dbus_message_iter_init (data->args, &arg_source);
+ dbus_message_iter_init_append (message, &arg_dest);
+
+ _g_dbus_message_iter_copy (&arg_dest, &arg_source);
+ }
+
+ _g_vfs_daemon_call_async (message,
+ async_path_call_done, data,
+ data->cancellable);
+
+ dbus_message_unref (message);
+}
+
+
+static void
+do_async_path_call (GVfsIcon *vfs_icon,
+ const char *op,
+ GCancellable *cancellable,
+ GAsyncReadyCallback op_callback,
+ gpointer op_callback_data,
+ AsyncPathCallCallback callback,
+ gpointer callback_data,
+ GDestroyNotify notify,
+ int first_arg_type,
+ ...)
+{
+ va_list var_args;
+ AsyncPathCall *data;
+
+ data = g_new0 (AsyncPathCall, 1);
+
+ data->result = g_simple_async_result_new (G_OBJECT (vfs_icon),
+ op_callback, op_callback_data,
+ NULL);
+
+ data->vfs_icon = g_object_ref (vfs_icon);
+ data->op = g_strdup (op);
+ if (cancellable)
+ data->cancellable = g_object_ref (cancellable);
+ data->callback = callback;
+ data->callback_data = callback_data;
+ data->notify = notify;
+
+ if (first_arg_type != 0)
+ {
+ data->args = dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_CALL);
+ if (data->args == NULL)
+ _g_dbus_oom ();
+
+ va_start (var_args, first_arg_type);
+ _g_dbus_message_append_args_valist (data->args,
+ first_arg_type,
+ var_args);
+ va_end (var_args);
+ }
+
+
+ _g_daemon_vfs_get_mount_info_async (vfs_icon->mount_spec,
+ "/",
+ do_async_path_call_callback,
+ data);
+}
+
+typedef struct {
+ GSimpleAsyncResult *result;
+ gboolean can_seek;
+} GetFDData;
+
+static void
+load_async_get_fd_cb (int fd,
+ gpointer callback_data)
+{
+ GetFDData *data = callback_data;
+ GFileInputStream *stream;
+
+ if (fd == -1)
+ {
+ g_simple_async_result_set_error (data->result,
+ G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("Couldn't get stream file descriptor"));
+ }
+ else
+ {
+ stream = g_daemon_file_input_stream_new (fd, data->can_seek);
+ g_simple_async_result_set_op_res_gpointer (data->result, stream, g_object_unref);
+ }
+
+ g_simple_async_result_complete (data->result);
+
+ g_object_unref (data->result);
+ g_free (data);
+}
+
+static void
+load_async_cb (DBusMessage *reply,
+ DBusConnection *connection,
+ GSimpleAsyncResult *result,
+ GCancellable *cancellable,
+ gpointer callback_data)
+{
+ guint32 fd_id;
+ dbus_bool_t can_seek;
+ GetFDData *get_fd_data;
+
+ if (!dbus_message_get_args (reply, NULL,
+ DBUS_TYPE_UINT32, &fd_id,
+ DBUS_TYPE_BOOLEAN, &can_seek,
+ DBUS_TYPE_INVALID))
+ {
+ g_simple_async_result_set_error (result,
+ G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("Invalid return value from open"));
+ g_simple_async_result_complete (result);
+ return;
+ }
+
+ get_fd_data = g_new0 (GetFDData, 1);
+ get_fd_data->result = g_object_ref (result);
+ get_fd_data->can_seek = can_seek;
+
+ _g_dbus_connection_get_fd_async (connection, fd_id,
+ load_async_get_fd_cb, get_fd_data);
+}
+
+static void
+g_vfs_icon_load_async (GLoadableIcon *icon,
+ int size,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ do_async_path_call (G_VFS_ICON (icon),
+ G_VFS_DBUS_MOUNT_OP_OPEN_ICON_FOR_READ,
+ cancellable,
+ callback, user_data,
+ load_async_cb, NULL, NULL,
+ 0);
+}
+
+static GInputStream *
+g_vfs_icon_load_finish (GLoadableIcon *icon,
+ GAsyncResult *res,
+ char **type,
+ GError **error)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
+ gpointer op;
+
+ op = g_simple_async_result_get_op_res_gpointer (simple);
+ if (op)
+ return g_object_ref (op);
+
+ return NULL;
+}
+
+
+static void
+g_vfs_icon_loadable_icon_iface_init (GLoadableIconIface *iface)
+{
+ iface->load = g_vfs_icon_load;
+ iface->load_async = g_vfs_icon_load_async;
+ iface->load_finish = g_vfs_icon_load_finish;
+}
+
+void
+_g_vfs_icon_add_loadable_interface (void)
+{
+ static const GInterfaceInfo g_implement_interface_info = {
+ (GInterfaceInitFunc) g_vfs_icon_loadable_icon_iface_init
+ };
+
+ g_type_add_interface_static (G_VFS_TYPE_ICON, G_TYPE_LOADABLE_ICON, &g_implement_interface_info);
+}
diff --git a/client/gvfsiconloadable.h b/client/gvfsiconloadable.h
new file mode 100644
index 00000000..bda7485a
--- /dev/null
+++ b/client/gvfsiconloadable.h
@@ -0,0 +1,35 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2008 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_ICON_LOADABLE_H__
+#define __G_VFS_ICON_LOADABLE_H__
+
+#include <gio/gio.h>
+#include <gmountspec.h>
+
+G_BEGIN_DECLS
+
+void _g_vfs_icon_add_loadable_interface (void);
+
+G_END_DECLS
+
+#endif /* __G_VFS_ICON_LOADABLE_H__ */
diff --git a/common/Makefile.am b/common/Makefile.am
index 2fbb908b..12dd9e83 100644
--- a/common/Makefile.am
+++ b/common/Makefile.am
@@ -16,6 +16,7 @@ libgvfscommon_la_SOURCES = \
gmountsource.c gmountsource.h \
gmounttracker.c gmounttracker.h \
gvfsdaemonprotocol.c gvfsdaemonprotocol.h \
+ gvfsicon.h gvfsicon.c \
$(NULL)
libgvfscommon_la_LIBADD = \
diff --git a/common/gmountspec.c b/common/gmountspec.c
index 7d8fa57e..bee872fc 100644
--- a/common/gmountspec.c
+++ b/common/gmountspec.c
@@ -455,6 +455,8 @@ char *
g_mount_spec_to_string (GMountSpec *spec)
{
GString *str;
+ char *k;
+ char *v;
int i;
if (spec == NULL)
@@ -466,13 +468,102 @@ g_mount_spec_to_string (GMountSpec *spec)
{
GMountSpecItem *item = &g_array_index (spec->items, GMountSpecItem, i);
- g_string_append_printf (str, "%s='%s',", item->key, item->value);
+ k = g_uri_escape_string (item->key, NULL, TRUE);
+ v = g_uri_escape_string (item->value, NULL, TRUE);
+ g_string_append_printf (str, "%s=%s,", k, v);
+ g_free (k);
+ g_free (v);
}
- g_string_append_printf (str, "mount_prefix='%s'", spec->mount_prefix);
+ k = g_uri_escape_string ("__mount_prefix", NULL, TRUE);
+ v = g_uri_escape_string (spec->mount_prefix, NULL, TRUE);
+ g_string_append_printf (str, "%s=%s", k, v);
+ g_free (k);
+ g_free (v);
return g_string_free (str, FALSE);
}
+GMountSpec *
+g_mount_spec_new_from_string (const gchar *str,
+ GError **error)
+{
+ GArray *items;
+ GMountSpec *mount_spec;
+ char **kv_pairs;
+ char *mount_prefix;
+ int i;
+
+ g_return_val_if_fail (str != NULL, NULL);
+
+ mount_spec = NULL;
+ mount_prefix = NULL;
+ items = g_array_new (FALSE, TRUE, sizeof (GMountSpecItem));
+
+ kv_pairs = g_strsplit (str, ",", 0);
+ for (i = 0; kv_pairs[i] != NULL; i++)
+ {
+ char **tokens;
+ GMountSpecItem item;
+
+ tokens = g_strsplit (kv_pairs[i], "=", 0);
+ if (g_strv_length (tokens) != 2)
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ "Encountered invalid key/value pair '%s' while decoding GMountSpec",
+ kv_pairs[i]);
+ g_strfreev (tokens);
+ g_strfreev (kv_pairs);
+ goto fail;
+ }
+
+ item.key = g_uri_unescape_string (tokens[0], NULL);
+ item.value = g_uri_unescape_string (tokens[1], NULL);
+
+ if (strcmp (item.key, "__mount_prefix") == 0)
+ {
+ g_free (item.key);
+ mount_prefix = item.value;
+ }
+ else
+ {
+ g_array_append_val (items, item);
+ }
+
+ g_strfreev (tokens);
+ }
+ g_strfreev (kv_pairs);
+
+ if (mount_prefix == NULL)
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ "Didn't find __mount_prefix while decoding '%s' GMountSpec",
+ str);
+ goto fail;
+ }
+
+ /* this constructor takes ownership of the data we pass in */
+ mount_spec = g_mount_spec_new_from_data (items,
+ mount_prefix);
+
+ return mount_spec;
+
+ fail:
+ for (i = 0; i < items->len; i++)
+ {
+ GMountSpecItem *item = &g_array_index (items, GMountSpecItem, i);
+ g_free (item->key);
+ g_free (item->value);
+ }
+ g_array_free (items, TRUE);
+ g_free (mount_prefix);
+ return NULL;
+}
+
+
char *
g_mount_spec_canonicalize_path (const char *path)
{
@@ -532,3 +623,15 @@ g_mount_spec_canonicalize_path (const char *path)
return canon;
}
+
+GType
+g_type_mount_spec_get_gtype (void)
+{
+ static GType type_id = 0;
+
+ if (type_id == 0)
+ type_id = g_boxed_type_register_static (g_intern_static_string ("GMountSpec"),
+ (GBoxedCopyFunc) g_mount_spec_ref,
+ (GBoxedFreeFunc) g_mount_spec_unref);
+ return type_id;
+}
diff --git a/common/gmountspec.h b/common/gmountspec.h
index 55ac5c63..879c39b8 100644
--- a/common/gmountspec.h
+++ b/common/gmountspec.h
@@ -92,11 +92,17 @@ const char *g_mount_spec_get (GMountSpec *spec,
const char *key);
const char *g_mount_spec_get_type (GMountSpec *spec);
-/* For debugging */
char * g_mount_spec_to_string (GMountSpec *spec);
+GMountSpec *g_mount_spec_new_from_string (const gchar *str,
+ GError **error);
+
char * g_mount_spec_canonicalize_path (const char *path);
+
+#define G_TYPE_MOUNT_SPEC (g_type_mount_spec_get_gtype ())
+GType g_type_mount_spec_get_gtype (void) G_GNUC_CONST;
+
G_END_DECLS
diff --git a/common/gvfsdaemonprotocol.h b/common/gvfsdaemonprotocol.h
index 7061d97c..38f7d0d3 100644
--- a/common/gvfsdaemonprotocol.h
+++ b/common/gvfsdaemonprotocol.h
@@ -49,6 +49,7 @@ G_BEGIN_DECLS
#define G_VFS_DBUS_MOUNT_OP_SET_ATTRIBUTE "SetAttribute"
#define G_VFS_DBUS_MOUNT_OP_QUERY_SETTABLE_ATTRIBUTES "QuerySettableAttributes"
#define G_VFS_DBUS_MOUNT_OP_QUERY_WRITABLE_NAMESPACES "QueryWritableNamespaces"
+#define G_VFS_DBUS_MOUNT_OP_OPEN_ICON_FOR_READ "OpenIconForRead"
/* Progress callback interface for copy and move */
#define G_VFS_DBUS_PROGRESS_INTERFACE "org.gtk.vfs.Progress"
diff --git a/common/gvfsicon.c b/common/gvfsicon.c
new file mode 100644
index 00000000..29dacbd8
--- /dev/null
+++ b/common/gvfsicon.c
@@ -0,0 +1,282 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2008 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 "gvfsicon.h"
+
+static void g_vfs_icon_icon_iface_init (GIconIface *iface);
+
+/* Because of the way dependencies are currently set up, the
+ * GLoadableIcon interface is in client/gvfsiconloadable.c and is
+ * added in g_io_module_load() in client/gdaemonvfs.c.
+ */
+
+enum
+{
+ PROP_0,
+ PROP_MOUNT_SPEC,
+ PROP_ICON_ID
+};
+
+G_DEFINE_TYPE_EXTENDED (GVfsIcon,
+ g_vfs_icon,
+ G_TYPE_OBJECT,
+ 0,
+ G_IMPLEMENT_INTERFACE (G_TYPE_ICON,
+ g_vfs_icon_icon_iface_init))
+
+static void
+g_vfs_icon_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GVfsIcon *icon = G_VFS_ICON (object);
+
+ switch (prop_id)
+ {
+ case PROP_MOUNT_SPEC:
+ g_value_set_boxed (value, icon->mount_spec);
+ break;
+
+ case PROP_ICON_ID:
+ g_value_set_string (value, icon->icon_id);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+g_vfs_icon_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GVfsIcon *icon = G_VFS_ICON (object);
+
+ switch (prop_id)
+ {
+ case PROP_MOUNT_SPEC:
+ icon->mount_spec = g_mount_spec_ref (g_value_get_boxed (value));
+ break;
+
+ case PROP_ICON_ID:
+ icon->icon_id = g_strdup (g_value_get_string (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+g_vfs_icon_finalize (GObject *object)
+{
+ GVfsIcon *vfs_icon;
+
+ vfs_icon = G_VFS_ICON (object);
+
+ if (vfs_icon->mount_spec != NULL)
+ g_mount_spec_unref (vfs_icon->mount_spec);
+ g_free (vfs_icon->icon_id);
+
+ G_OBJECT_CLASS (g_vfs_icon_parent_class)->finalize (object);
+}
+
+static void
+g_vfs_icon_class_init (GVfsIconClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->get_property = g_vfs_icon_get_property;
+ gobject_class->set_property = g_vfs_icon_set_property;
+ gobject_class->finalize = g_vfs_icon_finalize;
+
+ /**
+ * GVfsIcon:mount-spec:
+ *
+ * The mount spec.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_MOUNT_SPEC,
+ g_param_spec_boxed ("mount-spec",
+ "Mount Spec",
+ "Mount Spec",
+ G_TYPE_MOUNT_SPEC,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_BLURB |
+ G_PARAM_STATIC_NICK));
+
+ /**
+ * GVfsIcon:icon-id:
+ *
+ * The id of the icon.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_ICON_ID,
+ g_param_spec_string ("icon-id",
+ "Icon identifier",
+ "Icon identifier",
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_BLURB |
+ G_PARAM_STATIC_NICK));
+}
+
+static void
+g_vfs_icon_init (GVfsIcon *file)
+{
+}
+
+GMountSpec *
+g_vfs_icon_get_mount_spec (GVfsIcon *vfs_icon)
+{
+ g_return_val_if_fail (G_VFS_IS_ICON (vfs_icon), NULL);
+ return g_mount_spec_ref (vfs_icon->mount_spec);
+}
+
+const gchar *
+g_vfs_icon_get_icon_id (GVfsIcon *vfs_icon)
+{
+ g_return_val_if_fail (G_VFS_IS_ICON (vfs_icon), NULL);
+ return vfs_icon->icon_id;
+}
+
+
+GIcon *
+g_vfs_icon_new (GMountSpec *mount_spec,
+ const gchar *icon_id)
+{
+ return G_ICON (g_object_new (G_VFS_TYPE_ICON,
+ "mount-spec", mount_spec,
+ "icon-id", icon_id,
+ NULL));
+}
+
+static guint
+g_vfs_icon_hash (GIcon *icon)
+{
+ GVfsIcon *vfs_icon = G_VFS_ICON (icon);
+
+ return g_mount_spec_hash (vfs_icon->mount_spec) ^ g_str_hash (vfs_icon->icon_id);
+}
+
+static int
+safe_strcmp (const char *a,
+ const char *b)
+{
+ if (a == NULL)
+ a = "";
+ if (b == NULL)
+ b = "";
+
+ return strcmp (a, b);
+}
+
+static gboolean
+g_vfs_icon_equal (GIcon *icon1,
+ GIcon *icon2)
+{
+ GVfsIcon *vfs1 = G_VFS_ICON (icon1);
+ GVfsIcon *vfs2 = G_VFS_ICON (icon2);
+
+ return g_mount_spec_equal (vfs1->mount_spec, vfs2->mount_spec) &&
+ (safe_strcmp (vfs1->icon_id, vfs2->icon_id) == 0);
+}
+
+static gboolean
+g_vfs_icon_to_tokens (GIcon *icon,
+ GPtrArray *tokens,
+ gint *out_version)
+{
+ GVfsIcon *vfs_icon = G_VFS_ICON (icon);
+ char *s;
+
+ g_return_val_if_fail (out_version != NULL, FALSE);
+
+ *out_version = 0;
+
+ s = g_mount_spec_to_string (vfs_icon->mount_spec);
+ g_ptr_array_add (tokens, s);
+ g_ptr_array_add (tokens, vfs_icon->icon_id);
+
+ return TRUE;
+}
+
+static GIcon *
+g_vfs_icon_from_tokens (gchar **tokens,
+ gint num_tokens,
+ gint version,
+ GError **error)
+{
+ GMountSpec *mount_spec;
+ GIcon *icon;
+
+ icon = NULL;
+
+ if (version != 0)
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("Can't handle version %d of GVfsIcon encoding"),
+ version);
+ goto out;
+ }
+
+ if (num_tokens != 2)
+ {
+ g_set_error_literal (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("Malformed input data for GVfsIcon"));
+ goto out;
+ }
+
+ mount_spec = g_mount_spec_new_from_string (tokens[0], error);
+ if (mount_spec == NULL)
+ goto out;
+
+ icon = g_vfs_icon_new (mount_spec, tokens[1]);
+ g_mount_spec_unref (mount_spec);
+
+ out:
+ return icon;
+}
+
+static void
+g_vfs_icon_icon_iface_init (GIconIface *iface)
+{
+ iface->hash = g_vfs_icon_hash;
+ iface->equal = g_vfs_icon_equal;
+ iface->to_tokens = g_vfs_icon_to_tokens;
+ iface->from_tokens = g_vfs_icon_from_tokens;
+}
diff --git a/common/gvfsicon.h b/common/gvfsicon.h
new file mode 100644
index 00000000..b32c2ba4
--- /dev/null
+++ b/common/gvfsicon.h
@@ -0,0 +1,69 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2008 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_ICON_H__
+#define __G_VFS_ICON_H__
+
+#include <gio/gio.h>
+#include <gmountspec.h>
+
+G_BEGIN_DECLS
+
+#define G_VFS_TYPE_ICON (g_vfs_icon_get_type ())
+#define G_VFS_ICON(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_VFS_TYPE_ICON, GVfsIcon))
+#define G_VFS_ICON_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_VFS_TYPE_ICON, GVfsIconClass))
+#define G_VFS_IS_ICON(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_VFS_TYPE_ICON))
+#define G_VFS_IS_ICON_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_VFS_TYPE_ICON))
+#define G_VFS_ICON_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_VFS_TYPE_ICON, GVfsIconClass))
+
+/**
+ * GVfsIcon:
+ *
+ * An object for referencing icons originating from a #GVfsBackend
+ */
+typedef struct _GVfsIcon GVfsIcon;
+typedef struct _GVfsIconClass GVfsIconClass;
+
+struct _GVfsIcon
+{
+ GObject parent_instance;
+
+ GMountSpec *mount_spec;
+ char *icon_id;
+};
+
+struct _GVfsIconClass
+{
+ GObjectClass parent_class;
+};
+
+GType g_vfs_icon_get_type (void) G_GNUC_CONST;
+
+GIcon *g_vfs_icon_new (GMountSpec *mount_spec,
+ const gchar *icon_id);
+
+GMountSpec *g_vfs_icon_get_mount_spec (GVfsIcon *vfs_icon);
+const gchar *g_vfs_icon_get_icon_id (GVfsIcon *vfs_icon);
+
+G_END_DECLS
+
+#endif /* __G_VFS_ICON_H__ */
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 57e03080..653018b8 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -120,6 +120,7 @@ libdaemon_la_SOURCES = \
gvfsjobmountmountable.c gvfsjobmountmountable.h \
gvfsjobunmountmountable.c gvfsjobunmountmountable.h \
gvfsjobopenforread.c gvfsjobopenforread.h \
+ gvfsjobopeniconforread.c gvfsjobopeniconforread.h \
gvfsjobread.c gvfsjobread.h \
gvfsjobseekread.c gvfsjobseekread.h \
gvfsjobcloseread.c gvfsjobcloseread.h \
diff --git a/daemon/gvfsbackend.c b/daemon/gvfsbackend.c
index 4e6e9a53..c0eba0e1 100644
--- a/daemon/gvfsbackend.c
+++ b/daemon/gvfsbackend.c
@@ -35,6 +35,7 @@
#include "gvfsjobsource.h"
#include "gvfsdaemonprotocol.h"
#include <gvfsjobopenforread.h>
+#include <gvfsjobopeniconforread.h>
#include <gvfsjobopenforwrite.h>
#include <gvfsjobqueryinfo.h>
#include <gvfsjobqueryfsinfo.h>
@@ -482,6 +483,10 @@ backend_dbus_handler (DBusConnection *connection,
G_VFS_DBUS_MOUNT_OP_OPEN_FOR_READ))
job = g_vfs_job_open_for_read_new (connection, message, backend);
else if (dbus_message_is_method_call (message,
+ G_VFS_DBUS_MOUNT_INTERFACE,
+ G_VFS_DBUS_MOUNT_OP_OPEN_ICON_FOR_READ))
+ job = g_vfs_job_open_icon_for_read_new (connection, message, backend);
+ else if (dbus_message_is_method_call (message,
G_VFS_DBUS_MOUNT_INTERFACE,
G_VFS_DBUS_MOUNT_OP_QUERY_INFO))
job = g_vfs_job_query_info_new (connection, message, backend);
diff --git a/daemon/gvfsbackend.h b/daemon/gvfsbackend.h
index e47f3680..4dcf7409 100644
--- a/daemon/gvfsbackend.h
+++ b/daemon/gvfsbackend.h
@@ -48,6 +48,7 @@ typedef struct _GVfsJobUnmount GVfsJobUnmount;
typedef struct _GVfsJobMountMountable GVfsJobMountMountable;
typedef struct _GVfsJobUnmountMountable GVfsJobUnmountMountable;
typedef struct _GVfsJobOpenForRead GVfsJobOpenForRead;
+typedef struct _GVfsJobOpenIconForRead GVfsJobOpenIconForRead;
typedef struct _GVfsJobSeekRead GVfsJobSeekRead;
typedef struct _GVfsJobCloseRead GVfsJobCloseRead;
typedef struct _GVfsJobRead GVfsJobRead;
@@ -138,6 +139,12 @@ struct _GVfsBackendClass
gboolean (*try_open_for_read) (GVfsBackend *backend,
GVfsJobOpenForRead *job,
const char *filename);
+ void (*open_icon_for_read) (GVfsBackend *backend,
+ GVfsJobOpenIconForRead *job,
+ const char *icon_id);
+ gboolean (*try_open_icon_for_read) (GVfsBackend *backend,
+ GVfsJobOpenIconForRead *job,
+ const char *icon_id);
void (*close_read) (GVfsBackend *backend,
GVfsJobCloseRead *job,
GVfsBackendHandle handle);
diff --git a/daemon/gvfsbackendgphoto2.c b/daemon/gvfsbackendgphoto2.c
index 259ad920..d21d49dc 100644
--- a/daemon/gvfsbackendgphoto2.c
+++ b/daemon/gvfsbackendgphoto2.c
@@ -41,6 +41,7 @@
#include "gvfsbackendgphoto2.h"
#include "gvfsjobopenforread.h"
+#include "gvfsjobopeniconforread.h"
#include "gvfsjobread.h"
#include "gvfsjobseekread.h"
#include "gvfsjobqueryinfo.h"
@@ -52,6 +53,7 @@
#include "gvfsjobcreatemonitor.h"
#include "gvfsmonitor.h"
#include "gvfsjobseekwrite.h"
+#include "gvfsicon.h"
/* showing debug traces */
#if 0
@@ -1132,6 +1134,25 @@ file_get_info (GVfsBackendGphoto2 *gphoto2_backend,
mime_type = g_strdup ("application/octet-stream");
g_file_info_set_content_type (info, mime_type);
+ /* assume that all JPG files, and only all JPG files, has a preview file */
+ if (strcmp (mime_type, "image/jpg") == 0 ||
+ strcmp (mime_type, "image/jpeg") == 0)
+ {
+ char *icon_id;
+ GIcon *icon;
+ GMountSpec *mount_spec;
+
+ mount_spec = g_vfs_backend_get_mount_spec (G_VFS_BACKEND (gphoto2_backend));
+ icon_id = g_strdup_printf ("preview:%s/%s", dir + strlen (gphoto2_backend->ignore_prefix), name);
+ icon = g_vfs_icon_new (mount_spec,
+ icon_id);
+ g_file_info_set_attribute_object (info,
+ G_FILE_ATTRIBUTE_PREVIEW_ICON,
+ G_OBJECT (icon));
+ g_object_unref (icon);
+ g_free (icon_id);
+ }
+
icon = g_content_type_get_icon (mime_type);
DEBUG (" got icon %p for mime_type '%s'", icon, mime_type);
if (icon != NULL)
@@ -1141,7 +1162,6 @@ file_get_info (GVfsBackendGphoto2 *gphoto2_backend,
}
g_free (mime_type);
-
if (gp_info.file.fields & GP_FILE_INFO_MTIME)
mtime.tv_sec = gp_info.file.mtime;
else
@@ -1677,9 +1697,10 @@ free_read_handle (ReadHandle *read_handle)
}
static void
-do_open_for_read (GVfsBackend *backend,
- GVfsJobOpenForRead *job,
- const char *filename)
+do_open_for_read_real (GVfsBackend *backend,
+ GVfsJobOpenForRead *job,
+ const char *filename,
+ gboolean get_preview)
{
int rc;
GError *error;
@@ -1688,8 +1709,6 @@ do_open_for_read (GVfsBackend *backend,
char *dir;
char *name;
- DEBUG ("open_for_read (%s)", filename);
-
ensure_not_dirty (gphoto2_backend);
split_filename_with_ignore_prefix (gphoto2_backend, filename, &dir, &name);
@@ -1724,7 +1743,7 @@ do_open_for_read (GVfsBackend *backend,
rc = gp_camera_file_get (gphoto2_backend->camera,
dir,
name,
- GP_FILE_TYPE_NORMAL,
+ get_preview ? GP_FILE_TYPE_PREVIEW : GP_FILE_TYPE_NORMAL,
read_handle->file,
gphoto2_backend->context);
if (rc != 0)
@@ -1763,6 +1782,44 @@ do_open_for_read (GVfsBackend *backend,
g_free (dir);
}
+
+static void
+do_open_for_read (GVfsBackend *backend,
+ GVfsJobOpenForRead *job,
+ const char *filename)
+{
+ DEBUG ("open_for_read (%s)", filename);
+
+ do_open_for_read_real (backend,
+ job,
+ filename,
+ FALSE);
+}
+
+static void
+do_open_icon_for_read (GVfsBackend *backend,
+ GVfsJobOpenIconForRead *job,
+ const char *icon_id)
+{
+ DEBUG ("open_icon_for_read (%s)", icon_id);
+
+ if (g_str_has_prefix (icon_id, "preview:"))
+ {
+ do_open_for_read_real (backend,
+ G_VFS_JOB_OPEN_FOR_READ (job),
+ icon_id + sizeof ("preview:") - 1,
+ TRUE);
+ }
+ else
+ {
+ g_vfs_job_failed (G_VFS_JOB (job),
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("Malformed icon identifier '%s'"),
+ icon_id);
+ }
+}
+
/* ------------------------------------------------------------------------------------------------- */
static gboolean
@@ -3373,6 +3430,7 @@ g_vfs_backend_gphoto2_class_init (GVfsBackendGphoto2Class *klass)
backend_class->try_mount = try_mount;
backend_class->mount = do_mount;
backend_class->unmount = do_unmount;
+ backend_class->open_icon_for_read = do_open_icon_for_read;
backend_class->open_for_read = do_open_for_read;
backend_class->try_read = try_read;
backend_class->try_seek_on_read = try_seek_on_read;
diff --git a/daemon/gvfsjobopeniconforread.c b/daemon/gvfsjobopeniconforread.c
new file mode 100644
index 00000000..87936765
--- /dev/null
+++ b/daemon/gvfsjobopeniconforread.c
@@ -0,0 +1,142 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2006-2007 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: Alexander Larsson <alexl@redhat.com>
+ */
+
+#include <config.h>
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <glib/gi18n.h>
+#include "gvfsreadchannel.h"
+#include "gvfsjobopeniconforread.h"
+#include "gdbusutils.h"
+#include "gvfsdaemonutils.h"
+
+G_DEFINE_TYPE (GVfsJobOpenIconForRead, g_vfs_job_open_icon_for_read, G_VFS_TYPE_JOB_OPEN_FOR_READ)
+
+static void run (GVfsJob *job);
+static gboolean try (GVfsJob *job);
+
+static void
+g_vfs_job_open_icon_for_read_finalize (GObject *object)
+{
+ GVfsJobOpenIconForRead *job;
+
+ job = G_VFS_JOB_OPEN_ICON_FOR_READ (object);
+
+ if (G_OBJECT_CLASS (g_vfs_job_open_icon_for_read_parent_class)->finalize)
+ (*G_OBJECT_CLASS (g_vfs_job_open_icon_for_read_parent_class)->finalize) (object);
+}
+
+static void
+g_vfs_job_open_icon_for_read_class_init (GVfsJobOpenIconForReadClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GVfsJobClass *job_class = G_VFS_JOB_CLASS (klass);
+
+ gobject_class->finalize = g_vfs_job_open_icon_for_read_finalize;
+ job_class->run = run;
+ job_class->try = try;
+}
+
+static void
+g_vfs_job_open_icon_for_read_init (GVfsJobOpenIconForRead *job)
+{
+}
+
+GVfsJob *
+g_vfs_job_open_icon_for_read_new (DBusConnection *connection,
+ DBusMessage *message,
+ GVfsBackend *backend)
+{
+ GVfsJobOpenIconForRead *job;
+ GVfsJobOpenForRead *job_open_for_read;
+ DBusMessage *reply;
+ DBusError derror;
+ int path_len;
+ const char *path_data;
+
+ dbus_error_init (&derror);
+ if (!dbus_message_get_args (message, &derror,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
+ &path_data, &path_len,
+ 0))
+ {
+ reply = dbus_message_new_error (message,
+ derror.name,
+ derror.message);
+ dbus_error_free (&derror);
+
+ dbus_connection_send (connection, reply, NULL);
+ return NULL;
+ }
+
+ job = g_object_new (G_VFS_TYPE_JOB_OPEN_ICON_FOR_READ,
+ "message", message,
+ "connection", connection,
+ NULL);
+
+ job_open_for_read = G_VFS_JOB_OPEN_FOR_READ (job);
+
+ job->icon_id = g_strndup (path_data, path_len);
+ job_open_for_read->backend = backend;
+
+ return G_VFS_JOB (job);
+}
+
+static void
+run (GVfsJob *job)
+{
+ GVfsJobOpenIconForRead *op_job = G_VFS_JOB_OPEN_ICON_FOR_READ (job);
+ GVfsJobOpenForRead *op_job_open_for_read = G_VFS_JOB_OPEN_FOR_READ (job);
+ GVfsBackendClass *class = G_VFS_BACKEND_GET_CLASS (op_job_open_for_read->backend);
+
+ if (class->open_icon_for_read == NULL)
+ {
+ g_vfs_job_failed (job, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported by backend"));
+ return;
+ }
+
+ class->open_icon_for_read (op_job_open_for_read->backend,
+ op_job,
+ op_job->icon_id);
+}
+
+static gboolean
+try (GVfsJob *job)
+{
+ GVfsJobOpenIconForRead *op_job = G_VFS_JOB_OPEN_ICON_FOR_READ (job);
+ GVfsJobOpenForRead *op_job_open_for_read = G_VFS_JOB_OPEN_FOR_READ (job);
+ GVfsBackendClass *class = G_VFS_BACKEND_GET_CLASS (op_job_open_for_read->backend);
+
+ if (class->try_open_icon_for_read == NULL)
+ return FALSE;
+
+ return class->try_open_icon_for_read (op_job_open_for_read->backend,
+ op_job,
+ op_job->icon_id);
+}
diff --git a/daemon/gvfsjobopeniconforread.h b/daemon/gvfsjobopeniconforread.h
new file mode 100644
index 00000000..c4ed80e7
--- /dev/null
+++ b/daemon/gvfsjobopeniconforread.h
@@ -0,0 +1,63 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2006-2007 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: Alexander Larsson <alexl@redhat.com>
+ */
+
+#ifndef __G_VFS_JOB_OPEN_ICON_FOR_READ_H__
+#define __G_VFS_JOB_OPEN_ICON_FOR_READ_H__
+
+#include <dbus/dbus.h>
+#include <gvfsjobdbus.h>
+#include <gvfsbackend.h>
+#include <gvfsreadchannel.h>
+#include <gvfsjobopenforread.h>
+
+G_BEGIN_DECLS
+
+#define G_VFS_TYPE_JOB_OPEN_ICON_FOR_READ (g_vfs_job_open_icon_for_read_get_type ())
+#define G_VFS_JOB_OPEN_ICON_FOR_READ(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_VFS_TYPE_JOB_OPEN_ICON_FOR_READ, GVfsJobOpenIconForRead))
+#define G_VFS_JOB_OPEN_ICON_FOR_READ_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_VFS_TYPE_JOB_OPEN_ICON_FOR_READ, GVfsJobOpenIconForReadClass))
+#define G_VFS_IS_JOB_OPEN_ICON_FOR_READ(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_VFS_TYPE_JOB_OPEN_ICON_FOR_READ))
+#define G_VFS_IS_JOB_OPEN_ICON_FOR_READ_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_VFS_TYPE_JOB_OPEN_ICON_FOR_READ))
+#define G_VFS_JOB_OPEN_ICON_FOR_READ_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_VFS_TYPE_JOB_OPEN_ICON_FOR_READ, GVfsJobOpenIconForReadClass))
+
+typedef struct _GVfsJobOpenIconForReadClass GVfsJobOpenIconForReadClass;
+
+struct _GVfsJobOpenIconForRead
+{
+ GVfsJobOpenForRead parent_instance;
+
+ char *icon_id;
+};
+
+struct _GVfsJobOpenIconForReadClass
+{
+ GVfsJobOpenForReadClass parent_class;
+};
+
+GType g_vfs_job_open_icon_for_read_get_type (void) G_GNUC_CONST;
+
+GVfsJob * g_vfs_job_open_icon_for_read_new (DBusConnection *connection,
+ DBusMessage *message,
+ GVfsBackend *backend);
+
+G_END_DECLS
+
+#endif /* __G_VFS_JOB_OPEN_ICON_FOR_READ_H__ */