From d9b9fa0acd345dd7386fae72ae5613ecbd8c8c91 Mon Sep 17 00:00:00 2001 From: Jehan Date: Mon, 3 Apr 2023 22:48:26 +0200 Subject: [PATCH] app: only GimpUIManager's actions should be application actions. --- app/widgets/gimpaction.c | 51 +++++-------- app/widgets/gimpaction.h | 2 +- app/widgets/gimpactiongroup.c | 25 +++---- app/widgets/gimpactionview.c | 8 +- app/widgets/gimpuimanager.c | 133 ++++++++++++++++++++++++++++------ 5 files changed, 141 insertions(+), 78 deletions(-) diff --git a/app/widgets/gimpaction.c b/app/widgets/gimpaction.c index 8d1f245acc..befc3c20dd 100644 --- a/app/widgets/gimpaction.c +++ b/app/widgets/gimpaction.c @@ -69,6 +69,8 @@ struct _GimpActionPrivate gchar *icon_name; GIcon *icon; + gchar **accels; + GimpRGB *color; GimpViewable *viewable; PangoEllipsizeMode ellipsize; @@ -206,6 +208,7 @@ gimp_action_init (GimpAction *action) priv->tooltip = NULL; priv->icon_name = NULL; priv->icon = NULL; + priv->accels = NULL; priv->ellipsize = PANGO_ELLIPSIZE_NONE; priv->max_width_chars = -1; priv->proxies = NULL; @@ -493,24 +496,16 @@ void gimp_action_set_accels (GimpAction *action, const gchar **accels) { - GimpContext *context; - gchar *detailed_action_name; + GimpActionPrivate *priv = GET_PRIVATE (action); g_return_if_fail (GIMP_IS_ACTION (action)); - context = GET_PRIVATE (action)->context; - - if (context == NULL) + if (accels != NULL && priv->accels != NULL && + g_strv_equal (accels, (const gchar **) priv->accels)) return; - g_return_if_fail (GTK_IS_APPLICATION (context->gimp->app)); - - detailed_action_name = g_strdup_printf ("app.%s", - g_action_get_name (G_ACTION (action))); - gtk_application_set_accels_for_action (GTK_APPLICATION (context->gimp->app), - detailed_action_name, - accels); - g_free (detailed_action_name); + g_strfreev (priv->accels); + priv->accels = g_strdupv ((gchar **) accels); g_signal_emit (action, action_signals[ACCELS_CHANGED], 0, accels); } @@ -525,29 +520,15 @@ gimp_action_set_accels (GimpAction *action, * Returns: (transfer full): accelerators for @action, as a %NULL-terminated * array. Free with g_strfreev() when no longer needed */ -gchar ** +const gchar ** gimp_action_get_accels (GimpAction *action) { - gchar **accels; - GimpContext *context; - gchar *detailed_action_name; - g_return_val_if_fail (GIMP_IS_ACTION (action), NULL); - context = GET_PRIVATE (action)->context; - - if (context == NULL) - return NULL; - - g_return_val_if_fail (GTK_IS_APPLICATION (context->gimp->app), NULL); - - detailed_action_name = g_strdup_printf ("app.%s", - g_action_get_name (G_ACTION (action))); - accels = gtk_application_get_accels_for_action (GTK_APPLICATION (context->gimp->app), - detailed_action_name); - g_free (detailed_action_name); - - return accels; + if (GET_PRIVATE (action)->accels != NULL) + return (const gchar **) GET_PRIVATE (action)->accels; + else + return (const gchar **) { NULL }; } /** @@ -568,9 +549,9 @@ gimp_action_get_display_accels (GimpAction *action) g_return_val_if_fail (GIMP_IS_ACTION (action), NULL); - accels = gimp_action_get_accels (action); + accels = g_strdupv (GET_PRIVATE (action)->accels); - for (i = 0; accels[i] != NULL; i++) + for (i = 0; accels != NULL && accels[i] != NULL; i++) { guint accel_key = 0; GdkModifierType accel_mods = 0; @@ -1086,6 +1067,8 @@ gimp_action_private_finalize (GimpActionPrivate *priv) g_free (priv->icon_name); g_clear_object (&priv->icon); + g_strfreev (priv->accels); + for (GList *iter = priv->proxies; iter; iter = iter->next) { /* TODO GAction: if an action associated to a proxy menu item disappears, diff --git a/app/widgets/gimpaction.h b/app/widgets/gimpaction.h index d339e7088c..0674fbff05 100644 --- a/app/widgets/gimpaction.h +++ b/app/widgets/gimpaction.h @@ -109,7 +109,7 @@ gboolean gimp_action_is_sensitive (GimpAction *action, void gimp_action_set_accels (GimpAction *action, const gchar **accels); -gchar ** gimp_action_get_accels (GimpAction *action); +const gchar ** gimp_action_get_accels (GimpAction *action); gchar ** gimp_action_get_display_accels (GimpAction *action); void gimp_action_activate (GimpAction *action); diff --git a/app/widgets/gimpactiongroup.c b/app/widgets/gimpactiongroup.c index 640b4572db..fa91e2fe10 100644 --- a/app/widgets/gimpactiongroup.c +++ b/app/widgets/gimpactiongroup.c @@ -197,6 +197,7 @@ gimp_action_group_finalize (GObject *object) g_clear_pointer (&group->label, g_free); g_clear_pointer (&group->icon_name, g_free); + g_list_free_full (group->actions, g_object_unref); G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -377,15 +378,13 @@ gimp_action_group_add_action_with_accel (GimpActionGroup *group, GimpAction *action, const gchar *accelerator) { - - /* Making sure all our Gimp*Action classes are also GAction. */ - g_return_if_fail (G_IS_ACTION (action)); + g_return_if_fail (GIMP_IS_ACTION (action)); if (! g_list_find (group->actions, action)) { - group->actions = g_list_prepend (group->actions, action); + group->actions = g_list_prepend (group->actions, g_object_ref (action)); - g_action_map_add_action (G_ACTION_MAP (group->gimp->app), G_ACTION (action)); + g_signal_emit_by_name (group, "action-added", gimp_action_get_name (action)); if ((accelerator != NULL && g_strcmp0 (accelerator, "") != 0)) gimp_action_set_accels (action, (const char*[]) { accelerator, NULL }); @@ -396,9 +395,12 @@ void gimp_action_group_remove_action (GimpActionGroup *group, GimpAction *action) { - group->actions = g_list_remove (group->actions, action); - - g_signal_emit_by_name (group, "action-removed", gimp_action_get_name (action)); + if (g_list_find (group->actions, action)) + { + group->actions = g_list_remove (group->actions, action); + g_signal_emit_by_name (group, "action-removed", gimp_action_get_name (action)); + g_object_unref (action); + } } GimpAction * @@ -498,7 +500,6 @@ gimp_action_group_add_actions (GimpActionGroup *group, gimp_action_group_add_action_with_accel (group, GIMP_ACTION (action), entries[i].accelerator); - g_signal_emit_by_name (group, "action-added", entries[i].name); g_object_unref (action); } @@ -556,7 +557,6 @@ gimp_action_group_add_toggle_actions (GimpActionGroup *group, gimp_action_group_add_action_with_accel (group, GIMP_ACTION (action), entries[i].accelerator); - g_signal_emit_by_name (group, "action-added", entries[i].name); g_object_unref (action); } @@ -619,7 +619,6 @@ gimp_action_group_add_radio_actions (GimpActionGroup *group, gimp_toggle_action_set_active (GIMP_TOGGLE_ACTION (action), TRUE); gimp_action_group_add_action_with_accel (group, action, entries[i].accelerator); - g_signal_emit_by_name (group, "action-added", entries[i].name); g_object_unref (action); } @@ -685,7 +684,6 @@ gimp_action_group_add_enum_actions (GimpActionGroup *group, gimp_action_group_add_action_with_accel (group, GIMP_ACTION (action), entries[i].accelerator); - g_signal_emit_by_name (group, "action-added", entries[i].name); g_object_unref (action); } @@ -750,7 +748,6 @@ gimp_action_group_add_string_actions (GimpActionGroup *group, g_object_ref (action); } - g_signal_emit_by_name (group, "action-added", entries[i].name); g_object_unref (action); } } @@ -806,7 +803,6 @@ gimp_action_group_add_double_actions (GimpActionGroup *group, gimp_action_group_add_action_with_accel (group, GIMP_ACTION (action), entries[i].accelerator); - g_signal_emit_by_name (group, "action-added", entries[i].name); g_object_unref (action); } @@ -861,7 +857,6 @@ gimp_action_group_add_procedure_actions (GimpActionGroup *group, gimp_action_group_add_action_with_accel (group, GIMP_ACTION (action), entries[i].accelerator); - g_signal_emit_by_name (group, "action-added", entries[i].name); g_object_unref (action); } diff --git a/app/widgets/gimpactionview.c b/app/widgets/gimpactionview.c index 53c997eee4..2c4be671f3 100644 --- a/app/widgets/gimpactionview.c +++ b/app/widgets/gimpactionview.c @@ -204,15 +204,13 @@ gimp_action_view_new (Gimp *gimp, if (show_shortcuts) { - gchar **accels = NULL; + const gchar **accels = NULL; accels = gimp_action_get_accels (GIMP_ACTION (action)); - /* TODO: support multiple accelerators! */ + /* TODO GAction: support multiple accelerators! */ if (accels && accels[0]) gtk_accelerator_parse (accels[0], &accel_key, &accel_mask); - - g_strfreev (accels); } gtk_tree_store_append (store, &action_iter, &group_iter); @@ -506,7 +504,7 @@ gimp_action_view_accels_changed (GimpAction *action, if (it_action == action) { - gchar **accels; + const gchar **accels; guint accel_key = 0; GdkModifierType accel_mask = 0; diff --git a/app/widgets/gimpuimanager.c b/app/widgets/gimpuimanager.c index 66c694a1b2..75aeb4a067 100644 --- a/app/widgets/gimpuimanager.c +++ b/app/widgets/gimpuimanager.c @@ -72,33 +72,43 @@ typedef struct } GimpUIManagerMenuItem; -static void gimp_ui_manager_constructed (GObject *object); -static void gimp_ui_manager_dispose (GObject *object); -static void gimp_ui_manager_finalize (GObject *object); -static void gimp_ui_manager_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); -static void gimp_ui_manager_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); -static void gimp_ui_manager_real_update (GimpUIManager *manager, - gpointer update_data); +static void gimp_ui_manager_constructed (GObject *object); +static void gimp_ui_manager_dispose (GObject *object); +static void gimp_ui_manager_finalize (GObject *object); +static void gimp_ui_manager_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void gimp_ui_manager_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void gimp_ui_manager_real_update (GimpUIManager *manager, + gpointer update_data); static GimpUIManagerUIEntry * - gimp_ui_manager_entry_get (GimpUIManager *manager, - const gchar *ui_path); + gimp_ui_manager_entry_get (GimpUIManager *manager, + const gchar *ui_path); static GimpUIManagerUIEntry * - gimp_ui_manager_entry_ensure (GimpUIManager *manager, - const gchar *path); -static void gimp_ui_manager_delete_popdown_data (GtkWidget *widget, - GimpUIManager *manager); + gimp_ui_manager_entry_ensure (GimpUIManager *manager, + const gchar *path); +static void gimp_ui_manager_delete_popdown_data (GtkWidget *widget, + GimpUIManager *manager); -static void gimp_ui_manager_menu_item_free (GimpUIManagerMenuItem *item); +static void gimp_ui_manager_menu_item_free (GimpUIManagerMenuItem *item); -static void gimp_ui_manager_popup_hidden (GtkMenuShell *popup, - gpointer user_data); -static gboolean gimp_ui_manager_popup_destroy (GtkWidget *popup); +static void gimp_ui_manager_popup_hidden (GtkMenuShell *popup, + gpointer user_data); +static gboolean gimp_ui_manager_popup_destroy (GtkWidget *popup); + +static void gimp_ui_manager_image_action_added (GimpActionGroup *group, + gchar *action_name, + GimpUIManager *manager); +static void gimp_ui_manager_image_action_removed (GimpActionGroup *group, + gchar *action_name, + GimpUIManager *manager); +static void gimp_ui_manager_image_accels_changed (GimpAction *action, + const gchar **accels, + GimpUIManager *manager); G_DEFINE_TYPE (GimpUIManager, gimp_ui_manager, GIMP_TYPE_OBJECT) @@ -393,6 +403,26 @@ gimp_ui_manager_add_action_group (GimpUIManager *manager, { if (! g_list_find (manager->action_groups, group)) manager->action_groups = g_list_prepend (manager->action_groups, g_object_ref (group)); + + /* Special-case the UI Manager which should be unique and represent + * global application actions. + */ + if (g_strcmp0 (manager->name, "") == 0) + { + gchar **actions = g_action_group_list_actions (G_ACTION_GROUP (group)); + + for (int i = 0; i < g_strv_length (actions); i++) + gimp_ui_manager_image_action_added (group, actions[i], manager); + + g_signal_connect_object (group, "action-added", + G_CALLBACK (gimp_ui_manager_image_action_added), + manager, 0); + g_signal_connect_object (group, "action-removed", + G_CALLBACK (gimp_ui_manager_image_action_removed), + manager, 0); + + g_strfreev (actions); + } } GimpActionGroup * @@ -931,3 +961,60 @@ gimp_ui_manager_popup_destroy (GtkWidget *popup) return G_SOURCE_REMOVE; } + +static void +gimp_ui_manager_image_action_added (GimpActionGroup *group, + gchar *action_name, + GimpUIManager *manager) +{ + GimpAction *action; + const gchar **accels; + + g_return_if_fail (GIMP_IS_UI_MANAGER (manager)); + /* The action should not already exist in the application. */ + g_return_if_fail (g_action_map_lookup_action (G_ACTION_MAP (manager->gimp->app), action_name) == NULL); + + action = gimp_action_group_get_action (group, action_name); + g_return_if_fail (action != NULL); + + g_action_map_add_action (G_ACTION_MAP (manager->gimp->app), G_ACTION (action)); + g_signal_connect_object (action, "accels-changed", + G_CALLBACK (gimp_ui_manager_image_accels_changed), + manager, 0); + + accels = gimp_action_get_accels (action); + if (accels && g_strv_length ((gchar **) accels) > 0) + gimp_ui_manager_image_accels_changed (action, gimp_action_get_accels (action), manager); +} + +static void +gimp_ui_manager_image_action_removed (GimpActionGroup *group, + gchar *action_name, + GimpUIManager *manager) +{ + GAction *action; + + action = g_action_map_lookup_action (G_ACTION_MAP (manager->gimp->app), action_name); + + if (action != NULL) + { + g_action_map_remove_action (G_ACTION_MAP (manager->gimp->app), action_name); + g_signal_handlers_disconnect_by_func (action, + G_CALLBACK (gimp_ui_manager_image_accels_changed), + manager); + } +} + +static void +gimp_ui_manager_image_accels_changed (GimpAction *action, + const gchar **accels, + GimpUIManager *manager) +{ + gchar *detailed_action_name; + + detailed_action_name = g_strdup_printf ("app.%s", g_action_get_name (G_ACTION (action))); + gtk_application_set_accels_for_action (GTK_APPLICATION (manager->gimp->app), + detailed_action_name, + accels); + g_free (detailed_action_name); +}