changeset 2081:e8db6a10ad42

[xemacs-hg @ 2004-05-15 07:31:43 by malcolmp] Added support for Gtk menu bar, menu item and dialog button mnemonics.
author malcolmp
date Sat, 15 May 2004 07:31:49 +0000
parents ebba17579ace
children 16489ca72b3d
files lisp/ChangeLog lisp/dialog-gtk.el lisp/gtk-widgets.el src/ChangeLog src/event-gtk.c src/menubar-gtk.c
diffstat 6 files changed, 348 insertions(+), 64 deletions(-) [+]
line wrap: on
line diff
--- a/lisp/ChangeLog	Fri May 14 21:50:44 2004 +0000
+++ b/lisp/ChangeLog	Sat May 15 07:31:49 2004 +0000
@@ -1,3 +1,13 @@
+2004-05-15  Malcolm Purvis  <malcolmp@xemacs.org>
+
+	* gtk-widgets.el: New import: gtk-accel-group-new.
+	* dialog-gtk.el:
+	* dialog-gtk.el (gtk-popup-convert-underscores): New.
+	* dialog-gtk.el (popup-builtin-question-dialog):
+
+	Added support for dialog button mnemonics.
+
+
 2004-04-30  Stephen J. Turnbull  <stephen@xemacs.org>
 
 	* cl.el (gensym, gentemp): Improve docstrings.
--- a/lisp/dialog-gtk.el	Fri May 14 21:50:44 2004 +0000
+++ b/lisp/dialog-gtk.el	Sat May 15 07:31:49 2004 +0000
@@ -44,7 +44,33 @@
   gtk-window-set-title gtk-container-set-border-width
   gtk-box-set-spacing gtk-dialog-vbox gtk-container-add
   gtk-label-new gtk-button-new-with-label
-  gtk-widget-set-sensitive gtk-widget-show gtk-dialog-action-area))
+  gtk-widget-set-sensitive gtk-widget-show gtk-dialog-action-area
+  gtk-label-parse-uline gtk-widget-add-accelerator gtk-accel-group-new))
+
+(defun gtk-popup-convert-underscores (str)
+  ;; Convert the XEmacs button accelerator representation to Gtk mnemonic
+  ;; form.  If no accelerator has been provided, put one at the start of the
+  ;; string (this mirrors the behaviour under X). This algorithm is also found
+  ;; in menubar-gtk.c:convert_underscores().
+  (let ((new-str (string))
+	(i 0)
+	(found-accel nil))
+    (while (< i (length str))
+      (let ((c (aref str i)))
+	(cond ((eq c ?%)
+	       (setq i (1+ i))
+	       (if (and (not (eq (aref str i) ?_)) (not (eq (aref str i) ?%)))
+		   (setq i (1- i)))
+	       (setq found-accel 1)
+	       )
+	      ((eq c ?_)
+	       	(setq new-str (concat new-str "_")))
+	       ))
+	(setq new-str (concat new-str (string (aref str i))))
+	(setq i (1+ i))
+	)
+    (if found-accel new-str (concat "_" new-str)) 
+    ))
 
 (defun popup-builtin-open-dialog (keys)
   ;; Allowed keywords are:
@@ -197,6 +223,10 @@
 	(callback nil)
 	(flushrightp nil)
 	(length nil)
+	(label nil)
+	(gui-button nil)
+	(accel-group (gtk-accel-group-new))
+	(accel-key nil)
 	(errp t))
     (if (not buttons-descr)
 	(error 'syntax-error
@@ -244,7 +274,22 @@
 			(setq activep (plist-get plist :active)
 			      callback (plist-get plist :callback)))))
 
-		    (push (gtk-button-new-with-label (aref button 0)) buttons)
+		    ;; Create the label and determine what the mnemonic key is.
+		    (setq label (gtk-label-new ""))
+		    (setq accel-key (gtk-label-parse-uline label
+							   (gtk-popup-convert-underscores (aref button 0))))
+		    ;; Place the label in the button.
+		    (gtk-misc-set-alignment label 0.5 0.5)
+		    (setq gui-button (gtk-button-new))
+		    (gtk-container-add gui-button label)
+		    ;; Add ALT-mnemonic to the dialog's accelerator group.
+		    (gtk-widget-add-accelerator gui-button "clicked" accel-group
+						accel-key
+						8 ; GDK_MOD1_MASK
+						4 ; GTK_ACCEL_LOCKED
+						)
+		    
+		    (push gui-button buttons)
 		    (gtk-widget-set-sensitive (car buttons) (eval activep))
 		    
 		    ;; Apply the callback
