[gtk/wip/ebassi/shortcut: 899/900] Turn GtkShortcutTrigger into an object



commit 2e02fa016de4b64e9c3164465ade864a3fe4b5e0
Author: Emmanuele Bassi <ebassi gnome org>
Date:   Thu Mar 19 15:57:02 2020 +0000

    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.

 gtk/gtkapplicationaccels.c |  54 ++--
 gtk/gtkbuilder.c           |   2 +-
 gtk/gtkshortcut.c          |  45 ++-
 gtk/gtkshortcuttrigger.c   | 741 +++++++++++++++++++++++++++++----------------
 gtk/gtkshortcuttrigger.h   |  96 +++---
 testsuite/gtk/shortcuts.c  |  61 ++--
 6 files changed, 621 insertions(+), 378 deletions(-)
---
diff --git a/gtk/gtkapplicationaccels.c b/gtk/gtkapplicationaccels.c
index e4e60bfc4b..03e315d567 100644
--- a/gtk/gtkapplicationaccels.c
+++ b/gtk/gtkapplicationaccels.c
@@ -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;
     }
 }
diff --git a/gtk/gtkbuilder.c b/gtk/gtkbuilder.c
index a101faab5c..9c032951d8 100644
--- a/gtk/gtkbuilder.c
+++ b/gtk/gtkbuilder.c
@@ -2101,7 +2101,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,
diff --git a/gtk/gtkshortcut.c b/gtk/gtkshortcut.c
index 6a7ff1a148..9f1cbdbe13 100644
--- a/gtk/gtkshortcut.c
+++ b/gtk/gtkshortcut.c
@@ -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 *
diff --git a/gtk/gtkshortcuttrigger.c b/gtk/gtkshortcuttrigger.c
index dce75a1191..756f639c66 100644
--- a/gtk/gtkshortcuttrigger.c
+++ b/gtk/gtkshortcuttrigger.c
@@ -1,6 +1,8 @@
 /*
  * Copyright © 2018 Benjamin Otte
  *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
@@ -40,25 +42,22 @@
 #include "gtkshortcuttrigger.h"
 
 #include "gtkaccelgroupprivate.h"
+#include "gtkintl.h"
 
-typedef struct _GtkShortcutTriggerClass GtkShortcutTriggerClass;
-
-#define GTK_IS_SHORTCUT_TRIGGER_TYPE(trigger,type) (GTK_IS_SHORTCUT_TRIGGER (trigger) && 
(trigger)->trigger_class->trigger_type == (type))
+#define GTK_SHORTCUT_TRIGGER_HASH_NEVER         0u
+#define GTK_SHORTCUT_TRIGGER_HASH_KEYVAL        1u
+#define GTK_SHORTCUT_TRIGGER_HASH_MNEMONIC      2u
+#define GTK_SHORTCUT_TRIGGER_HASH_ALTERNATIVE   3u
 
 struct _GtkShortcutTrigger
 {
-  const GtkShortcutTriggerClass *trigger_class;
-
-  gatomicrefcount ref_count;
+  GObject parent_instance;
 };
 
 struct _GtkShortcutTriggerClass
 {
-  GtkShortcutTriggerType trigger_type;
-  gsize struct_size;
-  const char *type_name;
+  GObjectClass parent_class;
 
-  void            (* finalize)    (GtkShortcutTrigger  *trigger);
   gboolean        (* trigger)     (GtkShortcutTrigger  *trigger,
                                    GdkEvent            *event,
                                    gboolean             enable_mnemonics);
@@ -72,90 +71,16 @@ struct _GtkShortcutTriggerClass
                                    GString             *string);
 };
 
-G_DEFINE_BOXED_TYPE (GtkShortcutTrigger, gtk_shortcut_trigger,
-                     gtk_shortcut_trigger_ref,
-                     gtk_shortcut_trigger_unref)
+G_DEFINE_ABSTRACT_TYPE (GtkShortcutTrigger, gtk_shortcut_trigger, G_TYPE_OBJECT)
 
 static void
-gtk_shortcut_trigger_finalize (GtkShortcutTrigger *self)
-{
-  self->trigger_class->finalize (self);
-
-  g_free (self);
-}
-
-/*< private >
- * gtk_shortcut_trigger_new:
- * @trigger_class: class structure for this trigger
- *
- * Returns: (transfer full): the newly created #GtkShortcutTrigger
- */
-static GtkShortcutTrigger *
-gtk_shortcut_trigger_new (const GtkShortcutTriggerClass *trigger_class)
-{
-  GtkShortcutTrigger *self;
-
-  g_return_val_if_fail (trigger_class != NULL, NULL);
-
-  self = g_malloc0 (trigger_class->struct_size);
-  g_atomic_ref_count_init (&self->ref_count);
-
-  self->trigger_class = trigger_class;
-
-  return self;
-}
-
-/**
- * gtk_shortcut_trigger_ref:
- * @self: a #GtkShortcutTrigger
- *
- * Acquires a reference on the given #GtkShortcutTrigger.
- *
- * Returns: (transfer full): the #GtkShortcutTrigger with
- *    an additional reference
- */
-GtkShortcutTrigger *
-gtk_shortcut_trigger_ref (GtkShortcutTrigger *self)
-{
-  g_return_val_if_fail (GTK_IS_SHORTCUT_TRIGGER (self), NULL);
-
-  g_atomic_ref_count_inc (&self->ref_count);
-
-  return self;
-}
-
-/**
- * gtk_shortcut_trigger_unref:
- * @self: (transfer full): a #GtkShortcutTrigger
- *
- * Releases a reference on the given #GtkShortcutTrigger.
- *
- * If the reference was the last, the resources associated
- * to the trigger are freed.
- */
-void
-gtk_shortcut_trigger_unref (GtkShortcutTrigger *self)
+gtk_shortcut_trigger_class_init (GtkShortcutTriggerClass *klass)
 {
-  g_return_if_fail (GTK_IS_SHORTCUT_TRIGGER (self));
-
-  if (g_atomic_ref_count_dec (&self->ref_count))
-    gtk_shortcut_trigger_finalize (self);
 }
 
