[Xfce4-commits] <garcon:jannis/global-monitoring> Squashme

Jannis Pohlmann noreply at xfce.org
Sun Sep 5 14:50:32 CEST 2010


Updating branch refs/heads/jannis/global-monitoring
         to a45a599c89f2ef788f0d67d81d431aeea94285e9 (commit)
       from 76e190ae8d0d4e98f59ef59c00cf9d4c1e91eb8f (commit)

commit a45a599c89f2ef788f0d67d81d431aeea94285e9
Author: Jannis Pohlmann <jannis at xfce.org>
Date:   Mon Aug 30 14:57:06 2010 +0200

    Squashme

 garcon/garcon-config.h         |   10 +-
 garcon/garcon-config.h.in      |   11 +-
 garcon/garcon-menu-item-pool.c |    3 -
 garcon/garcon-menu-item.c      |   38 ++++-
 garcon/garcon-menu.c           |  384 +++++++++++++++++++++++++++++----------
 tests/test-display-menu.c      |   44 +++++
 6 files changed, 374 insertions(+), 116 deletions(-)

diff --git a/garcon/garcon-config.h b/garcon/garcon-config.h
index ee4c119..27f2c35 100644
--- a/garcon/garcon-config.h
+++ b/garcon/garcon-config.h
@@ -1,7 +1,7 @@
 /* $Id$ */
 /* vi:set expandtab sw=2 sts=2: */
 /*-
- * Copyright (c) 2008 Jannis Pohlmann <jannis at xfce.org>
+ * Copyright (c) 2008-2010 Jannis Pohlmann <jannis at xfce.org>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -83,12 +83,12 @@ extern const guint garcon_major_version;
 extern const guint garcon_minor_version;
 extern const guint garcon_micro_version;
 
-const gchar *garcon_check_version      (guint        required_major,
-                                        guint        required_minor,
-                                        guint        required_micro);
+const gchar *garcon_check_version      (guint required_major,
+                                        guint required_minor,
+                                        guint required_micro);
 
-gchar      **garcon_config_build_paths (const gchar *filename) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
 gchar       *garcon_config_lookup      (const gchar *filename) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
+gchar      **garcon_config_build_paths (const gchar *filename) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
 
 G_END_DECLS
 
diff --git a/garcon/garcon-config.h.in b/garcon/garcon-config.h.in
index baae3b8..1cb70f8 100644
--- a/garcon/garcon-config.h.in
+++ b/garcon/garcon-config.h.in
@@ -1,7 +1,7 @@
 /* $Id$ */
 /* vi:set expandtab sw=2 sts=2: */
 /*-
- * Copyright (c) 2008 Jannis Pohlmann <jannis at xfce.org>
+ * Copyright (c) 2008-2010 Jannis Pohlmann <jannis at xfce.org>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -83,11 +83,12 @@ extern const guint garcon_major_version;
 extern const guint garcon_minor_version;
 extern const guint garcon_micro_version;
 
-const gchar *garcon_check_version (guint required_major,
-                                   guint required_minor,
-                                   guint required_micro);
+const gchar *garcon_check_version      (guint required_major,
+                                        guint required_minor,
+                                        guint required_micro);
 
-gchar       *garcon_config_lookup (const gchar *filename) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
+gchar       *garcon_config_lookup      (const gchar *filename) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
+gchar      **garcon_config_build_paths (const gchar *filename) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
 
 G_END_DECLS
 
diff --git a/garcon/garcon-menu-item-pool.c b/garcon/garcon-menu-item-pool.c
index 5e55ff8..ccd2654 100644
--- a/garcon/garcon-menu-item-pool.c
+++ b/garcon/garcon-menu-item-pool.c
@@ -133,9 +133,6 @@ garcon_menu_item_pool_remove (GarconMenuItemPool *pool,
 
   /* 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);
 }
 
 
diff --git a/garcon/garcon-menu-item.c b/garcon/garcon-menu-item.c
index cc1b91c..f490f16 100644
--- a/garcon/garcon-menu-item.c
+++ b/garcon/garcon-menu-item.c
@@ -834,12 +834,16 @@ garcon_menu_item_reload_from_file (GarconMenuItem  *item,
                                    GError         **error)
 {
   GKeyFile *rc;
-  gchar    *contents;
-  gsize     length = 0;
+  gboolean  boolean;
   gboolean  succeed;
+  GList    *categories = NULL;
+  gchar   **mt;
+  gchar   **str_list;
+  gchar    *contents;
   gchar    *string;
-  gboolean  boolean;
-  gchar    *name, *exec;
+  gchar    *name;
+  gchar    *exec;
+  gsize     length = 0;
 
   g_return_val_if_fail (GARCON_IS_MENU_ITEM (item), FALSE);
   g_return_val_if_fail (G_IS_FILE (file), FALSE);
@@ -930,6 +934,32 @@ garcon_menu_item_reload_from_file (GarconMenuItem  *item,
   boolean = GET_KEY (boolean, G_KEY_FILE_DESKTOP_KEY_HIDDEN);
   garcon_menu_item_set_hidden (item, boolean);
 
+  /* Determine the categories this application should be shown in */
+  str_list = GET_STRING_LIST (G_KEY_FILE_DESKTOP_KEY_CATEGORIES);
+  if (G_LIKELY (str_list != NULL))
+    {
+      for (mt = str_list; *mt != NULL; ++mt)
+        {
+          if (**mt != '\0')
+            categories = g_list_prepend (categories, g_strdup (*mt));
+        }
+
+      /* Free list */
+      g_strfreev (str_list);
+
+      /* Assign categories list to the menu item */
+      garcon_menu_item_set_categories (item, categories);
+    }
+  else
+    {
+      /* Assign empty categories list to the menu item */
+      garcon_menu_item_set_categories (item, NULL);
+    }
+
+  /* Set the rest of the private data directly */
+  item->priv->only_show_in = GET_STRING_LIST (G_KEY_FILE_DESKTOP_KEY_ONLY_SHOW_IN);
+  item->priv->not_show_in = GET_STRING_LIST (G_KEY_FILE_DESKTOP_KEY_NOT_SHOW_IN);
+
   /* Flush property notifications */
   g_object_thaw_notify (G_OBJECT (item));
 
