app: GimpAccelLabel now closure-free.

- New gimp_action_get_display_accels() added to GimpAction API to get directly
  the human-visible strings for actions.
- Also adding an "accels-changed" signal to GimpAction. As far as I can see,
  even though accelerators are now to be set on the GtkApplication, there seems
  to be no signals or properties to connect to at all on this class. So instead,
  let's do it on our GimpAction (which means we must absolutely not use
  gtk_application_set_accels_for_action()).
- GimpAccelLabel now uses the proper GimpAction API instead of accelerator
  closure which is a disappearing concept.
This commit is contained in:
Jehan 2023-02-05 22:23:20 +01:00
parent 9ff9d16367
commit 05968c35e5
3 changed files with 94 additions and 105 deletions

View File

@ -46,23 +46,17 @@ struct _GimpAccelLabelPrivate
/* local function prototypes */
static void gimp_accel_label_dispose (GObject *object);
static void gimp_accel_label_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void gimp_accel_label_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static void gimp_accel_label_dispose (GObject *object);
static void gimp_accel_label_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void gimp_accel_label_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static void gimp_accel_label_accel_changed (GtkAccelGroup *accel_group,
guint keyval,
GdkModifierType modifier,
GClosure *accel_closure,
GimpAccelLabel *accel_label);
static void gimp_accel_label_update (GimpAccelLabel *accel_label);
static void gimp_accel_label_update (GimpAccelLabel *accel_label);
G_DEFINE_TYPE_WITH_PRIVATE (GimpAccelLabel, gimp_accel_label, GTK_TYPE_LABEL)
@ -144,67 +138,22 @@ gimp_accel_label_get_property (GObject *object,
}
}
static void
gimp_accel_label_accel_changed (GtkAccelGroup *accel_group,
guint keyval,
GdkModifierType modifier,
GClosure *accel_closure,
GimpAccelLabel *accel_label)
{
if (accel_closure ==
gimp_action_get_accel_closure (accel_label->priv->action))
{
gimp_accel_label_update (accel_label);
}
}
static gboolean
gimp_accel_label_update_accel_find_func (GtkAccelKey *key,
GClosure *closure,
gpointer data)
{
return (GClosure *) data == closure;
}
static void
gimp_accel_label_update (GimpAccelLabel *accel_label)
{
GClosure *accel_closure;
GtkAccelGroup *accel_group;
GtkAccelKey *accel_key;
gchar **accels;
gtk_label_set_label (GTK_LABEL (accel_label), NULL);
if (! accel_label->priv->action)
return;
accel_closure = gimp_action_get_accel_closure (accel_label->priv->action);
accels = gimp_action_get_display_accels (accel_label->priv->action);
if (! accel_closure)
return;
if (accels && accels[0])
gtk_label_set_label (GTK_LABEL (accel_label), accels[0]);
accel_group = gtk_accel_group_from_accel_closure (accel_closure);
if (! accel_group)
return;
accel_key = gtk_accel_group_find (accel_group,
gimp_accel_label_update_accel_find_func,
accel_closure);
if (accel_key &&
accel_key->accel_key &&
(accel_key->accel_flags & GTK_ACCEL_VISIBLE))
{
gchar *label;
label = gtk_accelerator_get_label (accel_key->accel_key,
accel_key->accel_mods);
gtk_label_set_label (GTK_LABEL (accel_label), label);
g_free (label);
}
g_strfreev (accels);
}
@ -230,45 +179,16 @@ gimp_accel_label_set_action (GimpAccelLabel *accel_label,
if (action != accel_label->priv->action)
{
if (accel_label->priv->action)
{
GClosure *accel_closure;
accel_closure = gimp_action_get_accel_closure (
accel_label->priv->action);
if (accel_closure)
{
GtkAccelGroup *accel_group;
accel_group = gtk_accel_group_from_accel_closure (accel_closure);
g_signal_handlers_disconnect_by_func (
accel_group,
gimp_accel_label_accel_changed,
accel_label);
}
}
g_signal_handlers_disconnect_by_func (accel_label->priv->action,
gimp_accel_label_update,
accel_label);
g_set_object (&accel_label->priv->action, action);
if (accel_label->priv->action)
{
GClosure *accel_closure;
accel_closure = gimp_action_get_accel_closure (
accel_label->priv->action);
if (accel_closure)
{
GtkAccelGroup *accel_group;
accel_group = gtk_accel_group_from_accel_closure (accel_closure);
g_signal_connect (accel_group, "accel-changed",
G_CALLBACK (gimp_accel_label_accel_changed),
accel_label);
}
}
g_signal_connect_swapped (action, "accels-changed",
G_CALLBACK (gimp_accel_label_update),
accel_label);
gimp_accel_label_update (accel_label);

View File

@ -45,6 +45,7 @@ enum
{
ACTIVATE,
CHANGE_STATE,
ACCELS_CHANGED,
LAST_SIGNAL
};
@ -105,6 +106,15 @@ gimp_action_default_init (GimpActionInterface *iface)
G_TYPE_NONE, 1,
G_TYPE_VARIANT);
action_signals[ACCELS_CHANGED] =
g_signal_new ("accels-changed",
G_TYPE_FROM_INTERFACE (iface),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (GimpActionInterface, accels_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 1,
G_TYPE_STRV);
g_object_interface_install_property (iface,
g_param_spec_object ("context",
NULL, NULL,
@ -407,6 +417,19 @@ gimp_action_connect_accelerator (GimpAction *action)
gtk_action_connect_accelerator ((GtkAction *) action);
}
/**
* gimp_action_set_accels:
* @action: a #GimpAction
* @accels: accelerators in the format understood by gtk_accelerator_parse().
* The first accelerator is the main one.
*
* Set the accelerators to be associated with the given @action.
*
* Note that the #GimpAction API will emit the signal "accels-changed" whereas
* GtkApplication has no signal (that we could find) to connect to. It means we
* must always change accelerators with this function.
* Never use gtk_application_set_accels_for_action() directly!
*/
void
gimp_action_set_accels (GimpAction *action,
const gchar **accels)
@ -426,6 +449,8 @@ gimp_action_set_accels (GimpAction *action,
detailed_action_name,
accels);
g_free (detailed_action_name);
g_signal_emit (action, action_signals[ACCELS_CHANGED], 0, accels);
}
/**
@ -460,6 +485,47 @@ gimp_action_get_accels (GimpAction *action)
return accels;
}
/**
* gimp_action_get_display_accels:
* @action: a #GimpAction
*
* Gets the accelerators that are currently associated with the given @action,
* in a format which can be presented to people on the GUI.
*
* Returns: (transfer full): accelerators for @action, as a %NULL-terminated
* array. Free with g_strfreev() when no longer needed
*/
gchar **
gimp_action_get_display_accels (GimpAction *action)
{
gchar **accels;
gint i;
g_return_val_if_fail (GIMP_IS_ACTION (action), NULL);
accels = gimp_action_get_accels (action);
for (i = 0; accels[i] != NULL; i++)
{
guint accel_key = 0;
GdkModifierType accel_mods = 0;
gtk_accelerator_parse (accels[i], &accel_key, &accel_mods);
if (accel_key != 0 || accel_mods != 0)
{
gchar *accel;
accel = gtk_accelerator_get_label (accel_key, accel_mods);
g_free (accels[i]);
accels[i] = accel;
}
}
return accels;
}
GSList *
gimp_action_get_proxies (GimpAction *action)
{

View File

@ -47,10 +47,12 @@ struct _GimpActionInterface
GTypeInterface base_interface;
/* Signals */
void (* activate) (GimpAction *action,
GVariant *value);
void (* change_state) (GimpAction *action,
GVariant *value);
void (* activate) (GimpAction *action,
GVariant *value);
void (* change_state) (GimpAction *action,
GVariant *value);
void (* accels_changed) (GimpAction *action,
const gchar **accels);
};
@ -114,6 +116,7 @@ void gimp_action_connect_accelerator (GimpAction *action);
void gimp_action_set_accels (GimpAction *action,
const gchar **accels);
gchar ** gimp_action_get_accels (GimpAction *action);
gchar ** gimp_action_get_display_accels (GimpAction *action);
GSList * gimp_action_get_proxies (GimpAction *action);