[gtk+] Only show the mnemonic underline when pressing Alt



commit c59f76fda2560273d7ee3255db9b697a7077ac38
Author: Matthias Clasen <mclasen redhat com>
Date:   Sun Dec 20 03:04:52 2009 -0500

    Only show the mnemonic underline when pressing Alt
    
    ...and show them in menus when navigating the menu with the keyboard.
    This is similar to what other platforms do, and reduces visual clutter.
    There is a setting to control this. Most of the work on this patch was
    done by Thomas Wood. See bug 588554.

 gtk/gtklabel.c     |  108 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 gtk/gtklabel.h     |    5 ++
 gtk/gtkmain.c      |   23 +++++++++++
 gtk/gtkmenu.c      |   12 ++++++
 gtk/gtkmenubar.c   |    1 +
 gtk/gtkmenuitem.c  |    3 +
 gtk/gtkmenushell.c |   86 ++++++++++++++++++++++++++++++++++++++++-
 gtk/gtkmenushell.h |    6 +++
 gtk/gtksettings.c  |   20 +++++++++-
 gtk/gtkwindow.c    |   94 ++++++++++++++++++++++++++++++++++++++++++++-
 gtk/gtkwindow.h    |    3 +
 11 files changed, 353 insertions(+), 8 deletions(-)
---
diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c
index 73fa93a..475d842 100644
--- a/gtk/gtklabel.c
+++ b/gtk/gtklabel.c
@@ -58,6 +58,8 @@ typedef struct
   gint wrap_width;
   gint width_chars;
   gint max_width_chars;
+
+  gboolean mnemonics_visible;
 } GtkLabelPrivate;
 
 /* Notes about the handling of links:
@@ -264,6 +266,9 @@ static void     gtk_label_buildable_custom_finished    (GtkBuildable     *builda
 							gpointer          user_data);
 
 
+static void connect_mnemonics_visible_notify    (GtkLabel   *label);
+
+
 /* For selectable labels: */
 static void gtk_label_move_cursor        (GtkLabel        *label,
 					  GtkMovementStep  step,
@@ -1037,6 +1042,8 @@ gtk_label_init (GtkLabel *label)
   label->mnemonic_widget = NULL;
   label->mnemonic_window = NULL;
 
+  priv->mnemonics_visible = TRUE;
+
   gtk_label_set_text (label, "");
 }
 
@@ -1486,7 +1493,9 @@ gtk_label_setup_mnemonic (GtkLabel *label,
     }
   
   if (label->mnemonic_keyval == GDK_VoidSymbol)
-    goto done;
+      goto done;
+
+  connect_mnemonics_visible_notify (GTK_LABEL (widget));
 
   toplevel = gtk_widget_get_toplevel (widget);
   if (GTK_WIDGET_TOPLEVEL (toplevel))
@@ -1565,6 +1574,65 @@ label_shortcut_setting_changed (GtkSettings *settings)
 }
 
 static void
