X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=openbox%2Fmenu.c;h=5d9ea796d5f71447ba1fd281b199563e7c373d08;hb=b41c3395313a97741f2f76b9133dc3b0b8eb5bbc;hp=6a217fc662a4f6a7c1ce1034d52130eb9405e6a4;hpb=5074d902aa215a2a656980d31b19574a5db1f795;p=chaz%2Fopenbox diff --git a/openbox/menu.c b/openbox/menu.c index 6a217fc6..5d9ea796 100644 --- a/openbox/menu.c +++ b/openbox/menu.c @@ -20,9 +20,12 @@ #include "debug.h" #include "menu.h" #include "openbox.h" +#include "mainloop.h" #include "stacking.h" +#include "grab.h" #include "client.h" #include "config.h" +#include "actions.h" #include "screen.h" #include "menuframe.h" #include "keyboard.h" @@ -45,6 +48,7 @@ struct _ObMenuParseState static GHashTable *menu_hash = NULL; static ObParseInst *menu_parse_inst; static ObMenuParseState menu_parse_state; +static gboolean menu_can_hide = FALSE; static void menu_destroy_hash_value(ObMenu *self); static void parse_menu_item(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node, @@ -55,7 +59,8 @@ static void parse_menu_separator(ObParseInst *i, static void parse_menu(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node, gpointer data); static gunichar parse_shortcut(const gchar *label, gboolean allow_shortcut, - gchar **strippedlabel, guint *position); + gchar **strippedlabel, guint *position, + gboolean *always_show); static void client_dest(ObClient *client, gpointer data) @@ -132,7 +137,22 @@ void menu_shutdown(gboolean reconfig) static gboolean menu_pipe_submenu(gpointer key, gpointer val, gpointer data) { ObMenu *menu = val; - return menu->pipe_creator == data; + return menu->pipe_creator != NULL; +} + +static void clear_cache(gpointer key, gpointer val, gpointer data) +{ + ObMenu *menu = val; + if (menu->execute) + menu_clear_entries(menu); +} + +void menu_clear_pipe_caches() +{ + /* delete any pipe menus' submenus */ + g_hash_table_foreach_remove(menu_hash, menu_pipe_submenu, NULL); + /* empty the top level pipe menus */ + g_hash_table_foreach(menu_hash, clear_cache, NULL); } void menu_pipe_execute(ObMenu *self) @@ -144,6 +164,8 @@ void menu_pipe_execute(ObMenu *self) if (!self->execute) return; + if (self->entries) /* the entries are already created and cached */ + return; if (!g_spawn_command_line_sync(self->execute, &output, NULL, NULL, &err)) { g_message(_("Failed to execute command for pipe-menu '%s': %s"), @@ -155,9 +177,6 @@ void menu_pipe_execute(ObMenu *self) if (parse_load_mem(output, strlen(output), "openbox_pipe_menu", &doc, &node)) { - g_hash_table_foreach_remove(menu_hash, menu_pipe_submenu, self); - menu_clear_entries(self); - menu_parse_state.pipe_creator = self; menu_parse_state.parent = self; parse_tree(menu_parse_inst, doc, node->children); @@ -186,11 +205,13 @@ static ObMenu* menu_from_name(gchar *name) ((c) >= 'a' && (c) <= 'z')) static gunichar parse_shortcut(const gchar *label, gboolean allow_shortcut, - gchar **strippedlabel, guint *position) + gchar **strippedlabel, guint *position, + gboolean *always_show) { gunichar shortcut = 0; *position = 0; + *always_show = FALSE; g_assert(strippedlabel != NULL); @@ -215,6 +236,7 @@ static gunichar parse_shortcut(const gchar *label, gboolean allow_shortcut, if (VALID_SHORTCUT(*(i+1))) { shortcut = g_unichar_tolower(g_utf8_get_char(i+1)); *position = i - *strippedlabel; + *always_show = TRUE; /* remove the & from the string */ for (; *i != '\0'; ++i) @@ -247,8 +269,7 @@ static void parse_menu_item(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node, for (node = node->children; node; node = node->next) if (!xmlStrcasecmp(node->name, (const xmlChar*) "action")) { - ObAction *a = action_parse - (i, doc, node, OB_USER_ACTION_MENU_SELECTION); + ObActionsAct *a = actions_parse(i, doc, node); if (a) acts = g_slist_append(acts, a); } @@ -323,7 +344,8 @@ ObMenu* menu_new(const gchar *name, const gchar *title, self->data = data; self->shortcut = parse_shortcut(title, allow_shortcut_selection, - &self->title, &self->shortcut_position); + &self->title, &self->shortcut_position, + &self->shortcut_always_show); g_hash_table_replace(menu_hash, self->name, self); @@ -384,13 +406,19 @@ void menu_free(ObMenu *menu) g_hash_table_remove(menu_hash, menu->name); } -void menu_show(gchar *name, gint x, gint y, gint button, ObClient *client) +static gboolean menu_hide_delay_func(gpointer data) +{ + menu_can_hide = TRUE; + return FALSE; /* no repeat */ +} + +void menu_show(gchar *name, gint x, gint y, gboolean mouse, ObClient *client) { ObMenu *self; ObMenuFrame *frame; - if (!(self = menu_from_name(name)) - || keyboard_interactively_grabbed()) return; + if (!(self = menu_from_name(name)) || + grab_on_keyboard() || grab_on_pointer()) return; /* if the requested menu is already the top visible menu, then don't bother */ @@ -402,26 +430,47 @@ void menu_show(gchar *name, gint x, gint y, gint button, ObClient *client) menu_frame_hide_all(); + /* clear the pipe menus when showing a new menu */ + menu_clear_pipe_caches(); + frame = menu_frame_new(self, 0, client); - if (!menu_frame_show_topmenu(frame, x, y, button)) + if (!menu_frame_show_topmenu(frame, x, y, mouse)) menu_frame_free(frame); - else if (!button) { - /* select the first entry if it's not a submenu and we opened - * the menu with the keyboard, and skip all headers */ - GList *it = frame->entries; - while (it) { - ObMenuEntryFrame *e = it->data; - if (e->entry->type == OB_MENU_ENTRY_TYPE_NORMAL) { - menu_frame_select(frame, e, FALSE); - break; - } else if (e->entry->type == OB_MENU_ENTRY_TYPE_SEPARATOR) - it = g_list_next(it); - else - break; + else { + if (!mouse) { + /* select the first entry if it's not a submenu and we opened + * the menu with the keyboard, and skip all headers */ + GList *it = frame->entries; + while (it) { + ObMenuEntryFrame *e = it->data; + if (e->entry->type == OB_MENU_ENTRY_TYPE_NORMAL) { + menu_frame_select(frame, e, FALSE); + break; + } else if (e->entry->type == OB_MENU_ENTRY_TYPE_SEPARATOR) + it = g_list_next(it); + else + break; + } + } + + /* reset the hide timer */ + if (!mouse) + menu_can_hide = TRUE; + else { + menu_can_hide = FALSE; + ob_main_loop_timeout_add(ob_main_loop, + config_menu_hide_delay * 1000, + menu_hide_delay_func, + NULL, g_direct_equal, NULL); } } } +gboolean menu_hide_delay_reached() +{ + return menu_can_hide; +} + static ObMenuEntry* menu_entry_new(ObMenu *menu, ObMenuEntryType type, gint id) { ObMenuEntry *self; @@ -458,7 +507,7 @@ void menu_entry_unref(ObMenuEntry *self) case OB_MENU_ENTRY_TYPE_NORMAL: g_free(self->data.normal.label); while (self->data.normal.actions) { - action_unref(self->data.normal.actions->data); + actions_act_unref(self->data.normal.actions->data); self->data.normal.actions = g_slist_delete_link(self->data.normal.actions, self->data.normal.actions); @@ -630,7 +679,8 @@ void menu_entry_set_label(ObMenuEntry *self, const gchar *label, g_free(self->data.normal.label); self->data.normal.shortcut = parse_shortcut(label, allow_shortcut, &self->data.normal.label, - &self->data.normal.shortcut_position); + &self->data.normal.shortcut_position, + &self->data.normal.shortcut_always_show); break; default: g_assert_not_reached();