diff --git a/garcon/garcon-menu.c b/garcon/garcon-menu.c
index a5d3782..902afb9 100644
--- a/garcon/garcon-menu.c
+++ b/garcon/garcon-menu.c
@@ -146,10 +146,13 @@ static void                 garcon_menu_resolve_items_by_rule           (GarconM
 static void                 garcon_menu_resolve_item_by_rule            (const gchar             *desktop_id,
                                                                          const gchar             *uri,
                                                                          GarconMenuPair          *data);
-static gchar               *garcon_menu_collect_file_from_path          (GarconMenu              *menu,
-                                                                         GFile                   *file,
+static gboolean             garcon_menu_collect_file_from_path          (GarconMenu              *menu,
                                                                          GFile                   *dir,
-                                                                         const gchar             *id_prefix);
+                                                                         const gchar             *id_prefix,
+                                                                         GFile                   *wanted_file,
+                                                                         const gchar             *wanted_desktop_id,
+                                                                         GFile                  **return_file,
+                                                                         gchar                  **return_desktop_id);
 #if 0
 static gboolean             garcon_menu_resolve_item_file               (GarconMenu              *menu,
                                                                          GFile                   *file,
@@ -334,7 +337,7 @@ garcon_menu_class_init (GarconMenuClass *klass)
                   NULL,
                   garcon_marshal_VOID__OBJECT_UINT,
                   G_TYPE_NONE,
-                  1,
+                  2,
                   GARCON_TYPE_MENU_ITEM,
                   G_TYPE_UINT);
 
@@ -1302,6 +1305,8 @@ garcon_menu_resolve_items (GarconMenu *menu,
               garcon_menu_item_pool_apply_exclude_rule (menu->priv->pool, iter->data);
             }
         }
+
+      g_list_free (rules);
     }
 
   /* Iterate over all submenus */
