blob: 03ff539263500a88bf0fda800bf6421f3e50152e [file] [log] [blame]
Pekka Paalanene844bf22013-04-25 13:57:43 +03001/*
2 * Copyright © 2012 Collabora, Ltd.
3 *
Bryce Harrington2cc92972015-06-11 15:39:40 -07004 * 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:
Pekka Paalanene844bf22013-04-25 13:57:43 +030011 *
Bryce Harrington2cc92972015-06-11 15:39:40 -070012 * 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.
15 *
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
23 * SOFTWARE.
Pekka Paalanene844bf22013-04-25 13:57:43 +030024 */
25
Andrew Wedgbury9cd661e2014-04-07 12:40:35 +010026#include "config.h"
27
Bryce Harringtona7680262014-11-19 17:18:34 -080028#include <stdio.h>
Pekka Paalanene844bf22013-04-25 13:57:43 +030029#include <string.h>
30
31#include "weston-test-client-helper.h"
Pekka Paalanene844bf22013-04-25 13:57:43 +030032
33#define NUM_SUBSURFACES 3
34
35struct 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];
40};
41
42static struct wl_subcompositor *
43get_subcompositor(struct client *client)
44{
45 struct global *g;
46 struct global *global_sub = NULL;
47 struct wl_subcompositor *sub;
48
49 wl_list_for_each(g, &client->global_list, link) {
50 if (strcmp(g->interface, "wl_subcompositor"))
51 continue;
52
53 if (global_sub)
54 assert(0 && "multiple wl_subcompositor objects");
55
56 global_sub = g;
57 }
58
59 assert(global_sub && "no wl_subcompositor found");
60
61 assert(global_sub->version == 1);
62
63 sub = wl_registry_bind(client->wl_registry, global_sub->name,
64 &wl_subcompositor_interface, 1);
65 assert(sub);
66
67 return sub;
68}
69
70static void
71populate_compound_surface(struct compound_surface *com, struct client *client)
72{
73 int i;
74
75 com->subco = get_subcompositor(client);
76
77 com->parent = wl_compositor_create_surface(client->wl_compositor);
78
79 for (i = 0; i < NUM_SUBSURFACES; i++) {
80 com->child[i] =
81 wl_compositor_create_surface(client->wl_compositor);
82 com->sub[i] =
83 wl_subcompositor_get_subsurface(com->subco,
84 com->child[i],
85 com->parent);
86 }
87}
88
89TEST(test_subsurface_basic_protocol)
90{
91 struct client *client;
92 struct compound_surface com1;
93 struct compound_surface com2;
94
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +020095 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +030096 assert(client);
97
98 populate_compound_surface(&com1, client);
99 populate_compound_surface(&com2, client);
100
101 client_roundtrip(client);
102}
103
104TEST(test_subsurface_position_protocol)
105{
106 struct client *client;
107 struct compound_surface com;
108 int i;
109
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200110 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300111 assert(client);
112
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);
117
118 client_roundtrip(client);
119}
120
121TEST(test_subsurface_placement_protocol)
122{
123 struct client *client;
124 struct compound_surface com;
125
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200126 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300127 assert(client);
128
129 populate_compound_surface(&com, client);
130
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);
135
136 client_roundtrip(client);
137}
138
Marek Chalupacfff3122014-07-16 11:40:25 +0200139TEST(test_subsurface_paradox)
Pekka Paalanene844bf22013-04-25 13:57:43 +0300140{
141 struct client *client;
142 struct wl_surface *parent;
143 struct wl_subcompositor *subco;
144
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200145 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300146 assert(client);
147
148 subco = get_subcompositor(client);
149 parent = wl_compositor_create_surface(client->wl_compositor);
150
151 /* surface is its own parent */
152 wl_subcompositor_get_subsurface(subco, parent, parent);
153
Marek Chalupacfff3122014-07-16 11:40:25 +0200154 expect_protocol_error(client, &wl_subcompositor_interface,
155 WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300156}
157
Marek Chalupacfff3122014-07-16 11:40:25 +0200158TEST(test_subsurface_identical_link)
Pekka Paalanene844bf22013-04-25 13:57:43 +0300159{
160 struct client *client;
161 struct compound_surface com;
162
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200163 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300164 assert(client);
165
166 populate_compound_surface(&com, client);
167
168 /* surface is already a subsurface */
169 wl_subcompositor_get_subsurface(com.subco, com.child[0], com.parent);
170
Marek Chalupacfff3122014-07-16 11:40:25 +0200171 expect_protocol_error(client, &wl_subcompositor_interface,
172 WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300173}
174
Marek Chalupacfff3122014-07-16 11:40:25 +0200175TEST(test_subsurface_change_link)
Pekka Paalanene844bf22013-04-25 13:57:43 +0300176{
177 struct client *client;
178 struct compound_surface com;
179 struct wl_surface *stranger;
180
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200181 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300182 assert(client);
183
184 stranger = wl_compositor_create_surface(client->wl_compositor);
185 populate_compound_surface(&com, client);
186
187 /* surface is already a subsurface */
188 wl_subcompositor_get_subsurface(com.subco, com.child[0], stranger);
189
Marek Chalupacfff3122014-07-16 11:40:25 +0200190 expect_protocol_error(client, &wl_subcompositor_interface,
191 WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300192}
193
194TEST(test_subsurface_nesting)
195{
196 struct client *client;
197 struct compound_surface com;
198 struct wl_surface *stranger;
199
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200200 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300201 assert(client);
202
203 stranger = wl_compositor_create_surface(client->wl_compositor);
204 populate_compound_surface(&com, client);
205
206 /* parent is a sub-surface */
207 wl_subcompositor_get_subsurface(com.subco, stranger, com.child[0]);
208
209 client_roundtrip(client);
210}
211
212TEST(test_subsurface_nesting_parent)
213{
214 struct client *client;
215 struct compound_surface com;
216 struct wl_surface *stranger;
217
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200218 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300219 assert(client);
220
221 stranger = wl_compositor_create_surface(client->wl_compositor);
222 populate_compound_surface(&com, client);
223
224 /* surface is already a parent */
225 wl_subcompositor_get_subsurface(com.subco, com.parent, stranger);
226
227 client_roundtrip(client);
228}
229
Marek Chalupacfff3122014-07-16 11:40:25 +0200230TEST(test_subsurface_loop_paradox)
Pekka Paalanen5e9bedb2013-05-17 16:46:06 +0300231{
232 struct client *client;
233 struct wl_surface *surface[3];
234 struct wl_subcompositor *subco;
235
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200236 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanen5e9bedb2013-05-17 16:46:06 +0300237 assert(client);
238
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);
243
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]);
248
Marek Chalupacfff3122014-07-16 11:40:25 +0200249 expect_protocol_error(client, &wl_subcompositor_interface,
250 WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE);
Pekka Paalanen5e9bedb2013-05-17 16:46:06 +0300251}
252
Arnaud Vracb8c16c92016-06-08 18:37:57 +0200253TEST(test_subsurface_place_above_nested_parent)
254{
255 struct client *client;
256 struct compound_surface com;
257 struct wl_surface *grandchild;
258 struct wl_subcompositor *subco;
259 struct wl_subsurface *sub;
260
261 client = create_client_and_test_surface(100, 50, 123, 77);
262 assert(client);
263
264 populate_compound_surface(&com, client);
265
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]);
269
270 wl_subsurface_place_above(sub, com.child[0]);
271
272 client_roundtrip(client);
273}
274
275TEST(test_subsurface_place_below_nested_parent)
276{
277 struct client *client;
278 struct compound_surface com;
279 struct wl_subcompositor *subco;
280 struct wl_surface *grandchild;
281 struct wl_subsurface *sub;
282
283 client = create_client_and_test_surface(100, 50, 123, 77);
284 assert(client);
285
286 populate_compound_surface(&com, client);
287
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]);
291
292 wl_subsurface_place_below(sub, com.child[0]);
293
294 client_roundtrip(client);
295}
296
Marek Chalupacfff3122014-07-16 11:40:25 +0200297TEST(test_subsurface_place_above_stranger)
Pekka Paalanene844bf22013-04-25 13:57:43 +0300298{
299 struct client *client;
300 struct compound_surface com;
301 struct wl_surface *stranger;
302
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200303 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300304 assert(client);
305
306 stranger = wl_compositor_create_surface(client->wl_compositor);
307 populate_compound_surface(&com, client);
308
309 /* bad sibling */
310 wl_subsurface_place_above(com.sub[0], stranger);
311
Marek Chalupacfff3122014-07-16 11:40:25 +0200312 expect_protocol_error(client, &wl_subsurface_interface,
313 WL_SUBSURFACE_ERROR_BAD_SURFACE);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300314}
315
Marek Chalupacfff3122014-07-16 11:40:25 +0200316TEST(test_subsurface_place_below_stranger)
Pekka Paalanene844bf22013-04-25 13:57:43 +0300317{
318 struct client *client;
319 struct compound_surface com;
320 struct wl_surface *stranger;
321
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200322 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300323 assert(client);
324
325 stranger = wl_compositor_create_surface(client->wl_compositor);
326 populate_compound_surface(&com, client);
327
328 /* bad sibling */
329 wl_subsurface_place_below(com.sub[0], stranger);
330
Marek Chalupacfff3122014-07-16 11:40:25 +0200331 expect_protocol_error(client, &wl_subsurface_interface,
332 WL_SUBSURFACE_ERROR_BAD_SURFACE);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300333}
334
Marek Chalupacfff3122014-07-16 11:40:25 +0200335TEST(test_subsurface_place_above_foreign)
Pekka Paalanene844bf22013-04-25 13:57:43 +0300336{
337 struct client *client;
338 struct compound_surface com1;
339 struct compound_surface com2;
340
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200341 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300342 assert(client);
343
344 populate_compound_surface(&com1, client);
345 populate_compound_surface(&com2, client);
346
347 /* bad sibling */
348 wl_subsurface_place_above(com1.sub[0], com2.child[0]);
349
Marek Chalupacfff3122014-07-16 11:40:25 +0200350 expect_protocol_error(client, &wl_subsurface_interface,
351 WL_SUBSURFACE_ERROR_BAD_SURFACE);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300352}
353
Marek Chalupacfff3122014-07-16 11:40:25 +0200354TEST(test_subsurface_place_below_foreign)
Pekka Paalanene844bf22013-04-25 13:57:43 +0300355{
356 struct client *client;
357 struct compound_surface com1;
358 struct compound_surface com2;
359
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200360 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300361 assert(client);
362
363 populate_compound_surface(&com1, client);
364 populate_compound_surface(&com2, client);
365
366 /* bad sibling */
367 wl_subsurface_place_below(com1.sub[0], com2.child[0]);
368
Marek Chalupacfff3122014-07-16 11:40:25 +0200369 expect_protocol_error(client, &wl_subsurface_interface,
370 WL_SUBSURFACE_ERROR_BAD_SURFACE);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300371}
372
373TEST(test_subsurface_destroy_protocol)
374{
375 struct client *client;
376 struct compound_surface com;
377
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200378 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300379 assert(client);
380
381 populate_compound_surface(&com, client);
382
383 /* not needed anymore */
384 wl_subcompositor_destroy(com.subco);
385
386 /* detach child from parent */
387 wl_subsurface_destroy(com.sub[0]);
388
389 /* destroy: child, parent */
390 wl_surface_destroy(com.child[1]);
391 wl_surface_destroy(com.parent);
392
393 /* destroy: parent, child */
394 wl_surface_destroy(com.child[2]);
395
396 /* destroy: sub, child */
397 wl_surface_destroy(com.child[0]);
398
399 /* 2x destroy: child, sub */
400 wl_subsurface_destroy(com.sub[2]);
401 wl_subsurface_destroy(com.sub[1]);
402
403 client_roundtrip(client);
404}
Pekka Paalanenbeb080e2013-05-17 16:46:04 +0300405
406static void
407create_subsurface_tree(struct client *client, struct wl_surface **surfs,
408 struct wl_subsurface **subs, int n)
409{
410 struct wl_subcompositor *subco;
411 int i;
412
413 subco = get_subcompositor(client);
414
415 for (i = 0; i < n; i++)
416 surfs[i] = wl_compositor_create_surface(client->wl_compositor);
417
418 /*
419 * The tree of sub-surfaces:
420 * 0
421 * / \
422 * 1 2 - 10
423 * / \ |\
424 * 3 5 9 6
425 * / / \
426 * 4 7 8
427 * Surface 0 has no wl_subsurface, others do.
428 */
429
430 switch (n) {
431 default:
432 assert(0);
433 break;
434
435#define SUB_LINK(s,p) \
436 subs[s] = wl_subcompositor_get_subsurface(subco, surfs[s], surfs[p])
437
438 case 11:
439 SUB_LINK(10, 2);
440 case 10:
441 SUB_LINK(9, 2);
442 case 9:
443 SUB_LINK(8, 6);
444 case 8:
445 SUB_LINK(7, 6);
446 case 7:
447 SUB_LINK(6, 2);
448 case 6:
449 SUB_LINK(5, 1);
450 case 5:
451 SUB_LINK(4, 3);
452 case 4:
453 SUB_LINK(3, 1);
454 case 3:
455 SUB_LINK(2, 0);
456 case 2:
457 SUB_LINK(1, 0);
458
459#undef SUB_LINK
460 };
461}
462
463static void
464destroy_subsurface_tree(struct wl_surface **surfs,
465 struct wl_subsurface **subs, int n)
466{
467 int i;
468
469 for (i = n; i-- > 0; ) {
470 if (surfs[i])
471 wl_surface_destroy(surfs[i]);
472
473 if (subs[i])
474 wl_subsurface_destroy(subs[i]);
475 }
476}
477
478static int
479has_dupe(int *cnt, int n)
480{
481 int i;
482
483 for (i = 0; i < n; i++)
484 if (cnt[i] == cnt[n])
485 return 1;
486
487 return 0;
488}
489
490/* Note: number of permutations to test is: set_size! / (set_size - NSTEPS)!
491 */
492#define NSTEPS 3
493
494struct permu_state {
495 int set_size;
496 int cnt[NSTEPS];
497};
498
499static void
500permu_init(struct permu_state *s, int set_size)
501{
502 int i;
503
504 s->set_size = set_size;
505 for (i = 0; i < NSTEPS; i++)
506 s->cnt[i] = 0;
507}
508
509static int
510permu_next(struct permu_state *s)
511{
512 int k;
513
514 s->cnt[NSTEPS - 1]++;
515
516 while (1) {
517 if (s->cnt[0] >= s->set_size) {
518 return -1;
519 }
520
521 for (k = 1; k < NSTEPS; k++) {
522 if (s->cnt[k] >= s->set_size) {
523 s->cnt[k - 1]++;
524 s->cnt[k] = 0;
525 break;
526 }
527
528 if (has_dupe(s->cnt, k)) {
529 s->cnt[k]++;
530 break;
531 }
532 }
533
534 if (k == NSTEPS)
535 return 0;
536 }
537}
538
539static void
540destroy_permu_object(struct wl_surface **surfs,
541 struct wl_subsurface **subs, int i)
542{
543 int h = (i + 1) / 2;
544
545 if (i & 1) {
546 fprintf(stderr, " [sub %2d]", h);
547 wl_subsurface_destroy(subs[h]);
548 subs[h] = NULL;
549 } else {
550 fprintf(stderr, " [surf %2d]", h);
551 wl_surface_destroy(surfs[h]);
552 surfs[h] = NULL;
553 }
554}
555
556TEST(test_subsurface_destroy_permutations)
557{
558 /*
559 * Test wl_surface and wl_subsurface destruction orders in a
560 * complex tree of sub-surfaces.
561 *
562 * In the tree of sub-surfaces, go through every possible
563 * permutation of destroying all wl_surface and wl_subsurface
564 * objects. Execpt, to limit running time to a reasonable level,
565 * execute only the first NSTEPS destructions from each
566 * permutation, and ignore identical cases.
567 */
568
569 const int test_size = 11;
570 struct client *client;
571 struct wl_surface *surfs[test_size];
572 struct wl_subsurface *subs[test_size];
573 struct permu_state per;
574 int counter = 0;
575 int i;
576
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200577 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanenbeb080e2013-05-17 16:46:04 +0300578 assert(client);
579
580 permu_init(&per, test_size * 2 - 1);
581 while (permu_next(&per) != -1) {
582 /* for each permutation of NSTEPS out of test_size */
583 memset(surfs, 0, sizeof surfs);
584 memset(subs, 0, sizeof subs);
585
586 create_subsurface_tree(client, surfs, subs, test_size);
587
588 fprintf(stderr, "permu");
589
590 for (i = 0; i < NSTEPS; i++)
591 fprintf(stderr, " %2d", per.cnt[i]);
592
593 for (i = 0; i < NSTEPS; i++)
594 destroy_permu_object(surfs, subs, per.cnt[i]);
595
596 fprintf(stderr, "\n");
597 client_roundtrip(client);
598
599 destroy_subsurface_tree(surfs, subs, test_size);
600 counter++;
601 }
602
603 client_roundtrip(client);
604 fprintf(stderr, "tried %d destroy permutations\n", counter);
605}