/* vim: set sw=4 ts=4 sts=4 et: */
#include "Efreet.h"
#include "efreet_private.h"
/**
* Efreet_Menu_Move
*/
typedef struct Efreet_Menu_Move Efreet_Menu_Move;
/**
* Efreet_Menu_Move
* Info on a menu movement
*/
struct Efreet_Menu_Move
{
char *old_name; /**< The menu path to move from */
char *new_name; /**< The menu path to move too */
};
/**
* Efreet_Menu_Internal
*/
typedef struct Efreet_Menu_Internal Efreet_Menu_Internal;
/**
* Efreet_Menu_Internal
* Contains the information about a menu
*/
struct Efreet_Menu_Internal
{
struct
{
char *path; /**< The base file path */
char *name; /**< The filename for this menu */
} file; /**< The menu file information */
struct
{
const char *internal; /**< The menu name */
const char *name; /**< Name to use in the menus */
} name; /**< The names for this menu */
Efreet_Desktop *directory; /**< The directory */
Ecore_DList *directories; /**< All the directories set in the menu file */
Efreet_Menu_Move *current_move; /**< The current move */
Eina_List *app_dirs; /**< .desktop application directories */
Eina_List *app_pool; /**< application pool */
Eina_List *applications; /**< applications in this menu */
Ecore_DList *directory_dirs; /**< .directory file directories */
Eina_Hash *directory_cache; /**< .directory dirs */
Eina_List *moves; /**< List of moves to be handled by the menu */
Eina_List *filters; /**< Include and Exclude filters */
Efreet_Menu_Internal *parent; /**< Our parent menu */
Eina_List *sub_menus; /**< Our sub menus */
Eina_List *layout; /**< This menus layout */
Eina_List *default_layout; /**< Default layout */
char show_empty; /**< Whether to show empty menus */
char in_line; /**< Whether this meny can be inlined */
char inline_limit; /**< Number of elements which triggers inline */
char inline_header; /**< Whether we should use the header name when this menu is inlined */
char inline_alias; /**< Whether we should use the menu name when inlining */
unsigned char seen_allocated:1; /**< have we set the only_unallocated */
unsigned char only_unallocated:1; /**< Show only unallocated .desktops */
unsigned char seen_deleted:1; /**< Have we seen the deleted item yet */
unsigned char deleted:1; /**< The menu is deleted */
};
/**
* Efreet_Menu_App_Dir
*/
typedef struct Efreet_Menu_App_Dir Efreet_Menu_App_Dir;
/**
* Holds information on an app dir
*/
struct Efreet_Menu_App_Dir
{
char *path; /**< directory path */
char *prefix; /**< If it's legacy it can have a prefix */
unsigned int legacy:1; /**< is this a legacy dir */
};
/**
* The type of operations we can perform with a filter
*/
enum Efreet_Menu_Filter_Op_Type
{
EFREET_MENU_FILTER_OP_OR,
EFREET_MENU_FILTER_OP_AND,
EFREET_MENU_FILTER_OP_NOT
};
/**
* Efreet_Menu_Filter_Op_Type
*/
typedef enum Efreet_Menu_Filter_Op_Type Efreet_Menu_Filter_Op_Type;
/**
* The type of filter
*/
enum Efreet_Menu_Filter_Type
{
EFREET_MENU_FILTER_INCLUDE,
EFREET_MENU_FILTER_EXCLUDE
};
/**
* Efreet_Menu_Filter_Type
*/
typedef enum Efreet_Menu_Filter_Type Efreet_Menu_Filter_Type;
/**
* Efreet_Menu_Filter_Op
*/
typedef struct Efreet_Menu_Filter_Op Efreet_Menu_Filter_Op;
/**
* Efreet_Menu_Filter_Op
* Contains information on a filter operation
*/
struct Efreet_Menu_Filter_Op
{
Efreet_Menu_Filter_Op_Type type; /**< The type of operation */
Eina_List *categories; /**< The categories this op applies too */
Eina_List *filenames; /**< The filenames this op applies too */
Eina_List *filters; /**< Child filters */
unsigned char all:1; /**< Applies to all .desktop files */
};
/**
* Efreet_Menu_Filter
*/
typedef struct Efreet_Menu_Filter Efreet_Menu_Filter;
/**
* Efreet_Menu_Filter
* Stores information on a filter
*/
struct Efreet_Menu_Filter
{
Efreet_Menu_Filter_Type type; /**< The type of filter */
Efreet_Menu_Filter_Op *op; /**< The filter operations */
};
/**
* The type of layout
*/
enum Efreet_Menu_Layout_Type
{
EFREET_MENU_LAYOUT_MENUNAME,
EFREET_MENU_LAYOUT_FILENAME,
EFREET_MENU_LAYOUT_SEPARATOR,
EFREET_MENU_LAYOUT_MERGE
};
/**
* Efreet_Menu_Layout_Type
*/
typedef enum Efreet_Menu_Layout_Type Efreet_Menu_Layout_Type;
/**
* Efreet_Menu_Layout
*/
typedef struct Efreet_Menu_Layout Efreet_Menu_Layout;
/**
* Efreet_Menu_Layout
* Stores information on a layout
*/
struct Efreet_Menu_Layout
{
Efreet_Menu_Layout_Type type; /**< The type of layout */
char *name; /**< The name of the element */
/* The items below are for Menuname Layout elements */
char show_empty; /**< Whether to show empty menus */
char in_line; /**< Whether this meny can be inlined */
char inline_limit; /**< Number of elements which triggers inline */
char inline_header; /**< Whether we should use the header name when this menu is inlined */
char inline_alias; /**< Whether we should use the menu name when inlining */
};
/**
* Efreet_Menu_Desktop
*/
typedef struct Efreet_Menu_Desktop Efreet_Menu_Desktop;
/**
* Efreet_Menu_Desktop
* Stores information on a desktop for the menu
*/
struct Efreet_Menu_Desktop
{
Efreet_Desktop *desktop; /**< The desktop we refer too */
const char *id; /**< The desktop file id */
unsigned char allocated:1; /**< If this desktop has been allocated */
};
static char *efreet_menu_prefix = NULL; /**< The $XDG_MENU_PREFIX env var */
Eina_List *efreet_menu_kde_legacy_dirs = NULL; /**< The directories to use for KDELegacy entries */
static const char *efreet_tag_menu = NULL;
static char *efreet_menu_file = NULL; /**< A menu file set explicityl as default */
static Eina_Hash *efreet_merged_menus = NULL;
static Eina_Hash *efreet_merged_dirs = NULL;
static Eina_Hash *efreet_menu_handle_cbs = NULL;
static Eina_Hash *efreet_menu_filter_cbs = NULL;
static Eina_Hash *efreet_menu_move_cbs = NULL;
static Eina_Hash *efreet_menu_layout_cbs = NULL;
static const char *efreet_menu_prefix_get(void);
static Efreet_Menu_Internal *efreet_menu_by_name_find(Efreet_Menu_Internal *internal,
const char *name,
Efreet_Menu_Internal **parent);
static int efreet_menu_cb_compare_names(Efreet_Menu_Internal *internal, const char *name);
static int efreet_menu_cb_md_compare_ids(Efreet_Menu_Desktop *md, const char *name);
static int efreet_menu_cb_entry_compare_menu(Efreet_Menu *entry, Efreet_Menu_Internal *internal);
static int efreet_menu_cb_entry_compare_desktop(Efreet_Menu *entry, Efreet_Desktop *desktop);
static int efreet_menu_cb_move_compare(Efreet_Menu_Move *move, const char *old);
static int efreet_menu_process(Efreet_Menu_Internal *internal, unsigned int only_unallocated);
static int efreet_menu_process_dirs(Efreet_Menu_Internal *internal);
static int efreet_menu_app_dirs_process(Efreet_Menu_Internal *internal);
static int efreet_menu_app_dir_scan(Efreet_Menu_Internal *internal,
const char *path,
const char *id,
int legacy);
static int efreet_menu_directory_dirs_process(Efreet_Menu_Internal *internal);
static int efreet_menu_directory_dir_scan(const char *path,
const char *relative_path,
Eina_Hash *cache);
static Efreet_Desktop *efreet_menu_directory_get(Efreet_Menu_Internal *internal,
const char *path);
static void efreet_menu_process_filters(Efreet_Menu_Internal *internal,
unsigned int only_unallocated);
static Eina_List * efreet_menu_process_app_pool(Eina_List *pool, Eina_List *applications,
Eina_Hash *matches,
Efreet_Menu_Filter *filter,
unsigned int only_unallocated);
static int efreet_menu_filter_matches(Efreet_Menu_Filter_Op *op,
Efreet_Menu_Desktop *md);
static int efreet_menu_filter_or_matches(Efreet_Menu_Filter_Op *op,
Efreet_Menu_Desktop *md);
static int efreet_menu_filter_and_matches(Efreet_Menu_Filter_Op *op,
Efreet_Menu_Desktop *md);
static int efreet_menu_filter_not_matches(Efreet_Menu_Filter_Op *op,
Efreet_Menu_Desktop *md);
static Efreet_Menu *efreet_menu_layout_menu(Efreet_Menu_Internal *internal);
static Efreet_Menu *efreet_menu_layout_desktop(Efreet_Menu_Desktop *md);
static void efreet_menu_layout_entries_get(Efreet_Menu *entry, Efreet_Menu_Internal *internal,
Efreet_Menu_Layout *layout);
static int efreet_menu_layout_is_empty(Efreet_Menu *entry);
static Efreet_Menu_Internal *efreet_menu_internal_new(void);
static void efreet_menu_internal_free(Efreet_Menu_Internal *internal);
static void efreet_menu_create_sub_menu_list(Efreet_Menu_Internal *internal);
static void efreet_menu_create_app_dirs_list(Efreet_Menu_Internal *internal);
static void efreet_menu_create_directory_dirs_list(Efreet_Menu_Internal *internal);
static void efreet_menu_create_directories_list(Efreet_Menu_Internal *internal);
static void efreet_menu_create_move_list(Efreet_Menu_Internal *internal);
static void efreet_menu_create_filter_list(Efreet_Menu_Internal *internal);
static void efreet_menu_create_layout_list(Efreet_Menu_Internal *internal);
static void efreet_menu_create_default_layout_list(Efreet_Menu_Internal *internal);
static char *efreet_menu_path_get(Efreet_Menu_Internal *internal, const char *suffix);
static Efreet_Menu_App_Dir *efreet_menu_app_dir_new(void);
static Efreet_Menu_Move *efreet_menu_move_new(void);
static void efreet_menu_move_free(Efreet_Menu_Move *move);
static Efreet_Menu_Filter *efreet_menu_filter_new(void);
static void efreet_menu_filter_free(Efreet_Menu_Filter *filter);
static Efreet_Menu_Layout *efreet_menu_layout_new(void);
static Efreet_Menu_Filter_Op *efreet_menu_filter_op_new(void);
static void efreet_menu_filter_op_free(Efreet_Menu_Filter_Op *op);
static Efreet_Menu_Desktop *efreet_menu_desktop_new(void);
static void efreet_menu_desktop_free(Efreet_Menu_Desktop *md);
static Efreet_Menu *efreet_menu_entry_new(void);
static int efreet_menu_handle_menu(Efreet_Menu_Internal *internal, Efreet_Xml *xml);
static int efreet_menu_handle_name(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_sub_menu(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_app_dir(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_default_app_dirs(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_directory_dir(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_default_directory_dirs(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_directory(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_only_unallocated(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_not_only_unallocated(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_deleted(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_not_deleted(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_include(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_exclude(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_filename(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml);
static int efreet_menu_handle_category(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml);
static int efreet_menu_handle_all(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml);
static int efreet_menu_handle_and(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml);
static int efreet_menu_handle_or(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml);
static int efreet_menu_handle_not(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml);
static int efreet_menu_handle_merge_file(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_merge_dir(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_default_merge_dirs(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_legacy_dir(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static Efreet_Menu_Internal *efreet_menu_handle_legacy_dir_helper(Efreet_Menu_Internal *root,
Efreet_Menu_Internal *parent,
const char *legacy_dir,
const char *prefix);
static int efreet_menu_handle_kde_legacy_dirs(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_move(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_old(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_new(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_layout(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_default_layout(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_filter(Efreet_Menu_Internal *parent, Efreet_Xml *xml,
Efreet_Menu_Filter_Type type);
static int efreet_menu_handle_filter_op(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml);
static int efreet_menu_handle_filter_child_op(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml,
Efreet_Menu_Filter_Op_Type type);
static int efreet_menu_handle_layout_menuname(Efreet_Menu_Internal *parent, Efreet_Xml *xml, int def);
static int efreet_menu_handle_layout_filename(Efreet_Menu_Internal *parent, Efreet_Xml *xml, int def);
static int efreet_menu_handle_layout_separator(Efreet_Menu_Internal *parent, Efreet_Xml *xml, int def);
static int efreet_menu_handle_layout_merge(Efreet_Menu_Internal *parent, Efreet_Xml *xml, int def);
static int efreet_menu_merge(Efreet_Menu_Internal *parent, Efreet_Xml *xml, const char *path);
static int efreet_menu_merge_dir(Efreet_Menu_Internal *parent, Efreet_Xml *xml, const char *path);
static int efreet_menu_cb_app_dirs_compare(Efreet_Menu_App_Dir *a, const char *b);
static void efreet_menu_resolve_moves(Efreet_Menu_Internal *internal);
static void efreet_menu_concatenate(Efreet_Menu_Internal *dest, Efreet_Menu_Internal *src);
static int efreet_menu_cb_menu_compare(Efreet_Menu_Internal *a, Efreet_Menu_Internal *b);
static int efreet_menu_cb_md_compare(Efreet_Menu_Desktop *a, Efreet_Menu_Desktop *b);
static int efreet_menu_save_menu(Efreet_Menu *menu, FILE *f, int indent);
static int efreet_menu_save_indent(FILE *f, int indent);
static void efreet_menu_path_set(Efreet_Menu_Internal *internal, const char *path);
/**
* @return Returns 1 on success, 0 on failure
* @brief Initializes the Efreet Menu system.
*/
int
efreet_menu_init(void)
{
int i;
struct
{
char *key;
int (*cb)(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
} menu_cbs[] = {
{"Menu", efreet_menu_handle_sub_menu},
{"AppDir", efreet_menu_handle_app_dir},
{"DefaultAppDirs", efreet_menu_handle_default_app_dirs},
{"DirectoryDir", efreet_menu_handle_directory_dir},
{"DefaultDirectoryDirs", efreet_menu_handle_default_directory_dirs},
{"Name", efreet_menu_handle_name},
{"Directory", efreet_menu_handle_directory},
{"OnlyUnallocated", efreet_menu_handle_only_unallocated},
{"NotOnlyUnallocated", efreet_menu_handle_not_only_unallocated},
{"Deleted", efreet_menu_handle_deleted},
{"NotDeleted", efreet_menu_handle_not_deleted},
{"Include", efreet_menu_handle_include},
{"Exclude", efreet_menu_handle_exclude},
{"MergeFile", efreet_menu_handle_merge_file},
{"MergeDir", efreet_menu_handle_merge_dir},
{"DefaultMergeDirs", efreet_menu_handle_default_merge_dirs},
{"LegacyDir", efreet_menu_handle_legacy_dir},
{"KDELegacyDirs", efreet_menu_handle_kde_legacy_dirs},
{"Move", efreet_menu_handle_move},
{"Layout", efreet_menu_handle_layout},
{"DefaultLayout", efreet_menu_handle_default_layout},
{NULL, NULL}
};
struct
{
char *key;
int (*cb)(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml);
} filter_cbs[] = {
{"Filename", efreet_menu_handle_filename},
{"Category", efreet_menu_handle_category},
{"All", efreet_menu_handle_all},
{"And", efreet_menu_handle_and},
{"Or", efreet_menu_handle_or},
{"Not", efreet_menu_handle_not},
{NULL, NULL}
};
struct
{
char *key;
int (*cb)(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
} move_cbs[] = {
{"Old", efreet_menu_handle_old},
{"New", efreet_menu_handle_new},
{NULL, NULL}
};
struct
{
char *key;
int (*cb)(Efreet_Menu_Internal *parent, Efreet_Xml *xml, int def);
} layout_cbs[] = {
{"Menuname", efreet_menu_handle_layout_menuname},
{"Filename", efreet_menu_handle_layout_filename},
{"Separator", efreet_menu_handle_layout_separator},
{"Merge", efreet_menu_handle_layout_merge},
{NULL, NULL}
};
if (!eina_stringshare_init()) return 0;
if (!efreet_xml_init()) return 0;
efreet_menu_handle_cbs = eina_hash_string_superfast_new(NULL);
efreet_menu_filter_cbs = eina_hash_string_superfast_new(NULL);
efreet_menu_move_cbs = eina_hash_string_superfast_new(NULL);
efreet_menu_layout_cbs = eina_hash_string_superfast_new(NULL);
if (!efreet_menu_handle_cbs || !efreet_menu_filter_cbs
|| !efreet_menu_move_cbs || !efreet_menu_layout_cbs)
return 0;
/* set Menu into it's own so we can check the XML is valid before trying
* to handle it */
efreet_tag_menu = eina_stringshare_add(menu_cbs[0].key);
for (i = 0; menu_cbs[i].key != NULL; i++)
{
eina_hash_del(efreet_menu_handle_cbs,
menu_cbs[i].key,
NULL);
eina_hash_add(efreet_menu_handle_cbs,
menu_cbs[i].key,
menu_cbs[i].cb);
}
for (i = 0; filter_cbs[i].key != NULL; i++)
{
eina_hash_del(efreet_menu_filter_cbs,
filter_cbs[i].key,
NULL);
eina_hash_add(efreet_menu_filter_cbs,
filter_cbs[i].key,
filter_cbs[i].cb);
}
for (i = 0; move_cbs[i].key != NULL; i++)
{
eina_hash_del(efreet_menu_move_cbs,
move_cbs[i].key,
NULL);
eina_hash_add(efreet_menu_move_cbs,
move_cbs[i].key,
move_cbs[i].cb);
}
for (i = 0; layout_cbs[i].key != NULL; i++)
{
eina_hash_del(efreet_menu_layout_cbs,
layout_cbs[i].key,
NULL);
eina_hash_add(efreet_menu_layout_cbs,
layout_cbs[i].key,
layout_cbs[i].cb);
}
return 1;
}
/**
* @return Returns no value
* @brief Initialize legacy kde support. This function blocks while
* the kde-config script is run.
*/
EAPI int
efreet_menu_kde_legacy_init(void)
{
FILE *f;
char buf[PATH_MAX];
char *p, *s;
IF_FREE_LIST(efreet_menu_kde_legacy_dirs);
f = popen("kde-config --path apps", "r");
if (!f) return 0;
/* XXX if the return from kde-config is a line longer than PATH_MAX,
* this won't be correct (increase buffer and get the rest...) */
if (!fgets(buf, PATH_MAX, f))
{
printf("Error initializing KDE legacy information\n");
return 0;
}
s = buf;
p = strchr(s, ':');
while (p)
{
*p = '\0';
efreet_menu_kde_legacy_dirs = eina_list_append(efreet_menu_kde_legacy_dirs,
(void *)eina_stringshare_add(s));
s = p + 1;
p = strchr(s, ':');
}
if (*s)
efreet_menu_kde_legacy_dirs = eina_list_append(efreet_menu_kde_legacy_dirs,
(void *)eina_stringshare_add(s));
pclose(f);
return 1;
}
/**
* @return Returns no value
* @brief Shuts down the Efreet menu system
*/
void
efreet_menu_shutdown(void)
{
IF_FREE(efreet_menu_prefix);
IF_FREE(efreet_menu_file);
IF_FREE_HASH(efreet_menu_handle_cbs);
IF_FREE_HASH(efreet_menu_filter_cbs);
IF_FREE_HASH(efreet_menu_move_cbs);
IF_FREE_HASH(efreet_menu_layout_cbs);
IF_FREE_LIST(efreet_menu_kde_legacy_dirs);
IF_FREE_HASH(efreet_merged_menus);
IF_FREE_HASH(efreet_merged_dirs);
IF_RELEASE(efreet_tag_menu);
efreet_xml_shutdown();
eina_stringshare_shutdown();
}
/**
* @param name The internal name of the menu
* @return Returns the Efreet_Menu on success or
* NULL on failure
* @brief Creates a new menu
*/
EAPI Efreet_Menu *
efreet_menu_new(const char *name)
{
Efreet_Menu *menu;
if (!name)
{
printf("Error creating a new menu, name is missing\n");
return NULL;
}
menu = efreet_menu_entry_new();
menu->type = EFREET_MENU_ENTRY_MENU;
menu->name = eina_stringshare_add(name);
return menu;
}
EAPI void
efreet_menu_file_set(const char *file)
{
IF_FREE(efreet_menu_file);
efreet_menu_file = NULL;
if (file) efreet_menu_file = strdup(file);
}
/**
* @return Returns the Efreet_Menu_Internal representation of the default menu or
* NULL if none found
* @brief Creates the default menu representation
*/
EAPI Efreet_Menu *
efreet_menu_get(void)
{
char menu[PATH_MAX];
const char *dir;
Eina_List *config_dirs, *l;
/* check the users config directory first */
snprintf(menu, sizeof(menu), "%s/menus/%sapplications.menu",
efreet_config_home_get(), efreet_menu_prefix_get());
if (ecore_file_exists(menu))
return efreet_menu_parse(menu);
if (efreet_menu_file)
{
if (ecore_file_exists(efreet_menu_file))
return efreet_menu_parse(efreet_menu_file);
}
/* fallback to the XDG_CONFIG_DIRS */
config_dirs = efreet_config_dirs_get();
EINA_LIST_FOREACH(config_dirs, l, dir)
{
snprintf(menu, sizeof(menu), "%s/menus/%sapplications.menu",
dir, efreet_menu_prefix_get());
if (ecore_file_exists(menu))
return efreet_menu_parse(menu);
}
return NULL;
}
/**
* @param path: The path of the menu to load
* @return Returns the Efreet_Menu_Internal representation on success or NULL on
* failure
* @brief Parses the given .menu file and creates the menu representation
*/
EAPI Efreet_Menu *
efreet_menu_parse(const char *path)
{
Efreet_Xml *xml;
Efreet_Menu_Internal *internal = NULL;
Efreet_Menu *entry = NULL;
Eina_List *search_dirs;
xml = efreet_xml_new(path);
if (!xml) return NULL;
/* make sure we've got a