blob: 0670e7f78fbe38c50efb4e0960cc57cc8803fa45 [file] [log] [blame]
Pekka Paalanene844bf22013-04-25 13:57:43 +03001/*
2 * Copyright © 2012 Collabora, Ltd.
3 *
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.
13 *
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.
21 */
22
Andrew Wedgbury9cd661e2014-04-07 12:40:35 +010023#include "config.h"
24
Pekka Paalanene844bf22013-04-25 13:57:43 +030025#include <string.h>
26
27#include "weston-test-client-helper.h"
Pekka Paalanenbeb080e2013-05-17 16:46:04 +030028#include <stdio.h>
Pekka Paalanene844bf22013-04-25 13:57:43 +030029
30#define NUM_SUBSURFACES 3
31
32struct 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];
37};
38
39static struct wl_subcompositor *
40get_subcompositor(struct client *client)
41{
42 struct global *g;
43 struct global *global_sub = NULL;
44 struct wl_subcompositor *sub;
45
46 wl_list_for_each(g, &client->global_list, link) {
47 if (strcmp(g->interface, "wl_subcompositor"))
48 continue;
49
50 if (global_sub)
51 assert(0 && "multiple wl_subcompositor objects");
52
53 global_sub = g;
54 }
55
56 assert(global_sub && "no wl_subcompositor found");
57
58 assert(global_sub->version == 1);
59
60 sub = wl_registry_bind(client->wl_registry, global_sub->name,
61 &wl_subcompositor_interface, 1);
62 assert(sub);
63
64 return sub;
65}
66
67static void
68populate_compound_surface(struct compound_surface *com, struct client *client)
69{
70 int i;
71
72 com->subco = get_subcompositor(client);
73
74 com->parent = wl_compositor_create_surface(client->wl_compositor);
75
76 for (i = 0; i < NUM_SUBSURFACES; i++) {
77 com->child[i] =
78 wl_compositor_create_surface(client->wl_compositor);
79 com->sub[i] =
80 wl_subcompositor_get_subsurface(com->subco,
81 com->child[i],
82 com->parent);
83 }
84}
85
86TEST(test_subsurface_basic_protocol)
87{
88 struct client *client;
89 struct compound_surface com1;
90 struct compound_surface com2;
91
92 client = client_create(100, 50, 123, 77);
93 assert(client);
94
95 populate_compound_surface(&com1, client);
96 populate_compound_surface(&com2, client);
97
98 client_roundtrip(client);
99}
100
101TEST(test_subsurface_position_protocol)
102{
103 struct client *client;
104 struct compound_surface com;
105 int i;
106
107 client = client_create(100, 50, 123, 77);
108 assert(client);
109
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);
114
115 client_roundtrip(client);
116}
117
118TEST(test_subsurface_placement_protocol)
119{
120 struct client *client;
121 struct compound_surface com;
122
123 client = client_create(100, 50, 123, 77);
124 assert(client);
125
126 populate_compound_surface(&com, client);
127
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);
132
133 client_roundtrip(client);
134}
135
136FAIL_TEST(test_subsurface_paradox)
137{
138 struct client *client;
139 struct wl_surface *parent;
140 struct wl_subcompositor *subco;
141
142 client = client_create(100, 50, 123, 77);
143 assert(client);
144
145 subco = get_subcompositor(client);
146 parent = wl_compositor_create_surface(client->wl_compositor);
147
148 /* surface is its own parent */
149 wl_subcompositor_get_subsurface(subco, parent, parent);
150
151 client_roundtrip(client);
152}
153
154FAIL_TEST(test_subsurface_identical_link)
155{
156 struct client *client;
157 struct compound_surface com;
158
159 client = client_create(100, 50, 123, 77);
160 assert(client);
161
162 populate_compound_surface(&com, client);
163
164 /* surface is already a subsurface */
165 wl_subcompositor_get_subsurface(com.subco, com.child[0], com.parent);
166
167 client_roundtrip(client);
168}
169
170FAIL_TEST(test_subsurface_change_link)
171{
172 struct client *client;
173 struct compound_surface com;
174 struct wl_surface *stranger;
175
176 client = client_create(100, 50, 123, 77);
177 assert(client);
178
179 stranger = wl_compositor_create_surface(client->wl_compositor);
180 populate_compound_surface(&com, client);
181
182 /* surface is already a subsurface */
183 wl_subcompositor_get_subsurface(com.subco, com.child[0], stranger);
184
185 client_roundtrip(client);
186}
187
188TEST(test_subsurface_nesting)
189{
190 struct client *client;
191 struct compound_surface com;
192 struct wl_surface *stranger;
193
194 client = client_create(100, 50, 123, 77);
195 assert(client);
196
197 stranger = wl_compositor_create_surface(client->wl_compositor);
198 populate_compound_surface(&com, client);
199
200 /* parent is a sub-surface */
201 wl_subcompositor_get_subsurface(com.subco, stranger, com.child[0]);
202
203 client_roundtrip(client);
204}
205
206TEST(test_subsurface_nesting_parent)
207{
208 struct client *client;
209 struct compound_surface com;
210 struct wl_surface *stranger;
211
212 client = client_create(100, 50, 123, 77);
213 assert(client);
214
215 stranger = wl_compositor_create_surface(client->wl_compositor);
216 populate_compound_surface(&com, client);
217
218 /* surface is already a parent */
219 wl_subcompositor_get_subsurface(com.subco, com.parent, stranger);
220
221 client_roundtrip(client);
222}
223
Pekka Paalanen5e9bedb2013-05-17 16:46:06 +0300224FAIL_TEST(test_subsurface_loop_paradox)
225{
226 struct client *client;
227 struct wl_surface *surface[3];
228 struct wl_subcompositor *subco;
229
230 client = client_create(100, 50, 123, 77);
231 assert(client);
232
233 subco = get_subcompositor(client);
234 surface[0] = wl_compositor_create_surface(client->wl_compositor);
235 surface[1] = wl_compositor_create_surface(client->wl_compositor);
236 surface[2] = wl_compositor_create_surface(client->wl_compositor);
237
238 /* create a nesting loop */
239 wl_subcompositor_get_subsurface(subco, surface[1], surface[0]);
240 wl_subcompositor_get_subsurface(subco, surface[2], surface[1]);
241 wl_subcompositor_get_subsurface(subco, surface[0], surface[2]);
242
243 client_roundtrip(client);
244}
245
Pekka Paalanene844bf22013-04-25 13:57:43 +0300246FAIL_TEST(test_subsurface_place_above_stranger)
247{
248 struct client *client;
249 struct compound_surface com;
250 struct wl_surface *stranger;
251
252 client = client_create(100, 50, 123, 77);
253 assert(client);
254
255 stranger = wl_compositor_create_surface(client->wl_compositor);
256 populate_compound_surface(&com, client);
257
258 /* bad sibling */
259 wl_subsurface_place_above(com.sub[0], stranger);
260
261 client_roundtrip(client);
262}
263
264FAIL_TEST(test_subsurface_place_below_stranger)
265{
266 struct client *client;
267 struct compound_surface com;
268 struct wl_surface *stranger;
269
270 client = client_create(100, 50, 123, 77);
271 assert(client);
272
273 stranger = wl_compositor_create_surface(client->wl_compositor);
274 populate_compound_surface(&com, client);
275
276 /* bad sibling */
277 wl_subsurface_place_below(com.sub[0], stranger);
278
279 client_roundtrip(client);
280}
281
282FAIL_TEST(test_subsurface_place_above_foreign)
283{
284 struct client *client;
285 struct compound_surface com1;
286 struct compound_surface com2;
287
288 client = client_create(100, 50, 123, 77);
289 assert(client);
290
291 populate_compound_surface(&com1, client);
292 populate_compound_surface(&com2, client);
293
294 /* bad sibling */
295 wl_subsurface_place_above(com1.sub[0], com2.child[0]);
296
297 client_roundtrip(client);
298}
299
300FAIL_TEST(test_subsurface_place_below_foreign)
301{
302 struct client *client;
303 struct compound_surface com1;
304 struct compound_surface com2;
305
306 client = client_create(100, 50, 123, 77);
307 assert(client);
308
309 populate_compound_surface(&com1, client);
310 populate_compound_surface(&com2, client);
311
312 /* bad sibling */
313 wl_subsurface_place_below(com1.sub[0], com2.child[0]);
314
315 client_roundtrip(client);
316}
317
318TEST(test_subsurface_destroy_protocol)
319{
320 struct client *client;
321 struct compound_surface com;
322
323 client = client_create(100, 50, 123, 77);
324 assert(client);
325
326 populate_compound_surface(&com, client);
327
328 /* not needed anymore */
329 wl_subcompositor_destroy(com.subco);
330
331 /* detach child from parent */
332 wl_subsurface_destroy(com.sub[0]);
333
334 /* destroy: child, parent */
335 wl_surface_destroy(com.child[1]);
336 wl_surface_destroy(com.parent);
337
338 /* destroy: parent, child */
339 wl_surface_destroy(com.child[2]);
340
341 /* destroy: sub, child */
342 wl_surface_destroy(com.child[0]);
343
344 /* 2x destroy: child, sub */
345 wl_subsurface_destroy(com.sub[2]);
346 wl_subsurface_destroy(com.sub[1]);
347
348 client_roundtrip(client);
349}
Pekka Paalanenbeb080e2013-05-17 16:46:04 +0300350
351static void
352create_subsurface_tree(struct client *client, struct wl_surface **surfs,
353 struct wl_subsurface **subs, int n)
354{
355 struct wl_subcompositor *subco;
356 int i;
357
358 subco = get_subcompositor(client);
359
360 for (i = 0; i < n; i++)
361 surfs[i] = wl_compositor_create_surface(client->wl_compositor);
362
363 /*
364 * The tree of sub-surfaces:
365 * 0
366 * / \
367 * 1 2 - 10
368 * / \ |\
369 * 3 5 9 6
370 * / / \
371 * 4 7 8
372 * Surface 0 has no wl_subsurface, others do.
373 */
374
375 switch (n) {
376 default:
377 assert(0);
378 break;
379
380#define SUB_LINK(s,p) \
381 subs[s] = wl_subcompositor_get_subsurface(subco, surfs[s], surfs[p])
382
383 case 11:
384 SUB_LINK(10, 2);
385 case 10:
386 SUB_LINK(9, 2);
387 case 9:
388 SUB_LINK(8, 6);
389 case 8:
390 SUB_LINK(7, 6);
391 case 7:
392 SUB_LINK(6, 2);
393 case 6:
394 SUB_LINK(5, 1);
395 case 5:
396 SUB_LINK(4, 3);
397 case 4:
398 SUB_LINK(3, 1);
399 case 3:
400 SUB_LINK(2, 0);
401 case 2:
402 SUB_LINK(1, 0);
403
404#undef SUB_LINK
405 };
406}
407
408static void
409destroy_subsurface_tree(struct wl_surface **surfs,
410 struct wl_subsurface **subs, int n)
411{
412 int i;
413
414 for (i = n; i-- > 0; ) {
415 if (surfs[i])
416 wl_surface_destroy(surfs[i]);
417
418 if (subs[i])
419 wl_subsurface_destroy(subs[i]);
420 }
421}
422
423static int
424has_dupe(int *cnt, int n)
425{
426 int i;
427
428 for (i = 0; i < n; i++)
429 if (cnt[i] == cnt[n])
430 return 1;
431
432 return 0;
433}
434
435/* Note: number of permutations to test is: set_size! / (set_size - NSTEPS)!
436 */
437#define NSTEPS 3
438
439struct permu_state {
440 int set_size;
441 int cnt[NSTEPS];
442};
443
444static void
445permu_init(struct permu_state *s, int set_size)
446{
447 int i;
448
449 s->set_size = set_size;
450 for (i = 0; i < NSTEPS; i++)
451 s->cnt[i] = 0;
452}
453
454static int
455permu_next(struct permu_state *s)
456{
457 int k;
458
459 s->cnt[NSTEPS - 1]++;
460
461 while (1) {
462 if (s->cnt[0] >= s->set_size) {
463 return -1;
464 }
465
466 for (k = 1; k < NSTEPS; k++) {
467 if (s->cnt[k] >= s->set_size) {
468 s->cnt[k - 1]++;
469 s->cnt[k] = 0;
470 break;
471 }
472
473 if (has_dupe(s->cnt, k)) {
474 s->cnt[k]++;
475 break;
476 }
477 }
478
479 if (k == NSTEPS)
480 return 0;
481 }
482}
483
484static void
485destroy_permu_object(struct wl_surface **surfs,
486 struct wl_subsurface **subs, int i)
487{
488 int h = (i + 1) / 2;
489
490 if (i & 1) {
491 fprintf(stderr, " [sub %2d]", h);
492 wl_subsurface_destroy(subs[h]);
493 subs[h] = NULL;
494 } else {
495 fprintf(stderr, " [surf %2d]", h);
496 wl_surface_destroy(surfs[h]);
497 surfs[h] = NULL;
498 }
499}
500
501TEST(test_subsurface_destroy_permutations)
502{
503 /*
504 * Test wl_surface and wl_subsurface destruction orders in a
505 * complex tree of sub-surfaces.
506 *
507 * In the tree of sub-surfaces, go through every possible
508 * permutation of destroying all wl_surface and wl_subsurface
509 * objects. Execpt, to limit running time to a reasonable level,
510 * execute only the first NSTEPS destructions from each
511 * permutation, and ignore identical cases.
512 */
513
514 const int test_size = 11;
515 struct client *client;
516 struct wl_surface *surfs[test_size];
517 struct wl_subsurface *subs[test_size];
518 struct permu_state per;
519 int counter = 0;
520 int i;
521
522 client = client_create(100, 50, 123, 77);
523 assert(client);
524
525 permu_init(&per, test_size * 2 - 1);
526 while (permu_next(&per) != -1) {
527 /* for each permutation of NSTEPS out of test_size */
528 memset(surfs, 0, sizeof surfs);
529 memset(subs, 0, sizeof subs);
530
531 create_subsurface_tree(client, surfs, subs, test_size);
532
533 fprintf(stderr, "permu");
534
535 for (i = 0; i < NSTEPS; i++)
536 fprintf(stderr, " %2d", per.cnt[i]);
537
538 for (i = 0; i < NSTEPS; i++)
539 destroy_permu_object(surfs, subs, per.cnt[i]);
540
541 fprintf(stderr, "\n");
542 client_roundtrip(client);
543
544 destroy_subsurface_tree(surfs, subs, test_size);
545 counter++;
546 }
547
548 client_roundtrip(client);
549 fprintf(stderr, "tried %d destroy permutations\n", counter);
550}