+mnemonics_visible_apply (GtkWidget *widget,
+                         gboolean   mnemonics_visible)
+{
+  GtkLabel *label;
+  GtkLabelPrivate *priv;
+
+  label = GTK_LABEL (widget);
+
+  if (!label->use_underline)
+    return;
+
+  priv = GTK_LABEL_GET_PRIVATE (label);
+
+  mnemonics_visible = mnemonics_visible != FALSE;
+
+  if (priv->mnemonics_visible != mnemonics_visible)
+    {
+      priv->mnemonics_visible = mnemonics_visible;
+
+      gtk_label_recalculate (label);
+    }
+}
+
+static void
+label_mnemonics_visible_traverse_container (GtkWidget *widget,
+                                            gpointer   data)
+{
+  gboolean mnemonics_visible = GPOINTER_TO_INT (data);
+
+  _gtk_label_mnemonics_visible_apply_recursively (widget, mnemonics_visible);
+}
+
+void
+_gtk_label_mnemonics_visible_apply_recursively (GtkWidget *widget,
+                                                gboolean   mnemonics_visible)
+{
+  if (GTK_IS_LABEL (widget))
+    mnemonics_visible_apply (widget, mnemonics_visible);
+  else if (GTK_IS_CONTAINER (widget))
+    gtk_container_forall (GTK_CONTAINER (widget),
+                          label_mnemonics_visible_traverse_container,
+                          GINT_TO_POINTER (mnemonics_visible));
+}
+
+static void
+label_mnemonics_visible_changed (GtkWindow  *window,
+                                 GParamSpec *pspec,
+                                 gpointer    data)
+{
+  gboolean mnemonics_visible;
+
+  g_object_get (window, "mnemonics-visible", &mnemonics_visible, NULL);
+
+  gtk_container_forall (GTK_CONTAINER (window),
+                        label_mnemonics_visible_traverse_container,
+                        GINT_TO_POINTER (mnemonics_visible));
+}
+
+static void
 gtk_label_screen_changed (GtkWidget *widget,
 			  GdkScreen *old_screen)
 {
@@ -2420,6 +2488,7 @@ static void
 gtk_label_set_pattern_internal (GtkLabel    *label,
 				const gchar *pattern)
 {
+  GtkLabelPrivate *priv = GTK_LABEL_GET_PRIVATE (label);
   PangoAttrList *attrs;
   gboolean enable_mnemonics;
 
@@ -2432,7 +2501,8 @@ gtk_label_set_pattern_internal (GtkLabel    *label,
 		"gtk-enable-mnemonics", &enable_mnemonics,
 		NULL);
 
-  if (enable_mnemonics && pattern)
+  if (enable_mnemonics && priv->mnemonics_visible && pattern &&
+      GTK_WIDGET_IS_SENSITIVE (label))
     attrs = gtk_label_pattern_to_attrs (label, pattern);
   else
     attrs = NULL;
@@ -4179,6 +4249,38 @@ gtk_label_button_release (GtkWidget      *widget,
 }
 
 static void
+connect_mnemonics_visible_notify (GtkLabel *label)
+{
+  GtkLabelPrivate *priv = GTK_LABEL_GET_PRIVATE (label);
+  GtkWidget *toplevel;
+  gboolean connected;
+
+  toplevel = gtk_widget_get_toplevel (GTK_WIDGET (label));
+
+  if (!GTK_IS_WINDOW (toplevel))
+    return;
+
+  /* always set up this widgets initial value */
+  priv->mnemonics_visible =
+    gtk_window_get_mnemonics_visible (GTK_WINDOW (toplevel));
+
+  connected =
+    GPOINTER_TO_INT (g_object_get_data (G_OBJECT (toplevel),
+                                        "gtk-label-mnemonics-visible-connected"));
+
+  if (!connected)
+    {
+      g_signal_connect (toplevel,
+                        "notify::mnemonics-visible",
+                        G_CALLBACK (label_mnemonics_visible_changed),
+                        label);
+      g_object_set_data (G_OBJECT (toplevel),
+                         "gtk-label-mnemonics-visible-connected",
+                         GINT_TO_POINTER (1));
+    }
+}
+
+static void
 drag_begin_cb (GtkWidget      *widget,
                GdkDragContext *context,
                gpointer        data)
@@ -5707,7 +5809,7 @@ gtk_label_activate_current_link (GtkLabel *label)
           if (window &&
               window->default_widget != widget &&
               !(widget == window->focus_widget &&
-                (!window->default_widget || !GTK_WIDGET_SENSITIVE (window->default_widget))))
+                (!window->default_widget || !GTK_WIDGET_IS_SENSITIVE (window->default_widget))))
             gtk_window_activate_default (window);
         }
     }
