[Xfce4-commits] <garcon:jannis/global-monitoring> Additional work on app dir monitoring.

Jannis Pohlmann noreply at xfce.org
Fri Mar 12 11:44:01 CET 2010


Updating branch refs/heads/jannis/global-monitoring
         to e2154ae864ae1c9f6a07b8be2584c1e60d9db5b0 (commit)
       from f1dc211fdde28069074ec0eb1d39af44dddcbab9 (commit)

commit e2154ae864ae1c9f6a07b8be2584c1e60d9db5b0
Author: Jannis Pohlmann <jannis at xfce.org>
Date:   Fri Mar 12 11:36:11 2010 +0100

    Additional work on app dir monitoring.
    
    This adds new functionality to find the GarconMenuItem and all
    GarconMenus corresponding to a GFile. App dirs are now only monitored by
    the root menu.
    
    We properly react on changes that cause a single desktop file to be
    unreadable or to break parsing. Reacting on a deleted desktop file is
    also partly support now (what still needs to be implemented is looking
    for a desktop file with the same desktop-file ID, replacing the deleted
    desktop file).
    
    TODOs in garcon-menu.c were updated.
    
    New signals introduced in this commit:
      - GarconMenu::item-added
      - GarconMenu::item-changed
      - GarconMenu::item-removed
    
    New methods introduced in this commit:
      - garcon_menu_element_equal()
      - garcon_menu_item_cache_remove_file()
      - garcon_menu_item_pool_remove()

 garcon/garcon-marshal.list      |    1 +
 garcon/garcon-menu-element.c    |   15 +++
 garcon/garcon-menu-element.h    |    4 +
 garcon/garcon-menu-item-cache.c |   26 +++++-
 garcon/garcon-menu-item-cache.h |    2 +
 garcon/garcon-menu-item-pool.c  |   16 +++
 garcon/garcon-menu-item-pool.h  |    2 +
 garcon/garcon-menu-item.c       |   18 ++++
 garcon/garcon-menu-separator.c  |   13 +++
 garcon/garcon-menu.c            |  214 +++++++++++++++++++++++++++++++++++----
 tests/test-display-menu.c       |   35 +++++++
 11 files changed, 326 insertions(+), 20 deletions(-)

diff --git a/garcon/garcon-marshal.list b/garcon/garcon-marshal.list
index 38076d6..7e5b59e 100644
--- a/garcon/garcon-marshal.list
+++ b/garcon/garcon-marshal.list
@@ -1 +1,2 @@
 VOID:OBJECT,OBJECT
+VOID:OBJECT,UINT
diff --git a/garcon/garcon-menu-element.c b/garcon/garcon-menu-element.c
index 84eea95..e598cee 100644
--- a/garcon/garcon-menu-element.c
+++ b/garcon/garcon-menu-element.c
@@ -104,3 +104,18 @@ garcon_menu_element_get_no_display (GarconMenuElement *element)
   return (*GARCON_MENU_ELEMENT_GET_IFACE (element)->get_no_display) (element);
 }
 
+
+
+gboolean
+garcon_menu_element_equal (GarconMenuElement *a,
+                           GarconMenuElement *b)
+{
+  g_return_val_if_fail (GARCON_IS_MENU_ELEMENT (a), FALSE);
+  g_return_val_if_fail (GARCON_IS_MENU_ELEMENT (b), FALSE);
+
+  if (G_TYPE_FROM_INSTANCE (a) != G_TYPE_FROM_INSTANCE (b))
+    return FALSE;
+
+  return (*GARCON_MENU_ELEMENT_GET_IFACE (a)->equal) (a, b);
+}
+
diff --git a/garcon/garcon-menu-element.h b/garcon/garcon-menu-element.h
index 8aacdd8..4c30547 100644
--- a/garcon/garcon-menu-element.h
+++ b/garcon/garcon-menu-element.h
@@ -48,6 +48,8 @@ struct _GarconMenuElementIface
   gboolean     (*get_visible)             (GarconMenuElement *element);
   gboolean     (*get_show_in_environment) (GarconMenuElement *element);
   gboolean     (*get_no_display)          (GarconMenuElement *element);
