[mutter/wip/carlosg/grabs-pt1: 93/93] tests: Add tests for crossing events generated during ClutterGrab
- From: Carlos Garnacho <carlosg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter/wip/carlosg/grabs-pt1: 93/93] tests: Add tests for crossing events generated during ClutterGrab
- Date: Tue, 7 Dec 2021 21:33:02 +0000 (UTC)
commit 1395113d5175810762cd82fac03472cc811f4502
Author: Carlos Garnacho <carlosg gnome org>
Date: Fri Nov 26 16:15:54 2021 +0100
tests: Add tests for crossing events generated during ClutterGrab
src/tests/clutter/conform/grab.c | 538 ++++++++++++++++++++++++++++++++++
src/tests/clutter/conform/meson.build | 1 +
2 files changed, 539 insertions(+)
---
diff --git a/src/tests/clutter/conform/grab.c b/src/tests/clutter/conform/grab.c
new file mode 100644
index 0000000000..63d76fa263
--- /dev/null
+++ b/src/tests/clutter/conform/grab.c
@@ -0,0 +1,538 @@
+#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
+#include <clutter/clutter.h>
+
+#include "tests/clutter-test-utils.h"
+
+typedef struct
+{
+ const char *name;
+ ClutterEventType type;
+} EventLog;
+
+typedef struct
+{
+ ClutterActor *stage, *a, *b, *c;
+ GArray *events;
+} TestData;
+
+static void
+event_log_compare (EventLog *expected,
+ GArray *obtained)
+{
+ EventLog *elem;
+ guint i;
+
+ for (i = 0; expected[i].name != NULL; i++)
+ {
+ g_assert_cmpuint (i, <, obtained->len);
+ elem = &g_array_index (obtained, EventLog, i);
+ g_assert_cmpuint (expected[i].type, ==, elem->type);
+ g_assert_cmpstr (expected[i].name, ==, elem->name);
+ }
+
+ if (i != obtained->len)
+ {
+ elem = &g_array_index (obtained, EventLog, i);
+ g_critical ("Unexpected event %d on actor '%s'",
+ elem->type, elem->name);
+ }
+
+ g_assert_cmpuint (i, ==, obtained->len);
+
+ /* Clear the array for future comparisons */
+ g_array_set_size (obtained, 0);
+}
+
+static void
+event_cb (ClutterActor *actor,
+ ClutterEvent *event,
+ gpointer user_data)
+{
+ GArray *events = user_data;
+
+ if ((event->type == CLUTTER_ENTER ||
+ event->type == CLUTTER_LEAVE) &&
+ (event->any.flags & CLUTTER_EVENT_FLAG_GRAB_NOTIFY) != 0)
+ {
+ EventLog entry = { clutter_actor_get_name (actor), event->type };
+
+ g_debug ("Event '%s' on actor '%s'",
+ entry.type == CLUTTER_ENTER ? "ENTER" : "LEAVE",
+ entry.name);
+ g_array_append_val (events, entry);
+ }
+}
+
+static void
+create_actors (ClutterActor *stage,
+ ClutterActor **a,
+ ClutterActor **b,
+ ClutterActor **c)
+{
+ /* This builds the following tree:
+ *
+ * stage
+ * ╱ ╲
+ * a c
+ * ╱
+ * b
+ */
+
+ *a = clutter_actor_new ();
+ clutter_actor_set_name (*a, "a");
+ clutter_actor_set_reactive (*a, TRUE);
+ clutter_actor_set_width (*a, clutter_actor_get_width (stage) / 2);
+ clutter_actor_set_height (*a, clutter_actor_get_height (stage));
+ clutter_actor_add_child (stage, *a);
+
+ *b = clutter_actor_new ();
+ clutter_actor_set_name (*b, "b");
+ clutter_actor_set_reactive (*b, TRUE);
+ clutter_actor_set_width (*b, clutter_actor_get_width (stage) / 2);
+ clutter_actor_set_height (*b, clutter_actor_get_height (stage));
+ clutter_actor_add_child (*a, *b);
+
+ *c = clutter_actor_new ();
+ clutter_actor_set_name (*c, "c");
+ clutter_actor_set_reactive (*c, TRUE);
+ clutter_actor_set_x (*c, clutter_actor_get_width (stage) / 2);
+ clutter_actor_set_width (*c, clutter_actor_get_width (stage) / 2);
+ clutter_actor_set_height (*c, clutter_actor_get_height (stage));
+ clutter_actor_add_child (stage, *c);
+}
+
+static void
+has_pointer_cb (ClutterActor *actor)
+{
+ if (clutter_actor_has_pointer (actor))
+ clutter_test_quit ();
+}
+
+static void
+create_pointer (ClutterActor *actor)
+{
+ ClutterVirtualInputDevice *pointer;
+ ClutterSeat *seat;
+ guint notify_id;
+
+ seat = clutter_backend_get_default_seat (clutter_get_default_backend ());
+ pointer = clutter_seat_create_virtual_device (seat, CLUTTER_POINTER_DEVICE);
+
+ clutter_virtual_input_device_notify_absolute_motion (pointer,
+ 0,
+ clutter_actor_get_x (actor) +
+ clutter_actor_get_width (actor) / 2,
+ clutter_actor_get_y (actor) +
+ clutter_actor_get_height (actor) / 2);
+
+ notify_id = g_signal_connect (actor, "notify::has-pointer",
+ G_CALLBACK (has_pointer_cb), NULL);
+ clutter_test_main ();
+
+ g_signal_handler_disconnect (actor, notify_id);
+
+ g_object_unref (pointer);
+}
+
+static void
+connect_signals (ClutterActor *stage,
+ ClutterActor *a,
+ ClutterActor *b,
+ ClutterActor *c,
+ gpointer user_data)
+{
+ g_signal_connect (stage, "event", G_CALLBACK (event_cb), user_data);
+ g_signal_connect (a, "event", G_CALLBACK (event_cb), user_data);
+ g_signal_connect (b, "event", G_CALLBACK (event_cb), user_data);
+ g_signal_connect (c, "event", G_CALLBACK (event_cb), user_data);
+}
+
+static void
+disconnect_signals (ClutterActor *stage,
+ ClutterActor *a,
+ ClutterActor *b,
+ ClutterActor *c,
+ gpointer user_data)
+{
+ g_signal_handlers_disconnect_by_func (stage, event_cb, user_data);
+ g_signal_handlers_disconnect_by_func (a, event_cb, user_data);
+ g_signal_handlers_disconnect_by_func (b, event_cb, user_data);
+ g_signal_handlers_disconnect_by_func (c, event_cb, user_data);
+}
+
+static void
+test_data_init (TestData *data)
+{
+ ClutterActor *stage;
+ ClutterActor *a, *b, *c;
+ GArray *events;
+
+ stage = clutter_test_get_stage ();
+ clutter_actor_set_name (stage, "stage");
+ create_actors (stage, &a, &b, &c);
+ clutter_actor_show (stage);
+ create_pointer (b);
+
+ events = g_array_new (TRUE, TRUE, sizeof (EventLog));
+
+ connect_signals (stage, a, b, c, events);
+
+ *data = (TestData) {
+ stage, a, b, c, events,
+ };
+}
+
+static void
+test_data_shutdown (TestData *data)
+{
+ disconnect_signals (data->stage, data->a, data->b, data->c, data->events);
+ clutter_actor_destroy (data->c);
+ clutter_actor_destroy (data->b);
+ clutter_actor_destroy (data->a);
+ g_array_unref (data->events);
+}
+
+static void
+grab_under_pointer (void)
+{
+ TestData data;
+ ClutterGrab *grab;
+ EventLog grab_log[] = {
+ { "a", CLUTTER_LEAVE },
+ { "stage", CLUTTER_LEAVE },
+ { NULL, 0 },
+ };
+ EventLog ungrab_log[] = {
+ { "a", CLUTTER_ENTER },
+ { "stage", CLUTTER_ENTER },
+ { NULL, 0 },
+ };
+
+ test_data_init (&data);
+
+ /* Grab 'b', pointer is on 'b' */
+ grab = clutter_stage_grab (CLUTTER_STAGE (data.stage), data.b);
+ event_log_compare ((EventLog *) &grab_log, data.events);
+
+ clutter_grab_dismiss (grab);
+ event_log_compare ((EventLog *) &ungrab_log, data.events);
+
+ test_data_shutdown (&data);
+}
+
+static void
+grab_under_pointers_parent (void)
+{
+ TestData data;
+ ClutterGrab *grab;
+ EventLog grab_log[] = {
+ { "stage", CLUTTER_LEAVE },
+ { NULL, 0 },
+ };
+ EventLog ungrab_log[] = {
+ { "stage", CLUTTER_ENTER },
+ { NULL, 0 },
+ };
+
+ test_data_init (&data);
+
+ /* Grab 'a', pointer is on its child 'b' */
+ grab = clutter_stage_grab (CLUTTER_STAGE (data.stage), data.a);
+ event_log_compare ((EventLog *) &grab_log, data.events);
+
+ clutter_grab_dismiss (grab);
+ event_log_compare ((EventLog *) &ungrab_log, data.events);
+
+ test_data_shutdown (&data);
+}
+
+static void
+grab_outside_pointer (void)
+{
+ TestData data;
+ ClutterGrab *grab;
+ EventLog grab_log[] = {
+ { "b", CLUTTER_LEAVE },
+ { "a", CLUTTER_LEAVE },
+ { "stage", CLUTTER_LEAVE },
+ { NULL, 0 },
+ };
+ EventLog ungrab_log[] = {
+ { "b", CLUTTER_ENTER },
+ { "a", CLUTTER_ENTER },
+ { "stage", CLUTTER_ENTER },
+ { NULL, 0 },
+ };
+
+ test_data_init (&data);
+
+ /* Grab 'c', pointer is on 'b' */
+ grab = clutter_stage_grab (CLUTTER_STAGE (data.stage), data.c);
+ event_log_compare ((EventLog *) &grab_log, data.events);
+
+ clutter_grab_dismiss (grab);
+ event_log_compare ((EventLog *) &ungrab_log, data.events);
+
+ test_data_shutdown (&data);
+}
+
+static void
+grab_stage (void)
+{
+ TestData data;
+ ClutterGrab *grab;
+ EventLog grab_log[] = {
+ { NULL, 0 },
+ };
+ EventLog ungrab_log[] = {
+ { NULL, 0 },
+ };
+
+ test_data_init (&data);
+
+ /* Grab 'stage', pointer is on 'b' */
+ grab = clutter_stage_grab (CLUTTER_STAGE (data.stage), data.stage);
+ event_log_compare ((EventLog *) &grab_log, data.events);
+
+ clutter_grab_dismiss (grab);
+ event_log_compare ((EventLog *) &ungrab_log, data.events);
+
+ test_data_shutdown (&data);
+}
+
+static void
+grab_stack_1 (void)
+{
+ TestData data;
+ ClutterGrab *grab1, *grab2;
+ EventLog grab1_log[] = {
+ { "a", CLUTTER_LEAVE },
+ { "stage", CLUTTER_LEAVE },
+ { NULL, 0 },
+ };
+ EventLog grab2_log[] = {
+ { "b", CLUTTER_LEAVE },
+ { "a", CLUTTER_LEAVE },
+ { "stage", CLUTTER_LEAVE },
+ { NULL, 0 },
+ };
+ EventLog ungrab2_log[] = {
+ { "b", CLUTTER_ENTER },
+ { NULL, 0 },
+ };
+ EventLog ungrab1_log[] = {
+ { "a", CLUTTER_ENTER },
+ { "stage", CLUTTER_ENTER },
+ { NULL, 0 },
+ };
+
+ test_data_init (&data);
+
+ /* Grab 'b', pointer is on 'b' */
+ grab1 = clutter_stage_grab (CLUTTER_STAGE (data.stage), data.b);
+ event_log_compare ((EventLog *) &grab1_log, data.events);
+
+ /* Grab 'c', pointer and grab is on 'b' */
+ grab2 = clutter_stage_grab (CLUTTER_STAGE (data.stage), data.c);
+ event_log_compare ((EventLog *) &grab2_log, data.events);
+
+ /* Dismiss orderly */
+ clutter_grab_dismiss (grab2);
+ event_log_compare ((EventLog *) &ungrab2_log, data.events);
+
+ clutter_grab_dismiss (grab1);
+ event_log_compare ((EventLog *) &ungrab1_log, data.events);
+
+ test_data_shutdown (&data);
+}
+
+static void
+grab_stack_2 (void)
+{
+ TestData data;
+ ClutterGrab *grab1, *grab2;
+ EventLog grab1_log[] = {
+ { "b", CLUTTER_LEAVE },
+ { "a", CLUTTER_LEAVE },
+ { "stage", CLUTTER_LEAVE },
+ { NULL, 0 },
+ };
+ EventLog grab2_log[] = {
+ { "b", CLUTTER_ENTER },
+ { NULL, 0 },
+ };
+ EventLog ungrab2_log[] = {
+ { "b", CLUTTER_LEAVE },
+ { "a", CLUTTER_LEAVE },
+ { "stage", CLUTTER_LEAVE },
+ { NULL, 0 },
+ };
+ EventLog ungrab1_log[] = {
+ { "b", CLUTTER_ENTER },
+ { "a", CLUTTER_ENTER },
+ { "stage", CLUTTER_ENTER },
+ { NULL, 0 },
+ };
+
+ test_data_init (&data);
+
+ /* Grab 'c', pointer is on 'b' */
+ grab1 = clutter_stage_grab (CLUTTER_STAGE (data.stage), data.c);
+ event_log_compare ((EventLog *) &grab1_log, data.events);
+
+ /* Grab 'b', pointer is on b, prior grab is on 'c' */
+ grab2 = clutter_stage_grab (CLUTTER_STAGE (data.stage), data.b);
+ event_log_compare ((EventLog *) &grab2_log, data.events);
+
+ /* Dismiss orderly */
+ clutter_grab_dismiss (grab2);
+ event_log_compare ((EventLog *) &ungrab2_log, data.events);
+
+ clutter_grab_dismiss (grab1);
+ event_log_compare ((EventLog *) &ungrab1_log, data.events);
+
+ test_data_shutdown (&data);
+}
+
+static void
+grab_unordered_ungrab_1 (void)
+{
+ TestData data;
+ ClutterGrab *grab1, *grab2;
+ EventLog grab1_log[] = {
+ { "a", CLUTTER_LEAVE },
+ { "stage", CLUTTER_LEAVE },
+ { NULL, 0 },
+ };
+ EventLog grab2_log[] = {
+ { "b", CLUTTER_LEAVE },
+ { "a", CLUTTER_LEAVE },
+ { "stage", CLUTTER_LEAVE },
+ { NULL, 0 },
+ };
+ EventLog ungrab1_log[] = {
+ { NULL, 0 },
+ };
+ EventLog ungrab2_log[] = {
+ { "b", CLUTTER_ENTER },
+ { "a", CLUTTER_ENTER },
+ { "stage", CLUTTER_ENTER },
+ { NULL, 0 },
+ };
+
+ test_data_init (&data);
+
+ /* Grab 'b', pointer is on 'b' */
+ grab1 = clutter_stage_grab (CLUTTER_STAGE (data.stage), data.b);
+ event_log_compare ((EventLog *) &grab1_log, data.events);
+
+ /* Grab 'c', pointer and grab is on 'b' */
+ grab2 = clutter_stage_grab (CLUTTER_STAGE (data.stage), data.c);
+ event_log_compare ((EventLog *) &grab2_log, data.events);
+
+ /* Dismiss disorderly */
+ clutter_grab_dismiss (grab1);
+ event_log_compare ((EventLog *) &ungrab1_log, data.events);
+
+ clutter_grab_dismiss (grab2);
+ event_log_compare ((EventLog *) &ungrab2_log, data.events);
+
+ test_data_shutdown (&data);
+}
+
+static void
+grab_unordered_ungrab_2 (void)
+{
+ TestData data;
+ ClutterGrab *grab1, *grab2;
+ EventLog grab1_log[] = {
+ { "b", CLUTTER_LEAVE },
+ { "a", CLUTTER_LEAVE },
+ { "stage", CLUTTER_LEAVE },
+ { NULL, 0 },
+ };
+ EventLog grab2_log[] = {
+ { "b", CLUTTER_ENTER },
+ { NULL, 0 },
+ };
+ EventLog ungrab1_log[] = {
+ { NULL, 0 },
+ };
+ EventLog ungrab2_log[] = {
+ { "a", CLUTTER_ENTER },
+ { "stage", CLUTTER_ENTER },
+ { NULL, 0 },
+ };
+
+ test_data_init (&data);
+
+ /* Grab 'c', pointer is on 'b' */
+ grab1 = clutter_stage_grab (CLUTTER_STAGE (data.stage), data.c);
+ event_log_compare ((EventLog *) &grab1_log, data.events);
+
+ /* Grab 'b', pointer is on b, prior grab is on 'c' */
+ grab2 = clutter_stage_grab (CLUTTER_STAGE (data.stage), data.b);
+ event_log_compare ((EventLog *) &grab2_log, data.events);
+
+ /* Dismiss disorderly */
+ clutter_grab_dismiss (grab1);
+ event_log_compare ((EventLog *) &ungrab1_log, data.events);
+
+ clutter_grab_dismiss (grab2);
+ event_log_compare ((EventLog *) &ungrab2_log, data.events);
+
+ test_data_shutdown (&data);
+}
+
+static void
+grab_key_focus_in_grab (void)
+{
+ TestData data;
+ ClutterGrab *grab;
+
+ test_data_init (&data);
+
+ clutter_actor_grab_key_focus (data.b);
+ g_assert_true (clutter_actor_has_key_focus (data.b));
+
+ grab = clutter_stage_grab (CLUTTER_STAGE (data.stage), data.b);
+ g_assert_true (clutter_actor_has_key_focus (data.b));
+
+ clutter_grab_dismiss (grab);
+ g_assert_true (clutter_actor_has_key_focus (data.b));
+
+ test_data_shutdown (&data);
+}
+
+static void
+grab_key_focus_outside_grab (void)
+{
+ TestData data;
+ ClutterGrab *grab;
+
+ test_data_init (&data);
+
+ clutter_actor_grab_key_focus (data.b);
+ g_assert_true (clutter_actor_has_key_focus (data.b));
+
+ grab = clutter_stage_grab (CLUTTER_STAGE (data.stage), data.c);
+ g_assert_false (clutter_actor_has_key_focus (data.b));
+
+ clutter_grab_dismiss (grab);
+ g_assert_true (clutter_actor_has_key_focus (data.b));
+
+ test_data_shutdown (&data);
+}
+
+CLUTTER_TEST_SUITE (
+ CLUTTER_TEST_UNIT ("/grab/grab-under-pointer", grab_under_pointer)
+ CLUTTER_TEST_UNIT ("/grab/grab-under-pointers-parent", grab_under_pointers_parent)
+ CLUTTER_TEST_UNIT ("/grab/grab-outside-pointer", grab_outside_pointer)
+ CLUTTER_TEST_UNIT ("/grab/grab-stage", grab_stage)
+ CLUTTER_TEST_UNIT ("/grab/grab-stack-1", grab_stack_1)
+ CLUTTER_TEST_UNIT ("/grab/grab-stack-2", grab_stack_2)
+ CLUTTER_TEST_UNIT ("/grab/grab-unordered-ungrab-1", grab_unordered_ungrab_1)
+ CLUTTER_TEST_UNIT ("/grab/grab-unordered-ungrab-2", grab_unordered_ungrab_2)
+ CLUTTER_TEST_UNIT ("/grab/key-focus-in-grab", grab_key_focus_in_grab);
+ CLUTTER_TEST_UNIT ("/grab/key-focus-outside-grab", grab_key_focus_outside_grab);
+)
diff --git a/src/tests/clutter/conform/meson.build b/src/tests/clutter/conform/meson.build
index f02b78b417..83aa7a054f 100644
--- a/src/tests/clutter/conform/meson.build
+++ b/src/tests/clutter/conform/meson.build
@@ -35,6 +35,7 @@ clutter_conform_tests_general_tests = [
'color',
'frame-clock',
'frame-clock-timeline',
+ 'grab',
'interval',
'script-parser',
'timeline',
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]