2 * Copyright © 2012 Collabora, Ltd.
4 * Permission to use, copy, modify, distribute, and sell this software and
5 * its documentation for any purpose is hereby granted without fee, provided
6 * that the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of the copyright holders not be used in
9 * advertising or publicity pertaining to distribution of the software
10 * without specific, written prior permission. The copyright holders make
11 * no representations about the suitability of this software for any
12 * purpose. It is provided "as is" without express or implied warranty.
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
15 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
17 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
18 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
19 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
25 #include "weston-test-client-helper.h"
26 #include "subsurface-client-protocol.h"
29 #define NUM_SUBSURFACES 3
31 struct compound_surface {
32 struct wl_subcompositor *subco;
33 struct wl_surface *parent;
34 struct wl_surface *child[NUM_SUBSURFACES];
35 struct wl_subsurface *sub[NUM_SUBSURFACES];
38 static struct wl_subcompositor *
39 get_subcompositor(struct client *client)
42 struct global *global_sub = NULL;
43 struct wl_subcompositor *sub;
45 wl_list_for_each(g, &client->global_list, link) {
46 if (strcmp(g->interface, "wl_subcompositor"))
50 assert(0 && "multiple wl_subcompositor objects");
55 assert(global_sub && "no wl_subcompositor found");
57 assert(global_sub->version == 1);
59 sub = wl_registry_bind(client->wl_registry, global_sub->name,
60 &wl_subcompositor_interface, 1);
67 populate_compound_surface(struct compound_surface *com, struct client *client)
71 com->subco = get_subcompositor(client);
73 com->parent = wl_compositor_create_surface(client->wl_compositor);
75 for (i = 0; i < NUM_SUBSURFACES; i++) {
77 wl_compositor_create_surface(client->wl_compositor);
79 wl_subcompositor_get_subsurface(com->subco,
85 TEST(test_subsurface_basic_protocol)
87 struct client *client;
88 struct compound_surface com1;
89 struct compound_surface com2;
91 client = client_create(100, 50, 123, 77);
94 populate_compound_surface(&com1, client);
95 populate_compound_surface(&com2, client);
97 client_roundtrip(client);
100 TEST(test_subsurface_position_protocol)
102 struct client *client;
103 struct compound_surface com;
106 client = client_create(100, 50, 123, 77);
109 populate_compound_surface(&com, client);
110 for (i = 0; i < NUM_SUBSURFACES; i++)
111 wl_subsurface_set_position(com.sub[i],
112 (i + 2) * 20, (i + 2) * 10);
114 client_roundtrip(client);
117 TEST(test_subsurface_placement_protocol)
119 struct client *client;
120 struct compound_surface com;
122 client = client_create(100, 50, 123, 77);
125 populate_compound_surface(&com, client);
127 wl_subsurface_place_above(com.sub[0], com.child[1]);
128 wl_subsurface_place_above(com.sub[1], com.parent);
129 wl_subsurface_place_below(com.sub[2], com.child[0]);
130 wl_subsurface_place_below(com.sub[1], com.parent);
132 client_roundtrip(client);
135 FAIL_TEST(test_subsurface_paradox)
137 struct client *client;
138 struct wl_surface *parent;
139 struct wl_subcompositor *subco;
141 client = client_create(100, 50, 123, 77);
144 subco = get_subcompositor(client);
145 parent = wl_compositor_create_surface(client->wl_compositor);
147 /* surface is its own parent */
148 wl_subcompositor_get_subsurface(subco, parent, parent);
150 client_roundtrip(client);
153 FAIL_TEST(test_subsurface_identical_link)
155 struct client *client;
156 struct compound_surface com;
158 client = client_create(100, 50, 123, 77);
161 populate_compound_surface(&com, client);
163 /* surface is already a subsurface */
164 wl_subcompositor_get_subsurface(com.subco, com.child[0], com.parent);
166 client_roundtrip(client);
169 FAIL_TEST(test_subsurface_change_link)
171 struct client *client;
172 struct compound_surface com;
173 struct wl_surface *stranger;
175 client = client_create(100, 50, 123, 77);
178 stranger = wl_compositor_create_surface(client->wl_compositor);
179 populate_compound_surface(&com, client);
181 /* surface is already a subsurface */
182 wl_subcompositor_get_subsurface(com.subco, com.child[0], stranger);
184 client_roundtrip(client);
187 TEST(test_subsurface_nesting)
189 struct client *client;
190 struct compound_surface com;
191 struct wl_surface *stranger;
193 client = client_create(100, 50, 123, 77);
196 stranger = wl_compositor_create_surface(client->wl_compositor);
197 populate_compound_surface(&com, client);
199 /* parent is a sub-surface */
200 wl_subcompositor_get_subsurface(com.subco, stranger, com.child[0]);
202 client_roundtrip(client);
205 TEST(test_subsurface_nesting_parent)
207 struct client *client;
208 struct compound_surface com;
209 struct wl_surface *stranger;
211 client = client_create(100, 50, 123, 77);
214 stranger = wl_compositor_create_surface(client->wl_compositor);
215 populate_compound_surface(&com, client);
217 /* surface is already a parent */
218 wl_subcompositor_get_subsurface(com.subco, com.parent, stranger);
220 client_roundtrip(client);
223 FAIL_TEST(test_subsurface_loop_paradox)
225 struct client *client;
226 struct wl_surface *surface[3];
227 struct wl_subcompositor *subco;
229 client = client_create(100, 50, 123, 77);
232 subco = get_subcompositor(client);
233 surface[0] = wl_compositor_create_surface(client->wl_compositor);
234 surface[1] = wl_compositor_create_surface(client->wl_compositor);
235 surface[2] = wl_compositor_create_surface(client->wl_compositor);
237 /* create a nesting loop */
238 wl_subcompositor_get_subsurface(subco, surface[1], surface[0]);
239 wl_subcompositor_get_subsurface(subco, surface[2], surface[1]);
240 wl_subcompositor_get_subsurface(subco, surface[0], surface[2]);
242 client_roundtrip(client);
245 FAIL_TEST(test_subsurface_place_above_stranger)
247 struct client *client;
248 struct compound_surface com;
249 struct wl_surface *stranger;
251 client = client_create(100, 50, 123, 77);
254 stranger = wl_compositor_create_surface(client->wl_compositor);
255 populate_compound_surface(&com, client);
258 wl_subsurface_place_above(com.sub[0], stranger);
260 client_roundtrip(client);
263 FAIL_TEST(test_subsurface_place_below_stranger)
265 struct client *client;
266 struct compound_surface com;
267 struct wl_surface *stranger;
269 client = client_create(100, 50, 123, 77);
272 stranger = wl_compositor_create_surface(client->wl_compositor);
273 populate_compound_surface(&com, client);
276 wl_subsurface_place_below(com.sub[0], stranger);
278 client_roundtrip(client);
281 FAIL_TEST(test_subsurface_place_above_foreign)
283 struct client *client;
284 struct compound_surface com1;
285 struct compound_surface com2;
287 client = client_create(100, 50, 123, 77);
290 populate_compound_surface(&com1, client);
291 populate_compound_surface(&com2, client);
294 wl_subsurface_place_above(com1.sub[0], com2.child[0]);
296 client_roundtrip(client);
299 FAIL_TEST(test_subsurface_place_below_foreign)
301 struct client *client;
302 struct compound_surface com1;
303 struct compound_surface com2;
305 client = client_create(100, 50, 123, 77);
308 populate_compound_surface(&com1, client);
309 populate_compound_surface(&com2, client);
312 wl_subsurface_place_below(com1.sub[0], com2.child[0]);
314 client_roundtrip(client);
317 TEST(test_subsurface_destroy_protocol)
319 struct client *client;
320 struct compound_surface com;
322 client = client_create(100, 50, 123, 77);
325 populate_compound_surface(&com, client);
327 /* not needed anymore */
328 wl_subcompositor_destroy(com.subco);
330 /* detach child from parent */
331 wl_subsurface_destroy(com.sub[0]);
333 /* destroy: child, parent */
334 wl_surface_destroy(com.child[1]);
335 wl_surface_destroy(com.parent);
337 /* destroy: parent, child */
338 wl_surface_destroy(com.child[2]);
340 /* destroy: sub, child */
341 wl_surface_destroy(com.child[0]);
343 /* 2x destroy: child, sub */
344 wl_subsurface_destroy(com.sub[2]);
345 wl_subsurface_destroy(com.sub[1]);
347 client_roundtrip(client);
351 create_subsurface_tree(struct client *client, struct wl_surface **surfs,
352 struct wl_subsurface **subs, int n)
354 struct wl_subcompositor *subco;
357 subco = get_subcompositor(client);
359 for (i = 0; i < n; i++)
360 surfs[i] = wl_compositor_create_surface(client->wl_compositor);
363 * The tree of sub-surfaces:
371 * Surface 0 has no wl_subsurface, others do.
379 #define SUB_LINK(s,p) \
380 subs[s] = wl_subcompositor_get_subsurface(subco, surfs[s], surfs[p])
408 destroy_subsurface_tree(struct wl_surface **surfs,
409 struct wl_subsurface **subs, int n)
413 for (i = n; i-- > 0; ) {
415 wl_surface_destroy(surfs[i]);
418 wl_subsurface_destroy(subs[i]);
423 has_dupe(int *cnt, int n)
427 for (i = 0; i < n; i++)
428 if (cnt[i] == cnt[n])
434 /* Note: number of permutations to test is: set_size! / (set_size - NSTEPS)!
444 permu_init(struct permu_state *s, int set_size)
448 s->set_size = set_size;
449 for (i = 0; i < NSTEPS; i++)
454 permu_next(struct permu_state *s)
458 s->cnt[NSTEPS - 1]++;
461 if (s->cnt[0] >= s->set_size) {
465 for (k = 1; k < NSTEPS; k++) {
466 if (s->cnt[k] >= s->set_size) {
472 if (has_dupe(s->cnt, k)) {
484 destroy_permu_object(struct wl_surface **surfs,
485 struct wl_subsurface **subs, int i)
490 fprintf(stderr, " [sub %2d]", h);
491 wl_subsurface_destroy(subs[h]);
494 fprintf(stderr, " [surf %2d]", h);
495 wl_surface_destroy(surfs[h]);
500 TEST(test_subsurface_destroy_permutations)
503 * Test wl_surface and wl_subsurface destruction orders in a
504 * complex tree of sub-surfaces.
506 * In the tree of sub-surfaces, go through every possible
507 * permutation of destroying all wl_surface and wl_subsurface
508 * objects. Execpt, to limit running time to a reasonable level,
509 * execute only the first NSTEPS destructions from each
510 * permutation, and ignore identical cases.
513 const int test_size = 11;
514 struct client *client;
515 struct wl_surface *surfs[test_size];
516 struct wl_subsurface *subs[test_size];
517 struct permu_state per;
521 client = client_create(100, 50, 123, 77);
524 permu_init(&per, test_size * 2 - 1);
525 while (permu_next(&per) != -1) {
526 /* for each permutation of NSTEPS out of test_size */
527 memset(surfs, 0, sizeof surfs);
528 memset(subs, 0, sizeof subs);
530 create_subsurface_tree(client, surfs, subs, test_size);
532 fprintf(stderr, "permu");
534 for (i = 0; i < NSTEPS; i++)
535 fprintf(stderr, " %2d", per.cnt[i]);
537 for (i = 0; i < NSTEPS; i++)
538 destroy_permu_object(surfs, subs, per.cnt[i]);
540 fprintf(stderr, "\n");
541 client_roundtrip(client);
543 destroy_subsurface_tree(surfs, subs, test_size);
547 client_roundtrip(client);
548 fprintf(stderr, "tried %d destroy permutations\n", counter);