Mnemonics patch



Ok. Here is the final patch for label uline accelerators, now called
mnemonics. I really like it.

If nobody says otherwise before 20:00 CET today I will check this in,
since I'll be gone for a while snowboarding and I don't want this to
bitrot in my tree while I'm gone.

Index: gtkwidget.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkwidget.h,v
retrieving revision 1.98
diff -u -p -r1.98 gtkwidget.h
--- gtkwidget.h	2001/03/18 04:50:34	1.98
+++ gtkwidget.h	2001/03/21 11:32:36
@@ -268,6 +268,10 @@ struct _GtkWidgetClass
 				guint           accel_key,
 				GdkModifierType accel_mods);

+  /* Mnemonics */
+  gboolean (* activate_mnemonic) (GtkWidget    *widget,
+				  gboolean      group_cycling);
+
   /* explicit focus */
   void (* grab_focus)          (GtkWidget      *widget);

@@ -464,6 +468,8 @@ guint	   gtk_widget_accelerator_signal
 void	   gtk_widget_lock_accelerators   (GtkWidget	       *widget);
 void	   gtk_widget_unlock_accelerators (GtkWidget	       *widget);
 gboolean   gtk_widget_accelerators_locked (GtkWidget	       *widget);
+gboolean   gtk_widget_activate_mnemonic   (GtkWidget           *widget,
+					   gboolean             group_cycling);
 gboolean   gtk_widget_event		  (GtkWidget	       *widget,
 					   GdkEvent	       *event);
 gint       gtk_widget_send_expose         (GtkWidget           *widget,
Index: gtkwidget.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkwidget.c,v
retrieving revision 1.195
diff -u -p -r1.195 gtkwidget.c
--- gtkwidget.c	2001/03/18 04:50:34	1.195
+++ gtkwidget.c	2001/03/21 11:32:36
@@ -62,6 +62,7 @@ enum {
   DIRECTION_CHANGED,
   ADD_ACCELERATOR,
   REMOVE_ACCELERATOR,
+  ACTIVATE_MNEMONIC,
   GRAB_FOCUS,
   EVENT,
   BUTTON_PRESS_EVENT,
@@ -188,6 +189,8 @@ static gint gtk_widget_event_internal

 static void gtk_widget_propagate_hierarchy_changed (GtkWidget *widget,
 						    gpointer   client_data);
+static gboolean gtk_widget_real_activate_mnemonic  (GtkWidget *widget,
+						    gboolean   group_cycling);

 static GtkWidgetAuxInfo* gtk_widget_aux_info_new     (void);
 static void		 gtk_widget_aux_info_destroy (GtkWidgetAuxInfo *aux_info);
@@ -290,6 +293,7 @@ gtk_widget_class_init (GtkWidgetClass *k
   klass->direction_changed = gtk_widget_direction_changed;
   klass->add_accelerator = (void*) gtk_accel_group_handle_add;
   klass->remove_accelerator = (void*) gtk_accel_group_handle_remove;
+  klass->activate_mnemonic = gtk_widget_real_activate_mnemonic;
   klass->grab_focus = gtk_widget_real_grab_focus;
   klass->event = NULL;
   klass->button_press_event = NULL;
@@ -460,6 +464,14 @@ gtk_widget_class_init (GtkWidgetClass *k
   widget_signals[REMOVE_ACCELERATOR] =
     gtk_accel_group_create_remove (GTK_CLASS_TYPE (object_class), GTK_RUN_LAST,
 				   GTK_SIGNAL_OFFSET (GtkWidgetClass, remove_accelerator));
+  widget_signals[ACTIVATE_MNEMONIC] =
+    gtk_signal_new ("activate_mnemonic",
+		    GTK_RUN_LAST,
+		    GTK_CLASS_TYPE (object_class),
+		    GTK_SIGNAL_OFFSET (GtkWidgetClass, activate_mnemonic),
+		    gtk_marshal_BOOLEAN__BOOLEAN,
+		    GTK_TYPE_BOOL, 1,
+		    GTK_TYPE_BOOL);
   widget_signals[GRAB_FOCUS] =
     gtk_signal_new ("grab_focus",
 		    GTK_RUN_LAST | GTK_RUN_ACTION,
@@ -2174,6 +2186,36 @@ gtk_widget_accelerator_signal (GtkWidget
     return ac_entry->signal_id;
   return 0;
 }
+
+gboolean
+gtk_widget_activate_mnemonic (GtkWidget *widget,
+                              gboolean   group_cycling)
+{
+  gboolean handled = FALSE;
+
+  g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+  if (!GTK_WIDGET_IS_SENSITIVE (widget))
+    return TRUE;
+
+  gtk_signal_emit_by_name (GTK_OBJECT (widget),
+                           "activate_mnemonic",
+                           group_cycling,
+                           &handled);
+  return handled;
+}
+
+static gboolean
+gtk_widget_real_activate_mnemonic (GtkWidget *widget,
+                                   gboolean   group_cycling)
+{
+  if (group_cycling)
+    gtk_widget_grab_focus (widget);
+  else if (!group_cycling)
+    gtk_widget_activate (widget);
+  return TRUE;
+}
+

 static gint
 gtk_widget_real_key_press_event (GtkWidget         *widget,
Index: gtkwindow.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkwindow.h,v
retrieving revision 1.30
diff -u -p -r1.30 gtkwindow.h
--- gtkwindow.h	2001/03/16 20:12:40	1.30
+++ gtkwindow.h	2001/03/21 11:32:37
@@ -99,6 +99,8 @@ struct _GtkWindow
   guint frame_top;
   guint frame_right;
   guint frame_bottom;
+
+  guint mnemonic_modifier;
 };

 struct _GtkWindowClass
@@ -174,6 +176,19 @@ GList*	   gtk_window_list_toplevels

 /* Get the "built-in" accel group (convenience thing) */
 GtkAccelGroup* gtk_window_get_default_accel_group (GtkWindow *window);
+
+void     gtk_window_add_mnemonic          (GtkWindow *window,
+					   guint      keyval,
+					   GtkWidget *target);
+void     gtk_window_remove_mnemonic       (GtkWindow *window,
+					   guint      keyval,
+					   GtkWidget *target);
+gboolean gtk_window_activate_mnemonic     (GtkWindow *window,
+					   guint      keyval,
+					   guint      modifier);
+void     gtk_window_set_mnemonic_modifier (GtkWindow *window,
+					   guint      modifier);
+

 void     gtk_window_present       (GtkWindow *window);
 void     gtk_window_iconify       (GtkWindow *window);
Index: gtkwindow.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkwindow.c,v
retrieving revision 1.106
diff -u -p -r1.106 gtkwindow.c
--- gtkwindow.c	2001/03/18 04:50:34	1.106
+++ gtkwindow.c	2001/03/21 11:32:37
@@ -99,6 +99,14 @@ typedef struct {
   GtkWindowLastGeometryInfo last;
 } GtkWindowGeometryInfo;

+typedef struct {
+  GtkWindow *window;
+  guint keyval;
+
+  GSList *targets;
+} GtkWindowMnemonic;
+
+
 static void gtk_window_class_init         (GtkWindowClass    *klass);
 static void gtk_window_init               (GtkWindow         *window);
 static void gtk_window_shutdown           (GObject           *object);
@@ -182,6 +190,7 @@ static void gtk_window_geometry_destroy


 static GSList      *toplevel_list = NULL;
+static GHashTable  *mnemonic_hash_table = NULL;
 static GtkBinClass *parent_class = NULL;
 static guint        window_signals[LAST_SIGNAL] = { 0 };

@@ -194,6 +203,36 @@ static void gtk_window_get_property (GOb
 				     GValue          *value,
 				     GParamSpec      *pspec);

+
+static guint
+mnemonic_hash (gconstpointer key)
+{
+  const GtkWindowMnemonic *k;
+  guint h;
+
+  k = (GtkWindowMnemonic *)key;
+
+  h = (gulong) k->window;
+  h ^= k->keyval << 16;
+  h ^= k->keyval >> 16;
+
+  return h;
+}
+
+static gboolean
+mnemonic_equal (gconstpointer a, gconstpointer b)
+{
+  const GtkWindowMnemonic *ka;
+  const GtkWindowMnemonic *kb;
+
+  ka = (GtkWindowMnemonic *)a;
+  kb = (GtkWindowMnemonic *)b;
+
+  return
+    (ka->window == kb->window) &&
+    (ka->keyval == kb->keyval);
+}
+
 GtkType
 gtk_window_get_type (void)
 {
@@ -373,6 +412,11 @@ gtk_window_class_init (GtkWindowClass *k
 		    gtk_marshal_BOOLEAN__BOXED,
 		    GTK_TYPE_BOOL, 1,
 		    GTK_TYPE_GDK_EVENT);
+
+
+  if (!mnemonic_hash_table)
+    mnemonic_hash_table = g_hash_table_new (mnemonic_hash,
+					    mnemonic_equal);
 }

 static void
@@ -407,6 +451,7 @@ gtk_window_init (GtkWindow *window)
   window->frame_bottom = 0;
   window->type_hint = GDK_WINDOW_TYPE_HINT_NORMAL;
   window->decorated = TRUE;
+  window->mnemonic_modifier = GDK_MOD1_MASK;

   gtk_widget_ref (GTK_WIDGET (window));
   gtk_object_sink (GTK_OBJECT (window));
@@ -801,6 +846,132 @@ gtk_window_get_default_accel_group (GtkW
 }

 void
+gtk_window_add_mnemonic (GtkWindow *window,
+			 guint      keyval,
+			 GtkWidget *target)
+{
+  GtkWindowMnemonic key;
+  GtkWindowMnemonic *mnemonic;
+
+  g_return_if_fail (window != NULL);
+  g_return_if_fail (GTK_IS_WINDOW (window));
+  g_return_if_fail (GTK_IS_WIDGET (target));
+
+  key.window = window;
+  key.keyval = keyval;
+
+  mnemonic = g_hash_table_lookup (mnemonic_hash_table, &key);
+
+  if (mnemonic)
+    mnemonic->targets = g_slist_prepend (mnemonic->targets, target);
+  else
+    {
+      mnemonic = g_new (GtkWindowMnemonic, 1);
+      *mnemonic = key;
+      mnemonic->targets = g_slist_prepend (NULL, target);
+      g_hash_table_insert (mnemonic_hash_table, mnemonic, mnemonic);
+    }
+}
+
+void
+gtk_window_remove_mnemonic (GtkWindow *window,
+			    guint      keyval,
+			    GtkWidget *target)
+{
+  GtkWindowMnemonic key;
+  GtkWindowMnemonic *mnemonic;
+
+  g_return_if_fail (window != NULL);
+  g_return_if_fail (GTK_IS_WINDOW (window));
+  g_return_if_fail (GTK_IS_WIDGET (target));
+
+  key.window = window;
+  key.keyval = keyval;
+
+  mnemonic = g_hash_table_lookup (mnemonic_hash_table, &key);
+
+  g_assert (mnemonic);
+
+  if (mnemonic)
+    {
+      mnemonic->targets = g_slist_remove (mnemonic->targets, target);
+
+      if (mnemonic->targets == NULL)
+	{
+	  g_hash_table_remove (mnemonic_hash_table, mnemonic);
+	  g_free (mnemonic);
+	}
+    }
+}
+
+gboolean
+gtk_window_activate_mnemonic (GtkWindow *window,
+			      guint      keyval,
+			      guint      modifier)
+{
+  GtkWindowMnemonic key;
+  GtkWindowMnemonic *mnemonic;
+  GSList *list;
+  GtkWidget *widget, *chosen_widget;
+  gboolean overloaded;
+
+  g_return_val_if_fail (window != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
+
+  if (modifier != window->mnemonic_modifier)
+    return FALSE;
+
+  key.window = window;
+  key.keyval = keyval;
+
+  mnemonic = g_hash_table_lookup (mnemonic_hash_table, &key);
+
+  if (!mnemonic)
+    return FALSE;
+
+  overloaded = FALSE;
+  chosen_widget = NULL;
+  list = mnemonic->targets;
+  while (list)
+    {
+      widget = GTK_WIDGET (list->data);
+
+      if (GTK_WIDGET_IS_SENSITIVE (widget) &&
+	  GTK_WIDGET_MAPPED (widget))
+	{
+	  if (chosen_widget)
+	    {
+	      overloaded = TRUE;
+	      break;
+	    }
+	  else
+	    chosen_widget = widget;
+	}
+      list = g_slist_next (list);
+    }
+
+  if (chosen_widget)
+    {
+      /* For round robin we put the activated entry on
+       * the end of the list after activation */
+      mnemonic->targets = g_slist_remove (mnemonic->targets, chosen_widget);
+      mnemonic->targets = g_slist_append (mnemonic->targets, chosen_widget);
+      return gtk_widget_activate_mnemonic (chosen_widget, overloaded);
+    }
+  return FALSE;
+}
+
+void
+gtk_window_set_mnemonic_modifier (GtkWindow *window,
+				  guint      modifier)
+{
+  g_return_if_fail (window != NULL);
+  g_return_if_fail (GTK_IS_WINDOW (window));
+
+  window->mnemonic_modifier = modifier;
+}
+
+void
 gtk_window_set_position (GtkWindow         *window,
 			 GtkWindowPosition  position)
 {
@@ -1358,6 +1529,24 @@ gtk_window_destroy (GtkObject *object)
   GTK_OBJECT_CLASS (parent_class)->destroy (object);
 }

+static gboolean
+gtk_window_mnemonic_hash_remove (gpointer	key,
+				 gpointer	value,
+				 gpointer	user)
+{
+  GtkWindowMnemonic *mnemonic = key;
+  GtkWindow *window = user;
+
+  if (mnemonic->window == window)
+    {
+      g_slist_free (mnemonic->targets);
+      g_free (mnemonic);
+
+      return TRUE;
+    }
+  return FALSE;
+}
+
 static void
 gtk_window_finalize (GObject *object)
 {
@@ -1373,6 +1562,10 @@ gtk_window_finalize (GObject *object)
   g_free (window->wmclass_name);
   g_free (window->wmclass_class);

+  g_hash_table_foreach_remove (mnemonic_hash_table,
+			       gtk_window_mnemonic_hash_remove,
+			       window);
+
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }

@@ -1877,7 +2070,12 @@ gtk_window_key_press_event (GtkWidget
     {
       handled = gtk_widget_event (window->focus_widget, (GdkEvent*) event);
     }
-
+
+  if (!handled)
+    handled = gtk_window_activate_mnemonic (window,
+					    event->keyval,
+					    event->state);
+
   if (!handled)
     handled = gtk_accel_groups_activate (GTK_OBJECT (window), event->keyval, event->state);

Index: gtklabel.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtklabel.h,v
retrieving revision 1.26
diff -u -p -r1.26 gtklabel.h
--- gtklabel.h	2001/03/07 21:10:44	1.26
+++ gtklabel.h	2001/03/21 11:32:34
@@ -29,6 +29,8 @@

 #include <gdk/gdk.h>
 #include <gtk/gtkmisc.h>
+#include <gtk/gtkmnemonicactivator.h>
+#include <gtk/gtkwindow.h>


 #ifdef __cplusplus
@@ -60,13 +62,16 @@ struct _GtkLabel
   guint   use_underline : 1;
   guint   use_markup : 1;

-  guint   accel_keyval;
+  guint   mnemonic_keyval;

   gchar  *text;
   PangoAttrList *attrs;

   PangoLayout *layout;

+  GtkWidget *mnemonic_widget;
+  GtkWindow *mnemonic_window;
+
   GtkLabelSelectionInfo *select_info;
 };

@@ -75,8 +80,9 @@ struct _GtkLabelClass
   GtkMiscClass parent_class;
 };

-GtkType    gtk_label_get_type       (void) G_GNUC_CONST;
-GtkWidget *gtk_label_new            (const char       *str);
+GtkType    gtk_label_get_type          (void) G_GNUC_CONST;
+GtkWidget *gtk_label_new               (const char       *str);
+GtkWidget *gtk_label_new_with_mnemonic (const char       *str);

 void                  gtk_label_set_text (GtkLabel   *label,
 					  const char *str);
@@ -86,23 +92,27 @@ void       gtk_label_set_attributes (Gtk
                                      PangoAttrList    *attrs);

 void  gtk_label_set_markup            (GtkLabel    *label,
-                                       const gchar *str);
-guint gtk_label_set_markup_with_accel (GtkLabel    *label,
                                        const gchar *str);
-
-guint gtk_label_get_accel_keyval   (GtkLabel    *label);
-void       gtk_label_set_justify   (GtkLabel         *label,
-				    GtkJustification  jtype);
-void       gtk_label_set_pattern   (GtkLabel         *label,
-				    const gchar      *pattern);
-void       gtk_label_set_line_wrap (GtkLabel         *label,
-				    gboolean          wrap);
+void  gtk_label_set_markup_with_mnemonic (GtkLabel    *label,
+					  const gchar *str);
+
+guint gtk_label_get_mnemonic_keyval (GtkLabel    *label);
+void       gtk_label_set_justify    (GtkLabel         *label,
+				     GtkJustification  jtype);
+void       gtk_label_set_pattern    (GtkLabel         *label,
+				     const gchar      *pattern);
+void       gtk_label_set_line_wrap  (GtkLabel         *label,
+				     gboolean          wrap);
 /* Convenience function to set the name and pattern by parsing
  * a string with embedded underscores, and return the appropriate
  * key symbol for the accelerator.
  */
-guint       gtk_label_parse_uline   (GtkLabel         *label,
-				     const gchar      *string);
+guint gtk_label_parse_uline            (GtkLabel    *label,
+					const gchar *string);
+void  gtk_label_set_text_with_mnemonic (GtkLabel    *label,
+					const gchar *string);
+void  gtk_label_set_mnemonic_widget    (GtkLabel    *label,
+					GtkWidget   *widget);

 void     gtk_label_set_selectable (GtkLabel *label,
                                    gboolean  setting);
Index: gtklabel.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtklabel.c,v
retrieving revision 1.79
diff -u -p -r1.79 gtklabel.c
--- gtklabel.c	2001/03/09 16:43:15	1.79
+++ gtklabel.c	2001/03/21 11:32:34
@@ -26,11 +26,15 @@
 #include <math.h>
 #include <string.h>
 #include "gtklabel.h"
+#include "gtksignal.h"
+#include "gtkwindow.h"
 #include "gdk/gdkkeysyms.h"
 #include "gtkclipboard.h"
 #include "gdk/gdki18n.h"
 #include <pango/pango.h>
 #include "gtkintl.h"
+#include "gtkmenuitem.h"
+#include "gtknotebook.h"

 struct _GtkLabelSelectionInfo
 {
@@ -39,6 +43,7 @@ struct _GtkLabelSelectionInfo
   gint selection_end;
 };

+
 enum {
   PROP_0,
   PROP_LABEL,
@@ -49,7 +54,7 @@ enum {
   PROP_PATTERN,
   PROP_WRAP,
   PROP_SELECTABLE,
-  PROP_ACCEL_KEYVAL
+  PROP_MNEMONIC_KEYVAL
 };

 static void gtk_label_class_init        (GtkLabelClass    *klass);
@@ -57,13 +62,11 @@ static void gtk_label_init
 static void gtk_label_set_property      (GObject          *object,
 					 guint             prop_id,
 					 const GValue     *value,
-					 GParamSpec       *pspec,
-					 const gchar      *trailer);
+					 GParamSpec       *pspec);
 static void gtk_label_get_property      (GObject          *object,
 					 guint             prop_id,
 					 GValue           *value,
-					 GParamSpec       *pspec,
-					 const gchar      *trailer);
+					 GParamSpec       *pspec);
 static void gtk_label_finalize          (GObject          *object);
 static void gtk_label_size_request      (GtkWidget        *widget,
 					 GtkRequisition   *requisition);
@@ -106,6 +109,7 @@ static void set_markup
 						  const gchar   *str,
 						  gboolean       with_uline);
 static void gtk_label_recalculate                (GtkLabel      *label);
+static void gtk_label_hierarchy_changed          (GtkWidget     *widget);

 static void gtk_label_create_window       (GtkLabel *label);
 static void gtk_label_destroy_window      (GtkLabel *label);
@@ -117,6 +121,9 @@ static void gtk_label_select_region_inde
                                            gint      anchor_index,
                                            gint      end_index);

+static gboolean gtk_label_activate_mnemonic (GtkWidget *widget,
+					     gboolean   group_cycling);
+

 static GtkMiscClass *parent_class = NULL;

@@ -175,6 +182,8 @@ gtk_label_class_init (GtkLabelClass *cla
   widget_class->button_press_event = gtk_label_button_press;
   widget_class->button_release_event = gtk_label_button_release;
   widget_class->motion_notify_event = gtk_label_motion;
+  widget_class->hierarchy_changed = gtk_label_hierarchy_changed;
+  widget_class->activate_mnemonic = gtk_label_activate_mnemonic;

   g_object_class_install_property (G_OBJECT_CLASS(object_class),
                                    PROP_LABEL,
@@ -201,7 +210,7 @@ gtk_label_class_init (GtkLabelClass *cla
                                    PROP_USE_UNDERLINE,
                                    g_param_spec_boolean ("use_underline",
 							 _("Use underline"),
-							 _("If set, an underline in the text indicates the next character should be used for the accelerator key"),
+							 _("If set, an underline in the text indicates the next character should be used for the mnemonic accelerator key"),
                                                         FALSE,
                                                         G_PARAM_READWRITE));

@@ -237,22 +246,22 @@ gtk_label_class_init (GtkLabelClass *cla
                                                         FALSE,
                                                         G_PARAM_READWRITE));
   g_object_class_install_property (gobject_class,
-                                   PROP_ACCEL_KEYVAL,
-                                   g_param_spec_uint ("accel_keyval",
-						      _("Accelerator key value"),
-						      _("The accelerator key for this label."),
+                                   PROP_MNEMONIC_KEYVAL,
+                                   g_param_spec_uint ("mnemonic_keyval",
+						      _("Mnemonic accelerator key value"),
+						      _("The mnemonic accelerator key for this label."),
 						      0,
 						      G_MAXUINT,
 						      GDK_VoidSymbol,
 						      G_PARAM_READABLE));
+
 }

 static void
 gtk_label_set_property (GObject      *object,
 			guint         prop_id,
 			const GValue *value,
-			GParamSpec   *pspec,
-			const gchar  *trailer)
+			GParamSpec   *pspec)
 {
   GtkLabel *label;

@@ -298,8 +307,7 @@ static void
 gtk_label_get_property (GObject     *object,
 			guint        prop_id,
 			GValue      *value,
-			GParamSpec  *pspec,
-			const gchar *trailer)
+			GParamSpec  *pspec)
 {
   GtkLabel *label;

@@ -328,8 +336,8 @@ gtk_label_get_property (GObject     *obj
     case PROP_SELECTABLE:
       g_value_set_boolean (value, gtk_label_get_selectable (label));
       break;
-    case PROP_ACCEL_KEYVAL:
-      g_value_set_uint (value, label->accel_keyval);
+    case PROP_MNEMONIC_KEYVAL:
+      g_value_set_uint (value, label->mnemonic_keyval);
       break;

     default:
@@ -351,14 +359,24 @@ gtk_label_init (GtkLabel *label)
   label->use_underline = FALSE;
   label->use_markup = FALSE;

-  label->accel_keyval = GDK_VoidSymbol;
+  label->mnemonic_keyval = GDK_VoidSymbol;
   label->layout = NULL;
   label->text = NULL;
   label->attrs = NULL;
+
+  label->mnemonic_widget = NULL;
+  label->mnemonic_window = NULL;

   gtk_label_set_text (label, "");
 }

+/**
+ * gtk_label_new:
+ * @str: The text of the label
+ * @returns: a new #GtkLabel
+ *
+ * Creates a new #GtkLabel, containing the text in @str.
+ **/
 GtkWidget*
 gtk_label_new (const gchar *str)
 {
@@ -373,20 +391,135 @@ gtk_label_new (const gchar *str)
 }

 /**
- * gtk_label_get_accel_keyval:
+ * gtk_label_new_with_mnemonic:
+ * @str: The text of the label, with an underscore in front of the
+ *       mnemonic character
+ * @returns: a new #GtkLabel
+ *
+ * Creates a new #GtkLabel, containing the text in @str.
+ *
+ * If characters in @str are preceded by an underscore, they are underlined
+ * indicating that they represent a keyboard accelerator called a mnemonic.
+ * The mnemonic key can be used to activate another widget, chosen automatically,
+ * or explicitly using @gtk_label_set_mnemonic_widget.
+ **/
+GtkWidget*
+gtk_label_new_with_mnemonic (const gchar *str)
+{
+  GtkLabel *label;
+
+  label = gtk_type_new (GTK_TYPE_LABEL);
+
+  if (str && *str)
+    gtk_label_set_text_with_mnemonic (label, str);
+
+  return GTK_WIDGET (label);
+}
+
+static gboolean
+gtk_label_activate_mnemonic (GtkWidget *widget,
+			     gboolean   group_cycling)
+{
+  GtkWidget *parent;
+
+  if (GTK_LABEL (widget)->mnemonic_widget)
+    return gtk_widget_activate_mnemonic (GTK_LABEL (widget)->mnemonic_widget, group_cycling);
+
+  /* Try to find the widget to activate by traversing the widget
+   * hierarachy.
+   */
+
+  parent = widget->parent;
+  while (parent)
+    {
+      if (GTK_WIDGET_CAN_FOCUS (parent) ||
+	  (!group_cycling && GTK_WIDGET_GET_CLASS (parent)->activate_signal) ||
+	  (parent->parent && GTK_IS_NOTEBOOK (parent->parent)) ||
+	  (GTK_IS_MENU_ITEM (parent)))
+	return gtk_widget_activate_mnemonic (parent, group_cycling);
+      parent = parent->parent;
+    }
+
+  g_warning ("Couldn't find a target for a mnemonic activation.");
+  gdk_beep ();
+
+  return FALSE;
+}
+
+static void
+gtk_label_setup_mnemonic (GtkLabel *label, guint last_key)
+{
+  GtkWidget *toplevel;
+
+  if ((last_key != GDK_VoidSymbol) && label->mnemonic_window)
+    gtk_window_remove_mnemonic  (label->mnemonic_window,
+				 last_key,
+				 GTK_WIDGET (label));
+
+  if (label->mnemonic_keyval == GDK_VoidSymbol)
+    return;
+
+  toplevel = gtk_widget_get_toplevel (GTK_WIDGET (label));
+
+  if (GTK_IS_WINDOW (toplevel))
+    gtk_window_add_mnemonic (GTK_WINDOW (toplevel),
+			     label->mnemonic_keyval,
+			     GTK_WIDGET (label));
+}
+
+static void
+gtk_label_hierarchy_changed (GtkWidget *widget)
+{
+  GtkLabel *label = GTK_LABEL (widget);
+
+  gtk_label_setup_mnemonic (label, label->mnemonic_keyval);
+}
+
+
+/**
+ * gtk_label_set_mnemonic_widget:
  * @label: a #GtkLabel
+ * @widget: the target #GtkWidget
+ *
+ * If the label has been set so that it has an mnemonic key (using i.e.
+ * @gtk_label_set_markup_with_mnemonic, @gtk_label_set_text_with_mnemonic,
+ * @gtk_label_new_with_mnemonic or the use_underline property) the label can be
+ * associated with a widget that is the target of the mnemonic. When the label
+ * is inside a widget (like a #GtkButton or a #GtkNotebook tab) it is automatically
+ * associated with the correct widget, but sometimes (i.e. when the target is
+ * a #GtkEntry next to the label) you need to set it explicitly using this
+ * function.
+ *
+ * The target widget will be accelerated by emitting "activate_mnemonic" on it.
+ * The default handler for this signal will activate the widget if there are no
+ * mnemonic collisions and toggle focus between the colliding widgets otherwise.
+ **/
+void
+gtk_label_set_mnemonic_widget (GtkLabel         *label,
+			       GtkWidget        *widget)
+{
+  g_return_if_fail (GTK_IS_LABEL (label));
+  g_return_if_fail (GTK_IS_WIDGET (widget));
+
+  label->mnemonic_widget = widget;
+}
+
+
+/**
+ * gtk_label_get_mnemonic_keyval:
+ * @label: a #GtkLabel
  * @Returns: GDK keyval usable for accelerators, or GDK_VoidSymbol
  *
- * If the label text was set using gtk_label_set_markup_with_accel,
- * gtk_label_parse_uline, or using the use_underline property this function
- * returns the keyval for the first underlined accelerator.
+ * If the label has been set so that it has an mnemonic key this function
+ * returns the keyval used for the mnemonic accelerator. If there is no
+ * mnemonic set up it returns #GDK_VoidSymbol.
  **/
 guint
-gtk_label_get_accel_keyval (GtkLabel *label)
+gtk_label_get_mnemonic_keyval (GtkLabel *label)
 {
   g_return_val_if_fail (GTK_IS_LABEL (label), GDK_VoidSymbol);

-  return label->accel_keyval;
+  return label->mnemonic_keyval;
 }

 static void
@@ -446,7 +579,7 @@ gtk_label_set_attributes_internal (GtkLa
 }


-/* Calculates text, attrs and accel_keyval from
+/* Calculates text, attrs and mnemonic_keyval from
  * label, use_underline and use_markup */
 static void
 gtk_label_recalculate (GtkLabel *label)
@@ -465,12 +598,25 @@ gtk_label_recalculate (GtkLabel *label)
     }

   if (!label->use_underline)
-    label->accel_keyval = GDK_VoidSymbol;
+    {
+      guint keyval = label->mnemonic_keyval;
+      label->mnemonic_keyval = GDK_VoidSymbol;
+      gtk_label_setup_mnemonic (label, keyval);
+    }

   gtk_label_clear_layout (label);
   gtk_widget_queue_resize (GTK_WIDGET (label));
 }

+/**
+ * gtk_label_set_text:
+ * label: a #GtkLabel
+ * str: a string
+ *
+ * Sets the text of the label to @str.
+ *
+ * This will also clear any previously set mnemonic accelerators.
+ **/
 void
 gtk_label_set_text (GtkLabel    *label,
 		    const gchar *str)
@@ -538,9 +684,9 @@ set_markup (GtkLabel    *label,
     }

   if (accel_char != 0)
-    label->accel_keyval = gdk_keyval_to_lower (gdk_unicode_to_keyval (accel_char));
+    label->mnemonic_keyval = gdk_keyval_to_lower (gdk_unicode_to_keyval (accel_char));
   else
-    label->accel_keyval = GDK_VoidSymbol;
+    label->mnemonic_keyval = GDK_VoidSymbol;
 }

 /**
@@ -565,31 +711,32 @@ gtk_label_set_markup (GtkLabel    *label
 }

 /**
- * gtk_label_set_markup_with_accel:
+ * gtk_label_set_markup_with_mnemonic:
  * @label: a #GtkLabel
  * @str: a markup string (see <link linkend="PangoMarkupFormat">Pango markup format</link>)
  *
  * Parses @str which is marked up with the Pango text markup language,
  * setting the label's text and attribute list based on the parse results.
  * If characters in @str are preceded by an underscore, they are underlined
- * indicating that they represent a keyboard accelerator, and the GDK
- * keyval for the first underlined accelerator is returned. If there are
- * no underlines in the text, GDK_VoidSymbol will be returned.
+ * indicating that they represent a keyboard accelerator called a mnemonic.
  *
- * Return value: GDK keyval for accelerator
+ * The mnemonic key can be used to activate another widget, chosen automatically,
+ * or explicitly using @gtk_label_set_mnemonic_widget.
  **/