@@ -273,6 +318,9 @@
 	  (gtk-window-set-transient-for dialog (frame-property nil 'shell-widget))
 	  (put dialog 'type 'dialog)
 	  (put dialog 'modal t)
+	  ;; Make the dialog listen for global mnemonic keys/
+	  (gtk-window-add-accel-group dialog accel-group)
+
 	  (gtk-widget-show-all dialog)
 	  (gtk-main)
 	  (gtk-widget-destroy dialog)
--- a/lisp/gtk-widgets.el	Fri May 14 21:50:44 2004 +0000
+++ b/lisp/gtk-widgets.el	Sat May 15 07:31:49 2004 +0000
@@ -35,6 +35,9 @@
  '(gtk-import-function-internal
    gtk-call-function gtk-import-variable-internal gtk-ctree-recurse))
 
+(gtk-import-function GtkAccelGroup gtk_accel_group_new)
+
+
 (gtk-import-function GtkType gtk_accel_label_get_type)
 (gtk-import-function GtkWidget gtk_accel_label_new GtkString)
 (gtk-import-function guint gtk_accel_label_get_accel_width GtkAccelLabel)
--- a/src/ChangeLog	Fri May 14 21:50:44 2004 +0000
+++ b/src/ChangeLog	Sat May 15 07:31:49 2004 +0000
@@ -1,3 +1,25 @@
+2004-05-15  Malcolm Purvis  <malcolmp@xemacs.org>
+
+	* event-gtk.c:
+	* event-gtk.c (gtk_event_to_emacs_event):
+	* menubar-gtk.c:
+	* menubar-gtk.c (gtk_xemacs_menubar_class_init):
+	* menubar-gtk.c (gtk_xemacs_menubar_size_request):
+	* menubar-gtk.c (gtk_xemacs_accel_label_get_type):
+	* menubar-gtk.c (gtk_xemacs_set_accel_keys):
+	* menubar-gtk.c (__activate_menu):
+	* menubar-gtk.c (convert_underscores):
+	* menubar-gtk.c (remove_underscores):
+	* menubar-gtk.c (menu_convert):
+	* menubar-gtk.c (menu_descriptor_to_widget_1):
+	* menubar-gtk.c (menu_descriptor_to_widget):
+	* menubar-gtk.c (menu_can_reuse_widget):
+	* menubar-gtk.c (menu_create_menubar):
+	* menubar-gtk.c (gtk_popup_menu):
+	* menubar-gtk.c (Fgtk_build_xemacs_menu):
+
+	Added support for Gtk menu bar and menu item mnemonics.
+
 2004-05-10  Jerry James  <james@xemacs.org>
 
 	* config.h.in: Add HAVE_LTDL.
--- a/src/event-gtk.c	Fri May 14 21:50:44 2004 +0000
+++ b/src/event-gtk.c	Sat May 15 07:31:49 2004 +0000
@@ -58,6 +58,10 @@
 #include "dragdrop.h"
 #endif
 
+#ifdef HAVE_MENUBARS
+# include "menubar.h"
+#endif
+
 #if defined (HAVE_OFFIX_DND)
 #include "offix.h"
 #endif
@@ -1326,6 +1330,22 @@
 	    GdkEventKey *key_event = &gdk_event->key;
 	    Lisp_Object keysym;
 
+#ifdef HAVE_MENUBARS
+	    /* If the user wants see if the event is a menu bar accelerator.
+	       The process of checking absorbs the event and starts menu
+	       processing so send a null event into XEmacs to make sure it
+	       does nothing.
+	    */
+	    if (!NILP (Vmenu_accelerator_enabled)
+		&& gtk_accel_groups_activate(GTK_OBJECT (FRAME_GTK_SHELL_WIDGET(frame)),
+					     key_event->keyval,
+					     (GdkModifierType) *state))
+	      {
+		zero_event(emacs_event);
+		return 1;
+	      }
+#endif
+
 	    /* This used to compute the frame from the given X window and
 	       store it here, but we really don't care about the frame. */
 	    emacs_event->channel = DEVICE_CONSOLE (d);
--- a/src/menubar-gtk.c	Fri May 14 21:50:44 2004 +0000
+++ b/src/menubar-gtk.c	Sat May 15 07:31:49 2004 +0000
@@ -1,4 +1,4 @@
-/* Implements an elisp-programmable menubar -- X interface.
+/* Implements an elisp-programmable menubar -- Gtk interface.
    Copyright (C) 1993, 1994 Free Software Foundation, Inc.
    Copyright (C) 1995 Tinker Systems and INS Engineering Corp.
    Copyright (C) 2002, 2003 Ben Wing.
@@ -49,7 +49,7 @@
 #define SUBMENU_TYPE	1
 #define POPUP_TYPE	2
 
-static GtkWidget *menu_descriptor_to_widget_1 (Lisp_Object descr);
+static GtkWidget *menu_descriptor_to_widget_1 (Lisp_Object descr, GtkAccelGroup* accel_group);
 
 #define FRAME_GTK_MENUBAR_DATA(f) (FRAME_GTK_DATA (f)->menubar_data)
 #define XFRAME_GTK_MENUBAR_DATA_LASTBUFF(f) XCAR (FRAME_GTK_MENUBAR_DATA (f))
@@ -113,7 +113,7 @@
   return xemacs_menubar_type;
 }
 
-static GtkWidgetClass *parent_class;
+static GtkWidgetClass *menubar_parent_class;
 
 static void
 gtk_xemacs_menubar_class_init	(GtkXEmacsMenubarClass *klass)
@@ -121,7 +121,7 @@
   GtkWidgetClass *widget_class;
 
   widget_class = (GtkWidgetClass*) klass;
-  parent_class = (GtkWidgetClass *) gtk_type_class (gtk_menu_bar_get_type ());
+  menubar_parent_class = (GtkWidgetClass *) gtk_type_class (gtk_menu_bar_get_type ());
 
   widget_class->size_request = gtk_xemacs_menubar_size_request;
 }
@@ -137,7 +137,7 @@
   GtkXEmacsMenubar *x = GTK_XEMACS_MENUBAR (widget);
   GtkRequisition frame_size;
 
-  parent_class->size_request (widget, requisition);
+  menubar_parent_class->size_request (widget, requisition);
 
   /* #### BILL!
   ** We should really only do this if the menu has not been detached!
@@ -160,6 +160,117 @@
   return (GTK_WIDGET (menubar));
 }
 
+/*
+ * Label with XEmacs accelerator character support.
+ *
+ * The default interfaces to GtkAccelLabel does not understand XEmacs
+ * keystroke printing conventions, nor is it convenient in the places where is
+ * it needed.  This subclass provides an alternative interface more suited to
+ * XEmacs needs but does not add new functionality.
+ */
+#define GTK_TYPE_XEMACS_ACCEL_LABEL	       (gtk_xemacs_accel_label_get_type ())
+#define GTK_XEMACS_ACCEL_LABEL(obj)	       (GTK_CHECK_CAST ((obj), GTK_TYPE_ACCEL_LABEL, GtkXEmacsAccelLabel))
+#define GTK_XEMACS_ACCEL_LABEL_CLASS(klass)    (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_ACCEL_LABEL, GtkXEmacsAccelLabelClass))
+#define GTK_IS_XEMACS_ACCEL_LABEL(obj)	       (GTK_CHECK_TYPE ((obj), GTK_TYPE_XEMACS_ACCEL_LABEL))
+#define GTK_IS_XEMACS_ACCEL_LABEL_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_XEMACS_ACCEL_LABEL))
+
+typedef struct _GtkXEmacsAccelLabel	    GtkXEmacsAccelLabel;
+typedef struct _GtkXEmacsAccelLabelClass  GtkXEmacsAccelLabelClass;
+
+/* Instance structure. No additional fields required. */
+struct _GtkXEmacsAccelLabel
+{
+  GtkAccelLabel label;
+};
+
+/* Class structure. No additional fields required. */
+struct _GtkXEmacsAccelLabelClass
+{
+  GtkAccelLabelClass	 parent_class;
+};
+
+static GtkType	  gtk_xemacs_accel_label_get_type(void);
+static GtkWidget* gtk_xemacs_accel_label_new(const gchar *string);
+static void       gtk_xemacs_set_accel_keys(GtkXEmacsAccelLabel* l,
+				       Lisp_Object keys);
+static void       gtk_xemacs_accel_label_class_init(GtkXEmacsAccelLabelClass *klass);
+static void       gtk_xemacs_accel_label_init(GtkXEmacsAccelLabel *xemacs);
+
+static GtkType
+gtk_xemacs_accel_label_get_type(void)
+{
+  static GtkType xemacs_accel_label_type = 0;
+
+  if (!xemacs_accel_label_type)
+    {
+      static const GtkTypeInfo xemacs_accel_label_info =
+      {
+	"GtkXEmacsAccelLabel",
+	sizeof (GtkXEmacsAccelLabel),
+	sizeof (GtkXEmacsAccelLabelClass),
+	(GtkClassInitFunc) gtk_xemacs_accel_label_class_init,
+	(GtkObjectInitFunc) gtk_xemacs_accel_label_init,
+	/* reserved_1 */ NULL,
+        /* reserved_2 */ NULL,
+        (GtkClassInitFunc) NULL,
+      };
+
+      xemacs_accel_label_type = gtk_type_unique (gtk_accel_label_get_type(), &xemacs_accel_label_info);
+    }
+
+  return xemacs_accel_label_type;
+}
+
+static void
+gtk_xemacs_accel_label_class_init(GtkXEmacsAccelLabelClass *klass)
+{
+  /* Nothing to do. */
+}
+
+static void
+gtk_xemacs_accel_label_init(GtkXEmacsAccelLabel *xemacs)
+{
+  /* Nothing to do. */
+}
+
+static GtkWidget*
+gtk_xemacs_accel_label_new (const gchar *string)
+{
+  GtkXEmacsAccelLabel *xemacs_accel_label;
+  
+  xemacs_accel_label = (GtkXEmacsAccelLabel*) gtk_type_new (GTK_TYPE_XEMACS_ACCEL_LABEL);
+  
+  if (string && *string)
+    gtk_label_set_text (GTK_LABEL (xemacs_accel_label), string);
+  
+  return GTK_WIDGET (xemacs_accel_label);
+}
+
+/* Make the string <keys> the accelerator string for the label. */
+static void
+gtk_xemacs_set_accel_keys(GtkXEmacsAccelLabel* l, Lisp_Object keys)
+{
+  g_return_if_fail (l != NULL);
+  g_return_if_fail (GTK_IS_XEMACS_ACCEL_LABEL (l));
+
+  /* Disable the standard way of finding the accelerator string for the
+     label. */
+  gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL(l), NULL);
+
+  /* Set the string straight from the object. */
+  if (STRINGP (keys) && XSTRING_LENGTH (keys))
+    {
+      C_STRING_TO_EXTERNAL_MALLOC(XSTRING_DATA (keys),
+				  l->label.accel_string,
+				  Qctext);
+    }
+  else
+    {
+      /* l->label.accel_string = NULL;*/
+    }
+}
+
+
 /* We now return you to your regularly scheduled menus... */
 
 int dockable_menubar;
