a7428f1da5e2653ccfb0de276b9efb243b0b9815
[platform/core/uifw/libds-tizen.git] / examples / tinyds-tdm.c
1 #include <assert.h>
2 #include <stdbool.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <signal.h>
6 #include <time.h>
7
8 #include <drm_fourcc.h>
9 #include <pixman.h>
10 #include <wayland-server.h>
11 #include <libds/log.h>
12 #include <libds/backend.h>
13 #include <libds/output.h>
14 #include <libds/compositor.h>
15 #include <libds/xdg_shell.h>
16 #include <libds-tizen/allocator/tbm.h>
17 #include <libds-tizen/backend/tdm.h>
18 #include <libds/backend/libinput.h>
19 #include <libds-tizen/tbm_server.h>
20 #include <libds-tizen/dpms.h>
21 #include <libds/input_device.h>
22 #include <libds/keyboard.h>
23 #include <libds/touch.h>
24 #include <libds/pointer.h>
25 #include <libds/seat.h>
26 #include <libds-tizen/input_devicemgr.h>
27 #include <xkbcommon/xkbcommon.h>
28 #include <libds/interfaces/keyboard.h>
29 #include <libds-tizen/launch.h>
30 #include <libds-tizen/backend/tdm_output_hwc.h>
31
32 #define USE_TDM_BUFFER_QUEUE
33
34 #ifdef USE_TDM_BUFFER_QUEUE
35 #include "pixman-tbm-helper.h"
36 #include "tinyds-tdm-renderer.h"
37 #else
38 #include <libds/swapchain.h>
39 #endif
40
41 #include "pixman-helper.h"
42
43 #define TINYDS_UNUSED   __attribute__((unused))
44 struct tinyds_keyboard;
45 struct tinyds_pointer;
46
47 struct tinyds_output
48 {
49     struct tinyds_server *server;
50     struct ds_output *ds_output;
51     struct ds_allocator *allocator;
52 #ifdef USE_TDM_BUFFER_QUEUE
53     struct tinyds_renderer renderer;
54     struct ds_tdm_buffer_queue *buffer_queue;
55     struct wl_listener buffer_queue_acquirable;
56 #else
57     struct ds_swapchain *swapchain;
58 #endif
59     struct ds_buffer *front_buffer;
60
61     struct wl_listener output_destroy;
62     struct wl_listener output_frame;
63
64     int width, height;
65
66     struct wl_event_source *idle_commit;
67     bool committable;
68     bool damaged;
69     bool target_updated;
70
71     struct ds_tdm_output_hwc *hwc;
72     struct ds_tdm_output_hwc_window *bg_hwc_window;
73 };
74
75 struct tinyds_dpms
76 {
77     struct ds_tizen_dpms *ds_dpms;
78     struct tinyds_server *server;
79
80     struct wl_listener destroy;
81     struct wl_listener set_dpms;
82     struct wl_listener get_dpms;
83 };
84
85 struct tinyds_server
86 {
87     struct ds_tbm_server *tbm_server;
88
89     struct wl_display *display;
90
91     struct ds_backend *backend;
92     struct ds_backend *input_backend;
93     struct ds_compositor *compositor;
94     struct ds_xdg_shell *xdg_shell;
95     struct ds_seat *seat;
96     uint32_t seat_caps;
97     double output_x, output_y;
98     struct ds_tizen_input_devicemgr *devicemgr;
99     struct ds_tizen_launch_effect *effect;
100     struct ds_tizen_launch_splash *splash;
101
102     struct tinyds_output *output;
103     struct tinyds_dpms *dpms;
104     struct wl_event_source *stdin_source;
105
106     struct wl_list views;
107
108     struct wl_listener new_output;
109     struct wl_listener new_input;
110     struct wl_listener new_xdg_surface;
111     struct wl_listener devicemgr_destroy;
112     struct wl_listener pointer_warp;
113     struct wl_listener effect_destroy;
114     struct wl_listener effect_type_set;
115     struct wl_listener effect_type_unset;
116     struct wl_listener new_splash;
117     struct wl_listener splash_owner;
118
119     struct wl_list keyboards;
120     struct wl_list pointers;
121 };
122
123 struct tinyds_view
124 {
125     struct tinyds_server *server;
126
127     struct tinyds_texture *texture;
128     struct ds_xdg_surface *xdg_surface;
129
130     struct wl_listener xdg_surface_map;
131     struct wl_listener xdg_surface_unmap;
132     struct wl_listener xdg_surface_destroy;
133     struct wl_listener surface_commit;
134     struct wl_list link; // tinyds_server::views
135
136     struct ds_tdm_output_hwc_window *hwc_window;
137
138     int x, y;
139     bool mapped;
140
141     pid_t pid;
142     int effect_type;
143 };
144
145 struct tinyds_pointer
146 {
147     struct ds_input_device *dev;
148     struct tinyds_server *server;
149
150     struct tinyds_view *focused_view;
151
152     struct wl_listener destroy;
153     struct wl_listener motion; //relative
154     struct wl_listener button;
155     struct wl_listener frame;
156     struct wl_list link; //tinyds_server::pointers
157 };
158
159 struct tinyds_keyboard
160 {
161     struct ds_input_device *dev;
162     struct tinyds_server *server;
163
164     struct wl_listener destroy;
165     struct wl_listener key;
166     struct wl_list link; //tinyds_server::keyboards
167 };
168
169 struct tinyds_touch
170 {
171     struct ds_input_device *dev;
172     struct tinyds_server *server;
173
174     struct wl_listener destroy;
175     struct wl_listener down;
176     struct wl_listener up;
177     struct wl_listener motion;
178 };
179
180 struct tinyds_server tinyds;
181
182 static bool init_server(struct tinyds_server *server, struct wl_display *display);
183 static int server_dispatch_stdin(int fd, uint32_t mask, void *data);
184 static void output_handle_destroy(struct wl_listener *listener, void *data);
185 static void output_handle_frame(struct wl_listener *listener, void *data);
186 static void draw_server_with_damage(struct tinyds_server *server);
187 static void draw_output(struct tinyds_output *output);
188 static void output_swap_buffer(struct tinyds_output *output,
189         struct ds_buffer *buffer);
190 static void view_send_frame_done(struct tinyds_view *view);
191 static void output_hwc_init(struct tinyds_output *output);
192 static void output_schedule_commit(struct tinyds_output *output);
193 static void output_commit(struct tinyds_output *output);
194 #ifdef USE_TDM_BUFFER_QUEUE
195 static void output_buffer_queue_init(struct tinyds_output *output);
196 static void output_renderer_init(struct tinyds_output *output);
197 static void output_draw_with_renderer(struct tinyds_output *output);
198 #else
199 static void output_swapchain_init(struct tinyds_output *output,
200         int width, int height, uint32_t format);
201 static void output_draw_with_swapchain(struct tinyds_output *output);
202 static void draw_view(struct tinyds_view *view, pixman_image_t *dst_image);
203 #endif
204 static void dpms_handle_destroy(struct wl_listener *listener, void *data);
205 static void dpms_handle_set_dpms(struct wl_listener *listener, void *data);
206 static void dpms_handle_get_dpms(struct wl_listener *listener, void *data);
207 static void server_add_keyboard(struct tinyds_server *server,
208         struct ds_input_device *dev);
209 static void server_add_pointer(struct tinyds_server *server,
210         struct ds_input_device *dev);
211 static void server_add_touch(struct tinyds_server *server,
212         struct ds_input_device *dev);
213
214 static struct tinyds_view *
215 server_view_at(struct tinyds_server *server, double lx, double ly,
216         double *sx, double *sy);
217
218 int
219 main(void)
220 {
221     struct tinyds_server *server = &tinyds;
222     struct wl_display *display;
223     struct wl_event_loop *loop;
224     const char *socket;
225     bool res;
226
227     ds_log_init(DS_INF, NULL);
228
229     display = wl_display_create();
230     assert(display);
231
232     res = init_server(server, display);
233     assert(res);
234
235     socket = wl_display_add_socket_auto(display);
236     assert(socket);
237
238     ds_backend_start(server->backend);
239     ds_backend_start(server->input_backend);
240
241     setenv("WAYLAND_DISPLAY", socket, true);
242
243     ds_inf("Running Wayland compositor on WAYLAND_DISPLAY=%s", socket);
244
245     loop = wl_display_get_event_loop(display);
246     server->stdin_source = wl_event_loop_add_fd(loop, STDIN_FILENO,
247             WL_EVENT_READABLE, server_dispatch_stdin, server);
248
249     wl_display_run(display);
250
251     wl_display_destroy_clients(display);
252     wl_display_destroy(display);
253
254     return 0;
255 }
256
257 static void
258 view_populate_pid(struct tinyds_view *view)
259 {
260     pid_t pid;
261     struct wl_client *client = NULL;
262     struct ds_surface *surface;
263
264     surface = ds_xdg_surface_get_surface(view->xdg_surface);
265     if (!surface)
266         return;
267
268     client = wl_resource_get_client(ds_surface_get_wl_resource(surface));
269     if (!client)
270         return;
271
272     wl_client_get_credentials(client, &pid, NULL, NULL);
273
274     ds_inf("view pid(%u)", pid);
275     view->pid = pid;
276
277     view->effect_type = ds_tizen_launch_effect_get_effect_type(view->server->effect, pid);
278     ds_tizen_launch_effect_unset_effect_type(view->server->effect, pid);
279     ds_inf("view effect_type(%d)", view->effect_type);
280 }
281
282 static void
283 view_handle_xdg_surface_map(struct wl_listener *listener,
284         void *data TINYDS_UNUSED)
285 {
286     struct tinyds_view *view;
287     struct ds_keyboard *keyboard;
288     struct tinyds_keyboard *kbd;
289
290     view = wl_container_of(listener, view, xdg_surface_map);
291     view->mapped = true;
292
293     view_populate_pid(view);
294
295     wl_list_for_each(kbd, &view->server->keyboards, link) {
296         keyboard = ds_input_device_get_keyboard(kbd->dev);
297         if (keyboard != NULL) {
298             ds_seat_keyboard_notify_enter(view->server->seat,
299                     ds_xdg_surface_get_surface(view->xdg_surface),
300                     keyboard->keycodes, keyboard->num_keycodes,
301                     &keyboard->modifiers);
302             return;
303         }
304     }
305 }
306
307 static void
308 view_handle_xdg_surface_unmap(struct wl_listener *listener,
309         void *data TINYDS_UNUSED)
310 {
311     struct tinyds_view *view;
312
313     view = wl_container_of(listener, view, xdg_surface_unmap);
314     view->mapped = false;
315 }
316
317 static void
318 view_handle_xdg_surface_destroy(struct wl_listener *listener,
319         void *data TINYDS_UNUSED) 
320 {
321     struct tinyds_view *view;
322
323     view = wl_container_of(listener, view, xdg_surface_destroy);
324
325     draw_server_with_damage(view->server);
326
327     ds_tdm_output_hwc_window_destroy(view->hwc_window);
328
329     wl_list_remove(&view->xdg_surface_destroy.link);
330     wl_list_remove(&view->xdg_surface_map.link);
331     wl_list_remove(&view->xdg_surface_unmap.link);
332     wl_list_remove(&view->surface_commit.link);
333     wl_list_remove(&view->link);
334     free(view);
335 }
336
337 static void
338 view_handle_surface_commit(struct wl_listener *listener,
339         void *data TINYDS_UNUSED)
340 {
341     struct tinyds_view *view;
342
343     view = wl_container_of(listener, view, surface_commit);
344     draw_server_with_damage(view->server);
345 }
346
347 static void
348 server_new_xdg_surface(struct wl_listener *listener, void *data)
349 {
350     struct tinyds_server *server;
351     struct tinyds_view *view;
352     struct ds_xdg_surface *xdg_surface;
353
354     server = wl_container_of(listener, server, new_xdg_surface);
355     xdg_surface = data;
356
357     ds_inf("New xdg_surface(%p)", (void *)xdg_surface);
358
359     view = calloc(1, sizeof *view);
360     assert(view);
361
362     view->server = server;
363     view->xdg_surface = xdg_surface;
364
365     view->xdg_surface_map.notify = view_handle_xdg_surface_map;
366     ds_xdg_surface_add_map_listener(xdg_surface,
367             &view->xdg_surface_map);
368
369     view->xdg_surface_unmap.notify = view_handle_xdg_surface_unmap;
370     ds_xdg_surface_add_unmap_listener(xdg_surface,
371             &view->xdg_surface_unmap);
372
373     view->xdg_surface_destroy.notify = view_handle_xdg_surface_destroy;
374     ds_xdg_surface_add_destroy_listener(xdg_surface,
375             &view->xdg_surface_destroy);
376
377     view->surface_commit.notify = view_handle_surface_commit;
378     ds_surface_add_commit_listener(
379             ds_xdg_surface_get_surface(xdg_surface),
380             &view->surface_commit);
381
382     view->x = rand() % 1000;
383     view->y = rand() % 500;
384
385     view->hwc_window = ds_tdm_output_hwc_window_create(server->output->hwc);
386     assert(view->hwc_window);
387
388     wl_list_insert(server->views.prev, &view->link);
389
390     view->pid = 0;
391     view->effect_type = -1;
392
393     ds_inf("view at (%d, %d)", view->x, view->y);
394 }
395
396 static void
397 backend_handle_new_output(struct wl_listener *listener, void *data)
398 {
399     struct tinyds_server *server;
400     struct tinyds_output *output;
401     struct ds_output *ds_output;
402     const struct ds_output_mode *mode;
403     struct ds_tdm_box src_box;
404
405     server = wl_container_of(listener, server, new_output);
406     ds_output = data;
407
408     ds_inf("New output(%p)", ds_output);
409
410     if (server->output)
411         return;
412
413     mode = ds_output_get_preferred_mode(ds_output);
414     ds_output_set_mode(ds_output, mode);
415
416     output = calloc(1, sizeof *output);
417     if (!output)
418         return;
419
420     output->server = server;
421     output->ds_output = ds_output;
422     output->width = mode->width;
423     output->height = mode->height;
424     output->damaged = true;
425     output->committable = true;
426
427     output_hwc_init(output);
428
429 #ifdef USE_TDM_BUFFER_QUEUE
430     output_buffer_queue_init(output);
431     output_renderer_init(output);
432 #else
433     output_swapchain_init(output, mode->width, mode->height,
434             DRM_FORMAT_XRGB8888);
435 #endif
436
437     output->bg_hwc_window = ds_tdm_output_hwc_window_create(output->hwc);
438     assert(output->bg_hwc_window);
439
440     src_box.x = 0;
441     src_box.y = 0;
442     src_box.width = output->width;
443     src_box.height = output->height;
444
445     ds_tdm_output_hwc_window_set_src_box(output->bg_hwc_window, &src_box);
446     ds_tdm_output_hwc_window_set_position(output->bg_hwc_window, 0, 0);
447     ds_tdm_output_hwc_window_set_dest_size(output->bg_hwc_window, output->width, output->height);
448     ds_tdm_output_hwc_window_set_transform(output->bg_hwc_window, WL_OUTPUT_TRANSFORM_NORMAL);
449
450     output->output_destroy.notify = output_handle_destroy;
451     ds_output_add_destroy_listener(ds_output, &output->output_destroy);
452
453     output->output_frame.notify = output_handle_frame;
454     ds_output_add_frame_listener(ds_output, &output->output_frame);
455
456     ds_tizen_input_devicemgr_set_output_width_height(server->devicemgr, (uint32_t)output->width, (uint32_t)output->height);
457
458     server->output = output;
459
460     output_schedule_commit(output);
461 }
462
463 static bool
464 add_new_dpms(struct tinyds_server *server)
465 {
466     struct tinyds_dpms *dpms;
467
468     dpms = calloc(1, sizeof *dpms);
469     if (!dpms)
470         return false;
471
472     dpms->ds_dpms = ds_tizen_dpms_create(server->display);
473     if (!dpms->ds_dpms) {
474         free(dpms);
475         ds_err("Could not create ds_tizen_dpms");
476         return false;
477     }
478
479     dpms->destroy.notify = dpms_handle_destroy;
480     ds_tizen_dpms_add_destroy_listener(dpms->ds_dpms, &dpms->destroy);
481
482     dpms->set_dpms.notify = dpms_handle_set_dpms;
483     ds_tizen_dpms_add_set_dpms_listener(dpms->ds_dpms, &dpms->set_dpms);
484
485     dpms->get_dpms.notify = dpms_handle_get_dpms;
486     ds_tizen_dpms_add_get_dpms_listener(dpms->ds_dpms, &dpms->get_dpms);
487
488     server->dpms = dpms;
489
490     ds_inf("Dpms (%p) added", dpms);
491
492     return true;
493 }
494
495 static void
496 backend_handle_new_input(struct wl_listener *listener, void *data)
497 {
498     struct tinyds_server *server;
499     struct ds_input_device *dev = data;
500     enum ds_input_device_type dev_type;
501
502     server = wl_container_of(listener, server, new_input);
503
504     dev_type = ds_input_device_get_type(dev);
505
506     switch (dev_type) {
507         case DS_INPUT_DEVICE_KEYBOARD:
508             server_add_keyboard(server, dev);
509             server->seat_caps |= WL_SEAT_CAPABILITY_KEYBOARD;
510             break;
511         case DS_INPUT_DEVICE_TOUCH:
512             server_add_touch(server, dev);
513             server->seat_caps |= WL_SEAT_CAPABILITY_TOUCH;
514             break;
515         case DS_INPUT_DEVICE_POINTER:
516             server_add_pointer(server, dev);
517             server->seat_caps |= WL_SEAT_CAPABILITY_POINTER;
518             break;
519         default:
520             ds_err("Unknown type(%d) of ds_input_device", dev_type);
521             break;
522     }
523
524     ds_seat_set_capabilities(server->seat, server->seat_caps);
525 }
526
527 static void
528 devicemgr_add_keymap_data(struct wl_list *list, const char *name, int keycode)
529 {
530     struct ds_tizen_input_devicemgr_keymap_data *data;
531
532     data = calloc(1, sizeof *data);
533     if (!data) {
534         ds_err("Failed to alloc memory");
535         return;
536     }
537
538     data->name = strdup(name);
539     data->keycode = keycode;
540
541     wl_list_insert(list, &data->link);
542 }
543
544 static void
545 devicemgr_cleanup_keymap_list(struct wl_list *list)
546 {
547     struct ds_tizen_input_devicemgr_keymap_data *data, *tmp;
548
549     wl_list_for_each_safe(data, tmp, list, link) {
550         wl_list_remove(&data->link);
551         free(data->name);
552         free(data);
553     }
554 }
555
556 static void
557 devicemgr_set_keymap(struct ds_tizen_input_devicemgr *devicemgr)
558 {
559     struct wl_list keymap_list;
560     bool res;
561
562     wl_list_init(&keymap_list);
563
564     devicemgr_add_keymap_data(&keymap_list, "XF86VolumeRaise", 455);
565     devicemgr_add_keymap_data(&keymap_list, "XF86VolumeLower", 456);
566     devicemgr_add_keymap_data(&keymap_list, "XF86LightOn", 457);
567     devicemgr_add_keymap_data(&keymap_list, "XF86LightOff", 458);
568
569     res = ds_tizen_input_devicemgr_set_keymap_list(devicemgr, &keymap_list);
570     if (!res)
571         ds_inf("Failed to set keymap");
572
573     devicemgr_cleanup_keymap_list(&keymap_list);
574 }
575
576 static void
577 devicemgr_handle_pointer_warp(struct wl_listener *listener, void *data)
578 {
579     struct tinyds_server *server;
580     struct tinyds_pointer *pointer;
581     struct ds_tizen_input_devicemgr_event_pointer_warp *event = data;
582     double sx = 0.f, sy = 0.f;
583     struct tinyds_view *view = NULL;
584
585     server = wl_container_of(listener, server, pointer_warp);
586
587     ds_inf("Pointer warp: surface(%p) x(%.2f) y(%.2f)", event->surface,
588             event->x, event->y);
589
590     wl_list_for_each(pointer, &server->pointers, link){
591         if (!pointer->focused_view) continue;
592         view = pointer->focused_view;
593     }
594     if (!view) return;
595
596     if (event->surface != ds_xdg_surface_get_surface(view->xdg_surface)) {
597         ds_inf("Pointer is not on the requested surface");
598         return;
599     }
600
601     server->output_x = view->x + (event->x * server->output->width);
602     server->output_y = view->y + (event->y * server->output->height);
603
604     server_view_at(server, server->output_x, server->output_y, &sx, &sy);
605
606     ds_inf("notify motion: sx:%.2f sy:%.2f, output_x:%.1f, output_y:%.1f",
607             sx, sy, server->output_x, server->output_y);
608
609     ds_seat_pointer_notify_motion(server->seat,
610             event->time_msec, sx, sy);
611 }
612
613 static void
614 devicemgr_handle_destroy(struct wl_listener *listener, void *data TINYDS_UNUSED)
615 {
616     struct tinyds_server *server =
617         wl_container_of(listener, server, devicemgr_destroy);
618
619     wl_list_remove(&server->devicemgr_destroy.link);
620     wl_list_remove(&server->pointer_warp.link);
621
622     server->devicemgr = NULL;
623 }
624
625 static void
626 launch_effect_handle_destroy(struct wl_listener *listener, void *data TINYDS_UNUSED)
627 {
628     struct tinyds_server *server =
629         wl_container_of(listener, server, effect_destroy);
630
631     wl_list_remove(&server->effect_destroy.link);
632     wl_list_remove(&server->effect_type_set.link);
633     wl_list_remove(&server->effect_type_unset.link);
634     wl_list_remove(&server->new_splash.link);
635
636     server->effect = NULL;
637 }
638
639 static void
640 launch_effect_handle_type_set(struct wl_listener *listener, void *data)
641 {
642     struct tinyds_server *server;
643     struct ds_tizen_launch_effect_event_type_set *event = data;
644     struct tinyds_view *view = NULL;
645     bool existing = false;
646
647     server = wl_container_of(listener, server, effect_type_set);
648
649     ds_inf("Launch effect. type_set: pid(%u) type:%s", event->pid, (event->effect_type == 1) ? "depth-in" : "launch");
650
651     wl_list_for_each(view, &server->views, link) {
652         if (view->pid == event->pid) {
653             view->effect_type = event->effect_type;
654             ds_inf("Launch effect. existing pid");
655             existing = true;
656         }
657     }
658     if (existing) {
659         ds_tizen_launch_effect_unset_effect_type(server->effect, event->pid);
660     } else {
661         ds_tizen_launch_effect_set_effect_type(server->effect, event->pid, event->effect_type);
662     }
663 }
664
665 static void
666 launch_effect_handle_type_unset(struct wl_listener *listener, void *data)
667 {
668     struct tinyds_server *server;
669     struct ds_tizen_launch_effect_event_type_unset *event = data;
670     struct tinyds_view *view = NULL;
671
672     server = wl_container_of(listener, server, effect_type_unset);
673
674     ds_inf("Launch effect. type_unset: pid(%u)", event->pid);
675
676     wl_list_for_each(view, &server->views, link) {
677         if (view->pid == event->pid) {
678             view->effect_type = -1;
679             ds_inf("Launch effect. pid found");
680         }
681     }
682     ds_tizen_launch_effect_unset_effect_type(server->effect, event->pid);
683 }
684
685 static void
686 launch_splash_handle_owner(struct wl_listener *listener, void *data)
687 {
688     struct tinyds_server *server;
689     struct ds_tizen_launch_splash_event_owner *event = data;
690     struct tinyds_view *view = NULL;
691
692     server = wl_container_of(listener, server, splash_owner);
693
694     ds_inf("Splash owner. pid(%u)", event->pid);
695
696     wl_list_for_each(view, &server->views, link) {
697         if (view->pid == event->pid) {
698             if (event->pid == ds_tizen_launch_splash_get_pid(server->splash))
699                 ;//
700             else {
701                 ds_tizen_launch_splash_set_pid(server->splash, event->pid);
702             }
703         }
704     }
705 }
706
707 static void
708 launch_effect_handle_new_splash(struct wl_listener *listener, void *data)
709 {
710     struct tinyds_server *server;
711     struct ds_tizen_launch_splash *splash = data;
712     struct tinyds_view *view = NULL;
713
714     server = wl_container_of(listener, server, new_splash);
715
716     ds_inf("Launch new splash. splash(%p)", splash);
717     if (!splash) return;
718
719     server->splash = splash;
720
721     // new view for "Launchscreen"
722     view = calloc(1, sizeof *view);
723     assert(view);
724     wl_list_insert(server->views.prev, &view->link);
725     view->pid = ds_tizen_launch_splash_get_pid(splash);
726
727     server->splash_owner.notify = launch_splash_handle_owner;
728     ds_tizen_launch_splash_add_owner_listener(server->splash,
729             &server->splash_owner);
730 }
731
732 static bool
733 init_server(struct tinyds_server *server, struct wl_display *display)
734 {
735     server->display = display;
736
737     wl_list_init(&server->views);
738
739     if (wl_display_init_shm(display) != 0)
740         return false;
741
742     server->backend = ds_tdm_backend_create(display);
743     if (!server->backend)
744         return false;
745
746     server->input_backend = ds_libinput_backend_create(display);
747     if (!server->input_backend) {
748         ds_backend_destroy(server->backend);
749         return false;
750     }
751
752     server->new_output.notify = backend_handle_new_output;
753     ds_backend_add_new_output_listener(server->backend,
754             &server->new_output);
755
756     wl_list_init(&server->keyboards);
757     wl_list_init(&server->pointers);
758     server->new_input.notify = backend_handle_new_input;
759     ds_backend_add_new_input_listener(server->input_backend, &server->new_input);
760
761     server->compositor = ds_compositor_create(display);
762     if (!server->compositor)
763         goto err;
764
765     server->tbm_server = ds_tbm_server_create(display);
766     if (!server->tbm_server)
767         goto err;
768
769     server->xdg_shell = ds_xdg_shell_create(display);
770     if (!server->xdg_shell)
771         goto err;
772
773     server->new_xdg_surface.notify = server_new_xdg_surface;
774     ds_xdg_shell_add_new_surface_listener(server->xdg_shell,
775             &server->new_xdg_surface);
776
777     if (!add_new_dpms(server))
778         goto err;
779
780     server->seat = ds_seat_create(display, "seat0" /* arbitrary name */);
781     if (!server->seat)
782         goto err;
783     server->seat_caps = 0;
784
785     server->devicemgr = ds_tizen_input_devicemgr_create(
786             server->input_backend, server->seat);
787     if (!server->devicemgr) {
788         ds_err("Could not create ds_tizen_input_devicemgr");
789         goto err;
790     }
791
792     devicemgr_set_keymap(server->devicemgr);
793
794     server->devicemgr_destroy.notify = devicemgr_handle_destroy;
795     ds_tizen_input_devicemgr_add_destroy_listener(server->devicemgr,
796             &server->devicemgr_destroy);
797
798     server->pointer_warp.notify = devicemgr_handle_pointer_warp;
799     ds_tizen_input_devicemgr_add_pointer_warp_listener(server->devicemgr,
800             &server->pointer_warp);
801
802     server->effect = ds_tizen_launch_effect_create(display);
803     if (!server->effect) {
804         goto err;
805     }
806
807     server->effect_destroy.notify = launch_effect_handle_destroy;
808     ds_tizen_launch_effect_add_destroy_listener(server->effect,
809             &server->effect_destroy);
810
811     server->effect_type_set.notify = launch_effect_handle_type_set;
812     ds_tizen_launch_effect_add_type_set_listener(server->effect,
813             &server->effect_type_set);
814
815     server->effect_type_unset.notify = launch_effect_handle_type_unset;
816     ds_tizen_launch_effect_add_type_unset_listener(server->effect,
817             &server->effect_type_unset);
818
819     server->new_splash.notify = launch_effect_handle_new_splash;
820     ds_tizen_launch_effect_add_new_splash_listener(server->effect,
821             &server->new_splash);
822
823     return true;
824
825 err:
826     ds_backend_destroy(server->backend);
827     ds_backend_destroy(server->input_backend);
828
829     return false;
830 }
831
832 static void
833 output_handle_destroy(struct wl_listener *listener, void *data TINYDS_UNUSED)
834 {
835     struct tinyds_output *output =
836         wl_container_of(listener, output, output_destroy);
837
838     if (output->bg_hwc_window)
839         ds_tdm_output_hwc_window_destroy(output->bg_hwc_window);
840
841     wl_list_remove(&output->output_destroy.link);
842     wl_list_remove(&output->output_frame.link);
843
844     if (output->front_buffer)
845         ds_buffer_unlock(output->front_buffer);
846
847 #ifdef USE_TDM_BUFFER_QUEUE
848     fini_renderer(&output->renderer);
849 #else
850     if (output->swapchain)
851         ds_swapchain_destroy(output->swapchain);
852
853     if (output->allocator)
854         ds_allocator_destroy(output->allocator);
855 #endif
856
857     wl_display_terminate(output->server->display);
858
859     output->server->output = NULL;
860
861     free(output);
862 }
863
864 static void
865 output_commit(struct tinyds_output *output)
866 {
867     uint32_t num_changed = 0;
868     uint32_t num_windows = 0, current_num_windows = 0;
869     struct ds_tdm_output_hwc_window **composited_hwc_windows = NULL;
870     struct ds_tdm_output_hwc_window **changed_hwc_windows = NULL;
871     enum ds_tdm_output_hwc_window_composition composition;
872     struct tinyds_view *view;
873     int i;
874     bool need_target = false;
875     bool fully_obscured = false;
876     struct ds_buffer *ds_buffer;
877     struct ds_tdm_box src_box;
878     int w = 0, h = 0;
879
880     if (!output->committable)
881         return;
882
883     if (!output->damaged && !output->target_updated)
884         return;
885
886     wl_list_for_each_reverse(view, &output->server->views, link) {
887         if (!view->hwc_window)
888             continue;
889
890         ds_buffer = ds_surface_get_buffer(
891                 ds_xdg_surface_get_surface(view->xdg_surface));
892         if (!ds_buffer)
893             continue;
894
895         if (!view->mapped)
896             continue;
897
898         num_windows++;
899
900         ds_buffer_get_size(ds_buffer, &w, &h);
901
902         if ((output->width <= w) && (output->height <= h))
903             fully_obscured = true;
904     }
905
906     if (fully_obscured) {
907         ds_tdm_output_hwc_window_set_composition(output->bg_hwc_window,
908                 DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_NONE);
909     } else {
910         ds_tdm_output_hwc_window_set_composition(output->bg_hwc_window,
911                 DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_CLIENT);
912         num_windows++;
913         need_target = true;
914     }
915
916     if (num_windows) {
917         composited_hwc_windows = calloc(num_windows, sizeof *composited_hwc_windows);
918         if (!composited_hwc_windows)
919             return;
920
921         wl_list_for_each_reverse(view, &output->server->views, link) {
922             if (!view->hwc_window)
923                 continue;
924
925             ds_buffer = ds_surface_get_buffer(
926                     ds_xdg_surface_get_surface(view->xdg_surface));
927             if (!ds_buffer)
928                 continue;
929
930             ds_tdm_output_hwc_window_set_buffer(view->hwc_window, ds_buffer);
931
932             ds_buffer_get_size(ds_buffer, &w, &h);
933
934             src_box.x = 0;
935             src_box.y = 0;
936             src_box.width = w;
937             src_box.height = h;
938
939             ds_tdm_output_hwc_window_set_src_box(view->hwc_window, &src_box);
940             ds_tdm_output_hwc_window_set_position(view->hwc_window, view->x, view->y);
941             ds_tdm_output_hwc_window_set_dest_size(view->hwc_window, w, h);
942             ds_tdm_output_hwc_window_set_transform(view->hwc_window, WL_OUTPUT_TRANSFORM_NORMAL);
943
944             if (view->mapped) {
945                 ds_tdm_output_hwc_window_set_composition(view->hwc_window,
946                         DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_DEVICE);
947
948                 composited_hwc_windows[current_num_windows] = view->hwc_window;
949                 current_num_windows++;
950             } else {
951                 ds_tdm_output_hwc_window_set_composition(view->hwc_window,
952                         DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_NONE);
953             }
954         }
955
956         if (!fully_obscured) {
957             composited_hwc_windows[current_num_windows] = output->bg_hwc_window;
958             current_num_windows++;
959         }
960     }
961
962     if (!ds_tdm_output_hwc_validate(output->hwc, composited_hwc_windows,
963             num_windows, &num_changed)) {
964         free(composited_hwc_windows);
965         ds_err("Could not hwc validate");
966         return;
967     }
968
969     if (composited_hwc_windows)
970         free(composited_hwc_windows);
971
972     if (num_changed > 0) {
973         changed_hwc_windows = calloc(num_windows, sizeof *changed_hwc_windows);
974         if (!changed_hwc_windows)
975             return;
976
977         if (!ds_tdm_output_hwc_get_changed_composition(output->hwc, &num_changed,
978                 changed_hwc_windows)) {
979             free(changed_hwc_windows);
980             ds_err("Could not get chaged composition");
981             return;
982         }
983
984         for (i = 0; i < num_changed; i++) {
985             composition = ds_tdm_output_hwc_window_get_composition(changed_hwc_windows[i]);
986             if (composition == DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_CLIENT) {
987                 need_target = true;
988                 break;
989             }
990         }
991     }
992
993     if (changed_hwc_windows)
994         free(changed_hwc_windows);
995
996     if (need_target && output->damaged)
997         draw_output(output);
998
999 #ifdef USE_TDM_BUFFER_QUEUE
1000     struct ds_buffer *buffer;
1001
1002     buffer = ds_tdm_buffer_queue_acquire(output->buffer_queue);
1003     if (buffer) {
1004         if (!ds_tdm_output_hwc_set_client_target_buffer(output->hwc, buffer)) {
1005             ds_err("Could not set hwc client target buffer");
1006             return;
1007         }
1008
1009         output_swap_buffer(output, buffer);
1010     }
1011 #endif
1012
1013     if (!ds_tdm_output_hwc_accept_validation(output->hwc)) {
1014         ds_err("Could not hwc accept validateion");
1015         return;
1016     }
1017
1018     ds_output_commit(output->ds_output);
1019
1020     output->committable = false;
1021     output->damaged = false;
1022     output->target_updated = false;
1023
1024     wl_list_for_each(view, &output->server->views, link) {
1025         enum ds_tdm_output_hwc_window_composition composition;
1026
1027         if (!view->mapped)
1028             continue;
1029
1030         composition = ds_tdm_output_hwc_window_get_composition(view->hwc_window);
1031         if ((composition == DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_DEVICE) ||
1032             (composition == DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_VIDEO) ||
1033             (composition == DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_CURSOR))
1034             view_send_frame_done(view);
1035     }
1036
1037     ds_dbg("output:%p commit", output);
1038 }
1039
1040 static void
1041 output_handle_frame(struct wl_listener *listener, void *data TINYDS_UNUSED)
1042 {
1043     struct tinyds_output *output =
1044         wl_container_of(listener, output, output_frame);
1045
1046     ds_dbg("output:%p handle frame", output);
1047
1048     output->committable = true;
1049
1050     output_commit(output);
1051 }
1052
1053 static void
1054 draw_server_with_damage(struct tinyds_server *server)
1055 {
1056     server->output->damaged = true;
1057     output_schedule_commit(server->output);
1058 }
1059
1060 static void
1061 output_hwc_init(struct tinyds_output *output)
1062 {
1063     struct ds_tdm_output *tdm_output;
1064
1065     tdm_output = ds_tdm_output_from_output(output->ds_output);
1066     assert(tdm_output);
1067
1068     output->hwc = ds_tdm_output_get_hwc(tdm_output);
1069     assert(output->hwc);
1070
1071     ds_tdm_output_hwc_set_enabled(output->hwc, true);
1072 }
1073
1074 #ifdef USE_TDM_BUFFER_QUEUE
1075 static void
1076 output_handle_buffer_queue_acquirable(struct wl_listener *listener,
1077         void *data TINYDS_UNUSED)
1078 {
1079     struct tinyds_output *output;
1080
1081     output = wl_container_of(listener, output, buffer_queue_acquirable);
1082
1083     output->target_updated = true;
1084     output_schedule_commit(output);
1085 }
1086
1087 static void
1088 output_buffer_queue_init(struct tinyds_output *output)
1089 {
1090     struct ds_tdm_output *tdm_output;
1091
1092     tdm_output = ds_tdm_output_from_output(output->ds_output);
1093     assert(tdm_output);
1094
1095     output->buffer_queue = ds_tdm_output_get_buffer_queue(tdm_output);
1096     assert(output->buffer_queue);
1097
1098     output->buffer_queue_acquirable.notify =
1099         output_handle_buffer_queue_acquirable;
1100     ds_tdm_buffer_queue_add_acquirable_listener(output->buffer_queue,
1101             &output->buffer_queue_acquirable);
1102 }
1103
1104 static void
1105 output_renderer_init(struct tinyds_output *output)
1106 {
1107     init_renderer(&output->renderer);
1108
1109     renderer_set_surface_queue(&output->renderer,
1110             ds_tdm_buffer_queue_get_native_queue(output->buffer_queue));
1111
1112     renderer_set_bg_color(&output->renderer, 80, 80, 80);
1113 }
1114
1115 static void
1116 output_draw_with_renderer(struct tinyds_output *output)
1117 {
1118     struct tinyds_view *view;
1119
1120     ds_dbg(">> BEGIN UPDATE TEXTURES");
1121
1122     wl_list_for_each(view, &output->server->views, link) {
1123         struct ds_buffer *ds_buffer;
1124         struct ds_tbm_client_buffer *tbm_buffer;
1125         tbm_surface_h surface;
1126         enum ds_tdm_output_hwc_window_composition composition;
1127
1128         if (!view->mapped)
1129             continue;
1130
1131         composition = ds_tdm_output_hwc_window_get_composition(view->hwc_window);
1132         if ((composition == DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_DEVICE) ||
1133             (composition == DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_VIDEO) ||
1134             (composition == DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_CURSOR))
1135             continue;
1136
1137         ds_buffer = ds_surface_get_buffer(
1138                 ds_xdg_surface_get_surface(view->xdg_surface));
1139         if (!ds_buffer)
1140             continue;
1141
1142         tbm_buffer = ds_tbm_client_buffer_from_buffer(ds_buffer);
1143         if (!tbm_buffer)
1144             continue;
1145
1146         surface = ds_tbm_client_buffer_get_tbm_surface(tbm_buffer);
1147         if (!surface)
1148             continue;
1149
1150         renderer_add_texture(&output->renderer, surface, view->x, view->y);
1151
1152         view_send_frame_done(view);
1153     }
1154
1155     ds_dbg("<< END UPDATE TEXTURES");
1156
1157     renderer_draw(&output->renderer);
1158 }
1159 #else
1160 static void
1161 output_swapchain_init(struct tinyds_output *output,
1162         int width, int height, uint32_t format)
1163
1164 {
1165     output->allocator = ds_tbm_allocator_create();
1166     assert(output->allocator);
1167
1168     output->swapchain = ds_swapchain_create(output->allocator,
1169             width, height, format);
1170     assert(output->swapchain);
1171 }
1172
1173 static void
1174 output_draw_with_swapchain(struct tinyds_output *output)
1175 {
1176     struct tinyds_view *view;
1177     struct ds_buffer *output_buffer;
1178     pixman_image_t *output_image;
1179     enum ds_tdm_output_hwc_window_composition composition;
1180
1181     output_buffer = ds_swapchain_acquire(output->swapchain, NULL);
1182     if (!output_buffer)
1183         return;
1184
1185     output_image = pixman_image_from_buffer(output_buffer,
1186             DS_BUFFER_DATA_PTR_ACCESS_WRITE);
1187     if (!output_image) {
1188         ds_buffer_unlock(output_buffer);
1189         return;
1190     }
1191
1192     pixman_image_fill_color(output_image, 80, 80, 80);
1193
1194     wl_list_for_each(view, &output->server->views, link) {
1195         if (!view->mapped)
1196             continue;
1197
1198         composition = ds_tdm_output_hwc_window_get_composition(view->hwc_window);
1199         if ((composition == DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_DEVICE) ||
1200             (composition == DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_VIDEO) ||
1201             (composition == DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_CURSOR))
1202             continue;
1203
1204         draw_view(view, output_image);
1205     }
1206     pixman_image_unref(output_image);
1207
1208     if (!ds_tdm_output_hwc_set_client_target_buffer(output->hwc, output_buffer)) {
1209         ds_err("Could not set hwc client target buffer");
1210         ds_buffer_unlock(output_buffer);
1211         return;
1212     }
1213
1214     output_swap_buffer(output, output_buffer);
1215 }
1216
1217 static void
1218 draw_view(struct tinyds_view *view, pixman_image_t *dst_image)
1219 {
1220     struct ds_buffer *buffer;
1221     pixman_image_t *src_image;
1222
1223     buffer = ds_surface_get_buffer(
1224             ds_xdg_surface_get_surface(view->xdg_surface));
1225     if (!buffer)
1226         return;
1227
1228     src_image = pixman_image_from_buffer(buffer,
1229             DS_BUFFER_DATA_PTR_ACCESS_READ);
1230     pixman_image_composite32(PIXMAN_OP_OVER,
1231             src_image,
1232             NULL,
1233             dst_image,
1234             0, 0, 0, 0,
1235             view->x, view->y,
1236             pixman_image_get_width(src_image),
1237             pixman_image_get_height(src_image));
1238     pixman_image_unref(src_image);
1239
1240     view_send_frame_done(view);
1241 }
1242 #endif
1243
1244 static void
1245 draw_output(struct tinyds_output *output)
1246 {
1247 #ifdef USE_TDM_BUFFER_QUEUE
1248     output_draw_with_renderer(output);
1249 #else
1250     output_draw_with_swapchain(output);
1251 #endif
1252
1253     ds_dbg("output:%p draw", output);
1254 }
1255
1256 static void
1257 output_swap_buffer(struct tinyds_output *output, struct ds_buffer *buffer)
1258 {
1259     ds_output_attach_buffer(output->ds_output, buffer);
1260
1261     if (output->front_buffer)
1262         ds_buffer_unlock(output->front_buffer);
1263     output->front_buffer = buffer;
1264 }
1265
1266 static void
1267 view_send_frame_done(struct tinyds_view *view)
1268 {
1269     struct timespec now;
1270     clock_gettime(CLOCK_MONOTONIC, &now);
1271     ds_surface_send_frame_done(ds_xdg_surface_get_surface(view->xdg_surface),
1272             &now);
1273 }
1274
1275 static int
1276 server_dispatch_stdin(int fd, uint32_t mask, void *data)
1277 {
1278     struct tinyds_server *server = data;
1279
1280     wl_display_terminate(server->display);
1281
1282     return 1;
1283 }
1284
1285 static void
1286 dpms_handle_destroy(struct wl_listener *listener, void *data)
1287 {
1288     struct tinyds_dpms *dpms;
1289
1290     dpms = wl_container_of(listener, dpms, destroy);
1291
1292     ds_inf("Dpms(%p) destroyed", dpms);
1293
1294     wl_list_remove(&dpms->destroy.link);
1295     wl_list_remove(&dpms->set_dpms.link);
1296     wl_list_remove(&dpms->get_dpms.link);
1297
1298     free(dpms);
1299 }
1300
1301 static void
1302 dpms_handle_set_dpms(struct wl_listener *listener, void *data)
1303 {
1304     struct tinyds_dpms *dpms;
1305     struct ds_tizen_dpms_event *event = data;
1306
1307     dpms = wl_container_of(listener, dpms, set_dpms);
1308
1309     ds_inf("Dpms(%p) set dpms : %d", dpms, event->mode);
1310
1311     //To do
1312     //set dpms mode to output
1313     ds_tizen_dpms_send_set_result(dpms->ds_dpms, event->mode,
1314         DS_TIZEN_DPMS_ERROR_NONE);
1315 }
1316
1317 static void
1318 dpms_handle_get_dpms(struct wl_listener *listener, void *data)
1319 {
1320     struct tinyds_dpms *dpms;
1321
1322     dpms = wl_container_of(listener, dpms, get_dpms);
1323
1324     ds_inf("Dpms(%p) get dpms", dpms);
1325
1326     //To do
1327     //get dpms mode from output
1328     ds_tizen_dpms_send_get_result(dpms->ds_dpms, DS_TIZEN_DPMS_MODE_ON,
1329         DS_TIZEN_DPMS_ERROR_NONE);
1330 }
1331
1332 static void
1333 keyboard_handle_device_destroy(struct wl_listener *listener, void *data)
1334 {
1335     struct tinyds_keyboard *kbd;
1336
1337     kbd = wl_container_of(listener, kbd, destroy);
1338
1339     ds_inf("Keyboard(%p) destroyed", kbd);
1340
1341     wl_list_remove(&kbd->destroy.link);
1342     wl_list_remove(&kbd->key.link);
1343     wl_list_remove(&kbd->link);
1344
1345     free(kbd);
1346 }
1347
1348 static bool
1349 server_handle_keybinding(struct tinyds_server *server, xkb_keysym_t sym)
1350 {
1351     switch (sym) {
1352         case XKB_KEY_BackSpace:
1353             wl_display_terminate(server->display);
1354             break;
1355         default:
1356             return false;
1357     }
1358
1359     return true;
1360 }
1361
1362 static void
1363 keyboard_handle_key(struct wl_listener *listener, void *data)
1364 {
1365     struct tinyds_keyboard *kbd;
1366     struct ds_event_keyboard_key *event = data;
1367     struct ds_keyboard *ds_keyboard;
1368     struct xkb_state *xkb_state;
1369     const xkb_keysym_t *syms;
1370     int nsyms;
1371     bool handled = false;
1372
1373     kbd = wl_container_of(listener, kbd, key);
1374
1375     ds_inf("Keyboard(%p) event key: keycode(%d), state(%d), time_msec(%d), "
1376             "update_state(%d)", kbd->dev,
1377             event->keycode, event->state, event->time_msec,
1378             event->update_state);
1379
1380     ds_keyboard = ds_input_device_get_keyboard(kbd->dev);
1381
1382     if (event->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
1383         xkb_state = ds_keyboard_get_xkb_state(ds_keyboard);
1384         if (xkb_state) {
1385             nsyms = xkb_state_key_get_syms(xkb_state, event->keycode + 8,
1386                     &syms);
1387             for (int i = 0; i < nsyms; i++) {
1388                 handled = server_handle_keybinding(kbd->server, syms[i]);
1389             }
1390         }
1391     }
1392
1393     if (!handled) {
1394         ds_seat_keyboard_notify_key(kbd->server->seat, event->time_msec,
1395                 event->keycode, event->state);
1396     }
1397 }
1398
1399 static void
1400 server_add_keyboard(struct tinyds_server *server, struct ds_input_device *dev)
1401 {
1402     struct tinyds_keyboard *kbd;
1403     struct xkb_context *context;
1404     struct xkb_keymap *keymap;
1405
1406     kbd = calloc(1, sizeof *kbd);
1407     assert(kbd);
1408
1409     kbd->dev = dev;
1410     kbd->server = server;
1411
1412     context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
1413     if (!context)
1414         goto err;
1415
1416     keymap = xkb_keymap_new_from_names(context, NULL,
1417             XKB_KEYMAP_COMPILE_NO_FLAGS);
1418
1419     if (!keymap) {
1420         ds_err("Failed to compile keymap");
1421         xkb_context_unref(context);
1422         goto err;
1423     }
1424
1425     ds_keyboard_set_keymap(ds_input_device_get_keyboard(dev), keymap);
1426
1427     xkb_keymap_unref(keymap);
1428     xkb_context_unref(context);
1429
1430     kbd->destroy.notify = keyboard_handle_device_destroy;
1431     ds_input_device_add_destroy_listener(dev, &kbd->destroy);
1432
1433     kbd->key.notify = keyboard_handle_key;
1434     ds_keyboard_add_key_listener(ds_input_device_get_keyboard(dev), &kbd->key);
1435
1436     wl_list_insert(&server->keyboards, &kbd->link);
1437
1438     ds_inf("Keyboard(%p) added", kbd);
1439
1440     return;
1441
1442 err:
1443     free(kbd);
1444 }
1445
1446 static struct tinyds_view *
1447 server_view_at(struct tinyds_server *server, double lx, double ly,
1448         double *sx, double *sy)
1449 {
1450     struct tinyds_view *view;
1451     struct ds_surface *surface;
1452     struct ds_buffer *buffer;
1453     int x, y, w = 0, h = 0;
1454
1455     wl_list_for_each(view, &server->views, link) {
1456         surface = ds_xdg_surface_get_surface(view->xdg_surface);
1457         buffer = ds_surface_get_buffer(surface);
1458         ds_buffer_get_size(buffer, &w, &h);
1459
1460         x = view->x;
1461         y = view->y;
1462
1463         if (lx >= x && lx <= x + w && ly >= y && ly <= y + h) {
1464             *sx = lx - x;
1465             *sy = ly - y;
1466
1467             return view;
1468         }
1469     }
1470
1471     return NULL;
1472 }
1473
1474 static void
1475 touch_handle_device_destroy(struct wl_listener *listener, void *data)
1476 {
1477     struct tinyds_touch *touch;
1478
1479     touch = wl_container_of(listener, touch, destroy);
1480
1481     ds_inf("Touch(%p) destroyed", touch);
1482
1483     wl_list_remove(&touch->destroy.link);
1484     wl_list_remove(&touch->down.link);
1485     wl_list_remove(&touch->up.link);
1486     wl_list_remove(&touch->motion.link);
1487
1488     free(touch);
1489 }
1490
1491 static void
1492 touch_handle_down(struct wl_listener *listener, void *data)
1493 {
1494     struct ds_event_touch_down *event = data;
1495     struct tinyds_touch *touch;
1496     struct tinyds_view *view;
1497     struct tinyds_server *server;
1498     double sx = 0.f, sy = 0.f;
1499
1500     touch = wl_container_of(listener, touch, down);
1501
1502     server = touch->server;
1503     server->output_x = event->x * server->output->width;
1504     server->output_y = event->y * server->output->height;
1505
1506     ds_inf("Touch(%p) event down: id(%d) x %.3f y %.3f output_x %.1f output_y %.1f",
1507             touch->dev, event->id, event->x, event->y, server->output_x, server->output_y);
1508
1509     view = server_view_at(server, server->output_x, server->output_y, &sx, &sy);
1510
1511     if (view) {
1512         ds_seat_touch_notify_down(touch->server->seat, ds_xdg_surface_get_surface(view->xdg_surface),
1513                 event->time_msec, event->id, sx, sy);
1514     }
1515 }
1516
1517 static void
1518 touch_handle_up(struct wl_listener *listener, void *data)
1519 {
1520     struct ds_event_touch_up *event = data;
1521     struct tinyds_touch *touch;
1522
1523     touch = wl_container_of(listener, touch, up);
1524
1525     ds_inf("Touch(%p) event up: id(%d) time_msec(%d)",
1526             touch->dev, event->id, event->time_msec);
1527
1528     ds_seat_touch_notify_up(touch->server->seat, event->time_msec, event->id);
1529 }
1530
1531 static void
1532 touch_handle_motion(struct wl_listener *listener, void *data)
1533 {
1534     struct ds_event_touch_motion *event = data;
1535     struct tinyds_touch *touch;
1536     struct tinyds_view *view;
1537     struct tinyds_server *server;
1538     double sx = 0.f, sy = 0.f;
1539
1540     touch = wl_container_of(listener, touch, motion);
1541
1542     server = touch->server;
1543     server->output_x = event->x * server->output->width;
1544     server->output_y = event->y * server->output->height;
1545
1546     ds_inf("Touch(%p) event motion: id(%d) x %.3f y %.3f output_x %.1f output_y %.1f",
1547             touch->dev, event->id, event->x, event->y, server->output_x, server->output_y);
1548
1549     view = server_view_at(server, server->output_x, server->output_y, &sx, &sy);
1550
1551     if (view) {
1552         ds_seat_touch_notify_motion(server->seat, event->time_msec,
1553                 event->id, sx, sy);
1554     }
1555 }
1556
1557 static void
1558 server_add_touch(struct tinyds_server *server, struct ds_input_device *dev)
1559 {
1560     struct tinyds_touch *touch;
1561
1562     touch = calloc(1, sizeof *touch);
1563     assert(touch);
1564
1565     touch->dev = dev;
1566     touch->server = server;
1567
1568     touch->destroy.notify = touch_handle_device_destroy;
1569     ds_input_device_add_destroy_listener(dev, &touch->destroy);
1570
1571     touch->down.notify = touch_handle_down;
1572     ds_touch_add_down_listener(ds_input_device_get_touch(dev), &touch->down);
1573
1574     touch->up.notify = touch_handle_up;
1575     ds_touch_add_up_listener(ds_input_device_get_touch(dev), &touch->up);
1576
1577     touch->motion.notify = touch_handle_motion;
1578     ds_touch_add_motion_listener(ds_input_device_get_touch(dev), &touch->motion);
1579
1580     ds_inf("Touch(%p) added", touch);
1581 }
1582
1583 static void
1584 pointer_handle_device_destroy(struct wl_listener *listener, void *data)
1585 {
1586     struct tinyds_pointer *pointer;
1587
1588     pointer = wl_container_of(listener, pointer, destroy);
1589
1590     ds_inf("Pointer(%p) destroyed", pointer);
1591
1592     wl_list_remove(&pointer->destroy.link);
1593     wl_list_remove(&pointer->motion.link);
1594     wl_list_remove(&pointer->button.link);
1595     wl_list_remove(&pointer->frame.link);
1596     wl_list_remove(&pointer->link);
1597
1598     free(pointer);
1599 }
1600
1601 static void
1602 pointer_handle_motion(struct wl_listener *listener, void *data)
1603 {
1604     struct tinyds_pointer *pointer;
1605     struct ds_event_pointer_motion *event = data;
1606     struct tinyds_view *view;
1607     struct tinyds_server *server;
1608     int ow = 0, oh = 0;
1609     double sx, sy;
1610
1611     pointer = wl_container_of(listener, pointer, motion);
1612
1613     server = pointer->server;
1614     if (server->output) {
1615         ow = server->output->width;
1616         oh = server->output->height;
1617     }
1618
1619     if (server->output_x + event->delta_x >= ow)
1620         server->output_x = ow;
1621     else if(server->output_x + event->delta_x <= 0.f)
1622         server->output_x = 0.f;
1623     else
1624         server->output_x = server->output_x + event->delta_x ;
1625     if (server->output_y + event->delta_y >= oh)
1626         server->output_y = oh;
1627     else if(server->output_y + event->delta_y <= 0.f)
1628         server->output_y = 0.f;
1629     else
1630         server->output_y = server->output_y + event->delta_y ;
1631
1632     ds_inf("Pointer(%p) motion: (delta_x %.1f delta_y %.1f) output_x %.1f output_y %.1f",
1633             pointer, event->delta_x, event->delta_y, server->output_x, server->output_y);
1634
1635     view = server_view_at(pointer->server, server->output_x, server->output_y, &sx, &sy);
1636
1637     if (pointer->focused_view != view) {
1638         if (pointer->focused_view) {
1639             ds_inf("Clear pointer focus from view(%p)", pointer->focused_view);
1640             ds_seat_pointer_notify_clear_focus(pointer->server->seat);
1641             pointer->focused_view = NULL;
1642         }
1643
1644         if (view) {
1645             ds_inf("Set pointer focus to view(%p)", view);
1646             ds_seat_pointer_notify_enter(pointer->server->seat,
1647                     ds_xdg_surface_get_surface(view->xdg_surface), sx, sy);
1648             pointer->focused_view = view;
1649         }
1650     }
1651
1652     if (view) {
1653         ds_seat_pointer_notify_motion(pointer->server->seat,
1654                 event->time_msec, sx, sy);
1655     }
1656 }
1657
1658 static void
1659 pointer_handle_button(struct wl_listener *listener, void *data)
1660 {
1661     struct tinyds_pointer *pointer;
1662     struct ds_event_pointer_button *event = data;
1663
1664     pointer = wl_container_of(listener, pointer, button);
1665
1666     ds_inf("Pointer(%p) button(%d): state(%s) time(%d)",
1667             pointer, event->button,
1668             (event->state == DS_BUTTON_PRESSED) ? "Pressed" : "Released",
1669             event->time_msec);
1670
1671     ds_seat_pointer_notify_button(pointer->server->seat, event->time_msec, event->button, event->state);
1672 }
1673
1674 static void
1675 pointer_handle_frame(struct wl_listener *listener, void *data)
1676 {
1677     struct tinyds_pointer *pointer;
1678
1679     pointer = wl_container_of(listener, pointer, frame);
1680
1681     ds_inf("Pointer(%p) frame", pointer);
1682     ds_seat_pointer_notify_frame(pointer->server->seat);
1683 }
1684
1685 static void
1686 server_add_pointer(struct tinyds_server *server, struct ds_input_device *dev)
1687 {
1688     struct tinyds_pointer *pointer;
1689
1690     pointer = calloc(1, sizeof *pointer);
1691     assert(pointer);
1692
1693     pointer->dev = dev;
1694     pointer->server = server;
1695     server->output_x = 200;
1696     server->output_y = 200;
1697
1698     pointer->destroy.notify = pointer_handle_device_destroy;
1699     ds_input_device_add_destroy_listener(dev, &pointer->destroy);
1700
1701     pointer->motion.notify = pointer_handle_motion;
1702     ds_pointer_add_motion_listener(ds_input_device_get_pointer(dev),
1703             &pointer->motion);
1704
1705     pointer->button.notify = pointer_handle_button;
1706     ds_pointer_add_button_listener(ds_input_device_get_pointer(dev),
1707             &pointer->button);
1708
1709     pointer->frame.notify = pointer_handle_frame;
1710     ds_pointer_add_frame_listener(ds_input_device_get_pointer(dev),
1711             &pointer->frame);
1712
1713     pointer->focused_view = NULL;
1714
1715     wl_list_insert(&server->pointers, &pointer->link);
1716
1717     ds_inf("Pointer(%p) added", pointer);
1718 }
1719
1720
1721 static void
1722 output_schedule_commit_handle_idle_timer(void *data)
1723 {
1724     struct tinyds_output *output = data;
1725     output->idle_commit = NULL;
1726
1727     output_commit(output);
1728 }
1729
1730 static void
1731 output_schedule_commit(struct tinyds_output *output)
1732 {
1733     if (output->idle_commit)
1734         return;
1735
1736     struct wl_event_loop *ev = wl_display_get_event_loop(output->server->display);
1737     output->idle_commit =
1738         wl_event_loop_add_idle(ev, output_schedule_commit_handle_idle_timer, output);
1739 }