@@ -52,10 +52,36 @@ struct _CinnamonAppSystemPrivate {
5252 GHashTable * running_apps ;
5353 GHashTable * id_to_app ;
5454 GHashTable * startup_wm_class_to_app ;
55+ GPtrArray * top_level_directories ;
5556
5657 GSList * known_vendor_prefixes ;
5758};
5859
60+ typedef struct {
61+ GMenuTreeEntry * entry ;
62+ GPtrArray * categories ;
63+ } FlattenedEntry ;
64+
65+ static FlattenedEntry *
66+ flattened_entry_new (GMenuTreeEntry * entry )
67+ {
68+ g_return_val_if_fail (entry != NULL , NULL );
69+ FlattenedEntry * out = g_slice_new (FlattenedEntry );
70+ out -> entry = gmenu_tree_item_ref (entry );
71+ out -> categories = g_ptr_array_new_with_free_func ((GDestroyNotify ) gmenu_tree_item_unref );
72+ return out ;
73+ }
74+
75+ static void
76+ flattened_entry_free (FlattenedEntry * entry )
77+ {
78+ g_return_if_fail (entry != NULL );
79+ g_clear_pointer (& entry -> entry , gmenu_tree_item_unref );
80+ g_clear_pointer (& entry -> categories , g_ptr_array_unref );
81+ g_slice_free (FlattenedEntry , entry );
82+ }
83+
84+
5985static void cinnamon_app_system_finalize (GObject * object );
6086static void on_apps_tree_changed_cb (GMenuTree * tree , gpointer user_data );
6187CinnamonApp * lookup_heuristic_basename (CinnamonAppSystem * system , const char * name );
@@ -127,6 +153,8 @@ cinnamon_app_system_init (CinnamonAppSystem *self)
127153 NULL ,
128154 (GDestroyNotify )g_object_unref );
129155
156+ priv -> top_level_directories = NULL ;
157+
130158 priv -> startup_wm_class_to_app = g_hash_table_new_full (g_str_hash , g_str_equal ,
131159 NULL ,
132160 (GDestroyNotify )g_object_unref );
@@ -476,12 +504,16 @@ deduplicate_apps (GPtrArray *app_array,
476504 DEBUG_RENAMING ("Done renaming for '%s'\n\n" , (gchar * ) key );
477505}
478506
479- static void
507+ static gboolean
480508get_flattened_entries_recurse (GMenuTreeDirectory * dir ,
481- GHashTable * entry_set )
509+ GMenuTreeDirectory * top_dir ,
510+ GHashTable * flattened_entry_set ,
511+ GPtrArray * top_level_dirs )
482512{
483513 GMenuTreeIter * iter = gmenu_tree_directory_iter (dir );
484514 GMenuTreeItemType next_type ;
515+ gboolean has_entries = FALSE;
516+ gboolean is_root = top_dir == NULL ;
485517
486518 while ((next_type = gmenu_tree_iter_next (iter )) != GMENU_TREE_ITEM_INVALID )
487519 {
@@ -492,17 +524,36 @@ get_flattened_entries_recurse (GMenuTreeDirectory *dir,
492524 case GMENU_TREE_ITEM_ENTRY :
493525 {
494526 GMenuTreeEntry * entry ;
527+ FlattenedEntry * f_entry ;
495528 item = entry = gmenu_tree_iter_get_entry (iter );
496- /* Key is owned by entry */
497- g_hash_table_replace (entry_set ,
498- (char * )gmenu_tree_entry_get_desktop_file_id (entry ),
499- gmenu_tree_item_ref (entry ));
529+ char * desktop_id = (char * )gmenu_tree_entry_get_desktop_file_id (entry );
530+
531+ f_entry = g_hash_table_lookup (flattened_entry_set , desktop_id );
532+ if (!f_entry )
533+ {
534+ f_entry = flattened_entry_new (entry );
535+
536+ if (!is_root )
537+ g_ptr_array_add (f_entry -> categories , g_strdup (gmenu_tree_directory_get_menu_id (top_dir )));
538+
539+ /* Key is owned by entry */
540+ g_hash_table_insert (flattened_entry_set , desktop_id , f_entry );
541+ }
542+ g_ptr_array_add (f_entry -> categories , g_strdup (gmenu_tree_directory_get_menu_id (dir )));
543+ has_entries = TRUE;
500544 }
501545 break ;
502546 case GMENU_TREE_ITEM_DIRECTORY :
503547 {
504- item = gmenu_tree_iter_get_directory (iter );
505- get_flattened_entries_recurse ((GMenuTreeDirectory * )item , entry_set );
548+ GMenuTreeDirectory * next_dir ;
549+ item = next_dir = gmenu_tree_iter_get_directory (iter );
550+ gboolean res = get_flattened_entries_recurse (next_dir ,
551+ is_root ? dir : top_dir ,
552+ flattened_entry_set ,
553+ top_level_dirs );
554+ has_entries |= res ;
555+ if (is_root && res && !g_ptr_array_find (top_level_dirs , item , NULL ))
556+ g_ptr_array_add (top_level_dirs , gmenu_tree_item_ref (item ));
506557 }
507558 break ;
508559 case GMENU_TREE_ITEM_INVALID :
@@ -518,26 +569,7 @@ get_flattened_entries_recurse (GMenuTreeDirectory *dir,
518569 }
519570
520571 gmenu_tree_iter_unref (iter );
521- }
522-
523- static GHashTable *
524- get_flattened_entries_from_tree (GMenuTree * tree )
525- {
526- GHashTable * table ;
527- GMenuTreeDirectory * root ;
528-
529- table = g_hash_table_new_full (g_str_hash , g_str_equal ,
530- (GDestroyNotify ) NULL ,
531- (GDestroyNotify ) gmenu_tree_item_unref );
532-
533- root = gmenu_tree_get_root_directory (tree );
534-
535- if (root != NULL )
536- get_flattened_entries_recurse (root , table );
537-
538- gmenu_tree_item_unref (root );
539-
540- return table ;
572+ return has_entries ;
541573}
542574
543575static void
@@ -547,11 +579,20 @@ on_apps_tree_changed_cb (GMenuTree *tree,
547579 CinnamonAppSystem * self = CINNAMON_APP_SYSTEM (user_data );
548580 GError * error = NULL ;
549581 GHashTable * new_apps , * display_names ;
582+ GPtrArray * dirs ;
583+ GMenuTreeDirectory * root ;
550584 GHashTableIter iter ;
551585 gpointer key , value ;
552586
553587 g_assert (tree == self -> priv -> apps_tree );
554588
589+ new_apps = g_hash_table_new_full (g_str_hash , g_str_equal ,
590+ (GDestroyNotify ) NULL ,
591+ (GDestroyNotify ) flattened_entry_free );
592+
593+ dirs = g_ptr_array_new_with_free_func ((GDestroyNotify ) gmenu_tree_item_unref );
594+ g_clear_pointer (& self -> priv -> top_level_directories , g_ptr_array_unref );
595+
555596 g_slist_free_full (self -> priv -> known_vendor_prefixes , g_free );
556597 self -> priv -> known_vendor_prefixes = NULL ;
557598
@@ -569,7 +610,14 @@ on_apps_tree_changed_cb (GMenuTree *tree,
569610 return ;
570611 }
571612
572- new_apps = get_flattened_entries_from_tree (self -> priv -> apps_tree );
613+ root = gmenu_tree_get_root_directory (self -> priv -> apps_tree );
614+
615+ if (root != NULL )
616+ get_flattened_entries_recurse (root , NULL , new_apps , dirs );
617+
618+ gmenu_tree_item_unref (root );
619+
620+ self -> priv -> top_level_directories = dirs ;
573621
574622 display_names = g_hash_table_new_full (g_str_hash , g_str_equal ,
575623 (GDestroyNotify ) g_free ,
@@ -579,7 +627,8 @@ on_apps_tree_changed_cb (GMenuTree *tree,
579627 while (g_hash_table_iter_next (& iter , & key , & value ))
580628 {
581629 const char * id = key ;
582- GMenuTreeEntry * entry = value ;
630+ FlattenedEntry * f_entry = value ;
631+ GMenuTreeEntry * entry = f_entry -> entry ;
583632 GMenuTreeEntry * old_entry ;
584633 char * prefix ;
585634 CinnamonApp * app ;
@@ -627,13 +676,14 @@ on_apps_tree_changed_cb (GMenuTree *tree,
627676#endif
628677
629678 _cinnamon_app_set_entry (app , entry );
679+ _cinnamon_app_set_categories (app , f_entry -> categories );
630680
631681 g_object_ref (app ); /* Extra ref, removed in _replace below */
632682 }
633683 else
634684 {
635685 old_entry = NULL ;
636- app = _cinnamon_app_new (entry );
686+ app = _cinnamon_app_new (entry , f_entry -> categories );
637687
638688 DEBUG_RENAMING ("New app entry: '%s' with source '%s'\n" ,
639689 _cinnamon_app_get_common_name (app ),
@@ -748,7 +798,7 @@ cinnamon_app_system_get_tree (CinnamonAppSystem *self)
748798/**
749799 * cinnamon_app_system_get_default:
750800 *
751- * Return Value : (transfer none): The global #CinnamonAppSystem singleton
801+ * Returns : (transfer none): The global #CinnamonAppSystem singleton
752802 */
753803CinnamonAppSystem *
754804cinnamon_app_system_get_default (void )
@@ -761,6 +811,19 @@ cinnamon_app_system_get_default (void)
761811 return instance ;
762812}
763813
814+ /**
815+ * cinnamon_app_system_get_top_directories:
816+ *
817+ * Returns: (nullable) (transfer none) (element-type GMenuTreeDirectory): A list of top level menu directories.
818+ */
819+ GPtrArray *
820+ cinnamon_app_system_get_top_directories (CinnamonAppSystem * self )
821+ {
822+ return self -> priv -> top_level_directories ;
823+ }
824+
825+
826+
764827gboolean
765828case_insensitive_search (const char * key ,
766829 const char * value ,
@@ -780,7 +843,7 @@ case_insensitive_search (const char *key,
780843 *
781844 * Find a #CinnamonApp corresponding to an id.
782845 *
783- * Return value : (transfer none): The #CinnamonApp for id, or %NULL if none
846+ * Returns : (transfer none): The #CinnamonApp for id, or %NULL if none
784847 */
785848CinnamonApp *
786849cinnamon_app_system_lookup_app (CinnamonAppSystem * self ,
0 commit comments