/* vi:set et ai sw=2 sts=2 ts=2: */ /*- * Copyright (c) 2006 Benedikt Meurer * Copyright (c) 2009-2010 Jannis Pohlmann * Copyright (c) 2010 Daniel Morales * * 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., 59 Temple * Place, Suite 330, Boston, MA 02111-1307 USA */ #ifdef HAVE_CONFIG_H #include #endif #ifdef HAVE_MEMORY_H #include #endif #ifdef HAVE_STRING_H #include #endif #include #include #include #include #include #include #include #include #include #include #include /* include generate dbus infos */ #include #include 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); static gboolean thunar_dbus_service_connect_trash_bin (ThunarDBusService *dbus_service, GError **error); static gboolean thunar_dbus_service_parse_uri_and_display (ThunarDBusService *dbus_service, const gchar *uri, const gchar *display, 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 (ThunarDBusFileManager *object, GDBusMethodInvocation *invocation, const gchar *uri, gboolean open, const gchar *display, const gchar *startup_id, ThunarDBusService *dbus_service); static gboolean thunar_dbus_service_display_folder (ThunarDBusFileManager *object, GDBusMethodInvocation *invocation, const gchar *uri, const gchar *display, const gchar *startup_id, ThunarDBusService *dbus_service); static gboolean thunar_dbus_service_display_folder_and_select (ThunarDBusFileManager *object, GDBusMethodInvocation *invocation, const gchar *uri, const gchar *filename, const gchar *display, const gchar *startup_id, ThunarDBusService *dbus_service); static gboolean thunar_dbus_service_display_file_properties (ThunarDBusFileManager *object, GDBusMethodInvocation *invocation, const gchar *uri, const gchar *display, const gchar *startup_id, ThunarDBusService *dbus_service); static gboolean thunar_dbus_service_launch (ThunarDBusFileManager *object, GDBusMethodInvocation *invocation, const gchar *uri, const gchar *display, const gchar *startup_id, ThunarDBusService *dbus_service); static gboolean thunar_dbus_service_execute (ThunarDBusFileManager *object, GDBusMethodInvocation *invocation, const gchar *working_directory, const gchar *uri, const gchar **files, const gchar *display, const gchar *startup_id, ThunarDBusService *dbus_service); static gboolean thunar_dbus_service_display_preferences_dialog (ThunarDBusFileManager *object, GDBusMethodInvocation *invocation, const gchar *display, const gchar *startup_id, ThunarDBusService *dbus_service); static gboolean thunar_dbus_service_display_trash (ThunarDBusTrash *object, GDBusMethodInvocation *invocation, const gchar *display, const gchar *startup_id, ThunarDBusService *dbus_service); static gboolean thunar_dbus_service_empty_trash (ThunarDBusTrash *object, GDBusMethodInvocation *invocation, const gchar *display, const gchar *startup_id, ThunarDBusService *dbus_service); static gboolean thunar_dbus_service_move_to_trash (ThunarDBusTrash *object, GDBusMethodInvocation *invocation, gchar **filenames, const gchar *display, const gchar *startup_id, ThunarDBusService *dbus_service); static gboolean thunar_dbus_service_query_trash (ThunarDBusTrash *object, GDBusMethodInvocation *invocation, ThunarDBusService *dbus_service); static gboolean thunar_dbus_service_bulk_rename (ThunarDBusThunar *object, GDBusMethodInvocation *invocation, const gchar *working_directory, gchar **filenames, gboolean standalone, const gchar *display, const gchar *startup_id, ThunarDBusService *dbus_service); static gboolean thunar_dbus_service_launch_files (ThunarDBusFileManager *object, GDBusMethodInvocation *invocation, const gchar *working_directory, gchar **filenames, const gchar *display, const gchar *startup_id, ThunarDBusService *dbus_service); static gboolean thunar_dbus_service_rename_file (ThunarDBusFileManager *object, GDBusMethodInvocation *invocation, const gchar *uri, const gchar *display, const gchar *startup_id, ThunarDBusService *dbus_service); static gboolean thunar_dbus_service_create_file (ThunarDBusFileManager *object, GDBusMethodInvocation *invocation, const gchar *parent_directory, const gchar *content_type, const gchar *display, const gchar *startup_id, ThunarDBusService *dbus_service); static gboolean thunar_dbus_service_create_file_from_template (ThunarDBusFileManager *object, GDBusMethodInvocation *invocation, const gchar *parent_directory, const gchar *template_uri, const gchar *display, const gchar *startup_id, ThunarDBusService *dbus_service); static gboolean thunar_dbus_service_copy_to (ThunarDBusFileManager *object, GDBusMethodInvocation *invocation, const gchar *working_directory, gchar **source_filenames, gchar **target_filenames, const gchar *display, const gchar *startup_id, ThunarDBusService *dbus_service); static gboolean thunar_dbus_service_copy_into (ThunarDBusFileManager *object, GDBusMethodInvocation *invocation, const gchar *working_directory, gchar **source_filenames, const gchar *target_filename, const gchar *display, const gchar *startup_id, ThunarDBusService *dbus_service); static gboolean thunar_dbus_service_move_into (ThunarDBusFileManager *object, GDBusMethodInvocation *invocation, const gchar *working_directory, gchar **source_filenames, const gchar *target_filenames, const gchar *display, const gchar *startup_id, ThunarDBusService *dbus_service); static gboolean thunar_dbus_service_link_into (ThunarDBusFileManager *object, GDBusMethodInvocation *invocation, const gchar *working_directory, gchar **source_filenames, const gchar *target_filename, const gchar *display, const gchar *startup_id, ThunarDBusService *dbus_service); static gboolean thunar_dbus_service_unlink_files (ThunarDBusFileManager *object, GDBusMethodInvocation *invocation, const gchar *working_directory, gchar **filenames, const gchar *display, const gchar *startup_id, ThunarDBusService *dbus_service); static gboolean thunar_dbus_service_terminate (ThunarDBusThunar *object, GDBusMethodInvocation *invocation, ThunarDBusService *dbus_service); static gboolean thunar_dbus_freedesktop_show_folders (ThunarOrgFreedesktopFileManager1 *object, GDBusMethodInvocation *invocation, gchar **uris, const gchar *startup_id, ThunarDBusService *dbus_service); static gboolean thunar_dbus_freedesktop_show_items (ThunarOrgFreedesktopFileManager1 *object, GDBusMethodInvocation *invocation, gchar **uris, const gchar *startup_id, ThunarDBusService *dbus_service); static gboolean thunar_dbus_freedesktop_show_item_properties (ThunarOrgFreedesktopFileManager1 *object, GDBusMethodInvocation *invocation, gchar **uris, const gchar *startup_id, ThunarDBusService *dbus_service); struct _ThunarDBusServiceClass { GObjectClass __parent__; }; struct _ThunarDBusService { GObject __parent__; ThunarDBusFileManager *file_manager; ThunarDBusTrash *trash; ThunarDBusThunar *thunar; ThunarOrgFreedesktopFileManager1 *file_manager_fdo; ThunarFile *trash_bin; }; G_DEFINE_TYPE (ThunarDBusService, thunar_dbus_service, G_TYPE_OBJECT) static void thunar_dbus_service_class_init (ThunarDBusServiceClass *klass) { GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS (klass); gobject_class->finalize = thunar_dbus_service_finalize; } static void connect_signals_multiple (gpointer object, gpointer data, ...) { va_list ap; const char *signal; gpointer *handler; va_start (ap, data); while ((signal = va_arg (ap, const char *))) { handler = va_arg (ap, gpointer); g_signal_connect (object, signal, G_CALLBACK (handler), data); } va_end (ap); } static void thunar_dbus_service_init (ThunarDBusService *dbus_service) { dbus_service->file_manager = thunar_dbus_file_manager_skeleton_new (); dbus_service->trash = thunar_dbus_trash_skeleton_new (); dbus_service->thunar = thunar_dbus_thunar_skeleton_new (); dbus_service->file_manager_fdo = thunar_org_freedesktop_file_manager1_skeleton_new (); connect_signals_multiple (dbus_service->file_manager, dbus_service, "handle-display-chooser-dialog", thunar_dbus_service_display_chooser_dialog, "handle-display-folder", thunar_dbus_service_display_folder, "handle-display-folder-and-select", thunar_dbus_service_display_folder_and_select, "handle-display-file-properties", thunar_dbus_service_display_file_properties, "handle-launch", thunar_dbus_service_launch, "handle-execute", thunar_dbus_service_execute, "handle-display-preferences-dialog", thunar_dbus_service_display_preferences_dialog, "handle-copy-to", thunar_dbus_service_copy_to, "handle-copy-into", thunar_dbus_service_copy_into, "handle-move-into", thunar_dbus_service_move_into, "handle-link-into", thunar_dbus_service_link_into, "handle-unlink-files", thunar_dbus_service_unlink_files, "handle-launch-files", thunar_dbus_service_launch_files, "handle-rename-file", thunar_dbus_service_rename_file, "handle-create-file", thunar_dbus_service_create_file, "handle-create-file-from-template", thunar_dbus_service_create_file_from_template, NULL); connect_signals_multiple (dbus_service->trash, dbus_service, "handle-display-trash", thunar_dbus_service_display_trash, "handle-empty-trash", thunar_dbus_service_empty_trash, "handle-move-to-trash", thunar_dbus_service_move_to_trash, "handle-query-trash", thunar_dbus_service_query_trash, NULL); connect_signals_multiple (dbus_service->thunar, dbus_service, "handle-bulk-rename", thunar_dbus_service_bulk_rename, "handle-terminate", thunar_dbus_service_terminate, NULL); connect_signals_multiple (dbus_service->file_manager_fdo, dbus_service, "handle-show-folders", thunar_dbus_freedesktop_show_folders, "handle-show-items", thunar_dbus_freedesktop_show_items, "handle-show-item-properties", thunar_dbus_freedesktop_show_item_properties, NULL); } static void thunar_dbus_service_finalize (GObject *object) { ThunarDBusService *dbus_service = THUNAR_DBUS_SERVICE (object); g_object_unref (dbus_service->file_manager); g_object_unref (dbus_service->trash); g_object_unref (dbus_service->thunar); g_object_unref (dbus_service->file_manager_fdo); if (dbus_service->trash_bin) g_object_unref (dbus_service->trash_bin); (*G_OBJECT_CLASS (thunar_dbus_service_parent_class)->finalize) (object); } static gboolean thunar_dbus_service_connect_trash_bin (ThunarDBusService *dbus_service, GError **error) { GFile *trash_bin_path; /* check if we're not already connected to the trash bin */ if (G_UNLIKELY (dbus_service->trash_bin == NULL)) { /* try to connect to the trash bin */ trash_bin_path = thunar_g_file_new_for_trash (); dbus_service->trash_bin = thunar_file_get (trash_bin_path, error); if (G_LIKELY (dbus_service->trash_bin != NULL)) { /* watch the trash bin for changes */ thunar_file_watch (dbus_service->trash_bin); /* stay informed about changes to the trash bin */ g_signal_connect_swapped (G_OBJECT (dbus_service->trash_bin), "changed", G_CALLBACK (thunar_dbus_service_trash_bin_changed), dbus_service); thunar_file_reload_idle (dbus_service->trash_bin); } g_object_unref (trash_bin_path); } return (dbus_service->trash_bin != NULL); } static gboolean thunar_dbus_service_parse_uri_and_display (ThunarDBusService *dbus_service, const gchar *uri, const gchar *display, ThunarFile **file_return, GdkScreen **screen_return, GError **error) { /* try to open the display */ *screen_return = thunar_gdk_screen_open (display, error); if (G_UNLIKELY (*screen_return == NULL)) return FALSE; /* try to determine the file for the URI */ *file_return = thunar_file_get_for_uri (uri, error); if (G_UNLIKELY (*file_return == NULL)) { g_object_unref (G_OBJECT (*screen_return)); return FALSE; } return TRUE; } static void thunar_dbus_service_trash_bin_changed (ThunarDBusService *dbus_service, ThunarFile *trash_bin) { _thunar_return_if_fail (THUNAR_IS_DBUS_SERVICE (dbus_service)); _thunar_return_if_fail (dbus_service->trash_bin == trash_bin); _thunar_return_if_fail (THUNAR_IS_FILE (trash_bin)); /* emit the "trash-changed" signal with the new state */ thunar_dbus_trash_emit_trash_changed (dbus_service->trash); } static gboolean thunar_dbus_service_display_chooser_dialog (ThunarDBusFileManager *object, GDBusMethodInvocation *invocation, const gchar *uri, gboolean open, const gchar *display, const gchar *startup_id, ThunarDBusService *dbus_service) { ThunarFile *file; GdkScreen *screen; GError *error = NULL; /* parse uri and display parameters */ if (!thunar_dbus_service_parse_uri_and_display (dbus_service, uri, display, &file, &screen, &error)) goto out; /* popup the chooser dialog */ /* TODO use the startup id! */ thunar_show_chooser_dialog (screen, file, open, FALSE); /* cleanup */ g_object_unref (G_OBJECT (screen)); g_object_unref (G_OBJECT (file)); out: if (error) g_dbus_method_invocation_take_error (invocation, error); else thunar_dbus_file_manager_complete_display_chooser_dialog (object, invocation); return TRUE; } static gboolean thunar_dbus_service_display_folder (ThunarDBusFileManager *object, GDBusMethodInvocation *invocation, const gchar *uri, const gchar *display, const gchar *startup_id, ThunarDBusService *dbus_service) { ThunarApplication *application; ThunarFile *file; GdkScreen *screen; GError *error = NULL; /* parse uri and display parameters */ if (!thunar_dbus_service_parse_uri_and_display (dbus_service, uri, display, &file, &screen, &error)) return FALSE; /* popup a new window for the folder */ application = thunar_application_get (); thunar_application_open_window (application, file, screen, startup_id, FALSE); g_object_unref (G_OBJECT (application)); /* cleanup */ g_object_unref (G_OBJECT (screen)); g_object_unref (G_OBJECT (file)); if (error) g_dbus_method_invocation_take_error (invocation, error); else thunar_dbus_file_manager_complete_display_folder (object, invocation); return TRUE; } static gboolean thunar_dbus_service_display_folder_and_select (ThunarDBusFileManager *object, GDBusMethodInvocation *invocation, const gchar *uri, const gchar *filename, const gchar *display, const gchar *startup_id, ThunarDBusService *dbus_service) { ThunarApplication *application; ThunarFile *file; ThunarFile *folder; GdkScreen *screen; GtkWidget *window; GFile *path; GError *error = NULL; /* verify that filename is valid */ if (G_UNLIKELY (filename == NULL || *filename == '\0' || strchr (filename, '/') != NULL)) { g_set_error (&error, G_FILE_ERROR, G_FILE_ERROR_INVAL, _("Invalid filename \"%s\""), filename); goto out; } /* parse uri and display parameters */ if (!thunar_dbus_service_parse_uri_and_display (dbus_service, uri, display, &folder, &screen, &error)) goto out; /* popup a new window for the folder */ application = thunar_application_get (); window = thunar_application_open_window (application, folder, screen, startup_id, FALSE); g_object_unref (application); /* determine the path for the filename relative to the folder */ path = g_file_resolve_relative_path (thunar_file_get_file (folder), filename); if (G_LIKELY (path != NULL)) { /* try to determine the file for the path */ file = thunar_file_get (path, NULL); if (G_LIKELY (file != NULL)) { /* tell the window to scroll to the given file and select it */ thunar_window_scroll_to_file (THUNAR_WINDOW (window), file, TRUE, TRUE, 0.5f, 0.5f); /* release the file reference */ g_object_unref (file); } /* release the path */ g_object_unref (path); } /* cleanup */ g_object_unref (screen); g_object_unref (folder); out: if (error) g_dbus_method_invocation_take_error (invocation, error); else thunar_dbus_file_manager_complete_display_folder_and_select (object, invocation); return TRUE; } static gboolean thunar_dbus_service_display_file_properties (ThunarDBusFileManager *object, GDBusMethodInvocation *invocation, const gchar *uri, const gchar *display, const gchar *startup_id, ThunarDBusService *dbus_service) { ThunarApplication *application; ThunarFile *file; GdkScreen *screen; GtkWidget *dialog; GError *error = NULL; /* parse uri and display parameters */ if (!thunar_dbus_service_parse_uri_and_display (dbus_service, uri, display, &file, &screen, &error)) goto out; /* popup the file properties dialog */ dialog = thunar_properties_dialog_new (NULL); gtk_window_set_screen (GTK_WINDOW (dialog), screen); gtk_window_set_startup_id (GTK_WINDOW (dialog), startup_id); thunar_properties_dialog_set_file (THUNAR_PROPERTIES_DIALOG (dialog), file); gtk_window_present (GTK_WINDOW (dialog)); /* let the application take control over the dialog */ application = thunar_application_get (); thunar_application_take_window (application, GTK_WINDOW (dialog)); g_object_unref (G_OBJECT (application)); /* cleanup */ g_object_unref (G_OBJECT (screen)); g_object_unref (G_OBJECT (file)); out: if (error) g_dbus_method_invocation_take_error (invocation, error); else thunar_dbus_file_manager_complete_display_file_properties (object, invocation); return TRUE; } static gboolean thunar_dbus_service_launch (ThunarDBusFileManager *object, GDBusMethodInvocation *invocation, const gchar *uri, const gchar *display, const gchar *startup_id, ThunarDBusService *dbus_service) { ThunarFile *file; GdkScreen *screen; GError *error = NULL; /* parse uri and display parameters */ if (thunar_dbus_service_parse_uri_and_display (dbus_service, uri, display, &file, &screen, &error)) { /* try to launch the file on the given screen */ thunar_file_launch (file, screen, startup_id, &error); /* cleanup */ g_object_unref (G_OBJECT (screen)); g_object_unref (G_OBJECT (file)); } if (error) g_dbus_method_invocation_take_error (invocation, error); else thunar_dbus_file_manager_complete_launch (object, invocation); return TRUE; } static gboolean thunar_dbus_service_execute (ThunarDBusFileManager *object, GDBusMethodInvocation *invocation, const gchar *working_directory, const gchar *uri, const gchar **files, const gchar *display, const gchar *startup_id, ThunarDBusService *dbus_service) { ThunarFile *file; GdkScreen *screen; GError *error = NULL; GFile *working_dir; GList *file_list = NULL; gchar *tmp_working_dir = NULL; gchar *old_working_dir = NULL; guint n; /* parse uri and display parameters */ if (thunar_dbus_service_parse_uri_and_display (dbus_service, uri, display, &file, &screen, &error)) { if (working_directory != NULL && *working_directory != '\0') old_working_dir = thunar_util_change_working_directory (working_directory); for (n = 0; files != NULL && files[n] != NULL; ++n) file_list = g_list_prepend (file_list, g_file_new_for_commandline_arg (files[n])); file_list = g_list_reverse (file_list); if (old_working_dir != NULL) { tmp_working_dir = thunar_util_change_working_directory (old_working_dir); g_free (tmp_working_dir); g_free (old_working_dir); } /* try to launch the file on the given screen */ working_dir = g_file_new_for_commandline_arg (working_directory); thunar_file_execute (file, working_dir, screen, file_list, startup_id, &error); g_object_unref (working_dir); /* cleanup */ g_list_free_full (file_list, g_object_unref); g_object_unref (screen); g_object_unref (file); } if (error) g_dbus_method_invocation_take_error (invocation, error); else thunar_dbus_file_manager_complete_launch (object, invocation); return TRUE; } static gboolean thunar_dbus_service_display_preferences_dialog (ThunarDBusFileManager *object, GDBusMethodInvocation *invocation, const gchar *display, const gchar *startup_id, ThunarDBusService *dbus_service) { ThunarApplication *application; GdkScreen *screen; GtkWidget *dialog; GError *error = NULL; /* try to open the screen for the display name */ screen = thunar_gdk_screen_open (display, &error); if (G_UNLIKELY (screen == NULL)) goto out; /* popup the preferences dialog... */ dialog = thunar_preferences_dialog_new (NULL); gtk_window_set_screen (GTK_WINDOW (dialog), screen); gtk_window_set_startup_id (GTK_WINDOW (dialog), startup_id); gtk_widget_show (GTK_WIDGET (dialog)); /* ...and let the application take care of it */ application = thunar_application_get (); thunar_application_take_window (application, GTK_WINDOW (dialog)); g_object_unref (G_OBJECT (application)); /* cleanup */ g_object_unref (G_OBJECT (screen)); out: if (error) g_dbus_method_invocation_take_error (invocation, error); else thunar_dbus_file_manager_complete_display_preferences_dialog (object, invocation); return TRUE; } static gboolean thunar_dbus_service_display_trash (ThunarDBusTrash *object, GDBusMethodInvocation *invocation, const gchar *display, const gchar *startup_id, ThunarDBusService *dbus_service) { ThunarApplication *application; GdkScreen *screen; GError *error = NULL; /* connect to the trash bin on-demand */ if (!thunar_dbus_service_connect_trash_bin (dbus_service, &error)) goto out; /* try to open the screen for the display name */ screen = thunar_gdk_screen_open (display, &error); if (G_LIKELY (screen != NULL)) { /* tell the application to display the trash bin */ application = thunar_application_get (); thunar_application_open_window (application, dbus_service->trash_bin, screen, startup_id, FALSE); g_object_unref (G_OBJECT (application)); /* release the screen */ g_object_unref (G_OBJECT (screen)); } out: if (error) g_dbus_method_invocation_take_error (invocation, error); else thunar_dbus_trash_complete_display_trash (object, invocation); return TRUE; } static gboolean thunar_dbus_service_empty_trash (ThunarDBusTrash *object, GDBusMethodInvocation *invocation, const gchar *display, const gchar *startup_id, ThunarDBusService *dbus_service) { ThunarApplication *application; GdkScreen *screen; GError *error = NULL; /* try to open the screen for the display name */ screen = thunar_gdk_screen_open (display, &error); if (G_LIKELY (screen != NULL)) { /* tell the application to empty the trash bin */ application = thunar_application_get (); thunar_application_empty_trash (application, screen, startup_id); g_object_unref (G_OBJECT (application)); /* release the screen */ g_object_unref (G_OBJECT (screen)); } if (error) g_dbus_method_invocation_take_error (invocation, error); else thunar_dbus_trash_complete_empty_trash (object, invocation); return TRUE; } static gboolean thunar_dbus_service_move_to_trash (ThunarDBusTrash *object, GDBusMethodInvocation *invocation, gchar **filenames, const gchar *display, const gchar *startup_id, ThunarDBusService *dbus_service) { ThunarApplication *application; GFile *file; GdkScreen *screen; GError *err = NULL; GList *file_list = NULL; gchar *filename; guint n; /* try to open the screen for the display name */ screen = thunar_gdk_screen_open (display, &err); if (G_LIKELY (screen != NULL)) { /* 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 (G_LIKELY (err == NULL)) { /* determine the path for the filename */ /* TODO Not sure this will work as expected */ file = g_file_new_for_commandline_arg (filename); file_list = thunar_g_list_append_deep (file_list, file); g_object_unref (file); } /* cleanup */ g_free (filename); } /* check if we succeed */ if (G_LIKELY (err == NULL)) { /* tell the application to move the specified files to the trash */ application = thunar_application_get (); thunar_application_trash (application, screen, file_list); g_object_unref (application); } /* cleanup */ thunar_g_list_free_full (file_list); g_object_unref (screen); } /* check if we failed */ if (err) g_dbus_method_invocation_take_error (invocation, err); else thunar_dbus_trash_complete_move_to_trash (object, invocation); return TRUE; } static gboolean thunar_dbus_service_query_trash (ThunarDBusTrash *object, GDBusMethodInvocation *invocation, ThunarDBusService *dbus_service) { GError *error = NULL; gboolean full = FALSE; /* connect to the trash bin on-demand */ if (thunar_dbus_service_connect_trash_bin (dbus_service, &error)) { /* check whether the trash bin is not empty */ full = (thunar_file_get_item_count (dbus_service->trash_bin) > 0); } if (error) g_dbus_method_invocation_take_error (invocation, error); else thunar_dbus_trash_complete_query_trash (object, invocation, full); return TRUE; } static gboolean thunar_dbus_service_bulk_rename (ThunarDBusThunar *object, GDBusMethodInvocation *invocation, const gchar *working_directory, gchar **filenames, gboolean standalone, const gchar *display, const gchar *startup_id, ThunarDBusService *dbus_service) { ThunarApplication *application; GdkScreen *screen; gchar *cwd; GError *error = NULL; /* determine a proper working directory */ cwd = (working_directory != NULL && *working_directory != '\0') ? g_strdup (working_directory) : g_get_current_dir (); /* try to open the screen for the display name */ screen = thunar_gdk_screen_open (display, &error); if (G_LIKELY (screen != NULL)) { /* tell the application to display the bulk rename dialog */ application = thunar_application_get (); thunar_application_bulk_rename (application, cwd, filenames, standalone, screen, startup_id, &error); g_object_unref (G_OBJECT (application)); /* release the screen */ g_object_unref (G_OBJECT (screen)); } /* release the cwd */ g_free (cwd); if (error) g_dbus_method_invocation_take_error (invocation, error); else thunar_dbus_thunar_complete_bulk_rename (object, invocation); return TRUE; } static gboolean thunar_dbus_service_launch_files (ThunarDBusFileManager *object, GDBusMethodInvocation *invocation, const gchar *working_directory, gchar **filenames, const gchar *display, const gchar *startup_id, ThunarDBusService *dbus_service) { ThunarApplication *application; GdkScreen *screen; GError *error = NULL; /* verify that a valid working directory is given */ if (G_UNLIKELY (!g_path_is_absolute (working_directory))) { /* LaunchFiles() invoked without a valid working directory */ g_set_error (&error, G_FILE_ERROR, G_FILE_ERROR_INVAL, _("The working directory must be an absolute path")); goto out; } /* verify that at least one filename is given */ if (G_UNLIKELY (filenames == NULL || *filenames == NULL)) { /* LaunchFiles() invoked with an empty filename list */ g_set_error (&error, G_FILE_ERROR, G_FILE_ERROR_INVAL, _("At least one filename must be specified")); goto out; } /* try to open the screen for the display name */ screen = thunar_gdk_screen_open (display, &error); if (G_LIKELY (screen != NULL)) { /* let the application process the filenames */ application = thunar_application_get (); thunar_application_process_filenames (application, working_directory, filenames, screen, startup_id, &error, THUNAR_APPLICATION_LAUNCH_FILES); g_object_unref (G_OBJECT (application)); /* release the screen */ g_object_unref (G_OBJECT (screen)); } out: if (error) g_dbus_method_invocation_take_error (invocation, error); else thunar_dbus_file_manager_complete_launch_files (object, invocation); return TRUE; } static gboolean thunar_dbus_service_rename_file (ThunarDBusFileManager *object, GDBusMethodInvocation *invocation, const gchar *uri, const gchar *display, const gchar *startup_id, ThunarDBusService *dbus_service) { ThunarApplication *application; ThunarFile *file; GdkScreen *screen; GError *error = NULL; /* parse uri and display parameters */ if (!thunar_dbus_service_parse_uri_and_display (dbus_service, uri, display, &file, &screen, &error)) goto out; /* popup a new window for the folder */ application = thunar_application_get (); thunar_application_rename_file (application, file, screen, startup_id); g_object_unref (G_OBJECT (application)); /* cleanup */ g_object_unref (G_OBJECT (screen)); g_object_unref (G_OBJECT (file)); out: if (error) g_dbus_method_invocation_take_error (invocation, error); else thunar_dbus_file_manager_complete_rename_file (object, invocation); return TRUE; } static gboolean thunar_dbus_service_create_file (ThunarDBusFileManager *object, GDBusMethodInvocation *invocation, const gchar *parent_directory, const gchar *content_type, const gchar *display, const gchar *startup_id, ThunarDBusService *dbus_service) { ThunarApplication *application; ThunarFile *file; GdkScreen *screen; GError *error = NULL; /* parse uri and display parameters */ if (!thunar_dbus_service_parse_uri_and_display (dbus_service, parent_directory, display, &file, &screen, &error)) goto out; /* fall back to plain text file if no content type is provided */ if (content_type == NULL || *content_type == '\0') content_type = "text/plain"; /* popup a new window for the folder */ application = thunar_application_get (); thunar_application_create_file (application, file, content_type, screen, startup_id); g_object_unref (G_OBJECT (application)); /* cleanup */ g_object_unref (G_OBJECT (screen)); g_object_unref (G_OBJECT (file)); out: if (error) g_dbus_method_invocation_take_error (invocation, error); else thunar_dbus_file_manager_complete_create_file (object, invocation); return TRUE; } static gboolean thunar_dbus_service_create_file_from_template (ThunarDBusFileManager *object, GDBusMethodInvocation *invocation, const gchar *parent_directory, const gchar *template_uri, const gchar *display, const gchar *startup_id, ThunarDBusService *dbus_service) { ThunarApplication *application; ThunarFile *file; ThunarFile *template_file; GdkScreen *screen; GError *error = NULL; /* parse uri and display parameters */ if (!thunar_dbus_service_parse_uri_and_display (dbus_service, parent_directory, display, &file, &screen, &error)) goto out; /* try to determine the file for the template URI */ template_file = thunar_file_get_for_uri (template_uri, &error); if(template_file == NULL) goto out; /* popup a new window for the folder */ application = thunar_application_get (); thunar_application_create_file_from_template (application, file, template_file, screen, startup_id); g_object_unref (G_OBJECT (application)); /* cleanup */ g_object_unref (G_OBJECT (screen)); g_object_unref (G_OBJECT (file)); out: if (error) g_dbus_method_invocation_take_error (invocation, error); else thunar_dbus_file_manager_complete_create_file_from_template (object, invocation); return TRUE; } 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 (!xfce_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_list_append_deep (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_list_append_deep (target_file_list, file); g_object_unref (file); g_free (filename); } } /* switch back to the previous working directory */ if (!xfce_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_list_free_full (source_file_list); thunar_g_list_free_full (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 (ThunarDBusFileManager *object, GDBusMethodInvocation *invocation, const gchar *working_directory, gchar **source_filenames, gchar **target_filenames, const gchar *display, const gchar *startup_id, ThunarDBusService *dbus_service) { GError *error = NULL; 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); if (error) g_dbus_method_invocation_take_error (invocation, error); else thunar_dbus_file_manager_complete_copy_to (object, invocation); return TRUE; } static gboolean thunar_dbus_service_copy_into (ThunarDBusFileManager *object, GDBusMethodInvocation *invocation, const gchar *working_directory, gchar **source_filenames, const gchar *target_filename, const gchar *display, const gchar *startup_id, ThunarDBusService *dbus_service) { const gchar *target_filenames[2] = { target_filename, NULL }; GError *error = NULL; thunar_dbus_service_transfer_files (THUNAR_DBUS_TRANSFER_MODE_COPY_INTO, working_directory, (const gchar * const *)source_filenames, target_filenames, display, startup_id, &error); if (error) g_dbus_method_invocation_take_error (invocation, error); else thunar_dbus_file_manager_complete_copy_into (object, invocation); return TRUE; } static gboolean thunar_dbus_service_move_into (ThunarDBusFileManager *object, GDBusMethodInvocation *invocation, const gchar *working_directory, gchar **source_filenames, const gchar *target_filename, const gchar *display, const gchar *startup_id, ThunarDBusService *dbus_service) { const gchar *target_filenames[2] = { target_filename, NULL }; GError *error = NULL; thunar_dbus_service_transfer_files (THUNAR_DBUS_TRANSFER_MODE_MOVE_INTO, working_directory, (const gchar * const *)source_filenames, target_filenames, display, startup_id, &error); if (error) g_dbus_method_invocation_take_error (invocation, error); else thunar_dbus_file_manager_complete_move_into (object, invocation); return TRUE; } static gboolean thunar_dbus_service_link_into (ThunarDBusFileManager *object, GDBusMethodInvocation *invocation, const gchar *working_directory, gchar **source_filenames, const gchar *target_filename, const gchar *display, const gchar *startup_id, ThunarDBusService *dbus_service) { const gchar *target_filenames[2] = { target_filename, NULL }; GError *error = NULL; thunar_dbus_service_transfer_files (THUNAR_DBUS_TRANSFER_MODE_LINK_INTO, working_directory, (const gchar * const *)source_filenames, target_filenames, display, startup_id, &error); if (error) g_dbus_method_invocation_take_error (invocation, error); else thunar_dbus_file_manager_complete_link_into (object, invocation); return TRUE; } static gboolean thunar_dbus_service_unlink_files (ThunarDBusFileManager *object, GDBusMethodInvocation *invocation, const gchar *working_directory, gchar **filenames, const gchar *display, const gchar *startup_id, ThunarDBusService *dbus_service) { 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 (&err, G_FILE_ERROR, G_FILE_ERROR_INVAL, _("At least one filename must be specified")); goto out; } /* 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 (!xfce_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 (!xfce_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 && file_list != 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_g_list_free_full (file_list); g_object_unref (screen); } out: if (err) g_dbus_method_invocation_take_error (invocation, err); else thunar_dbus_file_manager_complete_unlink_files (object, invocation); return TRUE; } static gboolean thunar_dbus_service_terminate (ThunarDBusThunar *object, GDBusMethodInvocation *invocation, ThunarDBusService *dbus_service) { /* leave the Gtk main loop as soon as possible */ ThunarApplication *app = thunar_application_get (); g_application_quit (G_APPLICATION (app)); g_object_unref (app); /* we cannot fail */ thunar_dbus_thunar_complete_terminate (object, invocation); return TRUE; } static gboolean thunar_dbus_freedesktop_show_folders (ThunarOrgFreedesktopFileManager1 *object, GDBusMethodInvocation *invocation, gchar **uris, const gchar *startup_id, ThunarDBusService *dbus_service) { ThunarApplication *application; GdkScreen *screen; gint n; GFile *file; ThunarFile *thunar_file; screen = gdk_screen_get_default (); application = thunar_application_get (); for (n = 0; uris[n] != NULL; ++n) { file = g_file_new_for_uri (uris[n]); thunar_file = thunar_file_get (file, NULL); g_object_unref (G_OBJECT (file)); if (thunar_file == NULL) continue; if (thunar_file_is_directory (thunar_file)) thunar_application_open_window (application, thunar_file, screen, startup_id, FALSE); g_object_unref (G_OBJECT (thunar_file)); } g_object_unref (G_OBJECT (application)); thunar_org_freedesktop_file_manager1_complete_show_folders (object, invocation); return TRUE; } static gboolean thunar_dbus_freedesktop_show_items (ThunarOrgFreedesktopFileManager1 *object, GDBusMethodInvocation *invocation, gchar **uris, const gchar *startup_id, ThunarDBusService *dbus_service) { ThunarApplication *application; GtkWidget *window; GdkScreen *screen; gint n; GFile *file; ThunarFile *thunar_folder, *thunar_file = NULL; screen = gdk_screen_get_default (); application = thunar_application_get (); for (n = 0; uris[n] != NULL; ++n) { file = g_file_new_for_uri (uris[n]); thunar_folder = thunar_file_get (file, NULL); g_object_unref (G_OBJECT (file)); if (thunar_folder == NULL) continue; if (G_LIKELY (thunar_file_has_parent (thunar_folder))) { thunar_file = thunar_folder; thunar_folder = thunar_file_get_parent (thunar_folder, NULL); } window = thunar_application_open_window (application, thunar_folder, screen, startup_id, FALSE); if (G_LIKELY (thunar_file != NULL)) { thunar_window_scroll_to_file (THUNAR_WINDOW (window), thunar_file, TRUE, TRUE, 0.5f, 0.5f); g_object_unref (G_OBJECT (thunar_file)); } g_object_unref (G_OBJECT (thunar_folder)); } g_object_unref (G_OBJECT (application)); thunar_org_freedesktop_file_manager1_complete_show_items (object, invocation); return TRUE; } static gboolean thunar_dbus_freedesktop_show_item_properties (ThunarOrgFreedesktopFileManager1 *object, GDBusMethodInvocation *invocation, gchar **uris, const gchar *startup_id, ThunarDBusService *dbus_service) { ThunarApplication *application; GdkScreen *screen; gint n; GFile *file; GtkWidget *dialog; ThunarFile *thunar_file; screen = gdk_screen_get_default (); application = thunar_application_get (); for (n = 0; uris[n] != NULL; ++n) { file = g_file_new_for_uri (uris[n]); thunar_file = thunar_file_get (file, NULL); g_object_unref (G_OBJECT (file)); if (thunar_file == NULL) continue; dialog = thunar_properties_dialog_new (NULL); gtk_window_set_screen (GTK_WINDOW (dialog), screen); gtk_window_set_startup_id (GTK_WINDOW (dialog), startup_id); thunar_properties_dialog_set_file (THUNAR_PROPERTIES_DIALOG (dialog), thunar_file); gtk_window_present (GTK_WINDOW (dialog)); thunar_application_take_window (application, GTK_WINDOW (dialog)); g_object_unref (G_OBJECT (thunar_file)); } g_object_unref (G_OBJECT (application)); thunar_org_freedesktop_file_manager1_complete_show_item_properties (object, invocation); return TRUE; } gboolean thunar_dbus_service_export_on_connection (ThunarDBusService *service, GDBusConnection *connection, GError **error) { if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (service->file_manager), connection, "/org/xfce/FileManager", error)) goto fail; if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (service->trash), connection, "/org/xfce/FileManager", error)) goto fail; if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (service->thunar), connection, "/org/xfce/FileManager", error)) goto fail; if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (service->file_manager_fdo), connection, "/org/freedesktop/FileManager1", error)) goto fail; return TRUE; fail: /* export either all or nothing */ g_dbus_interface_skeleton_unexport_from_connection (G_DBUS_INTERFACE_SKELETON (service->file_manager), connection); g_dbus_interface_skeleton_unexport_from_connection (G_DBUS_INTERFACE_SKELETON (service->trash), connection); g_dbus_interface_skeleton_unexport_from_connection (G_DBUS_INTERFACE_SKELETON (service->thunar), connection); g_dbus_interface_skeleton_unexport_from_connection (G_DBUS_INTERFACE_SKELETON (service->file_manager_fdo), connection); return FALSE; }