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