all repos — openbox @ 828c095c8b5a2df96a38faaeb8a0df504e68e70f

openbox fork - make it a bit more like ryudo

Don't hide submenus immediately when unselecting the parent's entry

This allows users to move to the submenu across other menu items (the same
as they already could across other menu items that were submenus).

This uses the same config delay for hiding submenus as it does for showing
new ones.

Based off the ideas in bug #3762.
Dana Jansens danakj@orodu.net
commit

828c095c8b5a2df96a38faaeb8a0df504e68e70f

parent

111465b7373cdcdd791b603aefd882ae06d5bf0b

3 files changed, 73 insertions(+), 13 deletions(-)

jump to
M openbox/event.copenbox/event.c

@@ -1841,7 +1841,12 @@ if ((e = g_hash_table_lookup(menu_frame_map, &ev->xcrossing.window)) &&

(f = find_active_menu()) && f->selected == e && e->entry->type != OB_MENU_ENTRY_TYPE_SUBMENU) { - menu_frame_select(e->frame, NULL, FALSE); + ObMenuEntryFrame *u = menu_entry_frame_under(ev->xcrossing.x_root, + ev->xcrossing.y_root); + /* if we're just going from one entry in the menu to the next, + don't unselect stuff first */ + if (!u || e->frame != u->frame) + menu_frame_select(e->frame, NULL, FALSE); } break; case MotionNotify:
M openbox/menuframe.copenbox/menuframe.c

@@ -48,7 +48,8 @@ static ObMenuEntryFrame* menu_entry_frame_new(ObMenuEntry *entry,

ObMenuFrame *frame); static void menu_entry_frame_free(ObMenuEntryFrame *self); static void menu_frame_update(ObMenuFrame *self); -static gboolean menu_entry_frame_submenu_timeout(gpointer data); +static gboolean menu_entry_frame_submenu_hide_timeout(gpointer data); +static gboolean menu_entry_frame_submenu_show_timeout(gpointer data); static void menu_frame_hide(ObMenuFrame *self); static Window createWindow(Window parent, gulong mask,

@@ -94,6 +95,7 @@ self = g_new0(ObMenuFrame, 1);

self->type = Window_Menu; self->menu = menu; self->selected = NULL; + self->open_submenu = NULL; self->client = client; self->direction_right = TRUE; self->show_from = show_from;

@@ -984,6 +986,7 @@

self->monitor = parent->monitor; self->parent = parent; self->parent_entry = parent_entry; + parent->open_submenu = parent_entry; /* set up parent's child to be us */ if (parent->child)

@@ -1028,8 +1031,10 @@

if (self->child) menu_frame_hide(self->child); - if (self->parent) + if (self->parent && self->parent->child == self) { self->parent->child = NULL; + self->parent->open_submenu = NULL; + } self->parent = NULL; self->parent_entry = NULL;

@@ -1053,7 +1058,10 @@

if (config_submenu_show_delay) { /* remove any submenu open requests */ ob_main_loop_timeout_remove(ob_main_loop, - menu_entry_frame_submenu_timeout); + menu_entry_frame_submenu_show_timeout); + /* remove any submenu close delays */ + ob_main_loop_timeout_remove(ob_main_loop, + menu_entry_frame_submenu_hide_timeout); } if ((it = g_list_last(menu_frame_visible))) menu_frame_hide(it->data);

@@ -1067,8 +1075,13 @@ ObMenuFrame *f = it->data;

if (f->client == client) { if (config_submenu_show_delay) { /* remove any submenu open requests */ - ob_main_loop_timeout_remove(ob_main_loop, - menu_entry_frame_submenu_timeout); + ob_main_loop_timeout_remove + (ob_main_loop, + menu_entry_frame_submenu_show_timeout); + /* remove any submenu close delays */ + ob_main_loop_timeout_remove + (ob_main_loop, + menu_entry_frame_submenu_hide_timeout); } menu_frame_hide(f); }

@@ -1103,7 +1116,6 @@ y -= ob_rr_theme->mbwidth + frame->area.y;

for (it = frame->entries; it; it = g_list_next(it)) { ObMenuEntryFrame *e = it->data; - if (RECT_CONTAINS(e->area, x, y)) { ret = e; break;

@@ -1113,7 +1125,15 @@ }

return ret; } -static gboolean menu_entry_frame_submenu_timeout(gpointer data) +static gboolean menu_entry_frame_submenu_hide_timeout(gpointer data) +{ + g_assert(menu_frame_visible); + g_assert(((ObMenuFrame*)data)->parent != NULL); + menu_frame_hide((ObMenuFrame*)data); + return FALSE; +} + +static gboolean menu_entry_frame_submenu_show_timeout(gpointer data) { g_assert(menu_frame_visible); menu_entry_frame_show_submenu((ObMenuEntryFrame*)data);

@@ -1134,25 +1154,57 @@

if (config_submenu_show_delay) { /* remove any submenu open requests */ ob_main_loop_timeout_remove(ob_main_loop, - menu_entry_frame_submenu_timeout); + menu_entry_frame_submenu_show_timeout); + } + + if (!entry && self->open_submenu) { + entry = self->open_submenu; + oldchild = NULL; + + /* remove any submenu close delays */ + ob_main_loop_timeout_remove(ob_main_loop, + menu_entry_frame_submenu_hide_timeout); } self->selected = entry; if (old) menu_entry_frame_render(old); - if (oldchild) - menu_frame_hide(oldchild); + + if (oldchild) { + /* there is an open submenu */ + + if (config_submenu_show_delay && !immediate) { + if (old == self->open_submenu) { + /* close the open submenu after a delay if we don't have + it selected */ + ob_main_loop_timeout_remove + (ob_main_loop, + menu_entry_frame_submenu_hide_timeout); + ob_main_loop_timeout_add(ob_main_loop, + config_submenu_show_delay * 1000, + menu_entry_frame_submenu_hide_timeout, + self->child, g_direct_equal, + NULL); + } + } + else + menu_frame_hide(oldchild); + } if (self->selected) { menu_entry_frame_render(self->selected); - if (self->selected->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU) { + /* if we've selected a submenu and it wasn't always open, then + show it */ + if (self->selected->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU && + self->selected != self->open_submenu) + { if (config_submenu_show_delay && !immediate) { /* initiate a new submenu open request */ ob_main_loop_timeout_add(ob_main_loop, config_submenu_show_delay * 1000, - menu_entry_frame_submenu_timeout, + menu_entry_frame_submenu_show_timeout, self->selected, g_direct_equal, NULL); } else {
M openbox/menuframe.hopenbox/menuframe.h

@@ -53,6 +53,9 @@ ObMenuFrame *child;

GList *entries; ObMenuEntryFrame *selected; + /* if a submenu was selected, then this holds the entry for that submenu + until it is closed */ + ObMenuEntryFrame *open_submenu; /* show entries from the menu starting at this index */ guint show_from;