update.
[chise/xemacs-chise.git.1] / src / menubar-gtk.c
index 8d2dac9..387e150 100644 (file)
@@ -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) 1993, 1994 Free Software Foundation, Inc.
    Copyright (C) 1995 Tinker Systems and INS Engineering Corp.
 
@@ -46,7 +46,7 @@ Boston, MA 02111-1307, USA.  */
 #define SUBMENU_TYPE   1
 #define POPUP_TYPE     2
 
 #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_MENUBAR_DATA(frame) ((frame)->menubar_data)
 #define XFRAME_MENUBAR_DATA_LASTBUFF(frame) (XCAR ((frame)->menubar_data))
 
 #define FRAME_MENUBAR_DATA(frame) ((frame)->menubar_data)
 #define XFRAME_MENUBAR_DATA_LASTBUFF(frame) (XCAR ((frame)->menubar_data))
@@ -110,14 +110,14 @@ gtk_xemacs_menubar_get_type (void)
   return xemacs_menubar_type;
 }
 
   return xemacs_menubar_type;
 }
 
-static GtkWidgetClass *parent_class;
+static GtkWidgetClass *menubar_parent_class;
 
 static void gtk_xemacs_menubar_class_init      (GtkXEmacsMenubarClass *klass)
 {
   GtkWidgetClass *widget_class;
 
   widget_class = (GtkWidgetClass*) klass;
 
 static void gtk_xemacs_menubar_class_init      (GtkXEmacsMenubarClass *klass)
 {
   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;
 }
 
   widget_class->size_request = gtk_xemacs_menubar_size_request;
 }
@@ -131,7 +131,7 @@ static void gtk_xemacs_menubar_size_request (GtkWidget *widget, GtkRequisition *
   GtkXEmacsMenubar *x = GTK_XEMACS_MENUBAR (widget);
   GtkRequisition frame_size;
 
   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!
 
   /* #### BILL!
   ** We should really only do this if the menu has not been detached!
@@ -154,6 +154,117 @@ gtk_xemacs_menubar_new (struct frame *f)
   return (GTK_WIDGET (menubar));
 }
 \f
   return (GTK_WIDGET (menubar));
 }
 \f
+/*
+ * 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 = 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;*/
+    }
+}
+\f
+
 /* We now return you to your regularly scheduled menus... */
 
 int dockable_menubar;
 /* We now return you to your regularly scheduled menus... */
 
 int dockable_menubar;
@@ -314,7 +425,8 @@ __activate_menu(GtkMenuItem *item, gpointer user_data)
        }
       else
        {
        }
       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)
        }
 
       if (!next)
@@ -349,6 +461,63 @@ __kill_stupid_gtk_timer (GtkObject *obj, gpointer user_data)
     }
 }
 
     }
 }
 
+/* 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 *
+convert_underscores(const char *name)
+{
+  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 = xmalloc_and_zero (strlen(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 char *name)
 {
 static char *
 remove_underscores(const char *name)
 {
@@ -362,7 +531,9 @@ remove_underscores(const char *name)
        if (!(name[i]))
          continue;
 
        if (!(name[i]))
          continue;
 
-       if ((name[i] == '_'))
+       if ((name[i] != '_') && (name[i] != '%'))
+         i--;
+       else
          continue;
       }
       rval[j++] = name[i];
          continue;
       }
       rval[j++] = name[i];
@@ -375,7 +546,8 @@ remove_underscores(const char *name)
    DESCR is either a list (meaning a submenu), a vector, or nil (if
    you include a :filter keyword) */
 static GtkWidget *
    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;
 {
   GtkWidget *menu_item = NULL;
   GtkWidget *submenu = NULL;
@@ -392,8 +564,23 @@ menu_convert (Lisp_Object desc, GtkWidget *reuse)
 
       if (!reuse)
        {
 
       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
          free (temp_menu_name);
        }
       else
@@ -542,28 +729,13 @@ menu_convert (Lisp_Object desc, GtkWidget *reuse)
   return (menu_item);
 }
 
   return (menu_item);
 }
 
