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