blob: 3ababdd38388398742f23893978d8556dc342c59 [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
Marek Chalupacfff3122014-07-16 11:40:25 +0200253TEST(test_subsurface_place_above_stranger)
Pekka Paalanene844bf22013-04-25 13:57:43 +0300254{
255 struct client *client;
256 struct compound_surface com;
257 struct wl_surface *stranger;
258
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200259 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300260 assert(client);
261
262 stranger = wl_compositor_create_surface(client->wl_compositor);
263 populate_compound_surface(&com, client);
264
265 /* bad sibling */
266 wl_subsurface_place_above(com.sub[0], stranger);
267
Marek Chalupacfff3122014-07-16 11:40:25 +0200268 expect_protocol_error(client, &wl_subsurface_interface,
269 WL_SUBSURFACE_ERROR_BAD_SURFACE);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300270}
271
Marek Chalupacfff3122014-07-16 11:40:25 +0200272TEST(test_subsurface_place_below_stranger)
Pekka Paalanene844bf22013-04-25 13:57:43 +0300273{
274 struct client *client;
275 struct compound_surface com;
276 struct wl_surface *stranger;
277
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200278 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300279 assert(client);
280
281 stranger = wl_compositor_create_surface(client->wl_compositor);
282 populate_compound_surface(&com, client);
283
284 /* bad sibling */
285 wl_subsurface_place_below(com.sub[0], stranger);
286
Marek Chalupacfff3122014-07-16 11:40:25 +0200287 expect_protocol_error(client, &wl_subsurface_interface,
288 WL_SUBSURFACE_ERROR_BAD_SURFACE);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300289}
290
Marek Chalupacfff3122014-07-16 11:40:25 +0200291TEST(test_subsurface_place_above_foreign)
Pekka Paalanene844bf22013-04-25 13:57:43 +0300292{
293 struct client *client;
294 struct compound_surface com1;
295 struct compound_surface com2;
296
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200297 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300298 assert(client);
299
300 populate_compound_surface(&com1, client);
301 populate_compound_surface(&com2, client);
302
303 /* bad sibling */
304 wl_subsurface_place_above(com1.sub[0], com2.child[0]);
305
Marek Chalupacfff3122014-07-16 11:40:25 +0200306 expect_protocol_error(client, &wl_subsurface_interface,
307 WL_SUBSURFACE_ERROR_BAD_SURFACE);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300308}
309
Marek Chalupacfff3122014-07-16 11:40:25 +0200310TEST(test_subsurface_place_below_foreign)
Pekka Paalanene844bf22013-04-25 13:57:43 +0300311{
312 struct client *client;
313 struct compound_surface com1;
314 struct compound_surface com2;
315
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200316 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300317 assert(client);
318
319 populate_compound_surface(&com1, client);
320 populate_compound_surface(&com2, client);
321
322 /* bad sibling */
323 wl_subsurface_place_below(com1.sub[0], com2.child[0]);
324
Marek Chalupacfff3122014-07-16 11:40:25 +0200325 expect_protocol_error(client, &wl_subsurface_interface,
326 WL_SUBSURFACE_ERROR_BAD_SURFACE);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300327}
328
329TEST(test_subsurface_destroy_protocol)
330{
331 struct client *client;
332 struct compound_surface com;
333
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200334 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300335 assert(client);
336
337 populate_compound_surface(&com, client);
338
339 /* not needed anymore */
340 wl_subcompositor_destroy(com.subco);
341
342 /* detach child from parent */
343 wl_subsurface_destroy(com.sub[0]);
344
345 /* destroy: child, parent */
346 wl_surface_destroy(com.child[1]);
347 wl_surface_destroy(com.parent);
348
349 /* destroy: parent, child */
350 wl_surface_destroy(com.child[2]);
351
352 /* destroy: sub, child */
353 wl_surface_destroy(com.child[0]);
354
355 /* 2x destroy: child, sub */
356 wl_subsurface_destroy(com.sub[2]);
357 wl_subsurface_destroy(com.sub[1]);
358
359 client_roundtrip(client);
360}
Pekka Paalanenbeb080e2013-05-17 16:46:04 +0300361
362static void
363create_subsurface_tree(struct client *client, struct wl_surface **surfs,
364 struct wl_subsurface **subs, int n)
365{
366 struct wl_subcompositor *subco;
367 int i;
368
369 subco = get_subcompositor(client);
370
371 for (i = 0; i < n; i++)
372 surfs[i] = wl_compositor_create_surface(client->wl_compositor);
373
374 /*
375 * The tree of sub-surfaces:
376 * 0
377 * / \
378 * 1 2 - 10
379 * / \ |\
380 * 3 5 9 6
381 * / / \
382 * 4 7 8
383 * Surface 0 has no wl_subsurface, others do.
384 */
385
386 switch (n) {
387 default:
388 assert(0);
389 break;
390
391#define SUB_LINK(s,p) \
392 subs[s] = wl_subcompositor_get_subsurface(subco, surfs[s], surfs[p])
393
394 case 11:
395 SUB_LINK(10, 2);
396 case 10:
397 SUB_LINK(9, 2);
398 case 9:
399 SUB_LINK(8, 6);
400 case 8:
401 SUB_LINK(7, 6);
402 case 7:
403 SUB_LINK(6, 2);
404 case 6:
405 SUB_LINK(5, 1);
406 case 5:
407 SUB_LINK(4, 3);
408 case 4:
409 SUB_LINK(3, 1);
410 case 3:
411 SUB_LINK(2, 0);
412 case 2:
413 SUB_LINK(1, 0);
414
415#undef SUB_LINK
416 };
417}
418
419static void
420destroy_subsurface_tree(struct wl_surface **surfs,
421 struct wl_subsurface **subs, int n)
422{
423 int i;
424
425 for (i = n; i-- > 0; ) {
426 if (surfs[i])
427 wl_surface_destroy(surfs[i]);
428
429 if (subs[i])
430 wl_subsurface_destroy(subs[i]);
431 }
432}
433
434static int
435has_dupe(int *cnt, int n)
436{
437 int i;
438
439 for (i = 0; i < n; i++)
440 if (cnt[i] == cnt[n])
441 return 1;
442
443 return 0;
444}
445
446/* Note: number of permutations to test is: set_size! / (set_size - NSTEPS)!
447 */
448#define NSTEPS 3
449
450struct permu_state {
451 int set_size;
452 int cnt[NSTEPS];
453};
454
455static void
456permu_init(struct permu_state *s, int set_size)
457{
458 int i;
459
460 s->set_size = set_size;
461 for (i = 0; i < NSTEPS; i++)
462 s->cnt[i] = 0;
463}
464
465static int
466permu_next(struct permu_state *s)
467{
468 int k;
469
470 s->cnt[NSTEPS - 1]++;
471
472 while (1) {
473 if (s->cnt[0] >= s->set_size) {
474 return -1;
475 }
476
477 for (k = 1; k < NSTEPS; k++) {
478 if (s->cnt[k] >= s->set_size) {
479 s->cnt[k - 1]++;
480 s->cnt[k] = 0;
481 break;
482 }
483
484 if (has_dupe(s->cnt, k)) {
485 s->cnt[k]++;
486 break;
487 }
488 }
489
490 if (k == NSTEPS)
491 return 0;
492 }
493}
494
495static void
496destroy_permu_object(struct wl_surface **surfs,
497 struct wl_subsurface **subs, int i)
498{
499 int h = (i + 1) / 2;
500
501 if (i & 1) {
502 fprintf(stderr, " [sub %2d]", h);
503 wl_subsurface_destroy(subs[h]);
504 subs[h] = NULL;
505 } else {
506 fprintf(stderr, " [surf %2d]", h);
507 wl_surface_destroy(surfs[h]);
508 surfs[h] = NULL;
509 }
510}
511
512TEST(test_subsurface_destroy_permutations)
513{
514 /*
515 * Test wl_surface and wl_subsurface destruction orders in a
516 * complex tree of sub-surfaces.
517 *
518 * In the tree of sub-surfaces, go through every possible
519 * permutation of destroying all wl_surface and wl_subsurface
520 * objects. Execpt, to limit running time to a reasonable level,
521 * execute only the first NSTEPS destructions from each
522 * permutation, and ignore identical cases.
523 */
524
525 const int test_size = 11;
526 struct client *client;
527 struct wl_surface *surfs[test_size];
528 struct wl_subsurface *subs[test_size];
529 struct permu_state per;
530 int counter = 0;
531 int i;
532
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200533 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanenbeb080e2013-05-17 16:46:04 +0300534 assert(client);
535
536 permu_init(&per, test_size * 2 - 1);
537 while (permu_next(&per) != -1) {
538 /* for each permutation of NSTEPS out of test_size */
539 memset(surfs, 0, sizeof surfs);
540 memset(subs, 0, sizeof subs);
541
542 create_subsurface_tree(client, surfs, subs, test_size);
543
544 fprintf(stderr, "permu");
545
546 for (i = 0; i < NSTEPS; i++)
547 fprintf(stderr, " %2d", per.cnt[i]);
548
549 for (i = 0; i < NSTEPS; i++)
550 destroy_permu_object(surfs, subs, per.cnt[i]);
551
552 fprintf(stderr, "\n");
553 client_roundtrip(client);
554
555 destroy_subsurface_tree(surfs, subs, test_size);
556 counter++;
557 }
558
559 client_roundtrip(client);
560 fprintf(stderr, "tried %d destroy permutations\n", counter);
561}