blob: 0a210fb6e9aedb1a3cf3bfa9b850da1dc6cd4984 [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
23#include <string.h>
24
25#include "weston-test-client-helper.h"
26#include "subsurface-client-protocol.h"
Pekka Paalanenbeb080e2013-05-17 16:46:04 +030027#include <stdio.h>
Pekka Paalanene844bf22013-04-25 13:57:43 +030028
29#define NUM_SUBSURFACES 3
30
31struct compound_surface {
32 struct wl_subcompositor *subco;
33 struct wl_surface *parent;
34 struct wl_surface *child[NUM_SUBSURFACES];
35 struct wl_subsurface *sub[NUM_SUBSURFACES];
36};
37
38static struct wl_subcompositor *
39get_subcompositor(struct client *client)
40{
41 struct global *g;
42 struct global *global_sub = NULL;
43 struct wl_subcompositor *sub;
44
45 wl_list_for_each(g, &client->global_list, link) {
46 if (strcmp(g->interface, "wl_subcompositor"))
47 continue;
48
49 if (global_sub)
50 assert(0 && "multiple wl_subcompositor objects");
51
52 global_sub = g;
53 }
54
55 assert(global_sub && "no wl_subcompositor found");
56
57 assert(global_sub->version == 1);
58
59 sub = wl_registry_bind(client->wl_registry, global_sub->name,
60 &wl_subcompositor_interface, 1);
61 assert(sub);
62
63 return sub;
64}
65
66static void
67populate_compound_surface(struct compound_surface *com, struct client *client)
68{
69 int i;
70
71 com->subco = get_subcompositor(client);
72
73 com->parent = wl_compositor_create_surface(client->wl_compositor);
74
75 for (i = 0; i < NUM_SUBSURFACES; i++) {
76 com->child[i] =
77 wl_compositor_create_surface(client->wl_compositor);
78 com->sub[i] =
79 wl_subcompositor_get_subsurface(com->subco,
80 com->child[i],
81 com->parent);
82 }
83}
84
85TEST(test_subsurface_basic_protocol)
86{
87 struct client *client;
88 struct compound_surface com1;
89 struct compound_surface com2;
90
91 client = client_create(100, 50, 123, 77);
92 assert(client);
93
94 populate_compound_surface(&com1, client);
95 populate_compound_surface(&com2, client);
96
97 client_roundtrip(client);
98}
99
100TEST(test_subsurface_position_protocol)
101{
102 struct client *client;
103 struct compound_surface com;
104 int i;
105
106 client = client_create(100, 50, 123, 77);
107 assert(client);
108
109 populate_compound_surface(&com, client);
110 for (i = 0; i < NUM_SUBSURFACES; i++)
111 wl_subsurface_set_position(com.sub[i],
112 (i + 2) * 20, (i + 2) * 10);
113
114 client_roundtrip(client);
115}
116
117TEST(test_subsurface_placement_protocol)
118{
119 struct client *client;
120 struct compound_surface com;
121
122 client = client_create(100, 50, 123, 77);
123 assert(client);
124
125 populate_compound_surface(&com, client);
126
127 wl_subsurface_place_above(com.sub[0], com.child[1]);
128 wl_subsurface_place_above(com.sub[1], com.parent);
129 wl_subsurface_place_below(com.sub[2], com.child[0]);
130 wl_subsurface_place_below(com.sub[1], com.parent);
131
132 client_roundtrip(client);
133}
134
135FAIL_TEST(test_subsurface_paradox)
136{
137 struct client *client;
138 struct wl_surface *parent;
139 struct wl_subcompositor *subco;
140
141 client = client_create(100, 50, 123, 77);
142 assert(client);
143
144 subco = get_subcompositor(client);
145 parent = wl_compositor_create_surface(client->wl_compositor);
146
147 /* surface is its own parent */
148 wl_subcompositor_get_subsurface(subco, parent, parent);
149
150 client_roundtrip(client);
151}
152
153FAIL_TEST(test_subsurface_identical_link)
154{
155 struct client *client;
156 struct compound_surface com;
157
158 client = client_create(100, 50, 123, 77);
159 assert(client);
160
161 populate_compound_surface(&com, client);
162
163 /* surface is already a subsurface */
164 wl_subcompositor_get_subsurface(com.subco, com.child[0], com.parent);
165
166 client_roundtrip(client);
167}
168
169FAIL_TEST(test_subsurface_change_link)
170{
171 struct client *client;
172 struct compound_surface com;
173 struct wl_surface *stranger;
174
175 client = client_create(100, 50, 123, 77);
176 assert(client);
177
178 stranger = wl_compositor_create_surface(client->wl_compositor);
179 populate_compound_surface(&com, client);
180
181 /* surface is already a subsurface */
182 wl_subcompositor_get_subsurface(com.subco, com.child[0], stranger);
183
184 client_roundtrip(client);
185}
186
187TEST(test_subsurface_nesting)
188{
189 struct client *client;
190 struct compound_surface com;
191 struct wl_surface *stranger;
192
193 client = client_create(100, 50, 123, 77);
194 assert(client);
195
196 stranger = wl_compositor_create_surface(client->wl_compositor);
197 populate_compound_surface(&com, client);
198
199 /* parent is a sub-surface */
200 wl_subcompositor_get_subsurface(com.subco, stranger, com.child[0]);
201
202 client_roundtrip(client);
203}
204
205TEST(test_subsurface_nesting_parent)
206{
207 struct client *client;
208 struct compound_surface com;
209 struct wl_surface *stranger;
210
211 client = client_create(100, 50, 123, 77);
212 assert(client);
213
214 stranger = wl_compositor_create_surface(client->wl_compositor);
215 populate_compound_surface(&com, client);
216
217 /* surface is already a parent */
218 wl_subcompositor_get_subsurface(com.subco, com.parent, stranger);
219
220 client_roundtrip(client);
221}
222
223FAIL_TEST(test_subsurface_place_above_stranger)
224{
225 struct client *client;
226 struct compound_surface com;
227 struct wl_surface *stranger;
228
229 client = client_create(100, 50, 123, 77);
230 assert(client);
231
232 stranger = wl_compositor_create_surface(client->wl_compositor);
233 populate_compound_surface(&com, client);
234
235 /* bad sibling */
236 wl_subsurface_place_above(com.sub[0], stranger);
237
238 client_roundtrip(client);
239}
240
241FAIL_TEST(test_subsurface_place_below_stranger)
242{
243 struct client *client;
244 struct compound_surface com;
245 struct wl_surface *stranger;
246
247 client = client_create(100, 50, 123, 77);
248 assert(client);
249
250 stranger = wl_compositor_create_surface(client->wl_compositor);
251 populate_compound_surface(&com, client);
252
253 /* bad sibling */
254 wl_subsurface_place_below(com.sub[0], stranger);
255
256 client_roundtrip(client);
257}
258
259FAIL_TEST(test_subsurface_place_above_foreign)
260{
261 struct client *client;
262 struct compound_surface com1;
263 struct compound_surface com2;
264
265 client = client_create(100, 50, 123, 77);
266 assert(client);
267
268 populate_compound_surface(&com1, client);
269 populate_compound_surface(&com2, client);
270
271 /* bad sibling */
272 wl_subsurface_place_above(com1.sub[0], com2.child[0]);
273
274 client_roundtrip(client);
275}
276
277FAIL_TEST(test_subsurface_place_below_foreign)
278{
279 struct client *client;
280 struct compound_surface com1;
281 struct compound_surface com2;
282
283 client = client_create(100, 50, 123, 77);
284 assert(client);
285
286 populate_compound_surface(&com1, client);
287 populate_compound_surface(&com2, client);
288
289 /* bad sibling */
290 wl_subsurface_place_below(com1.sub[0], com2.child[0]);
291
292 client_roundtrip(client);
293}
294
295TEST(test_subsurface_destroy_protocol)
296{
297 struct client *client;
298 struct compound_surface com;
299
300 client = client_create(100, 50, 123, 77);
301 assert(client);
302
303 populate_compound_surface(&com, client);
304
305 /* not needed anymore */
306 wl_subcompositor_destroy(com.subco);
307
308 /* detach child from parent */
309 wl_subsurface_destroy(com.sub[0]);
310
311 /* destroy: child, parent */
312 wl_surface_destroy(com.child[1]);
313 wl_surface_destroy(com.parent);
314
315 /* destroy: parent, child */
316 wl_surface_destroy(com.child[2]);
317
318 /* destroy: sub, child */
319 wl_surface_destroy(com.child[0]);
320
321 /* 2x destroy: child, sub */
322 wl_subsurface_destroy(com.sub[2]);
323 wl_subsurface_destroy(com.sub[1]);
324
325 client_roundtrip(client);
326}
Pekka Paalanenbeb080e2013-05-17 16:46:04 +0300327
328static void
329create_subsurface_tree(struct client *client, struct wl_surface **surfs,
330 struct wl_subsurface **subs, int n)
331{
332 struct wl_subcompositor *subco;
333 int i;
334
335 subco = get_subcompositor(client);
336
337 for (i = 0; i < n; i++)
338 surfs[i] = wl_compositor_create_surface(client->wl_compositor);
339
340 /*
341 * The tree of sub-surfaces:
342 * 0
343 * / \
344 * 1 2 - 10
345 * / \ |\
346 * 3 5 9 6
347 * / / \
348 * 4 7 8
349 * Surface 0 has no wl_subsurface, others do.
350 */
351
352 switch (n) {
353 default:
354 assert(0);
355 break;
356
357#define SUB_LINK(s,p) \
358 subs[s] = wl_subcompositor_get_subsurface(subco, surfs[s], surfs[p])
359
360 case 11:
361 SUB_LINK(10, 2);
362 case 10:
363 SUB_LINK(9, 2);
364 case 9:
365 SUB_LINK(8, 6);
366 case 8:
367 SUB_LINK(7, 6);
368 case 7:
369 SUB_LINK(6, 2);
370 case 6:
371 SUB_LINK(5, 1);
372 case 5:
373 SUB_LINK(4, 3);
374 case 4:
375 SUB_LINK(3, 1);
376 case 3:
377 SUB_LINK(2, 0);
378 case 2:
379 SUB_LINK(1, 0);
380
381#undef SUB_LINK
382 };
383}
384
385static void
386destroy_subsurface_tree(struct wl_surface **surfs,
387 struct wl_subsurface **subs, int n)
388{
389 int i;
390
391 for (i = n; i-- > 0; ) {
392 if (surfs[i])
393 wl_surface_destroy(surfs[i]);
394
395 if (subs[i])
396 wl_subsurface_destroy(subs[i]);
397 }
398}
399
400static int
401has_dupe(int *cnt, int n)
402{
403 int i;
404
405 for (i = 0; i < n; i++)
406 if (cnt[i] == cnt[n])
407 return 1;
408
409 return 0;
410}
411
412/* Note: number of permutations to test is: set_size! / (set_size - NSTEPS)!
413 */
414#define NSTEPS 3
415
416struct permu_state {
417 int set_size;
418 int cnt[NSTEPS];
419};
420
421static void
422permu_init(struct permu_state *s, int set_size)
423{
424 int i;
425
426 s->set_size = set_size;
427 for (i = 0; i < NSTEPS; i++)
428 s->cnt[i] = 0;
429}
430
431static int
432permu_next(struct permu_state *s)
433{
434 int k;
435
436 s->cnt[NSTEPS - 1]++;
437
438 while (1) {
439 if (s->cnt[0] >= s->set_size) {
440 return -1;
441 }
442
443 for (k = 1; k < NSTEPS; k++) {
444 if (s->cnt[k] >= s->set_size) {
445 s->cnt[k - 1]++;
446 s->cnt[k] = 0;
447 break;
448 }
449
450 if (has_dupe(s->cnt, k)) {
451 s->cnt[k]++;
452 break;
453 }
454 }
455
456 if (k == NSTEPS)
457 return 0;
458 }
459}
460
461static void
462destroy_permu_object(struct wl_surface **surfs,
463 struct wl_subsurface **subs, int i)
464{
465 int h = (i + 1) / 2;
466
467 if (i & 1) {
468 fprintf(stderr, " [sub %2d]", h);
469 wl_subsurface_destroy(subs[h]);
470 subs[h] = NULL;
471 } else {
472 fprintf(stderr, " [surf %2d]", h);
473 wl_surface_destroy(surfs[h]);
474 surfs[h] = NULL;
475 }
476}
477
478TEST(test_subsurface_destroy_permutations)
479{
480 /*
481 * Test wl_surface and wl_subsurface destruction orders in a
482 * complex tree of sub-surfaces.
483 *
484 * In the tree of sub-surfaces, go through every possible
485 * permutation of destroying all wl_surface and wl_subsurface
486 * objects. Execpt, to limit running time to a reasonable level,
487 * execute only the first NSTEPS destructions from each
488 * permutation, and ignore identical cases.
489 */
490
491 const int test_size = 11;
492 struct client *client;
493 struct wl_surface *surfs[test_size];
494 struct wl_subsurface *subs[test_size];
495 struct permu_state per;
496 int counter = 0;
497 int i;
498
499 client = client_create(100, 50, 123, 77);
500 assert(client);
501
502 permu_init(&per, test_size * 2 - 1);
503 while (permu_next(&per) != -1) {
504 /* for each permutation of NSTEPS out of test_size */
505 memset(surfs, 0, sizeof surfs);
506 memset(subs, 0, sizeof subs);
507
508 create_subsurface_tree(client, surfs, subs, test_size);
509
510 fprintf(stderr, "permu");
511
512 for (i = 0; i < NSTEPS; i++)
513 fprintf(stderr, " %2d", per.cnt[i]);
514
515 for (i = 0; i < NSTEPS; i++)
516 destroy_permu_object(surfs, subs, per.cnt[i]);
517
518 fprintf(stderr, "\n");
519 client_roundtrip(client);
520
521 destroy_subsurface_tree(surfs, subs, test_size);
522 counter++;
523 }
524
525 client_roundtrip(client);
526 fprintf(stderr, "tried %d destroy permutations\n", counter);
527}