From 082ff4eb7b58a49d8270752308f38159ce80f18f Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Thu, 17 Mar 2022 16:40:37 +0900 Subject: [PATCH 01/16] Add an example of using ds_tdm_buffer_queue Dependeing on the declaration of USE_TDM_BUFFER_QUEUE macro, tinyds-tdm may be run with ds_tbm_buffer_queue. Change-Id: I1d221d2d5eb94024902eea66d08f5973f1914771 --- src/examples/meson.build | 3 + src/examples/pixman-helper.c | 5 +- src/examples/pixman-helper.h | 3 + src/examples/pixman-tbm-helper.c | 64 +++++++++++ src/examples/pixman-tbm-helper.h | 13 +++ src/examples/tbm-server-helper.c | 24 ++-- src/examples/tbm-server-helper.h | 6 + src/examples/tinyds-tdm-renderer.c | 187 ++++++++++++++++++++++++++++++ src/examples/tinyds-tdm-renderer.h | 48 ++++++++ src/examples/tinyds-tdm.c | 227 +++++++++++++++++++++++++++++-------- 10 files changed, 520 insertions(+), 60 deletions(-) create mode 100644 src/examples/pixman-tbm-helper.c create mode 100644 src/examples/pixman-tbm-helper.h create mode 100644 src/examples/tinyds-tdm-renderer.c create mode 100644 src/examples/tinyds-tdm-renderer.h diff --git a/src/examples/meson.build b/src/examples/meson.build index f95bd50..c60b610 100644 --- a/src/examples/meson.build +++ b/src/examples/meson.build @@ -35,8 +35,10 @@ if get_option('tizen') tinyds_tdm_files = [ 'tinyds-tdm.c', + 'tinyds-tdm-renderer.c', 'tbm-server-helper.c', 'pixman-helper.c', + 'pixman-tbm-helper.c', ] executable('tinyds-tdm', tinyds_tdm_files, @@ -46,6 +48,7 @@ if get_option('tizen') dependency('libdrm', required: true), dependency('libtbm', required: true), dependency('wayland-tbm-server', required: true), + dependency('threads', required: true), ], install_dir: libds_bindir, install : true diff --git a/src/examples/pixman-helper.c b/src/examples/pixman-helper.c index 5d42ec6..36a22e8 100644 --- a/src/examples/pixman-helper.c +++ b/src/examples/pixman-helper.c @@ -5,8 +5,6 @@ static void destroy_pixman_image(pixman_image_t *image, void *data); static uint32_t convert_drm_format_to_pixman(uint32_t fmt); -static pixman_color_t *color_rgb888(pixman_color_t *tmp, - uint8_t r, uint8_t g, uint8_t b); pixman_image_t * pixman_image_from_buffer(struct ds_buffer *buffer, @@ -37,7 +35,6 @@ pixman_image_from_buffer(struct ds_buffer *buffer, return image; } - void pixman_image_fill_color(pixman_image_t *image, uint8_t r, uint8_t g, uint8_t b) { @@ -56,7 +53,7 @@ pixman_image_fill_color(pixman_image_t *image, uint8_t r, uint8_t g, uint8_t b) pixman_image_unref(color_image); } -static pixman_color_t * +pixman_color_t * color_rgb888(pixman_color_t *tmp, uint8_t r, uint8_t g, uint8_t b) { tmp->alpha = 65535; diff --git a/src/examples/pixman-helper.h b/src/examples/pixman-helper.h index aa039ff..99ceaca 100644 --- a/src/examples/pixman-helper.h +++ b/src/examples/pixman-helper.h @@ -12,4 +12,7 @@ void pixman_image_fill_color(pixman_image_t *image, uint8_t r, uint8_t g, uint8_t b); +pixman_color_t * +color_rgb888(pixman_color_t *tmp, uint8_t r, uint8_t g, uint8_t b); + #endif diff --git a/src/examples/pixman-tbm-helper.c b/src/examples/pixman-tbm-helper.c new file mode 100644 index 0000000..710eceb --- /dev/null +++ b/src/examples/pixman-tbm-helper.c @@ -0,0 +1,64 @@ +#include + +#include "pixman-tbm-helper.h" + +static uint32_t convert_tbm_format_to_pixman(uint32_t fmt); +static void destroy_tbm_pixman_image(pixman_image_t *image, void *data); + +pixman_image_t * +pixman_image_from_tbm_surface(tbm_surface_h surface, + enum ds_buffer_data_ptr_access_flag access_flag) +{ + pixman_image_t *image; + tbm_surface_info_s info; + uint32_t format; + int tbm_access_flag = 0; + int width, height; + int ret; + + width = tbm_surface_get_width(surface); + height = tbm_surface_get_height(surface); + + if (access_flag & DS_BUFFER_DATA_PTR_ACCESS_READ) + tbm_access_flag |= TBM_OPTION_READ; + if (access_flag & DS_BUFFER_DATA_PTR_ACCESS_WRITE) + tbm_access_flag |= TBM_OPTION_WRITE; + + ret = tbm_surface_map(surface, tbm_access_flag, &info); + assert(ret == TBM_SURFACE_ERROR_NONE); + + format = convert_tbm_format_to_pixman(info.format); + image = pixman_image_create_bits(format, width, height, + (uint32_t *)info.planes[0].ptr, + info.planes[0].stride); + assert(image); + + tbm_surface_internal_ref(surface); + + pixman_image_set_destroy_function(image, + destroy_tbm_pixman_image, surface); + + return image; +} + +static void +destroy_tbm_pixman_image(pixman_image_t *image, void *data) +{ + tbm_surface_h surface = data; + + tbm_surface_unmap(surface); + tbm_surface_internal_unref(surface); +} + +static uint32_t +convert_tbm_format_to_pixman(uint32_t fmt) +{ + switch (fmt) { + case TBM_FORMAT_XRGB8888: + return PIXMAN_x8r8g8b8; + case TBM_FORMAT_ARGB8888: + return PIXMAN_a8r8g8b8; + default: + assert(0 && "not reached"); + } +} diff --git a/src/examples/pixman-tbm-helper.h b/src/examples/pixman-tbm-helper.h new file mode 100644 index 0000000..bf9bd55 --- /dev/null +++ b/src/examples/pixman-tbm-helper.h @@ -0,0 +1,13 @@ +#ifndef EXAMPLES_PIXMAN_TBM_HELPER_H +#define EXAMPLES_PIXMAN_TBM_HELPER_H + +#include +#include +#include +#include + +pixman_image_t * +pixman_image_from_tbm_surface(tbm_surface_h surface, + enum ds_buffer_data_ptr_access_flag access_flag); + +#endif diff --git a/src/examples/tbm-server-helper.c b/src/examples/tbm-server-helper.c index bd3a34d..320ee4f 100644 --- a/src/examples/tbm-server-helper.c +++ b/src/examples/tbm-server-helper.c @@ -8,6 +8,8 @@ #include static const struct ds_buffer_resource_interface tbm_buffer_resource_iface; +static const struct ds_buffer_interface tbm_client_buffer_iface; + static void tbm_server_handle_display_destroy(struct wl_listener *listener, void *data); static struct tbm_client_buffer * @@ -42,6 +44,19 @@ tbm_server_init_display(struct tbm_server *tbm, struct wl_display *display) return true; } +struct tbm_client_buffer * +tbm_client_buffer_from_buffer(struct ds_buffer *ds_buffer) +{ + assert(ds_buffer->iface == &tbm_client_buffer_iface); + return (struct tbm_client_buffer *)ds_buffer; +} + +tbm_surface_h +tbm_client_buffer_get_tbm_surface(struct tbm_client_buffer *buffer) +{ + return buffer->surface; +} + static void tbm_server_handle_display_destroy(struct wl_listener *listener, void *data) { @@ -107,15 +122,6 @@ static const struct ds_buffer_resource_interface tbm_buffer_resource_iface = { .from_resource = tbm_buffer_resource_iface_from_resource, }; -static const struct ds_buffer_interface tbm_client_buffer_iface; - -static struct tbm_client_buffer * -tbm_client_buffer_from_buffer(struct ds_buffer *ds_buffer) -{ - assert(ds_buffer->iface == &tbm_client_buffer_iface); - return (struct tbm_client_buffer *)ds_buffer; -} - static void tbm_client_buffer_destroy(struct ds_buffer *ds_buffer) { diff --git a/src/examples/tbm-server-helper.h b/src/examples/tbm-server-helper.h index a82ad5b..609f370 100644 --- a/src/examples/tbm-server-helper.h +++ b/src/examples/tbm-server-helper.h @@ -32,4 +32,10 @@ bool tbm_server_init_display(struct tbm_server *tbm_server, struct wl_display *display); +struct tbm_client_buffer * +tbm_client_buffer_from_buffer(struct ds_buffer *ds_buffer); + +tbm_surface_h +tbm_client_buffer_get_tbm_surface(struct tbm_client_buffer *buffer); + #endif diff --git a/src/examples/tinyds-tdm-renderer.c b/src/examples/tinyds-tdm-renderer.c new file mode 100644 index 0000000..0074dc9 --- /dev/null +++ b/src/examples/tinyds-tdm-renderer.c @@ -0,0 +1,187 @@ +#include +#include + +#include + +#include "pixman-helper.h" +#include "pixman-tbm-helper.h" +#include "tinyds-tdm-renderer.h" + +static void renderer_setup_thread(struct tinyds_renderer *renderer); +static void *renderer_thread_func(void *data); +static void texture_destroy(struct tinyds_texture *texture); + +bool +init_renderer(struct tinyds_renderer *renderer) +{ + renderer->damaged = false; + + wl_list_init(&renderer->textures); + + renderer_setup_thread(renderer); + + return true; +} + +void +fini_renderer(struct tinyds_renderer *renderer) +{ + pthread_mutex_lock(&renderer->mutex); + + renderer->destroying = true; + pthread_cond_signal(&renderer->cond); + + pthread_mutex_unlock(&renderer->mutex); + + pthread_join(renderer->worker_thread, NULL); + + pthread_mutex_destroy(&renderer->mutex); + pthread_cond_destroy(&renderer->cond); +} + +void +renderer_set_surface_queue(struct tinyds_renderer *renderer, + void *surface_queue) +{ + pthread_mutex_lock(&renderer->mutex); + + renderer->surface_queue = (tbm_surface_queue_h)surface_queue; + + pthread_mutex_unlock(&renderer->mutex); +} + +void +renderer_set_bg_color(struct tinyds_renderer *renderer, + uint8_t r, uint8_t g, uint8_t b) +{ + pixman_color_t color; + + pthread_mutex_lock(&renderer->mutex); + + color_rgb888(&color, r, g, b); + + renderer->bg_image = pixman_image_create_solid_fill(&color); + assert(renderer->bg_image); + + renderer->damaged = true; + + pthread_mutex_unlock(&renderer->mutex); +} + +void +renderer_add_texture(struct tinyds_renderer *renderer, + tbm_surface_h tbm_surface, int x, int y) +{ + struct tinyds_texture *texture; + + pthread_mutex_lock(&renderer->mutex); + + texture = calloc(1, sizeof *texture); + + texture->x = x; + texture->y = y; + texture->renderer = renderer; + texture->surface = tbm_surface; + texture->image = pixman_image_from_tbm_surface(tbm_surface, + DS_BUFFER_DATA_PTR_ACCESS_READ); + + wl_list_insert(renderer->textures.prev, &texture->link); + + ds_dbg("Add texture(%p)", texture); + + pthread_mutex_unlock(&renderer->mutex); +} + +void +renderer_draw(struct tinyds_renderer *renderer) +{ + pthread_mutex_lock(&renderer->mutex); + + renderer->damaged = true; + pthread_cond_signal(&renderer->cond); + + pthread_mutex_unlock(&renderer->mutex); +} + +static void +renderer_setup_thread(struct tinyds_renderer *renderer) +{ + pthread_mutex_init(&renderer->mutex, NULL); + pthread_cond_init(&renderer->cond, NULL); + pthread_create(&renderer->worker_thread, NULL, + renderer_thread_func, renderer); +} + +static void * +renderer_thread_func(void *data) +{ + struct tinyds_renderer *renderer = data; + struct tinyds_texture *texture, *texture_tmp; + pixman_image_t *dst_image; + tbm_surface_h surface; + tbm_surface_queue_error_e err; + + pthread_mutex_lock(&renderer->mutex); + + while (!renderer->destroying) { + if (!renderer->damaged) + pthread_cond_wait(&renderer->cond, &renderer->mutex); + + if (!renderer->damaged) + continue; + + if (!tbm_surface_queue_can_dequeue(renderer->surface_queue, 0)) + continue; + + ds_dbg(">> BEGIN DRAW"); + + err = tbm_surface_queue_dequeue(renderer->surface_queue, &surface); + assert(err == TBM_SURFACE_QUEUE_ERROR_NONE); + + dst_image = pixman_image_from_tbm_surface(surface, + DS_BUFFER_DATA_PTR_ACCESS_WRITE); + + if (renderer->bg_image) { + pixman_image_composite32(PIXMAN_OP_SRC, + renderer->bg_image, + NULL, + dst_image, + 0, 0, 0, 0, 0, 0, + pixman_image_get_width(dst_image), + pixman_image_get_height(dst_image)); + } + + wl_list_for_each_safe(texture, texture_tmp, &renderer->textures, link) { + ds_dbg("Draw texture(%p)", texture); + pixman_image_composite32(PIXMAN_OP_OVER, + texture->image, + NULL, + dst_image, + 0, 0, 0, 0, + texture->x, texture->y, + pixman_image_get_width(texture->image), + pixman_image_get_height(texture->image)); + texture_destroy(texture); + } + pixman_image_unref(dst_image); + + err = tbm_surface_queue_enqueue(renderer->surface_queue, surface); + assert(err == TBM_SURFACE_QUEUE_ERROR_NONE); + + renderer->damaged = false; + + ds_dbg("<< END DRAW"); + } + + pthread_mutex_unlock(&renderer->mutex); + + return NULL; +} + +static void +texture_destroy(struct tinyds_texture *texture) +{ + pixman_image_unref(texture->image); + wl_list_remove(&texture->link); + free(texture); +} diff --git a/src/examples/tinyds-tdm-renderer.h b/src/examples/tinyds-tdm-renderer.h new file mode 100644 index 0000000..5f3e6fd --- /dev/null +++ b/src/examples/tinyds-tdm-renderer.h @@ -0,0 +1,48 @@ +#ifndef EXAMPLES_TINYDS_TDM_RENDERER_H +#define EXAMPLES_TINYDS_TDM_RENDERER_H + +#include +#include +#include +#include +#include + +struct tinyds_renderer +{ + tbm_surface_queue_h surface_queue; + + struct wl_list textures; + + pthread_t worker_thread; + pthread_mutex_t mutex; + pthread_cond_t cond; + + pixman_image_t *bg_image; + + bool damaged; + bool destroying; +}; + +struct tinyds_texture +{ + struct tinyds_renderer *renderer; + pixman_image_t *image; + tbm_surface_h surface; + + struct wl_list link; + struct wl_listener buffer_destroy; + + int x, y; +}; + +bool init_renderer(struct tinyds_renderer *renderer); +void fini_renderer(struct tinyds_renderer *renderer); +void renderer_set_surface_queue(struct tinyds_renderer *renderer, + void *surface_queue); +void renderer_set_bg_color(struct tinyds_renderer *renderer, + uint8_t r, uint8_t g, uint8_t b); +void renderer_add_texture(struct tinyds_renderer *renderer, + tbm_surface_h tbm_surface, int x, int y); +void renderer_draw(struct tinyds_renderer *renderer); + +#endif diff --git a/src/examples/tinyds-tdm.c b/src/examples/tinyds-tdm.c index 143d53e..6ec1156 100644 --- a/src/examples/tinyds-tdm.c +++ b/src/examples/tinyds-tdm.c @@ -1,6 +1,3 @@ -#include "tbm-server-helper.h" -#include "pixman-helper.h" - #include #include #include @@ -14,12 +11,23 @@ #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 "tbm-server-helper.h" +#include "pixman-helper.h" + #define TINYDS_UNUSED __attribute__((unused)) struct tinyds_output @@ -27,7 +35,13 @@ 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; @@ -62,6 +76,7 @@ struct tinyds_view { struct tinyds_server *server; + struct tinyds_texture *texture; struct ds_xdg_surface *xdg_surface; struct wl_listener xdg_surface_map; @@ -82,7 +97,18 @@ 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); +static void output_draw_with_swapchain(struct tinyds_output *output); static void draw_view(struct tinyds_view *view, pixman_image_t *dst_image); +#endif int main(void) @@ -150,10 +176,10 @@ 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); - - draw_server_with_damage(view->server); + server = view->server; wl_list_remove(&view->xdg_surface_destroy.link); wl_list_remove(&view->xdg_surface_map.link); @@ -161,6 +187,8 @@ view_handle_xdg_surface_destroy(struct wl_listener *listener, wl_list_remove(&view->surface_commit.link); wl_list_remove(&view->link); free(view); + + draw_server_with_damage(server); } static void @@ -237,32 +265,25 @@ backend_handle_new_output(struct wl_listener *listener, void *data) if (!output) return; - output->allocator = ds_tbm_allocator_create(); - if (!output->allocator) { - free(output); - return; - } - - output->swapchain = ds_swapchain_create(output->allocator, - mode->width, mode->height, DRM_FORMAT_XRGB8888); - if (!output->swapchain) { - ds_allocator_destroy(output->allocator); - free(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); +#endif + output->output_destroy.notify = output_handle_destroy; - ds_output_add_destroy_listener(ds_output, - &output->output_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); + ds_output_add_frame_listener(ds_output, &output->output_frame); server->output = output; @@ -318,11 +339,15 @@ output_handle_destroy(struct wl_listener *listener, void *data TINYDS_UNUSED) 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); @@ -348,15 +373,102 @@ draw_server_with_damage(struct tinyds_server *server) draw_output(server->output); } +#ifdef USE_TDM_BUFFER_QUEUE static void -draw_output(struct tinyds_output *output) +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 ds_buffer *output_buffer; - pixman_image_t *output_image; struct tinyds_view *view; - if (!output->drawable || !output->damaged) - return; + ds_dbg(">> BEGIN UPDATE TEXTURES"); + + wl_list_for_each(view, &output->server->views, link) { + struct ds_buffer *ds_buffer; + struct tbm_client_buffer *buffer; + tbm_surface_h surface; + + if (!view->mapped) + continue; + + ds_buffer = ds_surface_get_buffer( + ds_xdg_surface_get_surface(view->xdg_surface)); + assert(buffer); + + buffer = tbm_client_buffer_from_buffer(ds_buffer); + assert(buffer); + + surface = tbm_client_buffer_get_tbm_surface(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) +{ + output->allocator = ds_tbm_allocator_create(); + assert(output->allocator); + + output->swapchain = ds_swapchain_create(output->allocator, + mode->width, mode->height, DRM_FORMAT_XRGB8888); + 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) @@ -378,24 +490,7 @@ draw_output(struct tinyds_output *output) } pixman_image_unref(output_image); - ds_output_attach_buffer(output->ds_output, output_buffer); - ds_output_commit(output->ds_output); - - if (output->front_buffer) - ds_buffer_unlock(output->front_buffer); - output->front_buffer = output_buffer; - - output->drawable = false; - output->damaged = false; -} - -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); + output_swap_buffer(output, output_buffer); } static void @@ -423,6 +518,44 @@ draw_view(struct tinyds_view *view, pixman_image_t *dst_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) -- 2.7.4 From 43c51b3bee4ee7bf17cdba0cff235ebb21554234 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Thu, 17 Mar 2022 19:52:29 +0900 Subject: [PATCH 02/16] Fix typo on a word of header guard Change-Id: Ie18d91a7868efa6b13175693d4f9a99c2481d09e --- src/libds-tizen/backend/tdm/tdm_buffer_queue.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libds-tizen/backend/tdm/tdm_buffer_queue.h b/src/libds-tizen/backend/tdm/tdm_buffer_queue.h index 774b7c3..a983265 100644 --- a/src/libds-tizen/backend/tdm/tdm_buffer_queue.h +++ b/src/libds-tizen/backend/tdm/tdm_buffer_queue.h @@ -1,5 +1,5 @@ #ifndef DS_TIZEN_BACKEND_TDM_BUFFER_QUEUE_H -#define DS_TIZEN_BACKEND_TBM_BUFFER_QUEUE_H +#define DS_TIZEN_BACKEND_TDM_BUFFER_QUEUE_H #include #include -- 2.7.4 From 3009fac9ea49a2ed4b041128a259e6e47a1ca275 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Mon, 28 Mar 2022 20:03:20 +0900 Subject: [PATCH 03/16] Add ds_tbm_server ds_tbm_server initializes wayland_tbm to allow wl_client to use tbm_surface as a wl_buffer. Change-Id: Ic3a450b6d450bad94388eeca5e9433b5dc799513 --- include/libds-tizen/tbm_server.h | 24 +++ src/examples/meson.build | 6 +- src/examples/tbm-server-helper.h | 41 ----- src/examples/tinyds-tdm.c | 23 ++- src/libds-tizen/meson.build | 8 +- src/libds-tizen/pixel_format.c | 61 ++++++ src/libds-tizen/pixel_format.h | 10 + .../tbm_server.c} | 204 ++++++++++++--------- src/libds-tizen/tbm_server.h | 34 ++++ 9 files changed, 272 insertions(+), 139 deletions(-) create mode 100644 include/libds-tizen/tbm_server.h delete mode 100644 src/examples/tbm-server-helper.h create mode 100644 src/libds-tizen/pixel_format.c create mode 100644 src/libds-tizen/pixel_format.h rename src/{examples/tbm-server-helper.c => libds-tizen/tbm_server.c} (66%) create mode 100644 src/libds-tizen/tbm_server.h diff --git a/include/libds-tizen/tbm_server.h b/include/libds-tizen/tbm_server.h new file mode 100644 index 0000000..c48977e --- /dev/null +++ b/include/libds-tizen/tbm_server.h @@ -0,0 +1,24 @@ +#ifndef LIBDS_TIZEN_TBM_SERVER_H +#define LIBDS_TIZEN_TBM_SERVER_H + +#include +#include + +struct ds_tbm_server; + +struct ds_tbm_client_buffer; + +struct ds_tbm_server * +ds_tbm_server_create(struct wl_display *display); + +void +ds_tbm_server_add_destroy_listener(struct ds_tbm_server *tbm, + struct wl_listener *listener); + +struct ds_tbm_client_buffer * +ds_tbm_client_buffer_from_buffer(struct ds_buffer *ds_buffer); + +tbm_surface_h +ds_tbm_client_buffer_get_tbm_surface(struct ds_tbm_client_buffer *buffer); + +#endif diff --git a/src/examples/meson.build b/src/examples/meson.build index c60b610..ddb0792 100644 --- a/src/examples/meson.build +++ b/src/examples/meson.build @@ -35,19 +35,15 @@ if get_option('tizen') tinyds_tdm_files = [ 'tinyds-tdm.c', - 'tinyds-tdm-renderer.c', - 'tbm-server-helper.c', 'pixman-helper.c', 'pixman-tbm-helper.c', + 'tinyds-tdm-renderer.c', ] executable('tinyds-tdm', tinyds_tdm_files, dependencies: [ common_deps, dependency('pixman-1', required: true), - dependency('libdrm', required: true), - dependency('libtbm', required: true), - dependency('wayland-tbm-server', required: true), dependency('threads', required: true), ], install_dir: libds_bindir, diff --git a/src/examples/tbm-server-helper.h b/src/examples/tbm-server-helper.h deleted file mode 100644 index 609f370..0000000 --- a/src/examples/tbm-server-helper.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef EXAMPLES_TBM_SERVER_H -#define EXAMPLES_TBM_SERVER_H - -#include -#include -#include -#include -#include - -struct tbm_server -{ - struct wayland_tbm_server *wl_tbm; - - struct wl_listener display_destroy; -}; - -struct tbm_client_buffer -{ - struct ds_buffer base; - - tbm_surface_h surface; - struct wl_resource *resource; - - struct wl_listener buffer_release; - struct wl_listener resource_destroy; - - uint32_t format; - size_t stride; -}; - -bool -tbm_server_init_display(struct tbm_server *tbm_server, - struct wl_display *display); - -struct tbm_client_buffer * -tbm_client_buffer_from_buffer(struct ds_buffer *ds_buffer); - -tbm_surface_h -tbm_client_buffer_get_tbm_surface(struct tbm_client_buffer *buffer); - -#endif diff --git a/src/examples/tinyds-tdm.c b/src/examples/tinyds-tdm.c index 6ec1156..c14cb9e 100644 --- a/src/examples/tinyds-tdm.c +++ b/src/examples/tinyds-tdm.c @@ -15,6 +15,7 @@ #include #include #include +#include #define USE_TDM_BUFFER_QUEUE @@ -25,7 +26,6 @@ #include #endif -#include "tbm-server-helper.h" #include "pixman-helper.h" #define TINYDS_UNUSED __attribute__((unused)) @@ -55,7 +55,7 @@ struct tinyds_output struct tinyds_server { - struct tbm_server tbm_server; + struct ds_tbm_server *tbm_server; struct wl_display *display; @@ -127,9 +127,6 @@ main(void) res = init_server(server, display); assert(res); - res = tbm_server_init_display(&server->tbm_server, display); - assert(res); - socket = wl_display_add_socket_auto(display); assert(socket); @@ -314,6 +311,12 @@ init_server(struct tinyds_server *server, struct wl_display *display) return false; } + server->tbm_server = ds_tbm_server_create(display); + if (!server->tbm_server) { + ds_backend_destroy(server->backend); + return false; + } + server->xdg_shell = ds_xdg_shell_create(display); if (!server->xdg_shell) { ds_backend_destroy(server->backend); @@ -426,7 +429,7 @@ output_draw_with_renderer(struct tinyds_output *output) wl_list_for_each(view, &output->server->views, link) { struct ds_buffer *ds_buffer; - struct tbm_client_buffer *buffer; + struct ds_tbm_client_buffer *tbm_buffer; tbm_surface_h surface; if (!view->mapped) @@ -434,12 +437,12 @@ output_draw_with_renderer(struct tinyds_output *output) ds_buffer = ds_surface_get_buffer( ds_xdg_surface_get_surface(view->xdg_surface)); - assert(buffer); + assert(ds_buffer); - buffer = tbm_client_buffer_from_buffer(ds_buffer); - assert(buffer); + tbm_buffer = ds_tbm_client_buffer_from_buffer(ds_buffer); + assert(tbm_buffer); - surface = tbm_client_buffer_get_tbm_surface(buffer); + surface = ds_tbm_client_buffer_get_tbm_surface(tbm_buffer); renderer_add_texture(&output->renderer, surface, view->x, view->y); diff --git a/src/libds-tizen/meson.build b/src/libds-tizen/meson.build index e9ca734..4f76b68 100644 --- a/src/libds-tizen/meson.build +++ b/src/libds-tizen/meson.build @@ -1,7 +1,13 @@ -libds_tizen_files = [] +libds_tizen_files = [ + 'pixel_format.c', + 'tbm_server.c', +] libds_tizen_deps = [ dep_libds, + dependency('libdrm', required: true), + dependency('libtbm', required: true), + dependency('wayland-tbm-server', required: true), ] subdir('allocator') diff --git a/src/libds-tizen/pixel_format.c b/src/libds-tizen/pixel_format.c new file mode 100644 index 0000000..021652e --- /dev/null +++ b/src/libds-tizen/pixel_format.c @@ -0,0 +1,61 @@ +#include +#include +#include + +#include "libds/log.h" +#include "pixel_format.h" + +#ifdef ARRAY_LENGTH +#undef ARRAY_LENGTH +#endif + +#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) + +struct ds_tbm_format +{ + uint32_t drm_format; + uint32_t tbm_format; +}; + +static const struct ds_tbm_format formats[] = +{ + { + .drm_format = DRM_FORMAT_ARGB8888, + .tbm_format = TBM_FORMAT_ARGB8888, + }, + { + .drm_format = DRM_FORMAT_XRGB8888, + .tbm_format = TBM_FORMAT_XRGB8888, + }, + /* TODO more format */ +}; + +uint32_t +convert_drm_format_to_tbm(uint32_t fmt) +{ + size_t i; + + for (i = 0; i < ARRAY_LENGTH(formats); i++) { + if (formats[i].drm_format == fmt) + return formats[i].tbm_format; + } + + ds_err("DRM format 0x%"PRIX32" has no TBM equivalent", fmt); + + return 0; +} + +uint32_t +convert_tbm_format_to_drm(uint32_t fmt) +{ + size_t i; + + for (i = 0; i < ARRAY_LENGTH(formats); i++) { + if (formats[i].tbm_format == fmt) + return formats[i].drm_format; + } + + ds_err("TBM format 0x%"PRIX32" has no DRM equivalent", fmt); + + return 0; +} diff --git a/src/libds-tizen/pixel_format.h b/src/libds-tizen/pixel_format.h new file mode 100644 index 0000000..a63d096 --- /dev/null +++ b/src/libds-tizen/pixel_format.h @@ -0,0 +1,10 @@ +#ifndef DS_TIZEN_PIXEL_FORMAT_H +#define DS_TIZEN_PIXEL_FORMAT_H + +#include + +uint32_t convert_drm_format_to_tbm(uint32_t fmt); + +uint32_t convert_tbm_format_to_drm(uint32_t fmt); + +#endif diff --git a/src/examples/tbm-server-helper.c b/src/libds-tizen/tbm_server.c similarity index 66% rename from src/examples/tbm-server-helper.c rename to src/libds-tizen/tbm_server.c index 320ee4f..ecb46db 100644 --- a/src/examples/tbm-server-helper.c +++ b/src/libds-tizen/tbm_server.c @@ -1,82 +1,111 @@ -#include "tbm-server-helper.h" - #include #include #include -#include + #include -#include + +#include "libds/log.h" +#include "pixel_format.h" +#include "tbm_server.h" static const struct ds_buffer_resource_interface tbm_buffer_resource_iface; static const struct ds_buffer_interface tbm_client_buffer_iface; static void tbm_server_handle_display_destroy(struct wl_listener *listener, void *data); -static struct tbm_client_buffer * -tbm_client_buffer_create(struct wl_resource *resource); -bool -tbm_server_init_display(struct tbm_server *tbm, struct wl_display *display) +WL_EXPORT struct ds_tbm_server * +ds_tbm_server_create(struct wl_display *display) { + struct ds_tbm_server *tbm; tbm_bufmgr bufmgr; + tbm = calloc(1, sizeof *tbm); + if (!tbm) + return NULL; + + wl_signal_init(&tbm->events.destroy); + tbm->wl_tbm = wayland_tbm_server_init(display, NULL, -1, 0); if (!tbm->wl_tbm) { - return false; + goto err_wl_tbm; } bufmgr = wayland_tbm_server_get_bufmgr(tbm->wl_tbm); if (!bufmgr) { - wayland_tbm_server_deinit(tbm->wl_tbm); - return false; + goto err_bind; } if (!tbm_bufmgr_bind_native_display(bufmgr, (void *)display)) { - wayland_tbm_server_deinit(tbm->wl_tbm); - return false; + goto err_bind; } - ds_buffer_register_resource_interface(&tbm_buffer_resource_iface); - tbm->display_destroy.notify = tbm_server_handle_display_destroy; wl_display_add_destroy_listener(display, &tbm->display_destroy); - return true; + ds_buffer_register_resource_interface(&tbm_buffer_resource_iface); + + return tbm; + +err_bind: + wayland_tbm_server_deinit(tbm->wl_tbm); +err_wl_tbm: + free(tbm); + + return NULL; } -struct tbm_client_buffer * -tbm_client_buffer_from_buffer(struct ds_buffer *ds_buffer) +WL_EXPORT void +ds_tbm_server_add_destroy_listener(struct ds_tbm_server *tbm, + struct wl_listener *listener) { - assert(ds_buffer->iface == &tbm_client_buffer_iface); - return (struct tbm_client_buffer *)ds_buffer; + wl_signal_add(&tbm->events.destroy, listener); +} + +WL_EXPORT struct ds_tbm_client_buffer * +ds_tbm_client_buffer_from_buffer(struct ds_buffer *ds_buffer) +{ + if (ds_buffer->iface != &tbm_client_buffer_iface) + return NULL; + return (struct ds_tbm_client_buffer *)ds_buffer; } -tbm_surface_h -tbm_client_buffer_get_tbm_surface(struct tbm_client_buffer *buffer) +WL_EXPORT tbm_surface_h +ds_tbm_client_buffer_get_tbm_surface(struct ds_tbm_client_buffer *buffer) { + if (buffer->base.iface != &tbm_client_buffer_iface) + return NULL; return buffer->surface; } static void tbm_server_handle_display_destroy(struct wl_listener *listener, void *data) { - struct tbm_server *tbm; + struct ds_tbm_server *tbm; tbm = wl_container_of(listener, tbm, display_destroy); + + wl_signal_emit(&tbm->events.destroy, tbm); + wayland_tbm_server_deinit(tbm->wl_tbm); + free(tbm); } -static bool -tbm_buffer_resource_iface_is_instance(struct wl_resource *resource) +static void +tbm_client_buffer_handle_release(struct wl_listener *listener, void *data) { - return !!wayland_tbm_server_get_surface(NULL, resource); + struct ds_tbm_client_buffer *buffer; + + buffer = wl_container_of(listener, buffer, buffer_release); + if (buffer->resource) + wl_buffer_send_release(buffer->resource); } static void tbm_client_buffer_handle_resource_destroy(struct wl_listener *listener, void *data) { - struct tbm_client_buffer *buffer; + struct ds_tbm_client_buffer *buffer; buffer = wl_container_of(listener, buffer, resource_destroy); @@ -88,44 +117,17 @@ tbm_client_buffer_handle_resource_destroy(struct wl_listener *listener, ds_buffer_drop(&buffer->base); } -static struct tbm_client_buffer * -tbm_client_buffer_get_or_create(struct wl_resource *resource) -{ - struct tbm_client_buffer *buffer; - struct wl_listener *resource_destroy_listener; - - resource_destroy_listener = wl_resource_get_destroy_listener(resource, - tbm_client_buffer_handle_resource_destroy);; - if (resource_destroy_listener) { - buffer = wl_container_of(resource_destroy_listener, - buffer, resource_destroy); - return buffer; - } - - return tbm_client_buffer_create(resource); -} - -static struct ds_buffer * -tbm_buffer_resource_iface_from_resource(struct wl_resource *resource) +static struct ds_tbm_client_buffer * +tbm_client_buffer_from_buffer(struct ds_buffer *ds_buffer) { - struct tbm_client_buffer *buffer; - - buffer = tbm_client_buffer_get_or_create(resource); - assert(buffer); - - return &buffer->base; + assert(ds_buffer->iface == &tbm_client_buffer_iface); + return (struct ds_tbm_client_buffer *)ds_buffer; } -static const struct ds_buffer_resource_interface tbm_buffer_resource_iface = { - .name = "tbm", - .is_instance = tbm_buffer_resource_iface_is_instance, - .from_resource = tbm_buffer_resource_iface_from_resource, -}; - static void -tbm_client_buffer_destroy(struct ds_buffer *ds_buffer) +tbm_client_buffer_iface_destroy(struct ds_buffer *ds_buffer) { - struct tbm_client_buffer *buffer; + struct ds_tbm_client_buffer *buffer; buffer = tbm_client_buffer_from_buffer(ds_buffer); @@ -137,11 +139,11 @@ tbm_client_buffer_destroy(struct ds_buffer *ds_buffer) } static bool -tbm_client_buffer_begin_data_ptr_access(struct ds_buffer *ds_buffer, +tbm_client_buffer_iface_begin_data_ptr_access(struct ds_buffer *ds_buffer, enum ds_buffer_data_ptr_access_flag flags, void **data, uint32_t *format, size_t *stride) { - struct tbm_client_buffer *buffer; + struct ds_tbm_client_buffer *buffer; tbm_surface_info_s info; tbm_bo_access_option op = TBM_OPTION_NONE; int err; @@ -160,7 +162,7 @@ tbm_client_buffer_begin_data_ptr_access(struct ds_buffer *ds_buffer, return false; } - *format = DRM_FORMAT_XRGB8888; // FIXME + *format = convert_tbm_format_to_drm(buffer->format); *stride = info.planes[0].stride; *data = info.planes[0].ptr; @@ -168,9 +170,9 @@ tbm_client_buffer_begin_data_ptr_access(struct ds_buffer *ds_buffer, } static void -tbm_client_buffer_end_data_ptr_access(struct ds_buffer *ds_buffer) +tbm_client_buffer_iface_end_ptr_access(struct ds_buffer *ds_buffer) { - struct tbm_client_buffer *buffer; + struct ds_tbm_client_buffer *buffer; buffer = tbm_client_buffer_from_buffer(ds_buffer); @@ -178,36 +180,31 @@ tbm_client_buffer_end_data_ptr_access(struct ds_buffer *ds_buffer) } static const struct ds_buffer_interface tbm_client_buffer_iface = { - .destroy = tbm_client_buffer_destroy, - .begin_data_ptr_access = tbm_client_buffer_begin_data_ptr_access, - .end_data_ptr_access = tbm_client_buffer_end_data_ptr_access, + .destroy = tbm_client_buffer_iface_destroy, + .begin_data_ptr_access = tbm_client_buffer_iface_begin_data_ptr_access, + .end_data_ptr_access = tbm_client_buffer_iface_end_ptr_access, }; -static void -tbm_client_buffer_handle_release(struct wl_listener *listener, void *data) -{ - struct tbm_client_buffer *buffer; - - buffer = wl_container_of(listener, buffer, buffer_release); - if (buffer->resource) - wl_buffer_send_release(buffer->resource); -} - -static struct tbm_client_buffer * +static struct ds_tbm_client_buffer * tbm_client_buffer_create(struct wl_resource *resource) { - struct tbm_client_buffer *buffer; + struct ds_tbm_client_buffer *buffer; tbm_surface_h surface; int32_t width, height; surface = wayland_tbm_server_get_surface(NULL, resource); - assert(surface); + if (!surface) { + ds_err("Could not get tbm_surface from wl_resource@%d", + wl_resource_get_id(resource)); + return NULL; + } width = tbm_surface_get_width(surface); height = tbm_surface_get_height(surface); buffer = calloc(1, sizeof *buffer); - assert(buffer); + if (!buffer) + return NULL; ds_buffer_init(&buffer->base, &tbm_client_buffer_iface, width, height); @@ -226,3 +223,46 @@ tbm_client_buffer_create(struct wl_resource *resource) return buffer; } + +static struct ds_tbm_client_buffer * +tbm_client_buffer_get_or_create(struct wl_resource *resource) +{ + struct ds_tbm_client_buffer *buffer; + struct wl_listener *resource_destroy_listener; + + resource_destroy_listener = wl_resource_get_destroy_listener(resource, + tbm_client_buffer_handle_resource_destroy);; + if (resource_destroy_listener) { + buffer = wl_container_of(resource_destroy_listener, + buffer, resource_destroy); + return buffer; + } + + return tbm_client_buffer_create(resource); +} + +static bool +tbm_buffer_resource_iface_is_instance(struct wl_resource *resource) +{ + return !!wayland_tbm_server_get_surface(NULL, resource); +} + +static struct ds_buffer * +tbm_buffer_resource_iface_from_resource(struct wl_resource *resource) +{ + struct ds_tbm_client_buffer *buffer; + + buffer = tbm_client_buffer_get_or_create(resource); + if (!buffer) { + ds_err("Could not get or create ds_tbm_client_buffer"); + return NULL; + } + + return &buffer->base; +} + +static const struct ds_buffer_resource_interface tbm_buffer_resource_iface = { + .name = "tbm", + .is_instance = tbm_buffer_resource_iface_is_instance, + .from_resource = tbm_buffer_resource_iface_from_resource, +}; diff --git a/src/libds-tizen/tbm_server.h b/src/libds-tizen/tbm_server.h new file mode 100644 index 0000000..be56746 --- /dev/null +++ b/src/libds-tizen/tbm_server.h @@ -0,0 +1,34 @@ +#ifndef DS_TIZEN_TBM_SERVER_H +#define DS_TIZEN_TBM_SERVER_H + +#include +#include +#include +#include "libds/interfaces/buffer.h" + +struct ds_tbm_server +{ + struct wayland_tbm_server *wl_tbm; + + struct wl_listener display_destroy; + + struct { + struct wl_signal destroy; + } events; +}; + +struct ds_tbm_client_buffer +{ + struct ds_buffer base; + + tbm_surface_h surface; + struct wl_resource *resource; + + struct wl_listener buffer_release; + struct wl_listener resource_destroy; + + uint32_t format; + size_t stride; +}; + +#endif -- 2.7.4 From de85e1d57eb3b1ec7f8ff04a877b335ea99bca54 Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Wed, 30 Mar 2022 16:44:45 +0900 Subject: [PATCH 04/16] add extern 'C' at tbm_server.h Change-Id: Ida5b0215bcfd753f124c9b3d3102caeb881f5160 --- include/libds-tizen/tbm_server.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/libds-tizen/tbm_server.h b/include/libds-tizen/tbm_server.h index c48977e..f1cc97d 100644 --- a/include/libds-tizen/tbm_server.h +++ b/include/libds-tizen/tbm_server.h @@ -4,6 +4,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + struct ds_tbm_server; struct ds_tbm_client_buffer; @@ -21,4 +25,8 @@ ds_tbm_client_buffer_from_buffer(struct ds_buffer *ds_buffer); tbm_surface_h ds_tbm_client_buffer_get_tbm_surface(struct ds_tbm_client_buffer *buffer); +#ifdef __cplusplus +} +#endif + #endif -- 2.7.4 From 6e6592802e7dbc90538876e5ecb612e6906aafa4 Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Wed, 30 Mar 2022 19:57:41 +0900 Subject: [PATCH 05/16] add ws_members as reviewers Change-Id: I6e027ad8496c66d91de0edfa5cd9a9c8ed2bb712 --- CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODEOWNERS b/CODEOWNERS index 2c7fc6d..b37075e 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -5,5 +5,5 @@ # the repo. Unless a later match takes precedence, # @global-owner1 and @global-owner2 will be requested for # review when someone opens a pull request. -* @doyoun-kang @gl77-lee @sc1-lim @shiin-lee +* @TizenWS/ws_members -- 2.7.4 From d0f5cdc4e96100f43ecfe7e3ae60cb22b2636d23 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=EC=9E=84=EC=88=98=EC=B0=AC/Tizen=20Platform=20Lab=28SR=29/?= =?utf8?q?=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Mon, 11 Apr 2022 09:27:40 +0900 Subject: [PATCH 06/16] Update CODEOWNERS Change-Id: I1c8886c715c1fbf276cee3f3bf01ac6b3bf86641 --- CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODEOWNERS b/CODEOWNERS index b37075e..a215b9e 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -5,5 +5,5 @@ # the repo. Unless a later match takes precedence, # @global-owner1 and @global-owner2 will be requested for # review when someone opens a pull request. -* @TizenWS/ws_members +* @TizenWS/ws_members @sc1-lim @shiin-lee @joonbum-ko @cyeon-lee @doyoun-kang @gl77-lee @duna-oh @jinbong-lee @jk0430-kim @juns-kim @TizenWS/ws_members -- 2.7.4 From 299cfcd39bcc65080646cb8b5a13f19a604fdd41 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=EC=9E=84=EC=88=98=EC=B0=AC/Tizen=20Platform=20Lab=28SR=29/?= =?utf8?q?=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Mon, 11 Apr 2022 09:27:52 +0900 Subject: [PATCH 07/16] Update CODEOWNERS Change-Id: I6fef91c7a648346b2cdbd3da77f7dfbbb30d3803 --- CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODEOWNERS b/CODEOWNERS index a215b9e..d52bfc2 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -5,5 +5,5 @@ # the repo. Unless a later match takes precedence, # @global-owner1 and @global-owner2 will be requested for # review when someone opens a pull request. -* @TizenWS/ws_members @sc1-lim @shiin-lee @joonbum-ko @cyeon-lee @doyoun-kang @gl77-lee @duna-oh @jinbong-lee @jk0430-kim @juns-kim @TizenWS/ws_members +* @sc1-lim @shiin-lee @joonbum-ko @cyeon-lee @doyoun-kang @gl77-lee @duna-oh @jinbong-lee @jk0430-kim @juns-kim @TizenWS/ws_members -- 2.7.4 From 1e0090a999bab75aa5703da58c8cd33206c033d5 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Thu, 7 Apr 2022 10:46:48 +0900 Subject: [PATCH 08/16] Add ds_input_device, and ds_pointer. This patch is just the beginning of ds_input_device. Currently, a ds_input_device is created only on the wayland backend, and it only supports a ds_pointer. Other devices like keyboard and touch, and other backends like libinput will be supported in future patches. Change-Id: Ib0714d81b1083e063992848444517759aa7efadd --- include/libds/backend.h | 4 + include/libds/input_device.h | 31 +++ include/libds/interfaces/backend.h | 1 + include/libds/interfaces/input_device.h | 40 ++++ include/libds/interfaces/pointer.h | 30 +++ include/libds/pointer.h | 38 +++ src/examples/meson.build | 9 + src/examples/pointer-test.c | 278 ++++++++++++++++++++++ src/libds/backend.c | 8 + src/libds/backend/wayland/backend.c | 27 ++- src/libds/backend/wayland/backend.h | 61 +++++ src/libds/backend/wayland/meson.build | 1 + src/libds/backend/wayland/output.c | 28 +++ src/libds/backend/wayland/seat.c | 406 ++++++++++++++++++++++++++++++++ src/libds/input_device.c | 69 ++++++ src/libds/meson.build | 2 + src/libds/pointer.c | 55 +++++ 17 files changed, 1083 insertions(+), 5 deletions(-) create mode 100644 include/libds/input_device.h create mode 100644 include/libds/interfaces/input_device.h create mode 100644 include/libds/interfaces/pointer.h create mode 100644 include/libds/pointer.h create mode 100644 src/examples/pointer-test.c create mode 100644 src/libds/backend/wayland/seat.c create mode 100644 src/libds/input_device.c create mode 100644 src/libds/pointer.c diff --git a/include/libds/backend.h b/include/libds/backend.h index 6b587d2..d6a266f 100644 --- a/include/libds/backend.h +++ b/include/libds/backend.h @@ -31,6 +31,10 @@ void ds_backend_add_new_output_listener(struct ds_backend *backend, struct wl_listener *listener); +void +ds_backend_add_new_input_listener(struct ds_backend *backend, + struct wl_listener *listener); + #ifdef __cplusplus } #endif diff --git a/include/libds/input_device.h b/include/libds/input_device.h new file mode 100644 index 0000000..45e125b --- /dev/null +++ b/include/libds/input_device.h @@ -0,0 +1,31 @@ +#ifndef LIBDS_INPUT_DEVICE_H +#define LIBDS_INPUT_DEVICE_H + +struct ds_input_device; + +struct ds_pointer; + +enum ds_button_state +{ + DS_BUTTON_RELEASED, + DS_BUTTON_PRESSED, +}; + +enum ds_input_device_type +{ + DS_INPUT_DEVICE_POINTER, + DS_INPUT_DEVICE_KEYBOARD, + DS_INPUT_DEVICE_TOUCH, +}; + +enum ds_input_device_type +ds_input_device_get_type(struct ds_input_device *dev); + +struct ds_pointer * +ds_input_device_get_pointer(struct ds_input_device *dev); + +void +ds_input_device_add_destroy_listener(struct ds_input_device *dev, + struct wl_listener *listener); + +#endif diff --git a/include/libds/interfaces/backend.h b/include/libds/interfaces/backend.h index e960ac4..bad37a0 100644 --- a/include/libds/interfaces/backend.h +++ b/include/libds/interfaces/backend.h @@ -22,6 +22,7 @@ struct ds_backend { struct wl_signal destroy; struct wl_signal new_output; + struct wl_signal new_input; } events; bool started; diff --git a/include/libds/interfaces/input_device.h b/include/libds/interfaces/input_device.h new file mode 100644 index 0000000..f31594b --- /dev/null +++ b/include/libds/interfaces/input_device.h @@ -0,0 +1,40 @@ +#ifndef LIBDS_INTERFACES_INPUT_DEVICE_H +#define LIBDS_INTERFACES_INPUT_DEVICE_H + +#include +#include +#include + +struct ds_input_device_interface +{ + void (*destroy)(struct ds_input_device *dev); +}; + +struct ds_input_device +{ + const struct ds_input_device_interface *iface; + + char *name; + double width_mm, height_mm; + char *output_name; + + enum ds_input_device_type type; + union { + void *_device; + struct ds_pointer *pointer; + }; + + struct { + struct wl_signal destroy; + } events; + + struct wl_list link; +}; + +void ds_input_device_init(struct ds_input_device *dev, + enum ds_input_device_type type, + const struct ds_input_device_interface *iface, + const char *name, int vendor, int product); +void ds_input_device_destroy(struct ds_input_device *dev); + +#endif diff --git a/include/libds/interfaces/pointer.h b/include/libds/interfaces/pointer.h new file mode 100644 index 0000000..84b0e23 --- /dev/null +++ b/include/libds/interfaces/pointer.h @@ -0,0 +1,30 @@ +#ifndef LIBDS_INTERFACES_POINTER_H +#define LIBDS_INTERFACES_POINTER_H + +#include + +struct ds_pointer; + +struct ds_pointer_interface +{ + void (*destroy)(struct ds_pointer *pointer); +}; + +struct ds_pointer +{ + const struct ds_pointer_interface *iface; + + struct { + struct wl_signal motion; + struct wl_signal motion_absolute; + struct wl_signal button; + struct wl_signal frame; + } events; +}; + +void ds_pointer_init(struct ds_pointer *pointer, + const struct ds_pointer_interface *iface); + +void ds_pointer_destroy(struct ds_pointer *pointer); + +#endif diff --git a/include/libds/pointer.h b/include/libds/pointer.h new file mode 100644 index 0000000..30bfaca --- /dev/null +++ b/include/libds/pointer.h @@ -0,0 +1,38 @@ +#ifndef LIBDS_POINTER_H +#define LIBDS_POINTER_H + +#include +#include +#include + +struct ds_pointer; + +struct ds_event_pointer_motion_absolute +{ + struct ds_input_device *device; + uint32_t time_msec; + // From 0..1 + double x, y; +}; + +struct ds_event_pointer_button +{ + struct ds_input_device *device; + uint32_t time_msec; + uint32_t button; + enum ds_button_state state; +}; + +void ds_pointer_add_motion_listener(struct ds_pointer *pointer, + struct wl_listener *listener); + +void ds_pointer_add_motion_absolute_listener(struct ds_pointer *pointer, + struct wl_listener *listener); + +void ds_pointer_add_button_listener(struct ds_pointer *pointer, + struct wl_listener *listener); + +void ds_pointer_add_frame_listener(struct ds_pointer *pointer, + struct wl_listener *listener); + +#endif diff --git a/src/examples/meson.build b/src/examples/meson.build index ddb0792..f19f139 100644 --- a/src/examples/meson.build +++ b/src/examples/meson.build @@ -23,6 +23,15 @@ executable('tinyds', install : true ) +executable('pointer-test', + [ + 'pointer-test.c', + 'pixman-helper.c', + ], + dependencies: common_deps, + install_dir: libds_bindir, + install : true) + if get_option('tizen') common_deps += dep_libds_tizen diff --git a/src/examples/pointer-test.c b/src/examples/pointer-test.c new file mode 100644 index 0000000..d669a03 --- /dev/null +++ b/src/examples/pointer-test.c @@ -0,0 +1,278 @@ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "pixman-helper.h" + +#define WIDTH 700 +#define HEIGHT 400 + +struct pointer_device { + struct ds_pointer *ds_pointer; + + struct wl_listener destroy; + struct wl_listener motion_absolute; + struct wl_listener button; + struct wl_listener frame; +}; + +struct output +{ + struct server *server; + + struct ds_output *ds_output; + struct ds_allocator *allocator; + struct ds_swapchain *swapchain; + + struct ds_buffer *front_buffer; + + struct wl_listener destroy; +}; + +struct server +{ + struct wl_display *display; + + struct output output; + + struct ds_backend *backend; + + struct wl_listener backend_destroy; + struct wl_listener new_input; +}; + +struct server _server; + +static struct ds_backend *create_backend_auto(struct wl_display *display); +static void handle_backend_destroy(struct wl_listener *listener, void *data); +static void handle_new_input(struct wl_listener *listener, void *data); +static void output_init(struct output *output, struct server *sever); +static void output_draw(struct output *output); + +int +main(void) +{ + struct server *server = &_server; + + ds_log_init(DS_DBG, NULL); + + server->display = wl_display_create(); + assert(server->display); + + server->backend = create_backend_auto(server->display); + assert(server->backend); + + server->backend_destroy.notify = handle_backend_destroy; + ds_backend_add_destroy_listener(server->backend, &server->backend_destroy); + + server->new_input.notify = handle_new_input; + ds_backend_add_new_input_listener(server->backend, &server->new_input); + + output_init(&server->output, server); + + ds_backend_start(server->backend); + + output_draw(&server->output); + + wl_display_run(server->display); + + wl_display_destroy(server->display); + + return 0; +} + +static struct ds_backend * +create_backend_auto(struct wl_display *display) +{ + struct ds_backend *backend = NULL; + char name[512]; + int i; + + for (i = 0; i < 5; i++) { + snprintf(name, sizeof name, "wayland-%d", i); + backend = ds_wl_backend_create(display, name); + if (backend) + break; + } + + return backend; +} + +static void +handle_backend_destroy(struct wl_listener *listener, void *data) +{ + struct server *server; + + server = wl_container_of(listener, server, backend_destroy); + + wl_list_remove(&server->backend_destroy.link); + wl_list_remove(&server->new_input.link); +} + +static char * +device_type_to_string(enum ds_input_device_type type) +{ + switch (type) { + case DS_INPUT_DEVICE_POINTER: + return "pointer"; + break; + case DS_INPUT_DEVICE_KEYBOARD: + return "keyboard"; + break; + case DS_INPUT_DEVICE_TOUCH: + return "touch"; + break; + default: + return "Unknown"; + } +} + +static void +pointer_handle_device_destroy(struct wl_listener *listener, void *data) +{ + struct pointer_device *pointer; + + pointer = wl_container_of(listener, pointer, destroy); + + wl_list_remove(&pointer->destroy.link); + wl_list_remove(&pointer->motion_absolute.link); + wl_list_remove(&pointer->button.link); + wl_list_remove(&pointer->frame.link); + + free(pointer); +} + +static void +pointer_handle_motion_absolute(struct wl_listener *listener, void *data) +{ + struct ds_event_pointer_motion_absolute *event = data; + + ds_inf("Pointer device(%p): motion absolute (%f, %f) time(%d ms)", + event->device, event->x, event->y, event->time_msec); +} + +static void +pointer_handle_button(struct wl_listener *listener, void *data) +{ + struct ds_event_pointer_button *event = data; + + ds_inf("Pointer Device(%p): button(%d) state(%d) time(%d ms)", + event->device, event->button, event->state, event->time_msec); +} + +static void +pointer_handle_frame(struct wl_listener *listener, void *data) +{ + ds_inf("Pointer device(%p): frame", data); +} + +static void +add_pointer(struct ds_input_device *dev) +{ + struct pointer_device *pointer; + + pointer = calloc(1, sizeof *pointer); + if (!pointer) + return; + + pointer->ds_pointer = ds_input_device_get_pointer(dev); + + pointer->destroy.notify = pointer_handle_device_destroy; + ds_input_device_add_destroy_listener(dev, &pointer->destroy); + + pointer->motion_absolute.notify = pointer_handle_motion_absolute; + ds_pointer_add_motion_absolute_listener(pointer->ds_pointer, + &pointer->motion_absolute); + + pointer->button.notify = pointer_handle_button; + ds_pointer_add_button_listener(pointer->ds_pointer, + &pointer->button); + + pointer->frame.notify = pointer_handle_frame; + ds_pointer_add_frame_listener(pointer->ds_pointer, + &pointer->frame); +} + +static void +handle_new_input(struct wl_listener *listener, void *data) +{ + struct ds_input_device *dev = data; + enum ds_input_device_type type; + + type = ds_input_device_get_type(dev); + + if (type != DS_INPUT_DEVICE_POINTER) + return; + + ds_inf("New pointer device(%p) type(%s)", dev, + device_type_to_string(type)); + + add_pointer(dev); +} + +static void +output_handle_destroy(struct wl_listener *listener, void *data) +{ + struct output *output; + + output = wl_container_of(listener, output, destroy); + + wl_list_remove(&output->destroy.link); + + ds_swapchain_destroy(output->swapchain); + ds_allocator_destroy(output->allocator); +} + +static void +output_init(struct output *output, struct server *server) +{ + output->server = server; + + output->ds_output = ds_wl_backend_create_output(server->backend); + assert(output->ds_output); + + output->destroy.notify = output_handle_destroy; + ds_output_add_destroy_listener(output->ds_output, &output->destroy); + + output->allocator = ds_shm_allocator_create(); + assert(output->allocator); + + output->swapchain = ds_swapchain_create(output->allocator, + WIDTH, HEIGHT, DRM_FORMAT_XRGB8888); + assert(output->swapchain); +} + +static void +output_draw(struct output *output) +{ + struct ds_buffer *buffer; + pixman_image_t *img; + + ds_dbg("Redraw output"); + + buffer = ds_swapchain_acquire(output->swapchain, NULL); + assert(buffer); + + img = pixman_image_from_buffer(buffer, DS_BUFFER_DATA_PTR_ACCESS_WRITE); + assert(img); + + pixman_image_fill_color(img, 80, 80, 80); + + pixman_image_unref(img); + + 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; +} diff --git a/src/libds/backend.c b/src/libds/backend.c index ee2a912..641374a 100644 --- a/src/libds/backend.c +++ b/src/libds/backend.c @@ -41,6 +41,13 @@ ds_backend_add_new_output_listener(struct ds_backend *backend, wl_signal_add(&backend->events.new_output, listener); } +WL_EXPORT void +ds_backend_add_new_input_listener(struct ds_backend *backend, + struct wl_listener *listener) +{ + wl_signal_add(&backend->events.new_input, listener); +} + void ds_backend_init(struct ds_backend *backend, const struct ds_backend_interface *iface) @@ -48,6 +55,7 @@ ds_backend_init(struct ds_backend *backend, backend->iface = iface; wl_signal_init(&backend->events.destroy); wl_signal_init(&backend->events.new_output); + wl_signal_init(&backend->events.new_input); } void diff --git a/src/libds/backend/wayland/backend.c b/src/libds/backend/wayland/backend.c index 778ca1c..d956aa0 100644 --- a/src/libds/backend/wayland/backend.c +++ b/src/libds/backend/wayland/backend.c @@ -14,8 +14,8 @@ static const struct ds_backend_interface wl_backend_interface; static void wl_backend_handle_display_destroy(struct wl_listener *listener, void *data); -static bool wl_backend_server_init(struct ds_wl_backend_server *server, - const char *name); +static bool wl_backend_server_init(struct ds_wl_backend *wl_backend, + struct ds_wl_backend_server *server, const char *name); static void wl_backend_server_finish(struct ds_wl_backend_server *server); static int wl_backend_handle_dispatch_events(int fd, uint32_t mask, void *data); @@ -38,8 +38,9 @@ ds_wl_backend_create(struct wl_display *display, const char *server_name) wl_backend->display = display; wl_list_init(&wl_backend->buffers); wl_list_init(&wl_backend->outputs); + wl_list_init(&wl_backend->seats); - if (!wl_backend_server_init(&wl_backend->server, server_name)) { + if (!wl_backend_server_init(wl_backend, &wl_backend->server, server_name)) { ds_err("Failed to initialize Wayland Server"); goto err_server; } @@ -48,7 +49,7 @@ ds_wl_backend_create(struct wl_display *display, const char *server_name) fd = wl_display_get_fd(wl_backend->server.display); wl_backend->server_event_source = - wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE, + wl_event_loop_add_fd(loop, fd, WL_EVENT_WRITABLE | WL_EVENT_READABLE, wl_backend_handle_dispatch_events, wl_backend); if (!wl_backend->server_event_source) { ds_err("Failed to create event source"); @@ -84,6 +85,7 @@ wl_backend_destroy(struct ds_wl_backend *backend) { struct ds_wl_output *output, *tmp_output; struct ds_wl_buffer *buffer, *tmp_buffer; + struct ds_wl_seat *seat, *tmp_seat; ds_dbg("Destroy wayland backend(%p)", backend); @@ -93,6 +95,9 @@ wl_backend_destroy(struct ds_wl_backend *backend) wl_list_for_each_safe(buffer, tmp_buffer, &backend->buffers, link) destroy_wl_buffer(buffer); + wl_list_for_each_safe(seat, tmp_seat, &backend->seats, link) + destroy_wl_seat(seat); + ds_backend_finish(&backend->base); wl_list_remove(&backend->display_destroy.link); @@ -159,6 +164,7 @@ registry_handle_global(void *data, struct wl_registry *registry, uint32_t name, const char *iface, uint32_t version) { struct ds_wl_backend_server *server = data; + struct ds_wl_seat *seat; ds_log(DS_DBG, "Wayland global: %s v%d", iface, version); @@ -176,6 +182,15 @@ registry_handle_global(void *data, struct wl_registry *registry, server->shm = wl_registry_bind(registry, name, &wl_shm_interface, 1); wl_shm_add_listener(server->shm, &shm_listener, server); } + else if (strcmp(iface, wl_seat_interface.name) == 0) { + seat = create_wl_seat(server->backend, name, version); + if (!seat) { + ds_err("Could not create ds_wl_seat"); + return; + } + + wl_list_insert(&server->backend->seats, &seat->link); + } } static void @@ -192,8 +207,10 @@ static const struct wl_registry_listener registry_listener = }; static bool -wl_backend_server_init(struct ds_wl_backend_server *server, const char *name) +wl_backend_server_init(struct ds_wl_backend *wl_backend, struct ds_wl_backend_server *server, const char *name) { + server->backend = wl_backend; + server->display = wl_display_connect(name); if (!server->display) { ds_log_errno(DS_ERR, "Could not connect to display: name \"%s\"", name); diff --git a/src/libds/backend/wayland/backend.h b/src/libds/backend/wayland/backend.h index ab37ec0..12e594a 100644 --- a/src/libds/backend/wayland/backend.h +++ b/src/libds/backend/wayland/backend.h @@ -3,9 +3,12 @@ #include "libds/interfaces/backend.h" #include "libds/interfaces/output.h" +#include "libds/interfaces/input_device.h" +#include "libds/interfaces/pointer.h" struct ds_wl_backend_server { + struct ds_wl_backend *backend; struct wl_display *display; struct wl_registry *registry; struct wl_compositor *compositor; @@ -23,6 +26,7 @@ struct ds_wl_backend struct wl_list outputs; // ds_wl_output.link struct wl_list buffers; // ds_wl_buffer.link + struct wl_list seats; // ds_wl_seat.link struct wl_event_source *server_event_source; struct ds_wl_backend_server server; @@ -50,6 +54,53 @@ struct ds_wl_output struct wl_callback *frame_callback; struct wl_list link; + + struct { + struct ds_wl_pointer *pointer; + struct wl_surface *surface; + int32_t hotspot_x, hotspot_y; + uint32_t enter_serial; + } cursor; +}; + +struct ds_wl_seat +{ + struct ds_wl_backend *backend; + struct ds_wl_output *output; + + struct wl_seat *wl_seat; + char *name; + + struct ds_input_device *pointer_dev; + struct ds_input_device *keyboard_dev; + struct ds_input_device *touch_dev; + + struct wl_callback *initial_info_cb; + + struct wl_list link; // ds_wl_backend.seats + + enum wl_seat_capability caps; + + int version; + uint32_t enter_serial; + + bool initialized; +}; + +struct ds_wl_input_device +{ + struct ds_input_device base; + + struct ds_wl_backend *backend; + struct ds_wl_seat *seat; +}; + +struct ds_wl_pointer +{ + struct ds_pointer base; + + struct ds_wl_input_device *input_device; + struct wl_pointer *wl_pointer; }; struct ds_wl_backend * @@ -58,4 +109,14 @@ wl_backend_from_backend(struct ds_backend *backend); void destroy_wl_buffer(struct ds_wl_buffer *buffer); +struct ds_wl_seat *create_wl_seat(struct ds_wl_backend *backend, uint32_t id, + uint32_t available_version); + +void destroy_wl_seat(struct ds_wl_seat *seat); + +void output_enter_pointer(struct ds_wl_output *output, + struct ds_wl_pointer *pointer, uint32_t serial); + +void output_leave_pointer(struct ds_wl_output *output); + #endif diff --git a/src/libds/backend/wayland/meson.build b/src/libds/backend/wayland/meson.build index db68fe9..88574a4 100644 --- a/src/libds/backend/wayland/meson.build +++ b/src/libds/backend/wayland/meson.build @@ -1,6 +1,7 @@ libds_files += files( 'backend.c', 'output.c', + 'seat.c', ) protocols = { diff --git a/src/libds/backend/wayland/output.c b/src/libds/backend/wayland/output.c index 1966a97..36ea5f7 100644 --- a/src/libds/backend/wayland/output.c +++ b/src/libds/backend/wayland/output.c @@ -13,6 +13,8 @@ const struct ds_output_interface wl_output_iface; static const struct xdg_surface_listener wl_output_xdg_surface_listener; static const struct xdg_toplevel_listener wl_output_xdg_toplevel_listener; +static void output_update_cursor(struct ds_wl_output *output); + struct ds_output * ds_wl_backend_create_output(struct ds_backend *ds_backend) { @@ -90,6 +92,32 @@ destroy_wl_buffer(struct ds_wl_buffer *buffer) free(buffer); } +void +output_enter_pointer(struct ds_wl_output *output, + struct ds_wl_pointer *pointer, uint32_t serial) +{ + output->cursor.pointer = pointer; + output->cursor.enter_serial = serial; + + output_update_cursor(output); +} + +void +output_leave_pointer(struct ds_wl_output *output) +{ + output->cursor.pointer = NULL; + output->cursor.enter_serial = 0; +} + +static void output_update_cursor(struct ds_wl_output *output) +{ + struct ds_wl_pointer *pointer = output->cursor.pointer; + + wl_pointer_set_cursor(pointer->wl_pointer, output->cursor.enter_serial, + output->cursor.surface, output->cursor.hotspot_x, + output->cursor.hotspot_y); +} + static struct ds_wl_output * wl_output_from_output(struct ds_output *ds_output) { diff --git a/src/libds/backend/wayland/seat.c b/src/libds/backend/wayland/seat.c new file mode 100644 index 0000000..b799e66 --- /dev/null +++ b/src/libds/backend/wayland/seat.c @@ -0,0 +1,406 @@ +#include +#include +#include +#include +#include + +#include "libds/log.h" +#include "libds/pointer.h" + +#include "backend.h" + +#ifdef MIN +# undef MIN +#endif + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +static const struct wl_seat_listener seat_listener; +static const struct wl_callback_listener seat_callback_listener; + +static void seat_update_capabilities(struct ds_wl_seat *seat, + enum wl_seat_capability caps); +static struct ds_input_device * +create_wl_input_device(struct ds_wl_seat *seat, + enum ds_input_device_type type); +static struct ds_pointer *create_wl_pointer(struct ds_wl_seat *seat); + +struct ds_wl_seat * +create_wl_seat(struct ds_wl_backend *backend, uint32_t id, + uint32_t available_version) +{ + struct ds_wl_seat *seat; + + seat = calloc(1, sizeof *seat); + if (!seat) + return NULL; + + seat->backend = backend; + seat->version = MIN(available_version, 5); + seat->wl_seat = wl_registry_bind(backend->server.registry, id, + &wl_seat_interface, seat->version); + + wl_seat_add_listener(seat->wl_seat, &seat_listener, seat); + + seat->initial_info_cb = wl_display_sync(backend->server.display); + wl_callback_add_listener(seat->initial_info_cb, &seat_callback_listener, + seat); + + ds_dbg("wl_backend: Seat(%p) created", seat); + + return seat; +} + +void +destroy_wl_seat(struct ds_wl_seat *seat) +{ + ds_dbg("wl_backend: Seat(%p) destroy", seat); + + if (seat->pointer_dev) + ds_input_device_destroy(seat->pointer_dev); + + if (seat->keyboard_dev) + ds_input_device_destroy(seat->keyboard_dev); + + if (seat->touch_dev) + ds_input_device_destroy(seat->touch_dev); + + if (seat->version >= WL_SEAT_RELEASE_SINCE_VERSION) + wl_seat_release(seat->wl_seat); + else + wl_seat_destroy(seat->wl_seat); + + wl_list_remove(&seat->link); + + free(seat->name); + free(seat); +} + +static void +seat_handle_capabilities(void *data, struct wl_seat *wl_seat, + enum wl_seat_capability caps) +{ + struct ds_wl_seat *seat = data; + + if (seat->initialized) + seat_update_capabilities(seat, caps); + else + seat->caps = caps; + + ds_dbg("wl_backend: Seat(%p) capabilities(%d)", seat, caps); +} + +static void +seat_handle_name(void *data, struct wl_seat *wl_seat, const char *name) +{ + struct ds_wl_seat *seat = data; + + if (seat->name) + free(seat->name); + + ds_dbg("wl_backend: Seat(%p) name(%s)", seat, name); + + seat->name = strdup(name); +} + +static const struct wl_seat_listener seat_listener = { + .capabilities = seat_handle_capabilities, + .name = seat_handle_name, +}; + +static void +seat_add_callback_handle_done(void *data, struct wl_callback *callback, + uint32_t callback_data) +{ + struct ds_wl_seat *seat = data; + + wl_callback_destroy(seat->initial_info_cb); + seat->initial_info_cb = NULL; + seat->initialized = true; + + seat_update_capabilities(seat, seat->caps); +} + +static const struct wl_callback_listener seat_callback_listener = { + .done = seat_add_callback_handle_done, +}; + +static void +seat_update_capabilities(struct ds_wl_seat *seat, enum wl_seat_capability caps) +{ + if ((caps & WL_SEAT_CAPABILITY_POINTER) && seat->pointer_dev == NULL) { + ds_dbg("wl_backend: Seat(%p) offered pointer", seat); + + seat->pointer_dev = create_wl_input_device(seat, + DS_INPUT_DEVICE_POINTER); + seat->pointer_dev->pointer = create_wl_pointer(seat); + + wl_signal_emit(&seat->backend->base.events.new_input, + seat->pointer_dev); + } + else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && + seat->pointer_dev != NULL) { + ds_dbg("wl_backend: Seat(%p) dropped pointer", seat); + ds_input_device_destroy(seat->pointer_dev); + seat->pointer_dev = NULL; + } + + if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && seat->keyboard_dev == NULL) { + ds_dbg("wl_backend: Seat(%p) offered keyboard", seat); + + seat->keyboard_dev = create_wl_input_device(seat, + DS_INPUT_DEVICE_KEYBOARD); + } + else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && + seat->keyboard_dev != NULL) { + ds_dbg("wl_backend: Seat(%p) dropped keyboard", seat); + ds_input_device_destroy(seat->keyboard_dev); + seat->keyboard_dev = NULL; + } + + if ((caps & WL_SEAT_CAPABILITY_TOUCH) && seat->touch_dev == NULL) { + ds_dbg("wl_backend: Seat(%p) offered touch", seat); + seat->touch_dev = create_wl_input_device(seat, + DS_INPUT_DEVICE_TOUCH); + } + else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && + seat->touch_dev != NULL) { + ds_dbg("wl_backend: Seat(%p) dropped touch", seat); + ds_input_device_destroy(seat->touch_dev); + seat->touch_dev = NULL; + } +} + +static const struct ds_input_device_interface input_device_iface; + +static bool +ds_input_device_is_wl(struct ds_input_device *ds_dev) +{ + return ds_dev->iface == &input_device_iface; +} + +static struct ds_wl_input_device * +get_wl_input_device_from_input_device(struct ds_input_device *ds_dev) +{ + assert(ds_input_device_is_wl(ds_dev)); + return (struct ds_wl_input_device *)ds_dev; +} + +static void +input_device_iface_destroy(struct ds_input_device *ds_dev) +{ + struct ds_wl_input_device *dev; + + dev = get_wl_input_device_from_input_device(ds_dev); + + free(dev); +} + +static const struct ds_input_device_interface input_device_iface = +{ + .destroy = input_device_iface_destroy, +}; + +static struct ds_input_device * +create_wl_input_device(struct ds_wl_seat *seat, + enum ds_input_device_type type) +{ + struct ds_wl_input_device *dev; + unsigned int vendor = 0, product = 0; + size_t name_size; + char *name; + + dev = calloc(1, sizeof *dev); + if (!dev) + return NULL; + + dev->backend = seat->backend; + dev->seat = seat; + + name_size = 8 + strlen(seat->name) + 1; + name = alloca(name_size); + (void) snprintf(name, name_size, "wayland-%s", seat->name); + + ds_input_device_init(&dev->base, type, &input_device_iface, name, vendor, + product); + + return &dev->base; +} + +static const struct ds_pointer_interface pointer_iface; + +static struct ds_wl_pointer * +get_wl_pointer_from_pointer(struct ds_pointer *ds_pointer) +{ + assert(ds_pointer->iface == &pointer_iface); + return (struct ds_wl_pointer *)ds_pointer; +} + +static void +pointer_iface_destroy(struct ds_pointer *ds_pointer) +{ + struct ds_wl_pointer *pointer; + + pointer = get_wl_pointer_from_pointer(ds_pointer); + + wl_pointer_release(pointer->wl_pointer); + + free(pointer); +} + +static const struct ds_pointer_interface pointer_iface = { + .destroy = pointer_iface_destroy, +}; + +static void +pointer_handle_enter(void *data, struct wl_pointer *wl_pointer, + uint32_t serial, struct wl_surface *surface, + wl_fixed_t sx, wl_fixed_t sy) +{ + struct ds_wl_seat *seat = data; + struct ds_wl_pointer *pointer; + + if (!surface) + return; + + ds_dbg("Enter pointer"); + + seat->output = wl_surface_get_user_data(surface); + seat->enter_serial = serial; + + pointer = get_wl_pointer_from_pointer(seat->pointer_dev->pointer); + output_enter_pointer(seat->output, pointer, seat->enter_serial); +} + +static void +pointer_handle_leave(void *data, struct wl_pointer *wl_pointer, + uint32_t serial, struct wl_surface *surface) +{ + struct ds_wl_seat *seat = data; + struct ds_wl_output *output; + + if (!seat->output) + return; + + output = wl_surface_get_user_data(surface); + if (seat->output != output) + return; + + ds_dbg("Leave pointer"); + + output_leave_pointer(seat->output); + + seat->output = NULL; + seat->enter_serial = 0; +} + +static void +pointer_handle_motion(void *data, struct wl_pointer *wl_pointer, + uint32_t time, wl_fixed_t sx, wl_fixed_t sy) +{ + struct ds_wl_seat *seat = data; + + if (!seat->output) + return; + + // FIXME take size size of a output into account + struct ds_event_pointer_motion_absolute event = { + .device = seat->pointer_dev, + .time_msec = time, + .x = wl_fixed_to_double(sx) / 700, + .y = wl_fixed_to_double(sy) / 400, + }; + + wl_signal_emit(&seat->pointer_dev->pointer->events.motion_absolute, + &event); +} + +static void +pointer_handle_button(void *data, struct wl_pointer *wl_pointer, + uint32_t serial, uint32_t time, uint32_t button, uint32_t state) +{ + struct ds_wl_seat *seat = data; + + if (!seat->output) + return; + + struct ds_event_pointer_button event = { + .device = seat->pointer_dev, + .button = button, + .state = state, + .time_msec = time, + }; + + wl_signal_emit(&seat->pointer_dev->pointer->events.button, &event); +} + +static void +pointer_handle_axis(void *data, struct wl_pointer *wl_pointer, + uint32_t time, uint32_t axis, wl_fixed_t value) +{ + // TODO +} + +static void +pointer_handle_frame(void *data, struct wl_pointer *wl_pointer) +{ + struct ds_wl_seat *seat = data; + + if (!seat->output) + return; + + wl_signal_emit(&seat->pointer_dev->pointer->events.frame, + seat->pointer_dev); +} + +static void +pointer_handle_axis_source(void *data, struct wl_pointer *wl_pointer, + uint32_t axis_source) +{ + // TODO +} + +static void +pointer_handle_axis_stop(void *data, struct wl_pointer *wl_pointer, + uint32_t time, uint32_t axis) +{ + // TODO +} + +static void +pointer_handle_axis_discrete(void *data, struct wl_pointer *wl_pointer, + uint32_t axis, int32_t discrete) +{ + // TODO +} + +static const struct wl_pointer_listener wl_pointer_listener = { + .enter = pointer_handle_enter, + .leave = pointer_handle_leave, + .motion = pointer_handle_motion, + .button = pointer_handle_button, + .axis = pointer_handle_axis, + .frame = pointer_handle_frame, + .axis_source = pointer_handle_axis_source, + .axis_stop = pointer_handle_axis_stop, + .axis_discrete = pointer_handle_axis_discrete, +}; + +static struct ds_pointer * +create_wl_pointer(struct ds_wl_seat *seat) +{ + struct ds_wl_pointer *pointer; + + pointer = calloc(1, sizeof *pointer); + if (!pointer) { + ds_err("Could not allocate memory"); + return NULL; + } + + ds_pointer_init(&pointer->base, &pointer_iface); + + pointer->wl_pointer = wl_seat_get_pointer(seat->wl_seat); + wl_pointer_add_listener(pointer->wl_pointer, &wl_pointer_listener, seat); + + return &pointer->base; +} diff --git a/src/libds/input_device.c b/src/libds/input_device.c new file mode 100644 index 0000000..db84100 --- /dev/null +++ b/src/libds/input_device.c @@ -0,0 +1,69 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include + +#include "libds/log.h" +#include "libds/interfaces/input_device.h" +#include "libds/interfaces/pointer.h" + +WL_EXPORT enum ds_input_device_type +ds_input_device_get_type(struct ds_input_device *dev) +{ + return dev->type; +} + +WL_EXPORT struct ds_pointer * +ds_input_device_get_pointer(struct ds_input_device *dev) +{ + if (dev->type != DS_INPUT_DEVICE_POINTER) { + ds_err("Given ds_input_device is not a pointer device"); + return NULL; + } + + return dev->pointer; +} + +WL_EXPORT void +ds_input_device_add_destroy_listener(struct ds_input_device *dev, + struct wl_listener *listener) +{ + wl_signal_add(&dev->events.destroy, listener); +} + +void +ds_input_device_init(struct ds_input_device *dev, + enum ds_input_device_type type, + const struct ds_input_device_interface *iface, + const char *name, int vendor, int product) +{ + dev->type = type; + dev->iface = iface; + dev->name = strdup(name); + + wl_signal_init(&dev->events.destroy); +} + +void +ds_input_device_destroy(struct ds_input_device *dev) +{ + wl_signal_emit(&dev->events.destroy, dev); + + if (dev->_device) { + switch (dev->type) { + case DS_INPUT_DEVICE_POINTER: + ds_pointer_destroy(dev->pointer); + break; + default: + ds_err("Warning: leaking memory %p %p %d", + dev->_device, dev, dev->type); + break; + } + } + + free(dev->name); + if (dev->iface && dev->iface->destroy) + dev->iface->destroy(dev); + else + free(dev); +} diff --git a/src/libds/meson.build b/src/libds/meson.build index 50f7962..a08dfdc 100644 --- a/src/libds/meson.build +++ b/src/libds/meson.build @@ -18,6 +18,8 @@ libds_files = [ 'xdg_shell/xdg_toplevel.c', 'pixel_format.c', 'backend.c', + 'input_device.c', + 'pointer.c', ] protocols = { diff --git a/src/libds/pointer.c b/src/libds/pointer.c new file mode 100644 index 0000000..5c5cbda --- /dev/null +++ b/src/libds/pointer.c @@ -0,0 +1,55 @@ +#include +#include +#include "libds/interfaces/pointer.h" + +void +ds_pointer_init(struct ds_pointer *pointer, + const struct ds_pointer_interface *iface) +{ + pointer->iface = iface; + + wl_signal_init(&pointer->events.motion); + wl_signal_init(&pointer->events.motion_absolute); + wl_signal_init(&pointer->events.button); + wl_signal_init(&pointer->events.frame); +} + +void +ds_pointer_destroy(struct ds_pointer *pointer) +{ + if (!pointer) + return; + + if (pointer->iface && pointer->iface->destroy) + pointer->iface->destroy(pointer); + else + free(pointer); +} + +WL_EXPORT void +ds_pointer_add_motion_listener(struct ds_pointer *pointer, + struct wl_listener *listener) +{ + wl_signal_add(&pointer->events.motion, listener); +} + +WL_EXPORT void +ds_pointer_add_motion_absolute_listener(struct ds_pointer *pointer, + struct wl_listener *listener) +{ + wl_signal_add(&pointer->events.motion_absolute, listener); +} + +WL_EXPORT void +ds_pointer_add_button_listener(struct ds_pointer *pointer, + struct wl_listener *listener) +{ + wl_signal_add(&pointer->events.button, listener); +} + +WL_EXPORT void +ds_pointer_add_frame_listener(struct ds_pointer *pointer, + struct wl_listener *listener) +{ + wl_signal_add(&pointer->events.frame, listener); +} -- 2.7.4 From 6a33ab528956933deb2c90467e5762b33a7e0ae6 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Fri, 15 Apr 2022 16:11:57 +0900 Subject: [PATCH 09/16] Add missing header for alloca Change-Id: I87ff3dbbfe27a387c835ca2602b011e3dd866733 --- src/libds/backend/wayland/seat.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libds/backend/wayland/seat.c b/src/libds/backend/wayland/seat.c index b799e66..c569947 100644 --- a/src/libds/backend/wayland/seat.c +++ b/src/libds/backend/wayland/seat.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include "libds/log.h" -- 2.7.4 From cbae7a73a2da444633c693dd64fec6ef81ab0c14 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Mon, 18 Apr 2022 10:29:23 +0900 Subject: [PATCH 10/16] Add ds_keyboard A ds_keyboard is for abstracting phisical keyboard device. Change-Id: I382ea96db01679f036283b213c4e540e36687c9d --- include/libds/input_device.h | 5 + include/libds/interfaces/input_device.h | 2 + include/libds/interfaces/keyboard.h | 89 ++++++++++ include/libds/keyboard.h | 45 +++++ packaging/libds.spec | 1 + src/libds/input_device.c | 15 ++ src/libds/keyboard.c | 304 ++++++++++++++++++++++++++++++++ src/libds/meson.build | 5 + src/libds/util.h | 3 + src/libds/util/shm.c | 76 +++++++- 10 files changed, 544 insertions(+), 1 deletion(-) create mode 100644 include/libds/interfaces/keyboard.h create mode 100644 include/libds/keyboard.h create mode 100644 src/libds/keyboard.c diff --git a/include/libds/input_device.h b/include/libds/input_device.h index 45e125b..6143e00 100644 --- a/include/libds/input_device.h +++ b/include/libds/input_device.h @@ -5,6 +5,8 @@ struct ds_input_device; struct ds_pointer; +struct ds_keyboard; + enum ds_button_state { DS_BUTTON_RELEASED, @@ -24,6 +26,9 @@ ds_input_device_get_type(struct ds_input_device *dev); struct ds_pointer * ds_input_device_get_pointer(struct ds_input_device *dev); +struct ds_keyboard * +ds_input_device_get_keyboard(struct ds_input_device *dev); + void ds_input_device_add_destroy_listener(struct ds_input_device *dev, struct wl_listener *listener); diff --git a/include/libds/interfaces/input_device.h b/include/libds/interfaces/input_device.h index f31594b..7828503 100644 --- a/include/libds/interfaces/input_device.h +++ b/include/libds/interfaces/input_device.h @@ -4,6 +4,7 @@ #include #include #include +#include struct ds_input_device_interface { @@ -22,6 +23,7 @@ struct ds_input_device union { void *_device; struct ds_pointer *pointer; + struct ds_keyboard *keyboard; }; struct { diff --git a/include/libds/interfaces/keyboard.h b/include/libds/interfaces/keyboard.h new file mode 100644 index 0000000..f68c9a7 --- /dev/null +++ b/include/libds/interfaces/keyboard.h @@ -0,0 +1,89 @@ +#ifndef LIBDS_INTERFACES_KEYBOARD_H +#define LIBDS_INTERFACES_KEYBOARD_H + +#include +#include + +#include + +#define DS_LED_COUNT 3 + +enum ds_keyboard_led { + DS_LED_NUM_LOCK = 1 << 0, + DS_LED_CAPS_LOCK = 1 << 1, + DS_LED_SCROLL_LOCK = 1 << 2, +}; + +#define DS_MODIFIER_COUNT 8 + +enum ds_keyboard_modifier { + DS_MODIFIER_SHIFT = 1 << 0, + DS_MODIFIER_CAPS = 1 << 1, + DS_MODIFIER_CTRL = 1 << 2, + DS_MODIFIER_ALT = 1 << 3, + DS_MODIFIER_MOD2 = 1 << 4, + DS_MODIFIER_MOD3 = 1 << 5, + DS_MODIFIER_LOGO = 1 << 6, + DS_MODIFIER_MOD5 = 1 << 7, +}; + +#define DS_KEYBOARD_KEYS_CAP 32 + +struct ds_keyboard; + +struct ds_keyboard_interface +{ + void (*destroy)(struct ds_keyboard *keyboard); +}; + +struct ds_keyboard_modifiers +{ + xkb_mod_mask_t depressed; + xkb_mod_mask_t latched; + xkb_mod_mask_t locked; + xkb_mod_mask_t group; +}; + +struct ds_keyboard +{ + const struct ds_keyboard_interface *iface; + + char *keymap_string; + size_t keymap_size; + int keymap_fd; + struct xkb_keymap *keymap; + struct xkb_state *xkb_state; + xkb_led_index_t led_indexes[DS_LED_COUNT]; + xkb_mod_index_t mod_indexes[DS_MODIFIER_COUNT]; + + uint32_t keycodes[DS_KEYBOARD_KEYS_CAP]; + size_t num_keycodes; + struct ds_keyboard_modifiers modifiers; + + struct { + int32_t rate; + int32_t delay; + } repeat_info; + + struct { + struct wl_signal destroy; + struct wl_signal key; + struct wl_signal modifiers; + struct wl_signal keymap; + struct wl_signal repeat_info; + } events; +}; + +void ds_keyboard_init(struct ds_keyboard *keyboard, + const struct ds_keyboard_interface *iface); + +void ds_keyboard_destroy(struct ds_keyboard *keyboard); + +void ds_keyboard_notify_key(struct ds_keyboard *keyboard, + struct ds_event_keyboard_key *event); + +void ds_keyboard_notify_modifiers(struct ds_keyboard *keyboard, + uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, + uint32_t group); + +#endif diff --git a/include/libds/keyboard.h b/include/libds/keyboard.h new file mode 100644 index 0000000..e226cb4 --- /dev/null +++ b/include/libds/keyboard.h @@ -0,0 +1,45 @@ +#ifndef LIBDS_KEYBOARD_H +#define LIBDS_KEYBOARD_H + +#include +#include + +#include +#include + +struct ds_keyboard; + +struct ds_event_keyboard_key +{ + uint32_t time_msec; + uint32_t keycode; + bool update_state; + enum wl_keyboard_key_state state; +}; + +bool ds_keyboard_set_keymap(struct ds_keyboard *keyboard, + struct xkb_keymap *keymap); + +void ds_keyboard_set_repeat_info(struct ds_keyboard *keyboard, + int32_t rate, int32_t delay); + +uint32_t ds_keyboard_get_modifiers(struct ds_keyboard *keyboard); + +struct xkb_state *ds_keyboard_get_xkb_state(struct ds_keyboard *keyboard); + +void ds_keyboard_add_destroy_listener(struct ds_keyboard *keyboard, + struct wl_listener *listener); + +void ds_keyboard_add_key_listener(struct ds_keyboard *keyboard, + struct wl_listener *listener); + +void ds_keyboard_add_modifiers_listener(struct ds_keyboard *keyboard, + struct wl_listener *listener); + +void ds_keyboard_add_keymap_listener(struct ds_keyboard *keyboard, + struct wl_listener *listener); + +void ds_keyboard_add_repeat_info_listener(struct ds_keyboard *keyboard, + struct wl_listener *listener); + +#endif diff --git a/packaging/libds.spec b/packaging/libds.spec index 879a87d..806c75b 100644 --- a/packaging/libds.spec +++ b/packaging/libds.spec @@ -13,6 +13,7 @@ BuildRequires: pkgconfig(wayland-client) BuildRequires: pkgconfig(wayland-protocols) BuildRequires: pkgconfig(pixman-1) BuildRequires: pkgconfig(libdrm) +BuildRequires: pkgconfig(xkbcommon) BuildRequires: pkgconfig(libtdm) BuildRequires: pkgconfig(libtbm) diff --git a/src/libds/input_device.c b/src/libds/input_device.c index db84100..351361f 100644 --- a/src/libds/input_device.c +++ b/src/libds/input_device.c @@ -6,6 +6,7 @@ #include "libds/log.h" #include "libds/interfaces/input_device.h" #include "libds/interfaces/pointer.h" +#include "libds/interfaces/keyboard.h" WL_EXPORT enum ds_input_device_type ds_input_device_get_type(struct ds_input_device *dev) @@ -24,6 +25,17 @@ ds_input_device_get_pointer(struct ds_input_device *dev) return dev->pointer; } +WL_EXPORT struct ds_keyboard * +ds_input_device_get_keyboard(struct ds_input_device *dev) +{ + if (dev->type != DS_INPUT_DEVICE_KEYBOARD) { + ds_err("Given ds_input_device is not a keyboard device"); + return NULL; + } + + return dev->keyboard; +} + WL_EXPORT void ds_input_device_add_destroy_listener(struct ds_input_device *dev, struct wl_listener *listener) @@ -54,6 +66,9 @@ ds_input_device_destroy(struct ds_input_device *dev) case DS_INPUT_DEVICE_POINTER: ds_pointer_destroy(dev->pointer); break; + case DS_INPUT_DEVICE_KEYBOARD: + ds_keyboard_destroy(dev->keyboard); + break; default: ds_err("Warning: leaking memory %p %p %d", dev->_device, dev, dev->type); diff --git a/src/libds/keyboard.c b/src/libds/keyboard.c new file mode 100644 index 0000000..d122e81 --- /dev/null +++ b/src/libds/keyboard.c @@ -0,0 +1,304 @@ +#include +#include +#include +#include + +#include + +#include "libds/log.h" +#include "libds/interfaces/keyboard.h" +#include "util.h" + +static bool keyboard_modifier_update(struct ds_keyboard *keyboard); +static void keyboard_key_update(struct ds_keyboard *keyboard, + struct ds_event_keyboard_key *event); +static void keyboard_led_update(struct ds_keyboard *keyboard); + +WL_EXPORT bool +ds_keyboard_set_keymap(struct ds_keyboard *keyboard, struct xkb_keymap *keymap) +{ + char *tmp_keymap_string; + void *dst; + int rw_fd, ro_fd; + xkb_keycode_t keycode; + const char *led_names[DS_LED_COUNT] = { + XKB_LED_NAME_NUM, + XKB_LED_NAME_CAPS, + XKB_LED_NAME_SCROLL, + }; + const char *mod_names[DS_MODIFIER_COUNT] = { + XKB_MOD_NAME_SHIFT, + XKB_MOD_NAME_CAPS, + XKB_MOD_NAME_CTRL, + XKB_MOD_NAME_ALT, + XKB_MOD_NAME_NUM, + "Mod3", + XKB_MOD_NAME_LOGO, + "Mod5", + }; + + if (keyboard->keymap) + xkb_keymap_unref(keyboard->keymap); + + keyboard->keymap = xkb_keymap_ref(keymap); + + if (keyboard->xkb_state) + xkb_state_unref(keyboard->xkb_state); + + keyboard->xkb_state = xkb_state_new(keyboard->keymap); + if (!keyboard->xkb_state) { + ds_err("Failed to create XKB state"); + goto err_state; + } + + for (size_t i = 0; i < DS_LED_COUNT; i++) { + keyboard->led_indexes[i] = + xkb_map_led_get_index(keyboard->keymap, led_names[i]); + } + + for (size_t i = 0; i < DS_MODIFIER_COUNT; i++) { + keyboard->mod_indexes[i] = + xkb_map_mod_get_index(keyboard->keymap, mod_names[i]); + } + + tmp_keymap_string = xkb_keymap_get_as_string(keyboard->keymap, + XKB_KEYMAP_FORMAT_TEXT_V1); + if (!tmp_keymap_string) { + ds_err("Failed to get string version of keymap"); + goto err_keymap_string; + } + + if (keyboard->keymap_string) + free(keyboard->keymap_string); + keyboard->keymap_string = tmp_keymap_string; + keyboard->keymap_size = strlen(keyboard->keymap_string) + 1; + + if (!allocate_shm_file_pair(keyboard->keymap_size, &rw_fd, &ro_fd)) { + ds_err("Failed to allocate shm_file for keymap"); + goto err_shm_file; + } + + dst = mmap(NULL, keyboard->keymap_size, PROT_READ | PROT_WRITE, + MAP_SHARED, rw_fd, 0); + if (dst == MAP_FAILED) { + ds_log_errno(DS_ERR, "mmap failed"); + goto err_mmap; + } + + memcpy(dst, keyboard->keymap_string, keyboard->keymap_size); + munmap(dst, keyboard->keymap_size); + close(rw_fd); + + if (keyboard->keymap_fd >= 0) + close(keyboard->keymap_fd); + keyboard->keymap_fd = ro_fd; + + for (size_t i = 0; i < keyboard->num_keycodes; i++) { + keycode = keyboard->keycodes[i] + 8; + xkb_state_update_key(keyboard->xkb_state, keycode, XKB_KEY_DOWN); + } + + keyboard_modifier_update(keyboard); + + wl_signal_emit(&keyboard->events.keymap, keyboard); + + return true; + +err_mmap: + close(rw_fd); + close(ro_fd); +err_shm_file: + free(keyboard->keymap_string); + keyboard->keymap_string = NULL; +err_keymap_string: + xkb_state_unref(keyboard->xkb_state); + keyboard->xkb_state = NULL; +err_state: + xkb_keymap_unref(keymap); + keyboard->keymap = NULL; + + return false; +} + +WL_EXPORT void +ds_keyboard_set_repeat_info(struct ds_keyboard *keyboard, + int32_t rate, int32_t delay) +{ + if (keyboard->repeat_info.rate == rate && + keyboard->repeat_info.delay == delay) + return; + keyboard->repeat_info.rate = rate; + keyboard->repeat_info.delay = delay; + + wl_signal_emit(&keyboard->events.repeat_info, keyboard); +} + +WL_EXPORT uint32_t +ds_keyboard_get_modifiers(struct ds_keyboard *keyboard) +{ + xkb_mod_mask_t mask; + uint32_t modifiers = 0; + + mask = keyboard->modifiers.depressed | keyboard->modifiers.latched; + for (size_t i = 0; i < DS_MODIFIER_COUNT; i++) { + if (keyboard->mod_indexes[i] != XKB_MOD_INVALID && + (mask & (1 << keyboard->mod_indexes[i]))) + modifiers |= (1 << i); + } + + return modifiers; +} + +WL_EXPORT struct xkb_state * +ds_keyboard_get_xkb_state(struct ds_keyboard *keyboard) +{ + return keyboard->xkb_state; +} + +WL_EXPORT void +ds_keyboard_notify_key(struct ds_keyboard *keyboard, + struct ds_event_keyboard_key *event) +{ + uint32_t keycode; + enum xkb_key_direction dir; + bool updated; + + keyboard_key_update(keyboard, event); + + wl_signal_emit(&keyboard->events.key, event); + + if (!keyboard->xkb_state) + return; + + if (event->update_state) { + keycode = event->keycode + 8; + dir = (event->state == WL_KEYBOARD_KEY_STATE_PRESSED) ? + XKB_KEY_DOWN : XKB_KEY_UP; + xkb_state_update_key(keyboard->xkb_state, keycode, dir); + } + + updated = keyboard_modifier_update(keyboard); + if (updated) + wl_signal_emit(&keyboard->events.modifiers, keyboard); + + keyboard_led_update(keyboard); +} + +WL_EXPORT void +ds_keyboard_notify_modifiers(struct ds_keyboard *keyboard, + uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, + uint32_t group) +{ + bool updated; + + if (!keyboard->xkb_state) + return; + + xkb_state_update_mask(keyboard->xkb_state, mods_depressed, mods_latched, + mods_locked, 0, 0, group); + + updated = keyboard_modifier_update(keyboard); + if (updated) + wl_signal_emit(&keyboard->events.modifiers, keyboard); + + keyboard_led_update(keyboard); +} + +WL_EXPORT void +ds_keyboard_add_destroy_listener(struct ds_keyboard *keyboard, + struct wl_listener *listener) +{ + wl_signal_add(&keyboard->events.destroy, listener); +} + +WL_EXPORT void +ds_keyboard_add_key_listener(struct ds_keyboard *keyboard, + struct wl_listener *listener) +{ + wl_signal_add(&keyboard->events.key, listener); +} + +WL_EXPORT void +ds_keyboard_add_modifiers_listener(struct ds_keyboard *keyboard, + struct wl_listener *listener) +{ + wl_signal_add(&keyboard->events.modifiers, listener); +} + +WL_EXPORT void +ds_keyboard_add_keymap_listener(struct ds_keyboard *keyboard, + struct wl_listener *listener) +{ + wl_signal_add(&keyboard->events.keymap, listener); +} + +WL_EXPORT void +ds_keyboard_add_repeat_info_listener(struct ds_keyboard *keyboard, + struct wl_listener *listener) +{ + wl_signal_add(&keyboard->events.repeat_info, listener); +} + +void +ds_keyboard_init(struct ds_keyboard *keyboard, + const struct ds_keyboard_interface *iface) +{ + keyboard->iface = iface; + keyboard->keymap_fd = -1; + + wl_signal_init(&keyboard->events.destroy); + wl_signal_init(&keyboard->events.key); + wl_signal_init(&keyboard->events.modifiers); + wl_signal_init(&keyboard->events.keymap); + wl_signal_init(&keyboard->events.repeat_info); +} + +void +ds_keyboard_destroy(struct ds_keyboard *keyboard) +{ + if (keyboard->iface && keyboard->iface->destroy) + keyboard->iface->destroy(keyboard); + else + free(keyboard); +} + +static bool +keyboard_modifier_update(struct ds_keyboard *keyboard) +{ + xkb_mod_mask_t depressed, latched, locked, group; + + if (!keyboard->xkb_state) + return false; + + depressed = xkb_state_serialize_mods(keyboard->xkb_state, + XKB_STATE_MODS_DEPRESSED); + latched = xkb_state_serialize_mods(keyboard->xkb_state, + XKB_STATE_MODS_LATCHED); + locked = xkb_state_serialize_mods(keyboard->xkb_state, + XKB_STATE_MODS_LOCKED); + group = xkb_state_serialize_layout(keyboard->xkb_state, + XKB_STATE_LAYOUT_EFFECTIVE); + if (depressed == keyboard->modifiers.depressed && + latched == keyboard->modifiers.latched && + locked == keyboard->modifiers.locked && + group == keyboard->modifiers.group) + return false; + + keyboard->modifiers.depressed = depressed; + keyboard->modifiers.latched = latched; + keyboard->modifiers.locked = locked; + keyboard->modifiers.group = group; + + return true; +} + +static void keyboard_key_update(struct ds_keyboard *keyboard, + struct ds_event_keyboard_key *event) +{ + // TODO +} + +static void keyboard_led_update(struct ds_keyboard *keyboard) +{ + // TODO +} diff --git a/src/libds/meson.build b/src/libds/meson.build index a08dfdc..4d1ae39 100644 --- a/src/libds/meson.build +++ b/src/libds/meson.build @@ -20,6 +20,7 @@ libds_files = [ 'backend.c', 'input_device.c', 'pointer.c', + 'keyboard.c', ] protocols = { @@ -52,12 +53,16 @@ math = meson.get_compiler('c').find_library('m') wayland_server = dependency('wayland-server', required: true) pixman = dependency('pixman-1', required: true) libdrm = dependency('libdrm', required: true) +xkbcommon = dependency('xkbcommon', required: true) +rt = meson.get_compiler('c').find_library('rt') libds_deps = [ math, wayland_server, pixman, libdrm, + xkbcommon, + rt, ] subdir('backend') diff --git a/src/libds/util.h b/src/libds/util.h index 3b7448b..1c9326a 100644 --- a/src/libds/util.h +++ b/src/libds/util.h @@ -10,4 +10,7 @@ timespec_to_msec(const struct timespec *a); int allocate_shm_file(size_t size); +bool +allocate_shm_file_pair(size_t size, int *rw_fd_ptr, int *ro_fd_ptr); + #endif diff --git a/src/libds/util/shm.c b/src/libds/util/shm.c index c8c84e3..4abd229 100644 --- a/src/libds/util/shm.c +++ b/src/libds/util/shm.c @@ -24,13 +24,18 @@ */ #define _POSIX_C_SOURCE 200809L - +#include #include #include #include #include #include +#include #include +#include +#include + +#define RANDNAME_PATTERN "/libds-XXXXXX" int os_fd_set_cloexec(int fd) @@ -172,3 +177,72 @@ allocate_shm_file(off_t size) return fd; } + +static void +randname(char *buf) +{ + struct timespec ts; + long r; + + clock_gettime(CLOCK_REALTIME, &ts); + r = ts.tv_nsec; + for (int i = 0; i < 6; i++) { + buf[i] = 'A' + (r & 15) + (r & 16) * 2; + r >>= 5; + } +} + +static int +excl_shm_open(char *name) +{ + int retries = 100; + int fd; + + do { + randname(name + strlen(RANDNAME_PATTERN) - 6); + + --retries; + + fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600); + if (fd >= 0) + return fd; + } while (retries > 0 && errno == EEXIST); + + return -1; +} + +bool +allocate_shm_file_pair(size_t size, int *rw_fd_ptr, int *ro_fd_ptr) +{ + char name[] = RANDNAME_PATTERN; + int rw_fd, ro_fd; + int ret; + + rw_fd = excl_shm_open(name); + if (rw_fd < 0) + return false; + + ro_fd = shm_open(name, O_RDONLY, 0); + if (ro_fd < 0) { + shm_unlink(name); + close(rw_fd); + return false; + } + + shm_unlink(name); + + do { + ret = ftruncate(rw_fd, size); + } while (ret < 0 && errno == EINTR); + + if (ret < 0) { + close(rw_fd); + close(ro_fd); + return false; + } + + *rw_fd_ptr = rw_fd; + *ro_fd_ptr = ro_fd; + + return true; +} -- 2.7.4 From 22c42edd55619b8291c56d2710a57b73a38026f3 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Mon, 18 Apr 2022 10:33:19 +0900 Subject: [PATCH 11/16] backend/wayland: Support ds_keyboard Change-Id: I30a6a86e79f34abb22b789dee9ffe50d9d121a88 --- src/libds/backend/wayland/backend.h | 8 ++ src/libds/backend/wayland/seat.c | 196 ++++++++++++++++++++++++++++++++++++ src/libds/util.h | 3 + src/libds/util/time.c | 9 ++ 4 files changed, 216 insertions(+) diff --git a/src/libds/backend/wayland/backend.h b/src/libds/backend/wayland/backend.h index 12e594a..c35f7d1 100644 --- a/src/libds/backend/wayland/backend.h +++ b/src/libds/backend/wayland/backend.h @@ -5,6 +5,7 @@ #include "libds/interfaces/output.h" #include "libds/interfaces/input_device.h" #include "libds/interfaces/pointer.h" +#include "libds/interfaces/keyboard.h" struct ds_wl_backend_server { @@ -103,6 +104,13 @@ struct ds_wl_pointer struct wl_pointer *wl_pointer; }; +struct ds_wl_keyboard +{ + struct ds_keyboard base; + + struct wl_keyboard *wl_keyboard; +}; + struct ds_wl_backend * wl_backend_from_backend(struct ds_backend *backend); diff --git a/src/libds/backend/wayland/seat.c b/src/libds/backend/wayland/seat.c index c569947..966bf77 100644 --- a/src/libds/backend/wayland/seat.c +++ b/src/libds/backend/wayland/seat.c @@ -3,11 +3,14 @@ #include #include #include +#include #include +#include #include "libds/log.h" #include "libds/pointer.h" +#include "util.h" #include "backend.h" #ifdef MIN @@ -25,6 +28,7 @@ static struct ds_input_device * create_wl_input_device(struct ds_wl_seat *seat, enum ds_input_device_type type); static struct ds_pointer *create_wl_pointer(struct ds_wl_seat *seat); +static struct ds_keyboard *create_wl_keyboard(struct ds_wl_seat *seat); struct ds_wl_seat * create_wl_seat(struct ds_wl_backend *backend, uint32_t id, @@ -151,6 +155,10 @@ seat_update_capabilities(struct ds_wl_seat *seat, enum wl_seat_capability caps) seat->keyboard_dev = create_wl_input_device(seat, DS_INPUT_DEVICE_KEYBOARD); + seat->keyboard_dev->keyboard = create_wl_keyboard(seat); + + wl_signal_emit(&seat->backend->base.events.new_input, + seat->keyboard_dev); } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && seat->keyboard_dev != NULL) { @@ -405,3 +413,191 @@ create_wl_pointer(struct ds_wl_seat *seat) return &pointer->base; } + +static const struct ds_keyboard_interface keyboard_iface; + +static struct ds_wl_keyboard * +get_wl_keyboard_from_keyboard(struct ds_keyboard *ds_keyboard) +{ + assert(ds_keyboard->iface == &keyboard_iface); + return (struct ds_wl_keyboard *)ds_keyboard; +} + +static void +keyboard_iface_destroy(struct ds_keyboard *ds_keyboard) +{ + struct ds_wl_keyboard *keyboard; + + keyboard = get_wl_keyboard_from_keyboard(ds_keyboard); + + wl_keyboard_release(keyboard->wl_keyboard); + + free(keyboard); +} + +static const struct ds_keyboard_interface keyboard_iface = { + .destroy = keyboard_iface_destroy, +}; + +static void +keyboard_handle_keymap(void *data, struct wl_keyboard *wl_keyboard, + uint32_t format, int fd, uint32_t size) +{ + struct ds_wl_seat *seat = data; + struct xkb_context *context; + struct xkb_keymap *keymap; + char *map_str; + + ds_dbg("wl_keyboard: keymap"); + + if (format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { + map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + if (map_str == MAP_FAILED) { + ds_log_errno(DS_ERR, "mmap failed"); + goto end; + } + + context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + keymap = xkb_keymap_new_from_string(context, map_str, + XKB_KEYMAP_FORMAT_TEXT_V1, 0); + munmap(map_str, size); + + if (!keymap) { + ds_err("Failed to compile keymap"); + goto end; + } + + ds_keyboard_set_keymap(seat->keyboard_dev->keyboard, keymap); + + xkb_keymap_unref(keymap); + xkb_context_unref(context); + } + + // TODO More case? + +end: + close(fd); +} + +static void +keyboard_handle_enter(void *data, struct wl_keyboard *wl_keyboard, + uint32_t serial, struct wl_surface *surface, struct wl_array *keys) +{ + struct ds_wl_seat *seat = data; + uint32_t *keycode_ptr; + uint32_t time; + + ds_dbg("wl_keyboard: enter"); + + time = get_current_time_msec(); + + wl_array_for_each(keycode_ptr, keys) { + struct ds_event_keyboard_key event = { + .keycode = *keycode_ptr, + .state = WL_KEYBOARD_KEY_STATE_PRESSED, + .time_msec = time, + .update_state = false, + }; + + ds_keyboard_notify_key(seat->keyboard_dev->keyboard, &event); + } +} + +static void +keyboard_handle_leave(void *data, struct wl_keyboard *wl_keyboard, + uint32_t serial, struct wl_surface *surface) +{ + struct ds_wl_seat *seat = data; + struct ds_keyboard *keyboard = seat->keyboard_dev->keyboard; + uint32_t *pressed; + uint32_t time, keycode; + size_t num_keycodes; + + ds_dbg("wl_keyboard: leave"); + + time = get_current_time_msec(); + + num_keycodes = keyboard->num_keycodes; + pressed = alloca(num_keycodes + 1); + memcpy(pressed, keyboard->keycodes, num_keycodes * sizeof(uint32_t)); + + for (size_t i = 0; i < num_keycodes; i++) { + keycode = pressed[i]; + + struct ds_event_keyboard_key event = { + .keycode = keycode, + .state = WL_KEYBOARD_KEY_STATE_RELEASED, + .time_msec = time, + .update_state = false, + }; + + ds_keyboard_notify_key(keyboard, &event); + } +} + +static void +keyboard_handle_key(void *data, struct wl_keyboard *wl_keyboard, + uint32_t serial, uint32_t time, uint32_t key, uint32_t state) +{ + struct ds_wl_seat *seat = data; + + ds_dbg("wl_keyboard: key"); + + struct ds_event_keyboard_key event = { + .keycode = key, + .state = state, + .time_msec = time, + .update_state = false, + }; + + ds_keyboard_notify_key(seat->keyboard_dev->keyboard, &event); +} + +static void +keyboard_handle_modifiers(void *data, struct wl_keyboard *wl_keyboard, + uint32_t serial_in, uint32_t mods_depressed, uint32_t mods_latched, + uint32_t mods_locked, uint32_t group) +{ + struct ds_wl_seat *seat = data; + + ds_dbg("wl_keyboard: modifiers"); + + ds_keyboard_notify_modifiers(seat->keyboard_dev->keyboard, + mods_depressed, mods_latched, mods_locked, group); +} + +static void +keyboard_handle_repeat_info(void *data, struct wl_keyboard *wl_keyboard, + int32_t rate, int32_t delay) +{ + ds_dbg("wl_keyboard: repeat_info"); + + // This space is intentionally left blank +} + +static const struct wl_keyboard_listener wl_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 struct ds_keyboard * +create_wl_keyboard(struct ds_wl_seat *seat) +{ + struct ds_wl_keyboard *keyboard; + + keyboard = calloc(1, sizeof *keyboard); + if (!keyboard) + return NULL; + + ds_keyboard_init(&keyboard->base, &keyboard_iface); + + keyboard->wl_keyboard = wl_seat_get_keyboard(seat->wl_seat); + wl_keyboard_add_listener(keyboard->wl_keyboard, + &wl_keyboard_listener, seat); + + return &keyboard->base; +} diff --git a/src/libds/util.h b/src/libds/util.h index 1c9326a..4603544 100644 --- a/src/libds/util.h +++ b/src/libds/util.h @@ -7,6 +7,9 @@ int64_t timespec_to_msec(const struct timespec *a); +uint32_t +get_current_time_msec(void); + int allocate_shm_file(size_t size); diff --git a/src/libds/util/time.c b/src/libds/util/time.c index afb0e89..2461cb7 100644 --- a/src/libds/util/time.c +++ b/src/libds/util/time.c @@ -8,3 +8,12 @@ timespec_to_msec(const struct timespec *a) { return (int64_t)a->tv_sec * 1000 + a->tv_nsec / 1000000; } + +uint32_t +get_current_time_msec(void) +{ + struct timespec now; + + clock_gettime(CLOCK_MONOTONIC, &now); + return timespec_to_msec(&now); +} -- 2.7.4 From 2026e03cbcc2076dad9418dc91330938e5078931 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Mon, 18 Apr 2022 10:35:14 +0900 Subject: [PATCH 12/16] examples: Rename pointer-test to input-device-test This patch also adds code for ds_keyboard in input-device-test. Change-Id: I0e37a9a11beca9c38afc51e6841a08330e4852ab --- .../{pointer-test.c => input-device-test.c} | 105 +++++++++++++++++++-- src/examples/meson.build | 4 +- 2 files changed, 101 insertions(+), 8 deletions(-) rename src/examples/{pointer-test.c => input-device-test.c} (70%) diff --git a/src/examples/pointer-test.c b/src/examples/input-device-test.c similarity index 70% rename from src/examples/pointer-test.c rename to src/examples/input-device-test.c index d669a03..237d0b5 100644 --- a/src/examples/pointer-test.c +++ b/src/examples/input-device-test.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -24,6 +25,17 @@ struct pointer_device { struct wl_listener frame; }; +struct server; + +struct keyboard_device { + struct server *server; + struct ds_keyboard *ds_keyboard; + + struct wl_listener destroy; + struct wl_listener modifiers; + struct wl_listener key; +}; + struct output { struct server *server; @@ -202,20 +214,101 @@ add_pointer(struct ds_input_device *dev) } static void +keyboard_handle_device_destroy(struct wl_listener *listener, void *data) +{ + struct keyboard_device *keyboard; + + keyboard = wl_container_of(listener, keyboard, destroy); + + wl_list_remove(&keyboard->destroy.link); + wl_list_remove(&keyboard->modifiers.link); + wl_list_remove(&keyboard->key.link); + + free(keyboard); +} + +static void +keyboard_handle_modifiers(struct wl_listener *listener, void *data) +{ + struct keyboard_device *keyboard; + struct ds_keyboard *ds_keyboard = data; + + keyboard = wl_container_of(listener, keyboard, destroy); + + ds_inf("Keyboard(%p) event modifiers", ds_keyboard); +} + +static void +keyboard_handle_key(struct wl_listener *listener, void *data) +{ + struct ds_event_keyboard_key *event = data; + struct keyboard_device *keyboard; + struct xkb_state *xkb_state; + const xkb_keysym_t *syms; + int nsyms = 0; + + keyboard = wl_container_of(listener, keyboard, key); + + ds_inf("Keyboard(%p) event key: keycode(%d), state(%d), time_msec(%d), " + "update_state(%d)", keyboard->ds_keyboard, + event->keycode, event->state, event->time_msec, + event->update_state); + + xkb_state = ds_keyboard_get_xkb_state(keyboard->ds_keyboard); + if (!xkb_state) + return; + + nsyms = xkb_state_key_get_syms(xkb_state, event->keycode + 8, &syms); + + for (int i = 0; i < nsyms; i++) { + if (syms[i] == XKB_KEY_Escape) + wl_display_terminate(keyboard->server->display); + } +} + +static void +add_keyboard(struct server *server, struct ds_input_device *dev) +{ + struct keyboard_device *keyboard; + + keyboard = calloc(1, sizeof *keyboard); + if (!keyboard) + return; + + keyboard->server = server; + keyboard->ds_keyboard = ds_input_device_get_keyboard(dev); + + ds_inf("Keyboard(%p) added", keyboard->ds_keyboard); + + keyboard->destroy.notify = keyboard_handle_device_destroy; + ds_input_device_add_destroy_listener(dev, &keyboard->destroy); + + keyboard->modifiers.notify = keyboard_handle_modifiers; + ds_keyboard_add_modifiers_listener(keyboard->ds_keyboard, + &keyboard->modifiers); + + keyboard->key.notify = keyboard_handle_key; + ds_keyboard_add_key_listener(keyboard->ds_keyboard, + &keyboard->key); +} + +static void handle_new_input(struct wl_listener *listener, void *data) { + struct server *server; struct ds_input_device *dev = data; enum ds_input_device_type type; type = ds_input_device_get_type(dev); - if (type != DS_INPUT_DEVICE_POINTER) - return; + ds_inf("New device(%p) type(%s)", dev, device_type_to_string(type)); - ds_inf("New pointer device(%p) type(%s)", dev, - device_type_to_string(type)); - - add_pointer(dev); + if (type == DS_INPUT_DEVICE_POINTER) + add_pointer(dev); + else if (type == DS_INPUT_DEVICE_KEYBOARD) { + server = wl_container_of(listener, server, new_input); + add_keyboard(server, dev); + } } static void diff --git a/src/examples/meson.build b/src/examples/meson.build index f19f139..c568eb6 100644 --- a/src/examples/meson.build +++ b/src/examples/meson.build @@ -23,9 +23,9 @@ executable('tinyds', install : true ) -executable('pointer-test', +executable('input-device-test', [ - 'pointer-test.c', + 'input-device-test.c', 'pixman-helper.c', ], dependencies: common_deps, -- 2.7.4 From 418c71edde3b957e493912cb04a00729b0e1575e Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Mon, 18 Apr 2022 10:37:06 +0900 Subject: [PATCH 13/16] Enable user to get keyboard modifiers input-device-test take modifiers into account when handling key. Change-Id: Iec87c300323d891e18873afcf9b1eabf886ee068 --- include/libds/interfaces/keyboard.h | 13 ------------- include/libds/keyboard.h | 13 +++++++++++++ src/examples/input-device-test.c | 36 ++++++++++++++++++++++++++++-------- 3 files changed, 41 insertions(+), 21 deletions(-) diff --git a/include/libds/interfaces/keyboard.h b/include/libds/interfaces/keyboard.h index f68c9a7..3602fe5 100644 --- a/include/libds/interfaces/keyboard.h +++ b/include/libds/interfaces/keyboard.h @@ -14,19 +14,6 @@ enum ds_keyboard_led { DS_LED_SCROLL_LOCK = 1 << 2, }; -#define DS_MODIFIER_COUNT 8 - -enum ds_keyboard_modifier { - DS_MODIFIER_SHIFT = 1 << 0, - DS_MODIFIER_CAPS = 1 << 1, - DS_MODIFIER_CTRL = 1 << 2, - DS_MODIFIER_ALT = 1 << 3, - DS_MODIFIER_MOD2 = 1 << 4, - DS_MODIFIER_MOD3 = 1 << 5, - DS_MODIFIER_LOGO = 1 << 6, - DS_MODIFIER_MOD5 = 1 << 7, -}; - #define DS_KEYBOARD_KEYS_CAP 32 struct ds_keyboard; diff --git a/include/libds/keyboard.h b/include/libds/keyboard.h index e226cb4..2a515e3 100644 --- a/include/libds/keyboard.h +++ b/include/libds/keyboard.h @@ -9,6 +9,19 @@ struct ds_keyboard; +#define DS_MODIFIER_COUNT 8 + +enum ds_keyboard_modifier { + DS_MODIFIER_SHIFT = 1 << 0, + DS_MODIFIER_CAPS = 1 << 1, + DS_MODIFIER_CTRL = 1 << 2, + DS_MODIFIER_ALT = 1 << 3, + DS_MODIFIER_MOD2 = 1 << 4, + DS_MODIFIER_MOD3 = 1 << 5, + DS_MODIFIER_LOGO = 1 << 6, + DS_MODIFIER_MOD5 = 1 << 7, +}; + struct ds_event_keyboard_key { uint32_t time_msec; diff --git a/src/examples/input-device-test.c b/src/examples/input-device-test.c index 237d0b5..62fe8b0 100644 --- a/src/examples/input-device-test.c +++ b/src/examples/input-device-test.c @@ -230,12 +230,26 @@ keyboard_handle_device_destroy(struct wl_listener *listener, void *data) static void keyboard_handle_modifiers(struct wl_listener *listener, void *data) { - struct keyboard_device *keyboard; struct ds_keyboard *ds_keyboard = data; - - keyboard = wl_container_of(listener, keyboard, destroy); - - ds_inf("Keyboard(%p) event modifiers", ds_keyboard); + uint32_t modifiers; + + modifiers = ds_keyboard_get_modifiers(ds_keyboard); + if (modifiers & DS_MODIFIER_CTRL) + ds_inf("Keyboard(%p) modifier: Ctrl", ds_keyboard); + if (modifiers & DS_MODIFIER_SHIFT) + ds_inf("Keyboard(%p) modifier: Shift", ds_keyboard); + if (modifiers & DS_MODIFIER_CAPS) + ds_inf("Keyboard(%p) modifier: Caps", ds_keyboard); + if (modifiers & DS_MODIFIER_ALT) + ds_inf("Keyboard(%p) modifier: Alt", ds_keyboard); + if (modifiers & DS_MODIFIER_MOD2) + ds_inf("Keyboard(%p) modifier: Mod2", ds_keyboard); + if (modifiers & DS_MODIFIER_MOD3) + ds_inf("Keyboard(%p) modifier: Mod3", ds_keyboard); + if (modifiers & DS_MODIFIER_LOGO) + ds_inf("Keyboard(%p) modifier: Logo", ds_keyboard); + if (modifiers & DS_MODIFIER_MOD5) + ds_inf("Keyboard(%p) modifier: Mod5", ds_keyboard); } static void @@ -245,6 +259,7 @@ keyboard_handle_key(struct wl_listener *listener, void *data) struct keyboard_device *keyboard; struct xkb_state *xkb_state; const xkb_keysym_t *syms; + uint32_t modifiers; int nsyms = 0; keyboard = wl_container_of(listener, keyboard, key); @@ -260,9 +275,14 @@ keyboard_handle_key(struct wl_listener *listener, void *data) nsyms = xkb_state_key_get_syms(xkb_state, event->keycode + 8, &syms); - for (int i = 0; i < nsyms; i++) { - if (syms[i] == XKB_KEY_Escape) - wl_display_terminate(keyboard->server->display); + modifiers = ds_keyboard_get_modifiers(keyboard->ds_keyboard); + if ((modifiers & DS_MODIFIER_CTRL) && + (modifiers & DS_MODIFIER_ALT) && + event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { + for (int i = 0; i < nsyms; i++) { + if (syms[i] == XKB_KEY_BackSpace) + wl_display_terminate(keyboard->server->display); + } } } -- 2.7.4 From 292c034ac292876b58d449e30d29e7e8f313d8fe Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Mon, 18 Apr 2022 13:27:17 +0900 Subject: [PATCH 14/16] packaging: Add missing file mistakenly unpacked Change-Id: Ib2a1b45b4dc9a7d3fdeeb47cfce74d0bb552f48c --- packaging/libds.spec | 1 + 1 file changed, 1 insertion(+) diff --git a/packaging/libds.spec b/packaging/libds.spec index 806c75b..efba8cb 100644 --- a/packaging/libds.spec +++ b/packaging/libds.spec @@ -69,6 +69,7 @@ ninja -C builddir install %{_libdir}/libds.so %{_bindir}/wl-backend %{_bindir}/tinyds +%{_bindir}/input-device-test %files tizen-devel %manifest %{name}.manifest -- 2.7.4 From 464a27127ea22e7cf95e1546204ad57c9a5cc6d8 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Wed, 20 Apr 2022 11:29:17 +0900 Subject: [PATCH 15/16] examples/tinyds: Handle ds_keyboard tinyds now handles ds_keyboard, and it may be terminated by pressing Alt + Ctrl + Shift + BackSapce. Change-Id: I06ba652cd4103df9bc7a60fdc6d7b3a8fca56621 --- src/examples/tinyds.c | 118 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/src/examples/tinyds.c b/src/examples/tinyds.c index a4c1042..cfa55a6 100644 --- a/src/examples/tinyds.c +++ b/src/examples/tinyds.c @@ -17,12 +17,25 @@ #include #include #include +#include +#include #define TINYDS_UNUSED __attribute__((unused)) #define OUTPUT_WIDTH 1280 #define OUTPUT_HEIGHT 720 +struct tinyds_server; + +struct tinyds_keyboard +{ + struct ds_input_device *dev; + struct tinyds_server *server; + + struct wl_listener destroy; + struct wl_listener key; +}; + struct tinyds_output { struct tinyds_server *server; @@ -54,6 +67,7 @@ struct tinyds_server struct wl_list views; struct wl_list outputs; + struct wl_listener new_input; struct wl_listener new_xdg_surface; }; @@ -77,6 +91,7 @@ struct tinyds_server _tinyds; static bool init_server(struct tinyds_server *server, struct wl_display *display); static void fini_server(struct tinyds_server *server); +static void server_handle_new_input(struct wl_listener *listener, void *data); static bool init_output(struct tinyds_output *output, struct tinyds_server *server, int width, int height); static void fini_output(struct tinyds_output *output); @@ -240,6 +255,9 @@ init_server(struct tinyds_server *server, struct wl_display *display) if (!server->backend) return false; + server->new_input.notify = server_handle_new_input; + ds_backend_add_new_input_listener(server->backend, &server->new_input); + server->compositor = ds_compositor_create(display); if (!server->compositor) { ds_backend_destroy(server->backend); @@ -439,3 +457,103 @@ view_send_frame_done(struct tinyds_view *view) ds_surface_send_frame_done(ds_xdg_surface_get_surface(view->xdg_surface), &now); } + +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 bool +server_handle_keybinding(struct tinyds_server *server, xkb_keysym_t sym) +{ + switch (sym) { + case XKB_KEY_BackSpace: + wl_display_terminate(server->display); + break; + default: + return false; + } + + return true; +} + +static void +keyboard_handle_key(struct wl_listener *listener, void *data) +{ + struct tinyds_keyboard *kbd; + struct ds_event_keyboard_key *event = data; + struct ds_keyboard *ds_keyboard; + struct xkb_state *xkb_state; + const xkb_keysym_t *syms; + uint32_t modifiers; + int nsyms; + + kbd = wl_container_of(listener, kbd, key); + + ds_keyboard = ds_input_device_get_keyboard(kbd->dev); + + modifiers = ds_keyboard_get_modifiers(ds_keyboard); + if ((modifiers & DS_MODIFIER_CTRL) && + (modifiers & DS_MODIFIER_ALT) && + (modifiers & DS_MODIFIER_SHIFT) && + event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { + xkb_state = ds_keyboard_get_xkb_state(ds_keyboard); + if (xkb_state) { + nsyms = xkb_state_key_get_syms(xkb_state, event->keycode + 8, + &syms); + for (int i = 0; i < nsyms; i++) { + server_handle_keybinding(kbd->server, syms[i]); + } + } + } +} + +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 void +server_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); + break; + default: + ds_err("Unknown type(%d) of ds_input_device", dev_type); + break; + } +} -- 2.7.4 From 9cbe14ff64360116b7b367930e3cd66f66bbd319 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Wed, 20 Apr 2022 15:45:55 +0900 Subject: [PATCH 16/16] xdg_shell: Destroy ds_xdg_surfaces when cleaning up client This patch fixes memory corruption caused by removing ds_xdg_surfaces's link in destroy_xdg_surface(). When wl_client is destroyed, ds_xdg_shell_client can be destroyed before its own ds_xdg_surfaces. This led to memory corruption because of illegal access to a freed memory when trying to remove list of ds_xdg_surface.link. Change-Id: I2558e445af25e85a84f761f845dae22eb10eeab4 --- src/libds/xdg_shell/xdg_shell.c | 4 ++++ src/libds/xdg_shell/xdg_shell.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/src/libds/xdg_shell/xdg_shell.c b/src/libds/xdg_shell/xdg_shell.c index a53684a..0b5252c 100644 --- a/src/libds/xdg_shell/xdg_shell.c +++ b/src/libds/xdg_shell/xdg_shell.c @@ -140,9 +140,13 @@ static void xdg_client_handle_resource_destroy(struct wl_resource *resource) { struct ds_xdg_client *client; + struct ds_xdg_surface *surface, *tmp; client = wl_resource_get_user_data(resource); + wl_list_for_each_safe(surface, tmp, &client->surfaces, link) + destroy_xdg_surface(surface); + if (client->ping_timer != NULL) wl_event_source_remove(client->ping_timer); diff --git a/src/libds/xdg_shell/xdg_shell.h b/src/libds/xdg_shell/xdg_shell.h index ea67be7..dc50d37 100644 --- a/src/libds/xdg_shell/xdg_shell.h +++ b/src/libds/xdg_shell/xdg_shell.h @@ -168,6 +168,8 @@ struct ds_xdg_surface * create_xdg_surface(struct ds_xdg_client *client, struct ds_surface *surface, uint32_t id); +void destroy_xdg_surface(struct ds_xdg_surface *surface); + void reset_xdg_surface(struct ds_xdg_surface *surface); -- 2.7.4