]> Dogcows Code - chaz/openbox/blobdiff - openbox/menu.c
cache pipe menus until the menus close
[chaz/openbox] / openbox / menu.c
index fe664d3516ac58250e530b063eec2ac2a70208b1..344e1a5a1ea49b2ac97cfadcbac13d2fed1ff133 100644 (file)
@@ -20,6 +20,7 @@
 #include "debug.h"
 #include "menu.h"
 #include "openbox.h"
+#include "mainloop.h"
 #include "stacking.h"
 #include "client.h"
 #include "config.h"
@@ -45,6 +46,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,
@@ -132,7 +134,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 +161,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 +174,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);
@@ -327,6 +343,15 @@ ObMenu* menu_new(const gchar *name, const gchar *title,
 
     g_hash_table_replace(menu_hash, self->name, self);
 
+    /* Each menu has a single more_menu.  When the menu spills past what
+       can fit on the screen, a new menu frame entry is created from this
+       more_menu, and a new menu frame for the submenu is created for this
+       menu, also pointing to the more_menu.
+
+       This can be done multiple times using the same more_menu.
+
+       more_menu->more_menu will always be NULL, since there is only 1 for
+       each menu. */
     self->more_menu = g_new0(ObMenu, 1);
     self->more_menu->name = _("More...");
     self->more_menu->title = _("More...");
@@ -375,6 +400,12 @@ void menu_free(ObMenu *menu)
         g_hash_table_remove(menu_hash, menu->name);
 }
 
+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, gint button, ObClient *client)
 {
     ObMenu *self;
@@ -396,8 +427,9 @@ void menu_show(gchar *name, gint x, gint y, gint button, ObClient *client)
     frame = menu_frame_new(self, 0, client);
     if (!menu_frame_show_topmenu(frame, x, y, button))
         menu_frame_free(frame);
-    else {
-        /* select the first entry if it's not a submenu */
+    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;
@@ -410,6 +442,21 @@ void menu_show(gchar *name, gint x, gint y, gint button, ObClient *client)
                 break;
         }
     }
+
+    if (!button)
+        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)
@@ -546,50 +593,38 @@ ObMenuEntry* menu_add_separator(ObMenu *self, gint id, const gchar *label)
 
 void menu_set_show_func(ObMenu *self, ObMenuShowFunc func)
 {
-    do {
-        self->show_func = func;
-        self = self->more_menu;
-    } while (self);
+    self->show_func = func;
+    self->more_menu->show_func = func; /* keep it in sync */
 }
 
 void menu_set_hide_func(ObMenu *self, ObMenuHideFunc func)
 {
-    do {
-        self->hide_func = func;
-        self = self->more_menu;
-    } while (self);
+    self->hide_func = func;
+    self->more_menu->hide_func = func; /* keep it in sync */
 }
 
 void menu_set_update_func(ObMenu *self, ObMenuUpdateFunc func)
 {
-    do {
-        self->update_func = func;
-        self = self->more_menu;
-    } while (self);
+    self->update_func = func;
+    self->more_menu->update_func = func; /* keep it in sync */
 }
 
 void menu_set_execute_func(ObMenu *self, ObMenuExecuteFunc func)
 {
-    do {
-        self->execute_func = func;
-        self = self->more_menu;
-    } while (self);
+    self->execute_func = func;
+    self->more_menu->execute_func = func; /* keep it in sync */
 }
 
 void menu_set_destroy_func(ObMenu *self, ObMenuDestroyFunc func)
 {
-    do {
-        self->destroy_func = func;
-        self = self->more_menu;
-    } while (self);
+    self->destroy_func = func;
+    self->more_menu->destroy_func = func; /* keep it in sync */
 }
 
 void menu_set_place_func(ObMenu *self, ObMenuPlaceFunc func)
 {
-    do {
-        self->place_func = func;
-        self = self->more_menu;
-    } while (self);
+    self->place_func = func;
+    self->more_menu->place_func = func; /* keep it in sync */
 }
 
 ObMenuEntry* menu_find_entry_id(ObMenu *self, gint id)
This page took 0.023187 seconds and 4 git commands to generate.