+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;
+
+ gtk_accel_group_disconnect (window->priv->accels, &closure->closure);
+
+ 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;
+}
+
+/* Hack. We 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)
+{
+ GtkApplicationWindow *window = data;
+ GActionGroup *actions;
+ 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, "<GAction>/"))
+ return;
+
+ path = accel_path + strlen ("<GAction>/");
+ 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;
+ }
+
+ actions = G_ACTION_GROUP (_gtk_widget_get_action_muxer (GTK_WIDGET (window)));
+ if (g_action_group_has_action (actions, action_name))
+ {
+ closure = (AccelClosure*) g_closure_new_object (sizeof (AccelClosure), g_object_ref (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;
+
+ window->priv->accel_closures = g_slist_prepend (window->priv->accel_closures, g_closure_ref (&closure->closure));
+ g_closure_sink (&closure->closure);
+
+ gtk_accel_group_connect_by_path (window->priv->accels, accel_path, &closure->closure);
+ }
+ else if (parameter)
+ {
+ g_variant_unref (parameter);
+ }
+
+ g_free (action_name);
+}
+
+static void
+gtk_application_window_update_accels (GtkApplicationWindow *window)
+{
+ free_accel_closures (window);
+
+ gtk_accel_map_foreach (window, add_accel_closure);
+}
+