@@ -1371,82 +1376,84 @@ garcon_menu_resolve_item_by_rule (const gchar    *desktop_id,
 
 
 
-static gchar *
+static gboolean
 garcon_menu_collect_file (GarconMenu  *menu,
-                          GFile       *file)
+                          GFile       *wanted_file,
+                          const gchar *wanted_desktop_id,
+                          GFile      **return_file,
+                          gchar      **return_desktop_id)
 {
-  GList *app_dirs = NULL;
-  GList *iter;
-  GFile *dir;
-  gchar *desktop_id = NULL;
-
-  g_return_val_if_fail (GARCON_IS_MENU (menu), NULL);
-  g_return_val_if_fail (G_IS_FILE (file), NULL);
+  gboolean file_found = FALSE;
+  GList   *app_dirs = NULL;
+  GList   *iter;
+  GFile   *dir;
 
-  g_debug ("collect file: menu = %s, file = %s", 
-           garcon_menu_element_get_name (GARCON_MENU_ELEMENT (menu)),
-           g_file_get_path (file));
+  g_return_val_if_fail (GARCON_IS_MENU (menu), FALSE);
+  g_return_val_if_fail (wanted_file == NULL || G_IS_FILE (wanted_file), FALSE);
+  g_return_val_if_fail (!(wanted_file != NULL && wanted_desktop_id != NULL), FALSE);
 
   app_dirs = garcon_menu_get_app_dirs (menu, FALSE);
 
   /* Collect desktop entry filenames */
-  for (iter = app_dirs; desktop_id == NULL && iter != NULL; iter = g_list_next (iter))
+  for (iter = app_dirs; !file_found && iter != NULL; iter = iter->next)
     {
       dir = g_file_new_for_uri (iter->data);
-      desktop_id = garcon_menu_collect_file_from_path (menu, file, dir, NULL);
+      file_found = garcon_menu_collect_file_from_path (menu, dir, NULL,
+                                                       wanted_file, wanted_desktop_id, 
+                                                       return_file, return_desktop_id);
       g_object_unref (dir);
     }
 
   /* Free directory list */
   g_list_free (app_dirs);
 
-  if (desktop_id == NULL)
+  if (!file_found)
     {
       /* Collect filenames for submenus */
-      for (iter = menu->priv->submenus; 
-           desktop_id == NULL && iter != NULL; 
-           iter = g_list_next (iter))
+      for (iter = menu->priv->submenus; !file_found  && iter != NULL; iter = iter->next)
         {
-          desktop_id = garcon_menu_collect_file (iter->data, file);
+          file_found = garcon_menu_collect_file (iter->data, 
+                                                 wanted_file, wanted_desktop_id,
+                                                 return_file, return_desktop_id);
         }
     }
 
-  return desktop_id;
+  return file_found;
 }
 
 
 
