+
+static GtkMnemonicHash *
+gtk_menu_shell_get_mnemonic_hash (GtkMenuShell *menu_shell,
+ gboolean create)
+{
+ GtkMenuShellPrivate *private = GTK_MENU_SHELL_GET_PRIVATE (menu_shell);
+
+ if (!private->mnemonic_hash && create)
+ private->mnemonic_hash = _gtk_mnemonic_hash_new ();
+
+ return private->mnemonic_hash;
+}
+
+static void
+menu_shell_add_mnemonic_foreach (guint keyval,
+ GSList *targets,
+ gpointer data)
+{
+ GtkKeyHash *key_hash = data;
+
+ _gtk_key_hash_add_entry (key_hash, keyval, 0, GUINT_TO_POINTER (keyval));
+}
+
+static GtkKeyHash *
+gtk_menu_shell_get_key_hash (GtkMenuShell *menu_shell,
+ gboolean create)
+{
+ GtkMenuShellPrivate *private = GTK_MENU_SHELL_GET_PRIVATE (menu_shell);
+ GtkWidget *widget = GTK_WIDGET (menu_shell);
+
+ if (!private->key_hash && create && gtk_widget_has_screen (widget))
+ {
+ GtkMnemonicHash *mnemonic_hash = gtk_menu_shell_get_mnemonic_hash (menu_shell, FALSE);
+ GdkScreen *screen = gtk_widget_get_screen (widget);
+ GdkKeymap *keymap = gdk_keymap_get_for_display (gdk_screen_get_display (screen));
+
+ if (!mnemonic_hash)
+ return NULL;
+
+ private->key_hash = _gtk_key_hash_new (keymap, NULL);
+
+ _gtk_mnemonic_hash_foreach (mnemonic_hash,
+ menu_shell_add_mnemonic_foreach,
+ private->key_hash);
+ }
+
+ return private->key_hash;
+}
+
+static void
+gtk_menu_shell_reset_key_hash (GtkMenuShell *menu_shell)
+{
+ GtkMenuShellPrivate *private = GTK_MENU_SHELL_GET_PRIVATE (menu_shell);
+
+ if (private->key_hash)
+ {
+ _gtk_key_hash_free (private->key_hash);
+ private->key_hash = NULL;
+ }
+}
+
+static gboolean
+gtk_menu_shell_activate_mnemonic (GtkMenuShell *menu_shell,
+ GdkEventKey *event)
+{
+ GtkMnemonicHash *mnemonic_hash;
+ GtkKeyHash *key_hash;
+ GSList *entries;
+ gboolean result = FALSE;
+
+ mnemonic_hash = gtk_menu_shell_get_mnemonic_hash (menu_shell, FALSE);
+ if (!mnemonic_hash)
+ return FALSE;
+
+ key_hash = gtk_menu_shell_get_key_hash (menu_shell, TRUE);
+ if (!key_hash)
+ return FALSE;
+
+ entries = _gtk_key_hash_lookup (key_hash,
+ event->hardware_keycode,
+ event->state,
+ gtk_accelerator_get_default_mod_mask (),
+ event->group);
+
+ if (entries)
+ result = _gtk_mnemonic_hash_activate (mnemonic_hash,
+ GPOINTER_TO_UINT (entries->data));
+
+ return result;
+}
+
+void
+_gtk_menu_shell_add_mnemonic (GtkMenuShell *menu_shell,
+ guint keyval,
+ GtkWidget *target)
+{
+ g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell));
+ g_return_if_fail (GTK_IS_WIDGET (target));
+
+ _gtk_mnemonic_hash_add (gtk_menu_shell_get_mnemonic_hash (menu_shell, TRUE),
+ keyval, target);
+ gtk_menu_shell_reset_key_hash (menu_shell);
+}
+
+void
+_gtk_menu_shell_remove_mnemonic (GtkMenuShell *menu_shell,
+ guint keyval,
+ GtkWidget *target)
+{
+ g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell));
+ g_return_if_fail (GTK_IS_WIDGET (target));
+
+ _gtk_mnemonic_hash_remove (gtk_menu_shell_get_mnemonic_hash (menu_shell, TRUE),
+ keyval, target);
+ gtk_menu_shell_reset_key_hash (menu_shell);
+}
+
+/**
+ * gtk_menu_shell_get_take_focus:
+ * @menu_shell: a #GtkMenuShell
+ *
+ * Returns %TRUE if the menu shell will take the keyboard focus on popup.
+ *
+ * Returns: %TRUE if the menu shell will take the keyboard focus on popup.
+ *
+ * Since: 2.8
+ **/
+gboolean
+gtk_menu_shell_get_take_focus (GtkMenuShell *menu_shell)
+{
+ GtkMenuShellPrivate *priv;
+
+ g_return_val_if_fail (GTK_IS_MENU_SHELL (menu_shell), FALSE);
+
+ priv = GTK_MENU_SHELL_GET_PRIVATE (menu_shell);
+
+ return priv->take_focus;
+}
+
+/**
+ * gtk_menu_shell_set_take_focus:
+ * @menu_shell: a #GtkMenuShell
+ * @take_focus: %TRUE if the menu shell should take the keyboard focus on popup.
+ *
+ * If @take_focus is %TRUE (the default) the menu shell will take the keyboard
+ * focus so that it will receive all keyboard events which is needed to enable
+ * keyboard navigation in menus.
+ *
+ * Setting @take_focus to %FALSE is useful only for special applications
+ * like virtual keyboard implementations which should not take keyboard
+ * focus.
+ *
+ * The @take_focus state of a menu or menu bar is automatically propagated
+ * to submenus whenever a submenu is popped up, so you don't have to worry
+ * about recursively setting it for your entire menu hierarchy. Only when
+ * programmatically picking a submenu and popping it up manually, the
+ * @take_focus property of the submenu needs to be set explicitely.
+ *
+ * Note that setting it to %FALSE has side-effects:
+ *
+ * If the focus is in some other app, it keeps the focus and keynav in
+ * the menu doesn't work. Consequently, keynav on the menu will only
+ * work if the focus is on some toplevel owned by the onscreen keyboard.
+ *
+ * To avoid confusing the user, menus with @take_focus set to %FALSE
+ * should not display mnemonics or accelerators, since it cannot be
+ * guaranteed that they will work.
+ *
+ * See also gdk_keyboard_grab()
+ *
+ * Since: 2.8
+ **/
+void
+gtk_menu_shell_set_take_focus (GtkMenuShell *menu_shell,
+ gboolean take_focus)
+{
+ GtkMenuShellPrivate *priv;
+
+ g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell));
+
+ priv = GTK_MENU_SHELL_GET_PRIVATE (menu_shell);
+
+ if (priv->take_focus != take_focus)
+ {
+ priv->take_focus = take_focus;
+ g_object_notify (G_OBJECT (menu_shell), "take-focus");
+ }
+}
+
+#define __GTK_MENU_SHELL_C__
+#include "gtkaliasdef.c"