diff --git a/gio/gapplication.c b/gio/gapplication.c
index 17398e0..ba408ce 100644
--- a/gio/gapplication.c
+++ b/gio/gapplication.c
@@ -201,8 +201,7 @@ struct _GApplicationPrivate
   gchar             *id;
 
   GActionGroup      *actions;
-  GMenuModel        *app_menu;
-  GMenuModel        *menubar;
+  GHashTable        *menus;
 
   guint              inactivity_timeout_id;
   guint              inactivity_timeout;
@@ -225,9 +224,7 @@ enum
   PROP_IS_REGISTERED,
   PROP_IS_REMOTE,
   PROP_INACTIVITY_TIMEOUT,
-  PROP_ACTION_GROUP,
-  PROP_APP_MENU,
-  PROP_MENUBAR
+  PROP_ACTION_GROUP
 };
 
 enum
@@ -238,6 +235,7 @@ enum
   SIGNAL_OPEN,
   SIGNAL_ACTION,
   SIGNAL_COMMAND_LINE,
+  SIGNAL_MENU_CHANGED,
   NR_SIGNALS
 };
 
@@ -450,14 +448,6 @@ g_application_set_property (GObject      *object,
       application->priv->actions = g_value_dup_object (value);
       break;
 
-    case PROP_APP_MENU:
-      g_application_set_app_menu (application, g_value_get_object (value));
-      break;
-
-    case PROP_MENUBAR:
-      g_application_set_menubar (application, g_value_get_object (value));
-      break;
-
     default:
       g_assert_not_reached ();
     }
@@ -517,18 +507,7 @@ g_application_set_app_menu (GApplication *application,
 {
   g_return_if_fail (G_IS_APPLICATION (application));
 
-  if (app_menu != application->priv->app_menu)
-    {
-      if (application->priv->app_menu != NULL)
-        g_object_unref (application->priv->app_menu);
-
-      application->priv->app_menu = app_menu;
-
-      if (application->priv->app_menu != NULL)
-        g_object_ref (application->priv->app_menu);
-
-      g_object_notify (G_OBJECT (application), "app-menu");
-    }
+  g_application_set_menu (application, "AppMenu", app_menu);
 }
 
 /**
@@ -547,15 +526,34 @@ g_application_get_app_menu (GApplication *application)
 {
   g_return_val_if_fail (G_IS_APPLICATION (application), NULL);
 
-  return application->priv->app_menu;
+  return g_application_get_menu (application, "AppMenu");
+}
+
+void
+g_application_set_menubar (GApplication *application,
+                           GMenuModel   *menubar)
+{
+  g_return_if_fail (G_IS_APPLICATION (application));
+
+  g_application_set_menu (application, "MenuBar", menubar);
+}
+
+GMenuModel *
+g_application_get_menubar (GApplication *application)
+{
+  g_return_val_if_fail (G_IS_APPLICATION (application), NULL);
+
+  return g_application_get_menu (application, "MenuBar");
 }
 
 /**
- * g_application_set_menubar:
+ * g_application_set_menu:
  * @application: a #GApplication
- * @menubar: (allow-none): a #GMenuModel, or %NULL
+ * @id: an id for the menu
+ * @menu: (allow-none): a #GMenuModel, or %NULL
  *
- * Sets or unsets the menubar for windows of @application.
+ * Sets or unsets a menubar for windows of @application. Different
+ * windows may use different menubars by referring to the @id.
  *
  * This is a menubar in the traditional sense.
  *
@@ -570,42 +568,49 @@ g_application_get_app_menu (GApplication *application)
  * Since: 2.32
  */
 void
-g_application_set_menubar (GApplication *application,
-                            GMenuModel   *menubar)
+g_application_set_menu (GApplication *application,
+                        const gchar  *id,
+                        GMenuModel   *menu)
 {
+  GQuark detail;
   g_return_if_fail (G_IS_APPLICATION (application));
 
-  if (menubar != application->priv->menubar)
-    {
-      if (application->priv->menubar != NULL)
-        g_object_unref (application->priv->menubar);
-
-      application->priv->menubar = menubar;
-
-      if (application->priv->menubar != NULL)
-        g_object_ref (application->priv->menubar);
-
-      g_object_notify (G_OBJECT (application), "menubar");
-    }
+  detail = g_quark_from_string (id);
+  g_hash_table_insert (application->priv->menus,
+                       (gpointer)g_quark_to_string (detail),
+                       menu ? g_object_ref (menu) : NULL);
+  g_signal_emit (application,
+                 g_application_signals[SIGNAL_MENU_CHANGED],
+                 detail);
 }
 
 /**
- * g_application_get_menubar:
+ * g_application_get_menu:
  * @application: a #GApplication
+ * @id: an id
  *
- * Returns the menu model that has been set with
- * g_application_set_menubar().
+ * Returns a menu model that has been set with
+ * g_application_set_menu().
  *
- * Returns: the menubar for windows of @application
+ * Returns: the menu of @application with the given id
  *
  * Since: 2.32
  */
 GMenuModel *
-g_application_get_menubar (GApplication *application)
+g_application_get_menu (GApplication *application,
+                        const gchar  *id)
+{
+  g_return_val_if_fail (G_IS_APPLICATION (application), NULL);
+
+  return (GMenuModel *)g_hash_table_lookup (application->priv->menus, id);
+}
+
+GHashTable *
+g_application_get_all_menus (GApplication *application)
 {
   g_return_val_if_fail (G_IS_APPLICATION (application), NULL);
 
-  return application->priv->menubar;
+  return application->priv->menus;
 }
 
 static void
@@ -643,16 +648,6 @@ g_application_get_property (GObject    *object,
                         g_application_get_inactivity_timeout (application));
       break;
 
-    case PROP_APP_MENU:
-      g_value_set_object (value,
-                          g_application_get_app_menu (application));
-      break;
-
-    case PROP_MENUBAR:
-      g_value_set_object (value,
-                          g_application_get_menubar (application));
-      break;
-
     default:
       g_assert_not_reached ();
     }
