2 * Copyright © 2012 Collabora, Ltd.
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial
14 * portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31 #include "weston-test-client-helper.h"
33 #define NUM_SUBSURFACES 3
35 struct compound_surface {
36 struct wl_subcompositor *subco;
37 struct wl_surface *parent;
38 struct wl_surface *child[NUM_SUBSURFACES];
39 struct wl_subsurface *sub[NUM_SUBSURFACES];
42 static struct wl_subcompositor *
43 get_subcompositor(struct client *client)
46 struct global *global_sub = NULL;
47 struct wl_subcompositor *sub;
49 wl_list_for_each(g, &client->global_list, link) {
50 if (strcmp(g->interface, "wl_subcompositor"))
54 assert(0 && "multiple wl_subcompositor objects");
59 assert(global_sub && "no wl_subcompositor found");
61 assert(global_sub->version == 1);
63 sub = wl_registry_bind(client->wl_registry, global_sub->name,
64 &wl_subcompositor_interface, 1);
71 populate_compound_surface(struct compound_surface *com, struct client *client)
75 com->subco = get_subcompositor(client);
77 com->parent = wl_compositor_create_surface(client->wl_compositor);
79 for (i = 0; i < NUM_SUBSURFACES; i++) {
81 wl_compositor_create_surface(client->wl_compositor);
83 wl_subcompositor_get_subsurface(com->subco,
89 TEST(test_subsurface_basic_protocol)
91 struct client *client;
92 struct compound_surface com1;
93 struct compound_surface com2;
95 client = create_client_and_test_surface(100, 50, 123, 77);
98 populate_compound_surface(&com1, client);
99 populate_compound_surface(&com2, client);
101 client_roundtrip(client);
104 TEST(test_subsurface_position_protocol)
106 struct client *client;
107 struct compound_surface com;
110 client = create_client_and_test_surface(100, 50, 123, 77);
113 populate_compound_surface(&com, client);
114 for (i = 0; i < NUM_SUBSURFACES; i++)
115 wl_subsurface_set_position(com.sub[i],
116 (i + 2) * 20, (i + 2) * 10);
118 client_roundtrip(client);
121 TEST(test_subsurface_placement_protocol)
123 struct client *client;
124 struct compound_surface com;
126 client = create_client_and_test_surface(100, 50, 123, 77);
129 populate_compound_surface(&com, client);
131 wl_subsurface_place_above(com.sub[0], com.child[1]);
132 wl_subsurface_place_above(com.sub[1], com.parent);
133 wl_subsurface_place_below(com.sub[2], com.child[0]);
134 wl_subsurface_place_below(com.sub[1], com.parent);
136 client_roundtrip(client);
139 TEST(test_subsurface_paradox)
141 struct client *client;
142 struct wl_surface *parent;
143 struct wl_subcompositor *subco;
145 client = create_client_and_test_surface(100, 50, 123, 77);
148 subco = get_subcompositor(client);
149 parent = wl_compositor_create_surface(client->wl_compositor);
151 /* surface is its own parent */
152 wl_subcompositor_get_subsurface(subco, parent, parent);
154 expect_protocol_error(client, &wl_subcompositor_interface,
155 WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE);
158 TEST(test_subsurface_identical_link)
160 struct client *client;
161 struct compound_surface com;
163 client = create_client_and_test_surface(100, 50, 123, 77);
166 populate_compound_surface(&com, client);
168 /* surface is already a subsurface */
169 wl_subcompositor_get_subsurface(com.subco, com.child[0], com.parent);
171 expect_protocol_error(client, &wl_subcompositor_interface,
172 WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE);
175 TEST(test_subsurface_change_link)
177 struct client *client;
178 struct compound_surface com;
179 struct wl_surface *stranger;
181 client = create_client_and_test_surface(100, 50, 123, 77);
184 stranger = wl_compositor_create_surface(client->wl_compositor);
185 populate_compound_surface(&com, client);
187 /* surface is already a subsurface */
188 wl_subcompositor_get_subsurface(com.subco, com.child[0], stranger);
190 expect_protocol_error(client, &wl_subcompositor_interface,
191 WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE);
194 TEST(test_subsurface_nesting)
196 struct client *client;
197 struct compound_surface com;
198 struct wl_surface *stranger;
200 client = create_client_and_test_surface(100, 50, 123, 77);
203 stranger = wl_compositor_create_surface(client->wl_compositor);
204 populate_compound_surface(&com, client);
206 /* parent is a sub-surface */
207 wl_subcompositor_get_subsurface(com.subco, stranger, com.child[0]);
209 client_roundtrip(client);
212 TEST(test_subsurface_nesting_parent)
214 struct client *client;
215 struct compound_surface com;
216 struct wl_surface *stranger;
218 client = create_client_and_test_surface(100, 50, 123, 77);
221 stranger = wl_compositor_create_surface(client->wl_compositor);
222 populate_compound_surface(&com, client);
224 /* surface is already a parent */
225 wl_subcompositor_get_subsurface(com.subco, com.parent, stranger);
227 client_roundtrip(client);
230 TEST(test_subsurface_loop_paradox)
232 struct client *client;
233 struct wl_surface *surface[3];
234 struct wl_subcompositor *subco;
236 client = create_client_and_test_surface(100, 50, 123, 77);
239 subco = get_subcompositor(client);
240 surface[0] = wl_compositor_create_surface(client->wl_compositor);
241 surface[1] = wl_compositor_create_surface(client->wl_compositor);
242 surface[2] = wl_compositor_create_surface(client->wl_compositor);
244 /* create a nesting loop */
245 wl_subcompositor_get_subsurface(subco, surface[1], surface[0]);
246 wl_subcompositor_get_subsurface(subco, surface[2], surface[1]);
247 wl_subcompositor_get_subsurface(subco, surface[0], surface[2]);
249 expect_protocol_error(client, &wl_subcompositor_interface,
250 WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE);
253 TEST(test_subsurface_place_above_nested_parent)
255 struct client *client;
256 struct compound_surface com;
257 struct wl_surface *grandchild;
258 struct wl_subcompositor *subco;
259 struct wl_subsurface *sub;
261 client = create_client_and_test_surface(100, 50, 123, 77);
264 populate_compound_surface(&com, client);
266 subco = get_subcompositor(client);
267 grandchild = wl_compositor_create_surface(client->wl_compositor);
268 sub = wl_subcompositor_get_subsurface(subco, grandchild, com.child[0]);
270 wl_subsurface_place_above(sub, com.child[0]);
272 client_roundtrip(client);
275 TEST(test_subsurface_place_above_grandparent)
277 struct client *client;
278 struct compound_surface com;
279 struct wl_surface *grandchild;
280 struct wl_subsurface *sub;
281 struct wl_subcompositor *subco;
283 client = create_client_and_test_surface(100, 50, 123, 77);
286 populate_compound_surface(&com, client);
288 subco = get_subcompositor(client);
289 grandchild = wl_compositor_create_surface(client->wl_compositor);
290 sub = wl_subcompositor_get_subsurface(subco, grandchild, com.child[0]);
292 /* can't place a subsurface above its grandparent */
293 wl_subsurface_place_above(sub, com.parent);
295 expect_protocol_error(client, &wl_subsurface_interface,
296 WL_SUBSURFACE_ERROR_BAD_SURFACE);
299 TEST(test_subsurface_place_above_great_aunt)
301 struct client *client;
302 struct compound_surface com;
303 struct wl_surface *grandchild;
304 struct wl_subsurface *sub;
305 struct wl_subcompositor *subco;
307 client = create_client_and_test_surface(100, 50, 123, 77);
310 populate_compound_surface(&com, client);
312 subco = get_subcompositor(client);
313 grandchild = wl_compositor_create_surface(client->wl_compositor);
314 sub = wl_subcompositor_get_subsurface(subco, grandchild, com.child[0]);
316 /* can't place a subsurface above its parents' siblings */
317 wl_subsurface_place_above(sub, com.child[1]);
319 expect_protocol_error(client, &wl_subsurface_interface,
320 WL_SUBSURFACE_ERROR_BAD_SURFACE);
323 TEST(test_subsurface_place_above_child)
325 struct client *client;
326 struct compound_surface com;
327 struct wl_surface *grandchild;
328 struct wl_subcompositor *subco;
330 client = create_client_and_test_surface(100, 50, 123, 77);
333 populate_compound_surface(&com, client);
335 subco = get_subcompositor(client);
336 grandchild = wl_compositor_create_surface(client->wl_compositor);
337 wl_subcompositor_get_subsurface(subco, grandchild, com.child[0]);
339 /* can't place a subsurface above its own child subsurface */
340 wl_subsurface_place_above(com.sub[0], grandchild);
342 expect_protocol_error(client, &wl_subsurface_interface,
343 WL_SUBSURFACE_ERROR_BAD_SURFACE);
346 TEST(test_subsurface_place_below_nested_parent)
348 struct client *client;
349 struct compound_surface com;
350 struct wl_subcompositor *subco;
351 struct wl_surface *grandchild;
352 struct wl_subsurface *sub;
354 client = create_client_and_test_surface(100, 50, 123, 77);
357 populate_compound_surface(&com, client);
359 subco = get_subcompositor(client);
360 grandchild = wl_compositor_create_surface(client->wl_compositor);
361 sub = wl_subcompositor_get_subsurface(subco, grandchild, com.child[0]);
363 wl_subsurface_place_below(sub, com.child[0]);
365 client_roundtrip(client);
368 TEST(test_subsurface_place_below_grandparent)
370 struct client *client;
371 struct compound_surface com;
372 struct wl_surface *grandchild;
373 struct wl_subsurface *sub;
374 struct wl_subcompositor *subco;
376 client = create_client_and_test_surface(100, 50, 123, 77);
379 populate_compound_surface(&com, client);
381 subco = get_subcompositor(client);
382 grandchild = wl_compositor_create_surface(client->wl_compositor);
383 sub = wl_subcompositor_get_subsurface(subco, grandchild, com.child[0]);
385 /* can't place a subsurface below its grandparent */
386 wl_subsurface_place_below(sub, com.parent);
388 expect_protocol_error(client, &wl_subsurface_interface,
389 WL_SUBSURFACE_ERROR_BAD_SURFACE);
392 TEST(test_subsurface_place_below_great_aunt)
394 struct client *client;
395 struct compound_surface com;
396 struct wl_surface *grandchild;
397 struct wl_subsurface *sub;
398 struct wl_subcompositor *subco;
400 client = create_client_and_test_surface(100, 50, 123, 77);
403 populate_compound_surface(&com, client);
405 subco = get_subcompositor(client);
406 grandchild = wl_compositor_create_surface(client->wl_compositor);
407 sub = wl_subcompositor_get_subsurface(subco, grandchild, com.child[0]);
409 /* can't place a subsurface below its parents' siblings */
410 wl_subsurface_place_below(sub, com.child[1]);
412 expect_protocol_error(client, &wl_subsurface_interface,
413 WL_SUBSURFACE_ERROR_BAD_SURFACE);
416 TEST(test_subsurface_place_below_child)
418 struct client *client;
419 struct compound_surface com;
420 struct wl_surface *grandchild;
421 struct wl_subcompositor *subco;
423 client = create_client_and_test_surface(100, 50, 123, 77);
426 populate_compound_surface(&com, client);
428 subco = get_subcompositor(client);
429 grandchild = wl_compositor_create_surface(client->wl_compositor);
430 wl_subcompositor_get_subsurface(subco, grandchild, com.child[0]);
432 /* can't place a subsurface below its own child subsurface */
433 wl_subsurface_place_below(com.sub[0], grandchild);
435 expect_protocol_error(client, &wl_subsurface_interface,
436 WL_SUBSURFACE_ERROR_BAD_SURFACE);
439 TEST(test_subsurface_place_above_stranger)
441 struct client *client;
442 struct compound_surface com;
443 struct wl_surface *stranger;
445 client = create_client_and_test_surface(100, 50, 123, 77);
448 stranger = wl_compositor_create_surface(client->wl_compositor);
449 populate_compound_surface(&com, client);
452 wl_subsurface_place_above(com.sub[0], stranger);
454 expect_protocol_error(client, &wl_subsurface_interface,
455 WL_SUBSURFACE_ERROR_BAD_SURFACE);
458 TEST(test_subsurface_place_below_stranger)
460 struct client *client;
461 struct compound_surface com;
462 struct wl_surface *stranger;
464 client = create_client_and_test_surface(100, 50, 123, 77);
467 stranger = wl_compositor_create_surface(client->wl_compositor);
468 populate_compound_surface(&com, client);
471 wl_subsurface_place_below(com.sub[0], stranger);
473 expect_protocol_error(client, &wl_subsurface_interface,
474 WL_SUBSURFACE_ERROR_BAD_SURFACE);
477 TEST(test_subsurface_place_above_foreign)
479 struct client *client;
480 struct compound_surface com1;
481 struct compound_surface com2;
483 client = create_client_and_test_surface(100, 50, 123, 77);
486 populate_compound_surface(&com1, client);
487 populate_compound_surface(&com2, client);
490 wl_subsurface_place_above(com1.sub[0], com2.child[0]);
492 expect_protocol_error(client, &wl_subsurface_interface,
493 WL_SUBSURFACE_ERROR_BAD_SURFACE);
496 TEST(test_subsurface_place_below_foreign)
498 struct client *client;
499 struct compound_surface com1;
500 struct compound_surface com2;
502 client = create_client_and_test_surface(100, 50, 123, 77);
505 populate_compound_surface(&com1, client);
506 populate_compound_surface(&com2, client);
509 wl_subsurface_place_below(com1.sub[0], com2.child[0]);
511 expect_protocol_error(client, &wl_subsurface_interface,
512 WL_SUBSURFACE_ERROR_BAD_SURFACE);
515 TEST(test_subsurface_destroy_protocol)
517 struct client *client;
518 struct compound_surface com;
520 client = create_client_and_test_surface(100, 50, 123, 77);
523 populate_compound_surface(&com, client);
525 /* not needed anymore */
526 wl_subcompositor_destroy(com.subco);
528 /* detach child from parent */
529 wl_subsurface_destroy(com.sub[0]);
531 /* destroy: child, parent */
532 wl_surface_destroy(com.child[1]);
533 wl_surface_destroy(com.parent);
535 /* destroy: parent, child */
536 wl_surface_destroy(com.child[2]);
538 /* destroy: sub, child */
539 wl_surface_destroy(com.child[0]);
541 /* 2x destroy: child, sub */
542 wl_subsurface_destroy(com.sub[2]);
543 wl_subsurface_destroy(com.sub[1]);
545 client_roundtrip(client);
549 create_subsurface_tree(struct client *client, struct wl_surface **surfs,
550 struct wl_subsurface **subs, int n)
552 struct wl_subcompositor *subco;
555 subco = get_subcompositor(client);
557 for (i = 0; i < n; i++)
558 surfs[i] = wl_compositor_create_surface(client->wl_compositor);
561 * The tree of sub-surfaces:
569 * Surface 0 has no wl_subsurface, others do.
577 #define SUB_LINK(s,p) \
578 subs[s] = wl_subcompositor_get_subsurface(subco, surfs[s], surfs[p])
615 destroy_subsurface_tree(struct wl_surface **surfs,
616 struct wl_subsurface **subs, int n)
620 for (i = n; i-- > 0; ) {
622 wl_surface_destroy(surfs[i]);
625 wl_subsurface_destroy(subs[i]);
630 has_dupe(int *cnt, int n)
634 for (i = 0; i < n; i++)
635 if (cnt[i] == cnt[n])
641 /* Note: number of permutations to test is: set_size! / (set_size - NSTEPS)!
651 permu_init(struct permu_state *s, int set_size)
655 s->set_size = set_size;
656 for (i = 0; i < NSTEPS; i++)
661 permu_next(struct permu_state *s)
665 s->cnt[NSTEPS - 1]++;
668 if (s->cnt[0] >= s->set_size) {
672 for (k = 1; k < NSTEPS; k++) {
673 if (s->cnt[k] >= s->set_size) {
679 if (has_dupe(s->cnt, k)) {
691 destroy_permu_object(struct wl_surface **surfs,
692 struct wl_subsurface **subs, int i)
697 fprintf(stderr, " [sub %2d]", h);
698 wl_subsurface_destroy(subs[h]);
701 fprintf(stderr, " [surf %2d]", h);
702 wl_surface_destroy(surfs[h]);
707 TEST(test_subsurface_destroy_permutations)
710 * Test wl_surface and wl_subsurface destruction orders in a
711 * complex tree of sub-surfaces.
713 * In the tree of sub-surfaces, go through every possible
714 * permutation of destroying all wl_surface and wl_subsurface
715 * objects. Execpt, to limit running time to a reasonable level,
716 * execute only the first NSTEPS destructions from each
717 * permutation, and ignore identical cases.
720 const int test_size = 11;
721 struct client *client;
722 struct wl_surface *surfs[test_size];
723 struct wl_subsurface *subs[test_size];
724 struct permu_state per;
728 client = create_client_and_test_surface(100, 50, 123, 77);
731 permu_init(&per, test_size * 2 - 1);
732 while (permu_next(&per) != -1) {
733 /* for each permutation of NSTEPS out of test_size */
734 memset(surfs, 0, sizeof surfs);
735 memset(subs, 0, sizeof subs);
737 create_subsurface_tree(client, surfs, subs, test_size);
739 fprintf(stderr, "permu");
741 for (i = 0; i < NSTEPS; i++)
742 fprintf(stderr, " %2d", per.cnt[i]);
744 for (i = 0; i < NSTEPS; i++)
745 destroy_permu_object(surfs, subs, per.cnt[i]);
747 fprintf(stderr, "\n");
748 client_roundtrip(client);
750 destroy_subsurface_tree(surfs, subs, test_size);
754 client_roundtrip(client);
755 fprintf(stderr, "tried %d destroy permutations\n", counter);