Merge branch 'trigger-parser' into 'master'

Improve GtkShortcutTrigger parser

See merge request GNOME/gtk!1572
This commit is contained in:
Matthias Clasen 2020-03-27 15:45:08 +00:00
commit 9f72f4225d
2 changed files with 207 additions and 16 deletions

View File

@ -120,24 +120,63 @@ gtk_shortcut_trigger_trigger (GtkShortcutTrigger *self,
* - `never`, for #GtkNeverTrigger
* - a string parsed by gtk_accelerator_parse(), for a #GtkKeyvalTrigger
* - underscore, followed by a single character, for #GtkMnemonicTrigger
* - two valid trigger strings, separated by a `|` character, for a
* #GtkAlternativeTrigger
*
* Returns: (nullable): a new #GtkShortcutTrigger or %NULL on error
* Returns: (nullable) (transfer full): a new #GtkShortcutTrigger
* or %NULL on error
*/
GtkShortcutTrigger *
gtk_shortcut_trigger_parse_string (const char *string)
{
GdkModifierType modifiers;
guint keyval;
const char *sep;
g_return_val_if_fail (string != NULL, NULL);
if ((sep = strchr (string, '|')) != NULL)
{
char *frag_a = g_strndup (string, sep - string);
const char *frag_b = sep + 1;
GtkShortcutTrigger *t1, *t2;
/* empty first slot */
if (*frag_a == '\0')
return NULL;
/* empty second slot */
if (*frag_b == '\0')
return NULL;
t1 = gtk_shortcut_trigger_parse_string (frag_a);
if (t1 == NULL)
{
g_free (frag_a);
return NULL;
}
t2 = gtk_shortcut_trigger_parse_string (frag_b);
if (t2 == NULL)
{
g_object_unref (t1);
g_free (frag_a);
return NULL;
}
g_free (frag_a);
return gtk_alternative_trigger_new (t1, t2);
}
if (g_str_equal (string, "never"))
return gtk_never_trigger_get ();
return g_object_ref (gtk_never_trigger_get ());
if (string[0] == '_')
{
if (gtk_accelerator_parse (string + 1, &keyval, &modifiers))
return gtk_mnemonic_trigger_new (keyval);
keyval = gdk_keyval_from_name (string + 1);
if (keyval != GDK_KEY_VoidSymbol)
return gtk_mnemonic_trigger_new (gdk_keyval_to_lower (keyval));
}
if (gtk_accelerator_parse (string, &keyval, &modifiers))
@ -396,7 +435,7 @@ static void
gtk_never_trigger_print (GtkShortcutTrigger *trigger,
GString *string)
{
g_string_append (string, "<never>");
g_string_append (string, "never");
}
static gboolean
@ -1089,7 +1128,7 @@ gtk_alternative_trigger_print (GtkShortcutTrigger *trigger,
GtkAlternativeTrigger *self = GTK_ALTERNATIVE_TRIGGER (trigger);
gtk_shortcut_trigger_print (self->first, string);
g_string_append (string, ", ");
g_string_append (string, "|");
gtk_shortcut_trigger_print (self->second, string);
}

View File

@ -151,35 +151,183 @@ test_trigger_equal (void)
}
static void
test_trigger_parse (void)
test_trigger_parse_never (void)
{
struct {
GtkShortcutTrigger *trigger;
trigger = gtk_shortcut_trigger_parse_string ("never");
g_assert_true (GTK_IS_NEVER_TRIGGER (trigger));
g_object_unref (trigger);
}
static void
test_trigger_parse_keyval (void)
{
const struct
{
const char *str;
GdkModifierType modifiers;
guint keyval;
int trigger_type;
} tests[] = {
{ "<Primary><Alt>z", GDK_CONTROL_MASK|GDK_MOD1_MASK, 'z' },
{ "<Primary><Alt>z", GDK_CONTROL_MASK | GDK_MOD1_MASK, 'z' },
{ "<Control>U", GDK_CONTROL_MASK, 'u' },
{ "<Hyper>x", GDK_HYPER_MASK, 'x' },
{ "<Meta>y", GDK_META_MASK, 'y' },
{ "KP_7", 0, GDK_KEY_KP_7 },
{ "<Shift>exclam", GDK_SHIFT_MASK, '!' },
};
GtkShortcutTrigger *trigger;
int i;
for (i = 0; i < G_N_ELEMENTS (tests); i++)
for (int i = 0; i < G_N_ELEMENTS (tests); i++)
{
trigger = gtk_shortcut_trigger_parse_string (tests[i].str);
g_test_message ("Checking: '%s'", tests[i].str);
GtkShortcutTrigger *trigger = gtk_shortcut_trigger_parse_string (tests[i].str);
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_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);
}
}
static void
test_trigger_parse_mnemonic (void)
{
struct
{
const char *str;
guint keyval;
} tests[] = {
{ "_A", GDK_KEY_a },
{ "_s", GDK_KEY_s },
};
for (int i = 0; i < G_N_ELEMENTS (tests); i++)
{
g_test_message ("Checking: '%s'", tests[i].str);
GtkShortcutTrigger *trigger = gtk_shortcut_trigger_parse_string (tests[i].str);
g_assert_true (GTK_IS_MNEMONIC_TRIGGER (trigger));
g_assert_cmpuint (gtk_mnemonic_trigger_get_keyval (GTK_MNEMONIC_TRIGGER (trigger)),
==,
tests[i].keyval);
g_object_unref (trigger);
}
}
static void
test_trigger_parse_alternative (void)
{
enum
{
TRIGGER_NEVER,
TRIGGER_KEYVAL,
TRIGGER_MNEMONIC,
TRIGGER_ALTERNATIVE
};
const struct
{
const char *str;
int first;
int second;
} tests[] = {
{ "U|<Primary>U", TRIGGER_KEYVAL, TRIGGER_KEYVAL },
{ "_U|<Shift>u", TRIGGER_MNEMONIC, TRIGGER_KEYVAL },
{ "x|_x|<Primary>x", TRIGGER_KEYVAL, TRIGGER_ALTERNATIVE },
};
for (int i = 0; i < G_N_ELEMENTS (tests); i++)
{
g_test_message ("Checking: '%s'", tests[i].str);
GtkShortcutTrigger *trigger = gtk_shortcut_trigger_parse_string (tests[i].str);
g_assert_true (GTK_IS_ALTERNATIVE_TRIGGER (trigger));
GtkShortcutTrigger *t1 = gtk_alternative_trigger_get_first (GTK_ALTERNATIVE_TRIGGER (trigger));
switch (tests[i].first)
{
case TRIGGER_NEVER:
g_assert_true (GTK_IS_NEVER_TRIGGER (t1));
break;
case TRIGGER_KEYVAL:
g_assert_true (GTK_IS_KEYVAL_TRIGGER (t1));
break;
case TRIGGER_MNEMONIC:
g_assert_true (GTK_IS_MNEMONIC_TRIGGER (t1));
break;
case TRIGGER_ALTERNATIVE:
g_assert_true (GTK_IS_ALTERNATIVE_TRIGGER (t1));
break;
default:
g_assert_not_reached ();
break;
}
GtkShortcutTrigger *t2 = gtk_alternative_trigger_get_second (GTK_ALTERNATIVE_TRIGGER (trigger));
switch (tests[i].second)
{
case TRIGGER_NEVER:
g_assert_true (GTK_IS_NEVER_TRIGGER (t2));
break;
case TRIGGER_KEYVAL:
g_assert_true (GTK_IS_KEYVAL_TRIGGER (t2));
break;
case TRIGGER_MNEMONIC:
g_assert_true (GTK_IS_MNEMONIC_TRIGGER (t2));
break;
case TRIGGER_ALTERNATIVE:
g_assert_true (GTK_IS_ALTERNATIVE_TRIGGER (t2));
break;
default:
g_assert_not_reached ();
break;
}
g_object_unref (trigger);
}
}
static void
test_trigger_parse_invalid (void)
{
const char *tests[] = {
"<never>",
"Never",
"Foo",
"<Foo>Nyaa",
"never|",
"|never",
};
for (int i = 0; i < G_N_ELEMENTS (tests); i++)
{
g_test_message ("Checking: '%s'", tests[i]);
GtkShortcutTrigger *trigger = gtk_shortcut_trigger_parse_string (tests[i]);
g_assert_null (trigger);
}
}
static void
test_trigger_trigger (void)
{
@ -300,7 +448,11 @@ main (int argc, char *argv[])
g_test_add_func ("/shortcuts/trigger/basic", test_trigger_basic);
g_test_add_func ("/shortcuts/trigger/equal", test_trigger_equal);
g_test_add_func ("/shortcuts/trigger/parse", test_trigger_parse);
g_test_add_func ("/shortcuts/trigger/parse/never", test_trigger_parse_never);
g_test_add_func ("/shortcuts/trigger/parse/keyval", test_trigger_parse_keyval);
g_test_add_func ("/shortcuts/trigger/parse/mnemonic", test_trigger_parse_mnemonic);
g_test_add_func ("/shortcuts/trigger/parse/alternative", test_trigger_parse_alternative);
g_test_add_func ("/shortcuts/trigger/parse/invalid", test_trigger_parse_invalid);
g_test_add_func ("/shortcuts/trigger/trigger", test_trigger_trigger);
g_test_add_func ("/shortcuts/action/basic", test_action_basic);
g_test_add_func ("/shortcuts/action/activate", test_action_activate);