[Xfce4-commits] <garcon:master> Merge consecutive file change events using an idle handler.

Jannis Pohlmann noreply at xfce.org
Fri Nov 5 19:06:02 CET 2010


Updating branch refs/heads/master
         to e9cf76d8adcbc9eceab9a3c00a8213bbb54b6891 (commit)
       from 53a350d9380b89e062c7f122c16a493e972341ce (commit)

commit e9cf76d8adcbc9eceab9a3c00a8213bbb54b6891
Author: Jannis Pohlmann <jannis at xfce.org>
Date:   Fri Nov 5 19:01:31 2010 +0100

    Merge consecutive file change events using an idle handler.
    
    In combination with handling G_FILE_MONITOR_EVENT_CREATED, this properly
    picks up all changes to application directories now. An idle handler is
    used together with a GFile list to avoid processing the same file
    multiple times, e.g. when receiving three consecutive CREATED,
    CHANGES_DONE and ATTRIBUTE_CHANGED events.

 garcon/garcon-menu.c |   99 +++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 90 insertions(+), 9 deletions(-)

diff --git a/garcon/garcon-menu.c b/garcon/garcon-menu.c
index b4c3b2e..8a4cd30 100644
--- a/garcon/garcon-menu.c
+++ b/garcon/garcon-menu.c
@@ -221,6 +221,10 @@ struct _GarconMenuPrivate
   /* Shared menu item cache */
   GarconMenuItemCache *cache;
 
+  /* List to merge consecutive file changes into a a single event */
+  GList               *changed_files;
+  guint                file_changed_idle;
+
   /* Flag for marking custom path menus */
   guint                uses_custom_path : 1;
 };
@@ -336,6 +340,7 @@ garcon_menu_init (GarconMenu *menu)
   menu->priv->parent = NULL;
   menu->priv->pool = garcon_menu_item_pool_new ();
   menu->priv->uses_custom_path = TRUE;
+  menu->priv->changed_files = NULL;
 
   /* Take reference on the menu item cache */
   menu->priv->cache = garcon_menu_item_cache_get_default ();
