diff --git a/examples/bloatpad.c b/examples/bloatpad.c
index 93b9b6c..b49c5c5 100644
--- a/examples/bloatpad.c
+++ b/examples/bloatpad.c
@@ -72,6 +72,7 @@ new_window (GApplication *app,
   GtkWidget *window, *grid, *scrolled, *view;
 
   window = gtk_application_window_new (GTK_APPLICATION (app));
+  gtk_application_window_set_show_menubar (window, FALSE);
   gtk_window_set_default_size ((GtkWindow*)window, 640, 480);
   g_action_map_add_action_entries (G_ACTION_MAP (window), win_entries, G_N_ELEMENTS (win_entries), window);
   gtk_window_set_title (GTK_WINDOW (window), "Bloatpad");
@@ -195,7 +196,7 @@ bloat_pad_startup (GApplication *application)
                                "      <item label='_About Bloatpad' action='app.about'/>"
                                "    </section>"
                                "    <section>"
-                               "      <item label='_Quit' action='app.quit'/>"
+                               "      <item label='_Quit' action='app.quit' accel='&lt;Control&gt;q'/>"
                                "    </section>"
                                "  </menu>"
                                "  <menu id='menubar'>"
@@ -254,6 +255,8 @@ main (int argc, char **argv)
   int status;
 
   bloat_pad = bloat_pad_new ();
+  gtk_application_add_accelerator (GTK_APPLICATION (bloat_pad),
+                                   "F11", "win.fullscreen", NULL);
   status = g_application_run (G_APPLICATION (bloat_pad), argc, argv);
   g_object_unref (bloat_pad);
 
diff --git a/gtk/gtkapplication.c b/gtk/gtkapplication.c
index faf9901..1bd059b 100644
--- a/gtk/gtkapplication.c
+++ b/gtk/gtkapplication.c
@@ -31,6 +31,7 @@
 #include "gtkmarshalers.h"
 #include "gtkmain.h"
 #include "gtkwindow.h"
+#include "gtkaccelmap.h"
 
 #include <gdk/gdk.h>
 #ifdef GDK_WINDOWING_X11
@@ -190,10 +191,88 @@ gtk_application_window_removed (GtkApplication *application,
 }
 
 static void
+extract_accel_from_menu_item (GMenuModel     *model,
+                              gint            item,
+                              GtkApplication *app)
+{
+  GMenuAttributeIter *iter;
+  const gchar *key;
+  GVariant *value;
+  const gchar *accel = NULL;
+  const gchar *action = NULL;
+  GVariant *target = NULL;
+
+  iter = g_menu_model_iterate_item_attributes (model, item);
+  while (g_menu_attribute_iter_get_next (iter, &key, &value))
+    {
+      if (g_str_equal (key, "action") && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
+        action = g_variant_get_string (value, NULL);
+      else if (g_str_equal (key, "accel") && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
+        accel = g_variant_get_string (value, NULL);
+      else if (g_str_equal (key, "target"))
+        target = g_variant_ref (value);
+      g_variant_unref (value);
+    }
+  g_object_unref (iter);
+
+  if (accel && action)
+    gtk_application_add_accelerator (app, accel, action, target);
+
+  if (target)
+    g_variant_unref (target);
+}
+
+static void
+extract_accels_from_menu (GMenuModel     *model,
+                          GtkApplication *app)
+{
+  gint i;
+  GMenuLinkIter *iter;
+  const gchar *key;
+  GMenuModel *m;
+
+  for (i = 0; i < g_menu_model_get_n_items (model); i++)
+    {
+      extract_accel_from_menu_item (model, i, app);
+
+      iter = g_menu_model_iterate_item_links (model, i);
+      while (g_menu_link_iter_get_next (iter, &key, &m))
+        {
+          extract_accels_from_menu (m, app);
+          g_object_unref (m);
+        }
+      g_object_unref (iter);
+    }
+}
+
+static void
+gtk_application_notify (GObject    *object,
+                        GParamSpec *pspec)
+{
+  if (strcmp (pspec->name, "app-menu") == 0 ||
+      strcmp (pspec->name, "menubar") == 0)
+    {
+      GMenuModel *model;
+      g_object_get (object, pspec->name, &model, NULL);
+      if (model)
+        {
+          extract_accels_from_menu (model, GTK_APPLICATION (object));
+          g_object_unref (model);
+        }
+    }
+
+  if (G_OBJECT_CLASS (gtk_application_parent_class)->notify)
+    G_OBJECT_CLASS (gtk_application_parent_class)->notify (object, pspec);
+}
+
+static void
 gtk_application_class_init (GtkApplicationClass *class)
 {
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
   GApplicationClass *application_class = G_APPLICATION_CLASS (class);
 
+  object_class->notify = gtk_application_notify;
+
   application_class->add_platform_data = gtk_application_add_platform_data;
   application_class->before_emit = gtk_application_before_emit;
   application_class->after_emit = gtk_application_after_emit;
@@ -350,3 +429,75 @@ gtk_application_get_windows (GtkApplication *application)
 
   return application->priv->windows;
 }
+
+/* keep this in sync with gtkmodelmenuitem.c */
+static gchar *
+get_accel_path (const gchar *action_name,
+                GVariant    *parameter)
+{
+  GString *s;
+
+  s = g_string_new ("<Actions>/");
+  g_string_append (s, action_name);
+  if (parameter)
+    {
+      g_string_append_c (s, '/');
+      g_variant_print_string (parameter, s, FALSE);
+    }
+  return g_string_free (s, FALSE);
+}
+
+void
+gtk_application_add_accelerator (GtkApplication *application,
+                                 const gchar    *accelerator,
+                                 const gchar    *action_name,
+                                 GVariant       *parameter)
+{
+  gchar *accel_path;
+  guint accel_key;
+  GdkModifierType accel_mods;
+
+  g_return_if_fail (GTK_IS_APPLICATION (application));
+
+  /* FIXME */
+  _gtk_accel_map_init ();
+
+  gtk_accelerator_parse (accelerator, &accel_key, &accel_mods);
+
+  if (accel_key == 0)
+    {
+      g_warning ("Failed to parse accelerator: '%s'\n", accelerator);
+      return;
+    }
+
+  accel_path = get_accel_path (action_name, parameter);
+
+  if (gtk_accel_map_lookup_entry (accel_path, NULL))
+    gtk_accel_map_change_entry (accel_path, accel_key, accel_mods, TRUE);
+  else
+    gtk_accel_map_add_entry (accel_path, accel_key, accel_mods);
+
+  g_free (accel_path);
+}
+
+void
+gtk_application_remove_accelerator (GtkApplication *application,
+                                    const gchar    *action_name,
+                                    GVariant       *parameter)
+{
+  gchar *accel_path;
+
+  g_return_if_fail (GTK_IS_APPLICATION (application));
+
+  accel_path = get_accel_path (action_name, parameter);
+
+  if (!gtk_accel_map_lookup_entry (accel_path, NULL))
+    {
+      g_warning ("No accelerator found for '%s'\n", accel_path);
+      g_free (accel_path);
+      return;
+    }
+
+  gtk_accel_map_change_entry (accel_path, 0, 0, FALSE);
+  g_free (accel_path);
+}
diff --git a/gtk/gtkapplication.h b/gtk/gtkapplication.h
index 785afac..a75d66c 100644
--- a/gtk/gtkapplication.h
+++ b/gtk/gtkapplication.h
@@ -76,6 +76,13 @@ void             gtk_application_remove_window (GtkApplication    *application,
 
 GList *          gtk_application_get_windows   (GtkApplication    *application);
 
+void             gtk_application_add_accelerator    (GtkApplication  *application,
+                                                     const gchar     *accelerator,
+                                                     const gchar     *action_name,
+                                                     GVariant        *parameter);
+void             gtk_application_remove_accelerator (GtkApplication *application,
+                                                     const gchar    *action_name,
+                                                     GVariant       *parameter);
 
 G_END_DECLS
 
diff --git a/gtk/gtkapplicationwindow.c b/gtk/gtkapplicationwindow.c
index 3577842..86b1b72 100644
--- a/gtk/gtkapplicationwindow.c
+++ b/gtk/gtkapplicationwindow.c
@@ -25,6 +25,8 @@
 
 #include "gtkmodelmenu.h"
 #include "gactionmuxer.h"
+#include "gtkaccelgroup.h"
+#include "gtkaccelmap.h"
 #include "gtkintl.h"
 
 /**
@@ -56,12 +58,32 @@ struct _GtkApplicationWindowPrivate
 {
   GSimpleActionGroup *actions;
   GtkWidget *menubar;
+  GtkAccelGroup *accels;
+  GSList *accel_closures;
 
   GMenu *app_menu_section;
   GMenu *menubar_section;
   gboolean show_menubar;
 };
 
+/* GType boilerplate {{{1 */
+
+static void gtk_application_window_group_iface_init (GActionGroupInterface *iface);
+static void gtk_application_window_map_iface_init (GActionMapInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GtkApplicationWindow, gtk_application_window, GTK_TYPE_WINDOW,
+                         G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_GROUP, gtk_application_window_group_iface_init)
+                         G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_MAP, gtk_application_window_map_iface_init))
+
+enum {
+  PROP_0,
+  PROP_SHOW_MENUBAR,
+  N_PROPS
+};
+static GParamSpec *gtk_application_window_properties[N_PROPS];
+
+/* Menubar construction {{{1 */
+
 static void
 gtk_application_window_update_menubar (GtkApplicationWindow *window)
 {
@@ -95,7 +117,7 @@ gtk_application_window_update_menubar (GtkApplicationWindow *window)
       g_menu_append_section (combined, NULL, G_MENU_MODEL (window->priv->app_menu_section));
       g_menu_append_section (combined, NULL, G_MENU_MODEL (window->priv->menubar_section));
 
-      window->priv->menubar = gtk_model_menu_create_menu_bar (G_MENU_MODEL (combined), G_ACTION_OBSERVABLE (muxer));
+      window->priv->menubar = gtk_model_menu_create_menu_bar (G_MENU_MODEL (combined), G_ACTION_OBSERVABLE (muxer), window->priv->accels);
       gtk_widget_set_parent (window->priv->menubar, GTK_WIDGET (window));
       gtk_widget_show_all (window->priv->menubar);
       g_object_unref (combined);
@@ -163,6 +185,144 @@ gtk_application_window_update_shell_shows_menubar (GtkApplicationWindow *window,
     }
 }
 
+/* Accelerator handling {{{1 */
+
+typedef struct {
+  GClosure closure;
+  gchar *action_name;
+  GVariant *parameter;
+} AccelClosure;
+
+static void
+accel_activate (GClosure     *closure,
+                GValue       *return_value,
+                guint         n_param_values,
+                const GValue *param_values,
+                gpointer      invocation_hint,
+                gpointer      marshal_data)
+{
+  AccelClosure *aclosure = (AccelClosure*)closure;
+  GActionGroup *actions;
+
+  actions = G_ACTION_GROUP (closure->data);
+  if (g_action_group_get_action_enabled (actions, aclosure->action_name))
+    {
+       g_action_group_activate_action (actions, aclosure->action_name, aclosure->parameter);
+
+      /* we handled the accelerator */
+      g_value_set_boolean (return_value, TRUE);
+    }
+}
+
+static void
+free_accel_closures (GtkApplicationWindow *window)
+{
+  GSList *l;
+
+  for (l = window->priv->accel_closures; l; l = l->next)
+    {
+       AccelClosure *closure = l->data;
+
+       g_object_unref (closure->closure.data);
+       if (closure->parameter)
+         g_variant_unref (closure->parameter);
+       g_free (closure->action_name);
+       g_closure_invalidate (&closure->closure);
+       g_closure_unref (&closure->closure);
+    }
+  g_slist_free (window->priv->accel_closures);
+  window->priv->accel_closures = NULL;
+}
+
+typedef struct {
+  GtkApplicationWindow *window;
+  GActionGroup *actions;
+} AccelData;
+
+/* Hack. We need to iterate over the accel map instead of
+ * the actions, in order to pull the parameters out of
+ * accel map entries
+ */
+static void
+add_accel_closure (gpointer         data,
+                   const gchar     *accel_path,
+                   guint            accel_key,
+                   GdkModifierType  accel_mods,
+                   gboolean         changed)
+{
+  AccelData *d = data;
+  const gchar *path;
+  const gchar *p;
+  gchar *action_name;
+  GVariant *parameter;
+  AccelClosure *closure;
+
+  if (accel_key == 0)
+    return;
+
+  if (!g_str_has_prefix (accel_path, "<Actions>/"))
+    return;
+
+  path = accel_path + strlen ("<Actions>/");
+  p = strchr (path, '/');
+  if (p)
+    {
+      action_name = g_strndup (path, p - path);
+      parameter = g_variant_parse (NULL, p + 1, NULL, NULL, NULL);
+      if (!parameter)
+        g_warning ("Failed to parse parameter from '%s'\n", accel_path);
+    }
+  else
+    {
+      action_name = g_strdup (path);
+      parameter = NULL;
+    }
+
+  if (g_action_group_has_action (d->actions, action_name))
+    {
+      closure = (AccelClosure*) g_closure_new_object (sizeof (AccelClosure), g_object_ref (d->actions));
+      g_closure_set_marshal (&closure->closure, accel_activate);
+
+      closure->action_name = g_strdup (action_name);
+      closure->parameter = parameter ? g_variant_ref_sink (parameter) : NULL;
+
+      d->window->priv->accel_closures = g_slist_prepend (d->window->priv->accel_closures, g_closure_ref (&closure->closure));
+      g_closure_sink (&closure->closure);
+
+      gtk_accel_group_connect_by_path (d->window->priv->accels, accel_path, &closure->closure);
+    }
+
+  g_free (action_name);
+}
+
+static void
+gtk_application_window_update_accels (GtkApplicationWindow *window)
+{
+  GtkApplication *application;
+  AccelData data;
+  GActionMuxer *muxer;
+
+  /* FIXME: we should keep the muxer around, and listen for changes.
+   * Also, we should listen for accel map changes
+   */
+  application = gtk_window_get_application (GTK_WINDOW (window));
+
+  free_accel_closures (window);
+
+  muxer = g_action_muxer_new ();
+  g_action_muxer_insert (muxer, "app", G_ACTION_GROUP (application));
+  g_action_muxer_insert (muxer, "win", G_ACTION_GROUP (window));
+
+  data.window = window;
+  data.actions = G_ACTION_GROUP (muxer);
+
+  gtk_accel_map_foreach (&data, add_accel_closure);
+
+  g_object_unref (muxer);
+}
+
+/* GtkSettings callbacks {{{1 */
+
 static void
 gtk_application_window_shell_shows_app_menu_changed (GObject    *object,
                                                      GParamSpec *pspec,
@@ -185,6 +345,8 @@ gtk_application_window_shell_shows_menubar_changed (GObject    *object,
   gtk_application_window_update_menubar (window);
 }
 
+/* GActionGroup implementation {{{1 */
+
 static gchar **
 gtk_application_window_list_actions (GActionGroup *group)
 {
@@ -228,6 +390,17 @@ gtk_application_window_change_action_state (GActionGroup *group,
   return g_action_group_change_action_state (G_ACTION_GROUP (window->priv->actions), action_name, state);
 }
 
+static void
+gtk_application_window_group_iface_init (GActionGroupInterface *iface)
+{
+  iface->list_actions = gtk_application_window_list_actions;
+  iface->query_action = gtk_application_window_query_action;
+  iface->activate_action = gtk_application_window_activate_action;
+  iface->change_action_state = gtk_application_window_change_action_state;
+}
+
+/* GActionMap implementation {{{1 */
+
 static GAction *
 gtk_application_window_lookup_action (GActionMap  *action_map,
                                       const gchar *action_name)
@@ -256,15 +429,6 @@ gtk_application_window_remove_action (GActionMap  *action_map,
 }
 
 static void
-gtk_application_window_group_iface_init (GActionGroupInterface *iface)
-{
-  iface->list_actions = gtk_application_window_list_actions;
-  iface->query_action = gtk_application_window_query_action;
-  iface->activate_action = gtk_application_window_activate_action;
-  iface->change_action_state = gtk_application_window_change_action_state;
-}
-
-static void
 gtk_application_window_map_iface_init (GActionMapInterface *iface)
 {
   iface->lookup_action = gtk_application_window_lookup_action;
@@ -272,16 +436,7 @@ gtk_application_window_map_iface_init (GActionMapInterface *iface)
   iface->remove_action = gtk_application_window_remove_action;
 }
 
-G_DEFINE_TYPE_WITH_CODE (GtkApplicationWindow, gtk_application_window, GTK_TYPE_WINDOW,
-                         G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_GROUP, gtk_application_window_group_iface_init)
-                         G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_MAP, gtk_application_window_map_iface_init))
-
-enum {
-  PROP_0,
-  PROP_SHOW_MENUBAR,
-  N_PROPS
-};
-static GParamSpec *gtk_application_window_properties[N_PROPS];
+/* GtkWidget implementation {{{1 */
 
 static void
 gtk_application_window_real_get_preferred_height (GtkWidget *widget,
@@ -421,6 +576,7 @@ gtk_application_window_real_realize (GtkWidget *widget)
   gtk_application_window_update_shell_shows_app_menu (window, settings);
   gtk_application_window_update_shell_shows_menubar (window, settings);
   gtk_application_window_update_menubar (window);
+  gtk_application_window_update_accels (window);
 
   GTK_WIDGET_CLASS (gtk_application_window_parent_class)
     ->realize (widget);
@@ -453,6 +609,8 @@ gtk_application_window_real_map (GtkWidget *widget)
     ->map (widget);
 }
 
+/* GtkContainer implementation {{{1 */
+
 static void
 gtk_application_window_real_forall_internal (GtkContainer *container,
                                              gboolean      include_internal,
@@ -468,6 +626,7 @@ gtk_application_window_real_forall_internal (GtkContainer *container,
     ->forall (container, include_internal, callback, user_data);
 }
 
+/* GObject implementation {{{1 */
 
 static void
 gtk_application_window_get_property (GObject    *object,
@@ -521,6 +680,8 @@ gtk_application_window_dispose (GObject *object)
   g_clear_object (&window->priv->app_menu_section);
   g_clear_object (&window->priv->menubar_section);
   g_clear_object (&window->priv->actions);
+  g_clear_object (&window->priv->accels);
+  free_accel_closures (window);
 
   G_OBJECT_CLASS (gtk_application_window_parent_class)
     ->dispose (object);
@@ -534,6 +695,8 @@ gtk_application_window_init (GtkApplicationWindow *window)
   window->priv->actions = g_simple_action_group_new ();
   window->priv->app_menu_section = g_menu_new ();
   window->priv->menubar_section = g_menu_new ();
+  window->priv->accels = gtk_accel_group_new ();
+  gtk_window_add_accel_group (GTK_WINDOW (window), window->priv->accels);
 
   /* window->priv->actions is the one and only ref on the group, so when
    * we dispose, the action group will die, disconnecting all signals.
@@ -578,6 +741,8 @@ gtk_application_window_class_init (GtkApplicationWindowClass *class)
   g_type_class_add_private (class, sizeof (GtkApplicationWindowPrivate));
 }
 
+/* Public API {{{1 */
+
 /**
  * gtk_application_window_new:
  * @application: a #GtkApplication
@@ -621,3 +786,6 @@ gtk_application_window_set_show_menubar (GtkApplicationWindow *window,
       g_object_notify_by_pspec (G_OBJECT (window), gtk_application_window_properties[PROP_SHOW_MENUBAR]);
     }
 }
+
+/* Epilogue {{{1 */
+/* vim:set foldmethod=marker: */
diff --git a/gtk/gtkmodelmenu.c b/gtk/gtkmodelmenu.c
index a9979cd..2c3db13 100644
--- a/gtk/gtkmodelmenu.c
+++ b/gtk/gtkmodelmenu.c
@@ -33,6 +33,7 @@
 typedef struct {
   GActionObservable *actions;
   GMenuModel        *model;
+  GtkAccelGroup     *accels;
   GtkMenuShell      *shell;
   guint              update_idle;
   GSList            *connected;
@@ -85,7 +86,7 @@ gtk_model_menu_binding_append_item (GtkModelMenuBinding  *binding,
     {
       GtkMenuItem *item;
 
-      item = gtk_model_menu_item_new (model, item_index, binding->actions);
+      item = gtk_model_menu_item_new (model, item_index, binding->actions, binding->accels);
       gtk_menu_shell_append (binding->shell, GTK_WIDGET (item));
       gtk_widget_show (GTK_WIDGET (item));
       binding->n_items++;
@@ -225,6 +226,7 @@ void
 gtk_model_menu_bind (GtkMenuShell      *shell,
                      GMenuModel        *model,
                      GActionObservable *actions,
+                     GtkAccelGroup     *accels,
                      gboolean           with_separators)
 {
   GtkModelMenuBinding *binding;
@@ -232,6 +234,7 @@ gtk_model_menu_bind (GtkMenuShell      *shell,
   binding = g_slice_new (GtkModelMenuBinding);
   binding->model = g_object_ref (model);
   binding->actions = g_object_ref (actions);
+  binding->accels = accels;
   binding->shell = shell;
   binding->update_idle = 0;
   binding->connected = NULL;
@@ -243,24 +246,27 @@ gtk_model_menu_bind (GtkMenuShell      *shell,
 
 GtkWidget *
 gtk_model_menu_create_menu (GMenuModel        *model,
-                            GActionObservable *actions)
+                            GActionObservable *actions,
+                            GtkAccelGroup     *accels)
 {
   GtkWidget *menu;
 
   menu = gtk_menu_new ();
-  gtk_model_menu_bind (GTK_MENU_SHELL (menu), model, actions, TRUE);
+  gtk_menu_set_accel_group (GTK_MENU (menu), accels);
+  gtk_model_menu_bind (GTK_MENU_SHELL (menu), model, actions, accels, TRUE);
 
   return menu;
 }
 
 GtkWidget *
 gtk_model_menu_create_menu_bar (GMenuModel        *model,
-                                GActionObservable *actions)
+                                GActionObservable *actions,
+                                GtkAccelGroup     *accels)
 {
   GtkWidget *menubar;
 
   menubar = gtk_menu_bar_new ();
-  gtk_model_menu_bind (GTK_MENU_SHELL (menubar), model, actions, FALSE);
+  gtk_model_menu_bind (GTK_MENU_SHELL (menubar), model, actions, accels, FALSE);
 
   return menubar;
 }
diff --git a/gtk/gtkmodelmenu.h b/gtk/gtkmodelmenu.h
index 409d1f9..827d143 100644
--- a/gtk/gtkmodelmenu.h
+++ b/gtk/gtkmodelmenu.h
@@ -24,20 +24,24 @@
 
 #include <gtk/gactionobservable.h>
 #include <gtk/gtkmenushell.h>
+#include <gtk/gtkaccelgroup.h>
 #include <gio/gio.h>
 
 G_GNUC_INTERNAL
 void                    gtk_model_menu_bind                             (GtkMenuShell      *shell,
                                                                          GMenuModel        *model,
                                                                          GActionObservable *actions,
+                                                                         GtkAccelGroup     *accels,
                                                                          gboolean           with_separators);
 
 G_GNUC_INTERNAL
 GtkWidget *             gtk_model_menu_create_menu_bar                  (GMenuModel        *model,
-                                                                         GActionObservable *actions);
+                                                                         GActionObservable *actions,
+                                                                         GtkAccelGroup     *accels);
 
 G_GNUC_INTERNAL
 GtkWidget *             gtk_model_menu_create_menu                      (GMenuModel        *model,
-                                                                         GActionObservable *actions);
+                                                                         GActionObservable *actions,
+                                                                         GtkAccelGroup     *accels);
 
 #endif /* __GTK_MODEL_MENU_H__ */
diff --git a/gtk/gtkmodelmenuitem.c b/gtk/gtkmodelmenuitem.c
index 30ca3f4..36ee8c6 100644
--- a/gtk/gtkmodelmenuitem.c
+++ b/gtk/gtkmodelmenuitem.c
@@ -23,6 +23,7 @@
 
 #include "gtkmodelmenuitem.h"
 
+#include "gtkaccelmap.h"
 #include "gtkmodelmenu.h"
 
 struct _GtkModelMenuItem
@@ -188,11 +189,29 @@ gtk_model_menu_item_action_removed (GActionObserver   *observer,
   gtk_widget_queue_resize (GTK_WIDGET (item));
 }
 
+/* keep this in sync with gtkapplication.c */
+static gchar *
+get_accel_path (const gchar *action_name,
+                GVariant    *parameter)
+{
+  GString *s;
+
+  s = g_string_new ("<Actions>/");
+  g_string_append (s, action_name);
+  if (parameter)
+    {
+      g_string_append_c (s, '/');
+      g_variant_print_string (parameter, s, FALSE);
+    }
+  return g_string_free (s, FALSE);
+}
+
 static void
 gtk_model_menu_item_setup (GtkModelMenuItem  *item,
                            GMenuModel        *model,
                            gint               item_index,
-                           GActionObservable *actions)
+                           GActionObservable *actions,
+                           GtkAccelGroup     *accels)
 {
   GMenuAttributeIter *iter;
   GMenuModel *submenu;
@@ -201,7 +220,7 @@ gtk_model_menu_item_setup (GtkModelMenuItem  *item,
 
   if ((submenu = g_menu_model_get_item_link (model, item_index, "submenu")))
     {
-      gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), gtk_model_menu_create_menu (submenu, actions));
+      gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), gtk_model_menu_create_menu (submenu, actions, accels));
       g_object_unref (submenu);
     }
 
@@ -228,6 +247,7 @@ gtk_model_menu_item_setup (GtkModelMenuItem  *item,
       const GVariantType *type;
       gboolean enabled;
       GVariant *state;
+      gchar *path;
 
       /* observer already causes us to hold a hard ref on the group */
       item->actions = G_ACTION_GROUP (actions);
@@ -242,6 +262,10 @@ gtk_model_menu_item_setup (GtkModelMenuItem  *item,
 
       if (state != NULL)
         g_variant_unref (state);
+
+      path = get_accel_path (item->action_name, item->target);
+      gtk_menu_item_set_accel_path (GTK_MENU_ITEM (item), path);
+      g_free (path);
     }
 }
 
@@ -284,13 +308,14 @@ gtk_model_menu_item_class_init (GtkModelMenuItemClass *class)
 GtkMenuItem *
 gtk_model_menu_item_new (GMenuModel        *model,
                          gint               item_index,
-                         GActionObservable *actions)
+                         GActionObservable *actions,
+                         GtkAccelGroup     *accels)
 {
   GtkModelMenuItem *item;
 
   item = g_object_new (GTK_TYPE_MODEL_MENU_ITEM, NULL);
 
-  gtk_model_menu_item_setup (item, model, item_index, actions);
+  gtk_model_menu_item_setup (item, model, item_index, actions, accels);
 
   return GTK_MENU_ITEM (item);
 }
diff --git a/gtk/gtkmodelmenuitem.h b/gtk/gtkmodelmenuitem.h
index 4146bf9..176d68f 100644
--- a/gtk/gtkmodelmenuitem.h
+++ b/gtk/gtkmodelmenuitem.h
@@ -39,6 +39,7 @@ GType                   gtk_model_menu_item_get_type                    (void) G
 G_GNUC_INTERNAL
 GtkMenuItem *           gtk_model_menu_item_new                         (GMenuModel        *model,
                                                                          gint               item_index,
-                                                                         GActionObservable *actions);
+                                                                         GActionObservable *actions,
+                                                                         GtkAccelGroup     *accels);
 
 #endif /* __GTK_MODEL_MENU_ITEM_H__ */
