13 #include "parser/parse.h"
15 GHashTable
*menu_hash
= NULL
;
17 typedef struct _ObMenuParseState ObMenuParseState
;
19 struct _ObMenuParseState
24 static void menu_clear_entries_internal(ObMenu
*self
);
26 static ObMenu
* menu_from_name(gchar
*name
)
30 g_assert(name
!= NULL
);
32 if (!(self
= g_hash_table_lookup(menu_hash
, name
)))
33 g_warning("Attempted to access menu '%s' but it does not exist.",
38 static void parse_menu_item(ObParseInst
*i
, xmlDocPtr doc
, xmlNodePtr node
,
41 ObMenuParseState
*state
= data
;
45 if (parse_attr_string("label", node
, &label
)) {
48 for (node
= node
->xmlChildrenNode
; node
; node
= node
->next
)
49 if (!xmlStrcasecmp(node
->name
, (const xmlChar
*) "action"))
50 acts
= g_slist_append(acts
, action_parse(doc
, node
));
51 menu_add_normal(state
->menus
->data
, label
, acts
);
57 static void parse_menu_separator(ObParseInst
*i
,
58 xmlDocPtr doc
, xmlNodePtr node
,
61 ObMenuParseState
*state
= data
;
64 menu_add_separator(state
->menus
->data
);
67 static void parse_menu(ObParseInst
*i
, xmlDocPtr doc
, xmlNodePtr node
,
70 ObMenuParseState
*state
= data
;
71 gchar
*name
= NULL
, *title
= NULL
;
73 if (!parse_attr_string("id", node
, &name
))
76 if (!g_hash_table_lookup(menu_hash
, name
)) {
77 if (!parse_attr_string("label", node
, &title
))
80 if (menu_new(name
, title
, NULL
)) {
81 state
->menus
= g_slist_prepend(state
->menus
, name
);
82 parse_tree(i
, doc
, node
->xmlChildrenNode
);
83 state
->menus
= g_slist_delete_link(state
->menus
, state
->menus
);
88 menu_add_submenu(state
->menus
->data
, name
);
96 void menu_destroy_hash_value(ObMenu
*self
)
98 menu_clear_entries_internal(self
);
103 void menu_startup(ObParseInst
*i
)
105 menu_hash
= g_hash_table_new_full(g_str_hash
, g_str_equal
, NULL
,
106 (GDestroyNotify
)menu_destroy_hash_value
);
111 menu_frame_hide_all();
112 g_hash_table_destroy(menu_hash
);
118 ObMenuParseState parse_state
;
122 gboolean loaded
= FALSE
;
126 if (config_menu_path
)
128 parse_load(config_menu_path
, "openbox_menu", &doc
, &node
)))
129 g_warning("Failed to load menu from '%s'", config_menu_path
);
131 p
= g_build_filename(g_get_home_dir(), ".openbox", "menu", NULL
);
133 parse_load(p
, "openbox_menu", &doc
, &node
)))
134 g_warning("Failed to load menu from '%s'", p
);
138 p
= g_build_filename(RCDIR
, "menu", NULL
);
140 parse_load(p
, "openbox_menu", &doc
, &node
)))
141 g_warning("Failed to load menu from '%s'", p
);
146 parse_state
.menus
= NULL
;
148 parse_register(i
, "menu", parse_menu
, &parse_state
);
149 parse_register(i
, "item", parse_menu_item
, &parse_state
);
150 parse_register(i
, "separator", parse_menu_separator
, &parse_state
);
151 parse_tree(i
, doc
, node
->xmlChildrenNode
);
157 gboolean
menu_new(gchar
*name
, gchar
*title
, gpointer data
)
161 if (g_hash_table_lookup(menu_hash
, name
)) return FALSE
;
163 self
= g_new0(ObMenu
, 1);
164 self
->name
= g_strdup(name
);
165 self
->title
= g_strdup(title
);
168 g_hash_table_insert(menu_hash
, self
->name
, self
);
173 void menu_show(gchar
*name
, gint x
, gint y
, ObClient
*client
)
178 if (!(self
= menu_from_name(name
))) return;
180 /* XXX update entries */
182 frame
= menu_frame_new(self
, client
);
183 menu_frame_move(frame
, x
, y
);
184 menu_frame_show(frame
, NULL
);
187 static ObMenuEntry
* menu_entry_new(ObMenu
*menu
, ObMenuEntryType type
)
193 self
= g_new0(ObMenuEntry
, 1);
196 self
->enabled
= TRUE
;
200 static void menu_entry_free(ObMenuEntry
*self
)
203 switch (self
->type
) {
204 case OB_MENU_ENTRY_TYPE_NORMAL
:
205 g_free(self
->data
.normal
.label
);
206 while (self
->data
.normal
.actions
) {
207 action_free(self
->data
.normal
.actions
->data
);
208 self
->data
.normal
.actions
=
209 g_slist_delete_link(self
->data
.normal
.actions
,
210 self
->data
.normal
.actions
);
213 case OB_MENU_ENTRY_TYPE_SUBMENU
:
214 case OB_MENU_ENTRY_TYPE_SEPARATOR
:
222 void menu_clear_entries(gchar
*name
)
226 if (!(self
= menu_from_name(name
))) return;
228 menu_clear_entries_internal(self
);
231 static void menu_clear_entries_internal(ObMenu
*self
)
233 /* XXX assert that the menu isn't visible */
235 while (self
->entries
) {
236 menu_entry_free(self
->entries
->data
);
237 self
->entries
= g_list_delete_link(self
->entries
, self
->entries
);
241 void menu_add_normal(gchar
*name
, gchar
*label
, GSList
*actions
)
246 if (!(self
= menu_from_name(name
))) return;
248 e
= menu_entry_new(self
, OB_MENU_ENTRY_TYPE_NORMAL
);
249 e
->data
.normal
.label
= g_strdup(label
);
250 e
->data
.normal
.actions
= actions
;
252 self
->entries
= g_list_append(self
->entries
, e
);
255 void menu_add_submenu(gchar
*name
, gchar
*submenu
)
260 if (!(self
= menu_from_name(name
))) return;
261 if (!(sub
= menu_from_name(submenu
))) return;
263 e
= menu_entry_new(self
, OB_MENU_ENTRY_TYPE_SUBMENU
);
264 e
->data
.submenu
.submenu
= sub
;
266 self
->entries
= g_list_append(self
->entries
, e
);
269 void menu_add_separator(gchar
*name
)
274 if (!(self
= menu_from_name(name
))) return;
276 e
= menu_entry_new(self
, OB_MENU_ENTRY_TYPE_SEPARATOR
);
278 self
->entries
= g_list_append(self
->entries
, e
);