-static struct frame *
-__get_channel (GtkWidget *w)
-{
-  struct frame *f = NULL;
-
-  for (; w; w = w->parent)
-    {
-      if ((f = (struct frame *) gtk_object_get_data (GTK_OBJECT (w), "xemacs::frame")))
-       return (f);
-    }
-
-  return (selected_frame());
-}
-
-
 /* Called whenever a button, radio, or toggle is selected in the menu */
 static void
 __generic_button_callback (GtkMenuItem *item, gpointer user_data)
 {
   Lisp_Object callback, function, data, channel;
 
 /* Called whenever a button, radio, or toggle is selected in the menu */
 static void
 __generic_button_callback (GtkMenuItem *item, gpointer user_data)
 {
   Lisp_Object callback, function, data, channel;
 
-  XSETFRAME (channel, __get_channel (GTK_WIDGET (item)));
+  XSETFRAME (channel, gtk_widget_to_frame (GTK_WIDGET (item)));
 
   VOID_TO_LISP (callback, user_data);
 
 
   VOID_TO_LISP (callback, user_data);
 
@@ -576,7 +748,8 @@ __generic_button_callback (GtkMenuItem *item, gpointer user_data)
 /* This function cannot GC.
    It is only called from menu_item_descriptor_to_widget_value, which
    prohibits GC. */
 /* This function cannot GC.
    It is only called from menu_item_descriptor_to_widget_value, which
    prohibits GC. */
-static GtkWidget *menu_descriptor_to_widget_1 (Lisp_Object descr)
+static GtkWidget *
+menu_descriptor_to_widget_1 (Lisp_Object descr, GtkAccelGroup* accel_group)
 {
   if (STRINGP (descr))
     {
 {
   if (STRINGP (descr))
     {
@@ -589,7 +762,7 @@ static GtkWidget *menu_descriptor_to_widget_1 (Lisp_Object descr)
   else if (LISTP (descr))
     {
       /* It is a submenu */
   else if (LISTP (descr))
     {
       /* It is a submenu */
-      return (menu_convert (descr, NULL));
+      return (menu_convert (descr, NULL, accel_group));
     }
   else if (VECTORP (descr))
     {
     }
   else if (VECTORP (descr))
     {
@@ -610,6 +783,7 @@ static GtkWidget *menu_descriptor_to_widget_1 (Lisp_Object descr)
       int plist_p;
       int selected_spec = 0, included_spec = 0;
       GtkWidget *widget = NULL;
       int plist_p;
       int selected_spec = 0, included_spec = 0;
       GtkWidget *widget = NULL;
+      guint accel_key;
 
       if (length < 2)
        signal_simple_error ("button descriptors must be at least 2 long", descr);
 
       if (length < 2)
        signal_simple_error ("button descriptors must be at least 2 long", descr);
@@ -705,8 +879,9 @@ static GtkWidget *menu_descriptor_to_widget_1 (Lisp_Object descr)
              sprintf (label_buffer, "%s ", XSTRING_DATA (name));
            }
 
              sprintf (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);
        }
 
          free (temp_label);
        }
 
@@ -822,36 +997,23 @@ static GtkWidget *menu_descriptor_to_widget_1 (Lisp_Object descr)
                          GTK_SIGNAL_FUNC (__generic_button_callback),
                          LISP_TO_VOID (callback));
 
                          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)
        {
       */
       
       if (main_label)
        {
-         GtkAccelLabel *l = GTK_ACCEL_LABEL (main_label);
-
          gtk_container_add (GTK_CONTAINER (widget), 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))
-           {
-             l->accel_string = g_strdup (XSTRING_DATA (keys));
-           }
+         if (accel_group)
+           gtk_widget_add_accelerator (widget,
+                                       "activate_item",
+                                       accel_group,
+                                       accel_key, 0,
+                                       GTK_ACCEL_LOCKED);
        }
 
       return (widget);
        }
 
       return (widget);
@@ -859,11 +1021,12 @@ static GtkWidget *menu_descriptor_to_widget_1 (Lisp_Object descr)
   else
     {
       return (NULL);
   else
     {
       return (NULL);
-      /* abort (); ???? */
+      /* ABORT (); ???? */
     }
 }
 
     }
 }
 
