From fae26498fa599a6ff171aa602fd05083be120011 Mon Sep 17 00:00:00 2001 From: "duna.oh" Date: Wed, 18 May 2022 18:39:54 +0900 Subject: [PATCH] example: add an executable 'tinyds-tdm-libinput' and handle ds_seat Change-Id: I71e53ae7bb143fcd69ee6259d9b5934be192bbbf --- packaging/libds.spec | 1 + src/clients/simple-tbm.c | 168 +++++++ src/examples/meson.build | 17 + src/examples/tinyds-tdm-libinput.c | 992 +++++++++++++++++++++++++++++++++++++ 4 files changed, 1178 insertions(+) create mode 100644 src/examples/tinyds-tdm-libinput.c diff --git a/packaging/libds.spec b/packaging/libds.spec index 45329fe..2ffdca0 100644 --- a/packaging/libds.spec +++ b/packaging/libds.spec @@ -102,6 +102,7 @@ ninja -C builddir install %{_bindir}/tdm-backend %{_bindir}/tinyds-tdm %{_bindir}/ds-simple-tbm +%{_bindir}/tinyds-tdm-libinput %files tizen-keyrouter %manifest %{name}.manifest diff --git a/src/clients/simple-tbm.c b/src/clients/simple-tbm.c index f572b60..4fd9847 100644 --- a/src/clients/simple-tbm.c +++ b/src/clients/simple-tbm.c @@ -48,6 +48,7 @@ struct display { struct wl_compositor *compositor; struct xdg_wm_base *wm_base; struct wl_shm *shm; + struct wl_seat *seat; struct wayland_tbm_client *wl_tbm; bool has_xrgb; }; @@ -329,6 +330,168 @@ static const struct xdg_wm_base_listener xdg_wm_base_listener = { xdg_wm_base_ping, }; +static void pointer_handle_button(void *data, struct wl_pointer *pointer, + uint32_t serial, uint32_t time, uint32_t button, uint32_t state) +{ + if (state == WL_POINTER_BUTTON_STATE_PRESSED) { + fprintf(stderr, "pointer_handle_button: PRESSED\n"); + } + else { + fprintf(stderr, "pointer_handle_button: RELEASED\n"); + } +} + +static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer, + uint32_t serial, struct wl_surface *surface, + wl_fixed_t surface_x, wl_fixed_t surface_y) +{ + fprintf(stderr, "pointer_handle_enter surface_x:%d, surface_y:%d\n", + wl_fixed_to_int(surface_x), wl_fixed_to_int(surface_y)); +} + +static void pointer_handle_leave(void *data, struct wl_pointer *wl_pointer, + uint32_t serial, struct wl_surface *surface) +{ + fprintf(stderr, "pointer_handle_leave\n"); +} + +static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer, + uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) +{ + fprintf(stderr, "pointer_handle_motion surface_x:%d, surface_y:%d\n", + wl_fixed_to_int(surface_x), wl_fixed_to_int(surface_y)); +} + +static void pointer_handle_frame(void *data, struct wl_pointer *wl_pointer) +{ + fprintf(stderr, "pointer_handle_frame\n"); +} + +static struct wl_pointer_listener pointer_listener = { + .enter = pointer_handle_enter, + .leave = pointer_handle_leave, + .motion = pointer_handle_motion, + .button = pointer_handle_button, + .axis = NULL, + .frame = pointer_handle_frame, + .axis_source = NULL, + .axis_stop = NULL, + .axis_discrete = NULL, +}; + +static void touch_handle_down(void *data, struct wl_touch *wl_touch, + uint32_t serial, uint32_t time, struct wl_surface *surface, + int32_t id, wl_fixed_t x, wl_fixed_t y) +{ + fprintf(stderr, "touch_handle_down id:%d, x:%d, y:%d\n", + id, wl_fixed_to_int(x), wl_fixed_to_int(y)); +} + +static void touch_handle_up(void *data, struct wl_touch *wl_touch, + uint32_t serial, uint32_t time, int32_t id) +{ + fprintf(stderr, "touch_handle_up id:%d\n", id); +} + +static void touch_handle_motion(void *data, struct wl_touch *wl_touch, + uint32_t time, int32_t id, wl_fixed_t x, wl_fixed_t y) +{ + fprintf(stderr, "touch_handle_motion id:%d, x:%d, y:%d\n", + id, wl_fixed_to_int(x), wl_fixed_to_int(y)); +} + +static void touch_handle_frame(void *data, struct wl_touch *wl_touch) +{ + fprintf(stderr, "touch_handle_frame\n"); +} + +static struct wl_touch_listener touch_listener = { + .down = touch_handle_down, + .up = touch_handle_up, + .motion = touch_handle_motion, + .frame = touch_handle_frame, + .cancel = NULL, + .shape = NULL, + .orientation = NULL, +}; + +static void keyboard_handle_keymap(void *data, struct wl_keyboard *wl_keyboard, + uint32_t format, int32_t fd, uint32_t size) +{ + fprintf(stderr, "keyboard_handle_keymap\n"); +} +static void keyboard_handle_enter(void *data, struct wl_keyboard *wl_keyboard, + uint32_t serial, struct wl_surface *surface, struct wl_array *keys) +{ + fprintf(stderr, "keyboard_handle_enter\n"); +} +static void keyboard_handle_leave(void *data, struct wl_keyboard *wl_keyboard, + uint32_t serial, struct wl_surface *surface) +{ + fprintf(stderr, "keyboard_handle_leave\n"); +} +static void keyboard_handle_modifiers(void *data, struct wl_keyboard *wl_keyboard, + uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, + uint32_t mods_locked, uint32_t group) +{ + fprintf(stderr, "keyboard_handle_modifiers\n"); +} +static void keyboard_handle_repeat_info(void *data, struct wl_keyboard *wl_keyboard, + int32_t rate, int32_t delay) +{ + fprintf(stderr, "keyboard_handle_repeat_info\n"); +} + +static void keyboard_handle_key(void *data, struct wl_keyboard *wl_keyboard, + uint32_t serial, uint32_t time, uint32_t key, uint32_t state) +{ + if (state == WL_KEYBOARD_KEY_STATE_PRESSED) { + fprintf(stderr, "keyboard_handle_key: PRESSED\n"); + } else { + fprintf(stderr, "keyboard_handle_key: RELEASED\n"); + } +} + +static struct wl_keyboard_listener keyboard_listener = { + .keymap = keyboard_handle_keymap, + .enter = keyboard_handle_enter, + .leave = keyboard_handle_leave, + .key = keyboard_handle_key, + .modifiers = keyboard_handle_modifiers, + .repeat_info = keyboard_handle_repeat_info, +}; + +static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, + enum wl_seat_capability caps) +{ + if ((caps & WL_SEAT_CAPABILITY_KEYBOARD)) { + struct wl_keyboard *keyboard = wl_seat_get_keyboard(wl_seat); + wl_keyboard_add_listener(keyboard, &keyboard_listener, NULL); + fprintf(stderr, "seat_handle_capabilities: keyboard\n"); + } + if ((caps & WL_SEAT_CAPABILITY_POINTER)) { + struct wl_pointer *pointer = wl_seat_get_pointer(wl_seat); + wl_pointer_add_listener(pointer, &pointer_listener, NULL); + fprintf(stderr, "seat_handle_capabilities: pointer\n"); + } + if ((caps & WL_SEAT_CAPABILITY_TOUCH)) { + struct wl_touch *touch = wl_seat_get_touch(wl_seat); + wl_touch_add_listener(touch, &touch_listener, NULL); + fprintf(stderr, "seat_handle_capabilities: touch\n"); + } +} + +static void seat_handle_name(void *data, struct wl_seat *wl_seat, + const char *name) +{ + fprintf(stderr, "seat_handle_name name:%s\n", name); +} + +const struct wl_seat_listener seat_listener = { + .capabilities = seat_handle_capabilities, + .name = seat_handle_name, +}; + static void registry_handle_global(void *data, struct wl_registry *registry, uint32_t id, const char *interface, uint32_t version) @@ -347,6 +510,11 @@ registry_handle_global(void *data, struct wl_registry *registry, d->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1); wl_shm_add_listener(d->shm, &shm_listener, d); + } else if (strcmp(interface, "wl_seat") == 0) { + d->seat = wl_registry_bind(registry, + id, &wl_seat_interface, 7); + wl_seat_add_listener(d->seat, &seat_listener, d); + fprintf(stderr, "wl_seat bound!\n"); } } diff --git a/src/examples/meson.build b/src/examples/meson.build index 9f2d976..5c5c437 100644 --- a/src/examples/meson.build +++ b/src/examples/meson.build @@ -65,4 +65,21 @@ if get_option('tizen') install_dir: libds_bindir, install : true ) + + tinyds_tdm_libinput_files = [ + 'tinyds-tdm-libinput.c', + 'pixman-helper.c', + 'pixman-tbm-helper.c', + 'tinyds-tdm-renderer.c', + ] + executable('tinyds-tdm-libinput', + tinyds_tdm_libinput_files, + dependencies: [ + common_deps, + dependency('pixman-1', required: true), + dependency('threads', required: true), + ], + install_dir: libds_bindir, + install : true + ) endif diff --git a/src/examples/tinyds-tdm-libinput.c b/src/examples/tinyds-tdm-libinput.c new file mode 100644 index 0000000..f4e9319 --- /dev/null +++ b/src/examples/tinyds-tdm-libinput.c @@ -0,0 +1,992 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define USE_TDM_BUFFER_QUEUE + +#ifdef USE_TDM_BUFFER_QUEUE +#include "pixman-tbm-helper.h" +#include "tinyds-tdm-renderer.h" +#else +#include +#endif + +#include "pixman-helper.h" + +#define TINYDS_UNUSED __attribute__((unused)) + +struct tinyds_output +{ + struct tinyds_server *server; + struct ds_output *ds_output; + struct ds_allocator *allocator; +#ifdef USE_TDM_BUFFER_QUEUE + struct tinyds_renderer renderer; + struct ds_tdm_buffer_queue *buffer_queue; + struct wl_listener buffer_queue_acquirable; +#else + struct ds_swapchain *swapchain; +#endif + struct ds_buffer *front_buffer; + + struct wl_listener output_destroy; + struct wl_listener output_frame; + + int width, height; + + bool drawable; + bool damaged; +}; + +struct tinyds_server +{ + struct ds_tbm_server *tbm_server; + + struct wl_display *display; + + struct ds_backend *backend; + struct ds_backend *input_backend; + struct ds_compositor *compositor; + struct ds_xdg_shell *xdg_shell; + struct ds_seat *seat; + uint32_t seat_caps; + double output_x, output_y; + + struct tinyds_output *output; + struct wl_event_source *stdin_source; + + struct wl_list views; + + struct wl_listener new_output; + struct wl_listener new_input; + struct wl_listener new_xdg_surface; +}; + +struct tinyds_view +{ + struct tinyds_server *server; + + struct tinyds_texture *texture; + struct ds_xdg_surface *xdg_surface; + + struct wl_listener xdg_surface_map; + struct wl_listener xdg_surface_unmap; + struct wl_listener xdg_surface_destroy; + struct wl_listener surface_commit; + struct wl_list link; // tinyds_server::views + + int x, y; + bool mapped; +}; + +struct tinyds_pointer +{ + struct ds_input_device *dev; + struct tinyds_server *server; + + struct tinyds_view *focused_view; + + struct wl_listener destroy; + struct wl_listener motion; //relative + struct wl_listener button; + struct wl_listener frame; +}; + +struct tinyds_keyboard +{ + struct ds_input_device *dev; + struct tinyds_server *server; + + struct wl_listener destroy; + struct wl_listener key; +}; + +struct tinyds_touch +{ + struct ds_input_device *dev; + struct tinyds_server *server; + + struct wl_listener destroy; + struct wl_listener down; + struct wl_listener up; + struct wl_listener motion; +}; + +struct tinyds_server tinyds; + +static bool init_server(struct tinyds_server *server, struct wl_display *display); +static int server_dispatch_stdin(int fd, uint32_t mask, void *data); +static void output_handle_destroy(struct wl_listener *listener, void *data); +static void output_handle_frame(struct wl_listener *listener, void *data); +static void draw_server_with_damage(struct tinyds_server *server); +static void draw_output(struct tinyds_output *output); +static void output_swap_buffer(struct tinyds_output *output, + struct ds_buffer *buffer); +static void view_send_frame_done(struct tinyds_view *view); +#ifdef USE_TDM_BUFFER_QUEUE +static void output_buffer_queue_init(struct tinyds_output *output); +static void output_renderer_init(struct tinyds_output *output); +static void output_draw_with_renderer(struct tinyds_output *output); +#else +static void output_swapchain_init(struct tinyds_output *output, + int width, int height, uint32_t format); +static void output_draw_with_swapchain(struct tinyds_output *output); +static void draw_view(struct tinyds_view *view, pixman_image_t *dst_image); +#endif +static void server_add_keyboard(struct tinyds_server *server, + struct ds_input_device *dev); +static void server_add_pointer(struct tinyds_server *server, + struct ds_input_device *dev); +static void server_add_touch(struct tinyds_server *server, + struct ds_input_device *dev); + +int +main(void) +{ + struct tinyds_server *server = &tinyds; + struct wl_display *display; + struct wl_event_loop *loop; + const char *socket; + bool res; + + ds_log_init(DS_INF, NULL); + + display = wl_display_create(); + assert(display); + + res = init_server(server, display); + assert(res); + + socket = wl_display_add_socket_auto(display); + assert(socket); + + ds_backend_start(server->backend); + ds_backend_start(server->input_backend); + + setenv("WAYLAND_DISPLAY", socket, true); + + ds_inf("Running Wayland compositor on WAYLAND_DISPLAY=%s", socket); + + loop = wl_display_get_event_loop(display); + server->stdin_source = wl_event_loop_add_fd(loop, STDIN_FILENO, + WL_EVENT_READABLE, server_dispatch_stdin, server); + + wl_display_run(display); + + wl_display_destroy_clients(display); + wl_display_destroy(display); + + return 0; +} + +static void +view_handle_xdg_surface_map(struct wl_listener *listener, + void *data TINYDS_UNUSED) +{ + struct tinyds_view *view; + + view = wl_container_of(listener, view, xdg_surface_map); + view->mapped = true; +} + +static void +view_handle_xdg_surface_unmap(struct wl_listener *listener, + void *data TINYDS_UNUSED) +{ + struct tinyds_view *view; + + view = wl_container_of(listener, view, xdg_surface_unmap); + view->mapped = false; +} + +static void +view_handle_xdg_surface_destroy(struct wl_listener *listener, + void *data TINYDS_UNUSED) +{ + struct tinyds_view *view; + struct tinyds_server *server; + + view = wl_container_of(listener, view, xdg_surface_destroy); + server = view->server; + + wl_list_remove(&view->xdg_surface_destroy.link); + wl_list_remove(&view->xdg_surface_map.link); + wl_list_remove(&view->xdg_surface_unmap.link); + wl_list_remove(&view->surface_commit.link); + wl_list_remove(&view->link); + free(view); + + draw_server_with_damage(server); +} + +static void +view_handle_surface_commit(struct wl_listener *listener, + void *data TINYDS_UNUSED) +{ + struct tinyds_view *view; + + view = wl_container_of(listener, view, surface_commit); + draw_server_with_damage(view->server); +} + +static void +server_new_xdg_surface(struct wl_listener *listener, void *data) +{ + struct tinyds_server *server; + struct tinyds_view *view; + struct ds_xdg_surface *xdg_surface; + + server = wl_container_of(listener, server, new_xdg_surface); + xdg_surface = data; + + ds_inf("New xdg_surface(%p)", (void *)xdg_surface); + + view = calloc(1, sizeof *view); + assert(view); + + view->server = server; + view->xdg_surface = xdg_surface; + + view->xdg_surface_map.notify = view_handle_xdg_surface_map; + ds_xdg_surface_add_map_listener(xdg_surface, + &view->xdg_surface_map); + + view->xdg_surface_unmap.notify = view_handle_xdg_surface_unmap; + ds_xdg_surface_add_unmap_listener(xdg_surface, + &view->xdg_surface_unmap); + + view->xdg_surface_destroy.notify = view_handle_xdg_surface_destroy; + ds_xdg_surface_add_destroy_listener(xdg_surface, + &view->xdg_surface_destroy); + + view->surface_commit.notify = view_handle_surface_commit; + ds_surface_add_commit_listener( + ds_xdg_surface_get_surface(xdg_surface), + &view->surface_commit); + + wl_list_insert(server->views.prev, &view->link); + + view->x = rand() % 1000; + view->y = rand() % 500; +} + +static void +backend_handle_new_output(struct wl_listener *listener, void *data) +{ + struct tinyds_server *server; + struct tinyds_output *output; + struct ds_output *ds_output; + const struct ds_output_mode *mode; + + server = wl_container_of(listener, server, new_output); + ds_output = data; + + ds_inf("New output(%p)", ds_output); + + if (server->output) + return; + + mode = ds_output_get_preferred_mode(ds_output); + ds_output_set_mode(ds_output, mode); + + output = calloc(1, sizeof *output); + if (!output) + return; + + output->server = server; + output->ds_output = ds_output; + output->width = mode->width; + output->height = mode->height; + output->drawable = true; + output->damaged = true; + +#ifdef USE_TDM_BUFFER_QUEUE + output_buffer_queue_init(output); + output_renderer_init(output); +#else + output_swapchain_init(output, mode->width, mode->height, + DRM_FORMAT_XRGB8888); +#endif + + output->output_destroy.notify = output_handle_destroy; + ds_output_add_destroy_listener(ds_output, &output->output_destroy); + + output->output_frame.notify = output_handle_frame; + ds_output_add_frame_listener(ds_output, &output->output_frame); + + server->output = output; + + draw_output(output); +} + +static void +backend_handle_new_input(struct wl_listener *listener, void *data) +{ + struct tinyds_server *server; + struct ds_input_device *dev = data; + enum ds_input_device_type dev_type; + + server = wl_container_of(listener, server, new_input); + + dev_type = ds_input_device_get_type(dev); + + switch (dev_type) { + case DS_INPUT_DEVICE_KEYBOARD: + server_add_keyboard(server, dev); + server->seat_caps |= WL_SEAT_CAPABILITY_KEYBOARD; + break; + case DS_INPUT_DEVICE_TOUCH: + server_add_touch(server, dev); + server->seat_caps |= WL_SEAT_CAPABILITY_TOUCH; + break; + case DS_INPUT_DEVICE_POINTER: + server_add_pointer(server, dev); + server->seat_caps |= WL_SEAT_CAPABILITY_POINTER; + break; + default: + ds_err("Unknown type(%d) of ds_input_device", dev_type); + break; + } + + ds_seat_set_capabilities(server->seat, server->seat_caps); +} + +static bool +init_server(struct tinyds_server *server, struct wl_display *display) +{ + server->display = display; + + wl_list_init(&server->views); + + if (wl_display_init_shm(display) != 0) + return false; + + server->backend = ds_tdm_backend_create(display); + if (!server->backend) + return false; + + server->input_backend = ds_libinput_backend_create(display); + if (!server->input_backend) + return false; + + server->new_output.notify = backend_handle_new_output; + ds_backend_add_new_output_listener(server->backend, + &server->new_output); + + server->new_input.notify = backend_handle_new_input; + ds_backend_add_new_input_listener(server->input_backend, &server->new_input); + + server->compositor = ds_compositor_create(display); + if (!server->compositor) + goto err; + + server->tbm_server = ds_tbm_server_create(display); + if (!server->tbm_server) + goto err; + + server->xdg_shell = ds_xdg_shell_create(display); + if (!server->xdg_shell) + goto err; + + server->new_xdg_surface.notify = server_new_xdg_surface; + ds_xdg_shell_add_new_surface_listener(server->xdg_shell, + &server->new_xdg_surface); + + server->seat = ds_seat_create(display, "seat0" /* arbitrary name */); + if (!server->seat) + goto err; + server->seat_caps = 0; + + return true; + +err: + ds_backend_destroy(server->backend); + ds_backend_destroy(server->input_backend); + + return false; +} + +static void +output_handle_destroy(struct wl_listener *listener, void *data TINYDS_UNUSED) +{ + struct tinyds_output *output = + wl_container_of(listener, output, output_destroy); + + wl_list_remove(&output->output_destroy.link); + wl_list_remove(&output->output_frame.link); + + if (output->front_buffer) + ds_buffer_unlock(output->front_buffer); + +#ifdef USE_TDM_BUFFER_QUEUE + fini_renderer(&output->renderer); +#else + if (output->swapchain) + ds_swapchain_destroy(output->swapchain); + + if (output->allocator) + ds_allocator_destroy(output->allocator); +#endif + + wl_display_terminate(output->server->display); + + output->server->output = NULL; + + free(output); +} + +static void +output_handle_frame(struct wl_listener *listener, void *data TINYDS_UNUSED) +{ + struct tinyds_output *output = + wl_container_of(listener, output, output_frame); + + output->drawable = true; + draw_output(output); +} + +static void +draw_server_with_damage(struct tinyds_server *server) +{ + server->output->damaged = true; + draw_output(server->output); +} + +#ifdef USE_TDM_BUFFER_QUEUE +static void +output_handle_buffer_queue_acquirable(struct wl_listener *listener, + void *data TINYDS_UNUSED) +{ + struct tinyds_output *output; + struct ds_buffer *buffer; + + output = wl_container_of(listener, output, buffer_queue_acquirable); + + buffer = ds_tdm_buffer_queue_acquire(output->buffer_queue); + assert(buffer); + + output_swap_buffer(output, buffer); +} + +static void +output_buffer_queue_init(struct tinyds_output *output) +{ + struct ds_tdm_output *tdm_output; + + tdm_output = ds_tdm_output_from_output(output->ds_output); + assert(tdm_output); + + output->buffer_queue = ds_tdm_output_get_buffer_queue(tdm_output); + assert(output->buffer_queue); + + output->buffer_queue_acquirable.notify = + output_handle_buffer_queue_acquirable; + ds_tdm_buffer_queue_add_acquirable_listener(output->buffer_queue, + &output->buffer_queue_acquirable); +} + +static void +output_renderer_init(struct tinyds_output *output) +{ + init_renderer(&output->renderer); + + renderer_set_surface_queue(&output->renderer, + ds_tdm_buffer_queue_get_native_queue(output->buffer_queue)); + + renderer_set_bg_color(&output->renderer, 80, 80, 80); +} + +static void +output_draw_with_renderer(struct tinyds_output *output) +{ + struct tinyds_view *view; + + ds_dbg(">> BEGIN UPDATE TEXTURES"); + + wl_list_for_each(view, &output->server->views, link) { + struct ds_buffer *ds_buffer; + struct ds_tbm_client_buffer *tbm_buffer; + tbm_surface_h surface; + + if (!view->mapped) + continue; + + ds_buffer = ds_surface_get_buffer( + ds_xdg_surface_get_surface(view->xdg_surface)); + assert(ds_buffer); + + tbm_buffer = ds_tbm_client_buffer_from_buffer(ds_buffer); + assert(tbm_buffer); + + surface = ds_tbm_client_buffer_get_tbm_surface(tbm_buffer); + + renderer_add_texture(&output->renderer, surface, view->x, view->y); + + view_send_frame_done(view); + } + + ds_dbg("<< END UPDATE TEXTURES"); + + renderer_draw(&output->renderer); + +} +#else +static void +output_swapchain_init(struct tinyds_output *output, + int width, int height, uint32_t format); + +{ + output->allocator = ds_tbm_allocator_create(); + assert(output->allocator); + + output->swapchain = ds_swapchain_create(output->allocator, + width, height, format); + assert(output->swapchain); +} + +static void +output_draw_with_swapchain(struct tinyds_output *output) +{ + struct tinyds_view *view; + struct ds_buffer *output_buffer; + pixman_image_t *output_image; + + output_buffer = ds_swapchain_acquire(output->swapchain, NULL); + if (!output_buffer) + return; + + output_image = pixman_image_from_buffer(output_buffer, + DS_BUFFER_DATA_PTR_ACCESS_WRITE); + if (!output_image) { + ds_buffer_unlock(output_buffer); + return; + } + + pixman_image_fill_color(output_image, 80, 80, 80); + + wl_list_for_each(view, &output->server->views, link) { + if (!view->mapped) + continue; + draw_view(view, output_image); + } + pixman_image_unref(output_image); + + output_swap_buffer(output, output_buffer); +} + +static void +draw_view(struct tinyds_view *view, pixman_image_t *dst_image) +{ + struct ds_buffer *buffer; + pixman_image_t *src_image; + + buffer = ds_surface_get_buffer( + ds_xdg_surface_get_surface(view->xdg_surface)); + if (!buffer) + return; + + src_image = pixman_image_from_buffer(buffer, + DS_BUFFER_DATA_PTR_ACCESS_READ); + pixman_image_composite32(PIXMAN_OP_OVER, + src_image, + NULL, + dst_image, + 0, 0, 0, 0, + view->x, view->y, + pixman_image_get_width(src_image), + pixman_image_get_height(src_image)); + pixman_image_unref(src_image); + + view_send_frame_done(view); +} +#endif + +static void +draw_output(struct tinyds_output *output) +{ + + if (!output->drawable || !output->damaged) + return; + +#ifdef USE_TDM_BUFFER_QUEUE + output_draw_with_renderer(output); +#else + output_draw_with_swapchain(output); +#endif + + output->drawable = false; + output->damaged = false; +} + +static void +output_swap_buffer(struct tinyds_output *output, struct ds_buffer *buffer) +{ + ds_output_attach_buffer(output->ds_output, buffer); + ds_output_commit(output->ds_output); + + if (output->front_buffer) + ds_buffer_unlock(output->front_buffer); + output->front_buffer = buffer; +} + +static void +view_send_frame_done(struct tinyds_view *view) +{ + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + ds_surface_send_frame_done(ds_xdg_surface_get_surface(view->xdg_surface), + &now); +} + +static int +server_dispatch_stdin(int fd, uint32_t mask, void *data) +{ + struct tinyds_server *server = data; + + wl_display_terminate(server->display); + + return 1; +} + + +static void +keyboard_handle_device_destroy(struct wl_listener *listener, void *data) +{ + struct tinyds_keyboard *kbd; + + kbd = wl_container_of(listener, kbd, destroy); + + ds_inf("Keyboard(%p) destroyed", kbd); + + wl_list_remove(&kbd->destroy.link); + wl_list_remove(&kbd->key.link); + + free(kbd); +} + +static void +keyboard_handle_key(struct wl_listener *listener, void *data) +{ + struct tinyds_keyboard *kbd; + struct ds_event_keyboard_key *event = data; + + kbd = wl_container_of(listener, kbd, key); + + ds_inf("Keyboard(%p) event key: keycode(%d), state(%d), time_msec(%d), " + "update_state(%d)", kbd->dev, + event->keycode, event->state, event->time_msec, + event->update_state); + //TODO: + //ds_seat_keyboard_notify_key() +} + +static void +server_add_keyboard(struct tinyds_server *server, struct ds_input_device *dev) +{ + struct tinyds_keyboard *kbd; + + kbd = calloc(1, sizeof *kbd); + assert(kbd); + + kbd->dev = dev; + kbd->server = server; + + kbd->destroy.notify = keyboard_handle_device_destroy; + ds_input_device_add_destroy_listener(dev, &kbd->destroy); + + kbd->key.notify = keyboard_handle_key; + ds_keyboard_add_key_listener(ds_input_device_get_keyboard(dev), &kbd->key); + + ds_inf("Keyboard(%p) added", kbd); +} + +static struct tinyds_view * +server_view_at(struct tinyds_server *server, double lx, double ly, + double *sx, double *sy) +{ + struct tinyds_view *view; + struct ds_surface *surface; + struct ds_buffer *buffer; + int x, y, w = 0, h = 0; + + wl_list_for_each(view, &server->views, link) { + surface = ds_xdg_surface_get_surface(view->xdg_surface); + buffer = ds_surface_get_buffer(surface); + ds_buffer_get_size(buffer, &w, &h); + + x = view->x; + y = view->y; + + if (lx >= x && lx <= x + w && ly >= y && ly <= y + h) { + *sx = lx - x; + *sy = ly - y; + + return view; + } + } + + return NULL; +} + +static void +touch_handle_device_destroy(struct wl_listener *listener, void *data) +{ + struct tinyds_touch *touch; + + touch = wl_container_of(listener, touch, destroy); + + ds_inf("Touch(%p) destroyed", touch); + + wl_list_remove(&touch->destroy.link); + wl_list_remove(&touch->down.link); + wl_list_remove(&touch->up.link); + wl_list_remove(&touch->motion.link); + + free(touch); +} + +static void +touch_handle_down(struct wl_listener *listener, void *data) +{ + struct ds_event_touch_down *event = data; + struct tinyds_touch *touch; + struct tinyds_view *view; + struct tinyds_server *server; + double sx = 0.f, sy = 0.f; + + touch = wl_container_of(listener, touch, down); + + server = touch->server; + server->output_x = event->x * server->output->width; + server->output_y = event->y * server->output->height; + + ds_inf("Touch(%p) event down: id(%d) x %.3f y %.3f output_x %.1f output_y %.1f", + touch->dev, event->id, event->x, event->y, server->output_x, server->output_y); + + view = server_view_at(server, server->output_x, server->output_y, &sx, &sy); + + if (view) { + ds_seat_touch_notify_down(touch->server->seat, ds_xdg_surface_get_surface(view->xdg_surface), + event->time_msec, event->id, sx, sy); + } +} + +static void +touch_handle_up(struct wl_listener *listener, void *data) +{ + struct ds_event_touch_up *event = data; + struct tinyds_touch *touch; + + touch = wl_container_of(listener, touch, up); + + ds_inf("Touch(%p) event up: id(%d) time_msec(%d)", + touch->dev, event->id, event->time_msec); + + ds_seat_touch_notify_up(touch->server->seat, event->time_msec, event->id); +} + +static void +touch_handle_motion(struct wl_listener *listener, void *data) +{ + struct ds_event_touch_motion *event = data; + struct tinyds_touch *touch; + struct tinyds_view *view; + struct tinyds_server *server; + double sx = 0.f, sy = 0.f; + + touch = wl_container_of(listener, touch, motion); + + server = touch->server; + server->output_x = event->x * server->output->width; + server->output_y = event->y * server->output->height; + + ds_inf("Touch(%p) event motion: id(%d) x %.3f y %.3f output_x %.1f output_y %.1f", + touch->dev, event->id, event->x, event->y, server->output_x, server->output_y); + + view = server_view_at(server, server->output_x, server->output_y, &sx, &sy); + + if (view) { + ds_seat_touch_notify_motion(server->seat, event->time_msec, + event->id, sx, sy); + } +} + +static void +server_add_touch(struct tinyds_server *server, struct ds_input_device *dev) +{ + struct tinyds_touch *touch; + + touch = calloc(1, sizeof *touch); + assert(touch); + + touch->dev = dev; + touch->server = server; + + touch->destroy.notify = touch_handle_device_destroy; + ds_input_device_add_destroy_listener(dev, &touch->destroy); + + touch->down.notify = touch_handle_down; + ds_touch_add_down_listener(ds_input_device_get_touch(dev), &touch->down); + + touch->up.notify = touch_handle_up; + ds_touch_add_up_listener(ds_input_device_get_touch(dev), &touch->up); + + touch->motion.notify = touch_handle_motion; + ds_touch_add_motion_listener(ds_input_device_get_touch(dev), &touch->motion); + + ds_inf("Touch(%p) added", touch); +} + +static void +pointer_handle_device_destroy(struct wl_listener *listener, void *data) +{ + struct tinyds_pointer *pointer; + + pointer = wl_container_of(listener, pointer, destroy); + + ds_inf("Pointer(%p) destroyed", pointer); + + wl_list_remove(&pointer->destroy.link); + wl_list_remove(&pointer->motion.link); + wl_list_remove(&pointer->button.link); + wl_list_remove(&pointer->frame.link); + + free(pointer); +} + +static void +pointer_handle_motion(struct wl_listener *listener, void *data) +{ + struct tinyds_pointer *pointer; + struct ds_event_pointer_motion *event = data; + struct tinyds_view *view; + struct tinyds_server *server; + int ow = 0, oh = 0; + double sx, sy; + + pointer = wl_container_of(listener, pointer, motion); + + server = pointer->server; + if (server->output) { + ow = server->output->width; + oh = server->output->height; + } + + if (server->output_x + event->delta_x >= ow) + server->output_x = ow; + else if(server->output_x + event->delta_x <= 0.f) + server->output_x = 0.f; + else + server->output_x = server->output_x + event->delta_x ; + if (server->output_y + event->delta_y >= oh) + server->output_y = oh; + else if(server->output_y + event->delta_y <= 0.f) + server->output_y = 0.f; + else + server->output_y = server->output_y + event->delta_y ; + + ds_inf("Pointer(%p) motion: (delta_x %.1f delta_y %.1f) output_x %.1f output_y %.1f", + pointer, event->delta_x, event->delta_y, server->output_x, server->output_y); + + view = server_view_at(pointer->server, server->output_x, server->output_y, &sx, &sy); + + if (pointer->focused_view != view) { + if (pointer->focused_view) { + ds_inf("Clear pointer focus from view(%p)", pointer->focused_view); + ds_seat_pointer_notify_clear_focus(pointer->server->seat); + pointer->focused_view = NULL; + } + + if (view) { + ds_inf("Set pointer focus to view(%p)", view); + ds_seat_pointer_notify_enter(pointer->server->seat, + ds_xdg_surface_get_surface(view->xdg_surface), sx, sy); + pointer->focused_view = view; + } + } + + if (view) { + ds_seat_pointer_notify_motion(pointer->server->seat, + event->time_msec, sx, sy); + } +} + +static void +pointer_handle_button(struct wl_listener *listener, void *data) +{ + struct tinyds_pointer *pointer; + struct ds_event_pointer_button *event = data; + + pointer = wl_container_of(listener, pointer, button); + + ds_inf("Pointer(%p) button(%d): state(%s) time(%d)", + pointer, event->button, + (event->state == DS_BUTTON_PRESSED) ? "Pressed" : "Released", + event->time_msec); + + ds_seat_pointer_notify_button(pointer->server->seat, event->time_msec, event->button, event->state); +} + +static void +pointer_handle_frame(struct wl_listener *listener, void *data) +{ + struct tinyds_pointer *pointer; + + pointer = wl_container_of(listener, pointer, frame); + + ds_inf("Pointer(%p) frame", pointer); + ds_seat_pointer_notify_frame(pointer->server->seat); +} + +static void +server_add_pointer(struct tinyds_server *server, struct ds_input_device *dev) +{ + struct tinyds_pointer *pointer; + + pointer = calloc(1, sizeof *pointer); + assert(pointer); + + pointer->dev = dev; + pointer->server = server; + server->output_x = 200; + server->output_y = 200; + + pointer->destroy.notify = pointer_handle_device_destroy; + ds_input_device_add_destroy_listener(dev, &pointer->destroy); + + pointer->motion.notify = pointer_handle_motion; + ds_pointer_add_motion_listener(ds_input_device_get_pointer(dev), + &pointer->motion); + + pointer->button.notify = pointer_handle_button; + ds_pointer_add_button_listener(ds_input_device_get_pointer(dev), + &pointer->button); + + pointer->frame.notify = pointer_handle_frame; + ds_pointer_add_frame_listener(ds_input_device_get_pointer(dev), + &pointer->frame); + + ds_inf("Pointer(%p) added", pointer); +} -- 2.7.4