@@ -320,7 +431,8 @@
 	}
       else
 	{
-	  next = menu_descriptor_to_widget_1 (child);
+	  next = menu_descriptor_to_widget_1 (child,
+					      gtk_menu_ensure_uline_accel_group (GTK_MENU (item->submenu)));
 	}
 
       if (!next)
@@ -355,10 +467,66 @@
     }
 }
 
+/* Convert the XEmacs menu accelerator representation to Gtk mnemonic form. If
+  no accelerator has been provided, put one at the start of the string (this
+  mirrors the behaviour under X).  This algorithm is also found in
+  dialog-gtk.el:gtk-popup-convert-underscores.
+*/
 static char *
-remove_underscores(const Ibyte* name)
+convert_underscores(const Ibyte *name)
 {
-  char *rval = (char*) xmalloc_and_zero (strlen((char*) name) + 1);
+  char *rval;
+  int i,j;
+  int found_accel = FALSE;
+  int underscores = 0;
+
+  for (i = 0; name[i]; ++i)
+    if (name[i] == '%' && name[i+1] == '_')
+      {
+	found_accel = TRUE;
+      }
+    else if (name[i] == '_')
+      {
+	underscores++;
+      }
+
+  /* Allocate space for the original string, plus zero byte plus extra space
+     for all quoted underscores plus possible additional leading accelerator. */
+  rval = (char*) xmalloc_and_zero (qxestrlen(name) + 1 + underscores
+				   + (found_accel ? 0 : 1));
+
+  if (!found_accel)
+    rval[0] = '_';
+
+  for (i = 0, j = (found_accel ? 0 : 1); name[i]; i++)
+    {
+      if (name[i]=='%')
+	{
+	  i++;
+	  if (!(name[i]))
+	    continue;
+	  
+	  if ((name[i] != '_') && (name[i] != '%'))
+	    i--;
+
+	  found_accel = TRUE;
+	}
+      else if (name[i] == '_')
+	{
+	  rval[j++] = '_';
+	}
+
+      rval[j++] = name[i];
+    }
+
+  return rval;
+}
+
+/* Remove the XEmacs menu accellerator representation from a string. */
+static char *
+remove_underscores(const Ibyte *name)
+{
+  char *rval = (char*) xmalloc_and_zero (qxestrlen(name) + 1);
   int i,j;
 
   for (i = 0, j = 0; name[i]; i++)
@@ -368,7 +536,9 @@
 	if (!(name[i]))
 	  continue;
 
-	if ((name[i] == '_'))
+	if ((name[i] != '_') && (name[i] != '%'))
+	  i--;
+	else
 	  continue;
       }
       rval[j++] = name[i];
