diff options
author | Alexander Larsson <alexl@redhat.com> | 2008-10-21 12:58:45 +0000 |
---|---|---|
committer | Alexander Larsson <alexl@src.gnome.org> | 2008-10-21 12:58:45 +0000 |
commit | d73422735a1d60d1b014cf40b273e7391389e678 (patch) | |
tree | 63c01910d1ef0d30b1084209c90e21144ee4710b /client/gvfsiconloadable.c | |
parent | 1078f20f47debb00d0a0f6966b6680ad0473e32f (diff) | |
download | gvfs-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
Diffstat (limited to 'client/gvfsiconloadable.c')
-rw-r--r-- | client/gvfsiconloadable.c | 431 |
1 files changed, 431 insertions, 0 deletions
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); +} |