nested: Remove the surface from the surface list when destroyed
[profile/ivi/weston-ivi-shell.git] / clients / simple-shm.c
1 /*
2  * Copyright © 2011 Benjamin Franzke
3  * Copyright © 2010 Intel Corporation
4  *
5  * Permission to use, copy, modify, distribute, and sell this software and its
6  * documentation for any purpose is hereby granted without fee, provided that
7  * the above copyright notice appear in all copies and that both that copyright
8  * notice and this permission notice appear in supporting documentation, and
9  * that the name of the copyright holders not be used in advertising or
10  * publicity pertaining to distribution of the software without specific,
11  * written prior permission.  The copyright holders make no representations
12  * about the suitability of this software for any purpose.  It is provided "as
13  * is" without express or implied warranty.
14  *
15  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
21  * OF THIS SOFTWARE.
22  */
23
24 #include <config.h>
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <stdbool.h>
30 #include <assert.h>
31 #include <unistd.h>
32 #include <sys/mman.h>
33 #include <signal.h>
34
35 #include <wayland-client.h>
36 #include "../shared/os-compatibility.h"
37
38 struct display {
39         struct wl_display *display;
40         struct wl_registry *registry;
41         struct wl_compositor *compositor;
42         struct wl_shell *shell;
43         struct wl_shm *shm;
44         uint32_t formats;
45 };
46
47 struct buffer {
48         struct wl_buffer *buffer;
49         void *shm_data;
50         int busy;
51 };
52
53 struct window {
54         struct display *display;
55         int width, height;
56         struct wl_surface *surface;
57         struct wl_shell_surface *shell_surface;
58         struct buffer buffers[2];
59         struct buffer *prev_buffer;
60         struct wl_callback *callback;
61 };
62
63 static void
64 buffer_release(void *data, struct wl_buffer *buffer)
65 {
66         struct buffer *mybuf = data;
67
68         mybuf->busy = 0;
69 }
70
71 static const struct wl_buffer_listener buffer_listener = {
72         buffer_release
73 };
74
75 static int
76 create_shm_buffer(struct display *display, struct buffer *buffer,
77                   int width, int height, uint32_t format)
78 {
79         struct wl_shm_pool *pool;
80         int fd, size, stride;
81         void *data;
82
83         stride = width * 4;
84         size = stride * height;
85
86         fd = os_create_anonymous_file(size);
87         if (fd < 0) {
88                 fprintf(stderr, "creating a buffer file for %d B failed: %m\n",
89                         size);
90                 return -1;
91         }
92
93         data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
94         if (data == MAP_FAILED) {
95                 fprintf(stderr, "mmap failed: %m\n");
96                 close(fd);
97                 return -1;
98         }
99
100         pool = wl_shm_create_pool(display->shm, fd, size);
101         buffer->buffer = wl_shm_pool_create_buffer(pool, 0,
102                                                    width, height,
103                                                    stride, format);
104         wl_buffer_add_listener(buffer->buffer, &buffer_listener, buffer);
105         wl_shm_pool_destroy(pool);
106         close(fd);
107
108         buffer->shm_data = data;
109
110         return 0;
111 }
112
113 static void
114 handle_ping(void *data, struct wl_shell_surface *shell_surface,
115                                                         uint32_t serial)
116 {
117         wl_shell_surface_pong(shell_surface, serial);
118 }
119
120 static void
121 handle_configure(void *data, struct wl_shell_surface *shell_surface,
122                  uint32_t edges, int32_t width, int32_t height)
123 {
124 }
125
126 static void
127 handle_popup_done(void *data, struct wl_shell_surface *shell_surface)
128 {
129 }
130
131 static const struct wl_shell_surface_listener shell_surface_listener = {
132         handle_ping,
133         handle_configure,
134         handle_popup_done
135 };
136
137 static struct window *
138 create_window(struct display *display, int width, int height)
139 {
140         struct window *window;
141
142         window = calloc(1, sizeof *window);
143         if (!window)
144                 return NULL;
145
146         window->callback = NULL;
147         window->display = display;
148         window->width = width;
149         window->height = height;
150         window->surface = wl_compositor_create_surface(display->compositor);
151         window->shell_surface = wl_shell_get_shell_surface(display->shell,
152                                                            window->surface);
153
154         if (window->shell_surface)
155                 wl_shell_surface_add_listener(window->shell_surface,
156                                               &shell_surface_listener, window);
157
158         wl_shell_surface_set_title(window->shell_surface, "simple-shm");
159
160         wl_shell_surface_set_toplevel(window->shell_surface);
161
162         return window;
163 }
164
165 static void
166 destroy_window(struct window *window)
167 {
168         if (window->callback)
169                 wl_callback_destroy(window->callback);
170
171         if (window->buffers[0].buffer)
172                 wl_buffer_destroy(window->buffers[0].buffer);
173         if (window->buffers[1].buffer)
174                 wl_buffer_destroy(window->buffers[1].buffer);
175
176         wl_shell_surface_destroy(window->shell_surface);
177         wl_surface_destroy(window->surface);
178         free(window);
179 }
180
181 static struct buffer *
182 window_next_buffer(struct window *window)
183 {
184         struct buffer *buffer;
185         int ret = 0;
186
187         if (!window->buffers[0].busy)
188                 buffer = &window->buffers[0];
189         else if (!window->buffers[1].busy)
190                 buffer = &window->buffers[1];
191         else
192                 return NULL;
193
194         if (!buffer->buffer) {
195                 ret = create_shm_buffer(window->display, buffer,
196                                         window->width, window->height,
197                                         WL_SHM_FORMAT_XRGB8888);
198
199                 if (ret < 0)
200                         return NULL;
201
202                 /* paint the padding */
203                 memset(buffer->shm_data, 0xff,
204                        window->width * window->height * 4);
205         }
206
207         return buffer;
208 }
209
210 static void
211 paint_pixels(void *image, int padding, int width, int height, uint32_t time)
212 {
213         const int halfh = padding + (height - padding * 2) / 2;
214         const int halfw = padding + (width  - padding * 2) / 2;
215         int ir, or;
216         uint32_t *pixel = image;
217         int y;
218
219         /* squared radii thresholds */
220         or = (halfw < halfh ? halfw : halfh) - 8;
221         ir = or - 32;
222         or *= or;
223         ir *= ir;
224
225         pixel += padding * width;
226         for (y = padding; y < height - padding; y++) {
227                 int x;
228                 int y2 = (y - halfh) * (y - halfh);
229
230                 pixel += padding;
231                 for (x = padding; x < width - padding; x++) {
232                         uint32_t v;
233
234                         /* squared distance from center */
235                         int r2 = (x - halfw) * (x - halfw) + y2;
236
237                         if (r2 < ir)
238                                 v = (r2 / 32 + time / 64) * 0x0080401;
239                         else if (r2 < or)
240                                 v = (y + time / 32) * 0x0080401;
241                         else
242                                 v = (x + time / 16) * 0x0080401;
243                         v &= 0x00ffffff;
244
245                         /* cross if compositor uses X from XRGB as alpha */
246                         if (abs(x - y) > 6 && abs(x + y - height) > 6)
247                                 v |= 0xff000000;
248
249                         *pixel++ = v;
250                 }
251
252                 pixel += padding;
253         }
254 }
255
256 static const struct wl_callback_listener frame_listener;
257
258 static void
259 redraw(void *data, struct wl_callback *callback, uint32_t time)
260 {
261         struct window *window = data;
262         struct buffer *buffer;
263
264         buffer = window_next_buffer(window);
265         if (!buffer) {
266                 fprintf(stderr,
267                         !callback ? "Failed to create the first buffer.\n" :
268                         "Both buffers busy at redraw(). Server bug?\n");
269                 abort();
270         }
271
272         paint_pixels(buffer->shm_data, 20, window->width, window->height, time);
273
274         wl_surface_attach(window->surface, buffer->buffer, 0, 0);
275         wl_surface_damage(window->surface,
276                           20, 20, window->width - 40, window->height - 40);
277
278         if (callback)
279                 wl_callback_destroy(callback);
280
281         window->callback = wl_surface_frame(window->surface);
282         wl_callback_add_listener(window->callback, &frame_listener, window);
283         wl_surface_commit(window->surface);
284         buffer->busy = 1;
285 }
286
287 static const struct wl_callback_listener frame_listener = {
288         redraw
289 };
290
291 static void
292 shm_format(void *data, struct wl_shm *wl_shm, uint32_t format)
293 {
294         struct display *d = data;
295
296         d->formats |= (1 << format);
297 }
298
299 struct wl_shm_listener shm_listener = {
300         shm_format
301 };
302
303 static void
304 registry_handle_global(void *data, struct wl_registry *registry,
305                        uint32_t id, const char *interface, uint32_t version)
306 {
307         struct display *d = data;
308
309         if (strcmp(interface, "wl_compositor") == 0) {
310                 d->compositor =
311                         wl_registry_bind(registry,
312                                          id, &wl_compositor_interface, 1);
313         } else if (strcmp(interface, "wl_shell") == 0) {
314                 d->shell = wl_registry_bind(registry,
315                                             id, &wl_shell_interface, 1);
316         } else if (strcmp(interface, "wl_shm") == 0) {
317                 d->shm = wl_registry_bind(registry,
318                                           id, &wl_shm_interface, 1);
319                 wl_shm_add_listener(d->shm, &shm_listener, d);
320         }
321 }
322
323 static void
324 registry_handle_global_remove(void *data, struct wl_registry *registry,
325                               uint32_t name)
326 {
327 }
328
329 static const struct wl_registry_listener registry_listener = {
330         registry_handle_global,
331         registry_handle_global_remove
332 };
333
334 static struct display *
335 create_display(void)
336 {
337         struct display *display;
338
339         display = malloc(sizeof *display);
340         if (display == NULL) {
341                 fprintf(stderr, "out of memory\n");
342                 exit(1);
343         }
344         display->display = wl_display_connect(NULL);
345         assert(display->display);
346
347         display->formats = 0;
348         display->registry = wl_display_get_registry(display->display);
349         wl_registry_add_listener(display->registry,
350                                  &registry_listener, display);
351         wl_display_roundtrip(display->display);
352         if (display->shm == NULL) {
353                 fprintf(stderr, "No wl_shm global\n");
354                 exit(1);
355         }
356
357         wl_display_roundtrip(display->display);
358
359         if (!(display->formats & (1 << WL_SHM_FORMAT_XRGB8888))) {
360                 fprintf(stderr, "WL_SHM_FORMAT_XRGB32 not available\n");
361                 exit(1);
362         }
363
364         wl_display_get_fd(display->display);
365         
366         return display;
367 }
368
369 static void
370 destroy_display(struct display *display)
371 {
372         if (display->shm)
373                 wl_shm_destroy(display->shm);
374
375         if (display->shell)
376                 wl_shell_destroy(display->shell);
377
378         if (display->compositor)
379                 wl_compositor_destroy(display->compositor);
380
381         wl_registry_destroy(display->registry);
382         wl_display_flush(display->display);
383         wl_display_disconnect(display->display);
384         free(display);
385 }
386
387 static int running = 1;
388
389 static void
390 signal_int(int signum)
391 {
392         running = 0;
393 }
394
395 int
396 main(int argc, char **argv)
397 {
398         struct sigaction sigint;
399         struct display *display;
400         struct window *window;
401         int ret = 0;
402
403         display = create_display();
404         window = create_window(display, 250, 250);
405         if (!window)
406                 return 1;
407
408         sigint.sa_handler = signal_int;
409         sigemptyset(&sigint.sa_mask);
410         sigint.sa_flags = SA_RESETHAND;
411         sigaction(SIGINT, &sigint, NULL);
412
413         /* Initialise damage to full surface, so the padding gets painted */
414         wl_surface_damage(window->surface, 0, 0,
415                           window->width, window->height);
416
417         redraw(window, NULL, 0);
418
419         while (running && ret != -1)
420                 ret = wl_display_dispatch(display->display);
421
422         fprintf(stderr, "simple-shm exiting\n");
423         destroy_window(window);
424         destroy_display(display);
425
426         return 0;
427 }