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.
This commit is contained in:
Dana Jansens 2009-12-14 18:18:10 -05:00
parent 111465b737
commit 828c095c8b
3 changed files with 73 additions and 13 deletions

View file

@ -1841,7 +1841,12 @@ static gboolean event_handle_menu(XEvent *ev)
(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:

View file

@ -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 @@ ObMenuFrame* menu_frame_new(ObMenu *menu, guint show_from, ObClient *client)
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 @@ gboolean menu_frame_show_submenu(ObMenuFrame *self, ObMenuFrame *parent,
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 @@ static void menu_frame_hide(ObMenuFrame *self)
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 @@ void menu_frame_hide_all(void)
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 @@ void menu_frame_hide_all_client(ObClient *client)
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 @@ ObMenuEntryFrame* menu_entry_frame_under(gint x, gint 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 @@ ObMenuEntryFrame* menu_entry_frame_under(gint x, gint y)
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 @@ void menu_frame_select(ObMenuFrame *self, ObMenuEntryFrame *entry,
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 {

View file

@ -53,6 +53,9 @@ struct _ObMenuFrame
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;