diff --git a/ChangeLog b/ChangeLog index 52f9ec9aa1b0b258046fa68c163cfa660a4348ee..c0dd2655e4109604648f0b6ea9ff9934489a2a54 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2006-02-15 Benedikt Meurer <benny@xfce.org> + + * thunar-vfs/thunar-vfs-unlink-job.c(thunar_vfs_unlink_job_execute): + Ignore ENOENT errors returned by thunar_vfs_scandir() as well, to + fix the problem with not being able to delete broken links on + Linux. + * thunar/thunar-application.c: Generate unique roles for the Thunar + toplevel windows in preparation of session management support. + * thunar/thunar-dbus-service-infos.xml, thunar/thunar-dbus-service.c: + Add Terminate() method to the org.xfce.Thunar interface, which allows + to properly shutdown a daemon instance. + * thunar/main.c, thunar/thunar-dbus-client.{c,h}: Add -q/--quit command + line option, which terminates a running daemon instance. Also cleanup + the --daemon handling. + 2006-02-15 Benedikt Meurer <benny@xfce.org> * FAQ, thunar/thunar-icon-view.c: Add mouse gesture for "Reload" as diff --git a/thunar-vfs/thunar-vfs-unlink-job.c b/thunar-vfs/thunar-vfs-unlink-job.c index 9c5ad5af392b9f01c542cbca4749245bb27735c8..066481e8cd321da4e30a126daac411d56ea768a8 100644 --- a/thunar-vfs/thunar-vfs-unlink-job.c +++ b/thunar-vfs/thunar-vfs-unlink-job.c @@ -168,8 +168,8 @@ thunar_vfs_unlink_job_execute (ThunarVfsJob *job) paths = thunar_vfs_scandir (lp->data, &job->cancelled, THUNAR_VFS_SCANDIR_RECURSIVE, NULL, &error); if (G_UNLIKELY (error != NULL)) { - /* we can safely ignore ENOTDIR errors here */ - if (error->domain != G_FILE_ERROR || error->code != G_FILE_ERROR_NOTDIR) + /* we can safely ignore ENOENT/ENOTDIR errors here */ + if (error->domain != G_FILE_ERROR || (error->code != G_FILE_ERROR_NOENT && error->code != G_FILE_ERROR_NOTDIR)) { /* inform the user about the problem and abort the job */ thunar_vfs_job_error (job, error); diff --git a/thunar/main.c b/thunar/main.c index 3358e1b83e46cda474e1a0c54325c1a2e1bee18d..e80e0189a6919ae1d01c5c3c490e9bea0128a420 100644 --- a/thunar/main.c +++ b/thunar/main.c @@ -39,12 +39,22 @@ /* --- globals --- */ static gboolean opt_daemon = FALSE; +static gboolean opt_quit = FALSE; /* --- command line options --- */ static GOptionEntry option_entries[] = { +#ifdef HAVE_DBUS { "daemon", 0, 0, G_OPTION_ARG_NONE, &opt_daemon, N_ ("Run in daemon mode"), NULL, }, +#else + { "daemon", 0, 0, G_OPTION_ARG_NONE, &opt_daemon, N_ ("Run in daemon mode (not supported)"), NULL, }, +#endif +#ifdef HAVE_DBUS + { "quit", 'q', 0, G_OPTION_ARG_NONE, &opt_quit, N_ ("Quit a running Thunar instance"), NULL, }, +#else + { "quit", 'q', 0, G_OPTION_ARG_NONE, &opt_quit, N_ ("Quit a running Thunar instance (not supported)"), NULL, }, +#endif { NULL, }, }; @@ -58,7 +68,7 @@ main (int argc, char **argv) #endif ThunarApplication *application; GError *error = NULL; - gchar *working_directory = NULL; + gchar *working_directory; gchar **filenames = NULL; /* setup translation domain */ @@ -93,42 +103,55 @@ main (int argc, char **argv) return EXIT_FAILURE; } - /* do not try to connect to a running instance, or - * open any windows if run as daemon. - */ - if (G_LIKELY (!opt_daemon)) +#ifdef HAVE_DBUS + /* check if we should terminate a running Thunar instance */ + if (G_UNLIKELY (opt_quit)) { - /* determine the current working directory */ - working_directory = g_get_current_dir (); - - /* check if atleast one filename was specified */ - if (G_LIKELY (argc > 1)) + /* try to terminate whatever is running */ + if (!thunar_dbus_client_terminate (&error)) { - /* use the specified filenames */ - filenames = g_strdupv (argv + 1); - } - else - { - /* use the current working directory */ - filenames = g_new (gchar *, 2); - filenames[0] = g_strdup (working_directory); - filenames[1] = NULL; + g_fprintf (stderr, "Thunar: Failed to terminate running instance: %s\n", error->message); + g_error_free (error); + return EXIT_FAILURE; } + return EXIT_SUCCESS; + } +#endif + + /* determine the current working directory */ + working_directory = g_get_current_dir (); + + /* check if atleast one filename was specified, else + * fall back to opening the current working directory + * if daemon mode is not requested. + */ + if (G_LIKELY (argc > 1)) + { + /* use the specified filenames */ + filenames = g_strdupv (argv + 1); + } + else if (!opt_daemon) + { + /* use the current working directory */ + filenames = g_new (gchar *, 2); + filenames[0] = g_strdup (working_directory); + filenames[1] = NULL; + } + #ifdef HAVE_DBUS - /* try to reuse an existing instance */ - if (thunar_dbus_client_launch_files (working_directory, filenames, NULL, NULL)) - { - /* stop any running startup notification */ - gdk_notify_startup_complete (); + /* try to reuse an existing instance (if any files were specified) */ + if (filenames != NULL && thunar_dbus_client_launch_files (working_directory, filenames, NULL, NULL)) + { + /* stop any running startup notification */ + gdk_notify_startup_complete (); - /* that worked, let's get outa here */ - g_free (working_directory); - g_strfreev (filenames); - return EXIT_SUCCESS; - } -#endif + /* that worked, let's get outa here */ + g_free (working_directory); + g_strfreev (filenames); + return EXIT_SUCCESS; } +#endif /* initialize the ThunarVFS library */ thunar_vfs_init (); @@ -139,32 +162,28 @@ main (int argc, char **argv) /* acquire a reference on the global application */ application = thunar_application_get (); +#ifdef HAVE_DBUS + /* setup daemon mode if requested and supported */ + thunar_application_set_daemon (application, opt_daemon); +#endif + /* use the Thunar icon as default for new windows */ gtk_window_set_default_icon_name ("Thunar"); - /* if not in daemon mode, try to process the filenames here */ - if (G_LIKELY (!opt_daemon)) + /* try to process the given filenames (if any files were specified) */ + if (filenames != NULL && !thunar_application_process_filenames (application, working_directory, filenames, NULL, &error)) { - /* try to process the given filenames */ - if (!thunar_application_process_filenames (application, working_directory, filenames, NULL, &error)) - { - g_fprintf (stderr, "Thunar: %s\n", error->message); - g_object_unref (G_OBJECT (application)); - thunar_vfs_shutdown (); - g_error_free (error); - return EXIT_FAILURE; - } - - /* release working directory and filenames */ - g_free (working_directory); - g_strfreev (filenames); - } - else - { - /* run in daemon mode, since we were started by the message bus */ - thunar_application_set_daemon (application, TRUE); + g_fprintf (stderr, "Thunar: %s\n", error->message); + g_object_unref (G_OBJECT (application)); + thunar_vfs_shutdown (); + g_error_free (error); + return EXIT_FAILURE; } + /* release working directory and filenames */ + g_free (working_directory); + g_strfreev (filenames); + /* do not enter the main loop, unless we have atleast one window or we are in daemon mode */ if (thunar_application_has_windows (application) || thunar_application_get_daemon (application)) { diff --git a/thunar/thunar-application.c b/thunar/thunar-application.c index 6fd6c5980348ce68308fe90f5b22df428c4362d7..8c7a2722a40070d0cb354408ecf5b3d3b6e812e8 100644 --- a/thunar/thunar-application.c +++ b/thunar/thunar-application.c @@ -22,6 +22,10 @@ #include <config.h> #endif +#ifdef HAVE_TIME_H +#include <time.h> +#endif + #include <thunar/thunar-application.h> #include <thunar/thunar-dialogs.h> #include <thunar/thunar-gobject-extensions.h> @@ -46,37 +50,41 @@ enum -static void thunar_application_class_init (ThunarApplicationClass *klass); -static void thunar_application_init (ThunarApplication *application); -static void thunar_application_finalize (GObject *object); -static void thunar_application_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); -static void thunar_application_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); -static void thunar_application_collect_and_launch (ThunarApplication *application, - GtkWidget *widget, - const gchar *icon_name, - const gchar *title, - Launcher launcher, - GList *source_path_list, - ThunarVfsPath *target_path, - GClosure *new_files_closure); -static void thunar_application_launch (ThunarApplication *application, - GtkWidget *widget, - const gchar *icon_name, - const gchar *title, - Launcher launcher, - GList *source_path_list, - GList *target_path_list, - GClosure *new_files_closure); -static void thunar_application_window_destroyed (GtkWidget *window, - ThunarApplication *application); -static gboolean thunar_application_show_dialogs (gpointer user_data); -static void thunar_application_show_dialogs_destroy (gpointer user_data); +static void thunar_application_class_init (ThunarApplicationClass *klass); +static void thunar_application_init (ThunarApplication *application); +static void thunar_application_finalize (GObject *object); +static void thunar_application_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void thunar_application_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void thunar_application_collect_and_launch (ThunarApplication *application, + GtkWidget *widget, + const gchar *icon_name, + const gchar *title, + Launcher launcher, + GList *source_path_list, + ThunarVfsPath *target_path, + GClosure *new_files_closure); +static void thunar_application_launch (ThunarApplication *application, + GtkWidget *widget, + const gchar *icon_name, + const gchar *title, + Launcher launcher, + GList *source_path_list, + GList *target_path_list, + GClosure *new_files_closure); +static void thunar_application_open_window_with_role (ThunarApplication *application, + const gchar *role, + ThunarFile *directory, + GdkScreen *screen); +static void thunar_application_window_destroyed (GtkWidget *window, + ThunarApplication *application); +static gboolean thunar_application_show_dialogs (gpointer user_data); +static void thunar_application_show_dialogs_destroy (gpointer user_data); @@ -345,6 +353,35 @@ thunar_application_launch (ThunarApplication *application, +static void +thunar_application_open_window_with_role (ThunarApplication *application, + const gchar *role, + ThunarFile *directory, + GdkScreen *screen) +{ + GtkWidget *window; + + if (G_UNLIKELY (screen == NULL)) + screen = gdk_screen_get_default (); + + /* allocate the window */ + window = g_object_new (THUNAR_TYPE_WINDOW, + "role", role, + "screen", screen, + NULL); + + /* hook up the window */ + thunar_application_take_window (application, GTK_WINDOW (window)); + + /* show the new window */ + gtk_widget_show (window); + + /* change the directory */ + thunar_window_set_current_directory (THUNAR_WINDOW (window), directory); +} + + + static void thunar_application_window_destroyed (GtkWidget *window, ThunarApplication *application) @@ -545,28 +582,16 @@ thunar_application_open_window (ThunarApplication *application, ThunarFile *directory, GdkScreen *screen) { - GtkWidget *window; + gchar *role; g_return_if_fail (THUNAR_IS_APPLICATION (application)); g_return_if_fail (THUNAR_IS_FILE (directory)); g_return_if_fail (screen == NULL || GDK_IS_SCREEN (screen)); - if (G_UNLIKELY (screen == NULL)) - screen = gdk_screen_get_default (); - - /* allocate the window */ - window = g_object_new (THUNAR_TYPE_WINDOW, - "screen", screen, - NULL); - - /* hook up the window */ - thunar_application_take_window (application, GTK_WINDOW (window)); - - /* show the new window */ - gtk_widget_show (window); - - /* change the directory */ - thunar_window_set_current_directory (THUNAR_WINDOW (window), directory); + /* generate a unique role for the new window (for session management) */ + role = g_strdup_printf ("Thunar-%u-%u", (guint) time (NULL), (guint) g_random_int ()); + thunar_application_open_window_with_role (application, role, directory, screen); + g_free (role); } diff --git a/thunar/thunar-dbus-client.c b/thunar/thunar-dbus-client.c index 0f5586e3f54664fb26827e50791a56711df4d3a4..3df2107b7d3315527f2e0fb5843bc605a6202fac 100644 --- a/thunar/thunar-dbus-client.c +++ b/thunar/thunar-dbus-client.c @@ -121,3 +121,75 @@ thunar_dbus_client_launch_files (const gchar *working_directory, return TRUE; } + + +/** + * thunar_dbus_client_terminate: + * @error : Return location for errors or %NULL. + * + * Tells a running Thunar instance, connected to the D-BUS + * session bus, to terminate immediately. + * + * Return value: %TRUE if any instance was terminated, else + * %FALSE and @error is set. + **/ +gboolean +thunar_dbus_client_terminate (GError **error) +{ + DBusConnection *connection; + DBusMessage *message; + DBusMessage *result; + DBusError derror; + + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* initialize the DBusError struct */ + dbus_error_init (&derror); + + /* try to connect to the session bus */ + connection = dbus_bus_get (DBUS_BUS_SESSION, &derror); + if (G_UNLIKELY (connection == NULL)) + { + dbus_set_g_error (error, &derror); + dbus_error_free (&derror); + return FALSE; + } + + /* generate the LaunchFiles() method (disable activation!) */ + message = dbus_message_new_method_call ("org.xfce.Thunar", "/org/xfce/FileManager", "org.xfce.Thunar", "Terminate"); + dbus_message_set_auto_start (message, FALSE); + + /* send the message and release our references on connection and message */ + result = dbus_connection_send_with_reply_and_block (connection, message, 2000, &derror); + dbus_message_unref (message); + + /* check if no reply was received */ + if (G_UNLIKELY (result == NULL)) + { + /* check if there was nothing to terminate */ + if (dbus_error_has_name (&derror, DBUS_ERROR_NAME_HAS_NO_OWNER)) + { + dbus_error_free (&derror); + return TRUE; + } + + /* Looks like there was a real error */ + dbus_set_g_error (error, &derror); + dbus_error_free (&derror); + return FALSE; + } + + /* but maybe we received an error */ + if (dbus_message_get_type (result) == DBUS_MESSAGE_TYPE_ERROR) + { + dbus_set_error_from_message (&derror, result); + dbus_set_g_error (error, &derror); + dbus_message_unref (result); + dbus_error_free (&derror); + return FALSE; + } + + /* let's asume that it worked */ + dbus_message_unref (result); + return TRUE; +} diff --git a/thunar/thunar-dbus-client.h b/thunar/thunar-dbus-client.h index e053ab3c9f41fa70b2cd53ae98078a9ec156a00c..449a3c8046a0f430cee002135ff4f66aaf22331d 100644 --- a/thunar/thunar-dbus-client.h +++ b/thunar/thunar-dbus-client.h @@ -29,6 +29,8 @@ gboolean thunar_dbus_client_launch_files (const gchar *working_directory, GdkScreen *screen, GError **error); +gboolean thunar_dbus_client_terminate (GError **error); + G_END_DECLS; #endif /* !__THUNAR_DBUS_CLIENT_H__ */ diff --git a/thunar/thunar-dbus-service-infos.xml b/thunar/thunar-dbus-service-infos.xml index 64cd668c8d4f47a3da149c5c91a07c48f178710a..4959fc1ff69a6ae8431ebeb9a41da33f3cae2e41 100644 --- a/thunar/thunar-dbus-service-infos.xml +++ b/thunar/thunar-dbus-service-infos.xml @@ -110,5 +110,15 @@ <arg direction="in" name="filenames" type="as" /> <arg direction="in" name="display" type="s" /> </method> + + <!-- + Terminate () : VOID + + Tells a running Thunar instance to terminate immediately. + --> + <method name="Terminate"> + </method> </interface> </node> + +<!-- vi:set ts=2 sw=2 et ai: --> diff --git a/thunar/thunar-dbus-service.c b/thunar/thunar-dbus-service.c index c9d04d74c70a7b90f379043afbadf435d94ccffd..46616d596c4622a77a3d1ffbc0134334551e559a 100644 --- a/thunar/thunar-dbus-service.c +++ b/thunar/thunar-dbus-service.c @@ -65,6 +65,8 @@ static gboolean thunar_dbus_service_launch_files (ThunarDBusServi gchar **filenames, const gchar *display, GError **error); +static gboolean thunar_dbus_service_terminate (ThunarDBusService *dbus_service, + GError **error); @@ -380,4 +382,17 @@ thunar_dbus_service_launch_files (ThunarDBusService *dbus_service, +static gboolean +thunar_dbus_service_terminate (ThunarDBusService *dbus_service, + GError **error) +{ + /* leave the Gtk main loop as soon as possible */ + gtk_main_quit (); + + /* we cannot fail */ + return TRUE; +} + + + #include <thunar/thunar-dbus-service-infos.h>