Author: jannis Date: 2009-06-19 15:34:11 +0000 (Fri, 19 Jun 2009) New Revision: 30048
Added: thunar/branches/migration-to-gio/thunar/thunar-browser.c thunar/branches/migration-to-gio/thunar/thunar-browser.h Modified: thunar/branches/migration-to-gio/ChangeLog Log: * thunar/thunar-browser.{c,h}: Add a new interface with two convenience functions for browsing (possibly not yet mounted or resolved) volumes and files. thunar_browser_poke_file() can be used to asynchronously resolve shortcuts, mount mountables or enclosing volumes. When finished, the ThunarBrowserPokeFileFunc callback is called with the source and target file. thunar_browser_poke_volume() mounts volumes on demand and resolves the mount point and passes it to the ThunarBrowsePokeVolumeFunc callback. Both functions are possibly asynchronous. Modified: thunar/branches/migration-to-gio/ChangeLog =================================================================== --- thunar/branches/migration-to-gio/ChangeLog 2009-06-19 15:34:06 UTC (rev 30047) +++ thunar/branches/migration-to-gio/ChangeLog 2009-06-19 15:34:11 UTC (rev 30048) @@ -1,5 +1,17 @@ 2009-06-19 Jannis Pohlmann <jan...@xfce.org> + * thunar/thunar-browser.{c,h}: Add a new interface with two + convenience functions for browsing (possibly not yet mounted or + resolved) volumes and files. thunar_browser_poke_file() can be used + to asynchronously resolve shortcuts, mount mountables or enclosing + volumes. When finished, the ThunarBrowserPokeFileFunc callback is + called with the source and target file. thunar_browser_poke_volume() + mounts volumes on demand and resolves the mount point and passes it + to the ThunarBrowsePokeVolumeFunc callback. Both functions are + possibly asynchronous. + +2009-06-19 Jannis Pohlmann <jan...@xfce.org> + * thunar/thunar-file.{c,h}: Add "mountable::*" namespace to the file info attributes we request from the GFileInfo. In thunar_file_load(), check for type G_FILE_TYPE_MOUNTABLE and set Added: thunar/branches/migration-to-gio/thunar/thunar-browser.c =================================================================== --- thunar/branches/migration-to-gio/thunar/thunar-browser.c (rev 0) +++ thunar/branches/migration-to-gio/thunar/thunar-browser.c 2009-06-19 15:34:11 UTC (rev 30048) @@ -0,0 +1,549 @@ +/* vi:set et ai sw=2 sts=2 ts=2: */ +/*- + * Copyright (c) 2009 Jannis Pohlmann <jan...@xfce.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <glib-object.h> + +#include <thunar/thunar-browser.h> +#include <thunar/thunar-file.h> +#include <thunar/thunar-private.h> +#include <thunar/thunar-util.h> + + + +typedef struct _PokeFileData PokeFileData; +typedef struct _PokeVolumeData PokeVolumeData; + +struct _PokeFileData +{ + ThunarBrowser *browser; + ThunarFile *source; + ThunarFile *file; + ThunarBrowserPokeFileFunc func; + gpointer user_data; +}; + +struct _PokeVolumeData +{ + ThunarBrowser *browser; + GVolume *volume; + ThunarFile *mount_point; + ThunarBrowserPokeVolumeFunc func; + gpointer user_data; +}; + + + +GType +thunar_browser_get_type (void) +{ + static GType type = G_TYPE_INVALID; + + if (G_UNLIKELY (type == G_TYPE_INVALID)) + { + type = g_type_register_static_simple (G_TYPE_INTERFACE, + "ThunarBrowser", + sizeof (ThunarBrowserIface), + NULL, + 0, + NULL, + 0); + + g_type_interface_add_prerequisite (type, G_TYPE_OBJECT); + } + + return type; +} + + + +static PokeFileData * +thunar_browser_poke_file_data_new (ThunarBrowser *browser, + ThunarFile *source, + ThunarFile *file, + ThunarBrowserPokeFileFunc func, + gpointer user_data) +{ + PokeFileData *poke_data; + + _thunar_return_val_if_fail (THUNAR_IS_BROWSER (browser), NULL); + _thunar_return_val_if_fail (THUNAR_IS_FILE (source), NULL); + _thunar_return_val_if_fail (THUNAR_IS_FILE (file), NULL); + + poke_data = _thunar_slice_new0 (PokeFileData); + poke_data->browser = g_object_ref (browser); + poke_data->source = g_object_ref (source); + poke_data->file = g_object_ref (file); + poke_data->func = func; + poke_data->user_data = user_data; + + return poke_data; +} + + + +static void +thunar_browser_poke_file_data_free (PokeFileData *poke_data) +{ + _thunar_return_if_fail (poke_data != NULL); + _thunar_return_if_fail (THUNAR_IS_BROWSER (poke_data->browser)); + _thunar_return_if_fail (THUNAR_IS_FILE (poke_data->source)); + _thunar_return_if_fail (THUNAR_IS_FILE (poke_data->file)); + + g_object_unref (poke_data->browser); + g_object_unref (poke_data->source); + g_object_unref (poke_data->file); + + _thunar_slice_free (PokeFileData, poke_data); +} + + + +static PokeVolumeData * +thunar_browser_poke_volume_data_new (ThunarBrowser *browser, + GVolume *volume, + ThunarBrowserPokeVolumeFunc func, + gpointer user_data) +{ + PokeVolumeData *poke_data; + + _thunar_return_val_if_fail (THUNAR_IS_BROWSER (browser), NULL); + _thunar_return_val_if_fail (G_IS_VOLUME (volume), NULL); + + poke_data = _thunar_slice_new0 (PokeVolumeData); + poke_data->browser = g_object_ref (browser); + poke_data->volume = g_object_ref (volume); + poke_data->func = func; + poke_data->user_data = user_data; + + return poke_data; +} + + + +static void +thunar_browser_poke_volume_data_free (PokeVolumeData *poke_data) +{ + _thunar_return_if_fail (poke_data != NULL); + _thunar_return_if_fail (THUNAR_IS_BROWSER (poke_data->browser)); + _thunar_return_if_fail (G_IS_VOLUME (poke_data->volume)); + + g_object_unref (poke_data->browser); + g_object_unref (poke_data->volume); + + _thunar_slice_free (PokeVolumeData, poke_data); +} + + + +static GMountOperation * +thunar_browser_mount_operation_new (gpointer parent) +{ + GMountOperation *mount_operation; + GtkWindow *window = NULL; + GdkScreen *screen = NULL; + + mount_operation = gtk_mount_operation_new (NULL); + + screen = thunar_util_parse_parent (parent, &window); + gtk_mount_operation_set_screen (GTK_MOUNT_OPERATION (mount_operation), screen); + gtk_mount_operation_set_parent (GTK_MOUNT_OPERATION (mount_operation), window); + + return mount_operation; +} + + + +static void +thunar_browser_poke_mountable_finish (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + PokeFileData *poke_data = user_data; + ThunarFile *target = NULL; + GError *error = NULL; + GFile *location; + + _thunar_return_if_fail (G_IS_FILE (object)); + _thunar_return_if_fail (G_IS_ASYNC_RESULT (result)); + _thunar_return_if_fail (user_data != NULL); + _thunar_return_if_fail (THUNAR_IS_BROWSER (poke_data->browser)); + _thunar_return_if_fail (THUNAR_IS_FILE (poke_data->file)); + + g_debug (" poke mountable finish"); + + if (!g_file_mount_mountable_finish (G_FILE (object), result, &error)) + { + if (error->domain == G_IO_ERROR) + { + if (error->code == G_IO_ERROR_ALREADY_MOUNTED) + g_clear_error (&error); + } + } + + if (error == NULL) + { + thunar_file_reload (poke_data->file); + + location = thunar_file_get_target_location (poke_data->file); + target = thunar_file_get (location, &error); + g_object_unref (location); + } + + if (poke_data->func != NULL) + { + (poke_data->func) (poke_data->browser, poke_data->source, target, error, + poke_data->user_data); + } + + g_clear_error (&error); + + if (target != NULL) + g_object_unref (target); + + thunar_browser_poke_file_data_free (poke_data); +} + + + +static void +thunar_browser_poke_file_finish (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + PokeFileData *poke_data = user_data; + GError *error = NULL; + + _thunar_return_if_fail (G_IS_FILE (object)); + _thunar_return_if_fail (G_IS_ASYNC_RESULT (result)); + _thunar_return_if_fail (user_data != NULL); + _thunar_return_if_fail (THUNAR_IS_BROWSER (poke_data->browser)); + _thunar_return_if_fail (THUNAR_IS_FILE (poke_data->file)); + + g_debug (" poke file finish"); + + if (!g_file_mount_enclosing_volume_finish (G_FILE (object), result, &error)) + { + if (error->domain == G_IO_ERROR) + { + if (error->code == G_IO_ERROR_ALREADY_MOUNTED) + g_clear_error (&error); + } + } + + if (error == NULL) + thunar_file_reload (poke_data->file); + + g_debug (" %s type %d", thunar_file_dup_uri (poke_data->file), + thunar_file_get_kind (poke_data->file)); + + if (poke_data->func != NULL) + { + if (error == NULL) + { + (poke_data->func) (poke_data->browser, poke_data->source, poke_data->file, + NULL, poke_data->user_data); + } + else + { + (poke_data->func) (poke_data->browser, poke_data->source, NULL, error, + poke_data->user_data); + } + } + + g_clear_error (&error); + + thunar_browser_poke_file_data_free (poke_data); +} + + + +static void +thunar_browser_poke_file_internal (ThunarBrowser *browser, + ThunarFile *source, + ThunarFile *file, + gpointer widget, + ThunarBrowserPokeFileFunc func, + gpointer user_data) +{ + GMountOperation *mount_operation; + ThunarFile *target; + PokeFileData *poke_data; + GError *error = NULL; + GFile *location; + + _thunar_return_if_fail (THUNAR_IS_BROWSER (browser)); + _thunar_return_if_fail (THUNAR_IS_FILE (source)); + _thunar_return_if_fail (THUNAR_IS_FILE (file)); + + g_debug ("poke %s", thunar_file_dup_uri (file)); + + if (thunar_file_get_kind (file) == G_FILE_TYPE_SHORTCUT) + { + location = thunar_file_get_target_location (file); + target = thunar_file_get (location, &error); + g_debug (" shortcut, target %s (%p)", g_file_get_uri (location), target); + g_object_unref (location); + + if (target != NULL) + { + /* TODO in very rare occasions (shortcut X -> other shortcut -> shortcut X), + * this can lead to endless recursion */ + thunar_browser_poke_file_internal (browser, source, target, widget, + func, user_data); + } + else + { + if (func != NULL) + func (browser, source, NULL, error, user_data); + } + + g_clear_error (&error); + + if (target != NULL) + g_object_unref (target); + } + else if (thunar_file_get_kind (file) == G_FILE_TYPE_MOUNTABLE) + { + if (thunar_file_is_mounted (file)) + { + g_debug (" mountable, already mounted"); + + location = thunar_file_get_target_location (file); + target = thunar_file_get (location, &error); + g_object_unref (location); + + if (func != NULL) + func (browser, source, target, error, user_data); + + g_clear_error (&error); + + if (target != NULL) + g_object_unref (target); + } + else + { + g_debug (" mountable, needs mounting"); + + poke_data = thunar_browser_poke_file_data_new (browser, source, file, + func, user_data); + + mount_operation = thunar_browser_mount_operation_new (widget); + + g_file_mount_mountable (thunar_file_get_file (file), + G_MOUNT_MOUNT_NONE, mount_operation, NULL, + thunar_browser_poke_mountable_finish, + poke_data); + + g_object_unref (mount_operation); + } + } + else if (!thunar_file_is_mounted (file)) + { + g_debug (" file, enclosing volume needs mounting"); + + poke_data = thunar_browser_poke_file_data_new (browser, source, file, + func, user_data); + + mount_operation = thunar_browser_mount_operation_new (widget); + + g_file_mount_enclosing_volume (thunar_file_get_file (file), + G_MOUNT_MOUNT_NONE, mount_operation, NULL, + thunar_browser_poke_file_finish, + poke_data); + + g_object_unref (mount_operation); + } + else + { + g_debug (" file, enclosing volume already mounted"); + + if (func != NULL) + func (browser, source, file, NULL, user_data); + } +} + + + +/** + * thunar_browser_poke_file: + * @browser : a #ThunarBrowser. + * @file : a #ThunarFile. + * @widget : a #GtkWidget, a #GdkScreen or %NULL. + * @func : a #ThunarBrowserPokeFileFunc callback or %NULL. + * @user_data : pointer to arbitrary user data or %NULL. + * + * Pokes a #ThunarFile to see what's behind it. + * + * If @file has the type %G_FILE_TYPE_SHORTCUT, it tries to load and mount + * the file that is referred to by the %G_FILE_ATTRIBUTE_STANDARD_TARGET_URI + * of the @file. + * + * If @file has the type %G_FILE_TYPE_MOUNTABLE, it tries to mount the @file. + * + * In the other cases, if the enclosing volume of the @file is not mounted + * yet, it tries to mount it. + * + * When finished or if an error occured, it calls @func with the provided + * @user data. The #GError parameter to @func is set if, and only if there + * was an error. + **/ +void +thunar_browser_poke_file (ThunarBrowser *browser, + ThunarFile *file, + gpointer widget, + ThunarBrowserPokeFileFunc func, + gpointer user_data) +{ + _thunar_return_if_fail (THUNAR_IS_BROWSER (browser)); + _thunar_return_if_fail (THUNAR_IS_FILE (file)); + + thunar_browser_poke_file_internal (browser, file, file, widget, func, user_data); +} + + + +static void +thunar_browser_poke_volume_finish (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + PokeVolumeData *poke_data = user_data; + ThunarFile *file; + GError *error = NULL; + GMount *mount; + GFile *mount_point; + + _thunar_return_if_fail (G_IS_VOLUME (object)); + _thunar_return_if_fail (G_IS_ASYNC_RESULT (result)); + _thunar_return_if_fail (user_data != NULL); + _thunar_return_if_fail (THUNAR_IS_BROWSER (poke_data->browser)); + _thunar_return_if_fail (G_IS_VOLUME (poke_data->volume)); + _thunar_return_if_fail (G_VOLUME (object) == poke_data->volume); + + if (!g_volume_mount_finish (G_VOLUME (object), result, &error)) + { + if (error->domain == G_IO_ERROR) + { + if (error->code == G_IO_ERROR_ALREADY_MOUNTED) + g_clear_error (&error); + } + } + + if (error == NULL) + { + mount = g_volume_get_mount (poke_data->volume); + mount_point = g_mount_get_root (mount); + + file = thunar_file_get (mount_point, &error); + + g_object_unref (mount_point); + g_object_unref (mount); + + if (poke_data->func != NULL) + { + (poke_data->func) (poke_data->browser, poke_data->volume, file, error, + poke_data->user_data); + } + + if (file != NULL) + g_object_unref (file); + } + else + { + if (poke_data->func != NULL) + { + (poke_data->func) (poke_data->browser, poke_data->volume, NULL, error, + poke_data->user_data); + } + } + + thunar_browser_poke_volume_data_free (poke_data); +} + + + +/** + * thunar_browser_poke_volume: + * @browser : a #ThunarBrowser. + * @volume : a #GVolume. + * @widget : a #GtkWidget, a #GdkScreen or %NULL. + * @func : a #ThunarBrowserPokeVolumeFunc callback or %NULL. + * @user_data : pointer to arbitrary user data or %NULL. + * + * This function checks if @volume is mounted or not. If it is, it loads + * a #ThunarFile for the mount root and calls @func. If it is not mounted, + * it first mounts the volume asynchronously and calls @func with the + * #ThunarFile corresponding to the mount root when the mounting is finished. + * + * The #ThunarFile passed to @func will be %NULL if, and only if mounting + * the @volume failed. The #GError passed to @func will be set if, and only if + * mounting failed. + **/ +void +thunar_browser_poke_volume (ThunarBrowser *browser, + GVolume *volume, + gpointer widget, + ThunarBrowserPokeVolumeFunc func, + gpointer user_data) +{ + GMountOperation *mount_operation; + PokeVolumeData *poke_data; + ThunarFile *file; + GError *error = NULL; + GMount *mount; + GFile *mount_point; + + _thunar_return_if_fail (THUNAR_IS_BROWSER (browser)); + _thunar_return_if_fail (G_IS_VOLUME (volume)); + + if (g_volume_is_mounted (volume)) + { + mount = g_volume_get_mount (volume); + mount_point = g_mount_get_root (mount); + + file = thunar_file_get (mount_point, &error); + + g_object_unref (mount_point); + g_object_unref (mount); + + if (func != NULL) + func (browser, volume, file, error, user_data); + + g_clear_error (&error); + + if (file != NULL) + g_object_unref (file); + } + else + { + poke_data = thunar_browser_poke_volume_data_new (browser, volume, func, user_data); + + mount_operation = thunar_browser_mount_operation_new (widget); + + g_volume_mount (volume, G_MOUNT_MOUNT_NONE, mount_operation, NULL, + thunar_browser_poke_volume_finish, poke_data); + + g_object_unref (mount_operation); + } +} Added: thunar/branches/migration-to-gio/thunar/thunar-browser.h =================================================================== --- thunar/branches/migration-to-gio/thunar/thunar-browser.h (rev 0) +++ thunar/branches/migration-to-gio/thunar/thunar-browser.h 2009-06-19 15:34:11 UTC (rev 30048) @@ -0,0 +1,72 @@ +/* vi:set et ai sw=2 sts=2 ts=2: */ +/*- + * Copyright (c) 2009 Jannis Pohlmann <jan...@xfce.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __THUNAR_BROWSER_H__ +#define __THUNAR_BROWSER_H__ + +#include <thunar/thunar-file.h> + +G_BEGIN_DECLS + +#define THUNAR_TYPE_BROWSER (thunar_browser_get_type ()) +#define THUNAR_BROWSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THUNAR_TYPE_BROWSER, ThunarBrowser)) +#define THUNAR_IS_BROWSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THUNAR_TYPE_BROWSER)) +#define THUNAR_BROWSER_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), THUNAR_TYPE_BROWSER, ThunarBrowserIface)) + +typedef struct _ThunarBrowser ThunarBrowser; +typedef struct _ThunarBrowserIface ThunarBrowserIface; + +typedef void (*ThunarBrowserPokeFileFunc) (ThunarBrowser *browser, + ThunarFile *file, + ThunarFile *target_file, + GError *error, + gpointer user_data); + +typedef void (*ThunarBrowserPokeVolumeFunc) (ThunarBrowser *browser, + GVolume *volume, + ThunarFile *mount_point, + GError *error, + gpointer user_data); + +struct _ThunarBrowserIface +{ + GTypeInterface __parent__; + + /* signals */ + + /* virtual methods */ +}; + +GType thunar_browser_get_type (void) G_GNUC_CONST; + +void thunar_browser_poke_file (ThunarBrowser *browser, + ThunarFile *file, + gpointer widget, + ThunarBrowserPokeFileFunc func, + gpointer user_data); +void thunar_browser_poke_volume (ThunarBrowser *browser, + GVolume *volume, + gpointer widget, + ThunarBrowserPokeVolumeFunc func, + gpointer user_data); + +G_END_DECLS + +#endif /* !__THUNAR_BROWSER_H__ */ _______________________________________________ Xfce4-commits mailing list Xfce4-commits@xfce.org http://foo-projects.org/mailman/listinfo/xfce4-commits