@@ -1760,6 +1765,12 @@ garcon_menu_start_monitoring (GarconMenu *menu)
   /* Let only the root menu monitor menu files, merge files/directories and app dirs */
   if (menu->priv->parent == NULL)
     {
+      /* Create the list for merging consecutive file change events */
+      menu->priv->changed_files = NULL;
+
+      /* Reset the idle source for handling file changes */
+      menu->priv->file_changed_idle = 0;
+
       garcon_menu_monitor_menu_files (menu);
 
       garcon_menu_monitor_files (menu, menu->priv->merge_files, 
@@ -1803,6 +1814,15 @@ garcon_menu_stop_monitoring (GarconMenu *menu)
   /* Free the monitor list */
   g_list_free (menu->priv->monitors);
   menu->priv->monitors = NULL;
+
+  /* Stop the idle source for handling file changes from being invoked */
+  if (menu->priv->file_changed_idle != 0)
+    g_source_remove (menu->priv->file_changed_idle);
+
+  /* Free the hash table for merging consecutive file change events */
+  g_list_foreach (menu->priv->changed_files, (GFunc) g_object_unref, NULL);
+  g_list_free (menu->priv->changed_files);
+  menu->priv->changed_files = NULL;
 }
 
 
@@ -2100,23 +2120,24 @@ garcon_menu_merge_dir_changed (GarconMenu       *menu,
 
 
 
-static void
-garcon_menu_app_dir_changed (GarconMenu       *menu,
-                             GFile            *file,
-                             GFile            *other_file,
-                             GFileMonitorEvent event_type,
-                             GFileMonitor     *monitor)
+static gboolean
+garcon_menu_process_file_changes (GarconMenu *menu)
 {
   GarconMenuItem *item;
   GFileType       file_type;
   gboolean        affects_the_outside = FALSE;
+  gboolean        stop_processing = FALSE;
+  GFile          *file;
+  GList          *lp;
   gchar          *path;
 
-  g_return_if_fail (GARCON_IS_MENU (menu));
-  g_return_if_fail (menu->priv->parent == NULL);
+  g_return_val_if_fail (GARCON_IS_MENU (menu), FALSE);
+  g_return_val_if_fail (menu->priv->parent == NULL, FALSE);
 
-  if (event_type == G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT)
+  for (lp = menu->priv->changed_files; !stop_processing && lp != NULL; lp = lp->next)
     {
+      file = G_FILE (lp->data);
+
       /* query the type of the changed file */
       file_type = g_file_query_file_type (file, G_FILE_QUERY_INFO_NONE, NULL);
 
@@ -2129,6 +2150,7 @@ garcon_menu_app_dir_changed (GarconMenu       *menu,
            * this is not trivial to handle, so we simply enforce a
            * menu reload to deal with the changes */
           g_signal_emit (menu, menu_signals[RELOAD_REQUIRED], 0);
+          stop_processing = TRUE;
         }
       else
         {
@@ -2149,6 +2171,7 @@ garcon_menu_app_dir_changed (GarconMenu       *menu,
                            * more complicated than one would first think, so just
                            * enforce a complete menu reload for now */
                           g_signal_emit (menu, menu_signals[RELOAD_REQUIRED], 0);
+                          stop_processing = TRUE;
                         }
                       else
                         {
@@ -2172,6 +2195,7 @@ garcon_menu_app_dir_changed (GarconMenu       *menu,
                        * tricky, so, again, we just enfore a menu reload until we have 
                        * something better */
                       g_signal_emit (menu, menu_signals[RELOAD_REQUIRED], 0);
+                      stop_processing = TRUE;
                     }
                 }
               else
@@ -2180,11 +2204,68 @@ garcon_menu_app_dir_changed (GarconMenu       *menu,
                    * stuff is complicated. for now, simply enforce a complete reload 
                    * of the menu structure */
                   g_signal_emit (menu, menu_signals[RELOAD_REQUIRED], 0);
+                  stop_processing = TRUE;
                 }
             }
           g_free (path);
         }
     }
+
+  /* reset the changed files list, all events processed */
+  g_list_foreach (menu->priv->changed_files, (GFunc) g_object_unref, NULL);
+  g_list_free (menu->priv->changed_files);
+  menu->priv->changed_files = NULL;
+
+  /* reset the idle source ID */
+  menu->priv->file_changed_idle = 0;
+
+  /* remove the idle source */
+  return FALSE;
+}
+
+
+
+static gint
+compare_files (gconstpointer a,
+               gconstpointer b)
+{
+  return g_file_equal (G_FILE (a), G_FILE (b)) ? 0 : 1;
+}
+
+
+
+static void
+garcon_menu_app_dir_changed (GarconMenu       *menu,
+                             GFile            *file,
+                             GFile            *other_file,
+                             GFileMonitorEvent event_type,
+                             GFileMonitor     *monitor)
+{
+  GarconMenuItem *item;
+  GFileType       file_type;
+
+  g_return_if_fail (GARCON_IS_MENU (menu));
+  g_return_if_fail (menu->priv->parent == NULL);
+
+  if (event_type == G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT
+      || event_type == G_FILE_MONITOR_EVENT_CREATED 
+      || event_type == G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED)
+    {
+      /* add the file to the changed files queue if we have no change event for
+       * it queued yet */
+      if (g_list_find_custom (menu->priv->changed_files, file, compare_files) == NULL)
+        {
+          menu->priv->changed_files = g_list_append (menu->priv->changed_files, 
+                                                     g_object_ref (file));
+
+          /* register the idle handler if it is not active yet */
+          if (menu->priv->file_changed_idle == 0)
+            {
+              menu->priv->file_changed_idle = 
+                g_idle_add ((GSourceFunc) garcon_menu_process_file_changes, menu);
+            }
+        }
+    }
   else if (event_type == G_FILE_MONITOR_EVENT_DELETED)
     {
       /* query the type of the changed file */



More information about the Xfce4-commits mailing list