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.
This commit is contained in:
Benjamin Otte 2018-08-05 04:10:11 +02:00 committed by Matthias Clasen
parent 6d452f1eb8
commit 81fa63260e
3 changed files with 172 additions and 35 deletions

View File

@ -65,10 +65,6 @@ struct _GtkShortcutTriggerClass
GString *string); GString *string);
}; };
static GtkShortcutTrigger * gtk_shortcut_trigger_new (const GtkShortcutTriggerClass *trigger_class,
gsize extra_size);
G_DEFINE_BOXED_TYPE (GtkShortcutTrigger, gtk_shortcut_trigger, G_DEFINE_BOXED_TYPE (GtkShortcutTrigger, gtk_shortcut_trigger,
gtk_shortcut_trigger_ref, gtk_shortcut_trigger_ref,
gtk_shortcut_trigger_unref) gtk_shortcut_trigger_unref)
@ -87,15 +83,14 @@ gtk_shortcut_trigger_finalize (GtkShortcutTrigger *self)
* *
* Returns: (transfer full): the newly created #GtkShortcutTrigger * Returns: (transfer full): the newly created #GtkShortcutTrigger
*/ */
GtkShortcutTrigger * static GtkShortcutTrigger *
gtk_shortcut_trigger_new (const GtkShortcutTriggerClass *trigger_class, gtk_shortcut_trigger_new (const GtkShortcutTriggerClass *trigger_class)
gsize extra_size)
{ {
GtkShortcutTrigger *self; GtkShortcutTrigger *self;
g_return_val_if_fail (trigger_class != NULL, NULL); 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);
g_atomic_ref_count_init (&self->ref_count); g_atomic_ref_count_init (&self->ref_count);
self->trigger_class = trigger_class; self->trigger_class = trigger_class;
@ -232,20 +227,20 @@ struct _GtkNeverTrigger
}; };
static void static void
gsk_never_trigger_finalize (GtkShortcutTrigger *trigger) gtk_never_trigger_finalize (GtkShortcutTrigger *trigger)
{ {
g_assert_not_reached (); g_assert_not_reached ();
} }
static gboolean static gboolean
gsk_never_trigger_trigger (GtkShortcutTrigger *trigger, gtk_never_trigger_trigger (GtkShortcutTrigger *trigger,
GdkEvent *event) GdkEvent *event)
{ {
return FALSE; return FALSE;
} }
static void static void
gsk_never_trigger_print (GtkShortcutTrigger *trigger, gtk_never_trigger_print (GtkShortcutTrigger *trigger,
GString *string) GString *string)
{ {
g_string_append (string, "<never>"); g_string_append (string, "<never>");
@ -255,15 +250,15 @@ static const GtkShortcutTriggerClass GTK_NEVER_TRIGGER_CLASS = {
GTK_SHORTCUT_TRIGGER_NEVER, GTK_SHORTCUT_TRIGGER_NEVER,
sizeof (GtkNeverTrigger), sizeof (GtkNeverTrigger),
"GtkNeverTrigger", "GtkNeverTrigger",
gsk_never_trigger_finalize, gtk_never_trigger_finalize,
gsk_never_trigger_trigger, gtk_never_trigger_trigger,
gsk_never_trigger_print gtk_never_trigger_print
}; };
static GtkNeverTrigger never = { { &GTK_NEVER_TRIGGER_CLASS, 1 } }; static GtkNeverTrigger never = { { &GTK_NEVER_TRIGGER_CLASS, 1 } };
/** /**
* gsk_never_trigger_get: * gtk_never_trigger_get:
* *
* Gets the never trigger. This is a singleton for a trigger * Gets the never trigger. This is a singleton for a trigger
* that never triggers. Use this trigger instead of %NULL * that never triggers. Use this trigger instead of %NULL
@ -290,12 +285,12 @@ struct _GtkKeyvalTrigger
}; };
static void static void
gsk_keyval_trigger_finalize (GtkShortcutTrigger *trigger) gtk_keyval_trigger_finalize (GtkShortcutTrigger *trigger)
{ {
} }
static gboolean static gboolean
gsk_keyval_trigger_trigger (GtkShortcutTrigger *trigger, gtk_keyval_trigger_trigger (GtkShortcutTrigger *trigger,
GdkEvent *event) GdkEvent *event)
{ {
GtkKeyvalTrigger *self = (GtkKeyvalTrigger *) trigger; GtkKeyvalTrigger *self = (GtkKeyvalTrigger *) trigger;
@ -318,7 +313,7 @@ gsk_keyval_trigger_trigger (GtkShortcutTrigger *trigger,
} }
static void static void
gsk_keyval_trigger_print (GtkShortcutTrigger *trigger, gtk_keyval_trigger_print (GtkShortcutTrigger *trigger,
GString *string) GString *string)
{ {
GtkKeyvalTrigger *self = (GtkKeyvalTrigger *) trigger; GtkKeyvalTrigger *self = (GtkKeyvalTrigger *) trigger;
@ -333,13 +328,13 @@ static const GtkShortcutTriggerClass GTK_KEYVAL_TRIGGER_CLASS = {
GTK_SHORTCUT_TRIGGER_KEYVAL, GTK_SHORTCUT_TRIGGER_KEYVAL,
sizeof (GtkKeyvalTrigger), sizeof (GtkKeyvalTrigger),
"GtkKeyvalTrigger", "GtkKeyvalTrigger",
gsk_keyval_trigger_finalize, gtk_keyval_trigger_finalize,
gsk_keyval_trigger_trigger, gtk_keyval_trigger_trigger,
gsk_keyval_trigger_print gtk_keyval_trigger_print
}; };
/** /**
* gsk_keyval_trigger_new: * gtk_keyval_trigger_new:
* @keyval: The keyval to trigger for * @keyval: The keyval to trigger for
* @modifiers: the modifiers that need to be present * @modifiers: the modifiers that need to be present
* *
@ -354,7 +349,7 @@ gtk_keyval_trigger_new (guint keyval,
{ {
GtkKeyvalTrigger *self; GtkKeyvalTrigger *self;
self = (GtkKeyvalTrigger *) gtk_shortcut_trigger_new (&GTK_KEYVAL_TRIGGER_CLASS, 0); self = (GtkKeyvalTrigger *) gtk_shortcut_trigger_new (&GTK_KEYVAL_TRIGGER_CLASS);
/* We store keyvals as lower key */ /* We store keyvals as lower key */
if (keyval == GDK_KEY_ISO_Left_Tab) if (keyval == GDK_KEY_ISO_Left_Tab)
@ -403,3 +398,130 @@ gtk_keyval_trigger_get_keyval (GtkShortcutTrigger *self)
return trigger->keyval; return trigger->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,
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 two 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 (&GTK_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 two 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 *self)
{
GtkAlternativeTrigger *trigger = (GtkAlternativeTrigger *) self;
g_return_val_if_fail (GTK_IS_SHORTCUT_TRIGGER_TYPE (self, GTK_SHORTCUT_TRIGGER_ALTERNATIVE), 0);
return trigger->first;
}
/**
* gtk_alternative_trigger_get_second:
* @self: an alternative #GtkShortcutTrigger
*
* Gets the second of the two 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 *self)
{
GtkAlternativeTrigger *trigger = (GtkAlternativeTrigger *) self;
g_return_val_if_fail (GTK_IS_SHORTCUT_TRIGGER_TYPE (self, GTK_SHORTCUT_TRIGGER_ALTERNATIVE), 0);
return trigger->second;
}

View File

@ -35,14 +35,17 @@ G_BEGIN_DECLS
/** /**
* GtkShortcutTriggerType: * GtkShortcutTriggerType:
* @GTK_SHORTCUT_TRIGGER_NEVER: Never ever trigger * @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. * 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. * The type of a trigger determines what the trigger triggers on.
**/ **/
typedef enum { typedef enum {
GTK_SHORTCUT_TRIGGER_NEVER, GTK_SHORTCUT_TRIGGER_NEVER,
GTK_SHORTCUT_TRIGGER_KEYVAL GTK_SHORTCUT_TRIGGER_KEYVAL,
GTK_SHORTCUT_TRIGGER_ALTERNATIVE
} GtkShortcutTriggerType; } GtkShortcutTriggerType;
GDK_AVAILABLE_IN_ALL GDK_AVAILABLE_IN_ALL
@ -77,6 +80,14 @@ GdkModifierType gtk_keyval_trigger_get_modifiers (GtkShortcutTrig
GDK_AVAILABLE_IN_ALL GDK_AVAILABLE_IN_ALL
guint gtk_keyval_trigger_get_keyval (GtkShortcutTrigger *self); 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 *self);
GDK_AVAILABLE_IN_ALL
GtkShortcutTrigger * gtk_alternative_trigger_get_second (GtkShortcutTrigger *self);
G_END_DECLS G_END_DECLS
#endif /* __GTK_SHORTCUT_TRIGGER_H__ */ #endif /* __GTK_SHORTCUT_TRIGGER_H__ */

View File

@ -62,6 +62,8 @@
#include "gtkroot.h" #include "gtkroot.h"
#include "gtknative.h" #include "gtknative.h"
#include "gtksettings.h" #include "gtksettings.h"
#include "gtkshortcut.h"
#include "gtkshortcuttrigger.h"
#include "gtksnapshot.h" #include "gtksnapshot.h"
#include "gtkstylecontextprivate.h" #include "gtkstylecontextprivate.h"
#include "gtktypebuiltins.h" #include "gtktypebuiltins.h"
@ -556,16 +558,18 @@ add_tab_bindings (GtkWidgetClass *widget_class,
GdkModifierType modifiers, GdkModifierType modifiers,
GtkDirectionType direction) GtkDirectionType direction)
{ {
gtk_widget_class_add_binding_signal (widget_class, GtkShortcut *shortcut;
GDK_KEY_Tab, modifiers,
"move-focus", shortcut = gtk_shortcut_new ();
"(i)", gtk_shortcut_set_trigger (shortcut,
direction); gtk_alternative_trigger_new (gtk_keyval_trigger_new (GDK_KEY_Tab, modifiers),
gtk_widget_class_add_binding_signal (widget_class, gtk_keyval_trigger_new (GDK_KEY_KP_Tab, modifiers)));
GDK_KEY_KP_Tab, modifiers, gtk_shortcut_set_signal (shortcut, "move-focus");
"move-focus", gtk_shortcut_set_arguments (shortcut, g_variant_new_tuple ((GVariant*[1]) { g_variant_new_int32 (direction) }, 1));
"(i)",
direction); gtk_widget_class_add_shortcut (widget_class, shortcut);
g_object_unref (shortcut);
} }
static void static void