example: add an executable 'tinyds-tdm-libinput' and handle ds_seat
[platform/core/uifw/libds-tizen.git] / src / clients / simple-tbm.c
1 /*
2  * Copyright © 2011 Benjamin Franzke
3  * Copyright © 2010 Intel Corporation
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  */
24
25 #include <stdint.h>
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 #include <errno.h>
35
36 #include <wayland-client.h>
37 #include <wayland-tbm-client.h>
38 #include <tbm_surface.h>
39 #include <tbm_surface_internal.h>
40 #include "xdg-shell-client-protocol.h"
41
42 static uint64_t buffer_info_key;
43 #define BUFFER_INFO_KEY (unsigned long)(&buffer_info_key)
44
45 struct display {
46         struct wl_display *display;
47         struct wl_registry *registry;
48         struct wl_compositor *compositor;
49         struct xdg_wm_base *wm_base;
50         struct wl_shm *shm;
51         struct wl_seat *seat;
52     struct wayland_tbm_client *wl_tbm;
53         bool has_xrgb;
54 };
55
56 struct window {
57         struct display *display;
58         int width, height;
59         struct wl_surface *surface;
60         struct xdg_surface *xdg_surface;
61         struct xdg_toplevel *xdg_toplevel;
62         struct wl_callback *callback;
63     tbm_surface_queue_h surface_queue;
64         bool wait_for_configure;
65 };
66
67 struct buffer_info {
68     struct window *window;
69     struct wl_buffer *wl_buffer;
70 };
71
72 static int running = 1;
73
74 static void
75 redraw(void *data, struct wl_callback *callback, uint32_t time);
76
77 static void
78 handle_xdg_surface_configure(void *data, struct xdg_surface *surface,
79                              uint32_t serial)
80 {
81         struct window *window = data;
82
83         xdg_surface_ack_configure(surface, serial);
84
85         if (window->wait_for_configure) {
86                 redraw(window, NULL, 0);
87                 window->wait_for_configure = false;
88         }
89 }
90
91 static const struct xdg_surface_listener xdg_surface_listener = {
92         handle_xdg_surface_configure,
93 };
94
95 static void
96 handle_xdg_toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel,
97                               int32_t width, int32_t height,
98                               struct wl_array *state)
99 {
100 }
101
102 static void
103 handle_xdg_toplevel_close(void *data, struct xdg_toplevel *xdg_toplevel)
104 {
105         running = 0;
106 }
107
108 static const struct xdg_toplevel_listener xdg_toplevel_listener = {
109         handle_xdg_toplevel_configure,
110         handle_xdg_toplevel_close,
111 };
112
113 static struct window *
114 create_window(struct display *display, int width, int height)
115 {
116         struct window *window;
117
118         window = calloc(1, sizeof *window);
119         if (!window)
120                 return NULL;
121
122         window->callback = NULL;
123         window->display = display;
124         window->width = width;
125         window->height = height;
126         window->surface = wl_compositor_create_surface(display->compositor);
127
128         if (display->wm_base) {
129                 window->xdg_surface =
130                         xdg_wm_base_get_xdg_surface(display->wm_base,
131                                                     window->surface);
132                 assert(window->xdg_surface);
133                 xdg_surface_add_listener(window->xdg_surface,
134                                          &xdg_surface_listener, window);
135
136                 window->xdg_toplevel =
137                         xdg_surface_get_toplevel(window->xdg_surface);
138                 assert(window->xdg_toplevel);
139                 xdg_toplevel_add_listener(window->xdg_toplevel,
140                                           &xdg_toplevel_listener, window);
141
142                 xdg_toplevel_set_title(window->xdg_toplevel, "simple-tbm");
143                 wl_surface_commit(window->surface);
144                 window->wait_for_configure = true;
145         } else {
146                 assert(0);
147         }
148
149     window->surface_queue =
150         wayland_tbm_client_create_surface_queue(display->wl_tbm,
151                 window->surface,
152                 3,
153                 width,
154                 height,
155                 TBM_FORMAT_XRGB8888);
156     assert(window->surface_queue);
157
158         return window;
159 }
160
161 static void
162 destroy_window(struct window *window)
163 {
164     tbm_surface_queue_destroy(window->surface_queue);
165
166         if (window->callback)
167                 wl_callback_destroy(window->callback);
168
169         if (window->xdg_toplevel)
170                 xdg_toplevel_destroy(window->xdg_toplevel);
171         if (window->xdg_surface)
172                 xdg_surface_destroy(window->xdg_surface);
173         wl_surface_destroy(window->surface);
174         free(window);
175 }
176
177 static void
178 paint_pixels(void *image, int padding, int width, int height, uint32_t time)
179 {
180         const int halfh = padding + (height - padding * 2) / 2;
181         const int halfw = padding + (width  - padding * 2) / 2;
182         int ir, or;
183         uint32_t *pixel = image;
184         int y;
185
186         /* squared radii thresholds */
187         or = (halfw < halfh ? halfw : halfh) - 8;
188         ir = or - 32;
189         or *= or;
190         ir *= ir;
191
192         pixel += padding * width;
193         for (y = padding; y < height - padding; y++) {
194                 int x;
195                 int y2 = (y - halfh) * (y - halfh);
196
197                 pixel += padding;
198                 for (x = padding; x < width - padding; x++) {
199                         uint32_t v;
200
201                         /* squared distance from center */
202                         int r2 = (x - halfw) * (x - halfw) + y2;
203
204                         if (r2 < ir)
205                                 v = (r2 / 32 + time / 64) * 0x0080401;
206                         else if (r2 < or)
207                                 v = (y + time / 32) * 0x0080401;
208                         else
209                                 v = (x + time / 16) * 0x0080401;
210                         v &= 0x00ffffff;
211
212                         /* cross if compositor uses X from XRGB as alpha */
213                         if (abs(x - y) > 6 && abs(x + y - height) > 6)
214                                 v |= 0xff000000;
215
216                         *pixel++ = v;
217                 }
218
219                 pixel += padding;
220         }
221 }
222
223 static void
224 buffer_info_free_cb(void *data)
225 {
226     struct buffer_info *buffer_info = data;
227
228     if (!buffer_info)
229         return;
230
231     wayland_tbm_client_destroy_buffer(buffer_info->window->display->wl_tbm,
232             buffer_info->wl_buffer);
233     free(buffer_info);
234 }
235
236 static void
237 buffer_handle_release(void *data, struct wl_buffer *wl_buffer)
238 {
239     tbm_surface_h surface = data;
240     struct buffer_info *buffer_info;
241
242     tbm_surface_internal_get_user_data(surface, BUFFER_INFO_KEY,
243             (void **)&buffer_info);
244     if (buffer_info)
245         tbm_surface_queue_release(buffer_info->window->surface_queue, surface);
246 }
247
248 static const struct wl_buffer_listener buffer_listener = {
249     .release = buffer_handle_release,
250 };
251
252 static const struct wl_callback_listener frame_listener;
253
254 static void
255 redraw(void *data, struct wl_callback *callback, uint32_t time)
256 {
257         struct window *window = data;
258     struct buffer_info *buffer_info = NULL;
259     tbm_surface_h surface = NULL;
260     tbm_surface_info_s surface_info;
261
262     if (!tbm_surface_queue_can_dequeue(window->surface_queue, 0))
263         return;
264
265     tbm_surface_queue_dequeue(window->surface_queue, &surface);
266     assert(surface);
267
268     tbm_surface_internal_get_user_data(surface, BUFFER_INFO_KEY,
269             (void **)&buffer_info);
270     if (!buffer_info) {
271         buffer_info = calloc(1, sizeof *buffer_info);
272         assert(buffer_info);
273
274         tbm_surface_internal_add_user_data(surface, BUFFER_INFO_KEY, buffer_info_free_cb);
275         tbm_surface_internal_set_user_data(surface, BUFFER_INFO_KEY, buffer_info);
276
277         buffer_info->wl_buffer =
278             wayland_tbm_client_create_buffer(window->display->wl_tbm, surface);
279         assert(buffer_info->wl_buffer);
280
281         wl_buffer_add_listener(buffer_info->wl_buffer, &buffer_listener,
282                 surface);
283
284         buffer_info->window = window;
285     }
286
287     tbm_surface_map(surface, TBM_SURF_OPTION_WRITE, &surface_info);
288
289         paint_pixels(surface_info.planes[0].ptr, 20,
290             (surface_info.planes[0].stride/4), surface_info.height, time);
291
292     tbm_surface_unmap(surface);
293
294         wl_surface_attach(window->surface, buffer_info->wl_buffer, 0, 0);
295         wl_surface_damage(window->surface,
296                           20, 20, window->width - 40, window->height - 40);
297
298         if (callback)
299                 wl_callback_destroy(callback);
300
301         window->callback = wl_surface_frame(window->surface);
302         wl_callback_add_listener(window->callback, &frame_listener, window);
303         wl_surface_commit(window->surface);
304 }
305
306 static const struct wl_callback_listener frame_listener = {
307         redraw
308 };
309
310 static void
311 shm_format(void *data, struct wl_shm *wl_shm, uint32_t format)
312 {
313         struct display *d = data;
314
315         if (format == WL_SHM_FORMAT_XRGB8888)
316                 d->has_xrgb = true;
317 }
318
319 struct wl_shm_listener shm_listener = {
320         shm_format
321 };
322
323 static void
324 xdg_wm_base_ping(void *data, struct xdg_wm_base *shell, uint32_t serial)
325 {
326         xdg_wm_base_pong(shell, serial);
327 }
328
329 static const struct xdg_wm_base_listener xdg_wm_base_listener = {
330         xdg_wm_base_ping,
331 };
332
333 static void pointer_handle_button(void *data, struct wl_pointer *pointer,
334         uint32_t serial, uint32_t time, uint32_t button, uint32_t state)
335 {
336     if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
337         fprintf(stderr, "pointer_handle_button: PRESSED\n");
338     }
339     else {
340         fprintf(stderr, "pointer_handle_button: RELEASED\n");
341     }
342 }
343
344 static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer,
345         uint32_t serial, struct wl_surface *surface,
346         wl_fixed_t surface_x, wl_fixed_t surface_y)
347 {
348     fprintf(stderr, "pointer_handle_enter surface_x:%d, surface_y:%d\n",
349             wl_fixed_to_int(surface_x), wl_fixed_to_int(surface_y));
350 }
351
352 static void pointer_handle_leave(void *data, struct wl_pointer *wl_pointer,
353         uint32_t serial, struct wl_surface *surface)
354 {
355     fprintf(stderr, "pointer_handle_leave\n");
356 }
357
358 static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer,
359         uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y)
360 {
361     fprintf(stderr, "pointer_handle_motion surface_x:%d, surface_y:%d\n",
362             wl_fixed_to_int(surface_x), wl_fixed_to_int(surface_y));
363 }
364
365 static void pointer_handle_frame(void *data, struct wl_pointer *wl_pointer)
366 {
367     fprintf(stderr, "pointer_handle_frame\n");
368 }
369
370 static struct wl_pointer_listener pointer_listener = {
371     .enter = pointer_handle_enter,
372     .leave = pointer_handle_leave,
373     .motion = pointer_handle_motion,
374     .button = pointer_handle_button,
375     .axis = NULL,
376     .frame = pointer_handle_frame,
377     .axis_source = NULL,
378     .axis_stop = NULL,
379     .axis_discrete = NULL,
380 };
381
382 static void touch_handle_down(void *data, struct wl_touch *wl_touch,
383         uint32_t serial, uint32_t time, struct wl_surface *surface,
384         int32_t id, wl_fixed_t x, wl_fixed_t y)
385 {
386     fprintf(stderr, "touch_handle_down id:%d, x:%d, y:%d\n",
387             id, wl_fixed_to_int(x), wl_fixed_to_int(y));
388 }
389
390 static void touch_handle_up(void *data, struct wl_touch *wl_touch,
391         uint32_t serial, uint32_t time, int32_t id)
392 {
393     fprintf(stderr, "touch_handle_up id:%d\n", id);
394 }
395
396 static void touch_handle_motion(void *data, struct wl_touch *wl_touch,
397         uint32_t time, int32_t id, wl_fixed_t x, wl_fixed_t y)
398 {
399     fprintf(stderr, "touch_handle_motion id:%d, x:%d, y:%d\n",
400             id, wl_fixed_to_int(x), wl_fixed_to_int(y));
401 }
402
403 static void touch_handle_frame(void *data, struct wl_touch *wl_touch)
404 {
405     fprintf(stderr, "touch_handle_frame\n");
406 }
407
408 static struct wl_touch_listener touch_listener = {
409     .down = touch_handle_down,
410     .up = touch_handle_up,
411     .motion = touch_handle_motion,
412     .frame = touch_handle_frame,
413     .cancel = NULL,
414     .shape = NULL,
415     .orientation = NULL,
416 };
417
418 static void keyboard_handle_keymap(void *data, struct wl_keyboard *wl_keyboard,
419         uint32_t format, int32_t fd, uint32_t size)
420 {
421     fprintf(stderr, "keyboard_handle_keymap\n");
422 }
423 static void keyboard_handle_enter(void *data, struct wl_keyboard *wl_keyboard,
424         uint32_t serial, struct wl_surface *surface, struct wl_array *keys)
425 {
426     fprintf(stderr, "keyboard_handle_enter\n");
427 }
428 static void keyboard_handle_leave(void *data, struct wl_keyboard *wl_keyboard,
429         uint32_t serial, struct wl_surface *surface)
430 {
431     fprintf(stderr, "keyboard_handle_leave\n");
432 }
433 static void keyboard_handle_modifiers(void *data, struct wl_keyboard *wl_keyboard,
434         uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched,
435         uint32_t mods_locked, uint32_t group)
436 {
437     fprintf(stderr, "keyboard_handle_modifiers\n");
438 }
439 static void keyboard_handle_repeat_info(void *data, struct wl_keyboard *wl_keyboard,
440         int32_t rate, int32_t delay)
441 {
442     fprintf(stderr, "keyboard_handle_repeat_info\n");
443 }
444
445 static void keyboard_handle_key(void *data, struct wl_keyboard *wl_keyboard,
446         uint32_t serial, uint32_t time, uint32_t key, uint32_t state)
447 {
448     if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
449         fprintf(stderr, "keyboard_handle_key: PRESSED\n");
450     } else {
451         fprintf(stderr, "keyboard_handle_key: RELEASED\n");
452     }
453 }
454
455 static struct wl_keyboard_listener keyboard_listener = {
456     .keymap = keyboard_handle_keymap,
457     .enter = keyboard_handle_enter,
458     .leave = keyboard_handle_leave,
459     .key = keyboard_handle_key,
460     .modifiers = keyboard_handle_modifiers,
461     .repeat_info = keyboard_handle_repeat_info,
462 };
463
464 static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
465         enum wl_seat_capability caps)
466 {
467     if ((caps & WL_SEAT_CAPABILITY_KEYBOARD)) {
468         struct wl_keyboard *keyboard = wl_seat_get_keyboard(wl_seat);
469         wl_keyboard_add_listener(keyboard, &keyboard_listener, NULL);
470         fprintf(stderr, "seat_handle_capabilities: keyboard\n");
471     }
472     if ((caps & WL_SEAT_CAPABILITY_POINTER)) {
473         struct wl_pointer *pointer = wl_seat_get_pointer(wl_seat);
474         wl_pointer_add_listener(pointer, &pointer_listener, NULL);
475         fprintf(stderr, "seat_handle_capabilities: pointer\n");
476     }
477     if ((caps & WL_SEAT_CAPABILITY_TOUCH)) {
478         struct wl_touch *touch = wl_seat_get_touch(wl_seat);
479         wl_touch_add_listener(touch, &touch_listener, NULL);
480         fprintf(stderr, "seat_handle_capabilities: touch\n");
481     }
482 }
483
484 static void seat_handle_name(void *data, struct wl_seat *wl_seat,
485         const char *name)
486 {
487     fprintf(stderr, "seat_handle_name name:%s\n", name);
488 }
489
490 const struct wl_seat_listener seat_listener = {
491     .capabilities = seat_handle_capabilities,
492     .name = seat_handle_name,
493 };
494
495 static void
496 registry_handle_global(void *data, struct wl_registry *registry,
497                        uint32_t id, const char *interface, uint32_t version)
498 {
499         struct display *d = data;
500
501         if (strcmp(interface, "wl_compositor") == 0) {
502                 d->compositor =
503                         wl_registry_bind(registry,
504                                          id, &wl_compositor_interface, 1);
505         } else if (strcmp(interface, "xdg_wm_base") == 0) {
506                 d->wm_base = wl_registry_bind(registry,
507                                               id, &xdg_wm_base_interface, 1);
508                 xdg_wm_base_add_listener(d->wm_base, &xdg_wm_base_listener, d);
509         } else if (strcmp(interface, "wl_shm") == 0) {
510                 d->shm = wl_registry_bind(registry,
511                                           id, &wl_shm_interface, 1);
512                 wl_shm_add_listener(d->shm, &shm_listener, d);
513         } else if (strcmp(interface, "wl_seat") == 0) {
514                 d->seat = wl_registry_bind(registry,
515                                           id, &wl_seat_interface, 7);
516                 wl_seat_add_listener(d->seat, &seat_listener, d);
517                 fprintf(stderr, "wl_seat bound!\n");
518         }
519 }
520
521 static void
522 registry_handle_global_remove(void *data, struct wl_registry *registry,
523                               uint32_t name)
524 {
525 }
526
527 static const struct wl_registry_listener registry_listener = {
528         registry_handle_global,
529         registry_handle_global_remove
530 };
531
532 static struct display *
533 create_display(void)
534 {
535         struct display *display;
536
537         display = calloc(1, sizeof *display);
538         if (display == NULL) {
539                 fprintf(stderr, "out of memory\n");
540                 exit(1);
541         }
542         display->display = wl_display_connect(NULL);
543         assert(display->display);
544
545         display->has_xrgb = false;
546         display->registry = wl_display_get_registry(display->display);
547         wl_registry_add_listener(display->registry,
548                                  &registry_listener, display);
549         wl_display_roundtrip(display->display);
550         if (display->shm == NULL) {
551                 fprintf(stderr, "No wl_shm global\n");
552                 exit(1);
553         }
554
555         wl_display_roundtrip(display->display);
556
557         /*
558          * Why do we need two roundtrips here?
559          *
560          * wl_display_get_registry() sends a request to the server, to which
561          * the server replies by emitting the wl_registry.global events.
562          * The first wl_display_roundtrip() sends wl_display.sync. The server
563          * first processes the wl_display.get_registry which includes sending
564          * the global events, and then processes the sync. Therefore when the
565          * sync (roundtrip) returns, we are guaranteed to have received and
566          * processed all the global events.
567          *
568          * While we are inside the first wl_display_roundtrip(), incoming
569          * events are dispatched, which causes registry_handle_global() to
570          * be called for each global. One of these globals is wl_shm.
571          * registry_handle_global() sends wl_registry.bind request for the
572          * wl_shm global. However, wl_registry.bind request is sent after
573          * the first wl_display.sync, so the reply to the sync comes before
574          * the initial events of the wl_shm object.
575          *
576          * The initial events that get sent as a reply to binding to wl_shm
577          * include wl_shm.format. These tell us which pixel formats are
578          * supported, and we need them before we can create buffers. They
579          * don't change at runtime, so we receive them as part of init.
580          *
581          * When the reply to the first sync comes, the server may or may not
582          * have sent the initial wl_shm events. Therefore we need the second
583          * wl_display_roundtrip() call here.
584          *
585          * The server processes the wl_registry.bind for wl_shm first, and
586          * the second wl_display.sync next. During our second call to
587          * wl_display_roundtrip() the initial wl_shm events are received and
588          * processed. Finally, when the reply to the second wl_display.sync
589          * arrives, it guarantees we have processed all wl_shm initial events.
590          *
591          * This sequence contains two examples on how wl_display_roundtrip()
592          * can be used to guarantee, that all reply events to a request
593          * have been received and processed. This is a general Wayland
594          * technique.
595          */
596
597         if (!display->has_xrgb) {
598                 fprintf(stderr, "WL_SHM_FORMAT_XRGB32 not available\n");
599                 exit(1);
600         }
601
602     display->wl_tbm = wayland_tbm_client_init(display->display);
603     if (!display->wl_tbm) {
604         fprintf(stderr, "failed wayland_tbm_client_init()\n");
605         exit(1);
606     }
607
608         return display;
609 }
610
611 static void
612 destroy_display(struct display *display)
613 {
614         if (display->shm)
615                 wl_shm_destroy(display->shm);
616
617         if (display->wm_base)
618                 xdg_wm_base_destroy(display->wm_base);
619
620         if (display->compositor)
621                 wl_compositor_destroy(display->compositor);
622
623     wayland_tbm_client_deinit(display->wl_tbm);
624         wl_registry_destroy(display->registry);
625         wl_display_flush(display->display);
626         wl_display_disconnect(display->display);
627         free(display);
628 }
629
630 static void
631 signal_int(int signum)
632 {
633         running = 0;
634 }
635
636 int
637 main(int argc, char **argv)
638 {
639         struct sigaction sigint;
640         struct display *display;
641         struct window *window;
642         int ret = 0;
643
644         display = create_display();
645         window = create_window(display, 250, 250);
646         if (!window)
647                 return 1;
648
649         sigint.sa_handler = signal_int;
650         sigemptyset(&sigint.sa_mask);
651         sigint.sa_flags = SA_RESETHAND;
652         sigaction(SIGINT, &sigint, NULL);
653
654         /* Initialise damage to full surface, so the padding gets painted */
655         wl_surface_damage(window->surface, 0, 0,
656                           window->width, window->height);
657
658         if (!window->wait_for_configure)
659                 redraw(window, NULL, 0);
660
661         while (running && ret != -1)
662                 ret = wl_display_dispatch(display->display);
663
664         fprintf(stderr, "simple-shm exiting\n");
665
666         destroy_window(window);
667         destroy_display(display);
668
669         return 0;
670 }