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