Turn GtkShortcutTrigger into an object

The lightweight inheritance mechanism used for GtkShortcutTrigger is not
going to be usable by bindings, because boxed types cannot have derived
types.

We could use GTypeInstance and derive everything from that, like
GParamSpec, but in the end shortcuts are not really a performance
critical paths, unlike CSS values or render nodes.
This commit is contained in:
Emmanuele Bassi 2020-03-19 15:57:02 +00:00 committed by Matthias Clasen
parent 1ddd8586dd
commit 457b6657bb
9 changed files with 654 additions and 378 deletions

View File

@ -118,9 +118,8 @@ gtk_application_accels_set_accels_for_action (GtkApplicationAccels *accels,
{
g_critical ("Unable to parse accelerator '%s': ignored request to install accelerators",
accelerators[i]);
if (trigger)
gtk_shortcut_trigger_unref (trigger);
goto out;;
g_clear_object (&trigger);
goto out;
}
new_trigger = gtk_keyval_trigger_new (key, modifier);
if (trigger)
@ -146,23 +145,23 @@ static void
append_accelerators (GPtrArray *accels,
GtkShortcutTrigger *trigger)
{
switch (gtk_shortcut_trigger_get_trigger_type (trigger))
if (GTK_IS_KEYVAL_TRIGGER (trigger))
{
case GTK_SHORTCUT_TRIGGER_KEYVAL:
g_ptr_array_add (accels,
gtk_accelerator_name (gtk_keyval_trigger_get_keyval (trigger),
gtk_keyval_trigger_get_modifiers (trigger)));
return;
GtkKeyvalTrigger *kt = GTK_KEYVAL_TRIGGER (trigger);
guint keyval = gtk_keyval_trigger_get_keyval (kt);
GdkModifierType mods = gtk_keyval_trigger_get_modifiers (kt);
case GTK_SHORTCUT_TRIGGER_ALTERNATIVE:
append_accelerators (accels, gtk_alternative_trigger_get_first (trigger));
append_accelerators (accels, gtk_alternative_trigger_get_second (trigger));
g_ptr_array_add (accels, gtk_accelerator_name (keyval, mods));
return;
}
else if (GTK_IS_ALTERNATIVE_TRIGGER (trigger))
{
GtkAlternativeTrigger *at = GTK_ALTERNATIVE_TRIGGER (trigger);
GtkShortcutTrigger *first = gtk_alternative_trigger_get_first (at);
GtkShortcutTrigger *second = gtk_alternative_trigger_get_second (at);
case GTK_SHORTCUT_TRIGGER_MNEMONIC:
case GTK_SHORTCUT_TRIGGER_NEVER:
default:
/* not an accelerator */
append_accelerators (accels, first);
append_accelerators (accels, second);
return;
}
}
@ -217,19 +216,22 @@ trigger_matches_accel (GtkShortcutTrigger *trigger,
guint keyval,
GdkModifierType modifiers)
{
switch (gtk_shortcut_trigger_get_trigger_type (trigger))
if (GTK_IS_KEYVAL_TRIGGER (trigger))
{
case GTK_SHORTCUT_TRIGGER_KEYVAL:
return gtk_keyval_trigger_get_keyval (trigger) == keyval
&& gtk_keyval_trigger_get_modifiers (trigger) == modifiers;
GtkKeyvalTrigger *kt = GTK_KEYVAL_TRIGGER (trigger);
case GTK_SHORTCUT_TRIGGER_ALTERNATIVE:
return trigger_matches_accel (gtk_alternative_trigger_get_first (trigger), keyval, modifiers)
|| trigger_matches_accel (gtk_alternative_trigger_get_second (trigger), keyval, modifiers);
return gtk_keyval_trigger_get_keyval (kt) == keyval
&& gtk_keyval_trigger_get_modifiers (kt) == modifiers;
}
else if (GTK_IS_ALTERNATIVE_TRIGGER (trigger))
{
GtkAlternativeTrigger *at = GTK_ALTERNATIVE_TRIGGER (trigger);
case GTK_SHORTCUT_TRIGGER_MNEMONIC:
case GTK_SHORTCUT_TRIGGER_NEVER:
default:
return trigger_matches_accel (gtk_alternative_trigger_get_first (at), keyval, modifiers)
|| trigger_matches_accel (gtk_alternative_trigger_get_second (at), keyval, modifiers);
}
else
{
return FALSE;
}
}

View File

@ -2102,7 +2102,7 @@ gtk_builder_value_from_string_type (GtkBuilder *builder,
GtkShortcutTrigger *trigger = gtk_shortcut_trigger_parse_string (string);
if (trigger)
g_value_take_boxed (value, trigger);
g_value_take_object (value, trigger);
else
{
g_set_error (error,

View File

@ -80,7 +80,7 @@ gtk_shortcut_dispose (GObject *object)
GtkShortcut *self = GTK_SHORTCUT (object);
g_clear_pointer (&self->action, gtk_shortcut_action_unref);
g_clear_pointer (&self->trigger, gtk_shortcut_trigger_unref);
g_clear_object (&self->trigger);
g_clear_pointer (&self->args, g_variant_unref);
G_OBJECT_CLASS (gtk_shortcut_parent_class)->dispose (object);
@ -105,7 +105,7 @@ gtk_shortcut_get_property (GObject *object,
break;
case PROP_TRIGGER:
g_value_set_boxed (value, self->trigger);
g_value_set_object (value, self->trigger);
break;
default:
@ -133,7 +133,7 @@ gtk_shortcut_set_property (GObject *object,
break;
case PROP_TRIGGER:
gtk_shortcut_set_trigger (self, g_value_dup_boxed (value));
gtk_shortcut_set_trigger (self, g_value_dup_object (value));
break;
default:
@ -182,11 +182,13 @@ gtk_shortcut_class_init (GtkShortcutClass *klass)
* The trigger that triggers this shortcut.
*/
properties[PROP_TRIGGER] =
g_param_spec_boxed ("trigger",
P_("Trigger"),
P_("The trigger for this shortcut"),
GTK_TYPE_SHORTCUT_TRIGGER,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
g_param_spec_object ("trigger",
P_("Trigger"),
P_("The trigger for this shortcut"),
GTK_TYPE_SHORTCUT_TRIGGER,
G_PARAM_READWRITE |
G_PARAM_EXPLICIT_NOTIFY |
G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (gobject_class, N_PROPS, properties);
}
@ -195,13 +197,13 @@ static void
gtk_shortcut_init (GtkShortcut *self)
{
self->action = gtk_nothing_action_new ();
self->trigger = gtk_shortcut_trigger_ref (gtk_never_trigger_get ());
self->trigger = g_object_ref (gtk_never_trigger_get ());
}
/**
* gtk_shortcut_new:
* @trigger: (transfer full) (allow-none): The trigger that will trigger the shortcut
* @action: (transfer full) (allow-none): The action that will be activated upon
* @trigger: (transfer full) (nullable): The trigger that will trigger the shortcut
* @action: (transfer full) (nullable): The action that will be activated upon
* triggering
*
* Creates a new #GtkShortcut that is triggered by @trigger and then activates
@ -221,7 +223,7 @@ gtk_shortcut_new (GtkShortcutTrigger *trigger,
NULL);
if (trigger)
gtk_shortcut_trigger_unref (trigger);
g_object_unref (trigger);
if (action)
gtk_shortcut_action_unref (action);
@ -230,8 +232,8 @@ gtk_shortcut_new (GtkShortcutTrigger *trigger,
/**
* gtk_shortcut_new_with_arguments: (skip)
* @trigger: (transfer full) (allow-none): The trigger that will trigger the shortcut
* @action: (transfer full) (allow-none): The action that will be activated upon
* @trigger: (transfer full) (nullable): The trigger that will trigger the shortcut
* @action: (transfer full) (nullable): The action that will be activated upon
* triggering
* @format_string: (allow-none): GVariant format string for arguments or %NULL for
* no arguments
@ -270,7 +272,7 @@ gtk_shortcut_new_with_arguments (GtkShortcutTrigger *trigger,
NULL);
if (trigger)
gtk_shortcut_trigger_unref (trigger);
g_object_unref (trigger);
if (action)
gtk_shortcut_action_unref (action);
@ -353,18 +355,13 @@ gtk_shortcut_set_trigger (GtkShortcut *self,
g_return_if_fail (GTK_IS_SHORTCUT (self));
if (trigger == NULL)
trigger = gtk_shortcut_trigger_ref (gtk_never_trigger_get ());
trigger = g_object_ref (gtk_never_trigger_get ());
if (self->trigger == trigger)
if (g_set_object (&self->trigger, trigger))
{
gtk_shortcut_trigger_unref (trigger);
return;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TRIGGER]);
g_object_unref (trigger);
}
gtk_shortcut_trigger_unref (self->trigger);
self->trigger = trigger;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TRIGGER]);
}
GVariant *

File diff suppressed because it is too large Load Diff

View File

@ -30,26 +30,11 @@ G_BEGIN_DECLS
#define GTK_TYPE_SHORTCUT_TRIGGER (gtk_shortcut_trigger_get_type ())
#define GTK_IS_SHORTCUT_TRIGGER(obj) ((obj) != NULL)
/**
* GtkShortcutTriggerType:
* @GTK_SHORTCUT_TRIGGER_NEVER: Never ever trigger
* @GTK_SHORTCUT_TRIGGER_KEYVAL: Trigger if a key event with matching
* modifiers and keyval is received.
* @GTK_SHORTCUT_TRIGGER_MNEMONIC: Trigger if a key event with matching
* keyval is received and mnemonics are enabled for this event.
* @GTK_SHORTCUT_TRIGGER_ALTERNAITVE: Trigger if either if two
* alternatives triggers
* GtkShortcutTrigger:
*
* The type of a trigger determines what the trigger triggers on.
**/
typedef enum {
GTK_SHORTCUT_TRIGGER_NEVER,
GTK_SHORTCUT_TRIGGER_KEYVAL,
GTK_SHORTCUT_TRIGGER_MNEMONIC,
GTK_SHORTCUT_TRIGGER_ALTERNATIVE
} GtkShortcutTriggerType;
* A trigger for a key shortcut.
*/
/**
* GtkShortcutTriggerMatch:
@ -71,15 +56,7 @@ typedef enum {
} GtkShortcutTriggerMatch;
GDK_AVAILABLE_IN_ALL
GType gtk_shortcut_trigger_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_ALL
GtkShortcutTrigger * gtk_shortcut_trigger_ref (GtkShortcutTrigger *self);
GDK_AVAILABLE_IN_ALL
void gtk_shortcut_trigger_unref (GtkShortcutTrigger *self);
GDK_AVAILABLE_IN_ALL
GtkShortcutTriggerType gtk_shortcut_trigger_get_trigger_type (GtkShortcutTrigger *self);
GDK_DECLARE_INTERNAL_TYPE (GtkShortcutTrigger, gtk_shortcut_trigger, GTK, SHORTCUT_TRIGGER, GObject)
GDK_AVAILABLE_IN_ALL
GtkShortcutTrigger * gtk_shortcut_trigger_parse_string (const char *string);
@ -111,29 +88,75 @@ GtkShortcutTriggerMatch gtk_shortcut_trigger_trigger (GtkShortcutTrig
GdkEvent *event,
gboolean enable_mnemonics);
#define GTK_TYPE_NEVER_TRIGGER (gtk_never_trigger_get_type())
/**
* GtkNeverTrigger:
*
* A #GtkShortcutTrigger that never triggers.
*/
GDK_AVAILABLE_IN_ALL
GDK_DECLARE_INTERNAL_TYPE (GtkNeverTrigger, gtk_never_trigger, GTK, NEVER_TRIGGER, GtkShortcutTrigger)
GDK_AVAILABLE_IN_ALL
GtkShortcutTrigger * gtk_never_trigger_get (void);
#define GTK_TYPE_KEYVAL_TRIGGER (gtk_keyval_trigger_get_type())
/**
* GtkKeyvalTrigger:
*
* A #GtkShortcutTrigger that triggers when a specific keyval
* and (optionally) modifiers are pressed.
*/
GDK_AVAILABLE_IN_ALL
GtkShortcutTrigger * gtk_keyval_trigger_new (guint keyval,
GdkModifierType modifiers);
GDK_DECLARE_INTERNAL_TYPE (GtkKeyvalTrigger, gtk_keyval_trigger, GTK, KEYVAL_TRIGGER, GtkShortcutTrigger)
GDK_AVAILABLE_IN_ALL
GdkModifierType gtk_keyval_trigger_get_modifiers (GtkShortcutTrigger *self);
GtkShortcutTrigger * gtk_keyval_trigger_new (guint keyval,
GdkModifierType modifiers);
GDK_AVAILABLE_IN_ALL
guint gtk_keyval_trigger_get_keyval (GtkShortcutTrigger *self);
GdkModifierType gtk_keyval_trigger_get_modifiers (GtkKeyvalTrigger *self);
GDK_AVAILABLE_IN_ALL
guint gtk_keyval_trigger_get_keyval (GtkKeyvalTrigger *self);
#define GTK_TYPE_MNEMONIC_TRIGGER (gtk_mnemonic_trigger_get_type())
/**
* GtkMnemonicTrigger:
*
* A #GtkShortcutTrigger that triggers when a specific mnemonic
* is pressed.
*/
GDK_AVAILABLE_IN_ALL
GDK_DECLARE_INTERNAL_TYPE (GtkMnemonicTrigger, gtk_mnemonic_trigger, GTK, MNEMONIC_TRIGGER, GtkShortcutTrigger)
GDK_AVAILABLE_IN_ALL
GtkShortcutTrigger * gtk_mnemonic_trigger_new (guint keyval);
GDK_AVAILABLE_IN_ALL
guint gtk_mnemonic_trigger_get_keyval (GtkShortcutTrigger *self);
guint gtk_mnemonic_trigger_get_keyval (GtkMnemonicTrigger *self);
#define GTK_TYPE_ALTERNATIVE_TRIGGER (gtk_alternative_trigger_get_type())
/**
* GtkAlternativeTrigger:
*
* A #GtkShortcutTrigger that triggers when either of two
* #GtkShortcutTriggers trigger.
*/
GDK_AVAILABLE_IN_ALL
GtkShortcutTrigger * gtk_alternative_trigger_new (GtkShortcutTrigger *one,
GtkShortcutTrigger *two);
GDK_DECLARE_INTERNAL_TYPE (GtkAlternativeTrigger, gtk_alternative_trigger, GTK, ALTERNATIVE_TRIGGER, GtkShortcutTrigger)
GDK_AVAILABLE_IN_ALL
GtkShortcutTrigger * gtk_alternative_trigger_get_first (GtkShortcutTrigger *self);
GtkShortcutTrigger * gtk_alternative_trigger_new (GtkShortcutTrigger *first,
GtkShortcutTrigger *second);
GDK_AVAILABLE_IN_ALL
GtkShortcutTrigger * gtk_alternative_trigger_get_second (GtkShortcutTrigger *self);
GtkShortcutTrigger * gtk_alternative_trigger_get_first (GtkAlternativeTrigger *self);
GDK_AVAILABLE_IN_ALL
GtkShortcutTrigger * gtk_alternative_trigger_get_second (GtkAlternativeTrigger *self);
G_END_DECLS

View File

@ -100,6 +100,9 @@ test_type (gconstpointer data)
g_str_equal (g_type_name (type), "GtkPlacesSidebar"))
return;
if (g_type_is_a (type, GTK_TYPE_SHORTCUT_TRIGGER))
return;
klass = g_type_class_ref (type);
if (g_type_is_a (type, GTK_TYPE_SETTINGS))

View File

@ -419,6 +419,10 @@ test_type (gconstpointer data)
if (g_type_is_a (type, GTK_TYPE_DRAG_ICON))
return;
/* these assert in constructed */
if (g_type_is_a (type, GTK_TYPE_ALTERNATIVE_TRIGGER))
return;
klass = g_type_class_ref (type);
if (g_type_is_a (type, GTK_TYPE_SETTINGS))
@ -459,6 +463,9 @@ test_type (gconstpointer data)
NULL);
g_object_unref (list_store);
}
/* special casing for singletons */
else if (g_type_is_a (type, GTK_TYPE_NEVER_TRIGGER))
instance = (GObject *) g_object_ref (gtk_never_trigger_get ());
else
instance = g_object_new (type, NULL);

View File

@ -171,7 +171,8 @@ main (int argc, char **argv)
#endif
/* Not allowed to finalize a GdkPixbufLoader without calling gdk_pixbuf_loader_close() */
all_types[i] != GDK_TYPE_PIXBUF_LOADER &&
all_types[i] != gdk_pixbuf_simple_anim_iter_get_type())
all_types[i] != gdk_pixbuf_simple_anim_iter_get_type() &&
!g_type_is_a (all_types[i], GTK_TYPE_SHORTCUT_TRIGGER))
{
gchar *test_path = g_strdup_printf ("/FinalizeObject/%s", g_type_name (all_types[i]));

View File

@ -84,18 +84,14 @@ test_trigger_basic (void)
trigger = gtk_never_trigger_get ();
g_assert_cmpint (gtk_shortcut_trigger_get_trigger_type (trigger), ==, GTK_SHORTCUT_TRIGGER_NEVER);
trigger = gtk_keyval_trigger_new (GDK_KEY_a, GDK_CONTROL_MASK);
g_assert_cmpint (gtk_shortcut_trigger_get_trigger_type (trigger), ==, GTK_SHORTCUT_TRIGGER_KEYVAL);
g_assert_cmpint (gtk_keyval_trigger_get_keyval (trigger), ==, GDK_KEY_a);
g_assert_cmpint (gtk_keyval_trigger_get_modifiers (trigger), ==, GDK_CONTROL_MASK);
gtk_shortcut_trigger_unref (trigger);
g_assert_cmpint (gtk_keyval_trigger_get_keyval (GTK_KEYVAL_TRIGGER (trigger)), ==, GDK_KEY_a);
g_assert_cmpint (gtk_keyval_trigger_get_modifiers (GTK_KEYVAL_TRIGGER (trigger)), ==, GDK_CONTROL_MASK);
g_object_unref (trigger);
trigger = gtk_mnemonic_trigger_new (GDK_KEY_u);
g_assert_cmpint (gtk_shortcut_trigger_get_trigger_type (trigger), ==, GTK_SHORTCUT_TRIGGER_MNEMONIC);
g_assert_cmpint (gtk_mnemonic_trigger_get_keyval (trigger), ==, GDK_KEY_u);
gtk_shortcut_trigger_unref (trigger);
g_assert_cmpint (gtk_mnemonic_trigger_get_keyval (GTK_MNEMONIC_TRIGGER (trigger)), ==, GDK_KEY_u);
g_object_unref (trigger);
}
static void
@ -105,14 +101,14 @@ test_trigger_equal (void)
GtkShortcutTrigger *trigger5, *trigger6, *trigger1a, *trigger2a;
trigger1 = gtk_keyval_trigger_new ('u', GDK_CONTROL_MASK);
trigger2 = gtk_shortcut_trigger_ref (gtk_never_trigger_get ());
trigger3 = gtk_alternative_trigger_new (gtk_shortcut_trigger_ref (trigger1), gtk_shortcut_trigger_ref (trigger2));
trigger4 = gtk_alternative_trigger_new (gtk_shortcut_trigger_ref (trigger2), gtk_shortcut_trigger_ref (trigger1));
trigger2 = g_object_ref (gtk_never_trigger_get ());
trigger3 = gtk_alternative_trigger_new (g_object_ref (trigger1), g_object_ref (trigger2));
trigger4 = gtk_alternative_trigger_new (g_object_ref (trigger2), g_object_ref (trigger1));
trigger5 = gtk_keyval_trigger_new ('u', GDK_SHIFT_MASK);
trigger6 = gtk_mnemonic_trigger_new ('u');
trigger1a = gtk_keyval_trigger_new ('u', GDK_CONTROL_MASK);
trigger2a = gtk_shortcut_trigger_ref (gtk_never_trigger_get ());
trigger2a = g_object_ref (gtk_never_trigger_get ());
g_assert_true (gtk_shortcut_trigger_equal (trigger1, trigger1));
g_assert_true (gtk_shortcut_trigger_equal (trigger2, trigger2));
@ -144,14 +140,14 @@ test_trigger_equal (void)
g_assert_true (gtk_shortcut_trigger_equal (trigger1, trigger1a));
g_assert_true (gtk_shortcut_trigger_equal (trigger2, trigger2a));
gtk_shortcut_trigger_unref (trigger1);
gtk_shortcut_trigger_unref (trigger2);
gtk_shortcut_trigger_unref (trigger3);
gtk_shortcut_trigger_unref (trigger4);
gtk_shortcut_trigger_unref (trigger5);
gtk_shortcut_trigger_unref (trigger6);
gtk_shortcut_trigger_unref (trigger1a);
gtk_shortcut_trigger_unref (trigger2a);
g_object_unref (trigger1);
g_object_unref (trigger2);
g_object_unref (trigger3);
g_object_unref (trigger4);
g_object_unref (trigger5);
g_object_unref (trigger6);
g_object_unref (trigger1a);
g_object_unref (trigger2a);
}
static void
@ -175,11 +171,12 @@ test_trigger_parse (void)
for (i = 0; i < G_N_ELEMENTS (tests); i++)
{
trigger = gtk_shortcut_trigger_parse_string (tests[i].str);
g_assert_cmpint (gtk_shortcut_trigger_get_trigger_type (trigger), ==, GTK_SHORTCUT_TRIGGER_KEYVAL);
g_assert_cmpint (gtk_keyval_trigger_get_modifiers (trigger), ==, tests[i].modifiers);
g_assert_cmpuint (gtk_keyval_trigger_get_keyval (trigger), ==, tests[i].keyval);
gtk_shortcut_trigger_unref (trigger);
g_assert_true (GTK_IS_KEYVAL_TRIGGER (trigger));
g_assert_cmpint (gtk_keyval_trigger_get_modifiers (GTK_KEYVAL_TRIGGER (trigger)), ==, tests[i].modifiers);
g_assert_cmpuint (gtk_keyval_trigger_get_keyval (GTK_KEYVAL_TRIGGER (trigger)), ==, tests[i].keyval);
g_object_unref (trigger);
}
}
@ -206,11 +203,11 @@ test_trigger_trigger (void)
};
int i, j;
trigger[0] = gtk_shortcut_trigger_ref (gtk_never_trigger_get ());
trigger[0] = g_object_ref (gtk_never_trigger_get ());
trigger[1] = gtk_keyval_trigger_new (GDK_KEY_a, GDK_CONTROL_MASK);
trigger[2] = gtk_mnemonic_trigger_new (GDK_KEY_u);
trigger[3] = gtk_alternative_trigger_new (gtk_shortcut_trigger_ref (trigger[1]),
gtk_shortcut_trigger_ref (trigger[2]));
trigger[3] = gtk_alternative_trigger_new (g_object_ref (trigger[1]),
g_object_ref (trigger[2]));
display = gdk_display_get_default ();
device = gdk_seat_get_keyboard (gdk_display_get_default_seat (display));
@ -244,10 +241,10 @@ test_trigger_trigger (void)
g_object_unref (surface);
gtk_shortcut_trigger_unref (trigger[0]);
gtk_shortcut_trigger_unref (trigger[1]);
gtk_shortcut_trigger_unref (trigger[2]);
gtk_shortcut_trigger_unref (trigger[3]);
g_object_unref (trigger[0]);
g_object_unref (trigger[1]);
g_object_unref (trigger[2]);
g_object_unref (trigger[3]);
}
static int callback_count;