-static GtkWidget *menu_descriptor_to_widget (Lisp_Object descr)
+static GtkWidget *
+menu_descriptor_to_widget (Lisp_Object descr, GtkAccelGroup* accel_group)
 {
   int count = specpdl_depth ();
   GtkWidget *rval = NULL;
 {
   int count = specpdl_depth ();
   GtkWidget *rval = NULL;
@@ -873,7 +1036,7 @@ static GtkWidget *menu_descriptor_to_widget (Lisp_Object descr)
   gc_currently_forbidden = 1;
 
   /* Cannot GC from here on out... */
   gc_currently_forbidden = 1;
 
   /* 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, Qnil);
   return (rval);
   
   unbind_to (count, Qnil);
   return (rval);
   
@@ -883,23 +1046,24 @@ static gboolean
 menu_can_reuse_widget (GtkWidget *child, const char *label)
 {
   /* Everything up at the top level was done using
 menu_can_reuse_widget (GtkWidget *child, const char *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.
   */
   ** 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 (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))
       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
 }
 
 /* Converts a menubar description into a GtkMenuBar... a menubar is a
@@ -915,6 +1079,7 @@ menu_create_menubar (struct frame *f, Lisp_Object descr)
   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;
   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);
 
   /* Remove any existing protection for old menu items */
   ungcpro_popup_callbacks (id);
@@ -922,6 +1087,8 @@ menu_create_menubar (struct frame *f, Lisp_Object descr)
   /* GCPRO the whole damn thing */
   gcpro_popup_callbacks (id, descr);
 
   /* 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);
   EXTERNAL_LIST_LOOP (tail, value)
     {
       gpointer current_child = g_list_nth_data (GTK_MENU_SHELL (menubar)->children, menu_position);
@@ -939,7 +1106,7 @@ menu_create_menubar (struct frame *f, Lisp_Object descr)
          /* It is a button description */
          GtkWidget *item;
 
          /* 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)
          gtk_widget_set_name (item, "XEmacsMenuButton");
 
          if (!item)
@@ -961,12 +1128,13 @@ menu_create_menubar (struct frame *f, Lisp_Object descr)
          if (current_child && menu_can_reuse_widget (GTK_WIDGET (current_child),
                                                      XSTRING_DATA (XCAR (item_descr))))
            {
          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
            {
              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);
            }
              if (current_child) gtk_widget_destroy (GTK_WIDGET (current_child));
              gtk_menu_bar_insert (GTK_MENU_BAR (menubar), widget, menu_position);
            }
@@ -1005,6 +1173,10 @@ menu_create_menubar (struct frame *f, Lisp_Object descr)
          }
       }
   }
          }
       }
   }
+
+  /* Attach the new accelerator group to the frame. */
+  gtk_window_add_accel_group (GTK_WINDOW (FRAME_GTK_SHELL_WIDGET(f)),
+                             menubar_accel_group);
 }
 
 \f
 }
 
 \f
@@ -1216,11 +1388,21 @@ static void
 gtk_popup_menu (Lisp_Object menu_desc, Lisp_Object event)
 {
   struct Lisp_Event *eev = NULL;
 gtk_popup_menu (Lisp_Object menu_desc, Lisp_Object event)
 {
   struct Lisp_Event *eev = NULL;
-  GtkWidget *widget = menu_descriptor_to_widget (menu_desc);
-  GtkWidget *menu = GTK_MENU_ITEM (widget)->submenu;
-  gpointer id = gtk_object_get_data (GTK_OBJECT (widget), XEMACS_MENU_GUIID_TAG);
-
+  GtkWidget *widget = NULL;
+  GtkWidget *menu = NULL;
+  gpointer id = NULL;
+
+  /* Do basic error checking first... */
+  if (SYMBOLP (menu_desc))
+    menu_desc = Fsymbol_value (menu_desc);
+  CHECK_CONS (menu_desc);
+  CHECK_STRING (XCAR (menu_desc));
+
+  /* Now lets get down to business... */
+  widget = menu_descriptor_to_widget (menu_desc, NULL);
+  menu = GTK_MENU_ITEM (widget)->submenu;
   gtk_widget_set_name (widget, "XEmacsPopupMenu");
   gtk_widget_set_name (widget, "XEmacsPopupMenu");
+  id = gtk_object_get_data (GTK_OBJECT (widget), XEMACS_MENU_GUIID_TAG);
 
   __activate_menu (GTK_MENU_ITEM (widget), id);
 
 
   __activate_menu (GTK_MENU_ITEM (widget), id);
 
@@ -1261,7 +1443,7 @@ See the definition of `popup-menu' for more information on the format of MENU.
 */
        (menu))
 {
 */
        (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);
 }
 
   return (w ? build_gtk_object (GTK_OBJECT (w)) : Qnil);
 }