-/**
- * gtk_shortcut_trigger_get_trigger_type:
- * @self: a #GtkShortcutTrigger
- *
- * Returns the type of the @trigger.
- *
- * Returns: the type of the #GtkShortcutTrigger
- */
-GtkShortcutTriggerType
-gtk_shortcut_trigger_get_trigger_type (GtkShortcutTrigger *self)
+static void
+gtk_shortcut_trigger_init (GtkShortcutTrigger *self)
 {
-  g_return_val_if_fail (GTK_IS_SHORTCUT_TRIGGER (self), GTK_SHORTCUT_TRIGGER_NEVER);
-
-  return self->trigger_class->trigger_type;
 }
 
 /**
@@ -170,7 +95,7 @@ gtk_shortcut_trigger_get_trigger_type (GtkShortcutTrigger *self)
  * returns %TRUE.
  *
  * Returns: %TRUE if this event triggered the trigger
- **/
+ */
 gboolean
 gtk_shortcut_trigger_trigger (GtkShortcutTrigger *self,
                               GdkEvent           *event,
@@ -178,24 +103,25 @@ gtk_shortcut_trigger_trigger (GtkShortcutTrigger *self,
 {
   g_return_val_if_fail (GTK_IS_SHORTCUT_TRIGGER (self), FALSE);
 
-  return self->trigger_class->trigger (self, event, enable_mnemonics);
+  return GTK_SHORTCUT_TRIGGER_GET_CLASS (self)->trigger (self, event, enable_mnemonics);
 }
 
 /**
- * gtk_shortcut_trigger_parse_string:
+ * gtk_shortcut_trigger_parse_string: (constructor)
  * @string: the string to parse
  *
  * Tries to parse the given string into a trigger. On success,
  * the parsed trigger is returned. When parsing failed, %NULL is
  * returned.
  *
- * FIXME: Document the supported format here once we've figured
- * it out.
- * For now, this function only supports gtk_accelerator_parse() and
- * can only return a trigger of type %GTK_SHORTCUT_TRIGGER_KEYVAL.
+ * The accepted strings are:
  *
- * Returns: a new #GtkShortcutTrigger or %NULL on error
- **/
+ *   - `never`, for #GtkNeverTrigger
+ *   - a string parsed by gtk_accelerator_parse(), for a #GtkKeyvalTrigger
+ *   - underscore, followed by a single character, for #GtkMnemonicTrigger
+ *
+ * Returns: (nullable): a new #GtkShortcutTrigger or %NULL on error
+ */
 GtkShortcutTrigger *
 gtk_shortcut_trigger_parse_string (const char *string)
 {
@@ -204,6 +130,15 @@ gtk_shortcut_trigger_parse_string (const char *string)
 
   g_return_val_if_fail (string != NULL, NULL);
 
+  if (g_str_equal (string, "never"))
+    return gtk_never_trigger_get ();
+
+  if (string[0] == '_')
+    {
+      if (gtk_accelerator_parse (string + 1, &keyval, &modifiers))
+        return gtk_mnemonic_trigger_new (keyval);
+    }
+
   if (gtk_accelerator_parse (string, &keyval, &modifiers))
     return gtk_keyval_trigger_new (keyval, modifiers);
 
@@ -219,7 +154,7 @@ gtk_shortcut_trigger_parse_string (const char *string)
  * to help when debugging.
  *
  * Returns: (transfer full): a new string
- **/
+ */
 char *
 gtk_shortcut_trigger_to_string (GtkShortcutTrigger *self)
 {
@@ -228,6 +163,7 @@ gtk_shortcut_trigger_to_string (GtkShortcutTrigger *self)
   g_return_val_if_fail (self != NULL, NULL);
 
   string = g_string_new (NULL);
+
   gtk_shortcut_trigger_print (self, string);
 
   return g_string_free (string, FALSE);
@@ -243,7 +179,7 @@ gtk_shortcut_trigger_to_string (GtkShortcutTrigger *self)
  *
  * The form of the representation may change at any time
  * and is not guaranteed to stay identical.
- **/
+ */
 void
 gtk_shortcut_trigger_print (GtkShortcutTrigger *self,
                             GString            *string)
@@ -251,7 +187,7 @@ gtk_shortcut_trigger_print (GtkShortcutTrigger *self,
   g_return_if_fail (GTK_IS_SHORTCUT_TRIGGER (self));
   g_return_if_fail (string != NULL);
 
-  return self->trigger_class->print (self, string);
+  GTK_SHORTCUT_TRIGGER_GET_CLASS (self)->print (self, string);
 }
 
 /**
@@ -316,7 +252,7 @@ gtk_shortcut_trigger_print_label (GtkShortcutTrigger *self,
   g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
   g_return_val_if_fail (string != NULL, FALSE);
 
-  return self->trigger_class->print_label (self, display, string);
+  return GTK_SHORTCUT_TRIGGER_GET_CLASS (self)->print_label (self, display, string);
 }
 
 /**
@@ -340,9 +276,9 @@ gtk_shortcut_trigger_hash (gconstpointer trigger)
 {
   GtkShortcutTrigger *t = (GtkShortcutTrigger *) trigger;
 
-  g_return_val_if_fail (GTK_IS_SHORTCUT_TRIGGER (trigger), 0);
+  g_return_val_if_fail (GTK_IS_SHORTCUT_TRIGGER (t), 0);
 
-  return t->trigger_class->hash (t);
+  return GTK_SHORTCUT_TRIGGER_GET_CLASS (t)->hash (t);
 }
 
 /**
@@ -384,31 +320,33 @@ gtk_shortcut_trigger_compare (gconstpointer trigger1,
   GtkShortcutTrigger *t1 = (GtkShortcutTrigger *) trigger1;
   GtkShortcutTrigger *t2 = (GtkShortcutTrigger *) trigger2;
 
-  g_return_val_if_fail (GTK_IS_SHORTCUT_TRIGGER (trigger1), -1);
-  g_return_val_if_fail (GTK_IS_SHORTCUT_TRIGGER (trigger2), 1);
-
-  if (t1->trigger_class != t2->trigger_class)
-    return t1->trigger_class->trigger_type - t2->trigger_class->trigger_type;
+  g_return_val_if_fail (GTK_IS_SHORTCUT_TRIGGER (t1), -1);
+  g_return_val_if_fail (GTK_IS_SHORTCUT_TRIGGER (t2), 1);
 
-  return t1->trigger_class->compare (t1, t2);
+  return GTK_SHORTCUT_TRIGGER_GET_CLASS (t1)->compare (t1, t2);
 }
 
-/*** GTK_SHORTCUT_TRIGGER_NEVER ***/
-
-typedef struct _GtkNeverTrigger GtkNeverTrigger;
-
 struct _GtkNeverTrigger
 {
-  GtkShortcutTrigger trigger;
+  GtkShortcutTrigger parent_instance;
 
   guint never;
   GdkModifierType modifiers;
 };
 
+struct _GtkNeverTriggerClass
+{
+  GtkShortcutTriggerClass parent_class;
+};
+
+G_DEFINE_TYPE (GtkNeverTrigger, gtk_never_trigger, GTK_TYPE_SHORTCUT_TRIGGER)
+
 static void
-gtk_never_trigger_finalize (GtkShortcutTrigger *trigger)
+gtk_never_trigger_finalize (GObject *gobject)
 {
   g_assert_not_reached ();
+
+  G_OBJECT_CLASS (gtk_never_trigger_parent_class)->finalize (gobject);
 }
 
 static gboolean
@@ -422,7 +360,7 @@ gtk_never_trigger_trigger (GtkShortcutTrigger *trigger,
 static guint
 gtk_never_trigger_hash (GtkShortcutTrigger *trigger)
 {
-  return GTK_SHORTCUT_TRIGGER_NEVER;
+  return GTK_SHORTCUT_TRIGGER_HASH_NEVER;
 }
 
 static int
@@ -448,19 +386,25 @@ gtk_never_trigger_print_label (GtkShortcutTrigger *trigger,
   return FALSE;
 }
 
-static const GtkShortcutTriggerClass GTK_NEVER_TRIGGER_CLASS = {
-  GTK_SHORTCUT_TRIGGER_NEVER,
-  sizeof (GtkNeverTrigger),
-  "GtkNeverTrigger",
-  gtk_never_trigger_finalize,
-  gtk_never_trigger_trigger,
-  gtk_never_trigger_hash,
-  gtk_never_trigger_compare,
-  gtk_never_trigger_print,
-  gtk_never_trigger_print_label
-};
+static void
+gtk_never_trigger_class_init (GtkNeverTriggerClass *klass)
+{
+  GtkShortcutTriggerClass *trigger_class = GTK_SHORTCUT_TRIGGER_CLASS (klass);
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->finalize = gtk_never_trigger_finalize;
+
+  trigger_class->trigger = gtk_never_trigger_trigger;
+  trigger_class->hash = gtk_never_trigger_hash;
+  trigger_class->compare = gtk_never_trigger_compare;
+  trigger_class->print = gtk_never_trigger_print;
+  trigger_class->print_label = gtk_never_trigger_print_label;
+}
 
-static GtkNeverTrigger never = { { &GTK_NEVER_TRIGGER_CLASS, 1 } };
+static void
+gtk_never_trigger_init (GtkNeverTrigger *self)
+{
+}
 
 /**
  * gtk_never_trigger_get:
@@ -469,37 +413,49 @@ static GtkNeverTrigger never = { { &GTK_NEVER_TRIGGER_CLASS, 1 } };
  * that never triggers. Use this trigger instead of %NULL
  * because it implements all virtual functions.
  *
- * Returns: (transfer none): The never trigger
+ * Returns: (type GtkNeverTrigger) (transfer none): The never trigger
  */
 GtkShortcutTrigger *
 gtk_never_trigger_get (void)
 {
-  return &never.trigger;
-}
+  static GtkShortcutTrigger *never = NULL;
 
-/*** GTK_KEYVAL_TRIGGER ***/
+  if (G_UNLIKELY (never == NULL))
+    never = g_object_new (GTK_TYPE_NEVER_TRIGGER, NULL);
 
-typedef struct _GtkKeyvalTrigger GtkKeyvalTrigger;
+  return never;
+}
 
 struct _GtkKeyvalTrigger
 {
-  GtkShortcutTrigger trigger;
+  GtkShortcutTrigger parent_instance;
 
   guint keyval;
   GdkModifierType modifiers;
 };
 
-static void
-gtk_keyval_trigger_finalize (GtkShortcutTrigger *trigger)
+struct _GtkKeyvalTriggerClass
 {
-}
+  GtkShortcutTriggerClass parent_class;
+};
+
+G_DEFINE_TYPE (GtkKeyvalTrigger, gtk_keyval_trigger, GTK_TYPE_SHORTCUT_TRIGGER)
+
+enum
+{
+  KEYVAL_PROP_KEYVAL = 1,
+  KEYVAL_PROP_MODIFIERS,
+  KEYVAL_N_PROPS
+};
+
+static GParamSpec *keyval_props[KEYVAL_N_PROPS];
 
 static gboolean
 gtk_keyval_trigger_trigger (GtkShortcutTrigger *trigger,
                             GdkEvent           *event,
                             gboolean            enable_mnemonics)
 {
-  GtkKeyvalTrigger *self = (GtkKeyvalTrigger *) trigger;
+  GtkKeyvalTrigger *self = GTK_KEYVAL_TRIGGER (trigger);
   GdkModifierType modifiers;
   guint keyval;
 
@@ -521,20 +477,20 @@ gtk_keyval_trigger_trigger (GtkShortcutTrigger *trigger,
 static guint
 gtk_keyval_trigger_hash (GtkShortcutTrigger *trigger)
 {
-  GtkKeyvalTrigger *self = (GtkKeyvalTrigger *) trigger;
+  GtkKeyvalTrigger *self = GTK_KEYVAL_TRIGGER (trigger);
 
   return (self->modifiers << 24)
        | (self->modifiers >> 8)
        | (self->keyval << 16)
-       | GTK_SHORTCUT_TRIGGER_KEYVAL;
+       | GTK_SHORTCUT_TRIGGER_HASH_KEYVAL;
 }
 
 static int
 gtk_keyval_trigger_compare (GtkShortcutTrigger  *trigger1,
                             GtkShortcutTrigger  *trigger2)
 {
-  GtkKeyvalTrigger *self1 = (GtkKeyvalTrigger *) trigger1;
-  GtkKeyvalTrigger *self2 = (GtkKeyvalTrigger *) trigger2;
+  GtkKeyvalTrigger *self1 = GTK_KEYVAL_TRIGGER (trigger1);
+  GtkKeyvalTrigger *self2 = GTK_KEYVAL_TRIGGER (trigger2);
 
   if (self1->modifiers != self2->modifiers)
     return self2->modifiers - self1->modifiers;
@@ -547,7 +503,7 @@ gtk_keyval_trigger_print (GtkShortcutTrigger *trigger,
                           GString            *string)
                   
 {
-  GtkKeyvalTrigger *self = (GtkKeyvalTrigger *) trigger;
+  GtkKeyvalTrigger *self = GTK_KEYVAL_TRIGGER (trigger);
   char *accelerator_name;
 
   accelerator_name = gtk_accelerator_name (self->keyval, self->modifiers);
@@ -560,24 +516,119 @@ gtk_keyval_trigger_print_label (GtkShortcutTrigger *trigger,
                                 GdkDisplay         *display,
                                 GString            *string)
 {
-  GtkKeyvalTrigger *self = (GtkKeyvalTrigger *) trigger;
+  GtkKeyvalTrigger *self = GTK_KEYVAL_TRIGGER (trigger);
 
   gtk_accelerator_print_label (string, self->keyval, self->modifiers);
 
   return TRUE;
 }
 
-static const GtkShortcutTriggerClass GTK_KEYVAL_TRIGGER_CLASS = {
-  GTK_SHORTCUT_TRIGGER_KEYVAL,
-  sizeof (GtkKeyvalTrigger),
-  "GtkKeyvalTrigger",
-  gtk_keyval_trigger_finalize,
-  gtk_keyval_trigger_trigger,
-  gtk_keyval_trigger_hash,
-  gtk_keyval_trigger_compare,
-  gtk_keyval_trigger_print,
-  gtk_keyval_trigger_print_label
-};
+static void
+gtk_keyval_trigger_set_property (GObject      *gobject,
+                                 guint         prop_id,
+                                 const GValue *value,
+                                 GParamSpec   *pspec)
+{
+  GtkKeyvalTrigger *self = GTK_KEYVAL_TRIGGER (gobject);
+
+  switch (prop_id)
+    {
+    case KEYVAL_PROP_KEYVAL:
+      {
+        guint keyval = g_value_get_uint (value);
+
+        /* We store keyvals as lower key */
+        if (keyval == GDK_KEY_ISO_Left_Tab)
+          self->keyval = GDK_KEY_Tab;
+        else
+          self->keyval = gdk_keyval_to_lower (keyval);
+      }
+      break;
+
+    case KEYVAL_PROP_MODIFIERS:
+      self->modifiers = g_value_get_flags (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+    }
+}
+
+static void
+gtk_keyval_trigger_get_property (GObject    *gobject,
+                                 guint       prop_id,
+                                 GValue     *value,
+                                 GParamSpec *pspec)
+{
+  GtkKeyvalTrigger *self = GTK_KEYVAL_TRIGGER (gobject);
+
+  switch (prop_id)
+    {
+    case KEYVAL_PROP_KEYVAL:
+      g_value_set_uint (value, self->keyval);
+      break;
+
+    case KEYVAL_PROP_MODIFIERS:
+      g_value_set_flags (value, self->modifiers);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+    }
+}
+
+static void
+gtk_keyval_trigger_class_init (GtkKeyvalTriggerClass *klass)
+{
+  GtkShortcutTriggerClass *trigger_class = GTK_SHORTCUT_TRIGGER_CLASS (klass);
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->set_property = gtk_keyval_trigger_set_property;
+  gobject_class->get_property = gtk_keyval_trigger_get_property;
+
+  trigger_class->trigger = gtk_keyval_trigger_trigger;
+  trigger_class->hash = gtk_keyval_trigger_hash;
+  trigger_class->compare = gtk_keyval_trigger_compare;
+  trigger_class->print = gtk_keyval_trigger_print;
+  trigger_class->print_label = gtk_keyval_trigger_print_label;
+
+  /**
+   * GtkKeyvalTrigger:keyval:
+   *
+   * The key value for the trigger.
+   */
+  keyval_props[KEYVAL_PROP_KEYVAL] =
+    g_param_spec_uint (I_("keyval"),
+                       P_("Key value"),
+                       P_("The key value for the trigger"),
+                       0, G_MAXINT,
+                       0,
+                       G_PARAM_STATIC_STRINGS |
+                       G_PARAM_CONSTRUCT_ONLY |
+                       G_PARAM_READWRITE);
+
+  /**
+   * GtkKeyvalTrigger:modifiers:
+   *
+   * The key modifiers for the trigger.
+   */
+  keyval_props[KEYVAL_PROP_MODIFIERS] =
+    g_param_spec_flags (I_("modifiers"),
+                        P_("Modifiers"),
+                        P_("The key modifiers for the trigger"),
+                        GDK_TYPE_MODIFIER_TYPE,
+                        0,
+                        G_PARAM_STATIC_STRINGS |
+                        G_PARAM_CONSTRUCT_ONLY |
+                        G_PARAM_READWRITE);
+
+  g_object_class_install_properties (gobject_class, KEYVAL_N_PROPS, keyval_props);
+}
+
+static void
+gtk_keyval_trigger_init (GtkKeyvalTrigger *self)
+{
+}
 
 /**
  * gtk_keyval_trigger_new:
@@ -593,18 +644,10 @@ GtkShortcutTrigger *
 gtk_keyval_trigger_new (guint           keyval,
                         GdkModifierType modifiers)
 {
-  GtkKeyvalTrigger *self;
-
-  self = (GtkKeyvalTrigger *) gtk_shortcut_trigger_new (&GTK_KEYVAL_TRIGGER_CLASS);
-
-  /* We store keyvals as lower key */
-  if (keyval == GDK_KEY_ISO_Left_Tab)
-    self->keyval = GDK_KEY_Tab;
-  else
-    self->keyval = gdk_keyval_to_lower (keyval);
-  self->modifiers = modifiers;
-
-  return &self->trigger;
+  return g_object_new (GTK_TYPE_KEYVAL_TRIGGER,
+                       "keyval", keyval,
+                       "modifiers", modifiers,
+                       NULL);
 }
 
 /**
@@ -617,13 +660,11 @@ gtk_keyval_trigger_new (guint           keyval,
  * Returns: the modifiers
  **/
 GdkModifierType
-gtk_keyval_trigger_get_modifiers (GtkShortcutTrigger *self)
+gtk_keyval_trigger_get_modifiers (GtkKeyvalTrigger *self)
 {
-  GtkKeyvalTrigger *trigger = (GtkKeyvalTrigger *) self;
-
-  g_return_val_if_fail (GTK_IS_SHORTCUT_TRIGGER_TYPE (self, GTK_SHORTCUT_TRIGGER_KEYVAL), 0);
+  g_return_val_if_fail (GTK_IS_KEYVAL_TRIGGER (self), 0);
 
-  return trigger->modifiers;
+  return self->modifiers;
 }
 
 /**
@@ -636,37 +677,43 @@ gtk_keyval_trigger_get_modifiers (GtkShortcutTrigger *self)
  * Returns: the keyval
  **/
 guint
-gtk_keyval_trigger_get_keyval (GtkShortcutTrigger *self)
+gtk_keyval_trigger_get_keyval (GtkKeyvalTrigger *self)
 {
-  GtkKeyvalTrigger *trigger = (GtkKeyvalTrigger *) self;
-
-  g_return_val_if_fail (GTK_IS_SHORTCUT_TRIGGER_TYPE (self, GTK_SHORTCUT_TRIGGER_KEYVAL), 0);
+  g_return_val_if_fail (GTK_IS_KEYVAL_TRIGGER (self), 0);
 
-  return trigger->keyval;
+  return self->keyval;
 }
 
 /*** GTK_MNEMONIC_TRIGGER ***/
 
-typedef struct _GtkMnemonicTrigger GtkMnemonicTrigger;
-
 struct _GtkMnemonicTrigger
 {
-  GtkShortcutTrigger trigger;
+  GtkShortcutTrigger parent_instance;
 
   guint keyval;
 };
 
-static void
-gtk_mnemonic_trigger_finalize (GtkShortcutTrigger *trigger)
+struct _GtkMnemonicTriggerClass
 {
-}
+  GtkShortcutTriggerClass parent_class;
+};
+
+G_DEFINE_TYPE (GtkMnemonicTrigger, gtk_mnemonic_trigger, GTK_TYPE_SHORTCUT_TRIGGER)
+
+enum
+{
+  MNEMONIC_PROP_KEYVAL = 1,
+  MNEMONIC_N_PROPS
+};
+
+static GParamSpec *mnemonic_props[MNEMONIC_N_PROPS];
 
 static gboolean
 gtk_mnemonic_trigger_trigger (GtkShortcutTrigger *trigger,
                               GdkEvent           *event,
                               gboolean            enable_mnemonics)
 {
-  GtkMnemonicTrigger *self = (GtkMnemonicTrigger *) trigger;
+  GtkMnemonicTrigger *self = GTK_MNEMONIC_TRIGGER (trigger);
   guint keyval;
 
   if (!enable_mnemonics)
@@ -689,18 +736,18 @@ gtk_mnemonic_trigger_trigger (GtkShortcutTrigger *trigger,
 static guint
 gtk_mnemonic_trigger_hash (GtkShortcutTrigger *trigger)
 {
-  GtkMnemonicTrigger *self = (GtkMnemonicTrigger *) trigger;
+  GtkMnemonicTrigger *self = GTK_MNEMONIC_TRIGGER (trigger);
 
   return (self->keyval << 8)
-       | GTK_SHORTCUT_TRIGGER_MNEMONIC;
+       | GTK_SHORTCUT_TRIGGER_HASH_MNEMONIC;
 }
 
 static int
 gtk_mnemonic_trigger_compare (GtkShortcutTrigger  *trigger1,
                               GtkShortcutTrigger  *trigger2)
 {
-  GtkMnemonicTrigger *self1 = (GtkMnemonicTrigger *) trigger1;
-  GtkMnemonicTrigger *self2 = (GtkMnemonicTrigger *) trigger2;
+  GtkMnemonicTrigger *self1 = GTK_MNEMONIC_TRIGGER (trigger1);
+  GtkMnemonicTrigger *self2 = GTK_MNEMONIC_TRIGGER (trigger2);
 
   return self1->keyval - self2->keyval;
 }
@@ -709,7 +756,7 @@ static void
 gtk_mnemonic_trigger_print (GtkShortcutTrigger *trigger,
                             GString            *string)
 {
-  GtkMnemonicTrigger *self = (GtkMnemonicTrigger *) trigger;
+  GtkMnemonicTrigger *self = GTK_MNEMONIC_TRIGGER (trigger);
   const char *keyval_str;
 
   keyval_str = gdk_keyval_name (self->keyval);
@@ -725,7 +772,7 @@ gtk_mnemonic_trigger_print_label (GtkShortcutTrigger *trigger,
                                   GdkDisplay         *display,
                                   GString            *string)
 {
-  GtkMnemonicTrigger *self = (GtkMnemonicTrigger *) trigger;
+  GtkMnemonicTrigger *self = GTK_MNEMONIC_TRIGGER (trigger);
   const char *keyval_str;
 
   keyval_str = gdk_keyval_name (self->keyval);
@@ -737,17 +784,89 @@ gtk_mnemonic_trigger_print_label (GtkShortcutTrigger *trigger,
   return TRUE;
 }
 
-static const GtkShortcutTriggerClass GTK_MNEMONIC_TRIGGER_CLASS = {
-  GTK_SHORTCUT_TRIGGER_MNEMONIC,
-  sizeof (GtkMnemonicTrigger),
-  "GtkMnemonicTrigger",
-  gtk_mnemonic_trigger_finalize,
-  gtk_mnemonic_trigger_trigger,
-  gtk_mnemonic_trigger_hash,
-  gtk_mnemonic_trigger_compare,
-  gtk_mnemonic_trigger_print,
-  gtk_mnemonic_trigger_print_label
-};
+static void
+gtk_mnemonic_trigger_set_property (GObject      *gobject,
+                                   guint         prop_id,
+                                   const GValue *value,
+                                   GParamSpec   *pspec)
+{
+  GtkMnemonicTrigger *self = GTK_MNEMONIC_TRIGGER (gobject);
+
+  switch (prop_id)
+    {
+    case MNEMONIC_PROP_KEYVAL:
+      {
+        guint keyval = g_value_get_uint (value);
+
+        /* We store keyvals as lower key */
+        if (keyval == GDK_KEY_ISO_Left_Tab)
+          self->keyval = GDK_KEY_Tab;
+        else
+          self->keyval = gdk_keyval_to_lower (keyval);
+      }
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+    }
+}
+
+static void
+gtk_mnemonic_trigger_get_property (GObject    *gobject,
+                                   guint       prop_id,
+                                   GValue     *value,
+                                   GParamSpec *pspec)
+{
+  GtkMnemonicTrigger *self = GTK_MNEMONIC_TRIGGER (gobject);
+
+  switch (prop_id)
+    {
+    case MNEMONIC_PROP_KEYVAL:
+      g_value_set_uint (value, self->keyval);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+    }
+}
+
+static void
+gtk_mnemonic_trigger_class_init (GtkMnemonicTriggerClass *klass)
+{
+  GtkShortcutTriggerClass *trigger_class = GTK_SHORTCUT_TRIGGER_CLASS (klass);
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->set_property = gtk_mnemonic_trigger_set_property;
+  gobject_class->get_property = gtk_mnemonic_trigger_get_property;
+
+  trigger_class->trigger = gtk_mnemonic_trigger_trigger;
+  trigger_class->hash = gtk_mnemonic_trigger_hash;
+  trigger_class->compare = gtk_mnemonic_trigger_compare;
+  trigger_class->print = gtk_mnemonic_trigger_print;
+  trigger_class->print_label = gtk_mnemonic_trigger_print_label;
+
+  /**
+   * GtkMnemonicTrigger:keyval:
+   *
+   * The key value for the trigger.
+   */
+  mnemonic_props[KEYVAL_PROP_KEYVAL] =
+    g_param_spec_uint (I_("keyval"),
+                       P_("Key value"),
+                       P_("The key value for the trigger"),
+                       0, G_MAXINT,
+                       0,
+                       G_PARAM_STATIC_STRINGS |
+                       G_PARAM_CONSTRUCT_ONLY |
+                       G_PARAM_READWRITE);
+
+  g_object_class_install_properties (gobject_class, MNEMONIC_N_PROPS, mnemonic_props);
+}
+
+static void
+gtk_mnemonic_trigger_init (GtkMnemonicTrigger *self)
+{
+}
 
 /**
  * gtk_mnemonic_trigger_new:
@@ -759,61 +878,67 @@ static const GtkShortcutTriggerClass GTK_MNEMONIC_TRIGGER_CLASS = {
  * Mnemonics are activated by calling code when a key event with the right
  * modifiers is detected.
  *
- * Returns: A new #GtkShortcutTrigger
+ * Returns: (transfer full) (type GtkMnemonicTrigger): A new #GtkShortcutTrigger
  */
 GtkShortcutTrigger *
 gtk_mnemonic_trigger_new (guint keyval)
 {
-  GtkMnemonicTrigger *self;
-
-  self = (GtkMnemonicTrigger *) gtk_shortcut_trigger_new (&GTK_MNEMONIC_TRIGGER_CLASS);
-
-  /* We store keyvals as lower key */
-  if (keyval == GDK_KEY_ISO_Left_Tab)
-    self->keyval = GDK_KEY_Tab;
-  else
-    self->keyval = gdk_keyval_to_lower (keyval);
-
-  return &self->trigger;
+  return g_object_new (GTK_TYPE_MNEMONIC_TRIGGER,
+                       "keyval", keyval,
+                       NULL);
 }
 
 /**
  * gtk_mnemonic_trigger_get_keyval:
- * @trigger: a mnemonic #GtkShortcutTrigger
+ * @self: a mnemonic #GtkShortcutTrigger
  *
  * Gets the keyval that must be pressed to succeed triggering @self.
  *
  * Returns: the keyval
  **/
 guint
-gtk_mnemonic_trigger_get_keyval (GtkShortcutTrigger *trigger)
+gtk_mnemonic_trigger_get_keyval (GtkMnemonicTrigger *self)
 {
-  GtkMnemonicTrigger *self = (GtkMnemonicTrigger *) trigger;
-
-  g_return_val_if_fail (GTK_IS_SHORTCUT_TRIGGER_TYPE (trigger, GTK_SHORTCUT_TRIGGER_MNEMONIC), 0);
+  g_return_val_if_fail (GTK_IS_MNEMONIC_TRIGGER (self), 0);
 
   return self->keyval;
 }
 
 /*** GTK_ALTERNATIVE_TRIGGER ***/
 
-typedef struct _GtkAlternativeTrigger GtkAlternativeTrigger;
-
 struct _GtkAlternativeTrigger
 {
-  GtkShortcutTrigger trigger;
+  GtkShortcutTrigger parent_instance;
 
   GtkShortcutTrigger *first;
   GtkShortcutTrigger *second;
 };
 
+struct _GtkAlternativeTriggerClass
+{
+  GtkShortcutTriggerClass parent_class;
+};
+
+G_DEFINE_TYPE (GtkAlternativeTrigger, gtk_alternative_trigger, GTK_TYPE_SHORTCUT_TRIGGER)
+
+enum
+{
+  ALTERNATIVE_PROP_FIRST = 1,
+  ALTERNATIVE_PROP_SECOND,
+  ALTERNATIVE_N_PROPS
+};
+
+static GParamSpec *alternative_props[ALTERNATIVE_N_PROPS];
+
 static void
-gtk_alternative_trigger_finalize (GtkShortcutTrigger *trigger)
+gtk_alternative_trigger_dispose (GObject *gobject)
 {
-  GtkAlternativeTrigger *self = (GtkAlternativeTrigger *) trigger;
+  GtkAlternativeTrigger *self = GTK_ALTERNATIVE_TRIGGER (gobject);
+
+  g_clear_object (&self->first);
+  g_clear_object (&self->second);
 
-  gtk_shortcut_trigger_unref (self->first);
-  gtk_shortcut_trigger_unref (self->second);
+  G_OBJECT_CLASS (gtk_alternative_trigger_parent_class)->dispose (gobject);
 }
 
 static gboolean
@@ -821,7 +946,7 @@ gtk_alternative_trigger_trigger (GtkShortcutTrigger *trigger,
                                  GdkEvent           *event,
                                  gboolean            enable_mnemonics)
 {
-  GtkAlternativeTrigger *self = (GtkAlternativeTrigger *) trigger;
+  GtkAlternativeTrigger *self = GTK_ALTERNATIVE_TRIGGER (trigger);
 
   if (gtk_shortcut_trigger_trigger (self->first, event, enable_mnemonics))
     return TRUE;
@@ -835,7 +960,7 @@ gtk_alternative_trigger_trigger (GtkShortcutTrigger *trigger,
 static guint
 gtk_alternative_trigger_hash (GtkShortcutTrigger *trigger)
 {
-  GtkAlternativeTrigger *self = (GtkAlternativeTrigger *) trigger;
+  GtkAlternativeTrigger *self = GTK_ALTERNATIVE_TRIGGER (trigger);
   guint result;
 
   result = gtk_shortcut_trigger_hash (self->first);
@@ -844,15 +969,15 @@ gtk_alternative_trigger_hash (GtkShortcutTrigger *trigger)
   result |= gtk_shortcut_trigger_hash (self->second);
   result <<= 5;
 
-  return result | GTK_SHORTCUT_TRIGGER_ALTERNATIVE;
+  return result | GTK_SHORTCUT_TRIGGER_HASH_ALTERNATIVE;
 }
 
 static int
 gtk_alternative_trigger_compare (GtkShortcutTrigger  *trigger1,
                                  GtkShortcutTrigger  *trigger2)
 {
-  GtkAlternativeTrigger *self1 = (GtkAlternativeTrigger *) trigger1;
-  GtkAlternativeTrigger *self2 = (GtkAlternativeTrigger *) trigger2;
+  GtkAlternativeTrigger *self1 = GTK_ALTERNATIVE_TRIGGER (trigger1);
+  GtkAlternativeTrigger *self2 = GTK_ALTERNATIVE_TRIGGER (trigger2);
   int cmp;
 
   cmp = gtk_shortcut_trigger_compare (self1->first, self2->first);
@@ -866,7 +991,7 @@ static void
 gtk_alternative_trigger_print (GtkShortcutTrigger *trigger,
                                GString            *string)
 {
-  GtkAlternativeTrigger *self = (GtkAlternativeTrigger *) trigger;
+  GtkAlternativeTrigger *self = GTK_ALTERNATIVE_TRIGGER (trigger);
 
   gtk_shortcut_trigger_print (self->first, string);
   g_string_append (string, ", ");
@@ -878,7 +1003,7 @@ gtk_alternative_trigger_print_label (GtkShortcutTrigger *trigger,
                                      GdkDisplay         *display,
                                      GString            *string)
 {
-  GtkAlternativeTrigger *self = (GtkAlternativeTrigger *) trigger;
+  GtkAlternativeTrigger *self = GTK_ALTERNATIVE_TRIGGER (trigger);
 
   if (gtk_shortcut_trigger_print_label (self->first, display, string))
     {
@@ -893,17 +1018,118 @@ gtk_alternative_trigger_print_label (GtkShortcutTrigger *trigger,
     }
 }
 
-static const GtkShortcutTriggerClass GTK_ALTERNATIVE_TRIGGER_CLASS = {
-  GTK_SHORTCUT_TRIGGER_ALTERNATIVE,
-  sizeof (GtkAlternativeTrigger),
-  "GtkAlternativeTrigger",
-  gtk_alternative_trigger_finalize,
-  gtk_alternative_trigger_trigger,
-  gtk_alternative_trigger_hash,
-  gtk_alternative_trigger_compare,
-  gtk_alternative_trigger_print,
-  gtk_alternative_trigger_print_label
-};
+static void
+gtk_alternative_trigger_set_property (GObject      *gobject,
+                                      guint         prop_id,
+                                      const GValue *value,
+                                      GParamSpec   *pspec)
+{
+  GtkAlternativeTrigger *self = GTK_ALTERNATIVE_TRIGGER (gobject);
+
+  switch (prop_id)
+    {
+    case ALTERNATIVE_PROP_FIRST:
+      self->first = g_value_dup_object (value);
+      break;
+
+    case ALTERNATIVE_PROP_SECOND:
+      self->second = g_value_dup_object (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+    }
+}
+
+static void
+gtk_alternative_trigger_get_property (GObject    *gobject,
+                                      guint       prop_id,
+                                      GValue     *value,
+                                      GParamSpec *pspec)
+{
+  GtkAlternativeTrigger *self = GTK_ALTERNATIVE_TRIGGER (gobject);
+
+  switch (prop_id)
+    {
+    case ALTERNATIVE_PROP_FIRST:
+      g_value_set_object (value, self->first);
+      break;
+
+    case ALTERNATIVE_PROP_SECOND:
+      g_value_set_object (value, self->second);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+    }
+}
+
+static void
+gtk_alternative_trigger_constructed (GObject *gobject)
+{
+  GtkAlternativeTrigger *self = GTK_ALTERNATIVE_TRIGGER (gobject);
+
+  if (self->first == NULL || self->second == NULL)
+    {
+      g_critical ("Invalid alternative trigger, disabling");
+      self->first = g_object_ref (gtk_never_trigger_get ());
+      self->second = g_object_ref (gtk_never_trigger_get ());
+    }
+
+  G_OBJECT_CLASS (gtk_alternative_trigger_parent_class)->constructed (gobject);
+}
+
+static void
+gtk_alternative_trigger_class_init (GtkAlternativeTriggerClass *klass)
+{
+  GtkShortcutTriggerClass *trigger_class = GTK_SHORTCUT_TRIGGER_CLASS (klass);
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->constructed = gtk_alternative_trigger_constructed;
+  gobject_class->set_property = gtk_alternative_trigger_set_property;
+  gobject_class->get_property = gtk_alternative_trigger_get_property;
+  gobject_class->dispose = gtk_alternative_trigger_dispose;
+
+  trigger_class->trigger = gtk_alternative_trigger_trigger;
+  trigger_class->hash = gtk_alternative_trigger_hash;
+  trigger_class->compare = gtk_alternative_trigger_compare;
+  trigger_class->print = gtk_alternative_trigger_print;
+  trigger_class->print_label = gtk_alternative_trigger_print_label;
+
+  /**
+   * GtkAlternativeTrigger:first:
+   *
+   * The first #GtkShortcutTrigger to check.
+   */
+  alternative_props[ALTERNATIVE_PROP_FIRST] =
+    g_param_spec_object (I_("first"),
+                         P_("First"),
+                         P_("The first trigger to check"),
+                         GTK_TYPE_SHORTCUT_TRIGGER,
+                         G_PARAM_STATIC_STRINGS |
+                         G_PARAM_CONSTRUCT_ONLY |
+                         G_PARAM_READWRITE);
+  /**
+   * GtkAlternativeTrigger:second:
+   *
+   * The second #GtkShortcutTrigger to check.
+   */
+  alternative_props[ALTERNATIVE_PROP_SECOND] =
+    g_param_spec_object (I_("second"),
+                         P_("Second"),
+                         P_("The second trigger to check"),
+                         GTK_TYPE_SHORTCUT_TRIGGER,
+                         G_PARAM_STATIC_STRINGS |
+                         G_PARAM_CONSTRUCT_ONLY |
+                         G_PARAM_READWRITE);
+
+  g_object_class_install_properties (gobject_class, ALTERNATIVE_N_PROPS, alternative_props);
+}
+
+static void
+gtk_alternative_trigger_init (GtkAlternativeTrigger *self)
+{
+}
 
 /**
  * gtk_alternative_trigger_new:
@@ -922,17 +1148,20 @@ GtkShortcutTrigger *
 gtk_alternative_trigger_new (GtkShortcutTrigger *first,
                              GtkShortcutTrigger *second)
 {
-  GtkAlternativeTrigger *self;
+  GtkShortcutTrigger *res;
 
   g_return_val_if_fail (GTK_IS_SHORTCUT_TRIGGER (first), NULL);
   g_return_val_if_fail (GTK_IS_SHORTCUT_TRIGGER (second), NULL);
 
-  self = (GtkAlternativeTrigger *) gtk_shortcut_trigger_new (&GTK_ALTERNATIVE_TRIGGER_CLASS);
+  res = g_object_new (GTK_TYPE_ALTERNATIVE_TRIGGER,
+                      "first", first,
+                      "second", second,
+                      NULL);
 
-  self->first = first;
-  self->second = second;
+  g_object_unref (first);
+  g_object_unref (second);
 
-  return &self->trigger;
+  return res;
 }
 
 /**
@@ -946,13 +1175,11 @@ gtk_alternative_trigger_new (GtkShortcutTrigger *first,
  * Returns: (transfer none): the first alternative trigger
  **/
 GtkShortcutTrigger *
-gtk_alternative_trigger_get_first (GtkShortcutTrigger *self)
+gtk_alternative_trigger_get_first (GtkAlternativeTrigger *self)
 {
-  GtkAlternativeTrigger *trigger = (GtkAlternativeTrigger *) self;
-
-  g_return_val_if_fail (GTK_IS_SHORTCUT_TRIGGER_TYPE (self, GTK_SHORTCUT_TRIGGER_ALTERNATIVE), 0);
+  g_return_val_if_fail (GTK_IS_ALTERNATIVE_TRIGGER (self), NULL);
 
-  return trigger->first;
+  return self->first;
 }
 
 /**
@@ -966,11 +1193,9 @@ gtk_alternative_trigger_get_first (GtkShortcutTrigger *self)
  * Returns: (transfer none): the second alternative trigger
  **/
 GtkShortcutTrigger *
-gtk_alternative_trigger_get_second (GtkShortcutTrigger *self)
+gtk_alternative_trigger_get_second (GtkAlternativeTrigger *self)
 {
-  GtkAlternativeTrigger *trigger = (GtkAlternativeTrigger *) self;
-
-  g_return_val_if_fail (GTK_IS_SHORTCUT_TRIGGER_TYPE (self, GTK_SHORTCUT_TRIGGER_ALTERNATIVE), 0);
+  g_return_val_if_fail (GTK_IS_ALTERNATIVE_TRIGGER (self), NULL);
 
-  return trigger->second;
+  return self->second;
 }
diff --git a/gtk/gtkshortcuttrigger.h b/gtk/gtkshortcuttrigger.h
index b0ab8af862..4cf7c2cd7b 100644
--- a/gtk/gtkshortcuttrigger.h
+++ b/gtk/gtkshortcuttrigger.h
@@ -30,37 +30,13 @@ 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;
-
-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);
-
+ * A trigger for a key shortcut.
+ */
 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);
@@ -92,29 +68,75 @@ gboolean                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
+GDK_DECLARE_INTERNAL_TYPE (GtkAlternativeTrigger, gtk_alternative_trigger, GTK, ALTERNATIVE_TRIGGER, 
GtkShortcutTrigger)
 
 GDK_AVAILABLE_IN_ALL
-GtkShortcutTrigger *    gtk_alternative_trigger_new             (GtkShortcutTrigger *one,
-                                                                 GtkShortcutTrigger *two);
+GtkShortcutTrigger *    gtk_alternative_trigger_new             (GtkShortcutTrigger    *first,
+                                                                 GtkShortcutTrigger    *second);
 GDK_AVAILABLE_IN_ALL
-GtkShortcutTrigger *    gtk_alternative_trigger_get_first       (GtkShortcutTrigger *self);
+GtkShortcutTrigger *    gtk_alternative_trigger_get_first       (GtkAlternativeTrigger *self);
 GDK_AVAILABLE_IN_ALL
-GtkShortcutTrigger *    gtk_alternative_trigger_get_second      (GtkShortcutTrigger *self);
+GtkShortcutTrigger *    gtk_alternative_trigger_get_second      (GtkAlternativeTrigger *self);
 
 G_END_DECLS
 
diff --git a/testsuite/gtk/shortcuts.c b/testsuite/gtk/shortcuts.c
index 757b2803e4..f895863bc4 100644
--- a/testsuite/gtk/shortcuts.c
+++ b/testsuite/gtk/shortcuts.c
@@ -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;
 
-  trigger1 = gtk_shortcut_trigger_ref (gtk_never_trigger_get ());
+  trigger1 = g_object_ref (gtk_never_trigger_get ());
   trigger2 = gtk_keyval_trigger_new (GDK_KEY_a, GDK_CONTROL_MASK);
   trigger3 = gtk_mnemonic_trigger_new (GDK_KEY_u);
-  trigger4 = gtk_alternative_trigger_new (gtk_shortcut_trigger_ref (trigger2),
-                                          gtk_shortcut_trigger_ref (trigger3));
+  trigger4 = gtk_alternative_trigger_new (g_object_ref (trigger2),
+                                          g_object_ref (trigger3));
 
   display = gdk_display_get_default ();
   device = gdk_seat_get_keyboard (gdk_display_get_default_seat (display));
@@ -239,10 +236,10 @@ test_trigger_trigger (void)
 
   g_object_unref (surface);
 
-  gtk_shortcut_trigger_unref (trigger1);
-  gtk_shortcut_trigger_unref (trigger2);
-  gtk_shortcut_trigger_unref (trigger3);
-  gtk_shortcut_trigger_unref (trigger4);
+  g_object_unref (trigger1);
+  g_object_unref (trigger2);
+  g_object_unref (trigger3);
+  g_object_unref (trigger4);
 }
 
 static int callback_count;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]