Author: jannis Date: 2007-01-10 23:04:24 +0000 (Wed, 10 Jan 2007) New Revision: 24350
Modified: libfrap/trunk/libfrap/menu/ChangeLog libfrap/trunk/libfrap/menu/STATUS libfrap/trunk/libfrap/menu/frap-menu-item-cache.c libfrap/trunk/libfrap/menu/frap-menu-item-pool.c libfrap/trunk/libfrap/menu/frap-menu-item.c libfrap/trunk/libfrap/menu/frap-menu-item.h libfrap/trunk/libfrap/menu/frap-menu.c Log: * frap-menu-item.{c,h}: Remove "allocated" property and replace it with a kind of reference counter. Add frap_menu_item_ref/unref methods to be used instead of frap_menu_item_set_allocated() which has been removed. Use "guint ... : 1" notation for boolean values in the structs belonging to FrapMenuItem. * frap-menu-item-pool.c: Call frap_menu_item_ref when adding an item to the pool of a menu (instead of setting the allocated value directly). * frap-menu.c: Use "guint ... : 1" notation for boolean values in structs. Fix frap_menu_set_filename to make free'ing the filename possible. Implement recursive (bottom -> top) collecting of directory and legacy dirs (might be wrong for legacy dirs, I need to verify this during the next days). Implement two-pass mechanism to resolve menu items (in order to be able to handle <OnlyUnallocated> elements). Only set menu parse state to _STATE_ROOT if there are no other menus left on the stack. * STATUS: Update implementation STATUS. Modified: libfrap/trunk/libfrap/menu/ChangeLog =================================================================== --- libfrap/trunk/libfrap/menu/ChangeLog 2007-01-10 22:58:45 UTC (rev 24349) +++ libfrap/trunk/libfrap/menu/ChangeLog 2007-01-10 23:04:24 UTC (rev 24350) @@ -1,3 +1,23 @@ +2007-01-11 Jannis Pohlmann <[EMAIL PROTECTED]> + + * frap-menu-item.{c,h}: Remove "allocated" property and replace it + with a kind of reference counter. Add frap_menu_item_ref/unref + methods to be used instead of frap_menu_item_set_allocated() which + has been removed. Use "guint ... : 1" notation for boolean values + in the structs belonging to FrapMenuItem. + * frap-menu-item-pool.c: Call frap_menu_item_ref when adding an item + to the pool of a menu (instead of setting the allocated value + directly). + * frap-menu.c: Use "guint ... : 1" notation for boolean values in + structs. Fix frap_menu_set_filename to make free'ing the filename + possible. Implement recursive (bottom -> top) collecting of + directory and legacy dirs (might be wrong for legacy dirs, I need + to verify this during the next days). Implement two-pass mechanism + to resolve menu items (in order to be able to handle + <OnlyUnallocated> elements). Only set menu parse state to + _STATE_ROOT if there are no other menus left on the stack. + * STATUS: Update implementation STATUS. + 2006-11-07 Jannis Pohlmann <[EMAIL PROTECTED]> * frap-menu-item-pool.c: Fix backwards compatibility by passing Modified: libfrap/trunk/libfrap/menu/STATUS =================================================================== --- libfrap/trunk/libfrap/menu/STATUS 2007-01-10 22:58:45 UTC (rev 24349) +++ libfrap/trunk/libfrap/menu/STATUS 2007-01-10 23:04:24 UTC (rev 24350) @@ -25,6 +25,9 @@ [x] <Directory> [x] <OnlyUnallocated> and <NotOnlyUnallocated> + + Supported by using a two-pass resolving mechanism as stated + in the spec ("Generating the menus"). [x] <Deleted> and <NotDeleted> @@ -61,8 +64,10 @@ [-] <LegacyDir> - <LegacyDir> elements are parsed into a string list, but there is - no further parsing or merging performed afterwards - not yet. + <LegacyDir> elements are parsed and added to the menus + which contain them in the menu file. Legacy menus are created + for legacy dirs with a .directory file. However, their desktop + files are not parsed yet. [-] <DefaultLegacyDirs> Modified: libfrap/trunk/libfrap/menu/frap-menu-item-cache.c =================================================================== --- libfrap/trunk/libfrap/menu/frap-menu-item-cache.c 2007-01-10 22:58:45 UTC (rev 24349) +++ libfrap/trunk/libfrap/menu/frap-menu-item-cache.c 2007-01-10 23:04:24 UTC (rev 24350) @@ -277,7 +277,8 @@ /* Add item to the hash table */ g_hash_table_replace (cache->priv->items, g_strdup (filename), item); - /* Grab a reference on the item */ + /* Grab a reference on the item, but don't increase the allocation + * counter */ g_object_ref (G_OBJECT (item)); return item; @@ -298,7 +299,7 @@ /* The file has been loaded, add the item to the hash table */ g_hash_table_replace (cache->priv->items, g_strdup (filename), item); - /* Grab a reference on it */ + /* Grab a reference on it but don't increase the allocation counter */ g_object_ref (G_OBJECT (item)); } Modified: libfrap/trunk/libfrap/menu/frap-menu-item-pool.c =================================================================== --- libfrap/trunk/libfrap/menu/frap-menu-item-pool.c 2007-01-10 22:58:45 UTC (rev 24349) +++ libfrap/trunk/libfrap/menu/frap-menu-item-pool.c 2007-01-10 23:04:24 UTC (rev 24350) @@ -158,11 +158,8 @@ /* Insert into the hash table and remove old item (if any) */ g_hash_table_replace (pool->priv->items, g_strdup (frap_menu_item_get_desktop_id (item)), item); - /* Set allocation state of the item */ - frap_menu_item_set_allocated (item, TRUE); - /* Grab a reference on the item */ - g_object_ref (G_OBJECT (item)); + frap_menu_item_ref (item); } Modified: libfrap/trunk/libfrap/menu/frap-menu-item.c =================================================================== --- libfrap/trunk/libfrap/menu/frap-menu-item.c 2007-01-10 22:58:45 UTC (rev 24349) +++ libfrap/trunk/libfrap/menu/frap-menu-item.c 2007-01-10 23:04:24 UTC (rev 24350) @@ -46,7 +46,6 @@ PROP_NAME, PROP_ICON_NAME, PROP_COMMAND, - PROP_ALLOCATED, }; @@ -83,13 +82,13 @@ GList *categories; /* Whether this application requires a terminal to be started in */ - gboolean requires_terminal; + guint requires_terminal : 1; /* Whether this menu item should be hidden */ - gboolean hidden; + guint hidden : 1; /* Whether this application supports startup notification */ - gboolean supports_startup_notification; + guint supports_startup_notification : 1; /* Name to be displayed for the menu item */ gchar *name; @@ -100,8 +99,10 @@ /* Menu item icon name */ gchar *icon_name; - /* Whether this menu item is allocated by a menu */ - gboolean allocated; + /* Counter keeping the number of menus which use this item. This works + * like a reference counter and should be increased / decreased by FrapMenu + * items whenever the item is added to or removed from the menu. */ + guint num_allocated; }; struct _FrapMenuItem @@ -267,19 +268,6 @@ _("Name of the application icon"), NULL, G_PARAM_READWRITE)); - - /** - * FrapMenuItem:allocated: - * - * Whether this item is allocated by a menu. - **/ - g_object_class_install_property (gobject_class, - PROP_ICON_NAME, - g_param_spec_boolean ("allocated", - _("Allocated"), - _("Allocation state of the item"), - FALSE, - G_PARAM_READWRITE)); } @@ -294,6 +282,7 @@ item->priv->command = NULL; item->priv->icon_name = NULL; item->priv->categories = NULL; + item->priv->num_allocated = 0; } @@ -352,10 +341,6 @@ case PROP_ICON_NAME: break; - case PROP_ALLOCATED: - g_value_set_boolean (value, frap_menu_item_get_allocated (item)); - break; - default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -406,10 +391,6 @@ frap_menu_item_set_icon_name (item, g_value_get_string (value)); break; - case PROP_ALLOCATED: - frap_menu_item_set_allocated (item, g_value_get_boolean (value)); - break; - default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -826,8 +807,28 @@ void +frap_menu_item_ref (FrapMenuItem *item) +{ + g_return_if_fail (FRAP_IS_MENU_ITEM (item)); + + /* Increment the allocation counter */ + frap_menu_item_increment_allocated (item); + + /* Grab a reference on the object */ + g_object_ref (G_OBJECT (item)); +} + + + +void frap_menu_item_unref (FrapMenuItem *item) { + g_return_if_fail (FRAP_IS_MENU_ITEM (item)); + + /* Decrement allocation counter */ + frap_menu_item_decrement_allocated (item); + + /* Decrement the reference counter */ g_object_unref (G_OBJECT (item)); } @@ -837,21 +838,25 @@ frap_menu_item_get_allocated (FrapMenuItem *item) { g_return_val_if_fail (FRAP_IS_MENU_ITEM (item), FALSE); - return item->priv->allocated; + return item->priv->num_allocated > 0; } void -frap_menu_item_set_allocated (FrapMenuItem *item, - gboolean allocated) +frap_menu_item_increment_allocated (FrapMenuItem *item) { g_return_if_fail (FRAP_IS_MENU_ITEM (item)); + item->priv->num_allocated++; +} - if (item->priv->allocated == allocated) - return; - item->priv->allocated = allocated; - g_object_notify (G_OBJECT (item), "allocated"); +void +frap_menu_item_decrement_allocated (FrapMenuItem *item) +{ + g_return_if_fail (FRAP_IS_MENU_ITEM (item)); + + if (item->priv->num_allocated > 0) + item->priv->num_allocated--; } Modified: libfrap/trunk/libfrap/menu/frap-menu-item.h =================================================================== --- libfrap/trunk/libfrap/menu/frap-menu-item.h 2007-01-10 22:58:45 UTC (rev 24349) +++ libfrap/trunk/libfrap/menu/frap-menu-item.h 2007-01-10 23:04:24 UTC (rev 24350) @@ -73,10 +73,11 @@ GList *frap_menu_item_get_categories (FrapMenuItem *item); void frap_menu_item_set_categories (FrapMenuItem *item, GList *categories); +void frap_menu_item_ref (FrapMenuItem *item); void frap_menu_item_unref (FrapMenuItem *item); gboolean frap_menu_item_get_allocated (FrapMenuItem *item); -void frap_menu_item_set_allocated (FrapMenuItem *item, - gboolean allocated); +void frap_menu_item_increment_allocated (FrapMenuItem *item); +void frap_menu_item_decrement_allocated (FrapMenuItem *item); G_END_DECLS; Modified: libfrap/trunk/libfrap/menu/frap-menu.c =================================================================== --- libfrap/trunk/libfrap/menu/frap-menu.c 2007-01-10 22:58:45 UTC (rev 24349) +++ libfrap/trunk/libfrap/menu/frap-menu.c 2007-01-10 23:04:24 UTC (rev 24350) @@ -237,7 +237,8 @@ FrapMenuRules *rules); static void frap_menu_add_move (FrapMenu *menu, FrapMenuMove *move); -static void frap_menu_resolve_items (FrapMenu *menu); +static void frap_menu_resolve_items (FrapMenu *menu, + gboolean only_unallocated); static void frap_menu_resolve_items_from_path (FrapMenu *menu, const gchar *path, const gchar *id_prefix); @@ -273,10 +274,10 @@ GSList *app_dirs; /* Only include desktop entries not used in other menus */ - gboolean only_unallocated; + guint only_unallocated : 1; /* Whether this menu should be ignored or not */ - gboolean deleted; + guint deleted : 1; /* Include/exclude rules */ GSList *rules; @@ -674,12 +675,11 @@ frap_menu_set_filename (FrapMenu *menu, const gchar *filename) { g_return_if_fail (FRAP_IS_MENU (menu)); - g_return_if_fail (filename != NULL); /* Abort if filenames are equal */ if (G_UNLIKELY (menu->priv->filename != NULL)) { - if (G_UNLIKELY (g_utf8_collate (filename, menu->priv->filename) == 0)) + if (G_UNLIKELY (filename != NULL && g_utf8_collate (filename, menu->priv->filename) == 0)) return; /* Free old filename */ @@ -828,9 +828,39 @@ GSList* frap_menu_get_directory_dirs (FrapMenu *menu) { + FrapMenu *current_menu; + GSList *directories = NULL; + GList *menus = NULL; + GList *iter; + GSList *iter2; + g_return_val_if_fail (FRAP_IS_MENU (menu), NULL); - /* TODO collect directories from the bottom up to the root menu */ - return menu->priv->directory_dirs; + + /* Collect all menus from menu -> parent -> ... -> root */ + for (current_menu = menu; current_menu != NULL; current_menu = current_menu->priv->parent) + menus = g_list_prepend (menus, current_menu); + + /* Iterate over all menus from root -> parent -> ... -> menu */ + for (iter = menus; iter != NULL; iter = g_list_next (iter)) + { + /* Fetch current menu */ + current_menu = FRAP_MENU (iter->data); + + /* Iterate over all directory dirs */ + for (iter2 = current_menu->priv->directory_dirs; iter2 != NULL; iter2 = g_slist_next (iter2)) + { + /* Append directory dir to the list */ + directories = g_slist_append (directories, iter2->data); + } + + /* Free the directory dir list */ + g_slist_free (iter2); + } + + /* Free menu list */ + g_list_free (menus); + + return directories; } @@ -838,11 +868,44 @@ GSList* frap_menu_get_legacy_dirs (FrapMenu *menu) { + /* FIXME: Collecting legacy dirs from the bottom up might be wrong. Perhaps + * only <Menu> items with <LegacyDir> elements are allowed to parse + * legacy menu hierarchies - verify this! + */ + + FrapMenu *current_menu; + GSList *directories = NULL; + GList *menus = NULL; + GList *iter; + GSList *iter2; + g_return_val_if_fail (FRAP_IS_MENU (menu), NULL); - /* TODO collect directories from the bottom up to the root menu - does the - * spec treat legacy dirs differently than app dirs and directory dirs? - * */ - return menu->priv->legacy_dirs; + + /* Collect all menus from menu -> parent -> ... -> root */ + for (current_menu = menu; current_menu != NULL; current_menu = current_menu->priv->parent) + menus = g_list_prepend (menus, current_menu); + + /* Iterate over all menus from root -> parent -> ... -> menu */ + for (iter = menus; iter != NULL; iter = g_list_next (iter)) + { + /* Fetch current menu */ + current_menu = FRAP_MENU (iter->data); + + /* Iterate over all legacy directories */ + for (iter2 = current_menu->priv->legacy_dirs; iter2 != NULL; iter2 = g_slist_next (iter2)) + { + /* Append legacy dir to the list */ + directories = g_slist_append (directories, iter2->data); + } + + /* Free the legacy dir list */ + g_slist_free (iter2); + } + + /* Free menu list */ + g_list_free (menus); + + return directories; } @@ -963,12 +1026,16 @@ g_list_free (menu_context.menu_stack); g_list_free (menu_context.rule_stack); +#if 0 frap_menu_resolve_legacy_menus (menu); +#endif frap_menu_remove_duplicates (menu); frap_menu_resolve_directory (menu); frap_menu_resolve_moves (menu); frap_menu_resolve_deleted (menu); - frap_menu_resolve_items (menu); + + frap_menu_resolve_items (menu, FALSE); + frap_menu_resolve_items (menu, TRUE); } @@ -1068,11 +1135,8 @@ else if (g_utf8_collate (element_name, "Menu") == 0) { /* Create new menu */ - FrapMenu *menu = g_object_new (FRAP_TYPE_MENU, NULL); + FrapMenu *menu = g_object_new (FRAP_TYPE_MENU, "filename", current_menu->priv->filename, NULL); - /* Silently copy filename attribute from the current menu */ - menu->priv->filename = g_strdup (current_menu->priv->filename); - /* Add menu as submenu to the current menu */ frap_menu_add_menu (current_menu, menu); @@ -1189,8 +1253,10 @@ /* Remove current menu from stack */ menu_context->menu_stack = g_list_delete_link (menu_context->menu_stack, g_list_first (menu_context->menu_stack)); - /* Set parse state */ - menu_context->state = FRAP_MENU_PARSE_STATE_ROOT; + /* Set parse state to _STATE_ROOT only if there are no other menus + * left on the stack. Otherwise, we're still inside a <Menu> element. */ + if (G_LIKELY (g_list_length (menu_context->menu_stack) == 1)) + menu_context->state = FRAP_MENU_PARSE_STATE_ROOT; } break; @@ -1518,7 +1584,7 @@ gchar *kde_bin_dir = g_build_path (G_DIR_SEPARATOR_S, kde_dir, "bin", NULL); /* Expand PATH to include KDEDIR/bin - if necessary */ - gchar *occurence = g_strrstr (path, kde_bin_dir); + const gchar *occurence = g_strrstr (path, kde_bin_dir); if (G_LIKELY (occurence == NULL)) { /* PATH = $PATH:$KDEDIR/bin */ @@ -1530,8 +1596,6 @@ /* Free expanded PATH value */ g_free (kde_path); } - else - g_free (occurence); /* Free KDEDIR/bin */ g_free (kde_bin_dir); @@ -1596,11 +1660,35 @@ { int i; gchar *path; + gchar *kde_data_dir; + const gchar *kde_dir; const gchar * const *dirs; g_return_if_fail (FRAP_IS_MENU (menu)); + /* Append $KDEDIR/share/applications as a workaround for distributions + * not installing KDE menu files properly into $XDG_DATA_DIR */ + + /* Get KDEDIR environment variable */ + kde_dir = g_getenv ("KDEDIR"); + + /* Check if this variable is set */ + if (G_UNLIKELY (kde_dir != NULL)) + { + /* Build KDE data dir */ + kde_data_dir = g_build_filename (kde_dir, "share", "applications", NULL); + + /* Add it as an app dir if it exists */ + if (G_LIKELY (g_file_test (kde_data_dir, G_FILE_TEST_IS_DIR))) + frap_menu_add_app_dir (menu, kde_data_dir); + + /* Free the KDE data dir */ + g_free (kde_data_dir); + } + + /* The $KDEDIR workaround ends here */ + /* Append system-wide data dirs */ dirs = g_get_system_data_dirs (); for (i = 0; dirs[i] != NULL; i++) @@ -1747,10 +1835,14 @@ /* Build absolute filename for this entry */ absolute_filename = g_build_filename (path, filename, NULL); - /* Check if we have a .directory entry */ - if (G_UNLIKELY (g_utf8_collate (".directory", filename) == 0)) + if (g_file_test (absolute_filename, G_FILE_TEST_IS_DIR)) { - /* Create the directory object for the legacy menu */ + /* We have a subdir -> create another legacy menu for this subdirectory */ + frap_menu_resolve_legacy_menu (legacy_menu, absolute_filename); + } + else if (g_utf8_collate (".directory", filename) == 0) + { + /* We have a .directory file -> create the directory object for the legacy menu */ directory = g_object_new (FRAP_TYPE_MENU_DIRECTORY, "filename", absolute_filename, NULL); } } @@ -1765,6 +1857,7 @@ /* Add legacy menu to its new parent */ frap_menu_add_menu (menu, legacy_menu); } + else { /* Destroy the legacy menu again - no .directory file found */ g_object_unref (legacy_menu); @@ -1848,6 +1941,8 @@ g_slist_foreach (submenu->priv->app_dirs, (GFunc) frap_menu_merge_app_dir, merged_menu); g_slist_foreach (submenu->priv->rules, (GFunc) frap_menu_merge_rule, merged_menu); + /* TODO Merge submenus of submenu and merged_menu! */ + /* Add merged menu to the new list of submenus if not included already */ if (g_slist_find (merged_submenus, merged_menu) == NULL) merged_submenus = g_slist_append (merged_submenus, merged_menu); @@ -2067,7 +2162,8 @@ static void -frap_menu_resolve_items (FrapMenu *menu) +frap_menu_resolve_items (FrapMenu *menu, + gboolean only_unallocated) { GSList *iter; GDir *dir; @@ -2077,21 +2173,28 @@ /* TODO Remove all items from the pool if there are no include rules! */ - /* Iterate over all application directories */ - for (iter = frap_menu_get_app_dirs (menu); iter != NULL; iter = g_slist_next (iter)) + /* Resolve items in this menu (if it matches the only_unallocated argument. + * This means that in the first pass, all items of menus without + * <OnlyUnallocated /> are resolved and in the second pass, only items of + * menus with <OnlyUnallocated /> are resolved */ + if (menu->priv->only_unallocated == only_unallocated) { - /* Resolve items in the current directory */ - frap_menu_resolve_items_from_path (menu, iter->data, NULL); + /* Iterate over all application directories */ + for (iter = frap_menu_get_app_dirs (menu); iter != NULL; iter = g_slist_next (iter)) + { + /* Resolve items in the current directory */ + frap_menu_resolve_items_from_path (menu, iter->data, NULL); + } + + /* Filter items according to the include/exclude rules */ + frap_menu_item_pool_apply_rules (menu->priv->pool, menu->priv->rules); } - /* Filter items according to the include/exclude rules */ - frap_menu_item_pool_apply_rules (menu->priv->pool, menu->priv->rules); - /* Iterate over all submenus */ for (iter = menu->priv->submenus; iter != NULL; iter = g_slist_next (iter)) { /* Resolve items of the submenu */ - frap_menu_resolve_items (FRAP_MENU (iter->data)); + frap_menu_resolve_items (FRAP_MENU (iter->data), only_unallocated); } } @@ -2264,6 +2367,10 @@ /* Remove submenu from the submenu list */ menu->priv->submenus = g_slist_remove (menu->priv->submenus, submenu); + /* TODO Merge submenus of submenu and target_submenu. Perhaps even + * find a better way for merging menus as the current way is a) + * duplicated (see consolidate_child_menus) and b) buggy */ + /* TODO Free the submenu - this introduces a strange item pool * error ... */ /* g_object_unref (submenu); */ _______________________________________________ Xfce4-commits mailing list Xfce4-commits@xfce.org http://foo-projects.org/mailman/listinfo/xfce4-commits