tests: add test_seat_release() for symmetry
[platform/upstream/weston.git] / tests / subsurface-test.c
1 /*
2  * Copyright © 2012 Collabora, Ltd.
3  *
4  * 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:
11  *
12  * 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.
24  */
25
26 #include "config.h"
27
28 #include <stdio.h>
29 #include <string.h>
30
31 #include "weston-test-client-helper.h"
32
33 #define NUM_SUBSURFACES 3
34
35 struct 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
42 static struct wl_subcompositor *
43 get_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
70 static void
71 populate_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
89 TEST(test_subsurface_basic_protocol)
90 {
91         struct client *client;
92         struct compound_surface com1;
93         struct compound_surface com2;
94
95         client = create_client_and_test_surface(100, 50, 123, 77);
96         assert(client);
97
98         populate_compound_surface(&com1, client);
99         populate_compound_surface(&com2, client);
100
101         client_roundtrip(client);
102 }
103
104 TEST(test_subsurface_position_protocol)
105 {
106         struct client *client;
107         struct compound_surface com;
108         int i;
109
110         client = create_client_and_test_surface(100, 50, 123, 77);
111         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
121 TEST(test_subsurface_placement_protocol)
122 {
123         struct client *client;
124         struct compound_surface com;
125
126         client = create_client_and_test_surface(100, 50, 123, 77);
127         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
139 TEST(test_subsurface_paradox)
140 {
141         struct client *client;
142         struct wl_surface *parent;
143         struct wl_subcompositor *subco;
144
145         client = create_client_and_test_surface(100, 50, 123, 77);
146         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
154         expect_protocol_error(client, &wl_subcompositor_interface,
155                               WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE);
156 }
157
158 TEST(test_subsurface_identical_link)
159 {
160         struct client *client;
161         struct compound_surface com;
162
163         client = create_client_and_test_surface(100, 50, 123, 77);
164         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
171         expect_protocol_error(client, &wl_subcompositor_interface,
172                               WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE);
173 }
174
175 TEST(test_subsurface_change_link)
176 {
177         struct client *client;
178         struct compound_surface com;
179         struct wl_surface *stranger;
180
181         client = create_client_and_test_surface(100, 50, 123, 77);
182         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
190         expect_protocol_error(client, &wl_subcompositor_interface,
191                               WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE);
192 }
193
194 TEST(test_subsurface_nesting)
195 {
196         struct client *client;
197         struct compound_surface com;
198         struct wl_surface *stranger;
199
200         client = create_client_and_test_surface(100, 50, 123, 77);
201         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
212 TEST(test_subsurface_nesting_parent)
213 {
214         struct client *client;
215         struct compound_surface com;
216         struct wl_surface *stranger;
217
218         client = create_client_and_test_surface(100, 50, 123, 77);
219         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
230 TEST(test_subsurface_loop_paradox)
231 {
232         struct client *client;
233         struct wl_surface *surface[3];
234         struct wl_subcompositor *subco;
235
236         client = create_client_and_test_surface(100, 50, 123, 77);
237         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
249         expect_protocol_error(client, &wl_subcompositor_interface,
250                               WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE);
251 }
252
253 TEST(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
275 TEST(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
299 TEST(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
323 TEST(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
346 TEST(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
368 TEST(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
392 TEST(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
416 TEST(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
439 TEST(test_subsurface_place_above_stranger)
440 {
441         struct client *client;
442         struct compound_surface com;
443         struct wl_surface *stranger;
444
445         client = create_client_and_test_surface(100, 50, 123, 77);
446         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
454         expect_protocol_error(client, &wl_subsurface_interface,
455                               WL_SUBSURFACE_ERROR_BAD_SURFACE);
456 }
457
458 TEST(test_subsurface_place_below_stranger)
459 {
460         struct client *client;
461         struct compound_surface com;
462         struct wl_surface *stranger;
463
464         client = create_client_and_test_surface(100, 50, 123, 77);
465         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
473         expect_protocol_error(client, &wl_subsurface_interface,
474                               WL_SUBSURFACE_ERROR_BAD_SURFACE);
475 }
476
477 TEST(test_subsurface_place_above_foreign)
478 {
479         struct client *client;
480         struct compound_surface com1;
481         struct compound_surface com2;
482
483         client = create_client_and_test_surface(100, 50, 123, 77);
484         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
492         expect_protocol_error(client, &wl_subsurface_interface,
493                               WL_SUBSURFACE_ERROR_BAD_SURFACE);
494 }
495
496 TEST(test_subsurface_place_below_foreign)
497 {
498         struct client *client;
499         struct compound_surface com1;
500         struct compound_surface com2;
501
502         client = create_client_and_test_surface(100, 50, 123, 77);
503         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
511         expect_protocol_error(client, &wl_subsurface_interface,
512                               WL_SUBSURFACE_ERROR_BAD_SURFACE);
513 }
514
515 TEST(test_subsurface_destroy_protocol)
516 {
517         struct client *client;
518         struct compound_surface com;
519
520         client = create_client_and_test_surface(100, 50, 123, 77);
521         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 }
547
548 static void
549 create_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);
582                 /* fallthrough */
583         case 10:
584                 SUB_LINK(9, 2);
585                 /* fallthrough */
586         case 9:
587                 SUB_LINK(8, 6);
588                 /* fallthrough */
589         case 8:
590                 SUB_LINK(7, 6);
591                 /* fallthrough */
592         case 7:
593                 SUB_LINK(6, 2);
594                 /* fallthrough */
595         case 6:
596                 SUB_LINK(5, 1);
597                 /* fallthrough */
598         case 5:
599                 SUB_LINK(4, 3);
600                 /* fallthrough */
601         case 4:
602                 SUB_LINK(3, 1);
603                 /* fallthrough */
604         case 3:
605                 SUB_LINK(2, 0);
606                 /* fallthrough */
607         case 2:
608                 SUB_LINK(1, 0);
609
610 #undef SUB_LINK
611         };
612 }
613
614 static void
615 destroy_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
629 static int
630 has_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
645 struct permu_state {
646         int set_size;
647         int cnt[NSTEPS];
648 };
649
650 static void
651 permu_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
660 static int
661 permu_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
690 static void
691 destroy_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
707 TEST(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
728         client = create_client_and_test_surface(100, 50, 123, 77);
729         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 }