diff --git a/tests/conform/Makefile.am b/tests/conform/Makefile.am index 167605103..b34df28a1 100644 --- a/tests/conform/Makefile.am +++ b/tests/conform/Makefile.am @@ -60,8 +60,9 @@ units_sources += \ # actors tests units_sources += \ test-actor-destroy.c \ - test-actor-size.c \ test-actor-invariants.c \ + test-actor-layout.c \ + test-actor-size.c \ test-anchors.c \ test-binding-pool.c \ test-clutter-cairo-texture.c \ diff --git a/tests/conform/test-actor-layout.c b/tests/conform/test-actor-layout.c new file mode 100644 index 000000000..eb9b03101 --- /dev/null +++ b/tests/conform/test-actor-layout.c @@ -0,0 +1,288 @@ +#include +#include +#include "test-conform-common.h" + +typedef struct _TestState TestState; + +struct _TestState +{ + GPtrArray *actors; + GPtrArray *colors; + + ClutterActor *stage; + + gulong id; + + gint in_validation; + + guint is_running : 1; + guint success : 1; +}; + +static TestState * +test_state_new (void) +{ + return g_slice_new0 (TestState); +} + +static void validate_state (ClutterActor *stage, + TestState *state); + +static void +test_state_free (TestState *state) +{ + if (state->id != 0) + g_source_remove (state->id); + + if (state->actors != NULL) + g_ptr_array_unref (state->actors); + + if (state->colors != NULL) + g_ptr_array_unref (state->colors); + + if (state->stage != NULL) + { + g_signal_handlers_disconnect_by_func (state->stage, + G_CALLBACK (validate_state), + state); + clutter_actor_destroy (state->stage); + } + + g_slice_free (TestState, state); +} + +static void +test_state_set_stage (TestState *state, + ClutterActor *stage) +{ + g_assert (!state->is_running); + + state->stage = stage; +} + +static void +test_state_add_actor (TestState *state, + ClutterActor *actor, + const ClutterColor *color) +{ + g_assert (!state->is_running); + + if (state->actors == NULL) + { + state->actors = g_ptr_array_new (); + g_ptr_array_set_free_func (state->actors, + (GDestroyNotify) g_object_unref); + } + + g_ptr_array_add (state->actors, g_object_ref (actor)); + + if (state->colors == NULL) + { + state->colors = g_ptr_array_new (); + g_ptr_array_set_free_func (state->colors, + (GDestroyNotify) clutter_color_free); + } + + g_ptr_array_add (state->colors, clutter_color_copy (color)); +} + +static void +test_state_push_validation (TestState *state) +{ + state->in_validation += 1; +} + +static void +test_state_pop_validation (TestState *state) +{ + state->in_validation -= 1; +} + +static gboolean +test_state_in_validation (TestState *state) +{ + return state->in_validation > 0; +} + +static gboolean +check_color_at (ClutterActor *stage, + ClutterActor *actor, + ClutterColor *expected_color, + float x, + float y) +{ + guchar *buffer; + + if (g_test_verbose ()) + g_print ("Checking actor '%s'\n", clutter_actor_get_name (actor)); + + if (g_test_verbose ()) + g_print ("Sampling at { %d, %d }\t", (int) x, (int) y); + + buffer = clutter_stage_read_pixels (CLUTTER_STAGE (stage), x, y, 1, 1); + g_assert (buffer != NULL); + + if (g_test_verbose ()) + g_print ("Color: { %d, %d, %d } - Expected color { %d, %d, %d }\n", + buffer[0], + buffer[1], + buffer[2], + expected_color->red, + expected_color->green, + expected_color->blue); + + g_assert_cmpint (buffer[0], ==, expected_color->red); + g_assert_cmpint (buffer[1], ==, expected_color->green); + g_assert_cmpint (buffer[2], ==, expected_color->blue); + + g_free (buffer); + + return TRUE; +} + +static void +validate_state (ClutterActor *stage, + TestState *state) +{ + int i; + + /* avoid recursion */ + if (test_state_in_validation (state)) + return; + + g_assert (stage == state->stage); + g_assert (state->actors != NULL); + g_assert (state->colors != NULL); + + g_assert_cmpint (state->actors->len, ==, state->colors->len); + + test_state_push_validation (state); + + if (g_test_verbose ()) + g_print ("Sampling %d actors\n", state->actors->len); + + for (i = 0; i < state->actors->len; i++) + { + ClutterActor *actor = g_ptr_array_index (state->actors, i); + ClutterColor *color = g_ptr_array_index (state->colors, i); + ClutterActorBox box; + + clutter_actor_get_allocation_box (actor, &box); + + g_assert (check_color_at (stage, actor, color, box.x1 + 2, box.y1 + 2)); + g_assert (check_color_at (stage, actor, color, box.x2 - 2, box.y2 - 2)); + } + + test_state_pop_validation (state); + + state->success = TRUE; + + clutter_main_quit (); +} + +static gboolean +queue_redraw (gpointer data_) +{ + TestState *state = data_; + + clutter_actor_queue_redraw (state->stage); + + return TRUE; +} + +static gboolean +test_state_run (TestState *state) +{ + state->is_running = TRUE; + + g_signal_connect_after (state->stage, "paint", G_CALLBACK (validate_state), state); + state->id = clutter_threads_add_idle (queue_redraw, state); + + clutter_main (); + + return state->success; +} + +void +basic_layout (TestConformSimpleFixture *fixture, + gconstpointer data) +{ + ClutterActor *stage = clutter_stage_new (); + ClutterActor *vase; + ClutterActor *flower[3]; + TestState *state; + + vase = clutter_box_new (clutter_flow_layout_new (CLUTTER_FLOW_HORIZONTAL)); + clutter_container_add_actor (CLUTTER_CONTAINER (stage), vase); + + flower[0] = clutter_rectangle_new_with_color (CLUTTER_COLOR_Red); + clutter_actor_set_size (flower[0], 100, 100); + clutter_actor_set_name (flower[0], "Red Flower"); + clutter_container_add_actor (CLUTTER_CONTAINER (vase), flower[0]); + + flower[1] = clutter_rectangle_new_with_color (CLUTTER_COLOR_Yellow); + clutter_actor_set_size (flower[1], 100, 100); + clutter_actor_set_name (flower[1], "Yellow Flower"); + clutter_container_add_actor (CLUTTER_CONTAINER (vase), flower[1]); + + flower[2] = clutter_rectangle_new_with_color (CLUTTER_COLOR_Green); + clutter_actor_set_size (flower[2], 100, 100); + clutter_actor_set_name (flower[2], "Green Flower"); + clutter_container_add_actor (CLUTTER_CONTAINER (vase), flower[2]); + + clutter_actor_show_all (stage); + + state = test_state_new (); + test_state_set_stage (state, stage); + test_state_add_actor (state, flower[0], CLUTTER_COLOR_Red); + test_state_add_actor (state, flower[1], CLUTTER_COLOR_Yellow); + test_state_add_actor (state, flower[2], CLUTTER_COLOR_Green); + + g_assert (test_state_run (state)); + + test_state_free (state); +} + +void +margin_layout (TestConformSimpleFixture *fixture, + gconstpointer data) +{ + ClutterActor *stage = clutter_stage_new (); + ClutterActor *vase; + ClutterActor *flower[3]; + TestState *state; + + vase = clutter_box_new (clutter_flow_layout_new (CLUTTER_FLOW_HORIZONTAL)); + clutter_container_add_actor (CLUTTER_CONTAINER (stage), vase); + + flower[0] = clutter_rectangle_new_with_color (CLUTTER_COLOR_Red); + clutter_actor_set_size (flower[0], 100, 100); + clutter_actor_set_name (flower[0], "Red Flower"); + clutter_container_add_actor (CLUTTER_CONTAINER (vase), flower[0]); + + flower[1] = clutter_rectangle_new_with_color (CLUTTER_COLOR_Yellow); + clutter_actor_set_size (flower[1], 100, 100); + clutter_actor_set_name (flower[1], "Yellow Flower"); + clutter_actor_set_margin_right (flower[1], 6); + clutter_actor_set_margin_left (flower[1], 6); + clutter_container_add_actor (CLUTTER_CONTAINER (vase), flower[1]); + + flower[2] = clutter_rectangle_new_with_color (CLUTTER_COLOR_Green); + clutter_actor_set_size (flower[2], 100, 100); + clutter_actor_set_name (flower[2], "Green Flower"); + clutter_actor_set_margin_top (flower[2], 6); + clutter_actor_set_margin_bottom (flower[2], 6); + clutter_container_add_actor (CLUTTER_CONTAINER (vase), flower[2]); + + clutter_actor_show_all (stage); + + state = test_state_new (); + test_state_set_stage (state, stage); + test_state_add_actor (state, flower[0], CLUTTER_COLOR_Red); + test_state_add_actor (state, flower[1], CLUTTER_COLOR_Yellow); + test_state_add_actor (state, flower[2], CLUTTER_COLOR_Green); + + g_assert (test_state_run (state)); + + test_state_free (state); +} diff --git a/tests/conform/test-conform-main.c b/tests/conform/test-conform-main.c index afbde487a..c9903471a 100644 --- a/tests/conform/test-conform-main.c +++ b/tests/conform/test-conform-main.c @@ -135,6 +135,8 @@ main (int argc, char **argv) TEST_CONFORM_SIMPLE ("/actor", actor_preferred_size); TEST_CONFORM_SIMPLE ("/actor", test_offscreen_redirect); TEST_CONFORM_SIMPLE ("/actor", test_shader_effect); + TEST_CONFORM_SIMPLE ("/actor", basic_layout); + TEST_CONFORM_SIMPLE ("/actor", margin_layout); TEST_CONFORM_SIMPLE ("/invariants", test_initial_state); TEST_CONFORM_SIMPLE ("/invariants", test_shown_not_parented);