diff --git a/gtk/gtklabel.h b/gtk/gtklabel.h
index d44b142..88a9db7 100644
--- a/gtk/gtklabel.h
+++ b/gtk/gtklabel.h
@@ -197,6 +197,11 @@ guint gtk_label_parse_uline            (GtkLabel    *label,
 
 #endif /* GTK_DISABLE_DEPRECATED */
 
+/* private */
+
+void _gtk_label_mnemonics_visible_apply_recursively (GtkWidget *widget,
+                                                     gboolean   mnemonics_visible);
+
 G_END_DECLS
 
 #endif /* __GTK_LABEL_H__ */
diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c
index 581403b..af03f35 100644
--- a/gtk/gtkmain.c
+++ b/gtk/gtkmain.c
@@ -63,6 +63,8 @@
 #include "gtktooltip.h"
 #include "gtkdebug.h"
 #include "gtkalias.h"
+#include "gtkmenu.h"
+#include "gdk/gdkkeysyms.h"
 
 #include "gdk/gdkprivate.h" /* for GDK_WINDOW_DESTROYED */
 
@@ -1613,6 +1615,27 @@ gtk_main_do_event (GdkEvent *event)
 	  if (gtk_invoke_key_snoopers (grab_widget, event))
 	    break;
 	}
+      /* catch alt press to enable auto-mnemonics */
+      if (event->key.keyval == GDK_Alt_L || event->key.keyval == GDK_Alt_R)
+        {
+          gboolean auto_mnemonics;
+
+          g_object_get (gtk_widget_get_settings (grab_widget),
+                        "gtk-auto-mnemonics", &auto_mnemonics, NULL);
+
+          if (auto_mnemonics)
+            {
+              gboolean mnemonics_visible;
+              GtkWidget *window;
+
+              mnemonics_visible = (event->type == GDK_KEY_PRESS);
+
+              window = gtk_widget_get_toplevel (grab_widget);
+
+              if (GTK_IS_WINDOW (window))
+                gtk_window_set_mnemonics_visible (GTK_WINDOW (window), mnemonics_visible);
+            }
+        }
       /* else fall through */
     case GDK_MOTION_NOTIFY:
     case GDK_BUTTON_RELEASE:
diff --git a/gtk/gtkmenu.c b/gtk/gtkmenu.c
index e8813c9..241ef41 100644
--- a/gtk/gtkmenu.c
+++ b/gtk/gtkmenu.c
@@ -1616,6 +1616,18 @@ gtk_menu_popup (GtkMenu		    *menu,
   if (xgrab_shell == widget)
     popup_grab_on_window (widget->window, activate_time, grab_keyboard); /* Should always succeed */
   gtk_grab_add (GTK_WIDGET (menu));
+
+  if (parent_menu_shell)
+    {
+      gboolean keyboard_mode;
+
+      keyboard_mode = _gtk_menu_shell_get_keyboard_mode (GTK_MENU_SHELL (parent_menu_shell));
+      _gtk_menu_shell_set_keyboard_mode (menu_shell, keyboard_mode);
+    }
+  else if (menu_shell->button == 0) /* a keynav-activated context menu */
+    _gtk_menu_shell_set_keyboard_mode (menu_shell, TRUE);
+
+  _gtk_menu_shell_update_mnemonics (menu_shell);
 }
 
 void