@@ -681,11 +676,7 @@ g_application_finalize (GObject *object)
   if (g_application_get_default () == application)
     g_application_set_default (NULL);
 
-  if (application->priv->app_menu)
-    g_object_unref (application->priv->app_menu);
-
-  if (application->priv->menubar)
-    g_object_unref (application->priv->menubar);
+  g_hash_table_unref (application->priv->menus);
 
   if (application->priv->actions)
     g_object_unref (application->priv->actions);
@@ -701,6 +692,8 @@ g_application_init (GApplication *application)
                                                    G_TYPE_APPLICATION,
                                                    GApplicationPrivate);
   application->priv->actions = G_ACTION_GROUP (g_simple_action_group_new ());
+  application->priv->menus = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                                    NULL, g_object_unref);
 }
 
 static void
@@ -763,20 +756,6 @@ g_application_class_init (GApplicationClass *class)
                          G_TYPE_ACTION_GROUP,
                          G_PARAM_DEPRECATED | G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
 
-  g_object_class_install_property (object_class, PROP_APP_MENU,
-    g_param_spec_object ("app-menu",
-                         P_("Application menu"),
-                         P_("The GMenuModel for the application menu"),
-                         G_TYPE_MENU_MODEL,
-                         G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
-  g_object_class_install_property (object_class, PROP_MENUBAR,
-    g_param_spec_object ("menubar",
-                         P_("Menubar"),
-                         P_("The GMenuModel for the menubar"),
-                         G_TYPE_MENU_MODEL,
-                         G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
   /**
    * GApplication::startup:
    * @application: the application
@@ -850,6 +829,12 @@ g_application_class_init (GApplicationClass *class)
                   NULL,
                   G_TYPE_INT, 1, G_TYPE_APPLICATION_COMMAND_LINE);
 
+  g_application_signals[SIGNAL_MENU_CHANGED] =
+    g_signal_new ("menu-changed", G_TYPE_APPLICATION, G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+                  G_STRUCT_OFFSET (GApplicationClass, menu_changed),
+                  NULL, NULL, NULL,
+                  G_TYPE_NONE, 0);
+
   g_type_class_add_private (class, sizeof (GApplicationPrivate));
 }
 
diff --git a/gio/gapplication.h b/gio/gapplication.h
index 76fcf93..7c97e42 100644
--- a/gio/gapplication.h
+++ b/gio/gapplication.h
@@ -90,8 +90,11 @@ struct _GApplicationClass
   void                      (* run_mainloop)        (GApplication              *application);
   void                      (* shutdown)            (GApplication              *application);
 
+  /* another signal */
+  void                      (* menu_changed)        (GApplication              *application);
+
   /*< private >*/
-  gpointer padding[11];
+  gpointer padding[10];
 };
 
 GType                   g_application_get_type                          (void) G_GNUC_CONST;
@@ -124,6 +127,12 @@ GMenuModel             *g_application_get_app_menu                      (GApplic
 void                    g_application_set_menubar                       (GApplication             *application,
                                                                          GMenuModel               *menubar);
 GMenuModel *            g_application_get_menubar                       (GApplication             *application);
+void                    g_application_set_menu                          (GApplication             *application,
+                                                                         const gchar              *id,
+                                                                         GMenuModel               *menubar);
+GMenuModel *            g_application_get_menu                          (GApplication             *application,
+                                                                         const gchar              *id);
+GHashTable *            g_application_get_all_menus                     (GApplication             *application);
 
 gboolean                g_application_get_is_registered                 (GApplication             *application);
 gboolean                g_application_get_is_remote                     (GApplication             *application);
diff --git a/gio/gapplicationimpl-dbus.c b/gio/gapplicationimpl-dbus.c
index 3d15f52..2267963 100644
--- a/gio/gapplicationimpl-dbus.c
+++ b/gio/gapplicationimpl-dbus.c
@@ -61,8 +61,7 @@ static const gchar org_gtk_Application_xml[] =
   "      <arg type='a{sv}' name='platform-data' direction='in'/>"
   "      <arg type='i' name='exit-status' direction='out'/>"
   "    </method>"
-  "    <property name='AppMenu' type='ao' access='read'/>"
-  "    <property name='MenuBar' type='ao' access='read'/>"
+  "    <property name='Menus' type='a{so}' access='read'/>"
   "  </interface>"
   "</node>";
 
@@ -83,6 +82,21 @@ static const gchar org_gtk_private_CommandLine_xml[] =
 static GDBusInterfaceInfo *org_gtk_private_CommandLine;
 
 /* GApplication implementation {{{1 */
+
+typedef struct {
+  guint id;
+  gchar *path;
+} MenuData;
+
+static void
+menu_data_free (gpointer p)
+{
+  MenuData *data = p;
+
+  g_free (data->path);
+  g_free (data);
+}
+
 struct _GApplicationImpl
 {
   GDBusConnection *session_bus;
@@ -92,11 +106,7 @@ struct _GApplicationImpl
   guint            object_id;
   guint            actions_id;
 
-  gchar           *app_menu_path;
-  guint            app_menu_id;
-
-  gchar           *menubar_path;
-  guint            menubar_id;
+  GHashTable      *menus;
 
   gboolean         properties_live;
   gboolean         primary;
@@ -212,16 +222,15 @@ g_application_impl_get_property (GDBusConnection  *connection,
 
   g_variant_builder_init (&builder, G_VARIANT_TYPE_OBJECT_PATH_ARRAY);
 
-  if (g_str_equal (property_name, "AppMenu"))
+  if (g_str_equal (property_name, "Menus"))
     {
-      if (impl->app_menu_path != NULL)
-        g_variant_builder_add (&builder, "o", impl->app_menu_path);
-    }
+      GHashTableIter iter;
+      MenuData *data;
+      const gchar *id;
 
-  else if (g_str_equal (property_name, "MenuBar"))
-    {
-      if (impl->menubar_path != NULL)
-        g_variant_builder_add (&builder, "o", impl->menubar_path);
+      g_hash_table_iter_init (&iter, impl->menus);
+      while (g_hash_table_iter_next (&iter, (gpointer*)&id, (gpointer*)&data))
+        g_variant_builder_add (&builder, "{so}", id, data->path);
     }
 
   else
@@ -296,31 +305,48 @@ g_application_impl_publish_menu (GApplicationImpl  *impl,
 }
 
 static void
-g_application_impl_app_menu_changed (GObject    *source,
-                                     GParamSpec *pspec,
-                                     gpointer    user_data)
+g_application_impl_menu_changed (GObject  *source,
+                                 gpointer  user_data)
 {
   GApplicationImpl *impl = user_data;
+  GSignalInvocationHint *hint;
+  const gchar *id;
+  GMenuModel *menu;
+  MenuData *data;
 
   g_assert (source == impl->app);
 
-  g_application_impl_publish_menu (impl, "AppMenu", g_application_get_app_menu (impl->app),
-                                   &impl->app_menu_id, &impl->app_menu_path);
+  hint = g_signal_get_invocation_hint (source);
+  g_assert (hint != NULL);
+
+  id = g_quark_to_string (hint->detail);
+  menu = g_application_get_menu (impl->app, id);
+
+  data = g_new0 (MenuData, 1);
+  g_application_impl_publish_menu (impl, id, menu, &data->id, &data->path);
+  g_hash_table_insert (impl->menus, (gpointer)id, data);
 }
 
 static void
-g_application_impl_menubar_changed (GObject    *source,
-                                    GParamSpec *pspec,
-                                    gpointer    user_data)
+g_application_impl_all_menus_changed (GApplicationImpl *impl)
 {
-  GApplicationImpl *impl = user_data;
-
-  g_assert (source == impl->app);
-
-  g_application_impl_publish_menu (impl, "MenuBar", g_application_get_menubar (impl->app),
-                                   &impl->menubar_id, &impl->menubar_path);
+  GHashTable *menus;
+  GHashTableIter iter;
+  GMenuModel *menu;
+  const gchar *id;
+  MenuData *data;
+
+  menus = g_application_get_all_menus (impl->app);
+  g_hash_table_iter_init (&iter, menus);
+  while (g_hash_table_iter_next (&iter, (gpointer*)&id, (gpointer*)&menu))
+    {
+      data = g_new0 (MenuData, 1);
+      g_application_impl_publish_menu (impl, id, menu, &data->id, &data->path);
+      g_hash_table_insert (impl->menus, (gpointer)g_intern_string (id), data);
+    }
 }
 
+
 /* Attempt to become the primary instance.
  *
  * Returns %TRUE if everything went OK, regardless of if we became the
@@ -398,10 +424,8 @@ g_application_impl_attempt_primary (GApplicationImpl  *impl,
 
   if (impl->primary)
     {
-      g_signal_connect (impl->app, "notify::app-menu", G_CALLBACK (g_application_impl_app_menu_changed), impl);
-      g_signal_connect (impl->app, "notify::menubar", G_CALLBACK (g_application_impl_menubar_changed), impl);
-      g_application_impl_app_menu_changed (impl->app, NULL, impl);
-      g_application_impl_menubar_changed (impl->app, NULL, impl);
+      g_signal_connect (impl->app, "menu-changed", G_CALLBACK (g_application_impl_menu_changed), impl);
+      g_application_impl_all_menus_changed (impl);
     }
 
   return TRUE;
@@ -418,6 +442,10 @@ g_application_impl_attempt_primary (GApplicationImpl  *impl,
 static void
 g_application_impl_stop_primary (GApplicationImpl *impl)
 {
+  GHashTableIter iter;
+  const gchar *id;
+  MenuData *data;
+
   if (impl->object_id)
     {
       g_dbus_connection_unregister_object (impl->session_bus, impl->object_id);
@@ -432,8 +460,7 @@ g_application_impl_stop_primary (GApplicationImpl *impl)
 
   if (impl->primary)
     {
-      g_signal_handlers_disconnect_by_func (impl->app, g_application_impl_app_menu_changed, impl);
-      g_signal_handlers_disconnect_by_func (impl->app, g_application_impl_menubar_changed, impl);
+      g_signal_handlers_disconnect_by_func (impl->app, g_application_impl_menu_changed, impl);
 
       g_dbus_connection_call (impl->session_bus, "org.freedesktop.DBus",
                               "/org/freedesktop/DBus", "org.freedesktop.DBus",
@@ -442,21 +469,10 @@ g_application_impl_stop_primary (GApplicationImpl *impl)
       impl->primary = FALSE;
     }
 
-  if (impl->app_menu_id)
-    {
-      g_dbus_connection_unexport_menu_model (impl->session_bus, impl->app_menu_id);
-      g_free (impl->app_menu_path);
-      impl->app_menu_path = NULL;
-      impl->app_menu_id = 0;
-    }
-
-  if (impl->menubar_id)
-    {
-      g_dbus_connection_unexport_menu_model (impl->session_bus, impl->menubar_id);
-      g_free (impl->menubar_path);
-      impl->menubar_path = NULL;
-      impl->menubar_id = 0;
-    }
+  g_hash_table_iter_init (&iter, impl->menus);
+  while (g_hash_table_iter_next (&iter, (gpointer*)&id, (gpointer *)&data))
+    g_dbus_connection_unexport_menu_model (impl->session_bus, data->id);
+  g_hash_table_remove_all (impl->menus);
 }
 
 void
@@ -469,6 +485,8 @@ g_application_impl_destroy (GApplicationImpl *impl)
 
   g_free (impl->object_path);
 
+  g_hash_table_destroy (impl->menus);
+
   g_slice_free (GApplicationImpl, impl);
 }
 
@@ -501,6 +519,8 @@ g_application_impl_register (GApplication       *application,
 
   impl->object_path = application_path_from_appid (appid);
 
+  impl->menus = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, menu_data_free);
+
   /* Only try to be the primary instance if
    * G_APPLICATION_IS_LAUNCHER was not specified.
    */
