[gtk+/wip/csoriano/gtkpathbar_rework] gtkpathbar: listen to file changes and update pathbar



commit 377962ec2f467cf3c5e10cff7684764e87f76e42
Author: Carlos Soriano <csoriano gnome org>
Date:   Wed Mar 4 19:13:57 2015 +0100

    gtkpathbar: listen to file changes and update pathbar
    
    It's something we have more or less for free in Nautilus
    given that we have all the backend in NautilusFile.
    
    Here we have to do it ourselves, but we fix a long old bug,
    and one of the most confusing things of gtkpathbar.

 gtk/gtkpathbar.c |  230 +++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 210 insertions(+), 20 deletions(-)
---
diff --git a/gtk/gtkpathbar.c b/gtk/gtkpathbar.c
index 2eddd1b..7110392 100644
--- a/gtk/gtkpathbar.c
+++ b/gtk/gtkpathbar.c
@@ -41,6 +41,8 @@ struct _GtkPathBarPrivate
 
   GdkWindow *event_window;
 
+  GFile *current_path;
+
   GList *button_list;
   GList *first_scrolled_button;
   GtkWidget *up_slider_button;
@@ -91,6 +93,8 @@ struct _ButtonData
   gboolean is_root;
   char *dir_name;
   GFile *file;
+  GFileMonitor *monitor;
+  guint file_changed_signal_id;
   GtkWidget *image;
   GtkWidget *label;
   GCancellable *cancellable;
@@ -143,9 +147,9 @@ static void gtk_path_bar_style_updated            (GtkWidget        *widget);
 static void gtk_path_bar_screen_changed           (GtkWidget        *widget,
                                                   GdkScreen        *previous_screen);
 static void gtk_path_bar_check_icon_theme         (GtkPathBar       *path_bar);
-static void gtk_path_bar_update_button_appearance (GtkPathBar       *path_bar,
-                                                  ButtonData       *button_data,
-                                                  gboolean          current_dir);
+static void gtk_path_bar_update_button_appearance_and_state (ButtonData       *button_data,
+                                                             gboolean          current_dir);
+static void gtk_path_bar_update_button_appearance (ButtonData       *button_data);
 
 static void
 gtk_path_bar_init (GtkPathBar *path_bar)
@@ -1160,13 +1164,11 @@ reload_icons (GtkPathBar *path_bar)
   for (list = path_bar->priv->button_list; list; list = list->next)
     {
       ButtonData *button_data;
-      gboolean current_dir;
 
       button_data = BUTTON_DATA (list->data);
       if (button_data->type != NORMAL_BUTTON || button_data->is_root)
        {
-         current_dir = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_data->button));
-         gtk_path_bar_update_button_appearance (path_bar, button_data, current_dir);
+         gtk_path_bar_update_button_appearance (button_data);
        }
     }
   
@@ -1362,7 +1364,12 @@ static void
 button_data_free (ButtonData *button_data)
 {
   if (button_data->file)
-    g_object_unref (button_data->file);
+    {
+      g_signal_handler_disconnect (button_data->file,
+                                   button_data->file_changed_signal_id);
+      g_object_unref (button_data->monitor);
+      g_object_unref (button_data->file);
+    }
   button_data->file = NULL;
 
   g_free (button_data->dir_name);
@@ -1383,9 +1390,7 @@ get_dir_name (ButtonData *button_data)
 }
 
 static void
-gtk_path_bar_update_button_appearance (GtkPathBar *path_bar,
-                                      ButtonData *button_data,
-                                      gboolean    current_dir)
+gtk_path_bar_update_button_appearance (ButtonData *button_data)
 {
   const gchar *dir_name = get_dir_name (button_data);
   GIcon *icon;
@@ -1404,13 +1409,19 @@ gtk_path_bar_update_button_appearance (GtkPathBar *path_bar,
     {
       gtk_widget_hide (GTK_WIDGET (button_data->image));
     }
+}
 
-  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_data->button)) != current_dir)
-    {
-      button_data->ignore_changes = TRUE;
-      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button_data->button), current_dir);
-      button_data->ignore_changes = FALSE;
-    }
+static void
+gtk_path_bar_update_button_appearance_and_state (ButtonData *button_data,
+                                                gboolean    current_dir)
+{
+       gtk_path_bar_update_button_appearance (button_data);
+
+        if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_data->button)) != current_dir) {
+                button_data->ignore_changes = TRUE;
+                gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button_data->button), current_dir);
+                button_data->ignore_changes = FALSE;
+        }
 }
 
 gboolean