diff --git a/gtk/gtkmenubar.c b/gtk/gtkmenubar.c
index a54e456..3d2bbb5 100644
--- a/gtk/gtkmenubar.c
+++ b/gtk/gtkmenubar.c
@@ -625,6 +625,7 @@ window_key_press_handler (GtkWidget   *widget,
 	    {
 	      GtkMenuShell *menu_shell = GTK_MENU_SHELL (menubars->data);
 
+              _gtk_menu_shell_set_keyboard_mode (menu_shell, TRUE);
 	      _gtk_menu_shell_activate (menu_shell);
 	      gtk_menu_shell_select_first (menu_shell, FALSE);
 	      
diff --git a/gtk/gtkmenuitem.c b/gtk/gtkmenuitem.c
index 13db059..1f3e1a9 100644
--- a/gtk/gtkmenuitem.c
+++ b/gtk/gtkmenuitem.c
@@ -1374,6 +1374,9 @@ static gboolean
 gtk_menu_item_mnemonic_activate (GtkWidget *widget,
 				 gboolean   group_cycling)
 {
+  if (GTK_IS_MENU_SHELL (widget->parent))
+    _gtk_menu_shell_set_keyboard_mode (GTK_MENU_SHELL (widget->parent), TRUE);
+
   if (group_cycling &&
       widget->parent &&
       GTK_IS_MENU_SHELL (widget->parent) &&
diff --git a/gtk/gtkmenushell.c b/gtk/gtkmenushell.c
index 910c760..4f7d82c 100644
--- a/gtk/gtkmenushell.c
+++ b/gtk/gtkmenushell.c
@@ -30,6 +30,7 @@
 #include "gdk/gdkkeysyms.h"
 #include "gtkbindings.h"
 #include "gtkkeyhash.h"
+#include "gtklabel.h"
 #include "gtkmain.h"
 #include "gtkmarshalers.h"
 #include "gtkmenu.h"
@@ -773,6 +774,76 @@ gtk_menu_shell_button_release (GtkWidget      *widget,
   return TRUE;
 }
 
+void
+_gtk_menu_shell_set_keyboard_mode (GtkMenuShell *menu_shell,
+                                   gboolean      keyboard_mode)
+{
+  menu_shell->keyboard_mode = keyboard_mode;
+}
+
+gboolean
+_gtk_menu_shell_get_keyboard_mode (GtkMenuShell *menu_shell)
+{
+  return menu_shell->keyboard_mode;
+}
+
+void
+_gtk_menu_shell_update_mnemonics (GtkMenuShell *menu_shell)
+{
+  GtkMenuShell *target;
+  gboolean auto_mnemonics;
+  gboolean found;
+  gboolean mnemonics_visible;
+
+  g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu_shell)),
+                "gtk-auto-mnemonics", &auto_mnemonics, NULL);
+
+  if (!auto_mnemonics)
+    return;
+
+  target = menu_shell;
+  found = FALSE;
+  while (target)
+    {
+      /* The idea with keyboard mode is that once you start using
+       * the keyboard to navigate the menus, we show mnemonics
+       * until the menu navigation is over. To that end, we spread
+       * the keyboard mode upwards in the menu hierarchy here.
+       * Also see gtk_menu_popup, where we inherit it downwards.
+       */
+      if (menu_shell->keyboard_mode)
+        target->keyboard_mode = TRUE;
+
+      /* While navigating menus, the first parent menu with an active
+       * item is the one where mnemonics are effective, as can be seen
+       * in gtk_menu_shell_key_press below.
+       * We also show mnemonics in context menus. The grab condition is
+       * necessary to ensure we remove underlines from menu bars when
+       * dismissing menus.
+       */
+      mnemonics_visible = target->keyboard_mode &&
+                          ((target->active_menu_item && !found) ||
+                           (target == menu_shell &&
+                            !target->parent_menu_shell &&
+                            gtk_widget_has_grab (target)));
+
+      /* While menus are up, only show underlines inside the menubar,
+       * not in the entire window.
+       */
+      if (GTK_IS_MENU_BAR (target))
+        _gtk_label_mnemonics_visible_apply_recursively (GTK_WIDGET (target),
+                                                        mnemonics_visible);
+      else
+        gtk_window_set_mnemonics_visible (GTK_WINDOW (gtk_widget_get_toplevel (target)),
+                                          mnemonics_visible);
+
+      if (target->active_menu_item)
+        found = TRUE;
+
+      target = GTK_MENU_SHELL (target->parent_menu_shell);
+    }
+}
+
 static gint
 gtk_menu_shell_key_press (GtkWidget   *widget,
 			  GdkEventKey *event)
@@ -780,9 +851,11 @@ gtk_menu_shell_key_press (GtkWidget   *widget,
   GtkMenuShell *menu_shell = GTK_MENU_SHELL (widget);
   gboolean enable_mnemonics;
 
+  menu_shell->keyboard_mode = TRUE;
+
   if (!menu_shell->active_menu_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))
     return TRUE;
 
@@ -992,11 +1065,15 @@ gtk_real_menu_shell_deactivate (GtkMenuShell *menu_shell)
       if (menu_shell->have_xgrab)
 	{
 	  GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (menu_shell));
-	  
+
 	  menu_shell->have_xgrab = FALSE;
 	  gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
 	  gdk_display_keyboard_ungrab (display, GDK_CURRENT_TIME);
 	}
+
+      menu_shell->keyboard_mode = FALSE;
+
+      _gtk_menu_shell_update_mnemonics (menu_shell);
     }
 }
 