+  gboolean     (*equal)                   (GarconMenuElement *element,
+                                           GarconMenuElement *other);
 };
 
 GType        garcon_menu_element_get_type                (void) G_GNUC_CONST;
@@ -58,6 +60,8 @@ const gchar *garcon_menu_element_get_icon_name           (GarconMenuElement *ele
 gboolean     garcon_menu_element_get_visible             (GarconMenuElement *element);
 gboolean     garcon_menu_element_get_show_in_environment (GarconMenuElement *element);
 gboolean     garcon_menu_element_get_no_display          (GarconMenuElement *element);
+gboolean     garcon_menu_element_equal                   (GarconMenuElement *a,
+                                                          GarconMenuElement *b);
 
 G_END_DECLS
 
diff --git a/garcon/garcon-menu-item-cache.c b/garcon/garcon-menu-item-cache.c
index afccfd0..435fb07 100644
--- a/garcon/garcon-menu-item-cache.c
+++ b/garcon/garcon-menu-item-cache.c
@@ -87,8 +87,7 @@ garcon_menu_item_cache_init (GarconMenuItemCache *cache)
   cache->priv = GARCON_MENU_ITEM_CACHE_GET_PRIVATE (cache);
 
   /* Create empty hash table */
-  cache->priv->items = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
-                                              (GDestroyNotify) garcon_menu_item_unref);
+  cache->priv->items = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
 }
 
 