@@ -1512,6 +1523,175 @@ button_drag_data_get_cb (GtkWidget        *widget,
   g_free (uris[0]);
 }
 
+static void
+gtk_path_bar_file_changed_on_get_info (GObject      *object,
+                                       GAsyncResult *result,
+                                       gpointer      user_data)
+{
+  const gchar *display_name;
+  ButtonData *button_data;
+  GFileInfo *info;
+  GFile *file;
+
+  button_data = BUTTON_DATA (user_data);
+  file = G_FILE (object);
+
+  info = g_file_query_info_finish (file, result, NULL);
+  if (!info)
+    {
+      g_print ("no info for %s\n", g_file_get_uri (file));
+      return;
+    }
+  display_name = g_file_info_get_display_name (info);
+
+  if (g_strcmp0 (display_name, button_data->dir_name) != 0)
+    {
+      g_free (button_data->dir_name);
+      button_data->dir_name = g_strdup (display_name);
+    }
+
+  gtk_path_bar_update_button_appearance (button_data);
+
+  g_object_unref (info);
+}
+
+static void
+gtk_path_bar_on_file_changed (GFileMonitor      *monitor,
+                              GFile             *file,
+                              GFile             *other_file,
+                              GFileMonitorEvent  event_type,
+                              gpointer          *user_data)
+{
+  GFile *location, *current_location, *parent, *button_parent;
+  ButtonData *innermost_button_data, *button_data;
+  GtkPathBar *path_bar;
+  gboolean renamed, child;
+
+  button_data = BUTTON_DATA (user_data);
+  g_print ("gtk_path_bar_on_file_changed %s, %s\n", g_file_get_uri (file), g_file_get_uri 
(button_data->file));
+  path_bar = (GtkPathBar *) gtk_widget_get_ancestor (button_data->button,
+                                                     GTK_TYPE_PATH_BAR);
+  if (path_bar == NULL)
+    {
+      return;
+    }
+
+  innermost_button_data = g_list_nth_data(path_bar->priv->button_list, 0);
+
+  g_assert (path_bar->priv->current_path!= NULL);
+  g_assert (innermost_button_data != NULL);
+
+  /* There's an actual change in the name or location of the file reflected as
+   * different GFile between the one in the button_data and the one that were monitoring
+   * that was the same file at the time of creation of the button_data. */
+      g_print ("event type %i\n", event_type);
+  if (!g_file_equal (button_data->file, file))
+    {
+      parent = g_file_get_parent (file);
+      button_parent = g_file_get_parent (button_data->file);
+
+      renamed = (parent != NULL && button_parent != NULL) &&
+                g_file_equal (parent, button_parent);
+
+      if (parent != NULL)
+        {
+          g_object_unref (parent);
+        }
+      if (button_parent != NULL)
+        {
+          g_object_unref (button_parent);
+        }
+
+      if (renamed)
+        {
+          button_data->file= g_object_ref (file);
+        }
+      else
+        {
+          /* The file has been moved.
+           * If it was below the currently displayed location, remove it.
+           * If it was not below the currently displayed location, update the path bar
+           */
+          child = g_file_has_prefix (button_data->file,
+                                     path_bar->priv->current_path);
+
+          if (child)
+            {
+              /* moved file inside current path hierarchy */
+#if 0
+              location = g_file_get_parent (button_data->file);
+#endif
+              current_location = g_object_ref (path_bar->priv->current_path);
+            }
+          else
+            {
+              /* moved current path, or file outside current path hierarchy.
+               * Update path bar to new locations.
+               */
+              current_location = button_data->file;
+            }
+
+#if 0
+          nautilus_path_bar_update_path (path_bar, location);
+#endif
+          _gtk_path_bar_set_file (path_bar, current_location, TRUE);
+          g_object_unref (current_location);
+          return;
+        }
+    }
+#if 0
+  else if (nautilus_file_is_gone (file))
+    {
+      gint idx, position;
+
+      /* if the current or a parent location are gone, clear all the buttons,
+       * the view will set the new path.
+       */
+      current_location = nautilus_file_get_location (button_data->file);
+
+      if (g_file_has_prefix (current_location, location) ||
+          g_file_equal (current_location, location)) {
+        nautilus_path_bar_clear_buttons (path_bar);
+      } else if (g_file_has_prefix (location, current_location)) {
+        /* remove this and the following buttons */
+        position = g_list_position (path_bar->priv->button_list,
+                  g_list_find (path_bar->priv->button_list, button_data));
+
+        if (position != -1) {
+          for (idx = 0; idx <= position; idx++) {
+            gtk_container_remove (GTK_CONTAINER (path_bar),
+                      BUTTON_DATA (path_bar->priv->button_list->data)->button);
+          }
+        }
+      }
+
+      g_object_unref (current_location);
+      g_object_unref (location);
+      return;
+    }
+#endif
+
+  /* MOUNTs use the GMount as the name, so don't update for those */
+  if (button_data->type != MOUNT_BUTTON)
+    {
+      if (event_type == G_FILE_MONITOR_EVENT_CREATED ||
+          event_type == G_FILE_MONITOR_EVENT_MOVED)
+        {
+          g_file_query_info_async (file,
+                                   "standard::display-name",
+                                   G_FILE_QUERY_INFO_NONE,
+                                   G_PRIORITY_DEFAULT,
+                                   NULL,
+                                   gtk_path_bar_file_changed_on_get_info,
+                                   button_data);
+        }
+    }
+  else
+    {
+      gtk_path_bar_update_button_appearance (button_data);
+    }
+}
+
 static ButtonData *
 make_directory_button (GtkPathBar  *path_bar,
                       const char  *dir_name,
@@ -1557,10 +1737,15 @@ make_directory_button (GtkPathBar  *path_bar,
   button_data->file = g_object_ref (file);
   button_data->file_is_hidden = file_is_hidden;
 
+  button_data->monitor = g_file_monitor (file, G_FILE_MONITOR_SEND_MOVED, NULL, NULL);
+  button_data->file_changed_signal_id = g_signal_connect (button_data->monitor, "changed",
+                                                         G_CALLBACK (gtk_path_bar_on_file_changed),
+                                                         button_data);
+
   gtk_container_add (GTK_CONTAINER (button_data->button), child);
   gtk_widget_show_all (button_data->button);
 
-  gtk_path_bar_update_button_appearance (path_bar, button_data, current_dir);
+  gtk_path_bar_update_button_appearance_and_state (button_data, current_dir);
 
   g_signal_connect (button_data->button, "clicked",
                    G_CALLBACK (button_clicked_cb),
@@ -1602,9 +1787,8 @@ gtk_path_bar_check_parent_path (GtkPathBar         *path_bar,
     {
       for (list = path_bar->priv->button_list; list; list = list->next)
        {
-         gtk_path_bar_update_button_appearance (path_bar,
-                                                BUTTON_DATA (list->data),
-                                                (list == current_path) ? TRUE : FALSE);
+         gtk_path_bar_update_button_appearance_and_state (BUTTON_DATA (list->data),
+                                                           (list == current_path) ? TRUE : FALSE);
        }
 
       if (!gtk_widget_get_child_visible (BUTTON_DATA (current_path->data)->button))
@@ -1741,6 +1925,12 @@ _gtk_path_bar_set_file (GtkPathBar *path_bar,
   g_return_if_fail (GTK_IS_PATH_BAR (path_bar));
   g_return_if_fail (G_IS_FILE (file));
 
+  if (path_bar->priv->current_path != NULL)
+    {
+      g_object_unref (path_bar->priv->current_path);
+    }
+  path_bar->priv->current_path = g_object_ref (file);
+
   /* Check whether the new path is already present in the pathbar as buttons.
    * This could be a parent directory or a previous selected subdirectory.
    */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]