@@ -1079,6 +1156,8 @@ gtk_menu_shell_real_select_item (GtkMenuShell *menu_shell,
 				  GTK_MENU_SHELL_GET_CLASS (menu_shell)->submenu_placement);
   gtk_menu_item_select (GTK_MENU_ITEM (menu_shell->active_menu_item));
 
+  _gtk_menu_shell_update_mnemonics (menu_shell);
+
   /* This allows the bizarre radio buttons-with-submenus-display-history
    * behavior
    */
@@ -1095,6 +1174,7 @@ gtk_menu_shell_deselect (GtkMenuShell *menu_shell)
     {
       gtk_menu_item_deselect (GTK_MENU_ITEM (menu_shell->active_menu_item));
       menu_shell->active_menu_item = NULL;
+      _gtk_menu_shell_update_mnemonics (menu_shell);
     }
 }
 
@@ -1340,6 +1420,7 @@ gtk_real_menu_shell_move_current (GtkMenuShell         *menu_shell,
            * menu.
            */
           _gtk_menu_item_popdown_submenu (menu_shell->active_menu_item);
+          _gtk_menu_shell_update_mnemonics (menu_shell);
         }
       else if (parent_menu_shell)
 	{
@@ -1347,6 +1428,7 @@ gtk_real_menu_shell_move_current (GtkMenuShell         *menu_shell,
             {
               /* close menu when returning from submenu. */
               _gtk_menu_item_popdown_submenu (GTK_MENU (menu_shell)->parent_menu_item);
+              _gtk_menu_shell_update_mnemonics (parent_menu_shell);
               break;
             }
 
diff --git a/gtk/gtkmenushell.h b/gtk/gtkmenushell.h
index e8281bc..614d397 100644
--- a/gtk/gtkmenushell.h
+++ b/gtk/gtkmenushell.h
@@ -65,6 +65,7 @@ struct _GtkMenuShell
   guint GSEAL (ignore_leave) : 1; /* unused */
   guint GSEAL (menu_flag) : 1;    /* unused */
   guint GSEAL (ignore_enter) : 1;
+  guint GSEAL (keyboard_mode) : 1;
 };
 
 struct _GtkMenuShellClass
@@ -130,6 +131,11 @@ gboolean gtk_menu_shell_get_take_focus (GtkMenuShell *menu_shell);
 void     gtk_menu_shell_set_take_focus (GtkMenuShell *menu_shell,
                                         gboolean      take_focus);
 
+void     _gtk_menu_shell_update_mnemonics  (GtkMenuShell *menu_shell);
+void     _gtk_menu_shell_set_keyboard_mode (GtkMenuShell *menu_shell,
+                                            gboolean      keyboard_mode);
+gboolean _gtk_menu_shell_get_keyboard_mode (GtkMenuShell *menu_shell);
+
 G_END_DECLS
 
 #endif /* __GTK_MENU_SHELL_H__ */
diff --git a/gtk/gtksettings.c b/gtk/gtksettings.c
index 9e28fb9..a7ca546 100644
--- a/gtk/gtksettings.c
+++ b/gtk/gtksettings.c
@@ -124,7 +124,8 @@ enum {
   PROP_ENABLE_EVENT_SOUNDS,
   PROP_ENABLE_TOOLTIPS,
   PROP_TOOLBAR_STYLE,
-  PROP_TOOLBAR_ICON_SIZE
+  PROP_TOOLBAR_ICON_SIZE,
+  PROP_AUTO_MNEMONICS
 };
 
 
@@ -999,6 +1000,23 @@ gtk_settings_class_init (GtkSettingsClass *class)
                                                                    GTK_PARAM_READWRITE),
                                              gtk_rc_property_parse_enum);
   g_assert (result == PROP_TOOLBAR_ICON_SIZE);
