downstream: ivi-shell: configure the ivi surface when created
[profile/ivi/weston-ivi-shell.git] / tests / subsurface-test.c
1 /*
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
23 #include "config.h"
24
25 #include <string.h>
26
27 #include "weston-test-client-helper.h"
28 #include <stdio.h>
29
30 #define NUM_SUBSURFACES 3
31
32 struct 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
39 static struct wl_subcompositor *
40 get_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
67 static void
68 populate_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
86 TEST(test_subsurface_basic_protocol)
87 {
88         struct client *client;
89         struct compound_surface com1;
90         struct compound_surface com2;
91
92         client = client_create(100, 50, 123, 77);
93         assert(client);
94
95         populate_compound_surface(&com1, client);
96         populate_compound_surface(&com2, client);
97
98         client_roundtrip(client);
99 }
100
101 TEST(test_subsurface_position_protocol)
102 {
103         struct client *client;
104         struct compound_surface com;
105         int i;
106
107         client = client_create(100, 50, 123, 77);
108         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
118 TEST(test_subsurface_placement_protocol)
119 {
120         struct client *client;
121         struct compound_surface com;
122
123         client = client_create(100, 50, 123, 77);
124         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
136 TEST(test_subsurface_paradox)
137 {
138         struct client *client;
139         struct wl_surface *parent;
140         struct wl_subcompositor *subco;
141
142         client = client_create(100, 50, 123, 77);
143         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
151         expect_protocol_error(client, &wl_subcompositor_interface,
152                               WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE);
153 }
154
155 TEST(test_subsurface_identical_link)
156 {
157         struct client *client;
158         struct compound_surface com;
159
160         client = client_create(100, 50, 123, 77);
161         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
168         expect_protocol_error(client, &wl_subcompositor_interface,
169                               WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE);
170 }
171
172 TEST(test_subsurface_change_link)
173 {
174         struct client *client;
175         struct compound_surface com;
176         struct wl_surface *stranger;
177
178         client = client_create(100, 50, 123, 77);
179         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
187         expect_protocol_error(client, &wl_subcompositor_interface,
188                               WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE);
189 }
190
191 TEST(test_subsurface_nesting)
192 {
193         struct client *client;
194         struct compound_surface com;
195         struct wl_surface *stranger;
196
197         client = client_create(100, 50, 123, 77);
198         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
209 TEST(test_subsurface_nesting_parent)
210 {
211         struct client *client;
212         struct compound_surface com;
213         struct wl_surface *stranger;
214
215         client = client_create(100, 50, 123, 77);
216         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
227 TEST(test_subsurface_loop_paradox)
228 {
229         struct client *client;
230         struct wl_surface *surface[3];
231         struct wl_subcompositor *subco;
232
233         client = client_create(100, 50, 123, 77);
234         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
246         expect_protocol_error(client, &wl_subcompositor_interface,
247                               WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE);
248 }
249
250 TEST(test_subsurface_place_above_stranger)
251 {
252         struct client *client;
253         struct compound_surface com;
254         struct wl_surface *stranger;
255
256         client = client_create(100, 50, 123, 77);
257         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
265         expect_protocol_error(client, &wl_subsurface_interface,
266                               WL_SUBSURFACE_ERROR_BAD_SURFACE);
267 }
268
269 TEST(test_subsurface_place_below_stranger)
270 {
271         struct client *client;
272         struct compound_surface com;
273         struct wl_surface *stranger;
274
275         client = client_create(100, 50, 123, 77);
276         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
284         expect_protocol_error(client, &wl_subsurface_interface,
285                               WL_SUBSURFACE_ERROR_BAD_SURFACE);
286 }
287
288 TEST(test_subsurface_place_above_foreign)
289 {
290         struct client *client;
291         struct compound_surface com1;
292         struct compound_surface com2;
293
294         client = client_create(100, 50, 123, 77);
295         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
303         expect_protocol_error(client, &wl_subsurface_interface,
304                               WL_SUBSURFACE_ERROR_BAD_SURFACE);
305 }
306
307 TEST(test_subsurface_place_below_foreign)
308 {
309         struct client *client;
310         struct compound_surface com1;
311         struct compound_surface com2;
312
313         client = client_create(100, 50, 123, 77);
314         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
322         expect_protocol_error(client, &wl_subsurface_interface,
323                               WL_SUBSURFACE_ERROR_BAD_SURFACE);
324 }
325
326 TEST(test_subsurface_destroy_protocol)
327 {
328         struct client *client;
329         struct compound_surface com;
330
331         client = client_create(100, 50, 123, 77);
332         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 }
358
359 static void
360 create_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
416 static void
417 destroy_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
431 static int
432 has_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
447 struct permu_state {
448         int set_size;
449         int cnt[NSTEPS];
450 };
451
452 static void
453 permu_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
462 static int
463 permu_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
492 static void
493 destroy_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
509 TEST(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
530         client = client_create(100, 50, 123, 77);
531         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 }