blob: cdf595da0250a49099c5da1c1caa94be99051d4d [file] [log] [blame]
Pekka Paalanene844bf22013-04-25 13:57:43 +03001/*
2 * Copyright © 2012 Collabora, Ltd.
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and
5 * its documentation for any purpose is hereby granted without fee, provided
6 * that the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of the copyright holders not be used in
9 * advertising or publicity pertaining to distribution of the software
10 * without specific, written prior permission. The copyright holders make
11 * no representations about the suitability of this software for any
12 * purpose. It is provided "as is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
15 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
17 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
18 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
19 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 */
22
Andrew Wedgbury9cd661e2014-04-07 12:40:35 +010023#include "config.h"
24
Bryce Harringtona7680262014-11-19 17:18:34 -080025#include <stdio.h>
Pekka Paalanene844bf22013-04-25 13:57:43 +030026#include <string.h>
27
28#include "weston-test-client-helper.h"
Pekka Paalanene844bf22013-04-25 13:57:43 +030029
30#define NUM_SUBSURFACES 3
31
32struct compound_surface {
33 struct wl_subcompositor *subco;
34 struct wl_surface *parent;
35 struct wl_surface *child[NUM_SUBSURFACES];
36 struct wl_subsurface *sub[NUM_SUBSURFACES];
37};
38
39static struct wl_subcompositor *
40get_subcompositor(struct client *client)
41{
42 struct global *g;
43 struct global *global_sub = NULL;
44 struct wl_subcompositor *sub;
45
46 wl_list_for_each(g, &client->global_list, link) {
47 if (strcmp(g->interface, "wl_subcompositor"))
48 continue;
49
50 if (global_sub)
51 assert(0 && "multiple wl_subcompositor objects");
52
53 global_sub = g;
54 }
55
56 assert(global_sub && "no wl_subcompositor found");
57
58 assert(global_sub->version == 1);
59
60 sub = wl_registry_bind(client->wl_registry, global_sub->name,
61 &wl_subcompositor_interface, 1);
62 assert(sub);
63
64 return sub;
65}
66
67static void
68populate_compound_surface(struct compound_surface *com, struct client *client)
69{
70 int i;
71
72 com->subco = get_subcompositor(client);
73
74 com->parent = wl_compositor_create_surface(client->wl_compositor);
75
76 for (i = 0; i < NUM_SUBSURFACES; i++) {
77 com->child[i] =
78 wl_compositor_create_surface(client->wl_compositor);
79 com->sub[i] =
80 wl_subcompositor_get_subsurface(com->subco,
81 com->child[i],
82 com->parent);
83 }
84}
85
86TEST(test_subsurface_basic_protocol)
87{
88 struct client *client;
89 struct compound_surface com1;
90 struct compound_surface com2;
91
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +020092 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +030093 assert(client);
94
95 populate_compound_surface(&com1, client);
96 populate_compound_surface(&com2, client);
97
98 client_roundtrip(client);
99}
100
101TEST(test_subsurface_position_protocol)
102{
103 struct client *client;
104 struct compound_surface com;
105 int i;
106
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200107 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300108 assert(client);
109
110 populate_compound_surface(&com, client);
111 for (i = 0; i < NUM_SUBSURFACES; i++)
112 wl_subsurface_set_position(com.sub[i],
113 (i + 2) * 20, (i + 2) * 10);
114
115 client_roundtrip(client);
116}
117
118TEST(test_subsurface_placement_protocol)
119{
120 struct client *client;
121 struct compound_surface com;
122
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200123 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300124 assert(client);
125
126 populate_compound_surface(&com, client);
127
128 wl_subsurface_place_above(com.sub[0], com.child[1]);
129 wl_subsurface_place_above(com.sub[1], com.parent);
130 wl_subsurface_place_below(com.sub[2], com.child[0]);
131 wl_subsurface_place_below(com.sub[1], com.parent);
132
133 client_roundtrip(client);
134}
135
Marek Chalupacfff3122014-07-16 11:40:25 +0200136TEST(test_subsurface_paradox)
Pekka Paalanene844bf22013-04-25 13:57:43 +0300137{
138 struct client *client;
139 struct wl_surface *parent;
140 struct wl_subcompositor *subco;
141
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200142 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300143 assert(client);
144
145 subco = get_subcompositor(client);
146 parent = wl_compositor_create_surface(client->wl_compositor);
147
148 /* surface is its own parent */
149 wl_subcompositor_get_subsurface(subco, parent, parent);
150
Marek Chalupacfff3122014-07-16 11:40:25 +0200151 expect_protocol_error(client, &wl_subcompositor_interface,
152 WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300153}
154
Marek Chalupacfff3122014-07-16 11:40:25 +0200155TEST(test_subsurface_identical_link)
Pekka Paalanene844bf22013-04-25 13:57:43 +0300156{
157 struct client *client;
158 struct compound_surface com;
159
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200160 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300161 assert(client);
162
163 populate_compound_surface(&com, client);
164
165 /* surface is already a subsurface */
166 wl_subcompositor_get_subsurface(com.subco, com.child[0], com.parent);
167
Marek Chalupacfff3122014-07-16 11:40:25 +0200168 expect_protocol_error(client, &wl_subcompositor_interface,
169 WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300170}
171
Marek Chalupacfff3122014-07-16 11:40:25 +0200172TEST(test_subsurface_change_link)
Pekka Paalanene844bf22013-04-25 13:57:43 +0300173{
174 struct client *client;
175 struct compound_surface com;
176 struct wl_surface *stranger;
177
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200178 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300179 assert(client);
180
181 stranger = wl_compositor_create_surface(client->wl_compositor);
182 populate_compound_surface(&com, client);
183
184 /* surface is already a subsurface */
185 wl_subcompositor_get_subsurface(com.subco, com.child[0], stranger);
186
Marek Chalupacfff3122014-07-16 11:40:25 +0200187 expect_protocol_error(client, &wl_subcompositor_interface,
188 WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300189}
190
191TEST(test_subsurface_nesting)
192{
193 struct client *client;
194 struct compound_surface com;
195 struct wl_surface *stranger;
196
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200197 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300198 assert(client);
199
200 stranger = wl_compositor_create_surface(client->wl_compositor);
201 populate_compound_surface(&com, client);
202
203 /* parent is a sub-surface */
204 wl_subcompositor_get_subsurface(com.subco, stranger, com.child[0]);
205
206 client_roundtrip(client);
207}
208
209TEST(test_subsurface_nesting_parent)
210{
211 struct client *client;
212 struct compound_surface com;
213 struct wl_surface *stranger;
214
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200215 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300216 assert(client);
217
218 stranger = wl_compositor_create_surface(client->wl_compositor);
219 populate_compound_surface(&com, client);
220
221 /* surface is already a parent */
222 wl_subcompositor_get_subsurface(com.subco, com.parent, stranger);
223
224 client_roundtrip(client);
225}
226
Marek Chalupacfff3122014-07-16 11:40:25 +0200227TEST(test_subsurface_loop_paradox)
Pekka Paalanen5e9bedb2013-05-17 16:46:06 +0300228{
229 struct client *client;
230 struct wl_surface *surface[3];
231 struct wl_subcompositor *subco;
232
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200233 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanen5e9bedb2013-05-17 16:46:06 +0300234 assert(client);
235
236 subco = get_subcompositor(client);
237 surface[0] = wl_compositor_create_surface(client->wl_compositor);
238 surface[1] = wl_compositor_create_surface(client->wl_compositor);
239 surface[2] = wl_compositor_create_surface(client->wl_compositor);
240
241 /* create a nesting loop */
242 wl_subcompositor_get_subsurface(subco, surface[1], surface[0]);
243 wl_subcompositor_get_subsurface(subco, surface[2], surface[1]);
244 wl_subcompositor_get_subsurface(subco, surface[0], surface[2]);
245
Marek Chalupacfff3122014-07-16 11:40:25 +0200246 expect_protocol_error(client, &wl_subcompositor_interface,
247 WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE);
Pekka Paalanen5e9bedb2013-05-17 16:46:06 +0300248}
249
Marek Chalupacfff3122014-07-16 11:40:25 +0200250TEST(test_subsurface_place_above_stranger)
Pekka Paalanene844bf22013-04-25 13:57:43 +0300251{
252 struct client *client;
253 struct compound_surface com;
254 struct wl_surface *stranger;
255
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200256 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300257 assert(client);
258
259 stranger = wl_compositor_create_surface(client->wl_compositor);
260 populate_compound_surface(&com, client);
261
262 /* bad sibling */
263 wl_subsurface_place_above(com.sub[0], stranger);
264
Marek Chalupacfff3122014-07-16 11:40:25 +0200265 expect_protocol_error(client, &wl_subsurface_interface,
266 WL_SUBSURFACE_ERROR_BAD_SURFACE);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300267}
268
Marek Chalupacfff3122014-07-16 11:40:25 +0200269TEST(test_subsurface_place_below_stranger)
Pekka Paalanene844bf22013-04-25 13:57:43 +0300270{
271 struct client *client;
272 struct compound_surface com;
273 struct wl_surface *stranger;
274
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200275 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300276 assert(client);
277
278 stranger = wl_compositor_create_surface(client->wl_compositor);
279 populate_compound_surface(&com, client);
280
281 /* bad sibling */
282 wl_subsurface_place_below(com.sub[0], stranger);
283
Marek Chalupacfff3122014-07-16 11:40:25 +0200284 expect_protocol_error(client, &wl_subsurface_interface,
285 WL_SUBSURFACE_ERROR_BAD_SURFACE);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300286}
287
Marek Chalupacfff3122014-07-16 11:40:25 +0200288TEST(test_subsurface_place_above_foreign)
Pekka Paalanene844bf22013-04-25 13:57:43 +0300289{
290 struct client *client;
291 struct compound_surface com1;
292 struct compound_surface com2;
293
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200294 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300295 assert(client);
296
297 populate_compound_surface(&com1, client);
298 populate_compound_surface(&com2, client);
299
300 /* bad sibling */
301 wl_subsurface_place_above(com1.sub[0], com2.child[0]);
302
Marek Chalupacfff3122014-07-16 11:40:25 +0200303 expect_protocol_error(client, &wl_subsurface_interface,
304 WL_SUBSURFACE_ERROR_BAD_SURFACE);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300305}
306
Marek Chalupacfff3122014-07-16 11:40:25 +0200307TEST(test_subsurface_place_below_foreign)
Pekka Paalanene844bf22013-04-25 13:57:43 +0300308{
309 struct client *client;
310 struct compound_surface com1;
311 struct compound_surface com2;
312
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200313 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300314 assert(client);
315
316 populate_compound_surface(&com1, client);
317 populate_compound_surface(&com2, client);
318
319 /* bad sibling */
320 wl_subsurface_place_below(com1.sub[0], com2.child[0]);
321
Marek Chalupacfff3122014-07-16 11:40:25 +0200322 expect_protocol_error(client, &wl_subsurface_interface,
323 WL_SUBSURFACE_ERROR_BAD_SURFACE);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300324}
325
326TEST(test_subsurface_destroy_protocol)
327{
328 struct client *client;
329 struct compound_surface com;
330
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200331 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanene844bf22013-04-25 13:57:43 +0300332 assert(client);
333
334 populate_compound_surface(&com, client);
335
336 /* not needed anymore */
337 wl_subcompositor_destroy(com.subco);
338
339 /* detach child from parent */
340 wl_subsurface_destroy(com.sub[0]);
341
342 /* destroy: child, parent */
343 wl_surface_destroy(com.child[1]);
344 wl_surface_destroy(com.parent);
345
346 /* destroy: parent, child */
347 wl_surface_destroy(com.child[2]);
348
349 /* destroy: sub, child */
350 wl_surface_destroy(com.child[0]);
351
352 /* 2x destroy: child, sub */
353 wl_subsurface_destroy(com.sub[2]);
354 wl_subsurface_destroy(com.sub[1]);
355
356 client_roundtrip(client);
357}
Pekka Paalanenbeb080e2013-05-17 16:46:04 +0300358
359static void
360create_subsurface_tree(struct client *client, struct wl_surface **surfs,
361 struct wl_subsurface **subs, int n)
362{
363 struct wl_subcompositor *subco;
364 int i;
365
366 subco = get_subcompositor(client);
367
368 for (i = 0; i < n; i++)
369 surfs[i] = wl_compositor_create_surface(client->wl_compositor);
370
371 /*
372 * The tree of sub-surfaces:
373 * 0
374 * / \
375 * 1 2 - 10
376 * / \ |\
377 * 3 5 9 6
378 * / / \
379 * 4 7 8
380 * Surface 0 has no wl_subsurface, others do.
381 */
382
383 switch (n) {
384 default:
385 assert(0);
386 break;
387
388#define SUB_LINK(s,p) \
389 subs[s] = wl_subcompositor_get_subsurface(subco, surfs[s], surfs[p])
390
391 case 11:
392 SUB_LINK(10, 2);
393 case 10:
394 SUB_LINK(9, 2);
395 case 9:
396 SUB_LINK(8, 6);
397 case 8:
398 SUB_LINK(7, 6);
399 case 7:
400 SUB_LINK(6, 2);
401 case 6:
402 SUB_LINK(5, 1);
403 case 5:
404 SUB_LINK(4, 3);
405 case 4:
406 SUB_LINK(3, 1);
407 case 3:
408 SUB_LINK(2, 0);
409 case 2:
410 SUB_LINK(1, 0);
411
412#undef SUB_LINK
413 };
414}
415
416static void
417destroy_subsurface_tree(struct wl_surface **surfs,
418 struct wl_subsurface **subs, int n)
419{
420 int i;
421
422 for (i = n; i-- > 0; ) {
423 if (surfs[i])
424 wl_surface_destroy(surfs[i]);
425
426 if (subs[i])
427 wl_subsurface_destroy(subs[i]);
428 }
429}
430
431static int
432has_dupe(int *cnt, int n)
433{
434 int i;
435
436 for (i = 0; i < n; i++)
437 if (cnt[i] == cnt[n])
438 return 1;
439
440 return 0;
441}
442
443/* Note: number of permutations to test is: set_size! / (set_size - NSTEPS)!
444 */
445#define NSTEPS 3
446
447struct permu_state {
448 int set_size;
449 int cnt[NSTEPS];
450};
451
452static void
453permu_init(struct permu_state *s, int set_size)
454{
455 int i;
456
457 s->set_size = set_size;
458 for (i = 0; i < NSTEPS; i++)
459 s->cnt[i] = 0;
460}
461
462static int
463permu_next(struct permu_state *s)
464{
465 int k;
466
467 s->cnt[NSTEPS - 1]++;
468
469 while (1) {
470 if (s->cnt[0] >= s->set_size) {
471 return -1;
472 }
473
474 for (k = 1; k < NSTEPS; k++) {
475 if (s->cnt[k] >= s->set_size) {
476 s->cnt[k - 1]++;
477 s->cnt[k] = 0;
478 break;
479 }
480
481 if (has_dupe(s->cnt, k)) {
482 s->cnt[k]++;
483 break;
484 }
485 }
486
487 if (k == NSTEPS)
488 return 0;
489 }
490}
491
492static void
493destroy_permu_object(struct wl_surface **surfs,
494 struct wl_subsurface **subs, int i)
495{
496 int h = (i + 1) / 2;
497
498 if (i & 1) {
499 fprintf(stderr, " [sub %2d]", h);
500 wl_subsurface_destroy(subs[h]);
501 subs[h] = NULL;
502 } else {
503 fprintf(stderr, " [surf %2d]", h);
504 wl_surface_destroy(surfs[h]);
505 surfs[h] = NULL;
506 }
507}
508
509TEST(test_subsurface_destroy_permutations)
510{
511 /*
512 * Test wl_surface and wl_subsurface destruction orders in a
513 * complex tree of sub-surfaces.
514 *
515 * In the tree of sub-surfaces, go through every possible
516 * permutation of destroying all wl_surface and wl_subsurface
517 * objects. Execpt, to limit running time to a reasonable level,
518 * execute only the first NSTEPS destructions from each
519 * permutation, and ignore identical cases.
520 */
521
522 const int test_size = 11;
523 struct client *client;
524 struct wl_surface *surfs[test_size];
525 struct wl_subsurface *subs[test_size];
526 struct permu_state per;
527 int counter = 0;
528 int i;
529
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200530 client = create_client_and_test_surface(100, 50, 123, 77);
Pekka Paalanenbeb080e2013-05-17 16:46:04 +0300531 assert(client);
532
533 permu_init(&per, test_size * 2 - 1);
534 while (permu_next(&per) != -1) {
535 /* for each permutation of NSTEPS out of test_size */
536 memset(surfs, 0, sizeof surfs);
537 memset(subs, 0, sizeof subs);
538
539 create_subsurface_tree(client, surfs, subs, test_size);
540
541 fprintf(stderr, "permu");
542
543 for (i = 0; i < NSTEPS; i++)
544 fprintf(stderr, " %2d", per.cnt[i]);
545
546 for (i = 0; i < NSTEPS; i++)
547 destroy_permu_object(surfs, subs, per.cnt[i]);
548
549 fprintf(stderr, "\n");
550 client_roundtrip(client);
551
552 destroy_subsurface_tree(surfs, subs, test_size);
553 counter++;
554 }
555
556 client_roundtrip(client);
557 fprintf(stderr, "tried %d destroy permutations\n", counter);
558}