+
+  /**
+   * GtkSettings:gtk-auto-mnemonics:
+   *
+   * Whether mnemonics should be automatically shown and hidden when the user
+   * presses the mnemonic activator.
+   *
+   * Since: 2.20
+   */
+  result = settings_install_property_parser (class,
+                                             g_param_spec_boolean ("gtk-auto-mnemonics",
+                                                                   P_("Auto Mnemonics"),
+                                                                   P_("Whether mnemonics should be automatically shown and hidden when the user presses the mnemonic activator."),
+                                                                   FALSE,
+                                                                   GTK_PARAM_READWRITE),
+                                             NULL);
+  g_assert (result == PROP_AUTO_MNEMONICS);
 }
 
 static void
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index f01820d..f5ec59f 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -101,6 +101,8 @@ enum {
   /* Writeonly properties */
   PROP_STARTUP_ID,
   
+  PROP_MNEMONICS_VISIBLE,
+
   LAST_ARG
 };
 
@@ -185,6 +187,9 @@ struct _GtkWindowPrivate
   guint opacity_set : 1;
   guint builder_visible : 1;
 
+  guint mnemonics_visible : 1;
+  guint mnemonics_visible_set : 1;
+
   GdkWindowTypeHint type_hint;
 
   gdouble opacity;
@@ -230,6 +235,8 @@ static gint gtk_window_client_event	  (GtkWidget	     *widget,
 static void gtk_window_check_resize       (GtkContainer      *container);
 static gint gtk_window_focus              (GtkWidget        *widget,
 				           GtkDirectionType  direction);
+static void gtk_window_grab_notify        (GtkWidget         *widget,
+                                           gboolean           was_grabbed);
 static void gtk_window_real_set_focus     (GtkWindow         *window,
 					   GtkWidget         *focus);
 
@@ -456,9 +463,9 @@ gtk_window_class_init (GtkWindowClass *klass)
   widget_class->focus_out_event = gtk_window_focus_out_event;
   widget_class->client_event = gtk_window_client_event;
   widget_class->focus = gtk_window_focus;
-  
   widget_class->expose_event = gtk_window_expose;
-   
+  widget_class->grab_notify = gtk_window_grab_notify;
+
   container_class->check_resize = gtk_window_check_resize;
 
   klass->set_focus = gtk_window_real_set_focus;
@@ -591,6 +598,13 @@ gtk_window_class_init (GtkWindowClass *klass)
                                                         P_("Icon for this window"),
                                                         GDK_TYPE_PIXBUF,
                                                         GTK_PARAM_READWRITE));
+  g_object_class_install_property (gobject_class,
+                                   PROP_MNEMONICS_VISIBLE,
+                                   g_param_spec_boolean ("mnemonics-visible",
+                                                         P_("Mnemonics Visible"),
+                                                         P_("Whether mnemonics are currently visible in this window"),
+                                                         TRUE,
+                                                         GTK_PARAM_READWRITE));
   
   /**
    * GtkWindow:icon-name:
@@ -929,6 +943,7 @@ gtk_window_init (GtkWindow *window)
   priv->type_hint = GDK_WINDOW_TYPE_HINT_NORMAL;
   priv->opacity = 1.0;
   priv->startup_id = NULL;
+  priv->mnemonics_visible = TRUE;
 
   colormap = _gtk_widget_peek_colormap ();
   if (colormap)
@@ -951,9 +966,12 @@ gtk_window_set_property (GObject      *object,
 			 GParamSpec   *pspec)
 {
   GtkWindow  *window;
+  GtkWindowPrivate *priv;
   
   window = GTK_WINDOW (object);
 
+  priv = GTK_WINDOW_GET_PRIVATE (window);
+
   switch (prop_id)
     {
     case PROP_TYPE:
@@ -1050,6 +1068,9 @@ gtk_window_set_property (GObject      *object,
     case PROP_OPACITY:
       gtk_window_set_opacity (window, g_value_get_double (value));
       break;
+    case PROP_MNEMONICS_VISIBLE:
+      gtk_window_set_mnemonics_visible (window, g_value_get_boolean (value));
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -1165,6 +1186,9 @@ gtk_window_get_property (GObject      *object,
     case PROP_OPACITY:
       g_value_set_double (value, gtk_window_get_opacity (window));
       break;
+    case PROP_MNEMONICS_VISIBLE:
+      g_value_set_boolean (value, priv->mnemonics_visible);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -4537,6 +4561,7 @@ gtk_window_map (GtkWidget *widget)
   GtkWindow *window = GTK_WINDOW (widget);
   GtkWindowPrivate *priv = GTK_WINDOW_GET_PRIVATE (window);
   GdkWindow *toplevel;
+  gboolean auto_mnemonics;
 
   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
 
@@ -4612,6 +4637,14 @@ gtk_window_map (GtkWidget *widget)
           gdk_notify_startup_complete ();
         }
     }
+
+  /* if auto-mnemonics is enabled and mnemonics visible is not already set
+   * (as in the case of popup menus), then hide mnemonics initially
+   */
+  g_object_get (gtk_widget_get_settings (widget), "gtk-auto-mnemonics",
+                &auto_mnemonics, NULL);
+  if (auto_mnemonics && !priv->mnemonics_visible_set)
+    gtk_window_set_mnemonics_visible (window, FALSE);
 }
 
 static gboolean
