From a085bb1f0bcbd20723d181a5d7fa89f9ae56f92a Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sun, 14 Mar 2010 16:11:48 -0400 Subject: [PATCH] Improve the behaviour of automatic mnemonics With this change, key events continue to go to an open menu even when the pointer is moved over a non-selectable menuitem. The mnemonics are shown and hidden accordingly. --- gtk/gtkmenu.c | 7 +++++-- gtk/gtkmenushell.c | 50 +++++++++++++++++++++++++++++++++++++--------- 2 files changed, 46 insertions(+), 11 deletions(-) diff --git a/gtk/gtkmenu.c b/gtk/gtkmenu.c index 62039fe531..b5b9820faa 100644 --- a/gtk/gtkmenu.c +++ b/gtk/gtkmenu.c @@ -3262,7 +3262,10 @@ gtk_menu_motion_notify (GtkWidget *widget, */ if (!_gtk_menu_item_is_selectable (menu_item)) { - gtk_menu_shell_deselect (menu_shell); + /* We really want to deselect, but this gives the menushell code + * a chance to do some bookkeeping about the menuitem. + */ + gtk_menu_shell_select_item (menu_shell, menu_item); return FALSE; } @@ -3916,7 +3919,7 @@ gtk_menu_leave_notify (GtkWidget *widget, return TRUE; menu_item = GTK_MENU_ITEM (event_widget); - + /* Here we check to see if we're leaving an active menu item with a submenu, * in which case we enter submenu navigation mode. */ diff --git a/gtk/gtkmenushell.c b/gtk/gtkmenushell.c index bc8ea19bb9..710f835be8 100644 --- a/gtk/gtkmenushell.c +++ b/gtk/gtkmenushell.c @@ -137,6 +137,10 @@ struct _GtkMenuShellPrivate guint take_focus : 1; guint activated_submenu : 1; + /* This flag is a crutch to keep mnemonics in the same menu + * if the user moves the mouse over an unselectable menuitem. + */ + guint in_unselectable_item : 1; }; static void gtk_menu_shell_set_property (GObject *object, @@ -805,6 +809,7 @@ _gtk_menu_shell_update_mnemonics (GtkMenuShell *menu_shell) found = FALSE; while (target) { + GtkMenuShellPrivate *priv = GTK_MENU_SHELL_GET_PRIVATE (target); GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (target)); /* The idea with keyboard mode is that once you start using @@ -824,7 +829,7 @@ _gtk_menu_shell_update_mnemonics (GtkMenuShell *menu_shell) * dismissing menus. */ mnemonics_visible = target->keyboard_mode && - ((target->active_menu_item && !found) || + (((target->active_menu_item || priv->in_unselectable_item) && !found) || (target == menu_shell && !target->parent_menu_shell && gtk_widget_has_grab (GTK_WIDGET (target)))); @@ -841,7 +846,7 @@ _gtk_menu_shell_update_mnemonics (GtkMenuShell *menu_shell) else gtk_window_set_mnemonics_visible (GTK_WINDOW (toplevel), mnemonics_visible); - if (target->active_menu_item) + if (target->active_menu_item || priv->in_unselectable_item) found = TRUE; target = GTK_MENU_SHELL (target->parent_menu_shell); @@ -853,11 +858,12 @@ gtk_menu_shell_key_press (GtkWidget *widget, GdkEventKey *event) { GtkMenuShell *menu_shell = GTK_MENU_SHELL (widget); + GtkMenuShellPrivate *priv = GTK_MENU_SHELL_GET_PRIVATE (menu_shell); gboolean enable_mnemonics; menu_shell->keyboard_mode = TRUE; - if (!menu_shell->active_menu_item && menu_shell->parent_menu_shell) + if (!(menu_shell->active_menu_item || priv->in_unselectable_item) && menu_shell->parent_menu_shell) return gtk_widget_event (menu_shell->parent_menu_shell, (GdkEvent *)event); if (gtk_bindings_activate_event (GTK_OBJECT (widget), event)) @@ -890,10 +896,19 @@ gtk_menu_shell_enter_notify (GtkWidget *widget, menu_item = gtk_get_event_widget ((GdkEvent*) event); - if (!menu_item || - (GTK_IS_MENU_ITEM (menu_item) && - !_gtk_menu_item_is_selectable (menu_item))) - return TRUE; + if (!menu_item) + return TRUE; + + if (GTK_IS_MENU_ITEM (menu_item) && + !_gtk_menu_item_is_selectable (menu_item)) + { + GtkMenuShellPrivate *priv; + + priv = GTK_MENU_SHELL_GET_PRIVATE (menu_shell); + priv->in_unselectable_item = TRUE; + + return TRUE; + } if (menu_item->parent == widget && GTK_IS_MENU_ITEM (menu_item)) @@ -966,7 +981,14 @@ gtk_menu_shell_leave_notify (GtkWidget *widget, menu_item = GTK_MENU_ITEM (event_widget); if (!_gtk_menu_item_is_selectable (event_widget)) - return TRUE; + { + GtkMenuShellPrivate *priv; + + priv = GTK_MENU_SHELL_GET_PRIVATE (menu_shell); + priv->in_unselectable_item = TRUE; + + return TRUE; + } if ((menu_shell->active_menu_item == event_widget) && (menu_item->submenu == NULL)) @@ -1149,7 +1171,14 @@ gtk_menu_shell_real_select_item (GtkMenuShell *menu_shell, gtk_menu_shell_deselect (menu_shell); if (!_gtk_menu_item_is_selectable (menu_item)) - return; + { + GtkMenuShellPrivate *priv = GTK_MENU_SHELL_GET_PRIVATE (menu_shell); + + priv->in_unselectable_item = TRUE; + _gtk_menu_shell_update_mnemonics (menu_shell); + + return; + } menu_shell->active_menu_item = menu_item; if (pack_dir == GTK_PACK_DIRECTION_TTB || pack_dir == GTK_PACK_DIRECTION_BTT) @@ -1396,10 +1425,13 @@ static void gtk_real_menu_shell_move_current (GtkMenuShell *menu_shell, GtkMenuDirectionType direction) { + GtkMenuShellPrivate *priv = GTK_MENU_SHELL_GET_PRIVATE (menu_shell); GtkMenuShell *parent_menu_shell = NULL; gboolean had_selection; gboolean touchscreen_mode; + priv->in_unselectable_item = FALSE; + had_selection = menu_shell->active_menu_item != NULL; g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu_shell)),