gtk2/testsuite/gtk/shortcuts.c
Jonas Ådahl 2ff74eb667 gdk/toplevel: Negotiate surface size via a compute-size signal
GTK will not up front know how to correctly calculate a size, since it
will not be able to reliably predict the constraints that may exist
where it will be mapped.

Thus, to handle this, calculate the size of the toplevel by having GDK
emitting a signal called 'compute-size' that will contain information
needed for computing a toplevel window size.

This signal may be emitted at any time, e.g. during
gdk_toplevel_present(), or spontaneously if constraints change.

This also drops the max size from the toplevel layout, while moving the
min size from the toplevel layout struct to the struct passed via the
signal,

This needs changes to a test case where we make sure we process
GDK_CONFIGURE etc, which means we also needs to show the window and
process all pending events in the test-focus-chain test case.
2020-08-05 15:49:00 +02:00

460 lines
14 KiB
C

#include <gtk/gtk.h>
#define GTK_COMPILATION
#include "gdk/gdkeventsprivate.h"
static GdkEvent *
key_event_new (GdkEventType event_type,
GdkSurface *surface,
GdkDevice *device,
GdkDevice *source_device,
guint32 time_,
guint keycode,
GdkModifierType state,
gboolean is_modifier,
GdkTranslatedKey *translated,
GdkTranslatedKey *no_lock)
{
GdkKeyEvent *key_event = (GdkKeyEvent *) g_type_create_instance (GDK_TYPE_KEY_EVENT);
GdkEvent *event = (GdkEvent *) key_event;
event->event_type = event_type;
event->surface = g_object_ref (surface);
event->device = g_object_ref (device);
event->time = time_;
key_event->keycode = keycode;
key_event->state = state;
key_event->key_is_modifier = is_modifier;
key_event->translated[0] = *translated;
key_event->translated[1] = *no_lock;
return event;
}
static void
test_trigger_basic (void)
{
GtkShortcutTrigger *trigger;
trigger = gtk_never_trigger_get ();
trigger = gtk_keyval_trigger_new (GDK_KEY_a, GDK_CONTROL_MASK);
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_mnemonic_trigger_get_keyval (GTK_MNEMONIC_TRIGGER (trigger)), ==, GDK_KEY_u);
g_object_unref (trigger);
}
static void
test_trigger_equal (void)
{
GtkShortcutTrigger *trigger1, *trigger2, *trigger3, *trigger4;
GtkShortcutTrigger *trigger5, *trigger6, *trigger1a, *trigger2a;
trigger1 = gtk_keyval_trigger_new ('u', GDK_CONTROL_MASK);
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 = 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));
g_assert_true (gtk_shortcut_trigger_equal (trigger3, trigger3));
g_assert_true (gtk_shortcut_trigger_equal (trigger4, trigger4));
g_assert_true (gtk_shortcut_trigger_equal (trigger5, trigger5));
g_assert_true (gtk_shortcut_trigger_equal (trigger6, trigger6));
g_assert_false (gtk_shortcut_trigger_equal (trigger1, trigger2));
g_assert_false (gtk_shortcut_trigger_equal (trigger1, trigger3));
g_assert_false (gtk_shortcut_trigger_equal (trigger1, trigger4));
g_assert_false (gtk_shortcut_trigger_equal (trigger1, trigger5));
g_assert_false (gtk_shortcut_trigger_equal (trigger1, trigger6));
g_assert_false (gtk_shortcut_trigger_equal (trigger2, trigger3));
g_assert_false (gtk_shortcut_trigger_equal (trigger2, trigger4));
g_assert_false (gtk_shortcut_trigger_equal (trigger2, trigger5));
g_assert_false (gtk_shortcut_trigger_equal (trigger2, trigger6));
g_assert_false (gtk_shortcut_trigger_equal (trigger3, trigger4));
g_assert_false (gtk_shortcut_trigger_equal (trigger3, trigger5));
g_assert_false (gtk_shortcut_trigger_equal (trigger3, trigger6));
g_assert_false (gtk_shortcut_trigger_equal (trigger4, trigger5));
g_assert_false (gtk_shortcut_trigger_equal (trigger4, trigger6));
g_assert_false (gtk_shortcut_trigger_equal (trigger5, trigger6));
g_assert_true (gtk_shortcut_trigger_equal (trigger1, trigger1a));
g_assert_true (gtk_shortcut_trigger_equal (trigger2, 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
test_trigger_parse_never (void)
{
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_ALT_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, '!' },
};
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_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);
}
}
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)
{
GtkShortcutTrigger *trigger[4];
GdkDisplay *display;
GdkSeat *seat;
GdkSurface *surface;
GdkDevice *device;
GdkEvent *event;
struct {
guint keyval;
GdkModifierType state;
gboolean mnemonic;
GdkKeyMatch result[4];
} tests[] = {
{ GDK_KEY_a, GDK_CONTROL_MASK, FALSE, { GDK_KEY_MATCH_NONE, GDK_KEY_MATCH_EXACT, GDK_KEY_MATCH_NONE, GDK_KEY_MATCH_EXACT } },
{ GDK_KEY_a, GDK_CONTROL_MASK, TRUE, { GDK_KEY_MATCH_NONE, GDK_KEY_MATCH_EXACT, GDK_KEY_MATCH_NONE, GDK_KEY_MATCH_EXACT } },
{ GDK_KEY_a, GDK_SHIFT_MASK, FALSE, { GDK_KEY_MATCH_NONE, GDK_KEY_MATCH_NONE, GDK_KEY_MATCH_NONE, GDK_KEY_MATCH_NONE } },
{ GDK_KEY_a, GDK_SHIFT_MASK, TRUE, { GDK_KEY_MATCH_NONE, GDK_KEY_MATCH_NONE, GDK_KEY_MATCH_NONE, GDK_KEY_MATCH_NONE } },
{ GDK_KEY_u, GDK_SHIFT_MASK, FALSE, { GDK_KEY_MATCH_NONE, GDK_KEY_MATCH_NONE, GDK_KEY_MATCH_NONE, GDK_KEY_MATCH_NONE } },
{ GDK_KEY_u, GDK_SHIFT_MASK, TRUE, { GDK_KEY_MATCH_NONE, GDK_KEY_MATCH_NONE, GDK_KEY_MATCH_EXACT, GDK_KEY_MATCH_EXACT } },
};
int i, j;
display = gdk_display_get_default ();
seat = gdk_display_get_default_seat (display);
if (!seat)
{
g_test_skip ("Display has no seat");
return;
}
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 (g_object_ref (trigger[1]),
g_object_ref (trigger[2]));
device = gdk_seat_get_keyboard (seat);
surface = gdk_surface_new_toplevel (display);
for (i = 0; i < G_N_ELEMENTS (tests); i++)
{
GdkKeymapKey *keys;
int n_keys;
GdkTranslatedKey translated;
if (!gdk_display_map_keyval (display, tests[i].keyval, &keys, &n_keys))
continue;
translated.keyval = tests[i].keyval;
translated.consumed = 0;
translated.layout = keys[0].group;
translated.level = keys[0].level;
event = key_event_new (GDK_KEY_PRESS,
surface,
device,
device,
GDK_CURRENT_TIME,
keys[0].keycode,
tests[i].state,
FALSE,
&translated,
&translated);
for (j = 0; j < 4; j++)
{
g_assert_cmpint (gtk_shortcut_trigger_trigger (trigger[j], event, tests[i].mnemonic), ==, tests[i].result[j]);
}
gdk_event_unref (event);
g_free (keys);
}
gdk_surface_destroy (surface);
g_object_unref (surface);
g_object_unref (trigger[0]);
g_object_unref (trigger[1]);
g_object_unref (trigger[2]);
g_object_unref (trigger[3]);
}
static gboolean
callback (GtkWidget *widget,
GVariant *args,
gpointer user_data)
{
int *callback_count = user_data;
*callback_count += 1;
return TRUE;
}
static void
test_action_basic (void)
{
GtkShortcutAction *action;
action = gtk_signal_action_new ("activate");
g_assert_cmpstr (gtk_signal_action_get_signal_name (GTK_SIGNAL_ACTION (action)), ==, "activate");
g_object_unref (action);
action = gtk_named_action_new ("text.undo");
g_assert_cmpstr (gtk_named_action_get_action_name (GTK_NAMED_ACTION (action)), ==, "text.undo");
g_object_unref (action);
}
static void
test_action_activate (void)
{
GtkShortcutAction *action;
GtkWidget *widget;
int callback_count;
widget = gtk_label_new ("");
g_object_ref_sink (widget);
action = gtk_nothing_action_get ();
g_assert_false (gtk_shortcut_action_activate (action, 0, widget, NULL));
callback_count = 0;
action = gtk_callback_action_new (callback, &callback_count, NULL);
g_assert_true (gtk_shortcut_action_activate (action, 0, widget, NULL));
g_assert_cmpint (callback_count, ==, 1);
g_object_unref (action);
g_object_unref (widget);
}
static void
test_action_parse (void)
{
GtkShortcutAction *action;
action = gtk_shortcut_action_parse_string ("nothing");
g_assert_true (GTK_IS_NOTHING_ACTION (action));
g_object_unref (action);
action = gtk_shortcut_action_parse_string ("activate");
g_assert_true (GTK_IS_ACTIVATE_ACTION (action));
g_object_unref (action);
action = gtk_shortcut_action_parse_string ("mnemonic-activate");
g_assert_true (GTK_IS_MNEMONIC_ACTION (action));
g_object_unref (action);
action = gtk_shortcut_action_parse_string ("action(win.dark)");
g_assert_true (GTK_IS_NAMED_ACTION (action));
g_object_unref (action);
action = gtk_shortcut_action_parse_string ("signal(frob)");
g_assert_true (GTK_IS_SIGNAL_ACTION (action));
g_object_unref (action);
}
int
main (int argc, char *argv[])
{
gtk_test_init (&argc, &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/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);
g_test_add_func ("/shortcuts/action/parse", test_action_parse);
return g_test_run ();
}