diff --git a/src/gtkactionmuxer.c b/src/gtkactionmuxer.c index be6696501..1537864b7 100644 --- a/src/gtkactionmuxer.c +++ b/src/gtkactionmuxer.c @@ -24,8 +24,6 @@ #include "gtkactionobservable.h" #include "gtkactionobserver.h" -#include - #include /** @@ -67,6 +65,7 @@ struct _GtkActionMuxer GHashTable *observed_actions; GHashTable *groups; + GHashTable *primary_accels; GtkActionMuxer *parent; }; @@ -83,6 +82,8 @@ enum static GParamSpec *properties[NUM_PROPERTIES]; +guint accel_signal; + typedef struct { GtkActionMuxer *muxer; @@ -335,6 +336,39 @@ gtk_action_muxer_action_removed_from_parent (GActionGroup *action_group, gtk_action_muxer_action_removed (muxer, action_name); } +static void +gtk_action_muxer_primary_accel_changed (GtkActionMuxer *muxer, + const gchar *action_name, + const gchar *action_and_target) +{ + Action *action; + GSList *node; + + if (!action_name) + action_name = strrchr (action_and_target, '|') + 1; + + action = g_hash_table_lookup (muxer->observed_actions, action_name); + for (node = action ? action->watchers : NULL; node; node = node->next) + gtk_action_observer_primary_accel_changed (node->data, GTK_ACTION_OBSERVABLE (muxer), + action_name, action_and_target); + g_signal_emit (muxer, accel_signal, 0, action_name, action_and_target); +} + +static void +gtk_action_muxer_parent_primary_accel_changed (GtkActionMuxer *parent, + const gchar *action_name, + const gchar *action_and_target, + gpointer user_data) +{ + GtkActionMuxer *muxer = user_data; + + /* If it's in our table then don't let the parent one filter through */ + if (muxer->primary_accels && g_hash_table_lookup (muxer->primary_accels, action_and_target)) + return; + + gtk_action_muxer_primary_accel_changed (muxer, action_name, action_and_target); +} + static gboolean gtk_action_muxer_query_action (GActionGroup *action_group, const gchar *action_name, @@ -379,26 +413,6 @@ gtk_action_muxer_activate_action (GActionGroup *action_group, g_action_group_activate_action (G_ACTION_GROUP (muxer->parent), action_name, parameter); } -static GVariant * -get_platform_data (void) -{ - gchar time[32]; - GVariantBuilder *builder; - GVariant *result; - - g_snprintf (time, 32, "_TIME%d", clutter_get_current_event_time ()); - - builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); - - g_variant_builder_add (builder, "{sv}", "desktop-startup-id", - g_variant_new_string (time)); - - result = g_variant_builder_end (builder); - g_variant_builder_unref (builder); - - return result; -} - static void gtk_action_muxer_change_action_state (GActionGroup *action_group, const gchar *action_name, @@ -411,15 +425,7 @@ gtk_action_muxer_change_action_state (GActionGroup *action_group, group = gtk_action_muxer_find_group (muxer, action_name, &unprefixed_name); if (group) - { - if (G_IS_REMOTE_ACTION_GROUP (group->group)) - g_remote_action_group_change_action_state_full (G_REMOTE_ACTION_GROUP (group->group), - unprefixed_name, - state, - get_platform_data ()); - else - g_action_group_change_action_state (group->group, unprefixed_name, state); - } + g_action_group_change_action_state (group->group, unprefixed_name, state); else if (muxer->parent) g_action_group_change_action_state (G_ACTION_GROUP (muxer->parent), action_name, state); } @@ -544,6 +550,7 @@ gtk_action_muxer_dispose (GObject *object) g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_action_removed_from_parent, muxer); g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_parent_action_enabled_changed, muxer); g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_parent_action_state_changed, muxer); + g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_parent_primary_accel_changed, muxer); g_clear_object (&muxer->parent); } @@ -623,6 +630,9 @@ gtk_action_muxer_class_init (GObjectClass *class) class->finalize = gtk_action_muxer_finalize; class->dispose = gtk_action_muxer_dispose; + accel_signal = g_signal_new ("primary-accel-changed", GTK_TYPE_ACTION_MUXER, G_SIGNAL_RUN_LAST, + 0, NULL, NULL, NULL, G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING); + properties[PROP_PARENT] = g_param_spec_object ("parent", "Parent", "The parent muxer", GTK_TYPE_ACTION_MUXER, @@ -745,6 +755,26 @@ gtk_action_muxer_get_parent (GtkActionMuxer *muxer) return muxer->parent; } +static void +emit_changed_accels (GtkActionMuxer *muxer, + GtkActionMuxer *parent) +{ + while (parent) + { + if (parent->primary_accels) + { + GHashTableIter iter; + gpointer key; + + g_hash_table_iter_init (&iter, parent->primary_accels); + while (g_hash_table_iter_next (&iter, &key, NULL)) + gtk_action_muxer_primary_accel_changed (muxer, NULL, key); + } + + parent = parent->parent; + } +} + /** * gtk_action_muxer_set_parent: * @muxer: a #GtkActionMuxer @@ -772,10 +802,13 @@ gtk_action_muxer_set_parent (GtkActionMuxer *muxer, gtk_action_muxer_action_removed (muxer, *it); g_strfreev (actions); + emit_changed_accels (muxer, muxer->parent); + g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_action_added_to_parent, muxer); g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_action_removed_from_parent, muxer); g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_parent_action_enabled_changed, muxer); g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_parent_action_state_changed, muxer); + g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_parent_primary_accel_changed, muxer); g_object_unref (muxer->parent); } @@ -794,6 +827,8 @@ gtk_action_muxer_set_parent (GtkActionMuxer *muxer, gtk_action_muxer_action_added (muxer, *it, G_ACTION_GROUP (muxer->parent), *it); g_strfreev (actions); + emit_changed_accels (muxer, muxer->parent); + g_signal_connect (muxer->parent, "action-added", G_CALLBACK (gtk_action_muxer_action_added_to_parent), muxer); g_signal_connect (muxer->parent, "action-removed", @@ -802,7 +837,72 @@ gtk_action_muxer_set_parent (GtkActionMuxer *muxer, G_CALLBACK (gtk_action_muxer_parent_action_enabled_changed), muxer); g_signal_connect (muxer->parent, "action-state-changed", G_CALLBACK (gtk_action_muxer_parent_action_state_changed), muxer); + g_signal_connect (muxer->parent, "primary-accel-changed", + G_CALLBACK (gtk_action_muxer_parent_primary_accel_changed), muxer); } g_object_notify_by_pspec (G_OBJECT (muxer), properties[PROP_PARENT]); } + +void +gtk_action_muxer_set_primary_accel (GtkActionMuxer *muxer, + const gchar *action_and_target, + const gchar *primary_accel) +{ + if (!muxer->primary_accels) + muxer->primary_accels = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + + if (primary_accel) + g_hash_table_insert (muxer->primary_accels, g_strdup (action_and_target), g_strdup (primary_accel)); + else + g_hash_table_remove (muxer->primary_accels, action_and_target); + + gtk_action_muxer_primary_accel_changed (muxer, NULL, action_and_target); +} + +const gchar * +gtk_action_muxer_get_primary_accel (GtkActionMuxer *muxer, + const gchar *action_and_target) +{ + if (muxer->primary_accels) + { + const gchar *primary_accel; + + primary_accel = g_hash_table_lookup (muxer->primary_accels, action_and_target); + + if (primary_accel) + return primary_accel; + } + + if (!muxer->parent) + return NULL; + + return gtk_action_muxer_get_primary_accel (muxer->parent, action_and_target); +} + +gchar * +gtk_print_action_and_target (const gchar *action_namespace, + const gchar *action_name, + GVariant *target) +{ + GString *result; + + g_return_val_if_fail (strchr (action_name, '|') == NULL, NULL); + g_return_val_if_fail (action_namespace == NULL || strchr (action_namespace, '|') == NULL, NULL); + + result = g_string_new (NULL); + + if (target) + g_variant_print_string (target, result, TRUE); + g_string_append_c (result, '|'); + + if (action_namespace) + { + g_string_append (result, action_namespace); + g_string_append_c (result, '.'); + } + + g_string_append (result, action_name); + + return g_string_free (result, FALSE); +} diff --git a/src/gtkactionmuxer.h b/src/gtkactionmuxer.h index 401483072..d71abf48d 100644 --- a/src/gtkactionmuxer.h +++ b/src/gtkactionmuxer.h @@ -47,6 +47,18 @@ GtkActionMuxer * gtk_action_muxer_get_parent (GtkActi void gtk_action_muxer_set_parent (GtkActionMuxer *muxer, GtkActionMuxer *parent); +void gtk_action_muxer_set_primary_accel (GtkActionMuxer *muxer, + const gchar *action_and_target, + const gchar *primary_accel); + +const gchar * gtk_action_muxer_get_primary_accel (GtkActionMuxer *muxer, + const gchar *action_and_target); + +/* No better place for this... */ +gchar * gtk_print_action_and_target (const gchar *action_namespace, + const gchar *action_name, + GVariant *target); + G_END_DECLS #endif /* __GTK_ACTION_MUXER_H__ */ diff --git a/src/gtkactionobserver.c b/src/gtkactionobserver.c index cf70b20a3..3287106b7 100644 --- a/src/gtkactionobserver.c +++ b/src/gtkactionobserver.c @@ -157,3 +157,33 @@ gtk_action_observer_action_removed (GtkActionObserver *observer, GTK_ACTION_OBSERVER_GET_IFACE (observer) ->action_removed (observer, observable, action_name); } + +/** + * gtk_action_observer_primary_accel_changed: + * @observer: a #GtkActionObserver + * @observable: the source of the event + * @action_name: the name of the action + * @action_and_target: detailed action of the changed accel, in "action and target" format + * + * This function is called when an action that the observer is + * registered to receive events for has one of its accelerators changed. + * + * Accelerator changes are reported for all targets associated with the + * action. The @action_and_target string should be used to check if the + * reported target is the one that the observer is interested in. + */ +void +gtk_action_observer_primary_accel_changed (GtkActionObserver *observer, + GtkActionObservable *observable, + const gchar *action_name, + const gchar *action_and_target) +{ + GtkActionObserverInterface *iface; + + g_return_if_fail (GTK_IS_ACTION_OBSERVER (observer)); + + iface = GTK_ACTION_OBSERVER_GET_IFACE (observer); + + if (iface->primary_accel_changed) + iface->primary_accel_changed (observer, observable, action_name, action_and_target); +} diff --git a/src/gtkactionobserver.h b/src/gtkactionobserver.h index 83629a7e4..a4e9659c2 100644 --- a/src/gtkactionobserver.h +++ b/src/gtkactionobserver.h @@ -57,6 +57,10 @@ struct _GtkActionObserverInterface void (* action_removed) (GtkActionObserver *observer, GtkActionObservable *observable, const gchar *action_name); + void (* primary_accel_changed) (GtkActionObserver *observer, + GtkActionObservable *observable, + const gchar *action_name, + const gchar *action_and_target); }; GType gtk_action_observer_get_type (void); @@ -77,6 +81,10 @@ void gtk_action_observer_action_state_changed (GtkActi void gtk_action_observer_action_removed (GtkActionObserver *observer, GtkActionObservable *observable, const gchar *action_name); +void gtk_action_observer_primary_accel_changed (GtkActionObserver *observer, + GtkActionObservable *observable, + const gchar *action_name, + const gchar *action_and_target); G_END_DECLS