blob: 1a24ee3515a4dee1e19a555235c6738f1173a7f0 [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
Daniel Stone99834002016-11-22 12:40:34 +0000275TEST(test_subsurface_place_above_grandparent)
276{
277 struct client *client;
278 struct compound_surface com;
279 struct wl_surface *grandchild;
280 struct wl_subsurface *sub;
281 struct wl_subcompositor *subco;
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 /* can't place a subsurface above its grandparent */
293 wl_subsurface_place_above(sub, com.parent);
294
295 expect_protocol_error(client, &wl_subsurface_interface,
296 WL_SUBSURFACE_ERROR_BAD_SURFACE);
297}
298
299TEST(test_subsurface_place_above_great_aunt)
300{
301 struct client *client;
302 struct compound_surface com;
303 struct wl_surface *grandchild;
304 struct wl_subsurface *sub;
305 struct wl_subcompositor *subco;
306
307 client = create_client_and_test_surface(100, 50, 123, 77);
308 assert(client);
309
310 populate_compound_surface(&com, client);
311
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]);
315
316 /* can't place a subsurface above its parents' siblings */
317 wl_subsurface_place_above(sub, com.child[1]);
318
319 expect_protocol_error(client, &wl_subsurface_interface,
320 WL_SUBSURFACE_ERROR_BAD_SURFACE);
321}
322
323TEST(test_subsurface_place_above_child)
324{
325 struct client *client;
326 struct compound_surface com;
327 struct wl_surface *grandchild;
328 struct wl_subcompositor *subco;
329
330 client = create_client_and_test_surface(100, 50, 123, 77);
331 assert(client);
332
333 populate_compound_surface(&com, client);
334
335 subco = get_subcompositor(client);
336 grandchild = wl_compositor_create_surface(client->wl_compositor);
337 wl_subcompositor_get_subsurface(subco, grandchild, com.child[0]);
338
339 /* can't place a subsurface above its own child subsurface */
340 wl_subsurface_place_above(com.sub[0], grandchild);
341
342 expect_protocol_error(client, &wl_subsurface_interface,
343 WL_SUBSURFACE_ERROR_BAD_SURFACE);
344}
345
Arnaud Vracb8c16c92016-06-08 18:37:57 +0200346TEST(test_subsurface_place_below_nested_parent)
347{
348 struct client *client;
349 struct compound_surface com;
350 struct wl_subcompositor *subco;
351 struct wl_surface *grandchild;
352 struct wl_subsurface *sub;
353
354 client = create_client_and_test_surface(100, 50, 123, 77);
355 assert(client);
356
357 populate_compound_surface(&com, client);
358
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]);
362
363 wl_subsurface_place_below(sub, com.child[0]);
364
365 client_roundtrip(client);
366}
367
Daniel Stone99834002016-11-22 12:40:34 +0000368TEST(test_subsurface_place_below_grandparent)
369{
370 struct client *client;
371 struct compound_surface com;
372 struct wl_surface *grandchild;
373 struct wl_subsurface *sub;
374 struct wl_subcompositor *subco;
375
376 client = create_client_and_test_surface(100, 50, 123, 77);
377 assert(client);
378
379 populate_compound_surface(&com, client);
380
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]);
384
385 /* can't place a subsurface below its grandparent */
386 wl_subsurface_place_below(sub, com.parent);
387
388 expect_protocol_error(client, &wl_subsurface_interface,
389 WL_SUBSURFACE_ERROR_BAD_SURFACE);
390}
391
392TEST(test_subsurface_place_below_great_aunt)
393{
394 struct client *client;
395 struct compound_surface com;
396 struct wl_surface *grandchild;
397 struct wl_subsurface *sub;
398 struct wl_subcompositor *subco;
399
400 client = create_client_and_test_surface(100, 50, 123, 77);
401 assert(client);
402
403 populate_compound_surface(&com, client);
404
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]);
408
409 /* can't place a subsurface below its parents' siblings */
410 wl_subsurface_place_below(sub, com.child[1]);
411
412 expect_protocol_error(client, &wl_subsurface_interface,
413 WL_SUBSURFACE_ERROR_BAD_SURFACE);
414}
415
416TEST(test_subsurface_place_below_child)
417{
418 struct client *client;
419 struct compound_surface com;
420 struct wl_surface *grandchild;
421 struct wl_subcompositor *subco;
422
423 client = create_client_and_test_surface(100, 50, 123, 77);
424 assert(client);
425
426 populate_compound_surface(&com, client);
427
428 subco = get_subcompositor(client);
429 grandchild = wl_compositor_create_surface(client->wl_compositor);
430 wl_subcompositor_get_subsurface(subco, grandchild, com.child[0]);
431
432 /* can't place a subsurface below its own child subsurface */
433 wl_subsurface_place_below(com.sub[0], grandchild);
434
435 expect_protocol_error(client, &wl_subsurface_interface,
436 WL_SUBSURFACE_ERROR_BAD_SURFACE);
437}
438
Marek Chalupacfff3122014-07-16 11:40:25 +0200439TEST(test_subsurface_place_above_stranger)
Pekka Paalanene844bf22013-04-25 13:57:43 +0300440{
441 struct client *client;
442 struct compound_surface com;
443 struct wl_surface *stranger;
444
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200445 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300446 assert(client);
447
448 stranger = wl_compositor_create_surface(client->wl_compositor);
449 populate_compound_surface(&com, client);
450
451 /* bad sibling */
452 wl_subsurface_place_above(com.sub[0], stranger);
453
Marek Chalupacfff3122014-07-16 11:40:25 +0200454 expect_protocol_error(client, &wl_subsurface_interface,
455 WL_SUBSURFACE_ERROR_BAD_SURFACE);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300456}
457
Marek Chalupacfff3122014-07-16 11:40:25 +0200458TEST(test_subsurface_place_below_stranger)
Pekka Paalanene844bf22013-04-25 13:57:43 +0300459{
460 struct client *client;
461 struct compound_surface com;
462 struct wl_surface *stranger;
463
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200464 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300465 assert(client);
466
467 stranger = wl_compositor_create_surface(client->wl_compositor);
468 populate_compound_surface(&com, client);
469
470 /* bad sibling */
471 wl_subsurface_place_below(com.sub[0], stranger);
472
Marek Chalupacfff3122014-07-16 11:40:25 +0200473 expect_protocol_error(client, &wl_subsurface_interface,
474 WL_SUBSURFACE_ERROR_BAD_SURFACE);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300475}
476
Marek Chalupacfff3122014-07-16 11:40:25 +0200477TEST(test_subsurface_place_above_foreign)
Pekka Paalanene844bf22013-04-25 13:57:43 +0300478{
479 struct client *client;
480 struct compound_surface com1;
481 struct compound_surface com2;
482
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200483 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300484 assert(client);
485
486 populate_compound_surface(&com1, client);
487 populate_compound_surface(&com2, client);
488
489 /* bad sibling */
490 wl_subsurface_place_above(com1.sub[0], com2.child[0]);
491
Marek Chalupacfff3122014-07-16 11:40:25 +0200492 expect_protocol_error(client, &wl_subsurface_interface,
493 WL_SUBSURFACE_ERROR_BAD_SURFACE);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300494}
495
Marek Chalupacfff3122014-07-16 11:40:25 +0200496TEST(test_subsurface_place_below_foreign)
Pekka Paalanene844bf22013-04-25 13:57:43 +0300497{
498 struct client *client;
499 struct compound_surface com1;
500 struct compound_surface com2;
501
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200502 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300503 assert(client);
504
505 populate_compound_surface(&com1, client);
506 populate_compound_surface(&com2, client);
507
508 /* bad sibling */
509 wl_subsurface_place_below(com1.sub[0], com2.child[0]);
510
Marek Chalupacfff3122014-07-16 11:40:25 +0200511 expect_protocol_error(client, &wl_subsurface_interface,
512 WL_SUBSURFACE_ERROR_BAD_SURFACE);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300513}
514
515TEST(test_subsurface_destroy_protocol)
516{
517 struct client *client;
518 struct compound_surface com;
519
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200520 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300521 assert(client);
522
523 populate_compound_surface(&com, client);
524
525 /* not needed anymore */
526 wl_subcompositor_destroy(com.subco);
527
528 /* detach child from parent */
529 wl_subsurface_destroy(com.sub[0]);
530
531 /* destroy: child, parent */
532 wl_surface_destroy(com.child[1]);
533 wl_surface_destroy(com.parent);
534
535 /* destroy: parent, child */
536 wl_surface_destroy(com.child[2]);
537
538 /* destroy: sub, child */
539 wl_surface_destroy(com.child[0]);
540
541 /* 2x destroy: child, sub */
542 wl_subsurface_destroy(com.sub[2]);
543 wl_subsurface_destroy(com.sub[1]);
544
545 client_roundtrip(client);
546}
Pekka Paalanenbeb080e2013-05-17 16:46:04 +0300547
548static void
549create_subsurface_tree(struct client *client, struct wl_surface **surfs,
550 struct wl_subsurface **subs, int n)
551{
552 struct wl_subcompositor *subco;
553 int i;
554
555 subco = get_subcompositor(client);
556
557 for (i = 0; i < n; i++)
558 surfs[i] = wl_compositor_create_surface(client->wl_compositor);
559
560 /*
561 * The tree of sub-surfaces:
562 * 0
563 * / \
564 * 1 2 - 10
565 * / \ |\
566 * 3 5 9 6
567 * / / \
568 * 4 7 8
569 * Surface 0 has no wl_subsurface, others do.
570 */
571
572 switch (n) {
573 default:
574 assert(0);
575 break;
576
577#define SUB_LINK(s,p) \
578 subs[s] = wl_subcompositor_get_subsurface(subco, surfs[s], surfs[p])
579
580 case 11:
581 SUB_LINK(10, 2);
Daniel Stone2ef9b1a2017-03-13 16:31:36 +0000582 /* fallthrough */
Pekka Paalanenbeb080e2013-05-17 16:46:04 +0300583 case 10:
584 SUB_LINK(9, 2);
Daniel Stone2ef9b1a2017-03-13 16:31:36 +0000585 /* fallthrough */
Pekka Paalanenbeb080e2013-05-17 16:46:04 +0300586 case 9:
587 SUB_LINK(8, 6);
Daniel Stone2ef9b1a2017-03-13 16:31:36 +0000588 /* fallthrough */
Pekka Paalanenbeb080e2013-05-17 16:46:04 +0300589 case 8:
590 SUB_LINK(7, 6);
Daniel Stone2ef9b1a2017-03-13 16:31:36 +0000591 /* fallthrough */
Pekka Paalanenbeb080e2013-05-17 16:46:04 +0300592 case 7:
593 SUB_LINK(6, 2);
Daniel Stone2ef9b1a2017-03-13 16:31:36 +0000594 /* fallthrough */
Pekka Paalanenbeb080e2013-05-17 16:46:04 +0300595 case 6:
596 SUB_LINK(5, 1);
Daniel Stone2ef9b1a2017-03-13 16:31:36 +0000597 /* fallthrough */
Pekka Paalanenbeb080e2013-05-17 16:46:04 +0300598 case 5:
599 SUB_LINK(4, 3);
Daniel Stone2ef9b1a2017-03-13 16:31:36 +0000600 /* fallthrough */
Pekka Paalanenbeb080e2013-05-17 16:46:04 +0300601 case 4:
602 SUB_LINK(3, 1);
Daniel Stone2ef9b1a2017-03-13 16:31:36 +0000603 /* fallthrough */
Pekka Paalanenbeb080e2013-05-17 16:46:04 +0300604 case 3:
605 SUB_LINK(2, 0);
Daniel Stone2ef9b1a2017-03-13 16:31:36 +0000606 /* fallthrough */
Pekka Paalanenbeb080e2013-05-17 16:46:04 +0300607 case 2:
608 SUB_LINK(1, 0);
609
610#undef SUB_LINK
611 };
612}
613
614static void
615destroy_subsurface_tree(struct wl_surface **surfs,
616 struct wl_subsurface **subs, int n)
617{
618 int i;
619
620 for (i = n; i-- > 0; ) {
621 if (surfs[i])
622 wl_surface_destroy(surfs[i]);
623
624 if (subs[i])
625 wl_subsurface_destroy(subs[i]);
626 }
627}
628
629static int
630has_dupe(int *cnt, int n)
631{
632 int i;
633
634 for (i = 0; i < n; i++)
635 if (cnt[i] == cnt[n])
636 return 1;
637
638 return 0;
639}
640
641/* Note: number of permutations to test is: set_size! / (set_size - NSTEPS)!
642 */
643#define NSTEPS 3
644
645struct permu_state {
646 int set_size;
647 int cnt[NSTEPS];
648};
649
650static void
651permu_init(struct permu_state *s, int set_size)
652{
653 int i;
654
655 s->set_size = set_size;
656 for (i = 0; i < NSTEPS; i++)
657 s->cnt[i] = 0;
658}
659
660static int
661permu_next(struct permu_state *s)
662{
663 int k;
664
665 s->cnt[NSTEPS - 1]++;
666
667 while (1) {
668 if (s->cnt[0] >= s->set_size) {
669 return -1;
670 }
671
672 for (k = 1; k < NSTEPS; k++) {
673 if (s->cnt[k] >= s->set_size) {
674 s->cnt[k - 1]++;
675 s->cnt[k] = 0;
676 break;
677 }
678
679 if (has_dupe(s->cnt, k)) {
680 s->cnt[k]++;
681 break;
682 }
683 }
684
685 if (k == NSTEPS)
686 return 0;
687 }
688}
689
690static void
691destroy_permu_object(struct wl_surface **surfs,
692 struct wl_subsurface **subs, int i)
693{
694 int h = (i + 1) / 2;
695
696 if (i & 1) {
697 fprintf(stderr, " [sub %2d]", h);
698 wl_subsurface_destroy(subs[h]);
699 subs[h] = NULL;
700 } else {
701 fprintf(stderr, " [surf %2d]", h);
702 wl_surface_destroy(surfs[h]);
703 surfs[h] = NULL;
704 }
705}
706
707TEST(test_subsurface_destroy_permutations)
708{
709 /*
710 * Test wl_surface and wl_subsurface destruction orders in a
711 * complex tree of sub-surfaces.
712 *
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.
718 */
719
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;
725 int counter = 0;
726 int i;
727
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200728 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanenbeb080e2013-05-17 16:46:04 +0300729 assert(client);
730
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);
736
737 create_subsurface_tree(client, surfs, subs, test_size);
738
739 fprintf(stderr, "permu");
740
741 for (i = 0; i < NSTEPS; i++)
742 fprintf(stderr, " %2d", per.cnt[i]);
743
744 for (i = 0; i < NSTEPS; i++)
745 destroy_permu_object(surfs, subs, per.cnt[i]);
746
747 fprintf(stderr, "\n");
748 client_roundtrip(client);
749
750 destroy_subsurface_tree(surfs, subs, test_size);
751 counter++;
752 }
753
754 client_roundtrip(client);
755 fprintf(stderr, "tried %d destroy permutations\n", counter);
756}