-static gchar *
+static gboolean
 garcon_menu_collect_file_from_path (GarconMenu  *menu,
-                                    GFile       *file,
                                     GFile       *dir,
-                                    const gchar *id_prefix)
+                                    const gchar *id_prefix,
+                                    GFile       *wanted_file,
+                                    const gchar *wanted_desktop_id,
+                                    GFile      **return_file,
+                                    gchar      **return_desktop_id)
 {
   GFileEnumerator *enumerator;
   GFileInfo       *file_info;
+  gboolean         file_found = FALSE;
   GFile           *child_file;
   gchar           *base_name;
   gchar           *new_id_prefix;
   gchar           *desktop_id = NULL;
 
-  g_return_val_if_fail (GARCON_IS_MENU (menu), NULL);
-  g_return_val_if_fail (G_IS_FILE (file), NULL);
-  g_return_val_if_fail (G_IS_FILE (dir), NULL);
-
-  g_debug ("collect file from path: menu = %s, file = %s, dir = %s", 
-           garcon_menu_element_get_name (GARCON_MENU_ELEMENT (menu)),
-           g_file_get_path (file),
-           g_file_get_path (dir));
+  g_return_val_if_fail (GARCON_IS_MENU (menu), FALSE);
+  g_return_val_if_fail (G_IS_FILE (dir), FALSE);
+  g_return_val_if_fail (wanted_file == NULL || G_IS_FILE (wanted_file), FALSE);
+  g_return_val_if_fail (!(wanted_file != NULL && wanted_desktop_id != NULL), FALSE);
 
   /* Skip directory if it doesn't exist */
-  if (G_UNLIKELY (!g_file_query_exists (dir, NULL)))
-    return NULL;
+  if (!g_file_query_exists (dir, NULL))
+    return FALSE;
 
   /* Skip directory if it's not a directory */
-  if (G_UNLIKELY (g_file_query_file_type (dir, G_FILE_QUERY_INFO_NONE,
-                                          NULL) != G_FILE_TYPE_DIRECTORY))
+  if (g_file_query_file_type (dir, G_FILE_QUERY_INFO_NONE, 
+                              NULL) != G_FILE_TYPE_DIRECTORY)
     {
-      return NULL;
+      return FALSE;
     }
 
   /* Open directory for reading */
@@ -1454,15 +1461,15 @@ garcon_menu_collect_file_from_path (GarconMenu  *menu,
                                           G_FILE_QUERY_INFO_NONE, NULL, NULL);
 
   /* Abort if directory cannot be opened */
-  if (G_UNLIKELY (enumerator == NULL))
-    return NULL;
+  if (enumerator == NULL)
+    return FALSE;
 
   /* Read file by file */
-  while (TRUE && desktop_id == NULL)
+  while (!file_found)
     {
       file_info = g_file_enumerator_next_file (enumerator, NULL, NULL);
 
-      if (G_UNLIKELY (file_info == NULL))
+      if (file_info == NULL)
         break;
 
       child_file = g_file_resolve_relative_path (dir, g_file_info_get_name (file_info));
@@ -1472,28 +1479,53 @@ garcon_menu_collect_file_from_path (GarconMenu  *menu,
       if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY)
         {
           /* Create new desktop-file id prefix */
-          if (G_LIKELY (id_prefix == NULL))
+          if (id_prefix == NULL)
             new_id_prefix = g_strdup (base_name);
           else
             new_id_prefix = g_strjoin ("-", id_prefix, base_name, NULL);
 
           /* Collect files in the directory */
-          desktop_id = garcon_menu_collect_file_from_path (menu, file, child_file, 
-                                                           new_id_prefix);
+          file_found = garcon_menu_collect_file_from_path (menu, 
+                                                           child_file, new_id_prefix, 
+                                                           wanted_file, wanted_desktop_id, 
+                                                           return_file, return_desktop_id);
 
           /* Free id prefix */
           g_free (new_id_prefix);
         }
-      else if (G_LIKELY (g_str_has_suffix (base_name, ".desktop")))
+      else if (g_str_has_suffix (base_name, ".desktop"))
         {
+          /* Create desktop-file id */
+          if (id_prefix == NULL)
+            desktop_id = g_strdup (base_name);
+          else
+            desktop_id = g_strjoin ("-", id_prefix, base_name, NULL);
+
           /* Check if we have found the correct file */
-          if (g_file_equal (child_file, file))
+          if (wanted_file != NULL && g_file_equal (child_file, wanted_file))
             {
-              /* Create desktop-file id */
-              if (G_LIKELY (id_prefix == NULL))
-                desktop_id = g_strdup (base_name);
-              else
-                desktop_id = g_strjoin ("-", id_prefix, base_name, NULL);
+              if (return_file != NULL)
+                *return_file = g_object_ref (child_file);
+
+              if (return_desktop_id != NULL)
+                *return_desktop_id = desktop_id;
+              
+              file_found = TRUE;
+            }
+          else if (wanted_desktop_id != NULL 
+                   && g_strcmp0 (desktop_id, wanted_desktop_id) == 0)
+            {
+              if (return_file != NULL)
+                *return_file = g_object_ref (child_file);
+
+              if (return_desktop_id != NULL)
+                *return_desktop_id = desktop_id;
+
+              file_found = TRUE;
+            }
+          else
+            {
+              g_free (desktop_id);
             }
         }
 
@@ -1509,34 +1541,128 @@ garcon_menu_collect_file_from_path (GarconMenu  *menu,
 
   g_object_unref (enumerator);
 
-  return desktop_id;
+  return file_found;
 }
 
 
 
-#if 0
 static gboolean
-garcon_menu_resolve_item_file (GarconMenu      *menu,
-                               GFile           *file,
-                               GarconMenuItem **item,
-                               gchar          **desktop_id)
-{
+garcon_menu_update_item (GarconMenu     *menu,
+                         GarconMenuItem *item,
+                         gboolean        only_unallocated)
+{
+  GarconMenuItem *included_item;
+  const gchar    *desktop_id;
+  gboolean        menu_only_unallocated = FALSE;
+  gboolean        to_be_included = FALSE;
+  gboolean        included_somewhere = FALSE;
+  GList          *rules = NULL;
+  GList          *iter;
+
   g_return_val_if_fail (GARCON_IS_MENU (menu), FALSE);
-  g_return_val_if_fail (G_IS_FILE (file), FALSE);
-  g_return_val_if_fail (item != NULL && *item == NULL, FALSE);
-  g_return_val_if_fail (desktop_id != NULL && *desktop_id == NULL, FALSE);
-
-  /* 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 */
+  g_return_val_if_fail (GARCON_IS_MENU_ITEM (item), FALSE);
 
-  return FALSE;
+  g_debug ("update item: menu=%s, item=%s", 
+           garcon_menu_element_get_name (GARCON_MENU_ELEMENT (menu)),
+           garcon_menu_element_get_name (GARCON_MENU_ELEMENT (item)));
+
+  menu_only_unallocated = garcon_menu_node_tree_get_boolean_child (menu->priv->tree, 
+                                                                   GARCON_MENU_NODE_TYPE_ONLY_UNALLOCATED);
+
+  if (menu_only_unallocated == only_unallocated)
+    {
+      desktop_id = garcon_menu_item_get_desktop_id (item);
+      included_item = garcon_menu_item_pool_lookup (menu->priv->pool, desktop_id);
+
+      g_node_traverse (menu->priv->tree, G_IN_ORDER, G_TRAVERSE_ALL, 2,
+                       (GNodeTraverseFunc) collect_rules, &rules);
+
+      /* Iterate over all rules */
+      for (iter = rules; iter != NULL; iter = g_list_next (iter))
+        {
+          if (G_LIKELY (garcon_menu_node_tree_get_node_type (iter->data) == GARCON_MENU_NODE_TYPE_INCLUDE))
+            {
+              if (garcon_menu_node_tree_rule_matches (iter->data, item))
+                {
+                  g_debug ("  include rule matches");
+                  if (menu_only_unallocated)
+                    {
+                      g_debug ("  item allocation counter: %d", garcon_menu_item_get_allocated (item));
+                      if (garcon_menu_item_get_allocated (item) == 0)
+                        {
+                          to_be_included = TRUE;
+                        }
+                      else if (garcon_menu_item_get_allocated (item) == 1)
+                        {
+                          if (included_item != NULL 
+                              && garcon_menu_element_equal (GARCON_MENU_ELEMENT (item),
+                                                            GARCON_MENU_ELEMENT (included_item)))
+                            {
+                              g_debug ("  included element and new element are equal, good");
+                              to_be_included = TRUE;
+                            }
+                        }
+                    }
+                  else
+                    {
+                      to_be_included = TRUE;
+                    }
+                }
+            }
+          else
+            {
+              if (garcon_menu_node_tree_rule_matches (iter->data, item))
+                to_be_included = FALSE;
+            }
+        }
+
+      if (to_be_included)
+        {
+          g_debug ("  to be included");
+          if (included_item == NULL)
+            {
+              g_debug ("    add");
+              garcon_menu_item_pool_insert (menu->priv->pool, item);
+
+              /* TODO set the position parameter properly according to the layout */
+              g_signal_emit (menu, menu_signals[ITEM_ADDED], 0, item, 0);
+            }
+          else
+            {
+              g_debug ("    already included");
+            }
+
+          included_somewhere = TRUE;
+        }
+      else
+        {
+          g_debug ("  not to be included");
+          if (included_item != NULL)
+            {
+              g_debug ("    remove");
+              garcon_menu_item_pool_remove (menu->priv->pool, item);
+              g_signal_emit (menu, menu_signals[ITEM_REMOVED], 0, item);
+            }
+          else
+            {
+              g_debug ("    not included anyway");
+            }
+
+          included_somewhere = FALSE;
+        }
+
+      g_list_free (rules);
+    }
+
+  /* Iterate over all submenus */
+  for (iter = menu->priv->submenus; iter != NULL; iter = g_list_next (iter))
+    {
+      /* Resolve items of the submenu */
+      included_somewhere = garcon_menu_update_item (GARCON_MENU (iter->data), item, only_unallocated) || included_somewhere;
+    }
+
+  return included_somewhere;
 }
-#endif
 
 
 
@@ -2006,7 +2132,7 @@ garcon_menu_find_file_item (GarconMenu *menu,
       if (item != NULL)
         *menus = g_list_prepend (*menus, menu);
 
-      for (lp = menu->priv->submenus; lp != NULL; lp = lp->next)
+      for (lp = menu->priv->submenus; item == NULL && lp != NULL; lp = lp->next)
         item = garcon_menu_find_file_item (lp->data, file, menus);
     }
   else
@@ -2418,9 +2544,12 @@ garcon_menu_app_dir_changed (GarconMenu       *menu,
 {
   GarconMenuItem *item;
   GFileType       file_type;
+  gboolean        included_somewhere = FALSE;
+  GFile          *replacement_file;
   GList          *menus = NULL;
   GList          *lp;
   gchar          *desktop_id;
+  gchar          *uri;
 
   g_return_if_fail (GARCON_IS_MENU (menu));
 
@@ -2447,10 +2576,17 @@ garcon_menu_app_dir_changed (GarconMenu       *menu,
               /* 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");
+                  /* insert the item into the appropriate menus, if there are any */
+                  included_somewhere = garcon_menu_update_item (menu, item, FALSE);
+                  included_somewhere = garcon_menu_update_item (menu, item, TRUE) || included_somewhere;
+
+                  /* unload the item if it isn't included in any menus */
+                  if (!included_somewhere)
+                    {
+                      /* 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
                 {
@@ -2471,22 +2607,31 @@ garcon_menu_app_dir_changed (GarconMenu       *menu,
             }
           else
             {
-              desktop_id = garcon_menu_collect_file (menu, file);
+              /* determine the desktop ID for this file */
+              if (garcon_menu_collect_file (menu, file, NULL, NULL, &desktop_id))
+                {
+                  uri = g_file_get_uri (file);
 
-              g_debug ("  resolve item file => %s", desktop_id);
+                  /* try to load the desktop file from the item cache */
+                  item = garcon_menu_item_cache_lookup (menu->priv->cache, uri, desktop_id);
+                  if (item != NULL)
+                    {
+                      /* insert the item into the appropriate menus, if there are any */
+                      included_somewhere = garcon_menu_update_item (menu, item, FALSE);
+                      included_somewhere = garcon_menu_update_item (menu, item, TRUE) || included_somewhere;
+
+                      /* unload the item if it isn't included in any menus */
+                      if (!included_somewhere)
+                        {
+                          /* 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);
+                        }
+                    }
 
-#if 0
-              if (garcon_menu_resolve_item_file (menu, file, &item, &desktop_id))
-                {
-                  /* 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 */
+                  g_free (uri);
+                  g_free (desktop_id);
                 }
-#endif
             }
 
           /* free the menu list */
@@ -2506,6 +2651,7 @@ garcon_menu_app_dir_changed (GarconMenu       *menu,
        *      'item-added' signals)
        *    - monitor the newly created directory
        * 2) the new file is a regular file
+       *    - remove items with the same desktop id
        *    - load it into a GarconMenuItem
        *    - find the correct menu(s) for it
        *    - add it to those menus (make sure to emit 'item-added'
@@ -2535,6 +2681,8 @@ garcon_menu_app_dir_changed (GarconMenu       *menu,
           item = garcon_menu_find_file_item (menu, file, &menus);
           if (item != NULL)
             {
+              desktop_id = g_strdup (garcon_menu_item_get_desktop_id (item));
+
               /* reloading failed, remove the item from all menus and destroy it */
               for (lp = menus; lp != NULL; lp = lp->next)
                 {
@@ -2548,15 +2696,53 @@ garcon_menu_app_dir_changed (GarconMenu       *menu,
               /* 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);
+
+              /* NOTE: at this point a desktop file has been deleted (e.g. in 
+               * $HOME/.local/share/applications) but there may be a replacement
+               * for it (e.g. in /usr/local/share/applications) that was overloaded
+               * previously. so we now have to determine the desktop id again and then 
+               * try to load the corresponding menu item. this makes sure the 
+               * previously overloaded desktop file is picked up. */
+
+              /* NOTE: in theory we would have to do this even if the deleted file
+               * did not correspond to an existing item (e.g. empty files can override
+               * real desktop entries), but this is too complicated for now because 
+               * then we'd have to find out the desktop ID by splitting up the path
+               * into segments and iterating through the app dirs, removing them from
+               * the path segments and then replacing all dir separators with a "-".
+               * We can do that later... */
+
+              /* determine the next-priority desktop file with the same desktop ID */
+              if (garcon_menu_collect_file (menu, NULL, desktop_id, &replacement_file, NULL))
+                {
+                  uri = g_file_get_uri (replacement_file);
 
-          /* free the menu list */
-          g_list_free (menus);
+                  item = garcon_menu_item_cache_lookup (menu->priv->cache, uri, desktop_id);
+                  if (item != NULL)
+                    {
+                      /* insert the item into the appropriate menus, if there are any */
+                      included_somewhere = garcon_menu_update_item (menu, item, FALSE);
+                      included_somewhere = garcon_menu_update_item (menu, item, TRUE) || included_somewhere;
+
+                      /* unload the item if it isn't included in any menus */
+                      if (!included_somewhere)
+                        {
+                          /* 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);
+                        }
+                    }
+
+                  g_free (uri);
+                  g_object_unref (replacement_file);
+                }
+
+              g_free (desktop_id);
+              
+            }
         }
     }
 }
diff --git a/tests/test-display-menu.c b/tests/test-display-menu.c
index da3511a..fc9a615 100644
--- a/tests/test-display-menu.c
+++ b/tests/test-display-menu.c
@@ -146,6 +146,27 @@ create_item_icon (GarconMenuItem *item)
 
 
 static void
+item_changed (GarconMenuItem *item,
+              GtkWidget      *gtk_item)
+{
+  GdkPixbuf *icon;
+  GtkWidget *image;
+
+  /* Try reloading the icon */
+  icon = create_item_icon (item);
+
+  if (icon != NULL)
+    image = gtk_image_new_from_pixbuf (icon);
+  else
+    image = gtk_image_new_from_icon_name ("applications-other", ICON_SIZE);
+
+  gtk_menu_item_set_label (GTK_MENU_ITEM (gtk_item), garcon_menu_element_get_name (GARCON_MENU_ELEMENT (item)));
+  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (gtk_item), image);
+}
+
+
+
+static void
 create_item_widgets (GarconMenuItem *item,
                      GtkWidget      *parent_menu)
 {
@@ -168,6 +189,9 @@ create_item_widgets (GarconMenuItem *item,
 
   g_object_set_data_full (G_OBJECT (gtk_item), "garcon-menu-item", g_object_ref (item), g_object_unref);
 
+  /* React to changes made to the item on disk */
+  g_signal_connect (item, "changed", G_CALLBACK (item_changed), gtk_item);
+
   /* Execute command if item is clicked */
   g_signal_connect (gtk_item, "activate", G_CALLBACK (execute_item_command), item);
 }
@@ -201,6 +225,18 @@ directory_changed (GarconMenu          *menu,
 
 
 static void
+item_added (GarconMenu     *menu,
+            GarconMenuItem *item,
+            guint           position,
+            GtkWidget      *gtk_menu)
+{
+  /* Add menu item to the menu */
+  create_item_widgets (item, gtk_menu);
+}
+
+
+
+static void
 item_removed (GarconMenu     *menu,
               GarconMenuItem *item,
               GtkWidget      *gtk_menu)
@@ -302,14 +338,22 @@ create_menu_widgets (GtkWidget   *gtk_menu,
           /* 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-added", G_CALLBACK (item_added), gtk_submenu);
           g_signal_connect (submenu, "item-removed", G_CALLBACK (item_removed), gtk_submenu);
 
           /* Create widgets for submenu */
           create_menu_widgets (gtk_submenu, submenu);
 
           /* Destroy submenu if it is empty */
+          /* FIXME destroying menus will not work with monitoring. if a menu is destroyed and
+           * an item is added to it at runtime, where should we add it...? instead, we should
+           * just hide the empty menu */
+#if 0
           if (G_UNLIKELY (gtk_container_get_children (GTK_CONTAINER (gtk_submenu)) == NULL))
             gtk_widget_destroy (gtk_item);
+#endif
+          if (G_UNLIKELY (gtk_container_get_children (GTK_CONTAINER (gtk_submenu)) == NULL))
+            gtk_widget_hide (gtk_item);
         }
     }
 



More information about the Xfce4-commits mailing list