@@ -206,6 +205,29 @@ garcon_menu_item_cache_foreach (GarconMenuItemCache *cache,
 
 
 void
+garcon_menu_item_cache_remove_file (GarconMenuItemCache *cache,
+                                    GFile               *file)
+{
+  gchar *uri;
+
+  g_return_if_fail (GARCON_IS_MENU_ITEM_CACHE (cache));
+  g_return_if_fail (G_IS_FILE (file));
+
+  /* Acquire lock on the item cache */
+  g_static_mutex_lock (&lock);
+
+  /* Remove the item with the same URI from the item cache */
+  uri = g_file_get_uri (file);
+  g_hash_table_remove (cache->priv->items, uri);
+  g_free (uri);
+
+  /* Release item cache lock */
+  g_static_mutex_unlock (&lock);
+}
+
+
+
+void
 garcon_menu_item_cache_invalidate (GarconMenuItemCache *cache)
 {
   g_return_if_fail (GARCON_IS_MENU_ITEM_CACHE (cache));
diff --git a/garcon/garcon-menu-item-cache.h b/garcon/garcon-menu-item-cache.h
index 1e8bbb6..9a36ad0 100644
--- a/garcon/garcon-menu-item-cache.h
+++ b/garcon/garcon-menu-item-cache.h
@@ -66,6 +66,8 @@ GarconMenuItem      *garcon_menu_item_cache_lookup      (GarconMenuItemCache *ca
 void                 garcon_menu_item_cache_foreach     (GarconMenuItemCache *cache,
                                                          GHFunc               func,
                                                          gpointer             user_data);
+void                 garcon_menu_item_cache_remove_file (GarconMenuItemCache *cache,
+                                                         GFile               *file);
 void                 garcon_menu_item_cache_invalidate  (GarconMenuItemCache *cache);
 
 G_END_DECLS
diff --git a/garcon/garcon-menu-item-pool.c b/garcon/garcon-menu-item-pool.c
index 5f0923f..fe9cd4e 100644
--- a/garcon/garcon-menu-item-pool.c
+++ b/garcon/garcon-menu-item-pool.c
@@ -122,6 +122,22 @@ garcon_menu_item_pool_insert (GarconMenuItemPool *pool,
 
 
 
+void
+garcon_menu_item_pool_remove (GarconMenuItemPool *pool,
+                              GarconMenuItem     *item)
+{
+  g_return_if_fail (GARCON_IS_MENU_ITEM_POOL (pool));
+  g_return_if_fail (GARCON_IS_MENU_ITEM (item));
+
+  /* Remove the item from the hash table */
+  g_hash_table_remove (pool->priv->items, garcon_menu_item_get_desktop_id (item));
+
+  /* Release the reference on the item */
+  garcon_menu_item_unref (item);
+}
+
+
+
 GarconMenuItem*
 garcon_menu_item_pool_lookup (GarconMenuItemPool *pool,
                               const gchar        *desktop_id)
diff --git a/garcon/garcon-menu-item-pool.h b/garcon/garcon-menu-item-pool.h
index 3d95346..e062a91 100644
--- a/garcon/garcon-menu-item-pool.h
+++ b/garcon/garcon-menu-item-pool.h
@@ -47,6 +47,8 @@ GarconMenuItemPool *garcon_menu_item_pool_new                (void) G_GNUC_MALLO
 
 void                garcon_menu_item_pool_insert             (GarconMenuItemPool *pool,
                                                               GarconMenuItem     *item);
+void                garcon_menu_item_pool_remove             (GarconMenuItemPool *pool,
+                                                              GarconMenuItem     *item);
 GarconMenuItem     *garcon_menu_item_pool_lookup             (GarconMenuItemPool *pool,
                                                               const gchar        *desktop_id);
 GarconMenuItem     *garcon_menu_item_pool_lookup_file        (GarconMenuItemPool *pool,
diff --git a/garcon/garcon-menu-item.c b/garcon/garcon-menu-item.c
index ba21aed..ed502bf 100644
--- a/garcon/garcon-menu-item.c
+++ b/garcon/garcon-menu-item.c
@@ -85,6 +85,8 @@ static const gchar *garcon_menu_item_get_element_icon_name           (GarconMenu
 static gboolean     garcon_menu_item_get_element_visible             (GarconMenuElement      *element);
 static gboolean     garcon_menu_item_get_element_show_in_environment (GarconMenuElement      *element);
 static gboolean     garcon_menu_item_get_element_no_display          (GarconMenuElement      *element);
+static gboolean     garcon_menu_item_get_element_equal               (GarconMenuElement      *element,
+                                                                      GarconMenuElement      *other);
 
 
 
@@ -384,6 +386,7 @@ garcon_menu_item_element_init (GarconMenuElementIface *iface)
   iface->get_visible = garcon_menu_item_get_element_visible;
   iface->get_show_in_environment = garcon_menu_item_get_element_show_in_environment;
   iface->get_no_display = garcon_menu_item_get_element_no_display;
+  iface->equal = garcon_menu_item_get_element_equal;
 }
 
 
@@ -622,6 +625,21 @@ garcon_menu_item_get_element_no_display (GarconMenuElement *element)
   return garcon_menu_item_get_no_display (GARCON_MENU_ITEM (element));
 }
 
+
+
+static gboolean
+garcon_menu_item_get_element_equal (GarconMenuElement *element,
+                                    GarconMenuElement *other)
+{
+  g_return_val_if_fail (GARCON_IS_MENU_ITEM (element), FALSE);
+  g_return_val_if_fail (GARCON_IS_MENU_ITEM (other), FALSE);
+
+  return g_file_equal (GARCON_MENU_ITEM (element)->priv->file, 
+                       GARCON_MENU_ITEM (other)->priv->file);
+}
+
+
+
 static const gchar*
 garcon_menu_item_get_element_name (GarconMenuElement *element)
 {
diff --git a/garcon/garcon-menu-separator.c b/garcon/garcon-menu-separator.c
index fcfe900..e7e22e5 100644
--- a/garcon/garcon-menu-separator.c
+++ b/garcon/garcon-menu-separator.c
@@ -36,6 +36,8 @@ static const gchar *garcon_menu_separator_get_element_icon_name           (Garco
 static gboolean     garcon_menu_separator_get_element_visible             (GarconMenuElement        *element);
 static gboolean     garcon_menu_separator_get_element_show_in_environment (GarconMenuElement        *element);
 static gboolean     garcon_menu_separator_get_element_no_display          (GarconMenuElement        *element);
+static gboolean     garcon_menu_separator_get_element_equal               (GarconMenuElement        *element,
+                                                                           GarconMenuElement        *other);
 
 
 
@@ -64,6 +66,7 @@ garcon_menu_separator_element_init (GarconMenuElementIface *iface)
   iface->get_visible = garcon_menu_separator_get_element_visible;
   iface->get_show_in_environment = garcon_menu_separator_get_element_show_in_environment;
   iface->get_no_display = garcon_menu_separator_get_element_no_display;
+  iface->equal = garcon_menu_separator_get_element_equal;
 }
 
 
@@ -158,3 +161,13 @@ garcon_menu_separator_get_element_no_display (GarconMenuElement *element)
 {
   return FALSE;
 }
+
+
+
+static gboolean
+garcon_menu_separator_get_element_equal (GarconMenuElement *element,
+                                         GarconMenuElement *other)
+{
+  /* FIXME this is inherently broken as the separator is a singleton class */
+  return FALSE;
+}
diff --git a/garcon/garcon-menu.c b/garcon/garcon-menu.c
index 569112d..ff51df3 100644
--- a/garcon/garcon-menu.c
+++ b/garcon/garcon-menu.c
@@ -99,6 +99,9 @@ enum
 {
   RELOAD_REQUIRED,
   DIRECTORY_CHANGED,
+  ITEM_ADDED,
+  ITEM_CHANGED,
+  ITEM_REMOVED,
   LAST_SIGNAL,
 };
 
@@ -147,6 +150,11 @@ static const gchar         *garcon_menu_get_element_icon_name           (GarconM
 static gboolean             garcon_menu_get_element_visible             (GarconMenuElement       *element);
 static gboolean             garcon_menu_get_element_show_in_environment (GarconMenuElement       *element);
 static gboolean             garcon_menu_get_element_no_display          (GarconMenuElement       *element);
+static gboolean             garcon_menu_get_element_equal               (GarconMenuElement       *element,
+                                                                         GarconMenuElement       *other);
+static GarconMenuItem      *garcon_menu_find_file_item                  (GarconMenu              *menu,
+                                                                         GFile                   *file,
+                                                                         GList                  **menus);
 static void                 garcon_menu_start_monitoring                (GarconMenu              *menu);
 static void                 garcon_menu_stop_monitoring                 (GarconMenu              *menu);
 static void                 garcon_menu_monitor_menu_files              (GarconMenu              *menu);
@@ -296,6 +304,43 @@ garcon_menu_class_init (GarconMenuClass *klass)
                   GARCON_TYPE_MENU_DIRECTORY,
                   GARCON_TYPE_MENU_DIRECTORY);
 
+  menu_signals[ITEM_ADDED] = 
+    g_signal_new ("item-added",
+                  GARCON_TYPE_MENU,
+                  G_SIGNAL_RUN_LAST | G_SIGNAL_NO_HOOKS,
+                  0,
+                  NULL,
+                  NULL,
+                  garcon_marshal_VOID__OBJECT_UINT,
+                  G_TYPE_NONE,
+                  1,
+                  GARCON_TYPE_MENU_ITEM,
+                  G_TYPE_UINT);
+
+  menu_signals[ITEM_CHANGED] =
+    g_signal_new ("item-changed",
+                  GARCON_TYPE_MENU,
+                  G_SIGNAL_RUN_LAST | G_SIGNAL_NO_HOOKS,
+                  0,
+                  NULL,
+                  NULL,
+                  g_cclosure_marshal_VOID__OBJECT,
+                  G_TYPE_NONE,
+                  1,
+                  GARCON_TYPE_MENU_ITEM);
+
+  menu_signals[ITEM_REMOVED] =
+    g_signal_new ("item-removed",
+                  GARCON_TYPE_MENU,
+                  G_SIGNAL_RUN_LAST | G_SIGNAL_NO_HOOKS,
+                  0,
+                  NULL,
+                  NULL,
+                  g_cclosure_marshal_VOID__OBJECT,
+                  G_TYPE_NONE,
+                  1,
+                  GARCON_TYPE_MENU_ITEM);
+
   garcon_menu_file_quark = g_quark_from_string ("garcon-menu-file-quark");
 }
 
@@ -310,6 +355,7 @@ garcon_menu_element_init (GarconMenuElementIface *iface)
   iface->get_visible = garcon_menu_get_element_visible;
   iface->get_show_in_environment = garcon_menu_get_element_show_in_environment;
   iface->get_no_display = garcon_menu_get_element_no_display;
+  iface->equal = garcon_menu_get_element_equal;
 }
 
 
@@ -375,8 +421,12 @@ garcon_menu_clear (GarconMenu *menu)
   /* Clear the item pool */
   garcon_menu_item_pool_clear (menu->priv->pool);
 
+  /* Jannis: I don't think this is needed. If we don't invalidate all
+   * the time, consequtive reloads will be much faster */
+#if 0 
   /* Clear the item cache */
   garcon_menu_item_cache_invalidate (menu->priv->cache);
+#endif
 }
 
 
@@ -1011,7 +1061,7 @@ garcon_menu_get_app_dirs (GarconMenu *menu,
           submenu_app_dirs = garcon_menu_get_app_dirs (lp->data, recursive);
 
           for (sp = g_list_last (submenu_app_dirs); sp != NULL; sp = sp->prev) 
-            if (!g_list_find_custom (dirs, sp->data, (GCompareFunc) g_strcmp0))
+            if (g_list_find_custom (dirs, sp->data, (GCompareFunc) g_strcmp0) == NULL)
               dirs = g_list_prepend (dirs, sp->data);
         }
     }
@@ -1682,6 +1732,53 @@ garcon_menu_get_element_no_display (GarconMenuElement *element)
 
 
 
+static gboolean
+garcon_menu_get_element_equal (GarconMenuElement *element,
+                               GarconMenuElement *other)
+{
+  g_return_val_if_fail (GARCON_IS_MENU (element), FALSE);
+  g_return_val_if_fail (GARCON_IS_MENU (other), FALSE);
+
+  return GARCON_MENU (element) == GARCON_MENU (other);
+}
+
+
+
+static GarconMenuItem *
+garcon_menu_find_file_item (GarconMenu *menu,
+                            GFile      *file,
+                            GList     **menus)
+{
+  GarconMenuItem *item;
+  GList          *lp;
+
+  g_return_val_if_fail (GARCON_IS_MENU (menu), NULL);
+  g_return_val_if_fail (G_IS_FILE (file), NULL);
+
+  item = garcon_menu_item_pool_lookup_file (menu->priv->pool, file);
+
+  if (menus != NULL)
+    {
+      if (item != NULL)
+        *menus = g_list_prepend (*menus, menu);
+
+      for (lp = menu->priv->submenus; lp != NULL; lp = lp->next)
+        item = garcon_menu_find_file_item (lp->data, file, menus);
+    }
+  else
+    {
+      if (item == NULL)
+        {
+          for (lp = menu->priv->submenus; item == NULL && lp != NULL; lp = lp->next)
+            item = garcon_menu_find_file_item (lp->data, file, menus);
+        }
+    }
+
+  return item;
+}
+
+
+
 static void
 garcon_menu_start_monitoring (GarconMenu *menu)
 {
@@ -1695,10 +1792,11 @@ garcon_menu_start_monitoring (GarconMenu *menu)
       garcon_menu_monitor_menu_files (menu);
       garcon_menu_monitor_merge_files (menu);
       garcon_menu_monitor_merge_dirs (menu);
+
+      garcon_menu_monitor_app_dirs (menu);
     }
 
   garcon_menu_monitor_directory_dirs (menu);
-  garcon_menu_monitor_app_dirs (menu);
 
   /* Recurse into child menus */
   for (lp = menu->priv->submenus; lp != NULL; lp = lp->next)
@@ -1864,6 +1962,9 @@ garcon_menu_monitor_app_dirs (GarconMenu *menu)
   for (lp = app_dirs; lp != NULL; lp = lp->next)
     {
       dir = _garcon_file_new_relative_to_file (lp->data, menu->priv->file);
+  
+      g_debug ("%20s: monitor %s", garcon_menu_get_name (menu), g_file_get_path (dir));
+
       garcon_menu_monitor_app_dir (menu, dir);
       g_object_unref (dir);
     }
@@ -1902,7 +2003,7 @@ garcon_menu_monitor_app_dir (GarconMenu *menu,
   g_return_if_fail (GARCON_IS_MENU (menu));
   g_return_if_fail (G_IS_FILE (dir));
 
-  if (g_list_find_custom (menu->priv->monitors, dir, (GCompareFunc) find_monitor))
+  if (g_list_find_custom (menu->priv->monitors, dir, (GCompareFunc) find_monitor) != NULL)
     return;
 
   monitor = g_file_monitor (dir, G_FILE_MONITOR_NONE, NULL, NULL);
@@ -2075,6 +2176,8 @@ garcon_menu_app_dir_changed (GarconMenu       *menu,
   GFileInfo      *info;
   GFileType       file_type;
   gboolean        can_read;
+  GList          *menus = NULL;
+  GList          *lp;
 
   g_return_if_fail (GARCON_IS_MENU (menu));
 
@@ -2085,8 +2188,10 @@ garcon_menu_app_dir_changed (GarconMenu       *menu,
                garcon_menu_element_get_name (GARCON_MENU_ELEMENT (menu)),
                g_file_get_path (file), event_type);
 
+      /* query the type of the changed file */
       file_type = g_file_query_file_type (file, G_FILE_QUERY_INFO_NONE, NULL);
 
+      /* check if one of the app dirs was changed */
       if (file_type == G_FILE_TYPE_DIRECTORY)
         {
           info = g_file_query_info (file, G_FILE_ATTRIBUTE_ACCESS_CAN_READ,
@@ -2095,6 +2200,8 @@ garcon_menu_app_dir_changed (GarconMenu       *menu,
           can_read = g_file_info_get_attribute_boolean (info, 
                                                         G_FILE_ATTRIBUTE_ACCESS_CAN_READ);
 
+          /* if the app dir is no longer readable, we need to remove all items
+           * residing somewhere inside the directory from all menus */
           if (!can_read)
             {
               /* TODO emit 'item-removed' with all items that are included in the
@@ -2103,15 +2210,53 @@ garcon_menu_app_dir_changed (GarconMenu       *menu,
         }
       else
         {
-          item = garcon_menu_item_pool_lookup_file (menu->priv->pool, file);
+          /* a regular file changed, try to find the corresponding menu item 
+           * and all menus this item is part of */
+          item = garcon_menu_find_file_item (menu, file, &menus);
 
-          /* TODO 
-           * - find the menu(s) this item belongs to
-           * - reload the item
-           * - find the menu(s) the item belongs to after the reload
-           *   (make sure to emit 'item-changed' or 'item-removed' and 
-           *   'item-added' signals were appropriate)
-           */
+          /* if the item is already known, we need to reload it and check
+           * if it has to be moved around in the menu hierarchy */
+          if (item != NULL)
+            {
+              /* try to reload the item */
+              if (garcon_menu_item_reload (item, NULL))
+                {
+                  /* find out where to move the item (if it has to be moved at all)
+                   * and move it, taking care of emitting item-changed/item-removed/item-added 
+                   * signals */
+
+                  g_debug ("  successfully reloaded");
+                }
+              else
+                {
+                  /* reloading failed, remove the item from all menus and destroy it */
+                  for (lp = menus; lp != NULL; lp = lp->next)
+                    {
+                      /* emit an 'item-removed' signal for each menu the item was part of */
+                      g_signal_emit (GARCON_MENU (lp->data), menu_signals[ITEM_REMOVED], 0, item);
+
+                      /* remove the item from each menu item pool */
+                      garcon_menu_item_pool_remove (GARCON_MENU (lp->data)->priv->pool, item);
+                    }
+
+                  /* remove the item from the item cache, so we are forced to reload it from
+                   * disk the next time it becomes available */
+                  garcon_menu_item_cache_remove_file (menu->priv->cache, file);
+                }
+            }
+          else
+            {
+              /* TODO 
+               * the menu item is unknown, so we need to load it and find to which
+               * menus it belongs. this involves:
+               * 1. finding out its desktop-file ID
+               * 2. loading it via the GarconMenuItemCache
+               * 3. resolving the item similar to how we do it with all items
+               *    during the menu load process */
+            }
+
+          /* free the menu list */
+          g_list_free (menus);
         }
     }
   else if (event_type == G_FILE_MONITOR_EVENT_CREATED)
@@ -2139,13 +2284,46 @@ garcon_menu_app_dir_changed (GarconMenu       *menu,
                garcon_menu_element_get_name (GARCON_MENU_ELEMENT (menu)),
                g_file_get_path (file), event_type);
 
-      /* TODO 
-       * 1) the deleted file is a directory
-       *    - remove all menu items coming from the removed directory
-       *      from item pools (make sure to emit 'item-removed' signals)
-       * 2) the deleted file is a regular file
-       *
-       */
+      /* query the type of the changed file */
+      file_type = g_file_query_file_type (file, G_FILE_QUERY_INFO_NONE, NULL);
+
+      /* check if one of the app dirs was changed */
+      if (file_type == G_FILE_TYPE_DIRECTORY)
+        {
+          /* TODO 
+           * the deleted file is a directory, so remove all menu items 
+           * residing inside the directory from all menus */
+        }
+      else
+        {
+          /* a regular file was deleted, try to find the corresponding
+           * menu item and the menus the item was part of */
+          item = garcon_menu_find_file_item (menu, file, &menus);
+          if (item != NULL)
+            {
+              /* reloading failed, remove the item from all menus and destroy it */
+              for (lp = menus; lp != NULL; lp = lp->next)
+                {
+                  /* emit an 'item-removed' signal for each menu the item was part of */
+                  g_signal_emit (GARCON_MENU (lp->data), menu_signals[ITEM_REMOVED], 0, item);
+
+                  /* remove the item from each menu item pool */
+                  garcon_menu_item_pool_remove (GARCON_MENU (lp->data)->priv->pool, item);
+                }
+
+              /* remove the item from the item cache, so we are forced to reload it from
+               * disk the next time it becomes available */
+              garcon_menu_item_cache_remove_file (menu->priv->cache, file);
+            }
+
+          /* TODO
+           * check if a file with the same desktop-file ID still exists
+           * and load that file instead. then resolve the file into the
+           * correct menus */
+
+          /* free the menu list */
+          g_list_free (menus);
+        }
     }
 }
 
diff --git a/tests/test-display-menu.c b/tests/test-display-menu.c
index 459c73d..da3511a 100644
--- a/tests/test-display-menu.c
+++ b/tests/test-display-menu.c
@@ -166,6 +166,8 @@ create_item_widgets (GarconMenuItem *item,
   gtk_menu_shell_append (GTK_MENU_SHELL (parent_menu), gtk_item);
   gtk_widget_show (gtk_item);
 
+  g_object_set_data_full (G_OBJECT (gtk_item), "garcon-menu-item", g_object_ref (item), g_object_unref);
+
   /* Execute command if item is clicked */
   g_signal_connect (gtk_item, "activate", G_CALLBACK (execute_item_command), item);
 }
@@ -199,6 +201,33 @@ directory_changed (GarconMenu          *menu,
 
 
 static void
+item_removed (GarconMenu     *menu,
+              GarconMenuItem *item,
+              GtkWidget      *gtk_menu)
+{
+  GarconMenuItem *corresponding_item;
+  GList          *children;
+  GList          *lp;
+
+  children = gtk_container_get_children (GTK_CONTAINER (gtk_menu));
+
+  for (lp = children; lp != NULL; lp = lp->next)
+    {
+      corresponding_item = g_object_get_data (G_OBJECT (lp->data), "garcon-menu-item");
+      if (corresponding_item != NULL)
+        {
+          if (garcon_menu_element_equal (GARCON_MENU_ELEMENT (item),
+                                         GARCON_MENU_ELEMENT (corresponding_item)))
+            {
+              gtk_container_remove (GTK_CONTAINER (gtk_menu), lp->data);
+            }
+        }
+    }
+}
+
+
+
+static void
 create_menu_widgets (GtkWidget   *gtk_menu,
                      GarconMenu  *menu)
 {
@@ -269,6 +298,12 @@ create_menu_widgets (GtkWidget   *gtk_menu,
           /* Update the menu item when the menu directory changes */
           g_signal_connect (submenu, "directory-changed", G_CALLBACK (directory_changed), gtk_item);
 
+          /* Remvoe the menu item and submenu if there are no menu items left in it */
+          /* g_signal_connect (submenu, "destroy", G_CALLBACK (menu_destroyed), gtk_item); */
+
+          /* Remove menu items if they are removed on disk */
+          g_signal_connect (submenu, "item-removed", G_CALLBACK (item_removed), gtk_submenu);
+
           /* Create widgets for submenu */
           create_menu_widgets (gtk_submenu, submenu);
 



More information about the Xfce4-commits mailing list