[gnome-menus] libmenu: Do not send multiple notifications for one file change



commit 5092245c4fe1449bee93b8923e370d7db339f40f
Author: Vincent Untz <vuntz gnome org>
Date:   Wed Oct 6 15:45:31 2010 +0200

    libmenu: Do not send multiple notifications for one file change
    
    We emit notifications in the idle loop, which enables us to compress
    multiple notifications: this way, we can check if there is already a
    notification for a directory.
    
    We do this at the CachedDir level because it enables us to get one
    notification for a file rename, for example. But we also need it at the
    MenuLayout level to be sure to compress notifications accross multiple
    directories. It could be argued that we only need the latter, but I like
    it this way :-)
    
    https://bugzilla.gnome.org/show_bug.cgi?id=172046

 libmenu/entry-directories.c |   70 +++++++++++++++++++++++++++++++++++++++++-
 libmenu/menu-layout.c       |   35 +++++++++++++++++----
 2 files changed, 96 insertions(+), 9 deletions(-)
---
diff --git a/libmenu/entry-directories.c b/libmenu/entry-directories.c
index b96b845..ee22a55 100644
--- a/libmenu/entry-directories.c
+++ b/libmenu/entry-directories.c
@@ -74,6 +74,8 @@ struct CachedDirMonitor
   gpointer                   user_data;
 };
 
+static void     cached_dir_add_reference          (CachedDir *dir);
+static void     cached_dir_remove_reference       (CachedDir *dir);
 static void     cached_dir_free                   (CachedDir  *dir);
 static gboolean cached_dir_load_entries_recursive (CachedDir  *dir,
                                                    const char *dirname);
@@ -363,6 +365,9 @@ cached_dir_remove_subdir (CachedDir  *dir,
   return FALSE;
 }
 
+static guint   monitors_idle_handler = 0;
+static GSList *pending_monitors_dirs = NULL;
+
 static void
 cached_dir_invoke_monitors (CachedDir *dir)
 {
@@ -379,9 +384,70 @@ cached_dir_invoke_monitors (CachedDir *dir)
       tmp = next;
     }
 
+  /* we explicitly don't invoke monitors of the parent since an
+   * event has been queued for it too */
+}
+
+static gboolean
+emit_monitors_in_idle (void)
+{
+  GSList *monitors_to_emit;
+  GSList *tmp;
+
+  monitors_to_emit = pending_monitors_dirs;
+
+  pending_monitors_dirs = NULL;
+  monitors_idle_handler = 0;
+
+  tmp = monitors_to_emit;
+  while (tmp != NULL)
+    {
+      CachedDir *dir = tmp->data;
+
+      cached_dir_invoke_monitors (dir);
+      cached_dir_remove_reference (dir);
+
+      tmp = tmp->next;
+    }
+
+  g_slist_free (monitors_to_emit);
+
+  return FALSE;
+}
+
+static void
+cached_dir_queue_monitor_event (CachedDir *dir)
+{
+  GSList *tmp;
+
+  tmp = pending_monitors_dirs;
+  while (tmp != NULL)
+    {
+      CachedDir *d    = tmp->data;
+      GSList    *next = tmp->next;
+
+      if (dir->parent == d->parent &&
+          g_strcmp0 (dir->name, d->name) == 0)
+        break;
+
+      tmp = next;
+    }
+
+  /* not found, so let's queue it */
+  if (tmp == NULL)
+    {
+      cached_dir_add_reference (dir);
+      pending_monitors_dirs = g_slist_append (pending_monitors_dirs, dir);
+    }
+
   if (dir->parent)
     {
-      cached_dir_invoke_monitors (dir->parent);
+      cached_dir_queue_monitor_event (dir->parent);
+    }
+
+  if (monitors_idle_handler == 0)
+    {
+      monitors_idle_handler = g_idle_add ((GSourceFunc) emit_monitors_in_idle, NULL);
     }
 }
 
@@ -457,7 +523,7 @@ handle_cached_dir_changed (MenuMonitor      *monitor,
           _entry_directory_list_empty_desktop_cache ();
         }
 
-      cached_dir_invoke_monitors (dir);
+      cached_dir_queue_monitor_event (dir);
     }
 }
 
diff --git a/libmenu/menu-layout.c b/libmenu/menu-layout.c
index d9b800c..8439bca 100644
--- a/libmenu/menu-layout.c
+++ b/libmenu/menu-layout.c
@@ -65,6 +65,7 @@ struct MenuLayoutNodeRoot
   char *name;
 
   GSList *monitors;
+  guint   monitors_idle_handler;
 };
 
 struct MenuLayoutNodeMenu
@@ -133,16 +134,14 @@ node_next (MenuLayoutNode *node)
   return node->next;
 }
 
-static void
-handle_entry_directory_changed (EntryDirectory *dir,
-                                MenuLayoutNode *node)
+static gboolean
+menu_layout_invoke_monitors (MenuLayoutNodeRoot *nr)
 {
-  MenuLayoutNodeRoot *nr;
-  GSList             *tmp;
+  GSList *tmp;
 
-  g_assert (node->type == MENU_LAYOUT_NODE_MENU);
+  g_assert (nr->node.type == MENU_LAYOUT_NODE_ROOT);
 
-  nr = (MenuLayoutNodeRoot *) menu_layout_node_get_root (node);
+  nr->monitors_idle_handler = 0;
 
   tmp = nr->monitors;
   while (tmp != NULL)
@@ -154,6 +153,24 @@ handle_entry_directory_changed (EntryDirectory *dir,
 
       tmp = next;
     }
+
+  return FALSE;
+}
+
+static void
+handle_entry_directory_changed (EntryDirectory *dir,
+                                MenuLayoutNode *node)
+{
+  MenuLayoutNodeRoot *nr;
+
+  g_assert (node->type == MENU_LAYOUT_NODE_MENU);
+
+  nr = (MenuLayoutNodeRoot *) menu_layout_node_get_root (node);
+
+  if (nr->monitors_idle_handler == 0)
+    {
+      nr->monitors_idle_handler = g_idle_add ((GSourceFunc) menu_layout_invoke_monitors, nr);
+    }
 }
 
 static void
@@ -224,6 +241,10 @@ menu_layout_node_unref (MenuLayoutNode *node)
           g_slist_foreach (nr->monitors, (GFunc) g_free, NULL);
           g_slist_free (nr->monitors);
 
+          if (nr->monitors_idle_handler != 0)
+            g_source_remove (nr->monitors_idle_handler);
+          nr->monitors_idle_handler = 0;
+
           g_free (nr->basedir);
           g_free (nr->name);
         }



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