From c38ea19ad1b223b08d854660a67fa365605617a3 Mon Sep 17 00:00:00 2001 From: Benedikt Meurer <benny@xfce.org> Date: Thu, 30 Mar 2006 23:38:23 +0000 Subject: [PATCH] 2006-03-30 Benedikt Meurer <benny@xfce.org> * thunar/thunar-folder.c: Reload the folder when the corresponding file changes. Use the ThunarFileMonitor to stay informed about changes to the corresponding rather than connecting additional signal handlers to the file. * plugins/thunar-uca/thunar-uca-provider.c: Schedule a "changed" event for the working directory once the custom command terminates. Bug #1625. (Old svn revision: 20653) --- ChangeLog | 10 +++ plugins/thunar-uca/thunar-uca-provider.c | 104 ++++++++++++++++++++++- thunar/thunar-folder.c | 75 ++++++++-------- 3 files changed, 149 insertions(+), 40 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2e28c74e1..10232fdd5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2006-03-30 Benedikt Meurer <benny@xfce.org> + + * thunar/thunar-folder.c: Reload the folder when the corresponding + file changes. Use the ThunarFileMonitor to stay informed about + changes to the corresponding rather than connecting additional + signal handlers to the file. + * plugins/thunar-uca/thunar-uca-provider.c: Schedule a "changed" + event for the working directory once the custom command + terminates. Bug #1625. + 2006-03-28 Benedikt Meurer <benny@xfce.org> * configure.in.in: Check for limits.h and localeconv(). diff --git a/plugins/thunar-uca/thunar-uca-provider.c b/plugins/thunar-uca/thunar-uca-provider.c index 1d44e1e88..85983b95a 100644 --- a/plugins/thunar-uca/thunar-uca-provider.c +++ b/plugins/thunar-uca/thunar-uca-provider.c @@ -22,7 +22,7 @@ #include <config.h> #endif -#include <glib/gi18n-lib.h> +#include <thunar-vfs/thunar-vfs.h> #include <thunar-uca/thunar-uca-chooser.h> #include <thunar-uca/thunar-uca-context.h> @@ -46,6 +46,10 @@ static GList *thunar_uca_provider_get_folder_actions (ThunarxMenuProvider ThunarxFileInfo *folder); static void thunar_uca_provider_activated (ThunarUcaProvider *uca_provider, GtkAction *action); +static void thunar_uca_provider_child_watch (GPid pid, + gint status, + gpointer user_data); +static void thunar_uca_provider_child_watch_destroy (gpointer user_data); @@ -60,6 +64,13 @@ struct _ThunarUcaProvider ThunarUcaModel *model; gint last_action_id; /* used to generate unique action names */ + + /* child watch support for the last spawned child process + * to be able to refresh the folder contents after the + * child process has terminated. + */ + gchar *child_watch_path; + gint child_watch_id; }; @@ -118,6 +129,10 @@ thunar_uca_provider_init (ThunarUcaProvider *uca_provider) { /* grab a reference on the default model */ uca_provider->model = thunar_uca_model_get_default (); + + /* initialize child watch support */ + uca_provider->child_watch_path = NULL; + uca_provider->child_watch_id = -1; } @@ -126,6 +141,18 @@ static void thunar_uca_provider_finalize (GObject *object) { ThunarUcaProvider *uca_provider = THUNAR_UCA_PROVIDER (object); + GSource *source; + + /* give up maintaince of any pending child watch */ + if (G_UNLIKELY (uca_provider->child_watch_id >= 0)) + { + /* reset the callback function to g_spawn_close_pid() so the plugin can be + * safely unloaded and the child will still not become a zombie afterwards. + * This also resets the child_watch_id and child_watch_path properties. + */ + source = g_main_context_find_source_by_id (NULL, uca_provider->child_watch_id); + g_source_set_callback (source, (GSourceFunc) g_spawn_close_pid, NULL, NULL); + } /* drop our reference on the model */ g_object_unref (G_OBJECT (uca_provider->model)); @@ -275,6 +302,7 @@ thunar_uca_provider_activated (ThunarUcaProvider *uca_provider, GtkWidget *dialog; GtkWidget *window; gboolean succeed; + GSource *source; GError *error = NULL; GList *files; gchar **argv; @@ -283,6 +311,7 @@ thunar_uca_provider_activated (ThunarUcaProvider *uca_provider, gchar *label; gchar *uri; gint argc; + gint pid; g_return_if_fail (THUNAR_UCA_IS_PROVIDER (uca_provider)); g_return_if_fail (GTK_IS_ACTION (action)); @@ -331,7 +360,30 @@ thunar_uca_provider_activated (ThunarUcaProvider *uca_provider, /* spawn the command on the window's screen */ succeed = gdk_spawn_on_screen (gtk_widget_get_screen (GTK_WIDGET (window)), working_directory, - argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &error); + argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH, + NULL, NULL, &pid, &error); + + /* check if we succeed */ + if (G_LIKELY (succeed)) + { + /* check if we already have a child watch */ + if (G_UNLIKELY (uca_provider->child_watch_id >= 0)) + { + /* reset the callback function to g_spawn_close_pid() so the plugin can be + * safely unloaded and the child will still not become a zombie afterwards. + */ + source = g_main_context_find_source_by_id (NULL, uca_provider->child_watch_id); + g_source_set_callback (source, (GSourceFunc) g_spawn_close_pid, NULL, NULL); + } + + /* schedule the new child watch */ + uca_provider->child_watch_id = g_child_watch_add_full (G_PRIORITY_LOW, pid, thunar_uca_provider_child_watch, + uca_provider, thunar_uca_provider_child_watch_destroy); + + /* take over ownership of the working directory as child watch path */ + uca_provider->child_watch_path = working_directory; + working_directory = NULL; + } /* cleanup */ g_free (working_directory); @@ -358,4 +410,52 @@ thunar_uca_provider_activated (ThunarUcaProvider *uca_provider, +static void +thunar_uca_provider_child_watch (GPid pid, + gint status, + gpointer user_data) +{ + ThunarUcaProvider *uca_provider = THUNAR_UCA_PROVIDER (user_data); + ThunarVfsMonitor *monitor; + ThunarVfsPath *path; + + GDK_THREADS_ENTER (); + + /* verify that we still have a valid child_watch_path */ + if (G_LIKELY (uca_provider->child_watch_path != NULL)) + { + /* determine the corresponding ThunarVfsPath */ + path = thunar_vfs_path_new (uca_provider->child_watch_path, NULL); + if (G_LIKELY (path != NULL)) + { + /* schedule a changed notification on the path */ + monitor = thunar_vfs_monitor_get_default (); + thunar_vfs_monitor_feed (monitor, THUNAR_VFS_MONITOR_EVENT_CHANGED, path); + g_object_unref (G_OBJECT (monitor)); + + /* release the ThunarVfsPath */ + thunar_vfs_path_unref (path); + } + } + + /* need to cleanup */ + g_spawn_close_pid (pid); + + GDK_THREADS_LEAVE (); +} + + + +static void +thunar_uca_provider_child_watch_destroy (gpointer user_data) +{ + ThunarUcaProvider *uca_provider = THUNAR_UCA_PROVIDER (user_data); + + /* reset child watch id and path */ + g_free (uca_provider->child_watch_path); + uca_provider->child_watch_path = NULL; + uca_provider->child_watch_id = -1; +} + + diff --git a/thunar/thunar-folder.c b/thunar/thunar-folder.c index 355a49198..b7a9a4eae 100644 --- a/thunar/thunar-folder.c +++ b/thunar/thunar-folder.c @@ -60,9 +60,8 @@ static gboolean thunar_folder_infos_ready (ThunarVfsJob ThunarFolder *folder); static void thunar_folder_finished (ThunarVfsJob *job, ThunarFolder *folder); -static void thunar_folder_corresponding_file_destroy (ThunarFile *file, - ThunarFolder *folder); -static void thunar_folder_corresponding_file_renamed (ThunarFile *file, +static void thunar_folder_file_changed (ThunarFileMonitor *file_monitor, + ThunarFile *file, ThunarFolder *folder); static void thunar_folder_file_destroyed (ThunarFileMonitor *file_monitor, ThunarFile *file, @@ -162,7 +161,9 @@ thunar_folder_class_init (ThunarFolderClass *klass) **/ g_object_class_install_property (gobject_class, PROP_LOADING, - g_param_spec_boolean ("loading", "loading", "loading", + g_param_spec_boolean ("loading", + "loading", + "loading", FALSE, EXO_PARAM_READABLE)); @@ -223,6 +224,7 @@ thunar_folder_init (ThunarFolder *folder) { /* connect to the ThunarFileMonitor instance */ folder->file_monitor = thunar_file_monitor_get_default (); + g_signal_connect (G_OBJECT (folder->file_monitor), "file-changed", G_CALLBACK (thunar_folder_file_changed), folder); g_signal_connect (G_OBJECT (folder->file_monitor), "file-destroyed", G_CALLBACK (thunar_folder_file_destroyed), folder); /* connect to the file alteration monitor */ @@ -237,7 +239,7 @@ thunar_folder_finalize (GObject *object) ThunarFolder *folder = THUNAR_FOLDER (object); /* disconnect from the ThunarFileMonitor instance */ - g_signal_handlers_disconnect_by_func (G_OBJECT (folder->file_monitor), thunar_folder_file_destroyed, folder); + g_signal_handlers_disconnect_matched (G_OBJECT (folder->file_monitor), G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, folder); g_object_unref (G_OBJECT (folder->file_monitor)); /* disconnect from the file alteration monitor */ @@ -257,7 +259,6 @@ thunar_folder_finalize (GObject *object) if (G_LIKELY (folder->corresponding_file != NULL)) { /* drop the reference */ - g_signal_handlers_disconnect_matched (G_OBJECT (folder->corresponding_file), G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, folder); g_object_set_qdata (G_OBJECT (folder->corresponding_file), thunar_folder_quark, NULL); g_object_unref (G_OBJECT (folder->corresponding_file)); } @@ -425,29 +426,20 @@ thunar_folder_finished (ThunarVfsJob *job, static void -thunar_folder_corresponding_file_destroy (ThunarFile *file, - ThunarFolder *folder) -{ - g_return_if_fail (THUNAR_IS_FILE (file)); - g_return_if_fail (THUNAR_IS_FOLDER (folder)); - g_return_if_fail (folder->corresponding_file == file); - - /* the folder is useless now */ - gtk_object_destroy (GTK_OBJECT (folder)); -} - - - -static void -thunar_folder_corresponding_file_renamed (ThunarFile *file, - ThunarFolder *folder) +thunar_folder_file_changed (ThunarFileMonitor *file_monitor, + ThunarFile *file, + ThunarFolder *folder) { g_return_if_fail (THUNAR_IS_FILE (file)); g_return_if_fail (THUNAR_IS_FOLDER (folder)); - g_return_if_fail (folder->corresponding_file == file); + g_return_if_fail (THUNAR_IS_FILE_MONITOR (file_monitor)); - /* reload the folder contents as all paths need to be updated */ - thunar_folder_reload (folder); + /* check if the corresponding file changed... */ + if (G_UNLIKELY (folder->corresponding_file == file)) + { + /* ...and if so, reload the folder */ + thunar_folder_reload (folder); + } } @@ -464,19 +456,28 @@ thunar_folder_file_destroyed (ThunarFileMonitor *file_monitor, g_return_if_fail (THUNAR_IS_FOLDER (folder)); g_return_if_fail (THUNAR_IS_FILE_MONITOR (file_monitor)); - /* check if we have that file */ - lp = g_list_find (folder->files, file); - if (G_LIKELY (lp != NULL)) + /* check if the corresponding file was destroyed */ + if (G_UNLIKELY (folder->corresponding_file == file)) + { + /* the folder is useless now */ + gtk_object_destroy (GTK_OBJECT (folder)); + } + else { - /* remove the file from our list */ - folder->files = g_list_delete_link (folder->files, lp); + /* check if we have that file */ + lp = g_list_find (folder->files, file); + if (G_LIKELY (lp != NULL)) + { + /* remove the file from our list */ + folder->files = g_list_delete_link (folder->files, lp); - /* tell everybody that the file is gone */ - files.data = file; files.next = files.prev = NULL; - g_signal_emit (G_OBJECT (folder), folder_signals[FILES_REMOVED], 0, &files); + /* tell everybody that the file is gone */ + files.data = file; files.next = files.prev = NULL; + g_signal_emit (G_OBJECT (folder), folder_signals[FILES_REMOVED], 0, &files); - /* drop our reference to the file */ - g_object_unref (G_OBJECT (file)); + /* drop our reference to the file */ + g_object_unref (G_OBJECT (file)); + } } } @@ -587,9 +588,7 @@ thunar_folder_get_for_file (ThunarFile *file) /* drop the floating reference */ exo_gtk_object_ref_sink (GTK_OBJECT (folder)); - g_signal_connect (G_OBJECT (file), "destroy", G_CALLBACK (thunar_folder_corresponding_file_destroy), folder); - g_signal_connect (G_OBJECT (file), "renamed", G_CALLBACK (thunar_folder_corresponding_file_renamed), folder); - + /* connect the folder to the file */ g_object_set_qdata (G_OBJECT (file), thunar_folder_quark, folder); /* schedule the loading of the folder */ -- GitLab