WIP: Boostrapped agl-client-shell tests.
[src/agl-compositor.git] / tests / agl-client-shell-test.c
1 #include "config.h"
2
3 #include <stdint.h>
4 #include <stdio.h>
5
6 #include <libweston-test/weston-test-client-helper.h>
7 #include <libweston-test/weston-test-fixture-compositor.h>
8
9 #include "agl-shell-client-protocol.h"
10 #include "xdg-shell-client-protocol.h"
11 #include "agl-screenshooter-client-protocol.h"
12
13 #define WINDOW_WIDTH_SIZE       200
14 #define WINDOW_HEIGHT_SIZE      200
15
16 enum window_type {
17         BACKGROUND      = -1,
18         PANEL_TOP       = 0,
19         PANEL_BOTTOM    = 1,
20         PANEL_LEFT      = 2,
21         PANEL_RIGHT     = 3
22 };
23
24 pixman_color_t bg_color = {
25         .red   = 0x0000,
26         .green = 0x0000,
27         .blue  = 0xffff,
28         .alpha = 0xffff
29 };
30
31 pixman_color_t panel_top_color = {
32         .red   = 0xffff,
33         .green = 0x0000,
34         .blue  = 0x0000,
35         .alpha = 0xffff
36 };
37
38 pixman_color_t panel_bottom_color = {
39         .red   = 0x0000,
40         .green = 0xffff,
41         .blue  = 0x0000,
42         .alpha = 0xffff
43 };
44
45 struct display {
46         struct agl_shell *agl_shell;
47         struct xdg_wm_base *wm_base;
48         struct agl_screenshooter *screenshooter;
49         struct client *client;
50         struct wl_list win_list;
51         bool buffer_copy_done;
52 };
53
54 struct window {
55         struct display *display;
56         struct xdg_toplevel *xdg_toplevel;
57         struct xdg_surface *xdg_surface;
58         struct wl_surface *surface;
59         struct buffer *buffer;
60
61         bool wait_for_configure;
62
63         int width;
64         int height;
65         bool maximized;
66         bool fullscreen;
67         enum window_type w_type;
68
69         struct wl_list link;
70 };
71
72 static struct buffer *
73 agl_capture_screenshot_of_output(void *data);
74
75 static enum test_result_code
76 fixture_setup(struct weston_test_harness *harness)
77 {
78         struct compositor_setup setup;
79
80         compositor_setup_defaults(&setup);
81         setup.renderer = RENDERER_PIXMAN;
82         setup.width = 1920;
83         setup.height = 1080;
84         setup.shell = SHELL_EMBEDDED;
85         setup.extra_args = "--debug";
86
87         return weston_test_harness_execute_as_client(harness, &setup);
88 }
89
90 DECLARE_FIXTURE_SETUP(fixture_setup);
91
92 static struct window *
93 create_window(int width, int height)
94 {
95         struct window *window = calloc(1, sizeof(*window));
96
97         window->width = width;
98         window->height = height;
99
100         return window;
101 }
102
103 static struct display *
104 create_display(struct client *client, struct xdg_wm_base *wm_base,
105                struct agl_shell *agl_shell, struct agl_screenshooter *screenshooter)
106 {
107         struct display *display = calloc(1, sizeof(*display));
108
109         display->client = client;
110         display->wm_base = wm_base;
111         display->agl_shell = agl_shell;
112         display->screenshooter = screenshooter;
113
114         return display;
115 }
116
117 static void
118 xdg_wm_base_ping(void *data, struct xdg_wm_base *shell, uint32_t serial)
119 {
120         xdg_wm_base_pong(shell, serial);
121 }
122
123 static const struct xdg_wm_base_listener xdg_wm_base_listener = {
124         xdg_wm_base_ping,
125 };
126
127 static void
128 draw(struct window *window, pixman_color_t color)
129 {
130         struct client *client = window->display->client;
131
132         testlog("Creating a buffer with %dx%d\n", window->width, window->height);
133         window->buffer =
134                 create_shm_buffer_a8r8g8b8(client, window->width, window->height);
135         fill_image_with_color(window->buffer->image, &color);
136
137         wl_surface_attach(window->surface, window->buffer->proxy, 0, 0);
138         wl_surface_damage(window->surface, 0, 0, window->width, window->height);
139
140         wl_surface_commit(window->surface);
141 }
142
143 static void
144 handle_xdg_surface_configure(void *data, struct xdg_surface *surface, uint32_t serial)
145 {
146         struct window *window = data;
147         xdg_surface_ack_configure(surface, serial);
148
149         if (window->wait_for_configure) {
150                 switch (window->w_type) {
151                 case BACKGROUND:
152                         draw(window, bg_color);
153                         break;
154                 case PANEL_TOP:
155                         draw(window, panel_top_color);
156                         break;
157                 case PANEL_BOTTOM:
158                         draw(window, panel_bottom_color);
159                         break;
160                 case PANEL_LEFT:
161                 case PANEL_RIGHT:
162                         break;
163                 }
164                 window->wait_for_configure = false;
165         }
166 }
167
168 static const struct xdg_surface_listener xdg_surface_listener = {
169         handle_xdg_surface_configure,
170 };
171
172 static void
173 handle_xdg_toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel,
174                               int32_t width, int32_t height, struct wl_array *states)
175 {
176         struct window *window = data;
177         uint32_t *p;
178
179         window->fullscreen = 0;
180         window->maximized = 0;
181
182         wl_array_for_each(p, states) {
183                 uint32_t state = *p;
184                 switch (state) {
185                 case XDG_TOPLEVEL_STATE_FULLSCREEN:
186                         window->fullscreen = 1;
187                         break;
188                 case XDG_TOPLEVEL_STATE_MAXIMIZED:
189                         window->maximized = 1;
190                         break;
191                 }
192         }
193
194         if (width > 0 && height > 0) {
195                 if (!window->fullscreen && !window->maximized) {
196                         window->width = width;
197                         window->height = height;
198                 }
199                 window->width = width;
200                 window->height = height;
201         } else if (!window->fullscreen && !window->maximized) {
202                 if (width == 0)
203                         window->width = WINDOW_WIDTH_SIZE;
204                 else
205                         window->width = width;
206
207                 if (height == 0)
208                         window->height = WINDOW_HEIGHT_SIZE;
209                 else
210                         window->height = height;
211         }
212
213         /* if we've been resized set wait_for_configure to adjust the fb size
214          * in the frame callback handler, which will also clear this up */
215         if ((window->width > 0 && window->width != WINDOW_WIDTH_SIZE) &&
216             (window->height > 0 && window->height != WINDOW_HEIGHT_SIZE)) {
217                 window->wait_for_configure = true;
218         }
219 }
220
221 static void
222 handle_xdg_toplevel_close(void *data, struct xdg_toplevel *xdg_toplevel)
223 {
224 }
225
226 static const struct xdg_toplevel_listener xdg_toplevel_listener = {
227         handle_xdg_toplevel_configure,
228         handle_xdg_toplevel_close,
229 };
230
231
232 static struct window *
233 setup_agl_shell_client_bg(struct display *display)
234 {
235         struct window *window;
236         window = create_window(200, 200);
237
238         window->display = display;
239
240         xdg_wm_base_add_listener(display->wm_base, &xdg_wm_base_listener, display);
241
242         window->surface =
243                 wl_compositor_create_surface(display->client->wl_compositor);
244         window->xdg_surface =
245                 xdg_wm_base_get_xdg_surface(display->wm_base, window->surface);
246         assert(window->xdg_surface);
247
248         xdg_surface_add_listener(window->xdg_surface, &xdg_surface_listener, window);
249         window->xdg_toplevel = xdg_surface_get_toplevel(window->xdg_surface);
250         assert(window->xdg_toplevel);
251
252         xdg_toplevel_add_listener(window->xdg_toplevel, &xdg_toplevel_listener, window);
253
254         xdg_toplevel_set_title(window->xdg_toplevel, "bg");
255         xdg_toplevel_set_app_id(window->xdg_toplevel, "bg");
256
257         wl_surface_commit(window->surface);
258
259         window->wait_for_configure = true;
260
261         agl_shell_set_background(display->agl_shell, window->surface,
262                                  display->client->output->wl_output);
263
264         window->w_type = BACKGROUND;
265         return window;
266 }
267
268 static struct window *
269 setup_agl_shell_client_panel(struct display *display, enum agl_shell_edge edge)
270 {
271         struct window *window;
272         window = create_window(200, 200);
273
274         window->display = display;
275
276         xdg_wm_base_add_listener(display->wm_base,
277                                  &xdg_wm_base_listener, display);
278
279         window->surface =
280                 wl_compositor_create_surface(display->client->wl_compositor);
281         window->xdg_surface =
282                 xdg_wm_base_get_xdg_surface(display->wm_base, window->surface);
283         assert(window->xdg_surface);
284
285         xdg_surface_add_listener(window->xdg_surface,
286                                  &xdg_surface_listener, window);
287         window->xdg_toplevel = xdg_surface_get_toplevel(window->xdg_surface);
288         assert(window->xdg_toplevel);
289
290         xdg_toplevel_add_listener(window->xdg_toplevel,
291                                   &xdg_toplevel_listener, window);
292
293         switch (edge) {
294         case AGL_SHELL_EDGE_TOP:
295                 xdg_toplevel_set_title(window->xdg_toplevel, "panel top");
296                 xdg_toplevel_set_app_id(window->xdg_toplevel, "panel top");
297                 break;
298         case AGL_SHELL_EDGE_BOTTOM:
299                 xdg_toplevel_set_title(window->xdg_toplevel, "panel bottom");
300                 xdg_toplevel_set_app_id(window->xdg_toplevel, "panel bottom");
301                 break;
302         case AGL_SHELL_EDGE_LEFT:
303         case AGL_SHELL_EDGE_RIGHT:
304                 break;
305         }
306
307         wl_surface_commit(window->surface);
308
309         window->wait_for_configure = true;
310
311         agl_shell_set_panel(display->agl_shell, window->surface,
312                             display->client->output->wl_output, edge);
313
314         window->w_type = (enum window_type) edge;
315         return window;
316 }
317
318 static void
319 screenshot_done(void *data, struct agl_screenshooter *screenshooter, uint32_t status)
320 {
321         struct display *display = data;
322         display->buffer_copy_done = true;
323 }
324
325 static const struct agl_screenshooter_listener screenshooter_listener = {
326         screenshot_done
327 };
328
329 static struct buffer *
330 agl_capture_screenshot_of_output(void *data)
331 {
332         struct display *display = data;
333         struct client *client = display->client;
334         struct buffer *buffer;
335
336         buffer = create_shm_buffer_a8r8g8b8(client,
337                                             client->output->width,
338                                             client->output->height);
339
340         display->buffer_copy_done = false;
341         agl_screenshooter_take_shot(display->screenshooter,
342                                     client->output->wl_output,
343                                     buffer->proxy);
344
345         while (display->buffer_copy_done == false)
346                 assert(wl_display_dispatch(client->wl_display) >= 0);
347
348         return buffer;
349 }
350
351 static struct display *
352 setup_agl_shell_client(struct client *client)
353 {
354         struct display *display;
355         struct agl_shell *agl_shell;
356         struct xdg_wm_base *wm_base;
357         struct agl_screenshooter *screenshooter;
358
359         setenv("WESTON_TEST_REFERENCE_PATH", "../tests/reference", 1);
360         wm_base = bind_to_singleton_global(client, &xdg_wm_base_interface, 1);
361         assert(wm_base);
362
363         agl_shell = bind_to_singleton_global(client, &agl_shell_interface, 1);
364         assert(agl_shell);
365
366         screenshooter = bind_to_singleton_global(client, &agl_screenshooter_interface, 1);
367         assert(screenshooter);
368
369         display = create_display(client, wm_base, agl_shell, screenshooter);
370         wl_list_init(&display->win_list);
371
372         client_set_screenshoot(client, agl_capture_screenshot_of_output, display);
373         agl_screenshooter_add_listener(screenshooter, &screenshooter_listener, display);
374
375         struct window *win_bg = setup_agl_shell_client_bg(display);
376         wl_list_insert(&display->win_list, &win_bg->link);
377
378         struct window *win_panel_top =
379                 setup_agl_shell_client_panel(display, AGL_SHELL_EDGE_TOP);
380         wl_list_insert(&display->win_list, &win_panel_top->link);
381
382         struct window *win_panel_bottom =
383                 setup_agl_shell_client_panel(display, AGL_SHELL_EDGE_BOTTOM);
384         wl_list_insert(&display->win_list, &win_panel_bottom->link);
385
386         client_roundtrip(client);
387
388         /* send ready() */
389         agl_shell_ready(agl_shell);
390         return display;
391 }
392
393 static void
394 display_destroy(struct display *display)
395 {
396         struct window *win, *win_next;
397
398         wl_list_for_each_safe(win, win_next, &display->win_list, link) {
399                 wl_list_remove(&win->link);
400                 free(win);
401         }
402 }
403
404 TEST(agl_client_shell)
405 {
406         struct display *display;
407         struct client *client = create_client();
408         bool match;
409
410         assert(client);
411
412         /* Create the client */
413         testlog("Creating client shell for agl-shell\n");
414         display = setup_agl_shell_client(client);
415
416         client_roundtrip(client);
417
418         /* take a screenshot and compare it with reference ->
419          * agl-shell client shell works */
420         match = verify_screen_content(client, "agl_client_shell", 0, NULL, 0);
421         assert(match);
422
423         client_destroy(client);
424         display_destroy(display);
425 }