From fbaba0026a4c4615034002f05fa88847dd7d72b0 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 5 Aug 2018 04:10:11 +0200 Subject: [PATCH] trigger: Add an alternative trigger And use it. I just added it to GtkWidget just to show that I can. The real reason I want it is for gamepad/joystick triggers in games, so that it becomes possible to select 2 different triggers (gamepad and keyboard) for the same shortcut. --- gtk/gtkshortcuttrigger.c | 165 +++++++++++++++++++++++++++++++++------ gtk/gtkshortcuttrigger.h | 15 +++- gtk/gtkwindow.c | 24 +++--- 3 files changed, 169 insertions(+), 35 deletions(-) diff --git a/gtk/gtkshortcuttrigger.c b/gtk/gtkshortcuttrigger.c index 6bd64268bc..ad7a64afaf 100644 --- a/gtk/gtkshortcuttrigger.c +++ b/gtk/gtkshortcuttrigger.c @@ -65,10 +65,6 @@ struct _GtkShortcutTriggerClass GString *string); }; -static GtkShortcutTrigger * gtk_shortcut_trigger_new (const GtkShortcutTriggerClass *trigger_class, - gsize extra_size); - - G_DEFINE_BOXED_TYPE (GtkShortcutTrigger, gtk_shortcut_trigger, gtk_shortcut_trigger_ref, gtk_shortcut_trigger_unref) @@ -87,15 +83,14 @@ gtk_shortcut_trigger_finalize (GtkShortcutTrigger *self) * * Returns: (transfer full): the newly created #GtkShortcutTrigger */ -GtkShortcutTrigger * -gtk_shortcut_trigger_new (const GtkShortcutTriggerClass *trigger_class, - gsize extra_size) +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 + extra_size); + self = g_malloc0 (trigger_class->struct_size); self->trigger_class = trigger_class; @@ -232,13 +227,13 @@ struct _GtkNeverTrigger }; static void -gsk_never_trigger_finalize (GtkShortcutTrigger *trigger) +gtk_never_trigger_finalize (GtkShortcutTrigger *trigger) { g_assert_not_reached (); } static gboolean -gsk_never_trigger_trigger (GtkShortcutTrigger *trigger, +gtk_never_trigger_trigger (GtkShortcutTrigger *trigger, const GdkEvent *event) { @@ -246,7 +241,7 @@ gsk_never_trigger_trigger (GtkShortcutTrigger *trigger, } static void -gsk_never_trigger_print (GtkShortcutTrigger *trigger, +gtk_never_trigger_print (GtkShortcutTrigger *trigger, GString *string) { @@ -257,15 +252,15 @@ static const GtkShortcutTriggerClass GTK_NEVER_TRIGGER_CLASS = { GTK_SHORTCUT_TRIGGER_NEVER, sizeof (GtkNeverTrigger), "GtkNeverTrigger", - gsk_never_trigger_finalize, - gsk_never_trigger_trigger, - gsk_never_trigger_print + gtk_never_trigger_finalize, + gtk_never_trigger_trigger, + gtk_never_trigger_print }; static GtkNeverTrigger never = { { >K_NEVER_TRIGGER_CLASS, 1 } }; /** - * gsk_never_trigger_get: + * gtk_never_trigger_get: * * Gets the never trigger. This is a singleton for a trigger that never triggers. * Use this trigger instead of %NULL because it implements all virtual functions. @@ -291,12 +286,12 @@ struct _GtkKeyvalTrigger }; static void -gsk_keyval_trigger_finalize (GtkShortcutTrigger *trigger) +gtk_keyval_trigger_finalize (GtkShortcutTrigger *trigger) { } static gboolean -gsk_keyval_trigger_trigger (GtkShortcutTrigger *trigger, +gtk_keyval_trigger_trigger (GtkShortcutTrigger *trigger, const GdkEvent *event) { GtkKeyvalTrigger *self = (GtkKeyvalTrigger *) trigger; @@ -319,7 +314,7 @@ gsk_keyval_trigger_trigger (GtkShortcutTrigger *trigger, } static void -gsk_keyval_trigger_print (GtkShortcutTrigger *trigger, +gtk_keyval_trigger_print (GtkShortcutTrigger *trigger, GString *string) { @@ -335,13 +330,13 @@ static const GtkShortcutTriggerClass GTK_KEYVAL_TRIGGER_CLASS = { GTK_SHORTCUT_TRIGGER_KEYVAL, sizeof (GtkKeyvalTrigger), "GtkKeyvalTrigger", - gsk_keyval_trigger_finalize, - gsk_keyval_trigger_trigger, - gsk_keyval_trigger_print + gtk_keyval_trigger_finalize, + gtk_keyval_trigger_trigger, + gtk_keyval_trigger_print }; /** - * gsk_keyval_trigger_new: + * gtk_keyval_trigger_new: * @keyval: The keyval to trigger for * @modifiers: the modifiers that need to be present * @@ -356,7 +351,7 @@ gtk_keyval_trigger_new (guint keyval, { GtkKeyvalTrigger *self; - self = (GtkKeyvalTrigger *) gtk_shortcut_trigger_new (>K_KEYVAL_TRIGGER_CLASS, 0); + self = (GtkKeyvalTrigger *) gtk_shortcut_trigger_new (>K_KEYVAL_TRIGGER_CLASS); /* We store keyvals as lower key */ if (keyval == GDK_KEY_ISO_Left_Tab) @@ -404,4 +399,128 @@ gtk_keyval_trigger_get_keyval (GtkShortcutTrigger *trigger) return self->keyval; } +/*** GTK_ALTERNATIVE_TRIGGER ***/ + +typedef struct _GtkAlternativeTrigger GtkAlternativeTrigger; + +struct _GtkAlternativeTrigger +{ + GtkShortcutTrigger trigger; + + GtkShortcutTrigger *first; + GtkShortcutTrigger *second; +}; + +static void +gtk_alternative_trigger_finalize (GtkShortcutTrigger *trigger) +{ + GtkAlternativeTrigger *self = (GtkAlternativeTrigger *) trigger; + + gtk_shortcut_trigger_unref (self->first); + gtk_shortcut_trigger_unref (self->second); +} + +static gboolean +gtk_alternative_trigger_trigger (GtkShortcutTrigger *trigger, + const GdkEvent *event) +{ + GtkAlternativeTrigger *self = (GtkAlternativeTrigger *) trigger; + + if (gtk_shortcut_trigger_trigger (self->first, event)) + return TRUE; + + if (gtk_shortcut_trigger_trigger (self->second, event)) + return TRUE; + + return FALSE; +} + +static void +gtk_alternative_trigger_print (GtkShortcutTrigger *trigger, + GString *string) + +{ + GtkAlternativeTrigger *self = (GtkAlternativeTrigger *) trigger; + + gtk_shortcut_trigger_print (self->first, string); + g_string_append (string, ", "); + gtk_shortcut_trigger_print (self->second, string); +} + +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_print +}; + +/** + * gtk_alternative_trigger_new: + * @first: (transfer full): The first trigger that may trigger + * @second: (transfer full): The second trigger that may trigger + * + * Creates a #GtkShortcutTrigger that will trigger whenever either of the 2 given + * triggers gets triggered. + * + * Note that nesting is allowed, so if you want more than two alternative, create + * a new alternative trigger for each option. + * + * Returns: A new #GtkShortcutTrigger + */ +GtkShortcutTrigger * +gtk_alternative_trigger_new (GtkShortcutTrigger *first, + GtkShortcutTrigger *second) +{ + GtkAlternativeTrigger *self; + + 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 (>K_ALTERNATIVE_TRIGGER_CLASS); + + self->first = first; + self->second = second; + + return &self->trigger; +} + +/** + * gtk_alternative_trigger_get_first: + * @self: an alternative #GtkShortcutTrigger + * + * Gets the first of the 2 alternative triggers that may trigger @self. + * gtk_alternative_trigger_get_second() will return the other one. + * + * Returns: (transfer none): the first alternative trigger + **/ +GtkShortcutTrigger * +gtk_alternative_trigger_get_first (GtkShortcutTrigger *trigger) +{ + GtkAlternativeTrigger *self = (GtkAlternativeTrigger *) trigger; + + g_return_val_if_fail (GTK_IS_SHORTCUT_TRIGGER_TYPE (trigger, GTK_SHORTCUT_TRIGGER_ALTERNATIVE), 0); + + return self->first; +} + +/** + * gtk_alternative_trigger_get_second: + * @self: an alternative #GtkShortcutTrigger + * + * Gets the second of the 2 alternative triggers that may trigger @self. + * gtk_alternative_trigger_get_first() will return the other one. + * + * Returns: (transfer none): the second alternative trigger + **/ +GtkShortcutTrigger * +gtk_alternative_trigger_get_second (GtkShortcutTrigger *trigger) +{ + GtkAlternativeTrigger *self = (GtkAlternativeTrigger *) trigger; + + g_return_val_if_fail (GTK_IS_SHORTCUT_TRIGGER_TYPE (trigger, GTK_SHORTCUT_TRIGGER_ALTERNATIVE), 0); + + return self->second; +} diff --git a/gtk/gtkshortcuttrigger.h b/gtk/gtkshortcuttrigger.h index 83e54ec61c..3f3f0549ca 100644 --- a/gtk/gtkshortcuttrigger.h +++ b/gtk/gtkshortcuttrigger.h @@ -35,14 +35,17 @@ G_BEGIN_DECLS /** * GtkShortcutTriggerType: * @GTK_SHORTCUT_TRIGGER_NEVER: Never ever trigger - * @GTK_SHORTCUT_TRIGGER_KEYVAL: Trigger if a key even with matching + * @GTK_SHORTCUT_TRIGGER_KEYVAL: Trigger if a key event with matching * modifiers and keyval is received. + * @GTK_SHORTCUT_TRIGGER_ALTERNAITVE: Trigger if either if two + * alternatives triggers * * The type of a trigger determines what the trigger triggers on. **/ typedef enum { GTK_SHORTCUT_TRIGGER_NEVER, - GTK_SHORTCUT_TRIGGER_KEYVAL + GTK_SHORTCUT_TRIGGER_KEYVAL, + GTK_SHORTCUT_TRIGGER_ALTERNATIVE } GtkShortcutTriggerType; GDK_AVAILABLE_IN_ALL @@ -77,6 +80,14 @@ GdkModifierType gtk_keyval_trigger_get_modifiers (GtkShortcutTrig GDK_AVAILABLE_IN_ALL guint gtk_keyval_trigger_get_keyval (GtkShortcutTrigger *self); +GDK_AVAILABLE_IN_ALL +GtkShortcutTrigger * gtk_alternative_trigger_new (GtkShortcutTrigger *one, + GtkShortcutTrigger *two); +GDK_AVAILABLE_IN_ALL +GtkShortcutTrigger * gtk_alternative_trigger_get_first (GtkShortcutTrigger *trigger); +GDK_AVAILABLE_IN_ALL +GtkShortcutTrigger * gtk_alternative_trigger_get_second (GtkShortcutTrigger *trigger); + G_END_DECLS #endif /* __GTK_SHORTCUT_TRIGGER_H__ */ diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index ef606c0f7b..f4c2bfef03 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -64,6 +64,8 @@ #include "gtknative.h" #include "gtkseparatormenuitem.h" #include "gtksettings.h" +#include "gtkshortcut.h" +#include "gtkshortcuttrigger.h" #include "gtksnapshot.h" #include "gtkstylecontextprivate.h" #include "gtktypebuiltins.h" @@ -585,16 +587,18 @@ add_tab_bindings (GtkWidgetClass *widget_class, GdkModifierType modifiers, GtkDirectionType direction) { - gtk_widget_class_add_binding_signal (widget_class, - GDK_KEY_Tab, modifiers, - "move-focus", - "(i)", - direction); - gtk_widget_class_add_binding_signal (widget_class, - GDK_KEY_KP_Tab, modifiers, - "move-focus", - "(i)", - direction); + GtkShortcut *shortcut; + + shortcut = gtk_shortcut_new (); + gtk_shortcut_set_trigger (shortcut, + gtk_alternative_trigger_new (gtk_keyval_trigger_new (GDK_KEY_Tab, modifiers), + gtk_keyval_trigger_new (GDK_KEY_KP_Tab, modifiers))); + gtk_shortcut_set_signal (shortcut, "move-focus"); + gtk_shortcut_set_arguments (shortcut, g_variant_new_tuple ((GVariant*[1]) { g_variant_new_int32 (direction) }, 1)); + + gtk_widget_class_add_shortcut (widget_class, shortcut); + + g_object_unref (shortcut); } static void