@@ -5288,10 +5321,18 @@ gtk_window_focus_out_event (GtkWidget     *widget,
 			    GdkEventFocus *event)
 {
   GtkWindow *window = GTK_WINDOW (widget);
+  gboolean auto_mnemonics;
 
   _gtk_window_set_has_toplevel_focus (window, FALSE);
   _gtk_window_set_is_active (window, FALSE);
 
+  /* set the mnemonic-visible property to false */
+  g_object_get (gtk_widget_get_settings (widget),
+                "gtk-auto-mnemonics", &auto_mnemonics, NULL);
+  if (auto_mnemonics)
+    gtk_window_set_mnemonics_visible (window, FALSE);
+
+
   return FALSE;
 }
 
@@ -8432,6 +8473,55 @@ gtk_window_get_window_type (GtkWindow *window)
   return window->type;
 }
 
+gboolean
+gtk_window_get_mnemonics_visible (GtkWindow *window)
+{
+  GtkWindowPrivate *priv;
+
+  g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
+
+  priv = GTK_WINDOW_GET_PRIVATE (window);
+
+  return priv->mnemonics_visible;
+}
+
+void
+gtk_window_set_mnemonics_visible (GtkWindow *window,
+                                  gboolean   setting)
+{
+  GtkWindowPrivate *priv;
+
+  g_return_if_fail (GTK_IS_WINDOW (window));
+
+  priv = GTK_WINDOW_GET_PRIVATE (window);
+
+  setting = setting != FALSE;
+
+  if (priv->mnemonics_visible != setting)
+    {
+      priv->mnemonics_visible = setting;
+      g_object_notify (G_OBJECT (window), "mnemonics-visible");
+    }
+
+  priv->mnemonics_visible_set = TRUE;
+}
+
+static void
+gtk_window_grab_notify (GtkWidget *widget,
+                        gboolean   was_grabbed)
+{
+  gboolean auto_mnemonics;
+
+  if (was_grabbed)
+    return;
+
+  g_object_get (gtk_widget_get_settings (widget), "gtk-auto-mnemonics",
+                &auto_mnemonics, NULL);
+
+ if (auto_mnemonics)
+   gtk_window_set_mnemonics_visible (GTK_WINDOW (widget), FALSE);
+}
+
 #if defined (G_OS_WIN32) && !defined (_WIN64)
 
 #undef gtk_window_set_icon_from_file
diff --git a/gtk/gtkwindow.h b/gtk/gtkwindow.h
index dc59dfe..1b4362f 100644
--- a/gtk/gtkwindow.h
+++ b/gtk/gtkwindow.h
@@ -230,6 +230,9 @@ gboolean   gtk_window_get_focus_on_map         (GtkWindow           *window);
 void       gtk_window_set_destroy_with_parent  (GtkWindow           *window,
                                                 gboolean             setting);
 gboolean   gtk_window_get_destroy_with_parent  (GtkWindow           *window);
+void       gtk_window_set_mnemonics_visible    (GtkWindow           *window,
+                                                gboolean             setting);
+gboolean   gtk_window_get_mnemonics_visible    (GtkWindow           *window);
 
 void       gtk_window_set_resizable            (GtkWindow           *window,
                                                 gboolean             resizable);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]