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.
27 #include "weston-test-client-helper.h"
30 #define NUM_SUBSURFACES 3
32 struct compound_surface {
33 struct wl_subcompositor *subco;
34 struct wl_surface *parent;
35 struct wl_surface *child[NUM_SUBSURFACES];
36 struct wl_subsurface *sub[NUM_SUBSURFACES];
39 static struct wl_subcompositor *
40 get_subcompositor(struct client *client)
43 struct global *global_sub = NULL;
44 struct wl_subcompositor *sub;
46 wl_list_for_each(g, &client->global_list, link) {
47 if (strcmp(g->interface, "wl_subcompositor"))
51 assert(0 && "multiple wl_subcompositor objects");
56 assert(global_sub && "no wl_subcompositor found");
58 assert(global_sub->version == 1);
60 sub = wl_registry_bind(client->wl_registry, global_sub->name,
61 &wl_subcompositor_interface, 1);
68 populate_compound_surface(struct compound_surface *com, struct client *client)
72 com->subco = get_subcompositor(client);
74 com->parent = wl_compositor_create_surface(client->wl_compositor);
76 for (i = 0; i < NUM_SUBSURFACES; i++) {
78 wl_compositor_create_surface(client->wl_compositor);
80 wl_subcompositor_get_subsurface(com->subco,
86 TEST(test_subsurface_basic_protocol)
88 struct client *client;
89 struct compound_surface com1;
90 struct compound_surface com2;
92 client = client_create(100, 50, 123, 77);
95 populate_compound_surface(&com1, client);
96 populate_compound_surface(&com2, client);
98 client_roundtrip(client);
101 TEST(test_subsurface_position_protocol)
103 struct client *client;
104 struct compound_surface com;
107 client = client_create(100, 50, 123, 77);
110 populate_compound_surface(&com, client);
111 for (i = 0; i < NUM_SUBSURFACES; i++)
112 wl_subsurface_set_position(com.sub[i],
113 (i + 2) * 20, (i + 2) * 10);
115 client_roundtrip(client);
118 TEST(test_subsurface_placement_protocol)
120 struct client *client;
121 struct compound_surface com;
123 client = client_create(100, 50, 123, 77);
126 populate_compound_surface(&com, client);
128 wl_subsurface_place_above(com.sub[0], com.child[1]);
129 wl_subsurface_place_above(com.sub[1], com.parent);
130 wl_subsurface_place_below(com.sub[2], com.child[0]);
131 wl_subsurface_place_below(com.sub[1], com.parent);
133 client_roundtrip(client);
136 TEST(test_subsurface_paradox)
138 struct client *client;
139 struct wl_surface *parent;
140 struct wl_subcompositor *subco;
142 client = client_create(100, 50, 123, 77);
145 subco = get_subcompositor(client);
146 parent = wl_compositor_create_surface(client->wl_compositor);
148 /* surface is its own parent */
149 wl_subcompositor_get_subsurface(subco, parent, parent);
151 expect_protocol_error(client, &wl_subcompositor_interface,
152 WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE);
155 TEST(test_subsurface_identical_link)
157 struct client *client;
158 struct compound_surface com;
160 client = client_create(100, 50, 123, 77);
163 populate_compound_surface(&com, client);
165 /* surface is already a subsurface */
166 wl_subcompositor_get_subsurface(com.subco, com.child[0], com.parent);
168 expect_protocol_error(client, &wl_subcompositor_interface,
169 WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE);
172 TEST(test_subsurface_change_link)
174 struct client *client;
175 struct compound_surface com;
176 struct wl_surface *stranger;
178 client = client_create(100, 50, 123, 77);
181 stranger = wl_compositor_create_surface(client->wl_compositor);
182 populate_compound_surface(&com, client);
184 /* surface is already a subsurface */
185 wl_subcompositor_get_subsurface(com.subco, com.child[0], stranger);
187 expect_protocol_error(client, &wl_subcompositor_interface,
188 WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE);
191 TEST(test_subsurface_nesting)
193 struct client *client;
194 struct compound_surface com;
195 struct wl_surface *stranger;
197 client = client_create(100, 50, 123, 77);
200 stranger = wl_compositor_create_surface(client->wl_compositor);
201 populate_compound_surface(&com, client);
203 /* parent is a sub-surface */
204 wl_subcompositor_get_subsurface(com.subco, stranger, com.child[0]);
206 client_roundtrip(client);
209 TEST(test_subsurface_nesting_parent)
211 struct client *client;
212 struct compound_surface com;
213 struct wl_surface *stranger;
215 client = client_create(100, 50, 123, 77);
218 stranger = wl_compositor_create_surface(client->wl_compositor);
219 populate_compound_surface(&com, client);
221 /* surface is already a parent */
222 wl_subcompositor_get_subsurface(com.subco, com.parent, stranger);
224 client_roundtrip(client);
227 TEST(test_subsurface_loop_paradox)
229 struct client *client;
230 struct wl_surface *surface[3];
231 struct wl_subcompositor *subco;
233 client = client_create(100, 50, 123, 77);
236 subco = get_subcompositor(client);
237 surface[0] = wl_compositor_create_surface(client->wl_compositor);
238 surface[1] = wl_compositor_create_surface(client->wl_compositor);
239 surface[2] = wl_compositor_create_surface(client->wl_compositor);
241 /* create a nesting loop */
242 wl_subcompositor_get_subsurface(subco, surface[1], surface[0]);
243 wl_subcompositor_get_subsurface(subco, surface[2], surface[1]);
244 wl_subcompositor_get_subsurface(subco, surface[0], surface[2]);
246 expect_protocol_error(client, &wl_subcompositor_interface,
247 WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE);
250 TEST(test_subsurface_place_above_stranger)
252 struct client *client;
253 struct compound_surface com;
254 struct wl_surface *stranger;
256 client = client_create(100, 50, 123, 77);
259 stranger = wl_compositor_create_surface(client->wl_compositor);
260 populate_compound_surface(&com, client);
263 wl_subsurface_place_above(com.sub[0], stranger);
265 expect_protocol_error(client, &wl_subsurface_interface,
266 WL_SUBSURFACE_ERROR_BAD_SURFACE);
269 TEST(test_subsurface_place_below_stranger)
271 struct client *client;
272 struct compound_surface com;
273 struct wl_surface *stranger;
275 client = client_create(100, 50, 123, 77);
278 stranger = wl_compositor_create_surface(client->wl_compositor);
279 populate_compound_surface(&com, client);
282 wl_subsurface_place_below(com.sub[0], stranger);
284 expect_protocol_error(client, &wl_subsurface_interface,
285 WL_SUBSURFACE_ERROR_BAD_SURFACE);
288 TEST(test_subsurface_place_above_foreign)
290 struct client *client;
291 struct compound_surface com1;
292 struct compound_surface com2;
294 client = client_create(100, 50, 123, 77);
297 populate_compound_surface(&com1, client);
298 populate_compound_surface(&com2, client);
301 wl_subsurface_place_above(com1.sub[0], com2.child[0]);
303 expect_protocol_error(client, &wl_subsurface_interface,
304 WL_SUBSURFACE_ERROR_BAD_SURFACE);
307 TEST(test_subsurface_place_below_foreign)
309 struct client *client;
310 struct compound_surface com1;
311 struct compound_surface com2;
313 client = client_create(100, 50, 123, 77);
316 populate_compound_surface(&com1, client);
317 populate_compound_surface(&com2, client);
320 wl_subsurface_place_below(com1.sub[0], com2.child[0]);
322 expect_protocol_error(client, &wl_subsurface_interface,
323 WL_SUBSURFACE_ERROR_BAD_SURFACE);
326 TEST(test_subsurface_destroy_protocol)
328 struct client *client;
329 struct compound_surface com;
331 client = client_create(100, 50, 123, 77);
334 populate_compound_surface(&com, client);
336 /* not needed anymore */
337 wl_subcompositor_destroy(com.subco);
339 /* detach child from parent */
340 wl_subsurface_destroy(com.sub[0]);
342 /* destroy: child, parent */
343 wl_surface_destroy(com.child[1]);
344 wl_surface_destroy(com.parent);
346 /* destroy: parent, child */
347 wl_surface_destroy(com.child[2]);
349 /* destroy: sub, child */
350 wl_surface_destroy(com.child[0]);
352 /* 2x destroy: child, sub */
353 wl_subsurface_destroy(com.sub[2]);
354 wl_subsurface_destroy(com.sub[1]);
356 client_roundtrip(client);
360 create_subsurface_tree(struct client *client, struct wl_surface **surfs,
361 struct wl_subsurface **subs, int n)
363 struct wl_subcompositor *subco;
366 subco = get_subcompositor(client);
368 for (i = 0; i < n; i++)
369 surfs[i] = wl_compositor_create_surface(client->wl_compositor);
372 * The tree of sub-surfaces:
380 * Surface 0 has no wl_subsurface, others do.
388 #define SUB_LINK(s,p) \
389 subs[s] = wl_subcompositor_get_subsurface(subco, surfs[s], surfs[p])
417 destroy_subsurface_tree(struct wl_surface **surfs,
418 struct wl_subsurface **subs, int n)
422 for (i = n; i-- > 0; ) {
424 wl_surface_destroy(surfs[i]);
427 wl_subsurface_destroy(subs[i]);
432 has_dupe(int *cnt, int n)
436 for (i = 0; i < n; i++)
437 if (cnt[i] == cnt[n])
443 /* Note: number of permutations to test is: set_size! / (set_size - NSTEPS)!
453 permu_init(struct permu_state *s, int set_size)
457 s->set_size = set_size;
458 for (i = 0; i < NSTEPS; i++)
463 permu_next(struct permu_state *s)
467 s->cnt[NSTEPS - 1]++;
470 if (s->cnt[0] >= s->set_size) {
474 for (k = 1; k < NSTEPS; k++) {
475 if (s->cnt[k] >= s->set_size) {
481 if (has_dupe(s->cnt, k)) {
493 destroy_permu_object(struct wl_surface **surfs,
494 struct wl_subsurface **subs, int i)
499 fprintf(stderr, " [sub %2d]", h);
500 wl_subsurface_destroy(subs[h]);
503 fprintf(stderr, " [surf %2d]", h);
504 wl_surface_destroy(surfs[h]);
509 TEST(test_subsurface_destroy_permutations)
512 * Test wl_surface and wl_subsurface destruction orders in a
513 * complex tree of sub-surfaces.
515 * In the tree of sub-surfaces, go through every possible
516 * permutation of destroying all wl_surface and wl_subsurface
517 * objects. Execpt, to limit running time to a reasonable level,
518 * execute only the first NSTEPS destructions from each
519 * permutation, and ignore identical cases.
522 const int test_size = 11;
523 struct client *client;
524 struct wl_surface *surfs[test_size];
525 struct wl_subsurface *subs[test_size];
526 struct permu_state per;
530 client = client_create(100, 50, 123, 77);
533 permu_init(&per, test_size * 2 - 1);
534 while (permu_next(&per) != -1) {
535 /* for each permutation of NSTEPS out of test_size */
536 memset(surfs, 0, sizeof surfs);
537 memset(subs, 0, sizeof subs);
539 create_subsurface_tree(client, surfs, subs, test_size);
541 fprintf(stderr, "permu");
543 for (i = 0; i < NSTEPS; i++)
544 fprintf(stderr, " %2d", per.cnt[i]);
546 for (i = 0; i < NSTEPS; i++)
547 destroy_permu_object(surfs, subs, per.cnt[i]);
549 fprintf(stderr, "\n");
550 client_roundtrip(client);
552 destroy_subsurface_tree(surfs, subs, test_size);
556 client_roundtrip(client);
557 fprintf(stderr, "tried %d destroy permutations\n", counter);