-guint
-gtk_label_set_markup_with_accel (GtkLabel    *label,
-                                 const gchar *str)
+void
+gtk_label_set_markup_with_mnemonic (GtkLabel    *label,
+				    const gchar *str)
 {
-  g_return_val_if_fail (GTK_IS_LABEL (label), GDK_VoidSymbol);
+  guint last_keyval;
+  g_return_if_fail (GTK_IS_LABEL (label));

+  last_keyval = label->mnemonic_keyval;
   gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
   gtk_label_set_use_markup_internal (label, TRUE);
   gtk_label_set_use_underline_internal (label, TRUE);

   gtk_label_recalculate (label);
-  return label->accel_keyval;
+  gtk_label_setup_mnemonic (label, last_keyval);
 }

 /**
@@ -741,7 +888,7 @@ gtk_label_finalize (GObject *object)
     pango_attr_list_unref (label->attrs);

   g_free (label->select_info);
-
+
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }

@@ -1207,22 +1354,64 @@ gtk_label_set_uline_text_internal (GtkLa

   g_free (pattern);

-  label->accel_keyval = accel_key;
+  label->mnemonic_keyval = accel_key;
 }

 guint
 gtk_label_parse_uline (GtkLabel    *label,
 		       const gchar *str)
 {
+  guint keyval;
+  guint orig_keyval;
+
   g_return_val_if_fail (GTK_IS_LABEL (label), GDK_VoidSymbol);
   g_return_val_if_fail (str != NULL, GDK_VoidSymbol);

+  orig_keyval = label->mnemonic_keyval;
+
+  gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
+  gtk_label_set_use_markup_internal (label, FALSE);
+  gtk_label_set_use_underline_internal (label, TRUE);
+
+  gtk_label_recalculate (label);
+
+  keyval = label->mnemonic_keyval;
+  label->mnemonic_keyval = GDK_VoidSymbol;
+
+  gtk_label_setup_mnemonic (label, orig_keyval);
+
+  return keyval;
+}
+
+/**
+ * gtk_label_set_text_with_mnemonic:
+ * @label: a #GtkLabel
+ * @str: a string
+ *
+ * Sets the label's text from the string @str.
+ * If characters in @str are preceded by an underscore, they are underlined
+ * indicating that they represent a keyboard accelerator called a mnemonic.
+ * The mnemonic key can be used to activate another widget, chosen automatically,
+ * or explicitly using @gtk_label_set_mnemonic_widget.
+ **/
+void
+gtk_label_set_text_with_mnemonic (GtkLabel    *label,
+				  const gchar *str)
+{
+  guint last_keyval;
+
+  g_return_if_fail (GTK_IS_LABEL (label));
+  g_return_if_fail (str != NULL);
+
+  last_keyval = label->mnemonic_keyval;
+
   gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
   gtk_label_set_use_markup_internal (label, FALSE);
   gtk_label_set_use_underline_internal (label, TRUE);

   gtk_label_recalculate (label);
-  return label->accel_keyval;
+
+  gtk_label_setup_mnemonic (label, last_keyval);
 }


