Index: thunar/thunar-application.c =================================================================== --- thunar/thunar-application.c (revision 24449) +++ thunar/thunar-application.c (working copy) @@ -102,6 +102,9 @@ static void thunar_application_volman_device_removed (ThunarVfsVolumeManager *volume_manager, const gchar *udi, ThunarApplication *application); +static void thunar_application_volman_device_eject (ThunarVfsVolumeManager *volume_manager, + const gchar *udi, + ThunarApplication *application); static gboolean thunar_application_volman_idle (gpointer user_data); static void thunar_application_volman_idle_destroy (gpointer user_data); static void thunar_application_volman_watch (GPid pid, @@ -229,6 +232,7 @@ /* connect the volume manager support callbacks (used to spawn thunar-volman appropriately) */ g_signal_connect (G_OBJECT (application->volman), "device-added", G_CALLBACK (thunar_application_volman_device_added), application); g_signal_connect (G_OBJECT (application->volman), "device-removed", G_CALLBACK (thunar_application_volman_device_removed), application); + g_signal_connect (G_OBJECT (application->volman), "device-eject", G_CALLBACK (thunar_application_volman_device_eject), application); } } @@ -590,6 +594,44 @@ +static void +thunar_application_volman_device_eject (ThunarVfsVolumeManager *volume_manager, + const gchar *udi, + ThunarApplication *application) +{ + GdkScreen *screen; + GError *err = NULL; + gchar *argv[4]; + + _thunar_return_if_fail (THUNAR_VFS_IS_VOLUME_MANAGER (volume_manager)); + _thunar_return_if_fail (application->volman == volume_manager); + _thunar_return_if_fail (THUNAR_IS_APPLICATION (application)); + + /* generate the argument list for exo-eject */ + argv[0] = (gchar *) "exo-eject"; + argv[1] = (gchar *) "-h"; + argv[2] = (gchar *) udi; + argv[3] = NULL; + + /* locate the currently active screen (the one with the pointer) */ + screen = thunar_gdk_screen_get_active (); + + /* try to spawn the volman on the active screen */ + if (!gdk_spawn_on_screen (screen, NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &err)) + { + /* failed to launch exo-eject, inform the user about this */ + thunar_dialogs_show_error (screen, err, _("Failed to execute \"%s\""), "exo-eject"); + g_error_free (err); + } + else + { + /* we most probably removed the device */ + thunar_application_volman_device_removed (volume_manager, udi, application); + } +} + + + static gboolean thunar_application_volman_idle (gpointer user_data) { Index: thunar-vfs/thunar-vfs-volume-hal.c =================================================================== --- thunar-vfs/thunar-vfs-volume-hal.c (revision 24449) +++ thunar-vfs/thunar-vfs-volume-hal.c (working copy) @@ -22,9 +22,15 @@ #include #endif +#ifdef HAVE_MEMORY_H +#include +#endif #ifdef HAVE_STDLIB_H #include #endif +#ifdef HAVE_STRING_H +#include +#endif #include @@ -33,6 +39,7 @@ #include #include +#include #include #include #include @@ -609,6 +616,10 @@ const gchar *key, dbus_bool_t is_removed, dbus_bool_t is_added); +static void thunar_vfs_volume_manager_hal_device_condition (LibHalContext *context, + const gchar *udi, + const gchar *name, + const gchar *details); @@ -701,6 +712,27 @@ g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); + /** + * ThunarVfsVolumeManagerHal::device-eject: + * @manager_hal : a #ThunarVfsVolumeManagerlHal instance. + * @udi : the UDI of the device. + * + * Emitted by @manager_hal to let Thunar know that the "Eject" + * button was pressed on the device with the @udi. + * + * This signal is used by Thunar to support volume management. + * Since it's special to the HAL backend, no other application + * must use this signal, especially no application must assume + * that the signal is available on any given #ThunarVfsVolumeManager. + **/ + g_signal_new (I_("device-eject"), + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, + G_TYPE_STRING); + /* initialize exo-hal support */ if (!exo_hal_init ()) { @@ -747,6 +779,7 @@ libhal_ctx_set_device_new_capability (manager_hal->context, thunar_vfs_volume_manager_hal_device_new_capability); libhal_ctx_set_device_lost_capability (manager_hal->context, thunar_vfs_volume_manager_hal_device_lost_capability); libhal_ctx_set_device_property_modified (manager_hal->context, thunar_vfs_volume_manager_hal_device_property_modified); + libhal_ctx_set_device_condition (manager_hal->context, thunar_vfs_volume_manager_hal_device_condition); /* try to initialize the HAL context */ if (!libhal_ctx_init (manager_hal->context, &error)) @@ -1105,5 +1138,75 @@ +static void +thunar_vfs_volume_manager_hal_device_condition (LibHalContext *context, + const gchar *udi, + const gchar *name, + const gchar *details) +{ + ThunarVfsVolumeManagerHal *manager_hal = libhal_ctx_get_user_data (context); + ThunarVfsVolumeHal *volume_hal; + DBusError derror; + GList *volumes = NULL; + GList *lp; + gchar **volume_udis; + gint n_volume_udis; + gint n; + + _thunar_vfs_return_if_fail (THUNAR_VFS_IS_VOLUME_MANAGER_HAL (manager_hal)); + _thunar_vfs_return_if_fail (manager_hal->context == context); + + /* check if the device should be ejected */ + if (G_LIKELY (strcmp (name, "EjectPressed") == 0)) + { + /* check if we have a volume for the device */ + volume_hal = thunar_vfs_volume_manager_hal_get_volume_by_udi (manager_hal, udi); + if (G_LIKELY (volume_hal == NULL)) + { + /* initialize D-Bus error */ + dbus_error_init (&derror); + + /* the UDI most probably identifies the drive of the volume */ + volume_udis = libhal_manager_find_device_string_match (context, "info.parent", udi, &n_volume_udis, &derror); + if (G_LIKELY (volume_udis != NULL)) + { + /* determine the volumes for the UDIs */ + for (n = 0; n < n_volume_udis; ++n) + { + /* check if we have a mounted volume for this UDI */ + volume_hal = thunar_vfs_volume_manager_hal_get_volume_by_udi (manager_hal, volume_udis[n]); + if (thunar_vfs_volume_is_mounted (THUNAR_VFS_VOLUME (volume_hal))) + volumes = g_list_prepend (volumes, g_object_ref (G_OBJECT (volume_hal))); + } + libhal_free_string_array (volume_udis); + } + + /* free D-Bus error */ + dbus_error_free (&derror); + } + else if (thunar_vfs_volume_is_mounted (THUNAR_VFS_VOLUME (volume_hal))) + { + volumes = g_list_prepend (volumes, g_object_ref (G_OBJECT (volume_hal))); + } + + /* check there are any mounted volumes on the device */ + if (G_LIKELY (volumes != NULL)) + { + /* tell everybody, that we're about to unmount those volumes */ + for (lp = volumes; lp != NULL; lp = lp->next) + { + thunar_vfs_volume_pre_unmount (lp->data); + g_object_unref (G_OBJECT (lp->data)); + } + g_list_free (volumes); + + /* emit the "device-eject" signal and let Thunar eject the device */ + g_signal_emit_by_name (G_OBJECT (manager_hal), "device-eject", udi); + } + } +} + + + #define __THUNAR_VFS_VOLUME_HAL_C__ #include Index: thunar-vfs/thunar-vfs-volume.c =================================================================== --- thunar-vfs/thunar-vfs-volume.c (revision 24449) +++ thunar-vfs/thunar-vfs-volume.c (working copy) @@ -504,7 +504,7 @@ g_return_val_if_fail (window == NULL || GTK_IS_WINDOW (window), FALSE); /* we're about to unmount (and eject) the volume */ - g_signal_emit (G_OBJECT (volume), volume_signals[PRE_UNMOUNT], 0); + thunar_vfs_volume_pre_unmount (volume); /* setup a watch cursor on the window */ if (window != NULL && GTK_WIDGET_REALIZED (window)) @@ -631,7 +631,7 @@ g_return_val_if_fail (window == NULL || GTK_IS_WINDOW (window), FALSE); /* we're about to unmount the volume */ - g_signal_emit (G_OBJECT (volume), volume_signals[PRE_UNMOUNT], 0); + thunar_vfs_volume_pre_unmount (volume); /* setup a watch cursor on the window */ if (window != NULL && GTK_WIDGET_REALIZED (window)) @@ -672,7 +672,9 @@ void thunar_vfs_volume_changed (ThunarVfsVolume *volume) { - g_return_if_fail (THUNAR_VFS_IS_VOLUME (volume)); + _thunar_vfs_return_if_fail (THUNAR_VFS_IS_VOLUME (volume)); + + /* emit the "changed" signal */ g_signal_emit (G_OBJECT (volume), volume_signals[CHANGED], 0); /* rescan the mount points for the trash subsystem, @@ -683,6 +685,22 @@ +/** + * thunar_vfs_volume_pre_unmount: + * @volume :a #ThunarVfsVolume instance. + * + * Emits the "pre-unmount" signal on the @volume. This function + * should only be used by implementations of the #ThunarVfsVolume + * interface. + **/ +void +thunar_vfs_volume_pre_unmount (ThunarVfsVolume *volume) +{ + _thunar_vfs_return_if_fail (THUNAR_VFS_IS_VOLUME (volume)); + g_signal_emit (G_OBJECT (volume), volume_signals[PRE_UNMOUNT], 0); +} + + #define __THUNAR_VFS_VOLUME_C__ #include Index: thunar-vfs/thunar-vfs-volume-private.h =================================================================== --- thunar-vfs/thunar-vfs-volume-private.h (revision 24449) +++ thunar-vfs/thunar-vfs-volume-private.h (working copy) @@ -63,7 +63,8 @@ GObject __parent__; }; -void thunar_vfs_volume_changed (ThunarVfsVolume *volume) G_GNUC_INTERNAL; +void thunar_vfs_volume_changed (ThunarVfsVolume *volume) G_GNUC_INTERNAL; +void thunar_vfs_volume_pre_unmount (ThunarVfsVolume *volume) G_GNUC_INTERNAL; struct _ThunarVfsVolumeManagerClass