@@ -381,7 +551,8 @@
    DESCR is either a list (meaning a submenu), a vector, or nil (if
    you include a :filter keyword) */
 static GtkWidget *
-menu_convert (Lisp_Object desc, GtkWidget *reuse)
+menu_convert (Lisp_Object desc, GtkWidget *reuse,
+	      GtkAccelGroup* menubar_accel_group)
 {
   GtkWidget *menu_item = NULL;
   GtkWidget *submenu = NULL;
@@ -398,8 +569,23 @@
 
       if (!reuse)
 	{
-	  char *temp_menu_name = remove_underscores (XSTRING_DATA (XCAR (desc)));
-	  menu_item = gtk_menu_item_new_with_label (temp_menu_name);
+	  char *temp_menu_name = convert_underscores (XSTRING_DATA (XCAR (desc)));
+	  GtkWidget* accel_label = gtk_xemacs_accel_label_new(NULL);
+	  guint accel_key;
+
+	  gtk_misc_set_alignment (GTK_MISC (accel_label), 0.0, 0.5);
+	  accel_key = gtk_label_parse_uline (GTK_LABEL (accel_label), temp_menu_name);
+
+	  menu_item = gtk_menu_item_new ();
+	  gtk_container_add (GTK_CONTAINER (menu_item), accel_label);
+	  gtk_widget_show (accel_label);
+
+	  if (menubar_accel_group)
+	    gtk_widget_add_accelerator (menu_item,
+					"activate_item",
+					menubar_accel_group,
+					accel_key, GDK_MOD1_MASK,
+					GTK_ACCEL_LOCKED);
 	  free (temp_menu_name);
 	}
       else
@@ -583,7 +769,7 @@
    It is only called from menu_item_descriptor_to_widget_value, which
    prohibits GC. */
 static GtkWidget *
-menu_descriptor_to_widget_1 (Lisp_Object descr)
+menu_descriptor_to_widget_1 (Lisp_Object descr, GtkAccelGroup* accel_group)
 {
   if (STRINGP (descr))
     {
@@ -596,7 +782,7 @@
   else if (LISTP (descr))
     {
       /* It is a submenu */
-      return (menu_convert (descr, NULL));
+      return (menu_convert (descr, NULL, accel_group));
     }
   else if (VECTORP (descr))
     {
@@ -617,6 +803,7 @@
       int plist_p;
       int selected_spec = 0, included_spec = 0;
       GtkWidget *widget = NULL;
+      guint accel_key;
 
       if (length < 2)
 	sferror ("button descriptors must be at least 2 long", descr);
@@ -712,8 +899,9 @@
 	      sprintf ((char*) label_buffer, "%s ", XSTRING_DATA (name));
 	    }
 
-	  temp_label = remove_underscores (label_buffer);
-	  main_label = gtk_accel_label_new (temp_label);
+	  temp_label = convert_underscores (label_buffer);
+	  main_label = gtk_xemacs_accel_label_new (NULL);
+	  accel_key = gtk_label_parse_uline (GTK_LABEL (main_label), temp_label);
 	  free (temp_label);
 	}
 
@@ -837,42 +1025,23 @@
 			  GTK_SIGNAL_FUNC (__generic_button_callback),
 			  LISP_TO_VOID (callback));
 
-      /* We cheat here... GtkAccelLabel usually builds its
-	 `accel_string' from the widget it is attached to, but we do
-	 not want to go thru the overhead of converting our nice
-	 string back into the modifier + key format that requires,
-	 just so that they can convert it back into a (possibly
-	 different/wrong) string
-
-	 We set the label string manually, and things should 'just
-	 work'
-
-	 In an ideal world we would just subclass GtkLabel ourselves,
-	 but I have known for a very long time that this is not an
-	 ideal world.
-
-	 #### Should do menu shortcuts `correctly' one of these days.
+      /* Now that all the information about the menu item is know, set the
+	 remaining properties.
       */
       
       if (main_label)
 	{
-	  GtkAccelLabel *l = GTK_ACCEL_LABEL (main_label);
-
 	  gtk_container_add (GTK_CONTAINER (widget), main_label);
 
-	  gtk_accel_label_set_accel_widget (l, NULL);
-	  gtk_misc_set_alignment (GTK_MISC (l), 0.0, 0.5);
+	  gtk_misc_set_alignment (GTK_MISC (main_label), 0.0, 0.5);
+	  gtk_xemacs_set_accel_keys(GTK_XEMACS_ACCEL_LABEL(main_label), keys);
 
-	  if (STRINGP (keys) && XSTRING_LENGTH (keys))
-	    {
-	      C_STRING_TO_EXTERNAL_MALLOC (XSTRING_DATA (keys), l->accel_string,
-					   Qctext);
-	      stderr_out ("accel: %s\n", l->accel_string);
-	    }
-	  else
-	    {
-	      /* l->accel_string = ""; */
-	    }
+	  if (accel_group)
+	    gtk_widget_add_accelerator (widget,
+					"activate_item",
+					accel_group,
+					accel_key, 0,
+					GTK_ACCEL_LOCKED);
 	}
 
       return (widget);
@@ -885,13 +1054,13 @@
 }
 
 static GtkWidget *
