Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/gnome-menus/ChangeLog,v
retrieving revision 1.146
diff -u -p -r1.146 ChangeLog
--- ChangeLog	6 Sep 2005 09:15:30 -0000	1.146
+++ ChangeLog	30 Sep 2005 14:14:04 -0000
@@ -0,0 +1,12 @@
+2005-09-30  Mark McLoughlin  <mark@skynet.ie>
+
+	Hopefully fix issue where menus wouldn't be completely
+	reloaded after a spew of file change events (#313833)
+	
+	Detailed analysis from Frederic Crozat <fcrozat@mandriva.com>
+
+	* libmenu/menu-monitor.c: make the pending_events list global
+	rather than per-monitor and don't try and coalesce events for
+	the same path so that we can guarantee that we emit all the
+	events in the same order as we receive them from FAM.
+
Index: libmenu/menu-monitor.c
===================================================================
RCS file: /cvs/gnome/gnome-menus/libmenu/menu-monitor.c,v
retrieving revision 1.7
diff -u -p -r1.7 menu-monitor.c
--- libmenu/menu-monitor.c	24 Aug 2005 14:53:25 -0000	1.7
+++ libmenu/menu-monitor.c	30 Sep 2005 14:14:04 -0000
@@ -37,7 +37,6 @@ struct MenuMonitor
 
 #ifdef HAVE_FAM
   FAMRequest  request;
-  GSList     *pending_events;
 #endif /* HAVE_FAM */
 
   guint is_directory : 1;
@@ -70,6 +69,7 @@ static gboolean       opened_connection 
 static gboolean       failed_to_connect = FALSE;
 static guint          fam_io_watch = 0;
 static guint          events_idle_handler = 0;
+static GSList        *pending_events = NULL;
 
 static void
 invoke_notifies (MenuMonitor      *monitor,
@@ -83,7 +83,6 @@ invoke_notifies (MenuMonitor      *monit
   g_slist_foreach (copy,
 		   (GFunc) menu_monitor_notify_ref,
 		   NULL);
-		   
 
   tmp = copy;
   while (tmp != NULL)
@@ -104,62 +103,50 @@ invoke_notifies (MenuMonitor      *monit
   g_slist_free (copy);
 }
 
-static void
-list_pending_events_foreach (const char   *key,
-			     MenuMonitor  *monitor,
-			     GSList      **pending_events)
+static gboolean
+emit_events_in_idle (void)
 {
+  GSList *events_to_emit;
   GSList *tmp;
 
-  tmp = monitor->pending_events;
+  events_to_emit = pending_events;
+
+  pending_events = NULL;
+  events_idle_handler = 0;
+
+  tmp = events_to_emit;
   while (tmp != NULL)
     {
-      MenuMonitorEventInfo *event = tmp->data;
+      MenuMonitorEventInfo *event_info = tmp->data;
 
-      menu_monitor_ref (event->monitor);
+      menu_monitor_ref (event_info->monitor);
 
       tmp = tmp->next;
     }
-
-  *pending_events = g_slist_concat (*pending_events,
-				    monitor->pending_events);
-
-  monitor->pending_events = NULL;
-}
-
-static gboolean
-emit_events_in_idle (void)
-{
-  GSList *pending_events = NULL;
-  GSList *tmp;
-
-  events_idle_handler = 0;
   
-  g_hash_table_foreach (monitors_registry,
-			(GHFunc) list_pending_events_foreach,
-			&pending_events);
-
-  tmp = pending_events;
+  tmp = events_to_emit;
   while (tmp != NULL)
     {
-      MenuMonitorEventInfo *event = tmp->data;
+      MenuMonitorEventInfo *event_info = tmp->data;
 
-      invoke_notifies (event->monitor, event->event, event->path);
+      invoke_notifies (event_info->monitor,
+		       event_info->event,
+		       event_info->path);
 
-      menu_monitor_unref (event->monitor);
-      event->monitor = NULL;
+      menu_monitor_unref (event_info->monitor);
+      event_info->monitor = NULL;
 
-      g_free (event->path);
-      event->path = NULL;
+      g_free (event_info->path);
+      event_info->path = NULL;
 
-      event->event = MENU_MONITOR_EVENT_INVALID;
+      event_info->event = MENU_MONITOR_EVENT_INVALID;
 
-      g_free (event);
+      g_free (event_info);
 
       tmp = tmp->next;
     }
 
-  g_slist_free (pending_events);
+  g_slist_free (events_to_emit);
 
   return FALSE;
 }
@@ -168,10 +155,10 @@ static void
 queue_fam_event (MenuMonitor *monitor,
 		 FAMEvent    *fam_event)
 {
-  MenuMonitorEventInfo *event;
+  MenuMonitorEventInfo *event_info;
+  MenuMonitorEvent      event;
   const char           *path;
   char                 *freeme;
-  GSList               *tmp;
 
   freeme = NULL;
   if (fam_event->filename[0] == '/')
@@ -185,43 +172,19 @@ queue_fam_event (MenuMonitor *monitor,
 					NULL);
     }
 
-  event = NULL;
-  tmp = monitor->pending_events;
-  while (tmp != NULL)
-    {
-      event = tmp->data;
-
-      if (strcmp (event->path, path) == 0)
-	break;
-
-      event = NULL;
-
-      tmp = tmp->next;
-    }
-
-  if (event == NULL)
-    {
-      event = g_new0 (MenuMonitorEventInfo, 1);
-
-      event->path    = g_strdup (path);
-      event->monitor = monitor;
-
-      monitor->pending_events = g_slist_append (monitor->pending_events,
-						event);
-    }
-
+  event = MENU_MONITOR_EVENT_INVALID;
   switch (fam_event->code)
     {
     case FAMChanged:
-      event->event = MENU_MONITOR_EVENT_CHANGED;
+      event = MENU_MONITOR_EVENT_CHANGED;
       break;
 
     case FAMCreated:
-      event->event = MENU_MONITOR_EVENT_CREATED;
+      event = MENU_MONITOR_EVENT_CREATED;
       break;
 
     case FAMDeleted:
-      event->event = MENU_MONITOR_EVENT_DELETED;
+      event = MENU_MONITOR_EVENT_DELETED;
       break;
 
     default:
@@ -229,6 +192,14 @@ queue_fam_event (MenuMonitor *monitor,
       break;
     }
 
+  event_info = g_new0 (MenuMonitorEventInfo, 1);
+
+  event_info->path    = g_strdup (path);
+  event_info->event   = event;
+  event_info->monitor = monitor;
+
+  pending_events = g_slist_append (pending_events, event_info);
+
   if (events_idle_handler == 0)
     {
       events_idle_handler = g_idle_add ((GSourceFunc) emit_events_in_idle, NULL);
@@ -513,15 +484,31 @@ menu_monitor_ref (MenuMonitor *monitor)
 
 #ifdef HAVE_FAM
 static void
-free_event_info (MenuMonitorEventInfo *event)
+menu_monitor_clear_pending_events (MenuMonitor *monitor)
 {
-  g_free (event->path);
-  event->path = NULL;
+  GSList *tmp;
 
-  event->monitor = NULL;
-  event->event   = MENU_MONITOR_EVENT_INVALID;
+  tmp = pending_events;
+  while (tmp != NULL)
+    {
+      MenuMonitorEventInfo *event_info = tmp->data;
+      GSList               *next = tmp->next;
+
+      if (event_info->monitor == monitor)
+	{
+	  pending_events = g_slist_delete_link (pending_events, tmp);
+
+	  g_free (event_info->path);
+	  event_info->path = NULL;
+
+	  event_info->monitor = NULL;
+	  event_info->event   = MENU_MONITOR_EVENT_INVALID;
 
-  g_free (event);
+	  g_free (event_info);
+	}
+
+      tmp = next;
+    }
 }
 #endif /* HAVE_FAM */
 
@@ -547,10 +534,8 @@ menu_monitor_unref (MenuMonitor *monitor
   monitor->notifies = NULL;
 
 #ifdef HAVE_FAM
-  g_slist_foreach (monitor->pending_events, (GFunc) free_event_info, NULL);
-  g_slist_free (monitor->pending_events);
-  monitor->pending_events = NULL;
-#endif /* HAVE_FAM */
+  menu_monitor_clear_pending_events (monitor);
+#endif
 
   g_free (monitor->path);
   monitor->path = NULL;
