[Xfce4-commits] <garcon:jannis/global-monitoring> Additional work on app dir monitoring.
Jannis Pohlmann
noreply at xfce.org
Sun Sep 5 14:50:30 CEST 2010
Updating branch refs/heads/jannis/global-monitoring
to 60ebe007560bad63898aadcea3e20a6aae23e267 (commit)
from 3861be991174045868ca5a74c16db9f05f8ccb7a (commit)
commit 60ebe007560bad63898aadcea3e20a6aae23e267
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 5978120..5f6a5d6 100644
--- a/garcon/garcon-menu-element.c
+++ b/garcon/garcon-menu-element.c
@@ -116,3 +116,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 461ed02..cc1b91c 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 9642683..6a5c6fd 100644
--- a/garcon/garcon-menu.c
+++ b/garcon/garcon-menu.c
@@ -103,6 +103,9 @@ enum
{
RELOAD_REQUIRED,
DIRECTORY_CHANGED,
+ ITEM_ADDED,
+ ITEM_CHANGED,
+ ITEM_REMOVED,
LAST_SIGNAL,
};
@@ -151,6 +154,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);
@@ -300,6 +308,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");
}
@@ -314,6 +359,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;
}
@@ -379,8 +425,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
}
@@ -1049,7 +1099,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);
}
}
@@ -1740,6 +1790,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)
{
@@ -1753,10 +1850,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)
@@ -1922,6 +2020,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);
}
@@ -1960,7 +2061,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);
@@ -2133,6 +2234,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));
@@ -2143,8 +2246,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,
@@ -2153,6 +2258,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
@@ -2161,15 +2268,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)
@@ -2197,13 +2342,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