From 6371d5d886dcb5b92eab532c0852a57a96da1fb1 Mon Sep 17 00:00:00 2001 From: Jannis Pohlmann <jannis@xfce.org> Date: Sun, 29 Aug 2010 19:36:04 +0200 Subject: [PATCH] Add CopyTo, CopyInto, MoveInto, LinkInto, UnlinkFiles D-Bus methods. The groundwork for this was done by Daniel Morales. I refactored the code a little bit, fixed a few bugs and added a working directory parameter to all functions. The startup id parameter is unused at the moment but this may change in the future. The methods have been added to the org.xfce.FileManager D-Bus interface. --- thunar/thunar-application.c | 14 +- thunar/thunar-application.h | 3 +- thunar/thunar-dbus-service-infos.xml | 108 ++++++++ thunar/thunar-dbus-service.c | 364 +++++++++++++++++++++++++++ thunar/thunar-standard-view.c | 2 +- thunar/thunar-tree-view.c | 2 +- 6 files changed, 486 insertions(+), 7 deletions(-) diff --git a/thunar/thunar-application.c b/thunar/thunar-application.c index 96186d6cd..cbc1f2ddc 100644 --- a/thunar/thunar-application.c +++ b/thunar/thunar-application.c @@ -1404,6 +1404,9 @@ unlink_stub (GList *source_path_list, * @application : a #ThunarApplication. * @parent : a #GdkScreen, a #GtkWidget or %NULL. * @file_list : the list of #ThunarFile<!---->s that should be deleted. + * @permanently : whether to unlink the files permanently. Even if this is set to + * FALSE, the files may be erased permanently if the SHIFT key + * is pressed at the time the function is called. * * Deletes all files in the @file_list and takes care of all user interaction. * @@ -1414,13 +1417,13 @@ unlink_stub (GList *source_path_list, void thunar_application_unlink_files (ThunarApplication *application, gpointer parent, - GList *file_list) + GList *file_list, + gboolean permanently) { GdkModifierType state; GtkWidget *dialog; GtkWindow *window; GdkScreen *screen; - gboolean permanently; GList *path_list = NULL; GList *lp; gchar *message; @@ -1430,8 +1433,11 @@ thunar_application_unlink_files (ThunarApplication *application, _thunar_return_if_fail (parent == NULL || GDK_IS_SCREEN (parent) || GTK_IS_WIDGET (parent)); _thunar_return_if_fail (THUNAR_IS_APPLICATION (application)); - /* check if we should permanently delete the files (user holds shift) */ - permanently = (gtk_get_current_event_state (&state) && (state & GDK_SHIFT_MASK) != 0); + if (!permanently) + { + /* check if we should permanently delete the files (user holds shift) */ + permanently = (gtk_get_current_event_state (&state) && (state & GDK_SHIFT_MASK) != 0); + } /* determine the paths for the files */ for (lp = g_list_last (file_list); lp != NULL; lp = lp->prev, ++n_path_list) diff --git a/thunar/thunar-application.h b/thunar/thunar-application.h index 8fdf40190..53e3e3ef4 100644 --- a/thunar/thunar-application.h +++ b/thunar/thunar-application.h @@ -101,7 +101,8 @@ void thunar_application_move_into (ThunarApplication *ap void thunar_application_unlink_files (ThunarApplication *application, gpointer parent, - GList *file_list); + GList *file_list, + gboolean permanently); void thunar_application_trash (ThunarApplication *application, gpointer parent, diff --git a/thunar/thunar-dbus-service-infos.xml b/thunar/thunar-dbus-service-infos.xml index c2c01c745..ca7c0c4e2 100644 --- a/thunar/thunar-dbus-service-infos.xml +++ b/thunar/thunar-dbus-service-infos.xml @@ -124,6 +124,114 @@ <method name="DisplayPreferencesDialog"> <arg direction="in" name="display" type="s" /> </method> + + + <!-- + CopyTo (working-directory : STRING, source-filenames : ARRAY OF STRING, target-filenames : ARRAY OF STRING, display : STRING, startup-id : STRING) : VOID + + working-directory : working directory used to resolve relative filenames. + source-filenames : an array of file names to copy. The file names may + be either file:-URIs, absolute paths or paths relative + to the working-directory. + target-filenames : the target filenames. + display : the screen on which to launch the filenames or "" + to use the default screen of the file manager. + startup-id : the DESKTOP_STARTUP_ID environment variable for properly + handling startup notification and focus stealing. + --> + <method name="CopyTo"> + <arg direction="in" name="working-directory" type="s" /> + <arg direction="in" name="source-filenames" type="as" /> + <arg direction="in" name="target-filenames" type="as" /> + <arg direction="in" name="display" type="s" /> + <arg direction="in" name="startup-id" type="s" /> + </method> + + + <!-- + CopyInto (working-directory : STRING, source-filenames : ARRAY OF STRING, target-filename : STRING, display : STRING, startup-id : STRING) : VOID + + working-directory : working directory used to resolve relative filenames. + source-filenames : an array of file names to copy. The file names may + be either file:-URIs, absolute paths or paths relative + to the working-directory. + target-filename : the target directory. + display : the screen on which to launch the filenames or "" + to use the default screen of the file manager. + startup-id : the DESKTOP_STARTUP_ID environment variable for properly + handling startup notification and focus stealing. + --> + <method name="CopyInto"> + <arg direction="in" name="working-directory" type="s" /> + <arg direction="in" name="source-filenames" type="as" /> + <arg direction="in" name="target-filename" type="s" /> + <arg direction="in" name="display" type="s" /> + <arg direction="in" name="startup-id" type="s" /> + </method> + + + <!-- + MoveInto (working-directory : STRING, source-filenames : ARRAY OF STRING, target-filename : STRING, display : STRING, startup-id : STRING) : VOID + + working-directory : working directory used to resolve relative filenames. + source-filenames : an array of file names to move. The file names may + be either file:-URIs, absolute paths or paths relative + to the working-directory. + target-filename : the target directory. + display : the screen on which to launch the filenames or "" + to use the default screen of the file manager. + startup-id : the DESKTOP_STARTUP_ID environment variable for properly + handling startup notification and focus stealing. + --> + <method name="MoveInto"> + <arg direction="in" name="working-directory" type="s" /> + <arg direction="in" name="source-filenames" type="as" /> + <arg direction="in" name="target-filename" type="s" /> + <arg direction="in" name="display" type="s" /> + <arg direction="in" name="startup-id" type="s" /> + </method> + + + <!-- + LinkInto (working-directory : STRING, source-filenames : ARRAY OF STRING, target-filename : STRING, display : STRING, startup-id : STRING) : VOID + + working-directory : working directory used to resolve relative filenames. + source-filenames : an array of file names to link. The file names may + be either file:-URIs, absolute paths or paths relative + to the working-directory. + target-filename : the target directory. + display : the screen on which to launch the filenames or "" + to use the default screen of the file manager. + startup-id : the DESKTOP_STARTUP_ID environment variable for properly + handling startup notification and focus stealing. + --> + <method name="LinkInto"> + <arg direction="in" name="working-directory" type="s" /> + <arg direction="in" name="source-filenames" type="as" /> + <arg direction="in" name="target-filename" type="s" /> + <arg direction="in" name="display" type="s" /> + <arg direction="in" name="startup-id" type="s" /> + </method> + + + <!-- + UnlinkFiles (working-directory : STRING, filenames : ARRAY OF STRING, display : STRING, startup-id : STRING) : VOID + + working-directory : working directory used to resolve relative filenames. + filenames : an array of file names to delete. The file names may + be either file:-URIs, absolute paths or paths relative + to the working-directory. + display : the screen on which to launch the filenames or "" + to use the default screen of the file manager. + startup-id : the DESKTOP_STARTUP_ID environment variable for properly + handling startup notification and focus stealing. + --> + <method name="UnlinkFiles"> + <arg direction="in" name="working-directory" type="s" /> + <arg direction="in" name="filenames" type="as" /> + <arg direction="in" name="display" type="s" /> + <arg direction="in" name="startup-id" type="s" /> + </method> </interface> diff --git a/thunar/thunar-dbus-service.c b/thunar/thunar-dbus-service.c index 987c8e6d9..18543795b 100644 --- a/thunar/thunar-dbus-service.c +++ b/thunar/thunar-dbus-service.c @@ -35,6 +35,8 @@ #include <glib/gstdio.h> +#include <exo/exo.h> + #include <thunar/thunar-application.h> #include <thunar/thunar-chooser-dialog.h> #include <thunar/thunar-dbus-service.h> @@ -43,7 +45,16 @@ #include <thunar/thunar-preferences-dialog.h> #include <thunar/thunar-private.h> #include <thunar/thunar-properties-dialog.h> +#include <thunar/thunar-util.h> + +typedef enum +{ + THUNAR_DBUS_TRANSFER_MODE_COPY_TO, + THUNAR_DBUS_TRANSFER_MODE_COPY_INTO, + THUNAR_DBUS_TRANSFER_MODE_MOVE_INTO, + THUNAR_DBUS_TRANSFER_MODE_LINK_INTO, +} ThunarDBusTransferMode; static void thunar_dbus_service_finalize (GObject *object); @@ -55,6 +66,13 @@ static gboolean thunar_dbus_service_parse_uri_and_display (ThunarDBusServi ThunarFile **file_return, GdkScreen **screen_return, GError **error); +static gboolean thunar_dbus_service_transfer_files (ThunarDBusTransferMode transfer_mode, + const gchar *working_directory, + const gchar * const *source_filenames, + const gchar * const *target_filenames, + const gchar *display, + const gchar *startup_id, + GError **error); static void thunar_dbus_service_trash_bin_changed (ThunarDBusService *dbus_service, ThunarFile *trash_bin); static gboolean thunar_dbus_service_display_chooser_dialog (ThunarDBusService *dbus_service, @@ -108,6 +126,40 @@ static gboolean thunar_dbus_service_launch_files (ThunarDBusServi const gchar *display, const gchar *startup_id, GError **error); +static gboolean thunar_dbus_service_copy_to (ThunarDBusService *dbus_service, + const gchar *working_directory, + gchar **source_filenames, + gchar **target_filenames, + const gchar *display, + const gchar *startup_id, + GError **error); +static gboolean thunar_dbus_service_copy_into (ThunarDBusService *dbus_service, + const gchar *working_directory, + gchar **source_filenames, + const gchar *target_filename, + const gchar *display, + const gchar *startup_id, + GError **error); +static gboolean thunar_dbus_service_move_into (ThunarDBusService *dbus_service, + const gchar *working_directory, + gchar **source_filenames, + const gchar *target_filenames, + const gchar *display, + const gchar *startup_id, + GError **error); +static gboolean thunar_dbus_service_link_into (ThunarDBusService *dbus_service, + const gchar *working_directory, + gchar **source_filenames, + const gchar *target_filename, + const gchar *display, + const gchar *startup_id, + GError **error); +static gboolean thunar_dbus_service_unlink_files (ThunarDBusService *dbus_service, + const gchar *working_directory, + gchar **filenames, + const gchar *display, + const gchar *startup_id, + GError **error); static gboolean thunar_dbus_service_terminate (ThunarDBusService *dbus_service, GError **error); @@ -723,6 +775,318 @@ thunar_dbus_service_launch_files (ThunarDBusService *dbus_service, +static gboolean +thunar_dbus_service_transfer_files (ThunarDBusTransferMode transfer_mode, + const gchar *working_directory, + const gchar * const *source_filenames, + const gchar * const *target_filenames, + const gchar *display, + const gchar *startup_id, + GError **error) +{ + ThunarApplication *application; + GdkScreen *screen; + GError *err = NULL; + GFile *file; + GList *source_file_list = NULL; + GList *target_file_list = NULL; + gchar *filename; + gchar *new_working_dir = NULL; + gchar *old_working_dir = NULL; + guint n; + + /* verify that at least one file to transfer is given */ + if (source_filenames == NULL || *source_filenames == NULL) + { + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_INVAL, + _("At least one source filename must be specified")); + return FALSE; + } + + /* verify that the target filename is set / enough target filenames are given */ + if (transfer_mode == THUNAR_DBUS_TRANSFER_MODE_COPY_TO) + { + if (g_strv_length ((gchar **)source_filenames) != g_strv_length ((gchar **)target_filenames)) + { + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_INVAL, + _("The number of source and target filenames must be the same")); + return FALSE; + } + } + else + { + if (target_filenames == NULL || *target_filenames == NULL) + { + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_INVAL, + _("A destination directory must be specified")); + return FALSE; + } + } + + /* try to open the screen for the display name */ + screen = thunar_gdk_screen_open (display, &err); + if (screen != NULL) + { + /* change the working directory if necessary */ + if (!exo_str_is_empty (working_directory)) + old_working_dir = thunar_util_change_working_directory (working_directory); + + /* transform the source filenames into GFile objects */ + for (n = 0; err == NULL && source_filenames[n] != NULL; ++n) + { + filename = g_filename_from_utf8 (source_filenames[n], -1, NULL, NULL, &err); + if (filename != NULL) + { + file = g_file_new_for_commandline_arg (filename); + source_file_list = thunar_g_file_list_append (source_file_list, file); + g_object_unref (file); + g_free (filename); + } + } + + /* transform the target filename(s) into (a) GFile object(s) */ + for (n = 0; err == NULL && target_filenames[n] != NULL; ++n) + { + filename = g_filename_from_utf8 (target_filenames[n], -1, NULL, NULL, &err); + if (filename != NULL) + { + file = g_file_new_for_commandline_arg (filename); + target_file_list = thunar_g_file_list_append (target_file_list, file); + g_object_unref (file); + g_free (filename); + } + } + + /* switch back to the previous working directory */ + if (!exo_str_is_empty (working_directory)) + { + new_working_dir = thunar_util_change_working_directory (old_working_dir); + g_free (old_working_dir); + g_free (new_working_dir); + } + + if (err == NULL) + { + /* let the application process the filenames */ + application = thunar_application_get (); + switch (transfer_mode) + { + case THUNAR_DBUS_TRANSFER_MODE_COPY_TO: + thunar_application_copy_to (application, screen, + source_file_list, target_file_list, + NULL); + break; + case THUNAR_DBUS_TRANSFER_MODE_COPY_INTO: + thunar_application_copy_into (application, screen, + source_file_list, target_file_list->data, + NULL); + break; + case THUNAR_DBUS_TRANSFER_MODE_MOVE_INTO: + thunar_application_move_into (application, screen, + source_file_list, target_file_list->data, + NULL); + break; + case THUNAR_DBUS_TRANSFER_MODE_LINK_INTO: + thunar_application_link_into (application, screen, + source_file_list, target_file_list->data, + NULL); + break; + } + g_object_unref (application); + } + + /* free the file lists */ + thunar_g_file_list_free (source_file_list); + thunar_g_file_list_free (target_file_list); + + /* release the screen */ + g_object_unref (screen); + } + + if (err != NULL) + { + g_propagate_error (error, err); + return FALSE; + } + + return TRUE; +} + + + +static gboolean +thunar_dbus_service_copy_to (ThunarDBusService *dbus_service, + const gchar *working_directory, + gchar **source_filenames, + gchar **target_filenames, + const gchar *display, + const gchar *startup_id, + GError **error) +{ + return thunar_dbus_service_transfer_files (THUNAR_DBUS_TRANSFER_MODE_COPY_TO, + working_directory, + (const gchar * const *)source_filenames, + (const gchar * const *)target_filenames, + display, + startup_id, + error); +} + + + +static gboolean +thunar_dbus_service_copy_into (ThunarDBusService *dbus_service, + const gchar *working_directory, + gchar **source_filenames, + const gchar *target_filename, + const gchar *display, + const gchar *startup_id, + GError **error) +{ + const gchar *target_filenames[2] = { target_filename, NULL }; + + return thunar_dbus_service_transfer_files (THUNAR_DBUS_TRANSFER_MODE_COPY_INTO, + working_directory, + (const gchar * const *)source_filenames, + target_filenames, + display, + startup_id, + error); +} + + + +static gboolean +thunar_dbus_service_move_into (ThunarDBusService *dbus_service, + const gchar *working_directory, + gchar **source_filenames, + const gchar *target_filename, + const gchar *display, + const gchar *startup_id, + GError **error) +{ + const gchar *target_filenames[2] = { target_filename, NULL }; + + return thunar_dbus_service_transfer_files (THUNAR_DBUS_TRANSFER_MODE_MOVE_INTO, + working_directory, + (const gchar * const *)source_filenames, + target_filenames, + display, + startup_id, + error); +} + + + +static gboolean +thunar_dbus_service_link_into (ThunarDBusService *dbus_service, + const gchar *working_directory, + gchar **source_filenames, + const gchar *target_filename, + const gchar *display, + const gchar *startup_id, + GError **error) +{ + const gchar *target_filenames[2] = { target_filename, NULL }; + + return thunar_dbus_service_transfer_files (THUNAR_DBUS_TRANSFER_MODE_LINK_INTO, + working_directory, + (const gchar * const *)source_filenames, + target_filenames, + display, + startup_id, + error); +} + + +static gboolean +thunar_dbus_service_unlink_files (ThunarDBusService *dbus_service, + const gchar *working_directory, + gchar **filenames, + const gchar *display, + const gchar *startup_id, + GError **error) +{ + ThunarApplication *application; + ThunarFile *thunar_file; + GFile *file; + GdkScreen *screen; + GError *err = NULL; + GList *file_list = NULL; + gchar *filename; + gchar *new_working_dir = NULL; + gchar *old_working_dir = NULL; + guint n; + + /* verify that atleast one filename is given */ + if (filenames == NULL || *filenames == NULL) + { + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_INVAL, _("At least one filename must be specified")); + return FALSE; + } + + /* try to open the screen for the display name */ + screen = thunar_gdk_screen_open (display, &err); + if (screen != NULL) + { + /* change the working directory if necessary */ + if (!exo_str_is_empty (working_directory)) + old_working_dir = thunar_util_change_working_directory (working_directory); + + /* try to parse the specified filenames */ + for (n = 0; err == NULL && filenames[n] != NULL; ++n) + { + /* decode the filename (D-BUS uses UTF-8) */ + filename = g_filename_from_utf8 (filenames[n], -1, NULL, NULL, &err); + if (filename != NULL) + { + /* determine the path for the filename */ + file = g_file_new_for_commandline_arg (filename); + thunar_file = thunar_file_get (file, &err); + + if (thunar_file != NULL) + file_list = g_list_append (file_list, thunar_file); + + g_object_unref (file); + } + + /* cleanup */ + g_free (filename); + } + + /* switch back to the previous working directory */ + if (!exo_str_is_empty (working_directory)) + { + new_working_dir = thunar_util_change_working_directory (old_working_dir); + g_free (old_working_dir); + g_free (new_working_dir); + } + + /* check if we succeeded */ + if (err == NULL) + { + /* tell the application to move the specified files to the trash */ + application = thunar_application_get (); + thunar_application_unlink_files (application, screen, file_list, TRUE); + g_object_unref (application); + } + + /* cleanup */ + thunar_file_list_free (file_list); + g_object_unref (screen); + } + + if (err != NULL) + { + g_propagate_error (error, err); + return FALSE; + } + + return TRUE; +} + + + static gboolean thunar_dbus_service_terminate (ThunarDBusService *dbus_service, GError **error) diff --git a/thunar/thunar-standard-view.c b/thunar/thunar-standard-view.c index aed6542fd..04b3287ec 100644 --- a/thunar/thunar-standard-view.c +++ b/thunar/thunar-standard-view.c @@ -1973,7 +1973,7 @@ thunar_standard_view_action_delete (GtkAction *action, /* delete the selected files */ application = thunar_application_get (); - thunar_application_unlink_files (application, GTK_WIDGET (standard_view), standard_view->selected_files); + thunar_application_unlink_files (application, GTK_WIDGET (standard_view), standard_view->selected_files, FALSE); g_object_unref (G_OBJECT (application)); } diff --git a/thunar/thunar-tree-view.c b/thunar/thunar-tree-view.c index 1bee4bb18..2128e54a1 100644 --- a/thunar/thunar-tree-view.c +++ b/thunar/thunar-tree-view.c @@ -1643,7 +1643,7 @@ thunar_tree_view_action_delete (ThunarTreeView *view) /* delete the file */ application = thunar_application_get (); - thunar_application_unlink_files (application, GTK_WIDGET (view), &file_list); + thunar_application_unlink_files (application, GTK_WIDGET (view), &file_list, FALSE); g_object_unref (G_OBJECT (application)); /* release the file */ -- GitLab