From ceaa2df6e9f96245a0e99edeb29a8b28c39c79b1 Mon Sep 17 00:00:00 2001 From: Sergey Chupligin Date: Tue, 14 Jun 2022 15:35:59 +0300 Subject: src/gtk Update gtk part to version 3.24.8 Fixes https://github.com/AyatanaIndicators/qmenumodel/issues/22 --- libqmenumodel/src/gtk/gtkactionmuxer.c | 211 ++++++++++++++++++++++++++++++--- 1 file changed, 192 insertions(+), 19 deletions(-) (limited to 'libqmenumodel/src/gtk/gtkactionmuxer.c') diff --git a/libqmenumodel/src/gtk/gtkactionmuxer.c b/libqmenumodel/src/gtk/gtkactionmuxer.c index 4618564..3080b4b 100644 --- a/libqmenumodel/src/gtk/gtkactionmuxer.c +++ b/libqmenumodel/src/gtk/gtkactionmuxer.c @@ -26,7 +26,7 @@ #include -/** +/*< private > * SECTION:gtkactionmuxer * @short_description: Aggregate and monitor several action groups * @@ -37,19 +37,19 @@ * particular context into a single action group, with namespacing. * * Consider the case of two action groups -- one containing actions - * applicable to an entire application (such as 'quit') and one + * applicable to an entire application (such as “quit”) and one * containing actions applicable to a particular window in the - * application (such as 'fullscreen'). + * application (such as “fullscreen”). * * In this case, each of these action groups could be added to a - * #GtkActionMuxer with the prefixes "app" and "win", respectively. This - * would expose the actions as "app.quit" and "win.fullscreen" on the + * #GtkActionMuxer with the prefixes “app” and “win”, respectively. This + * would expose the actions as “app.quit” and “win.fullscreen” on the * #GActionGroup interface presented by the #GtkActionMuxer. * * Activations and state change requests on the #GtkActionMuxer are wired * through to the underlying action group in the expected way. * - * This class is typically only used at the site of "consumption" of + * This class is typically only used at the site of “consumption” of * actions (eg: when displaying a menu that contains many actions on * different objects). */ @@ -65,6 +65,7 @@ struct _GtkActionMuxer GHashTable *observed_actions; GHashTable *groups; + GHashTable *primary_accels; GtkActionMuxer *parent; }; @@ -81,6 +82,8 @@ enum static GParamSpec *properties[NUM_PROPERTIES]; +guint accel_signal; + typedef struct { GtkActionMuxer *muxer; @@ -134,7 +137,7 @@ gtk_action_muxer_list_actions (GActionGroup *action_group) actions); } - return (gchar **) g_array_free (actions, FALSE); + return (gchar **)(void *) g_array_free (actions, FALSE); } static Group * @@ -333,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, @@ -498,6 +534,8 @@ gtk_action_muxer_finalize (GObject *object) g_assert_cmpint (g_hash_table_size (muxer->observed_actions), ==, 0); g_hash_table_unref (muxer->observed_actions); g_hash_table_unref (muxer->groups); + if (muxer->primary_accels) + g_hash_table_unref (muxer->primary_accels); G_OBJECT_CLASS (gtk_action_muxer_parent_class) ->finalize (object); @@ -514,6 +552,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); } @@ -593,6 +632,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, @@ -602,7 +644,7 @@ gtk_action_muxer_class_init (GObjectClass *class) g_object_class_install_properties (class, NUM_PROPERTIES, properties); } -/** +/*< private > * gtk_action_muxer_insert: * @muxer: a #GtkActionMuxer * @prefix: the prefix string for the action group @@ -610,15 +652,15 @@ gtk_action_muxer_class_init (GObjectClass *class) * * Adds the actions in @action_group to the list of actions provided by * @muxer. @prefix is prefixed to each action name, such that for each - * action x in @action_group, there is an equivalent - * action @prefix.x in @muxer. + * action `x` in @action_group, there is an equivalent + * action @prefix`.x` in @muxer. * - * For example, if @prefix is "app" and @action_group - * contains an action called "quit", then @muxer will - * now contain an action called "app.quit". + * For example, if @prefix is “`app`” and @action_group + * contains an action called “`quit`”, then @muxer will + * now contain an action called “`app.quit`”. * * If any #GtkActionObservers are registered for actions in the group, - * "action_added" notifications will be emitted, as appropriate. + * “action_added” notifications will be emitted, as appropriate. * * @prefix must not contain a dot ('.'). */ @@ -656,7 +698,7 @@ gtk_action_muxer_insert (GtkActionMuxer *muxer, G_CALLBACK (gtk_action_muxer_group_action_state_changed), group); } -/** +/*< private > * gtk_action_muxer_remove: * @muxer: a #GtkActionMuxer * @prefix: the prefix of the action group to remove @@ -664,7 +706,7 @@ gtk_action_muxer_insert (GtkActionMuxer *muxer, * Removes a #GActionGroup from the #GtkActionMuxer. * * If any #GtkActionObservers are registered for actions in the group, - * "action_removed" notifications will be emitted, as appropriate. + * “action_removed” notifications will be emitted, as appropriate. */ void gtk_action_muxer_remove (GtkActionMuxer *muxer, @@ -690,7 +732,27 @@ gtk_action_muxer_remove (GtkActionMuxer *muxer, } } -/** +const gchar ** +gtk_action_muxer_list_prefixes (GtkActionMuxer *muxer) +{ + return (const gchar **) g_hash_table_get_keys_as_array (muxer->groups, NULL); +} + +GActionGroup * +gtk_action_muxer_lookup (GtkActionMuxer *muxer, + const gchar *prefix) +{ + Group *group; + + group = g_hash_table_lookup (muxer->groups, prefix); + + if (group != NULL) + return group->group; + + return NULL; +} + +/*< private > * gtk_action_muxer_new: * * Creates a new #GtkActionMuxer. @@ -701,7 +763,7 @@ gtk_action_muxer_new (void) return g_object_new (GTK_TYPE_ACTION_MUXER, NULL); } -/** +/*< private > * gtk_action_muxer_get_parent: * @muxer: a #GtkActionMuxer * @@ -715,7 +777,27 @@ 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; + } +} + +/*< private > * gtk_action_muxer_set_parent: * @muxer: a #GtkActionMuxer * @parent: (allow-none): the new parent #GtkActionMuxer @@ -742,10 +824,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); } @@ -764,6 +849,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", @@ -772,7 +859,93 @@ 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); +} + +gchar * +gtk_normalise_detailed_action_name (const gchar *detailed_action_name) +{ + GError *error = NULL; + gchar *action_and_target; + gchar *action_name; + GVariant *target; + + g_action_parse_detailed_name (detailed_action_name, &action_name, &target, &error); + g_assert_no_error (error); + + action_and_target = gtk_print_action_and_target (NULL, action_name, target); + + if (target) + g_variant_unref (target); + + g_free (action_name); + + return action_and_target; +} -- cgit v1.2.3