blob: 53f8f227f944aa7477d8144f505c46a09879f23c [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 Paalanen701676d2019-11-13 15:45:10 +020032#include "weston-test-fixture-compositor.h"
33
Pekka Paalanenc021e2f2021-06-18 10:33:29 +030034#define VERBOSE 0
35
Pekka Paalanen701676d2019-11-13 15:45:10 +020036static enum test_result_code
37fixture_setup(struct weston_test_harness *harness)
38{
39 struct compositor_setup setup;
40
41 compositor_setup_defaults(&setup);
42
43 return weston_test_harness_execute_as_client(harness, &setup);
44}
45DECLARE_FIXTURE_SETUP(fixture_setup);
Pekka Paalanene844bf22013-04-25 13:57:43 +030046
47#define NUM_SUBSURFACES 3
48
49struct compound_surface {
50 struct wl_subcompositor *subco;
51 struct wl_surface *parent;
52 struct wl_surface *child[NUM_SUBSURFACES];
53 struct wl_subsurface *sub[NUM_SUBSURFACES];
54};
55
56static struct wl_subcompositor *
57get_subcompositor(struct client *client)
58{
59 struct global *g;
60 struct global *global_sub = NULL;
61 struct wl_subcompositor *sub;
62
63 wl_list_for_each(g, &client->global_list, link) {
64 if (strcmp(g->interface, "wl_subcompositor"))
65 continue;
66
67 if (global_sub)
68 assert(0 && "multiple wl_subcompositor objects");
69
70 global_sub = g;
71 }
72
73 assert(global_sub && "no wl_subcompositor found");
74
75 assert(global_sub->version == 1);
76
77 sub = wl_registry_bind(client->wl_registry, global_sub->name,
78 &wl_subcompositor_interface, 1);
79 assert(sub);
80
81 return sub;
82}
83
84static void
85populate_compound_surface(struct compound_surface *com, struct client *client)
86{
87 int i;
88
89 com->subco = get_subcompositor(client);
90
91 com->parent = wl_compositor_create_surface(client->wl_compositor);
92
93 for (i = 0; i < NUM_SUBSURFACES; i++) {
94 com->child[i] =
95 wl_compositor_create_surface(client->wl_compositor);
96 com->sub[i] =
97 wl_subcompositor_get_subsurface(com->subco,
98 com->child[i],
99 com->parent);
100 }
101}
102
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300103static void
104fini_compound_surface(struct compound_surface *com)
105{
106 int i;
107
108 for (i = 0; i < NUM_SUBSURFACES; i++) {
109 if (com->sub[i])
110 wl_subsurface_destroy(com->sub[i]);
111 if (com->child[i])
112 wl_surface_destroy(com->child[i]);
113 }
114
115 wl_surface_destroy(com->parent);
116 wl_subcompositor_destroy(com->subco);
117}
118
Pekka Paalanene844bf22013-04-25 13:57:43 +0300119TEST(test_subsurface_basic_protocol)
120{
121 struct client *client;
122 struct compound_surface com1;
123 struct compound_surface com2;
124
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200125 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300126 assert(client);
127
128 populate_compound_surface(&com1, client);
129 populate_compound_surface(&com2, client);
130
131 client_roundtrip(client);
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300132
133 fini_compound_surface(&com1);
134 fini_compound_surface(&com2);
135 client_destroy(client);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300136}
137
138TEST(test_subsurface_position_protocol)
139{
140 struct client *client;
141 struct compound_surface com;
142 int i;
143
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200144 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300145 assert(client);
146
147 populate_compound_surface(&com, client);
148 for (i = 0; i < NUM_SUBSURFACES; i++)
149 wl_subsurface_set_position(com.sub[i],
150 (i + 2) * 20, (i + 2) * 10);
151
152 client_roundtrip(client);
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300153
154 fini_compound_surface(&com);
155 client_destroy(client);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300156}
157
158TEST(test_subsurface_placement_protocol)
159{
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 wl_subsurface_place_above(com.sub[0], com.child[1]);
169 wl_subsurface_place_above(com.sub[1], com.parent);
170 wl_subsurface_place_below(com.sub[2], com.child[0]);
171 wl_subsurface_place_below(com.sub[1], com.parent);
172
173 client_roundtrip(client);
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300174
175 fini_compound_surface(&com);
176 client_destroy(client);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300177}
178
Marek Chalupacfff3122014-07-16 11:40:25 +0200179TEST(test_subsurface_paradox)
Pekka Paalanene844bf22013-04-25 13:57:43 +0300180{
181 struct client *client;
182 struct wl_surface *parent;
183 struct wl_subcompositor *subco;
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300184 struct wl_subsurface *sub;
Pekka Paalanene844bf22013-04-25 13:57:43 +0300185
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200186 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300187 assert(client);
188
189 subco = get_subcompositor(client);
190 parent = wl_compositor_create_surface(client->wl_compositor);
191
192 /* surface is its own parent */
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300193 sub = wl_subcompositor_get_subsurface(subco, parent, parent);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300194
Marek Chalupacfff3122014-07-16 11:40:25 +0200195 expect_protocol_error(client, &wl_subcompositor_interface,
196 WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE);
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300197
198 wl_subsurface_destroy(sub);
199 wl_surface_destroy(parent);
200 wl_subcompositor_destroy(subco);
201 client_destroy(client);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300202}
203
Marek Chalupacfff3122014-07-16 11:40:25 +0200204TEST(test_subsurface_identical_link)
Pekka Paalanene844bf22013-04-25 13:57:43 +0300205{
206 struct client *client;
207 struct compound_surface com;
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300208 struct wl_subsurface *sub;
Pekka Paalanene844bf22013-04-25 13:57:43 +0300209
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200210 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300211 assert(client);
212
213 populate_compound_surface(&com, client);
214
215 /* surface is already a subsurface */
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300216 sub = wl_subcompositor_get_subsurface(com.subco, com.child[0], com.parent);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300217
Marek Chalupacfff3122014-07-16 11:40:25 +0200218 expect_protocol_error(client, &wl_subcompositor_interface,
219 WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE);
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300220
221 wl_subsurface_destroy(sub);
222 fini_compound_surface(&com);
223 client_destroy(client);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300224}
225
Marek Chalupacfff3122014-07-16 11:40:25 +0200226TEST(test_subsurface_change_link)
Pekka Paalanene844bf22013-04-25 13:57:43 +0300227{
228 struct client *client;
229 struct compound_surface com;
230 struct wl_surface *stranger;
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300231 struct wl_subsurface *sub;
Pekka Paalanene844bf22013-04-25 13:57:43 +0300232
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200233 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300234 assert(client);
235
236 stranger = wl_compositor_create_surface(client->wl_compositor);
237 populate_compound_surface(&com, client);
238
239 /* surface is already a subsurface */
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300240 sub = wl_subcompositor_get_subsurface(com.subco, com.child[0], stranger);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300241
Marek Chalupacfff3122014-07-16 11:40:25 +0200242 expect_protocol_error(client, &wl_subcompositor_interface,
243 WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE);
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300244
245 fini_compound_surface(&com);
246 wl_subsurface_destroy(sub);
247 wl_surface_destroy(stranger);
248 client_destroy(client);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300249}
250
251TEST(test_subsurface_nesting)
252{
253 struct client *client;
254 struct compound_surface com;
255 struct wl_surface *stranger;
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300256 struct wl_subsurface *sub;
Pekka Paalanene844bf22013-04-25 13:57:43 +0300257
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200258 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300259 assert(client);
260
261 stranger = wl_compositor_create_surface(client->wl_compositor);
262 populate_compound_surface(&com, client);
263
264 /* parent is a sub-surface */
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300265 sub = wl_subcompositor_get_subsurface(com.subco, stranger, com.child[0]);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300266
267 client_roundtrip(client);
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300268
269 wl_subsurface_destroy(sub);
270 wl_surface_destroy(stranger);
271 fini_compound_surface(&com);
272 client_destroy(client);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300273}
274
275TEST(test_subsurface_nesting_parent)
276{
277 struct client *client;
278 struct compound_surface com;
279 struct wl_surface *stranger;
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300280 struct wl_subsurface *sub;
Pekka Paalanene844bf22013-04-25 13:57:43 +0300281
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200282 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300283 assert(client);
284
285 stranger = wl_compositor_create_surface(client->wl_compositor);
286 populate_compound_surface(&com, client);
287
288 /* surface is already a parent */
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300289 sub = wl_subcompositor_get_subsurface(com.subco, com.parent, stranger);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300290
291 client_roundtrip(client);
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300292
293 wl_subsurface_destroy(sub);
294 fini_compound_surface(&com);
295 wl_surface_destroy(stranger);
296 client_destroy(client);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300297}
298
Marek Chalupacfff3122014-07-16 11:40:25 +0200299TEST(test_subsurface_loop_paradox)
Pekka Paalanen5e9bedb2013-05-17 16:46:06 +0300300{
301 struct client *client;
302 struct wl_surface *surface[3];
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300303 struct wl_subsurface *sub[3];
Pekka Paalanen5e9bedb2013-05-17 16:46:06 +0300304 struct wl_subcompositor *subco;
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300305 unsigned i;
Pekka Paalanen5e9bedb2013-05-17 16:46:06 +0300306
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200307 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanen5e9bedb2013-05-17 16:46:06 +0300308 assert(client);
309
310 subco = get_subcompositor(client);
311 surface[0] = wl_compositor_create_surface(client->wl_compositor);
312 surface[1] = wl_compositor_create_surface(client->wl_compositor);
313 surface[2] = wl_compositor_create_surface(client->wl_compositor);
314
315 /* create a nesting loop */
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300316 sub[0] = wl_subcompositor_get_subsurface(subco, surface[1], surface[0]);
317 sub[1] = wl_subcompositor_get_subsurface(subco, surface[2], surface[1]);
318 sub[2] = wl_subcompositor_get_subsurface(subco, surface[0], surface[2]);
Pekka Paalanen5e9bedb2013-05-17 16:46:06 +0300319
Marek Chalupacfff3122014-07-16 11:40:25 +0200320 expect_protocol_error(client, &wl_subcompositor_interface,
321 WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE);
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300322
323 for (i = 0; i < ARRAY_LENGTH(sub); i++) {
324 wl_subsurface_destroy(sub[i]);
325 wl_surface_destroy(surface[i]);
326 }
327
328 wl_subcompositor_destroy(subco);
329 client_destroy(client);
Pekka Paalanen5e9bedb2013-05-17 16:46:06 +0300330}
331
Arnaud Vracb8c16c92016-06-08 18:37:57 +0200332TEST(test_subsurface_place_above_nested_parent)
333{
334 struct client *client;
335 struct compound_surface com;
336 struct wl_surface *grandchild;
337 struct wl_subcompositor *subco;
338 struct wl_subsurface *sub;
339
340 client = create_client_and_test_surface(100, 50, 123, 77);
341 assert(client);
342
343 populate_compound_surface(&com, client);
344
345 subco = get_subcompositor(client);
346 grandchild = wl_compositor_create_surface(client->wl_compositor);
347 sub = wl_subcompositor_get_subsurface(subco, grandchild, com.child[0]);
348
349 wl_subsurface_place_above(sub, com.child[0]);
350
351 client_roundtrip(client);
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300352
353 wl_subsurface_destroy(sub);
354 wl_surface_destroy(grandchild);
355 wl_subcompositor_destroy(subco);
356 fini_compound_surface(&com);
357 client_destroy(client);
Arnaud Vracb8c16c92016-06-08 18:37:57 +0200358}
359
Daniel Stone99834002016-11-22 12:40:34 +0000360TEST(test_subsurface_place_above_grandparent)
361{
362 struct client *client;
363 struct compound_surface com;
364 struct wl_surface *grandchild;
365 struct wl_subsurface *sub;
366 struct wl_subcompositor *subco;
367
368 client = create_client_and_test_surface(100, 50, 123, 77);
369 assert(client);
370
371 populate_compound_surface(&com, client);
372
373 subco = get_subcompositor(client);
374 grandchild = wl_compositor_create_surface(client->wl_compositor);
375 sub = wl_subcompositor_get_subsurface(subco, grandchild, com.child[0]);
376
377 /* can't place a subsurface above its grandparent */
378 wl_subsurface_place_above(sub, com.parent);
379
380 expect_protocol_error(client, &wl_subsurface_interface,
381 WL_SUBSURFACE_ERROR_BAD_SURFACE);
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300382
383 wl_subsurface_destroy(sub);
384 wl_surface_destroy(grandchild);
385 wl_subcompositor_destroy(subco);
386 fini_compound_surface(&com);
387 client_destroy(client);
Daniel Stone99834002016-11-22 12:40:34 +0000388}
389
390TEST(test_subsurface_place_above_great_aunt)
391{
392 struct client *client;
393 struct compound_surface com;
394 struct wl_surface *grandchild;
395 struct wl_subsurface *sub;
396 struct wl_subcompositor *subco;
397
398 client = create_client_and_test_surface(100, 50, 123, 77);
399 assert(client);
400
401 populate_compound_surface(&com, client);
402
403 subco = get_subcompositor(client);
404 grandchild = wl_compositor_create_surface(client->wl_compositor);
405 sub = wl_subcompositor_get_subsurface(subco, grandchild, com.child[0]);
406
407 /* can't place a subsurface above its parents' siblings */
408 wl_subsurface_place_above(sub, com.child[1]);
409
410 expect_protocol_error(client, &wl_subsurface_interface,
411 WL_SUBSURFACE_ERROR_BAD_SURFACE);
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300412
413 wl_subsurface_destroy(sub);
414 wl_surface_destroy(grandchild);
415 wl_subcompositor_destroy(subco);
416 fini_compound_surface(&com);
417 client_destroy(client);
Daniel Stone99834002016-11-22 12:40:34 +0000418}
419
420TEST(test_subsurface_place_above_child)
421{
422 struct client *client;
423 struct compound_surface com;
424 struct wl_surface *grandchild;
425 struct wl_subcompositor *subco;
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300426 struct wl_subsurface *sub;
Daniel Stone99834002016-11-22 12:40:34 +0000427
428 client = create_client_and_test_surface(100, 50, 123, 77);
429 assert(client);
430
431 populate_compound_surface(&com, client);
432
433 subco = get_subcompositor(client);
434 grandchild = wl_compositor_create_surface(client->wl_compositor);
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300435 sub = wl_subcompositor_get_subsurface(subco, grandchild, com.child[0]);
Daniel Stone99834002016-11-22 12:40:34 +0000436
437 /* can't place a subsurface above its own child subsurface */
438 wl_subsurface_place_above(com.sub[0], grandchild);
439
440 expect_protocol_error(client, &wl_subsurface_interface,
441 WL_SUBSURFACE_ERROR_BAD_SURFACE);
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300442
443 wl_subsurface_destroy(sub);
444 wl_surface_destroy(grandchild);
445 wl_subcompositor_destroy(subco);
446 fini_compound_surface(&com);
447 client_destroy(client);
Daniel Stone99834002016-11-22 12:40:34 +0000448}
449
Arnaud Vracb8c16c92016-06-08 18:37:57 +0200450TEST(test_subsurface_place_below_nested_parent)
451{
452 struct client *client;
453 struct compound_surface com;
454 struct wl_subcompositor *subco;
455 struct wl_surface *grandchild;
456 struct wl_subsurface *sub;
457
458 client = create_client_and_test_surface(100, 50, 123, 77);
459 assert(client);
460
461 populate_compound_surface(&com, client);
462
463 subco = get_subcompositor(client);
464 grandchild = wl_compositor_create_surface(client->wl_compositor);
465 sub = wl_subcompositor_get_subsurface(subco, grandchild, com.child[0]);
466
467 wl_subsurface_place_below(sub, com.child[0]);
468
469 client_roundtrip(client);
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300470
471 wl_subsurface_destroy(sub);
472 wl_surface_destroy(grandchild);
473 wl_subcompositor_destroy(subco);
474 fini_compound_surface(&com);
475 client_destroy(client);
Arnaud Vracb8c16c92016-06-08 18:37:57 +0200476}
477
Daniel Stone99834002016-11-22 12:40:34 +0000478TEST(test_subsurface_place_below_grandparent)
479{
480 struct client *client;
481 struct compound_surface com;
482 struct wl_surface *grandchild;
483 struct wl_subsurface *sub;
484 struct wl_subcompositor *subco;
485
486 client = create_client_and_test_surface(100, 50, 123, 77);
487 assert(client);
488
489 populate_compound_surface(&com, client);
490
491 subco = get_subcompositor(client);
492 grandchild = wl_compositor_create_surface(client->wl_compositor);
493 sub = wl_subcompositor_get_subsurface(subco, grandchild, com.child[0]);
494
495 /* can't place a subsurface below its grandparent */
496 wl_subsurface_place_below(sub, com.parent);
497
498 expect_protocol_error(client, &wl_subsurface_interface,
499 WL_SUBSURFACE_ERROR_BAD_SURFACE);
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300500
501 wl_subsurface_destroy(sub);
502 wl_surface_destroy(grandchild);
503 wl_subcompositor_destroy(subco);
504 fini_compound_surface(&com);
505 client_destroy(client);
Daniel Stone99834002016-11-22 12:40:34 +0000506}
507
508TEST(test_subsurface_place_below_great_aunt)
509{
510 struct client *client;
511 struct compound_surface com;
512 struct wl_surface *grandchild;
513 struct wl_subsurface *sub;
514 struct wl_subcompositor *subco;
515
516 client = create_client_and_test_surface(100, 50, 123, 77);
517 assert(client);
518
519 populate_compound_surface(&com, client);
520
521 subco = get_subcompositor(client);
522 grandchild = wl_compositor_create_surface(client->wl_compositor);
523 sub = wl_subcompositor_get_subsurface(subco, grandchild, com.child[0]);
524
525 /* can't place a subsurface below its parents' siblings */
526 wl_subsurface_place_below(sub, com.child[1]);
527
528 expect_protocol_error(client, &wl_subsurface_interface,
529 WL_SUBSURFACE_ERROR_BAD_SURFACE);
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300530
531 wl_subsurface_destroy(sub);
532 wl_surface_destroy(grandchild);
533 wl_subcompositor_destroy(subco);
534 fini_compound_surface(&com);
535 client_destroy(client);
Daniel Stone99834002016-11-22 12:40:34 +0000536}
537
538TEST(test_subsurface_place_below_child)
539{
540 struct client *client;
541 struct compound_surface com;
542 struct wl_surface *grandchild;
543 struct wl_subcompositor *subco;
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300544 struct wl_subsurface *sub;
Daniel Stone99834002016-11-22 12:40:34 +0000545
546 client = create_client_and_test_surface(100, 50, 123, 77);
547 assert(client);
548
549 populate_compound_surface(&com, client);
550
551 subco = get_subcompositor(client);
552 grandchild = wl_compositor_create_surface(client->wl_compositor);
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300553 sub = wl_subcompositor_get_subsurface(subco, grandchild, com.child[0]);
Daniel Stone99834002016-11-22 12:40:34 +0000554
555 /* can't place a subsurface below its own child subsurface */
556 wl_subsurface_place_below(com.sub[0], grandchild);
557
558 expect_protocol_error(client, &wl_subsurface_interface,
559 WL_SUBSURFACE_ERROR_BAD_SURFACE);
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300560
561 wl_subsurface_destroy(sub);
562 wl_surface_destroy(grandchild);
563 wl_subcompositor_destroy(subco);
564 fini_compound_surface(&com);
565 client_destroy(client);
Daniel Stone99834002016-11-22 12:40:34 +0000566}
567
Marek Chalupacfff3122014-07-16 11:40:25 +0200568TEST(test_subsurface_place_above_stranger)
Pekka Paalanene844bf22013-04-25 13:57:43 +0300569{
570 struct client *client;
571 struct compound_surface com;
572 struct wl_surface *stranger;
573
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200574 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300575 assert(client);
576
577 stranger = wl_compositor_create_surface(client->wl_compositor);
578 populate_compound_surface(&com, client);
579
580 /* bad sibling */
581 wl_subsurface_place_above(com.sub[0], stranger);
582
Marek Chalupacfff3122014-07-16 11:40:25 +0200583 expect_protocol_error(client, &wl_subsurface_interface,
584 WL_SUBSURFACE_ERROR_BAD_SURFACE);
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300585
586 wl_surface_destroy(stranger);
587 fini_compound_surface(&com);
588 client_destroy(client);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300589}
590
Marek Chalupacfff3122014-07-16 11:40:25 +0200591TEST(test_subsurface_place_below_stranger)
Pekka Paalanene844bf22013-04-25 13:57:43 +0300592{
593 struct client *client;
594 struct compound_surface com;
595 struct wl_surface *stranger;
596
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200597 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300598 assert(client);
599
600 stranger = wl_compositor_create_surface(client->wl_compositor);
601 populate_compound_surface(&com, client);
602
603 /* bad sibling */
604 wl_subsurface_place_below(com.sub[0], stranger);
605
Marek Chalupacfff3122014-07-16 11:40:25 +0200606 expect_protocol_error(client, &wl_subsurface_interface,
607 WL_SUBSURFACE_ERROR_BAD_SURFACE);
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300608
609 wl_surface_destroy(stranger);
610 fini_compound_surface(&com);
611 client_destroy(client);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300612}
613
Marek Chalupacfff3122014-07-16 11:40:25 +0200614TEST(test_subsurface_place_above_foreign)
Pekka Paalanene844bf22013-04-25 13:57:43 +0300615{
616 struct client *client;
617 struct compound_surface com1;
618 struct compound_surface com2;
619
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200620 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300621 assert(client);
622
623 populate_compound_surface(&com1, client);
624 populate_compound_surface(&com2, client);
625
626 /* bad sibling */
627 wl_subsurface_place_above(com1.sub[0], com2.child[0]);
628
Marek Chalupacfff3122014-07-16 11:40:25 +0200629 expect_protocol_error(client, &wl_subsurface_interface,
630 WL_SUBSURFACE_ERROR_BAD_SURFACE);
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300631
632 fini_compound_surface(&com1);
633 fini_compound_surface(&com2);
634 client_destroy(client);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300635}
636
Marek Chalupacfff3122014-07-16 11:40:25 +0200637TEST(test_subsurface_place_below_foreign)
Pekka Paalanene844bf22013-04-25 13:57:43 +0300638{
639 struct client *client;
640 struct compound_surface com1;
641 struct compound_surface com2;
642
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200643 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300644 assert(client);
645
646 populate_compound_surface(&com1, client);
647 populate_compound_surface(&com2, client);
648
649 /* bad sibling */
650 wl_subsurface_place_below(com1.sub[0], com2.child[0]);
651
Marek Chalupacfff3122014-07-16 11:40:25 +0200652 expect_protocol_error(client, &wl_subsurface_interface,
653 WL_SUBSURFACE_ERROR_BAD_SURFACE);
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300654
655 fini_compound_surface(&com1);
656 fini_compound_surface(&com2);
657 client_destroy(client);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300658}
659
660TEST(test_subsurface_destroy_protocol)
661{
662 struct client *client;
663 struct compound_surface com;
664
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200665 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300666 assert(client);
667
668 populate_compound_surface(&com, client);
669
670 /* not needed anymore */
671 wl_subcompositor_destroy(com.subco);
672
673 /* detach child from parent */
674 wl_subsurface_destroy(com.sub[0]);
675
676 /* destroy: child, parent */
677 wl_surface_destroy(com.child[1]);
678 wl_surface_destroy(com.parent);
679
680 /* destroy: parent, child */
681 wl_surface_destroy(com.child[2]);
682
683 /* destroy: sub, child */
684 wl_surface_destroy(com.child[0]);
685
686 /* 2x destroy: child, sub */
687 wl_subsurface_destroy(com.sub[2]);
688 wl_subsurface_destroy(com.sub[1]);
689
690 client_roundtrip(client);
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300691
692 client_destroy(client);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300693}
Pekka Paalanenbeb080e2013-05-17 16:46:04 +0300694
695static void
696create_subsurface_tree(struct client *client, struct wl_surface **surfs,
697 struct wl_subsurface **subs, int n)
698{
699 struct wl_subcompositor *subco;
700 int i;
701
702 subco = get_subcompositor(client);
703
704 for (i = 0; i < n; i++)
705 surfs[i] = wl_compositor_create_surface(client->wl_compositor);
706
707 /*
708 * The tree of sub-surfaces:
709 * 0
710 * / \
711 * 1 2 - 10
712 * / \ |\
713 * 3 5 9 6
714 * / / \
715 * 4 7 8
716 * Surface 0 has no wl_subsurface, others do.
717 */
718
719 switch (n) {
720 default:
721 assert(0);
722 break;
723
724#define SUB_LINK(s,p) \
725 subs[s] = wl_subcompositor_get_subsurface(subco, surfs[s], surfs[p])
726
727 case 11:
728 SUB_LINK(10, 2);
Daniel Stone2ef9b1a2017-03-13 16:31:36 +0000729 /* fallthrough */
Pekka Paalanenbeb080e2013-05-17 16:46:04 +0300730 case 10:
731 SUB_LINK(9, 2);
Daniel Stone2ef9b1a2017-03-13 16:31:36 +0000732 /* fallthrough */
Pekka Paalanenbeb080e2013-05-17 16:46:04 +0300733 case 9:
734 SUB_LINK(8, 6);
Daniel Stone2ef9b1a2017-03-13 16:31:36 +0000735 /* fallthrough */
Pekka Paalanenbeb080e2013-05-17 16:46:04 +0300736 case 8:
737 SUB_LINK(7, 6);
Daniel Stone2ef9b1a2017-03-13 16:31:36 +0000738 /* fallthrough */
Pekka Paalanenbeb080e2013-05-17 16:46:04 +0300739 case 7:
740 SUB_LINK(6, 2);
Daniel Stone2ef9b1a2017-03-13 16:31:36 +0000741 /* fallthrough */
Pekka Paalanenbeb080e2013-05-17 16:46:04 +0300742 case 6:
743 SUB_LINK(5, 1);
Daniel Stone2ef9b1a2017-03-13 16:31:36 +0000744 /* fallthrough */
Pekka Paalanenbeb080e2013-05-17 16:46:04 +0300745 case 5:
746 SUB_LINK(4, 3);
Daniel Stone2ef9b1a2017-03-13 16:31:36 +0000747 /* fallthrough */
Pekka Paalanenbeb080e2013-05-17 16:46:04 +0300748 case 4:
749 SUB_LINK(3, 1);
Daniel Stone2ef9b1a2017-03-13 16:31:36 +0000750 /* fallthrough */
Pekka Paalanenbeb080e2013-05-17 16:46:04 +0300751 case 3:
752 SUB_LINK(2, 0);
Daniel Stone2ef9b1a2017-03-13 16:31:36 +0000753 /* fallthrough */
Pekka Paalanenbeb080e2013-05-17 16:46:04 +0300754 case 2:
755 SUB_LINK(1, 0);
756
757#undef SUB_LINK
758 };
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300759
760 wl_subcompositor_destroy(subco);
Pekka Paalanenbeb080e2013-05-17 16:46:04 +0300761}
762
763static void
764destroy_subsurface_tree(struct wl_surface **surfs,
765 struct wl_subsurface **subs, int n)
766{
767 int i;
768
769 for (i = n; i-- > 0; ) {
770 if (surfs[i])
771 wl_surface_destroy(surfs[i]);
772
773 if (subs[i])
774 wl_subsurface_destroy(subs[i]);
775 }
776}
777
778static int
779has_dupe(int *cnt, int n)
780{
781 int i;
782
783 for (i = 0; i < n; i++)
784 if (cnt[i] == cnt[n])
785 return 1;
786
787 return 0;
788}
789
790/* Note: number of permutations to test is: set_size! / (set_size - NSTEPS)!
791 */
792#define NSTEPS 3
793
794struct permu_state {
795 int set_size;
796 int cnt[NSTEPS];
797};
798
799static void
800permu_init(struct permu_state *s, int set_size)
801{
802 int i;
803
804 s->set_size = set_size;
805 for (i = 0; i < NSTEPS; i++)
806 s->cnt[i] = 0;
807}
808
809static int
810permu_next(struct permu_state *s)
811{
812 int k;
813
814 s->cnt[NSTEPS - 1]++;
815
816 while (1) {
817 if (s->cnt[0] >= s->set_size) {
818 return -1;
819 }
820
821 for (k = 1; k < NSTEPS; k++) {
822 if (s->cnt[k] >= s->set_size) {
823 s->cnt[k - 1]++;
824 s->cnt[k] = 0;
825 break;
826 }
827
828 if (has_dupe(s->cnt, k)) {
829 s->cnt[k]++;
830 break;
831 }
832 }
833
834 if (k == NSTEPS)
835 return 0;
836 }
837}
838
839static void
840destroy_permu_object(struct wl_surface **surfs,
841 struct wl_subsurface **subs, int i)
842{
843 int h = (i + 1) / 2;
844
845 if (i & 1) {
Pekka Paalanenc021e2f2021-06-18 10:33:29 +0300846 if (VERBOSE)
847 testlog(" [sub %2d]", h);
Pekka Paalanenbeb080e2013-05-17 16:46:04 +0300848 wl_subsurface_destroy(subs[h]);
849 subs[h] = NULL;
850 } else {
Pekka Paalanenc021e2f2021-06-18 10:33:29 +0300851 if (VERBOSE)
852 testlog(" [surf %2d]", h);
Pekka Paalanenbeb080e2013-05-17 16:46:04 +0300853 wl_surface_destroy(surfs[h]);
854 surfs[h] = NULL;
855 }
856}
857
858TEST(test_subsurface_destroy_permutations)
859{
860 /*
861 * Test wl_surface and wl_subsurface destruction orders in a
862 * complex tree of sub-surfaces.
863 *
864 * In the tree of sub-surfaces, go through every possible
865 * permutation of destroying all wl_surface and wl_subsurface
866 * objects. Execpt, to limit running time to a reasonable level,
867 * execute only the first NSTEPS destructions from each
868 * permutation, and ignore identical cases.
869 */
870
871 const int test_size = 11;
872 struct client *client;
873 struct wl_surface *surfs[test_size];
874 struct wl_subsurface *subs[test_size];
875 struct permu_state per;
876 int counter = 0;
877 int i;
878
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200879 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanenbeb080e2013-05-17 16:46:04 +0300880 assert(client);
881
882 permu_init(&per, test_size * 2 - 1);
883 while (permu_next(&per) != -1) {
884 /* for each permutation of NSTEPS out of test_size */
885 memset(surfs, 0, sizeof surfs);
886 memset(subs, 0, sizeof subs);
887
888 create_subsurface_tree(client, surfs, subs, test_size);
889
Pekka Paalanenc021e2f2021-06-18 10:33:29 +0300890 if (VERBOSE)
891 testlog("permu");
Pekka Paalanenbeb080e2013-05-17 16:46:04 +0300892
Pekka Paalanenc021e2f2021-06-18 10:33:29 +0300893 if (VERBOSE)
894 for (i = 0; i < NSTEPS; i++)
895 testlog(" %2d", per.cnt[i]);
Pekka Paalanenbeb080e2013-05-17 16:46:04 +0300896
897 for (i = 0; i < NSTEPS; i++)
898 destroy_permu_object(surfs, subs, per.cnt[i]);
899
Pekka Paalanenc021e2f2021-06-18 10:33:29 +0300900 if (VERBOSE)
901 testlog("\n");
Pekka Paalanenbeb080e2013-05-17 16:46:04 +0300902 client_roundtrip(client);
903
904 destroy_subsurface_tree(surfs, subs, test_size);
905 counter++;
906 }
907
908 client_roundtrip(client);
Pekka Paalanen12a138d2019-11-06 15:59:33 +0200909 testlog("tried %d destroy permutations\n", counter);
Pekka Paalanenecbf1db2021-06-17 17:46:55 +0300910
911 client_destroy(client);
Pekka Paalanenbeb080e2013-05-17 16:46:04 +0300912}