@@ -1659,8 +1848,6 @@ gtk_label_select_region  (GtkLabel *labe

   if (label->text && label->select_info)
     {
-      GtkClipboard *clipboard;
-
       if (start_offset < 0)
         start_offset = 0;

Index: gtkbutton.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkbutton.c,v
retrieving revision 1.55
diff -u -p -r1.55 gtkbutton.c
--- gtkbutton.c	2001/03/16 20:12:39	1.55
+++ gtkbutton.c	2001/03/21 11:32:33
@@ -319,9 +319,17 @@ gtk_button_new_with_label (const gchar *
   return button;
 }

+/**
+ * gtk_button_new_from_stock:
+ * @stock_id: the name of the stock item
+ * @returns: a new #GtkButton
+ *
+ * Creates a new #GtkButton containing the image and text from a stock item.
+ * Some stock ids have preprocessor macros like #GTK_STOCK_BUTTON_OK and
+ * #GTK_STOCK_BUTTON_APPLY.
+ **/
 GtkWidget*
-gtk_button_new_stock (const gchar   *stock_id,
-                      GtkAccelGroup *accel_group)
+gtk_button_new_from_stock (const gchar   *stock_id)
 {
   GtkWidget *button;
   GtkStockItem item;
@@ -331,35 +339,13 @@ gtk_button_new_stock (const gchar   *sto
       GtkWidget *label;
       GtkWidget *image;
       GtkWidget *hbox;
-      guint keyval;

       button = gtk_button_new ();

-      label = gtk_label_new (NULL);
-      keyval = gtk_label_parse_uline (GTK_LABEL (label),
-                                      item.label);
-
-      if (keyval && accel_group)
-        {
-          gtk_widget_add_accelerator (button,
-                                      "clicked",
-                                      accel_group,
-                                      keyval,
-                                      GDK_MOD1_MASK,
-                                      GTK_ACCEL_LOCKED);
-        }
-
-      /* Also add the stock accelerator if one was specified. */
-      if (item.keyval && accel_group)
-        {
-          gtk_widget_add_accelerator (button,
-                                      "clicked",
-                                      accel_group,
-                                      item.keyval,
-                                      item.modifier,
-                                      GTK_ACCEL_LOCKED);
-        }
+      label = gtk_label_new_with_mnemonic (item.label);

+      gtk_label_set_mnemonic_widget (GTK_LABEL (label), button);
+
       image = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_BUTTON);
       hbox = gtk_hbox_new (FALSE, 0);

@@ -371,37 +357,37 @@ gtk_button_new_stock (const gchar   *sto
     }
   else
     {
-      button = gtk_button_new_accel (stock_id, accel_group);
+      button = gtk_button_new_with_mnemonic (stock_id);
     }

   return button;
 }

+/**
+ * gtk_button_new_with_mnemonic:
+ * @label: The text of the button, with an underscore in front of the
+ *         mnemonic character
+ * @returns: a new #GtkButton
+ *
+ * Creates a new #GtkButton containing a label.
+ * If characters in @label are preceded by an underscore, they are underlined
+ * indicating that they represent a keyboard accelerator called a mnemonic.
+ * Pressing Alt and that key activates the button.
+ **/
 GtkWidget*
-gtk_button_new_accel (const gchar   *uline_label,
-                      GtkAccelGroup *accel_group)
+gtk_button_new_with_mnemonic (const gchar *label)
 {
   GtkWidget *button;
-  GtkWidget *label;
-  guint keyval;
+  GtkWidget *label_widget;

   button = gtk_button_new ();

-  label = gtk_label_new (NULL);
-  keyval = gtk_label_parse_uline (GTK_LABEL (label), uline_label);
+  label_widget = gtk_label_new_with_mnemonic (label);

-  if (keyval && accel_group)
-    {
-      gtk_widget_add_accelerator (button,
-                                  "clicked",
-                                  accel_group,
-                                  keyval,
-                                  GDK_MOD1_MASK,
-                                  GTK_ACCEL_LOCKED);
-    }
+  gtk_label_set_mnemonic_widget (GTK_LABEL (label_widget), button);

-  gtk_container_add (GTK_CONTAINER (button), label);
-  gtk_widget_show (label);
+  gtk_container_add (GTK_CONTAINER (button), label_widget);
+  gtk_widget_show (label_widget);

   return button;
 }
Index: gtkbutton.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkbutton.h,v
retrieving revision 1.15
diff -u -p -r1.15 gtkbutton.h
--- gtkbutton.h	2001/03/06 15:51:09	1.15
+++ gtkbutton.h	2001/03/21 11:32:33
@@ -77,20 +77,18 @@ struct _GtkButtonClass


 GtkType        gtk_button_get_type       (void) G_GNUC_CONST;
-GtkWidget*     gtk_button_new            (void);
-GtkWidget*     gtk_button_new_with_label (const gchar   *label);
-GtkWidget*     gtk_button_new_stock      (const gchar   *stock_id,
-                                          GtkAccelGroup *accel_group);
-GtkWidget*     gtk_button_new_accel      (const gchar   *uline_label,
-                                          GtkAccelGroup *accel_group);
-void           gtk_button_pressed        (GtkButton *button);
-void           gtk_button_released       (GtkButton *button);
-void           gtk_button_clicked        (GtkButton *button);
-void           gtk_button_enter          (GtkButton *button);
-void           gtk_button_leave          (GtkButton *button);
-void           gtk_button_set_relief     (GtkButton *button,
-					  GtkReliefStyle newstyle);
-GtkReliefStyle gtk_button_get_relief      (GtkButton *button);
+GtkWidget*     gtk_button_new               (void);
+GtkWidget*     gtk_button_new_with_label    (const gchar    *label);
+GtkWidget*     gtk_button_new_from_stock    (const gchar    *stock_id);
+GtkWidget*     gtk_button_new_with_mnemonic (const gchar    *label);
+void           gtk_button_pressed           (GtkButton      *button);
+void           gtk_button_released          (GtkButton      *button);
+void           gtk_button_clicked           (GtkButton      *button);
+void           gtk_button_enter             (GtkButton      *button);
+void           gtk_button_leave             (GtkButton      *button);
+void           gtk_button_set_relief        (GtkButton      *button,
+					     GtkReliefStyle  newstyle);
+GtkReliefStyle gtk_button_get_relief        (GtkButton      *button);


 #ifdef __cplusplus
Index: gtkcheckbutton.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkcheckbutton.c,v
retrieving revision 1.26
diff -u -p -r1.26 gtkcheckbutton.c
--- gtkcheckbutton.c	2001/03/09 13:28:23	1.26
+++ gtkcheckbutton.c	2001/03/21 11:32:33
@@ -123,6 +123,35 @@ gtk_check_button_new_with_label (const g
   return check_button;
 }

+/**
+ * gtk_check_button_new_with_mnemonic:
+ * @label: The text of the button, with an underscore in front of the
+ *         mnemonic character
+ * @returns: a new #GtkCheckButton
+ *
+ * Creates a new #GtkCheckButton containing a label.
+ * If characters in @label are preceded by an underscore, they are underlined
+ * indicating that they represent a keyboard accelerator called a mnemonic.
+ * Pressing Alt and that key activates the checkbutton.
+ **/
+GtkWidget*
+gtk_check_button_new_with_mnemonic (const gchar *label)
+{
+  GtkWidget *check_button;
+  GtkWidget *label_widget;
+
+  check_button = gtk_check_button_new ();
+  label_widget = gtk_label_new_with_mnemonic (label);
+  gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
+  gtk_label_set_mnemonic_widget (GTK_LABEL (label_widget), check_button);
+
+  gtk_container_add (GTK_CONTAINER (check_button), label_widget);
+  gtk_widget_show (label_widget);
+
+  return check_button;
+}
+
+
 /* This should only be called when toggle_button->draw_indicator
  * is true.
  */
Index: gtkcheckbutton.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkcheckbutton.h,v
retrieving revision 1.7
diff -u -p -r1.7 gtkcheckbutton.h
--- gtkcheckbutton.h	2000/08/30 00:33:37	1.7
+++ gtkcheckbutton.h	2001/03/21 11:32:33
@@ -66,8 +66,9 @@ struct _GtkCheckButtonClass


 GtkType    gtk_check_button_get_type       (void) G_GNUC_CONST;
-GtkWidget* gtk_check_button_new            (void);
-GtkWidget* gtk_check_button_new_with_label (const gchar *label);
+GtkWidget* gtk_check_button_new               (void);
+GtkWidget* gtk_check_button_new_with_label    (const gchar *label);
+GtkWidget* gtk_check_button_new_with_mnemonic (const gchar *label);


 #ifdef __cplusplus
Index: gtkdialog.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkdialog.c,v
retrieving revision 1.21
diff -u -p -r1.21 gtkdialog.c
--- gtkdialog.c	2001/03/07 21:32:50	1.21
+++ gtkdialog.c	2001/03/21 11:32:33
@@ -471,8 +471,7 @@ gtk_dialog_add_button (GtkDialog   *dial
   g_return_val_if_fail (GTK_IS_DIALOG (dialog), NULL);
   g_return_val_if_fail (button_text != NULL, NULL);

-  button = gtk_button_new_stock (button_text,
-                                 gtk_window_get_default_accel_group (GTK_WINDOW (dialog)));
+  button = gtk_button_new_from_stock (button_text);

   GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);

Index: gtkentry.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkentry.c,v
retrieving revision 1.115
diff -u -p -r1.115 gtkentry.c
--- gtkentry.c	2001/03/16 01:44:54	1.115
+++ gtkentry.c	2001/03/21 11:32:33
@@ -250,6 +250,8 @@ static void         gtk_entry_paste
 static void         gtk_entry_update_primary_selection (GtkEntry       *entry);
 static void         gtk_entry_popup_menu               (GtkEntry       *entry,
 							GdkEventButton *event);
+static gboolean     gtk_entry_activate_mnemonic        (GtkWidget     *widget,
+							gboolean       group_cycling);

 static GtkWidgetClass *parent_class = NULL;

@@ -341,6 +343,7 @@ gtk_entry_class_init (GtkEntryClass *cla
   widget_class->style_set = gtk_entry_style_set;
   widget_class->direction_changed = gtk_entry_direction_changed;
   widget_class->state_changed = gtk_entry_state_changed;
+  widget_class->activate_mnemonic = gtk_entry_activate_mnemonic;

   widget_class->drag_motion = gtk_entry_drag_motion;
   widget_class->drag_leave = gtk_entry_drag_leave;
@@ -3131,6 +3134,15 @@ activate_cb (GtkWidget *menuitem,
 {
   const gchar *signal = gtk_object_get_data (GTK_OBJECT (menuitem), "gtk-signal");
   gtk_signal_emit_by_name (GTK_OBJECT (entry), signal);
+}
+
+
+static gboolean
+gtk_entry_activate_mnemonic (GtkWidget *widget,
+			     gboolean   group_cycling)
+{
+  gtk_widget_grab_focus (widget);
+  return TRUE;
 }

 static void
Index: gtkitemfactory.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkitemfactory.c,v
retrieving revision 1.34
diff -u -p -r1.34 gtkitemfactory.c
--- gtkitemfactory.c	2001/03/19 21:06:37	1.34
+++ gtkitemfactory.c	2001/03/21 11:32:33
@@ -1227,25 +1276,8 @@ gtk_item_factory_create_item (GtkItemFac
 			      "GtkAccelLabel::accel_widget", widget,
 			      "GtkMisc::xalign", 0.0,
 			      NULL);
-
-      accel_key = gtk_label_parse_uline (GTK_LABEL (label), name);

-      if (accel_key != GDK_VoidSymbol)
-	{
-	  if (GTK_IS_MENU_BAR (parent))
-	    gtk_widget_add_accelerator (widget,
-					"activate_item",
-					ifactory->accel_group,
-					accel_key, GDK_MOD1_MASK,
-					GTK_ACCEL_LOCKED);
-
-	  if (GTK_IS_MENU (parent))
-	    gtk_widget_add_accelerator (widget,
-					"activate_item",
-					gtk_menu_ensure_uline_accel_group (GTK_MENU (parent)),
-					accel_key, 0,
-					GTK_ACCEL_LOCKED);
-	}
+      gtk_label_set_text_with_mnemonic (GTK_LABEL (label), name);
     }

   g_free (name);
Index: gtkmarshal.list
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkmarshal.list,v
retrieving revision 1.24
diff -u -p -r1.24 gtkmarshal.list
--- gtkmarshal.list	2001/03/09 14:49:00	1.24
+++ gtkmarshal.list	2001/03/21 11:32:34
@@ -25,6 +25,7 @@ BOOLEAN:BOXED
 BOOLEAN:OBJECT,INT,INT,UINT
 BOOLEAN:OBJECT,STRING,STRING,BOXED
 BOOLEAN:VOID
+BOOLEAN:BOOLEAN
 ENUM:ENUM
 INT:OBJECT,BOXED,BOXED
 INT:POINTER
Index: gtkmenu.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkmenu.c,v
retrieving revision 1.59
diff -u -p -r1.59 gtkmenu.c
--- gtkmenu.c	2001/03/09 13:28:25	1.59
+++ gtkmenu.c	2001/03/21 11:32:34
@@ -116,7 +116,6 @@ static void gtk_menu_remove         (Gtk

 static GtkMenuShellClass *parent_class = NULL;
 static const gchar	 *attach_data_key = "gtk-menu-attach-data";
-static GQuark             quark_uline_accel_group = 0;

 GtkType
 gtk_menu_get_type (void)
@@ -248,6 +247,7 @@ gtk_menu_init (GtkMenu *menu)
 				     NULL);
   gtk_window_set_policy (GTK_WINDOW (menu->toplevel),
 			 FALSE, FALSE, TRUE);
+  gtk_window_set_mnemonic_modifier (GTK_WINDOW (menu->toplevel), 0);

   /* Refloat the menu, so that reference counting for the menu isn't
    * affected by it being a child of the toplevel
@@ -739,38 +739,6 @@ gtk_menu_get_accel_group (GtkMenu *menu)
   return menu->accel_group;
 }

-GtkAccelGroup*
-gtk_menu_ensure_uline_accel_group (GtkMenu *menu)
-{
-  GtkAccelGroup *accel_group;
-
-  g_return_val_if_fail (GTK_IS_MENU (menu), NULL);
-
-  if (!quark_uline_accel_group)
-    quark_uline_accel_group = g_quark_from_static_string ("GtkMenu-uline-accel-group");
-
-  accel_group = gtk_object_get_data_by_id (GTK_OBJECT (menu), quark_uline_accel_group);
-  if (!accel_group)
-    {
-      accel_group = gtk_accel_group_new ();
-      gtk_accel_group_attach (accel_group, GTK_OBJECT (menu));
-      gtk_object_set_data_by_id_full (GTK_OBJECT (menu),
-				      quark_uline_accel_group,
-				      accel_group,
-				      (GtkDestroyNotify) gtk_accel_group_unref);
-    }
-
-  return accel_group;
-}
-
-GtkAccelGroup*
-gtk_menu_get_uline_accel_group (GtkMenu *menu)
-{
-  g_return_val_if_fail (GTK_IS_MENU (menu), NULL);
-
-  return gtk_object_get_data_by_id (GTK_OBJECT (menu), quark_uline_accel_group);
-}
-
 void
 gtk_menu_reposition (GtkMenu *menu)
 {
@@ -844,6 +812,7 @@ gtk_menu_set_tearoff_state (GtkMenu  *me
 						       NULL);
 	      gtk_window_set_type_hint (GTK_WINDOW (menu->tearoff_window),
 					GDK_WINDOW_TYPE_HINT_MENU);
+	      gtk_window_set_mnemonic_modifier (GTK_WINDOW (menu->tearoff_window), 0);
 	      gtk_widget_set_app_paintable (menu->tearoff_window, TRUE);
 	      gtk_signal_connect (GTK_OBJECT (menu->tearoff_window),
 				  "event",
@@ -1420,7 +1389,6 @@ gtk_menu_key_press (GtkWidget	*widget,
       (delete ||
        (gtk_accelerator_valid (event->keyval, event->state) &&
 	(event->state ||
-	 !gtk_menu_get_uline_accel_group (GTK_MENU (menu_shell)) ||
 	 (event->keyval >= GDK_F1 && event->keyval <= GDK_F35)))))
     {
       GtkMenuItem *menu_item;
Index: gtkmenu.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkmenu.h,v
retrieving revision 1.23
diff -u -p -r1.23 gtkmenu.h
--- gtkmenu.h	2000/11/08 17:34:52	1.23
+++ gtkmenu.h	2001/03/21 11:32:34
@@ -147,12 +147,6 @@ void	       gtk_menu_set_accel_group	  (
 					   GtkAccelGroup       *accel_group);
 GtkAccelGroup* gtk_menu_get_accel_group	  (GtkMenu	       *menu);

-/* get the accelerator group that is used internally by the menu for
- * underline accelerators while the menu is popped up.
- */
-GtkAccelGroup* gtk_menu_get_uline_accel_group    (GtkMenu         *menu);
-GtkAccelGroup* gtk_menu_ensure_uline_accel_group (GtkMenu         *menu);
-

 /* A reference count is kept for a widget when it is attached to
  * a particular widget. This is typically a menu item; it may also
Index: gtkmenuitem.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkmenuitem.c,v
retrieving revision 1.48
diff -u -p -r1.48 gtkmenuitem.c
--- gtkmenuitem.c	2001/03/16 20:12:39	1.48
+++ gtkmenuitem.c	2001/03/21 11:32:34
@@ -67,6 +67,8 @@ static void gtk_real_menu_item_toggle_si
 						     gint        *requisition);
 static void gtk_real_menu_item_toggle_size_allocate (GtkMenuItem *menu_item,
 						     gint         allocation);
+static gboolean gtk_menu_item_activate_mnemonic     (GtkWidget   *widget,
+						     gboolean     group_cycling);

 static gint gtk_menu_item_select_timeout (gpointer          data);
 static void gtk_menu_item_popup_submenu  (gpointer     data);
@@ -82,6 +84,7 @@ static void gtk_menu_item_forall
 					  GtkCallback      callback,
 					  gpointer         callback_data);

+
 static GtkItemClass *parent_class;
 static guint menu_item_signals[LAST_SIGNAL] = { 0 };
 static guint32	last_submenu_deselect_time = 0;
@@ -137,6 +140,7 @@ gtk_menu_item_class_init (GtkMenuItemCla
   widget_class->expose_event = gtk_menu_item_expose;
   widget_class->show_all = gtk_menu_item_show_all;
   widget_class->hide_all = gtk_menu_item_hide_all;
+  widget_class->activate_mnemonic = gtk_menu_item_activate_mnemonic;

   container_class->forall = gtk_menu_item_forall;

@@ -600,6 +604,25 @@ gtk_real_menu_item_deselect (GtkItem *it
   gtk_widget_set_state (GTK_WIDGET (menu_item), GTK_STATE_NORMAL);
   gtk_widget_draw (GTK_WIDGET (menu_item), NULL);
 }
+
+static gboolean
+gtk_menu_item_activate_mnemonic (GtkWidget *widget,
+				 gboolean   group_cycling)
+{
+  if (group_cycling)
+    {
+      if (widget->parent &&
+	  GTK_IS_MENU_SHELL (widget->parent))
+	gtk_menu_shell_select_item (GTK_MENU_SHELL (widget->parent),
+				    widget);
+
+    }
+  else
+    gtk_signal_emit (GTK_OBJECT (widget), menu_item_signals[ACTIVATE_ITEM]);
+
+  return TRUE;
+}
+

 static void
 gtk_real_menu_item_activate_item (GtkMenuItem *menu_item)
Index: gtkmenushell.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkmenushell.c,v
retrieving revision 1.39
diff -u -p -r1.39 gtkmenushell.c
--- gtkmenushell.c	2001/03/06 15:51:10	1.39
+++ gtkmenushell.c	2001/03/21 11:32:35
@@ -31,8 +31,8 @@
 #include "gtktearoffmenuitem.h" /* FIXME */
 #include "gtkmenushell.h"
 #include "gtksignal.h"
+#include "gtkwindow.h"

-
 #define MENU_SHELL_TIMEOUT   500


@@ -551,6 +551,7 @@ gtk_menu_shell_key_press (GtkWidget	*wid
 			  GdkEventKey *event)
 {
   GtkMenuShell *menu_shell;
+  GtkWidget *toplevel;

   g_return_val_if_fail (widget != NULL, FALSE);
   g_return_val_if_fail (GTK_IS_MENU_SHELL (widget), FALSE);
@@ -566,6 +567,13 @@ gtk_menu_shell_key_press (GtkWidget	*wid
 			     event->state))
     return TRUE;

+  toplevel = gtk_widget_get_toplevel (widget);
+  if (GTK_IS_WINDOW (toplevel) &&
+      gtk_window_activate_mnemonic (GTK_WINDOW (toplevel),
+				    event->keyval,
+				    event->state))
+    return TRUE;
+
   if (gtk_accel_groups_activate (GTK_OBJECT (widget), event->keyval, event->state))
     return TRUE;

Index: gtknotebook.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtknotebook.c,v
retrieving revision 1.82
diff -u -p -r1.82 gtknotebook.c
--- gtknotebook.c	2001/03/09 13:28:25	1.82
+++ gtknotebook.c	2001/03/21 11:32:35
@@ -94,6 +94,8 @@ struct _GtkNotebookPage

   GtkRequisition requisition;
   GtkAllocation allocation;
+
+  guint activate_mnemonic_signal;
 };

 #ifdef G_DISABLE_CHECKS
@@ -1972,6 +1974,10 @@ gtk_notebook_real_remove (GtkNotebook *n
   if (GTK_WIDGET_VISIBLE (page->child) && GTK_WIDGET_VISIBLE (notebook))
     need_resize = TRUE;

+  if (page->tab_label && page->activate_mnemonic_signal)
+    gtk_signal_disconnect (page->tab_label,
+			   page->activate_mnemonic_signal);
+
   gtk_widget_unparent (page->child);

   if (page->tab_label)
@@ -3618,6 +3624,35 @@ gtk_notebook_insert_page (GtkNotebook *n
   gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
 }

+
+static gint
+gtk_notebook_page_compare_tab (gconstpointer a,
+			       gconstpointer b)
+{
+  return (((GtkNotebookPage *) a)->tab_label != b);
+}
+
+static gboolean
+gtk_notebook_activate_mnemonic_switch_page (GtkWidget *child,
+					    gboolean overload,
+					    gpointer data)
+{
+  GtkNotebook *notebook = GTK_NOTEBOOK (data);
+  GtkNotebookPage *page;
+  GList *list;
+
+  list = g_list_find_custom (notebook->children, child,
+			     gtk_notebook_page_compare_tab);
+  if (!list)
+    return TRUE;
+
+
+  page = list->data;
+
+  gtk_notebook_switch_page (notebook, page,  -1);
+  return TRUE;
+}
+
 /**
  * gtk_notebook_insert_page_menu:
  * @notebook: a #GtkNotebook
@@ -3661,6 +3696,7 @@ gtk_notebook_insert_page_menu (GtkNotebo
   page->allocation.height = 0;
   page->default_menu = FALSE;
   page->default_tab = FALSE;
+  page->activate_mnemonic_signal = 0;

   nchildren = g_list_length (notebook->children);
   if ((position < 0) || (position > nchildren))
@@ -3741,6 +3777,13 @@ gtk_notebook_insert_page_menu (GtkNotebo
 	    gtk_widget_hide (tab_label);
 	}
     }
+
+  if (tab_label)
+    page->activate_mnemonic_signal =
+      gtk_signal_connect (GTK_OBJECT (tab_label),
+			  "activate_mnemonic",
+			  (GtkSignalFunc) gtk_notebook_activate_mnemonic_switch_page,
+			  notebook);
 }

 /**






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