-menu_descriptor_to_widget (Lisp_Object descr)
+menu_descriptor_to_widget (Lisp_Object descr, GtkAccelGroup* accel_group)
 {
   GtkWidget *rval = NULL;
   int count = begin_gc_forbidden ();
 
   /* Cannot GC from here on out... */
-  rval = menu_descriptor_to_widget_1 (descr);
+  rval = menu_descriptor_to_widget_1 (descr, accel_group);
   unbind_to (count);
   return (rval);
   
@@ -901,23 +1070,24 @@
 menu_can_reuse_widget (GtkWidget *child, const Ibyte *label)
 {
   /* Everything up at the top level was done using
-  ** gtk_menu_item_new_with_label(), but we still double check to make
+  ** gtk_xemacs_accel_label_new(), but we still double check to make
   ** sure we don't seriously foobar ourselves.
   */
-  char *temp_label = NULL;
-  gpointer possible_child = g_list_nth_data (gtk_container_children (GTK_CONTAINER (child)), 0);
+  gpointer possible_child =
+    g_list_nth_data (gtk_container_children (GTK_CONTAINER (child)), 0);
+  gboolean ret_val = FALSE;
 
   if (possible_child && GTK_IS_LABEL (possible_child))
     {
-      if (!temp_label) temp_label = remove_underscores (label);
+      char *temp_label = remove_underscores (label);
+
       if (!strcmp (GTK_LABEL (possible_child)->label, temp_label))
-	{
-	  free (temp_label);
-	  return (TRUE);
-	}
+	ret_val = TRUE;
+
+      free (temp_label);
     }
-  if (temp_label) free (temp_label);
-  return (FALSE);
+
+  return ret_val;
 }
 
 /* Converts a menubar description into a GtkMenuBar... a menubar is a
@@ -933,6 +1103,7 @@
   GtkWidget *menubar = FRAME_GTK_MENUBAR_WIDGET (f);
   GUI_ID id = (GUI_ID) gtk_object_get_data (GTK_OBJECT (menubar), XEMACS_MENU_GUIID_TAG);
   guint menu_position = 0;
+  GtkAccelGroup *menubar_accel_group;
 
   /* Remove any existing protection for old menu items */
   ungcpro_popup_callbacks (id);
@@ -940,6 +1111,8 @@
   /* GCPRO the whole damn thing */
   gcpro_popup_callbacks (id, descr);
 
+  menubar_accel_group = gtk_accel_group_new();
+
   EXTERNAL_LIST_LOOP (tail, value)
     {
       gpointer current_child = g_list_nth_data (GTK_MENU_SHELL (menubar)->children, menu_position);
@@ -957,7 +1130,7 @@
 	  /* It is a button description */
 	  GtkWidget *item;
 
-	  item = menu_descriptor_to_widget (item_descr);
+	  item = menu_descriptor_to_widget (item_descr, menubar_accel_group);
 	  gtk_widget_set_name (item, "XEmacsMenuButton");
 
 	  if (!item)
@@ -979,12 +1152,13 @@
 	  if (current_child && menu_can_reuse_widget (GTK_WIDGET (current_child),
 						      XSTRING_DATA (XCAR (item_descr))))
 	    {
-	      widget = menu_convert (item_descr, GTK_WIDGET (current_child));
+	      widget = menu_convert (item_descr, GTK_WIDGET (current_child),
+				     menubar_accel_group);
 	      reused_p = TRUE;
 	    }
 	  else
 	    {
-	      widget = menu_convert (item_descr, NULL);
+	      widget = menu_convert (item_descr, NULL, menubar_accel_group);
 	      if (current_child) gtk_widget_destroy (GTK_WIDGET (current_child));
 	      gtk_menu_bar_insert (GTK_MENU_BAR (menubar), widget, menu_position);
 	    }
@@ -1023,6 +1197,10 @@
 	  }
       }
   }
+
+  /* Attach the new accelerator group to the frame. */
+  gtk_window_add_accel_group (GTK_WINDOW (FRAME_GTK_SHELL_WIDGET(f)),
+			      menubar_accel_group);
 }
 
 
@@ -1246,7 +1424,7 @@
   CHECK_STRING (XCAR (menu_desc));
 
   /* Now lets get down to business... */
-  widget = menu_descriptor_to_widget (menu_desc);
+  widget = menu_descriptor_to_widget (menu_desc, NULL);
   menu = GTK_MENU_ITEM (widget)->submenu;
   gtk_widget_set_name (widget, "XEmacsPopupMenu");
   id = gtk_object_get_data (GTK_OBJECT (widget), XEMACS_MENU_GUIID_TAG);
@@ -1290,7 +1468,7 @@
 */
        (menu))
 {
-  GtkWidget *w = menu_descriptor_to_widget (menu);
+  GtkWidget *w = menu_descriptor_to_widget (menu, NULL);
 
   return (w ? build_gtk_object (GTK_OBJECT (w)) : Qnil);
 }
@@ -1333,3 +1511,6 @@
 #endif
   reinit_vars_of_menubar_gtk ();
 }
+
+/*---------------------------------------------------------------------------*/
+