From 077dca5cc5b0f05c4655318e195861640903948c Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Thu, 19 May 2022 19:34:06 +0900 Subject: [PATCH 01/16] keyrouter: change the prefix of the internal functions remove the tizen prefix. Change-Id: I57bf64185af71a0ea2f423e21d3bdfc8ccf3a93f --- src/libds-tizen/keyrouter/keyrouter.c | 42 +++++++++++++++--------------- src/libds-tizen/keyrouter/keyrouter.h | 16 ++++++------ src/libds-tizen/keyrouter/keyrouter_grab.c | 16 ++++++------ 3 files changed, 37 insertions(+), 37 deletions(-) diff --git a/src/libds-tizen/keyrouter/keyrouter.c b/src/libds-tizen/keyrouter/keyrouter.c index eaa831a..6b5b220 100644 --- a/src/libds-tizen/keyrouter/keyrouter.c +++ b/src/libds-tizen/keyrouter/keyrouter.c @@ -13,13 +13,13 @@ #include "keyrouter.h" static void -tizen_keyrouter_bind(struct wl_client *client, void *data, uint32_t version, +keyrouter_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id); static bool keyrouter_check_privilege(struct ds_tizen_keyrouter_client *keyrouter_client, struct wl_client *client, uint32_t mode, uint32_t keycode); static void -tizen_keyrouter_options_set(struct ds_tizen_keyrouter *keyrouter); +keyrouter_options_set(struct ds_tizen_keyrouter *keyrouter); static void keyrouter_handle_display_destroy(struct wl_listener *listener, void *data) @@ -40,7 +40,7 @@ keyrouter_handle_display_destroy(struct wl_listener *listener, void *data) wl_global_destroy(keyrouter->global); - tizen_keyrouter_grab_destroy(keyrouter->keyrouter_grab); + keyrouter_grab_destroy(keyrouter->keyrouter_grab); free(keyrouter); } @@ -55,7 +55,7 @@ ds_tizen_keyrouter_create(struct wl_display *display) return NULL; } - keyrouter->keyrouter_grab = tizen_keyrouter_grab_create(); + keyrouter->keyrouter_grab = keyrouter_grab_create(); if (keyrouter->keyrouter_grab == NULL) { ds_err("Failed to create keyrouter."); free(keyrouter); @@ -63,9 +63,9 @@ ds_tizen_keyrouter_create(struct wl_display *display) } keyrouter->global = wl_global_create(display, &tizen_keyrouter_interface, - 2, keyrouter, tizen_keyrouter_bind); + 2, keyrouter, keyrouter_bind); if (!keyrouter->global) { - tizen_keyrouter_grab_destroy(keyrouter->keyrouter_grab); + keyrouter_grab_destroy(keyrouter->keyrouter_grab); free(keyrouter); return NULL; } @@ -77,7 +77,7 @@ ds_tizen_keyrouter_create(struct wl_display *display) keyrouter->display_destroy.notify = keyrouter_handle_display_destroy; wl_display_add_destroy_listener(display, &keyrouter->display_destroy); - tizen_keyrouter_options_set(keyrouter); + keyrouter_options_set(keyrouter); if (!tizen_security_init()) { ds_inf("tizen_security_init() is not sucessful. keyrouter works without security."); @@ -115,7 +115,7 @@ keyrouter_handle_keygrab_set(struct wl_client *client, return; } - res = tizen_keyrouter_grab_grab_key(keyrouter->keyrouter_grab, + res = keyrouter_grab_grab_key(keyrouter->keyrouter_grab, mode, key, (void *)client); if (res == TIZEN_KEYROUTER_ERROR_NONE && keyrouter_client->grabbed != true) keyrouter_client->grabbed = true; @@ -136,7 +136,7 @@ keyrouter_handle_keygrab_unset(struct wl_client *client, keyrouter = keyrouter_client->keyrouter; /* ungrab TOP POSITION grab first, this grab mode is not check privilege */ - tizen_keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab, + keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab, TIZEN_KEYROUTER_MODE_TOPMOST, key, (void *)client); ret = keyrouter_check_privilege(keyrouter_client, @@ -147,13 +147,13 @@ keyrouter_handle_keygrab_unset(struct wl_client *client, return; } - tizen_keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab, + keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab, TIZEN_KEYROUTER_MODE_EXCLUSIVE, key, (void *)client); - tizen_keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab, + keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab, TIZEN_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE, key, (void *)client); - tizen_keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab, + keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab, TIZEN_KEYROUTER_MODE_TOPMOST, key, (void *)client); - tizen_keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab, + keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab, TIZEN_KEYROUTER_MODE_SHARED, key, (void *)client); tizen_keyrouter_send_keygrab_notify(resource, surface, key, TIZEN_KEYROUTER_MODE_NONE, res); @@ -205,7 +205,7 @@ keyrouter_handle_keygrab_set_list(struct wl_client *client, if (ret == false) { grab_data->err = TIZEN_KEYROUTER_ERROR_NO_PERMISSION; } else { - res = tizen_keyrouter_grab_grab_key(keyrouter->keyrouter_grab, + res = keyrouter_grab_grab_key(keyrouter->keyrouter_grab, grab_data->mode, grab_data->key, (void *)client); if (res == TIZEN_KEYROUTER_ERROR_NONE && keyrouter_client->grabbed != true) keyrouter_client->grabbed = true; @@ -240,7 +240,7 @@ keyrouter_handle_keygrab_unset_list(struct wl_client *client, } wl_array_for_each(ungrab_data, ungrab_list) { - tizen_keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab, + keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab, TIZEN_KEYROUTER_MODE_TOPMOST, ungrab_data->key, (void *)client); ret = keyrouter_check_privilege(keyrouter_client, client, @@ -248,16 +248,16 @@ keyrouter_handle_keygrab_unset_list(struct wl_client *client, if (!ret) { ungrab_data->err = TIZEN_KEYROUTER_ERROR_NO_PERMISSION; } else { - tizen_keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab, + keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab, TIZEN_KEYROUTER_MODE_EXCLUSIVE, ungrab_data->key, (void *)client); - tizen_keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab, + keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab, TIZEN_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE, ungrab_data->key, (void *)client); - tizen_keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab, + keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab, TIZEN_KEYROUTER_MODE_TOPMOST, ungrab_data->key, (void *)client); - tizen_keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab, + keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab, TIZEN_KEYROUTER_MODE_SHARED, ungrab_data->key, (void *)client); ungrab_data->err = TIZEN_KEYROUTER_ERROR_NONE; @@ -329,7 +329,7 @@ keyrouter_handle_resource_destory(struct wl_resource *resource) } static void -tizen_keyrouter_bind(struct wl_client *client, void *data, uint32_t version, +keyrouter_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id) { struct ds_tizen_keyrouter *keyrouter = data; @@ -386,7 +386,7 @@ keyrouter_check_privilege(struct ds_tizen_keyrouter_client *keyrouter_client, } static void -tizen_keyrouter_options_set(struct ds_tizen_keyrouter *keyrouter) +keyrouter_options_set(struct ds_tizen_keyrouter *keyrouter) { FILE *file; int keycode; diff --git a/src/libds-tizen/keyrouter/keyrouter.h b/src/libds-tizen/keyrouter/keyrouter.h index c8dfa0f..ffbb3cd 100644 --- a/src/libds-tizen/keyrouter/keyrouter.h +++ b/src/libds-tizen/keyrouter/keyrouter.h @@ -83,26 +83,26 @@ struct ds_tizen_ungrab_data }; struct ds_tizen_keyrouter_grab * -tizen_keyrouter_grab_create(void); +keyrouter_grab_create(void); void -tizen_keyrouter_grab_destroy(struct ds_tizen_keyrouter_grab *keyrouter_grab); +keyrouter_grab_destroy(struct ds_tizen_keyrouter_grab *keyrouter_grab); int -tizen_keyrouter_grab_grab_key(struct ds_tizen_keyrouter_grab *keyrouter_grab, +keyrouter_grab_grab_key(struct ds_tizen_keyrouter_grab *keyrouter_grab, int type, int keycode, void *data); void -tizen_keyrouter_grab_ungrab_key(struct ds_tizen_keyrouter_grab *keyrouter_grab, +keyrouter_grab_ungrab_key(struct ds_tizen_keyrouter_grab *keyrouter_grab, int type, int keycode, void *data); int -tizen_keyrouter_grab_key_process(struct ds_tizen_keyrouter_grab *keyrouter_grab, +keyrouter_grab_key_process(struct ds_tizen_keyrouter_grab *keyrouter_grab, int keycode, int pressed, struct wl_list *delivery_list); void -tizen_keyrouter_grab_set_focus_client(struct ds_tizen_keyrouter_grab *keyrouter_grab, +keyrouter_grab_set_focus_client(struct ds_tizen_keyrouter_grab *keyrouter_grab, void *focus_client); void -tizen_keyrouter_grab_set_top_client(struct ds_tizen_keyrouter_grab *keyrouter_grab, +keyrouter_grab_set_top_client(struct ds_tizen_keyrouter_grab *keyrouter_grab, void *top_client); bool -tizen_keyrouter_grab_check_grabbed_key(struct ds_tizen_keyrouter_grab *keyrouter_grab, +keyrouter_grab_check_grabbed_key(struct ds_tizen_keyrouter_grab *keyrouter_grab, int keycode); #endif diff --git a/src/libds-tizen/keyrouter/keyrouter_grab.c b/src/libds-tizen/keyrouter/keyrouter_grab.c index 873f4b1..f5467ae 100644 --- a/src/libds-tizen/keyrouter/keyrouter_grab.c +++ b/src/libds-tizen/keyrouter/keyrouter_grab.c @@ -24,7 +24,7 @@ keyrouter_grab_get_grabbed_list(struct ds_tizen_keyrouter_grab *keyrouter_grab, } bool -tizen_keyrouter_grab_check_grabbed_key(struct ds_tizen_keyrouter_grab *keyrouter_grab, int keycode) +keyrouter_grab_check_grabbed_key(struct ds_tizen_keyrouter_grab *keyrouter_grab, int keycode) { struct wl_list *list; @@ -101,7 +101,7 @@ keyrouter_grab_check_grabbed(struct ds_tizen_keyrouter_grab *keyrouter_grab, } void -tizen_keyrouter_grab_set_focus_client(struct ds_tizen_keyrouter_grab *keyrouter_grab, +keyrouter_grab_set_focus_client(struct ds_tizen_keyrouter_grab *keyrouter_grab, void *focus_client) { keyrouter_grab->focus_client = focus_client; @@ -113,7 +113,7 @@ tizen_keyrouter_grab_set_focus_client(struct ds_tizen_keyrouter_grab *keyrouter_ } void -tizen_keyrouter_grab_set_top_client(struct ds_tizen_keyrouter_grab *keyrouter_grab, void *top_client) +keyrouter_grab_set_top_client(struct ds_tizen_keyrouter_grab *keyrouter_grab, void *top_client) { keyrouter_grab->top_client = top_client; @@ -124,7 +124,7 @@ tizen_keyrouter_grab_set_top_client(struct ds_tizen_keyrouter_grab *keyrouter_gr } int -tizen_keyrouter_grab_key_process(struct ds_tizen_keyrouter_grab *keyrouter_grab, +keyrouter_grab_key_process(struct ds_tizen_keyrouter_grab *keyrouter_grab, int keycode, int pressed, struct wl_list *delivery_list) { struct ds_tizen_keyrouter_key_info *info, *delivery; @@ -209,7 +209,7 @@ tizen_keyrouter_grab_key_process(struct ds_tizen_keyrouter_grab *keyrouter_grab, } int -tizen_keyrouter_grab_grab_key(struct ds_tizen_keyrouter_grab *keyrouter_grab, +keyrouter_grab_grab_key(struct ds_tizen_keyrouter_grab *keyrouter_grab, int type, int keycode, void *data) { struct ds_tizen_keyrouter_key_info *info = NULL; @@ -264,7 +264,7 @@ keyrouter_list_remove_data(struct wl_list *list, void *data) } void -tizen_keyrouter_grab_ungrab_key(struct ds_tizen_keyrouter_grab *keyrouter_grab, +keyrouter_grab_ungrab_key(struct ds_tizen_keyrouter_grab *keyrouter_grab, int type, int keycode, void *data) { struct wl_list *list; @@ -287,7 +287,7 @@ tizen_keyrouter_grab_ungrab_key(struct ds_tizen_keyrouter_grab *keyrouter_grab, } struct ds_tizen_keyrouter_grab * -tizen_keyrouter_grab_create(void) +keyrouter_grab_create(void) { struct ds_tizen_keyrouter_grab *keyrouter_grab = NULL; int i; @@ -334,7 +334,7 @@ keyrouter_grab_delete_list(struct wl_list *list) } void -tizen_keyrouter_grab_destroy(struct ds_tizen_keyrouter_grab *keyrouter_grab) +keyrouter_grab_destroy(struct ds_tizen_keyrouter_grab *keyrouter_grab) { int i; -- 2.7.4 From eb92ef1fe647d00c1412d942e1f6d33126b3308d Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Wed, 18 May 2022 14:32:31 +0900 Subject: [PATCH 02/16] fix the build warning Change-Id: I045dbf51644e8ab10ed12820a8c7a9e624741354 --- src/libds-tizen/util/security.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/libds-tizen/util/security.c b/src/libds-tizen/util/security.c index 735caf5..ad19027 100644 --- a/src/libds-tizen/util/security.c +++ b/src/libds-tizen/util/security.c @@ -145,18 +145,16 @@ tizen_security_finish(void) #ifdef HAVE_CYNARA if (g_cynara_refcount < 1) { ds_err("%s called without tizen_security_init\n", __FUNCTION__); - return 0; + return; } if (--g_cynara_refcount != 0) - return 1; + return; if (g_cynara) { cynara_finish(g_cynara); g_cynara = NULL; } #endif - - return 1; } -- 2.7.4 From a002a9cf36b0c0e691d4f9aa5494a119a4d485ff Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Mon, 16 May 2022 17:39:29 +0900 Subject: [PATCH 03/16] shell: implement wl_shell_interface ds_shell and ds_shell_surface are resources which implement the wl_shell_interface and wl_shell_surface_interface. Change-Id: I1064d0b431bdf1fd734353b58bc7994d202e9c57 --- include/libds/shell.h | 50 +++++ src/libds/meson.build | 2 + src/libds/shell.c | 175 +++++++++++++++ src/libds/shell.h | 157 ++++++++++++++ src/libds/shell_surface.c | 540 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 924 insertions(+) create mode 100644 include/libds/shell.h create mode 100644 src/libds/shell.c create mode 100644 src/libds/shell.h create mode 100644 src/libds/shell_surface.c diff --git a/include/libds/shell.h b/include/libds/shell.h new file mode 100644 index 0000000..b4fa688 --- /dev/null +++ b/include/libds/shell.h @@ -0,0 +1,50 @@ +#ifndef LIBDS_SHELL_H +#define LIBDS_SHELL_H + +#include +#include + +#include "surface.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct ds_shell; + +struct ds_shell_surface; + +struct ds_shell * +ds_shell_create(struct wl_display *display); + +void +ds_shell_add_destroy_listener(struct ds_shell *shell, + struct wl_listener *listener); + +void +ds_shell_add_new_surface_listener(struct ds_shell *shell, + struct wl_listener *listener); + +void +ds_shell_surface_add_destroy_listener(struct ds_shell_surface *surface, + struct wl_listener *listener); + +void +ds_shell_surface_add_map_listener(struct ds_shell_surface *surface, + struct wl_listener *listener); + +void +ds_shell_surface_add_unmap_listener(struct ds_shell_surface *surface, + struct wl_listener *listener); + +void +ds_shell_surface_ping(struct ds_shell_surface *surface); + +struct ds_surface * +ds_shell_surface_get_surface(struct ds_shell_surface *surface); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/libds/meson.build b/src/libds/meson.build index 43bdeae..b59fda2 100644 --- a/src/libds/meson.build +++ b/src/libds/meson.build @@ -26,6 +26,8 @@ libds_files = [ 'seat/seat_pointer.c', 'seat/seat_keyboard.c', 'seat/seat_touch.c', + 'shell.c', + 'shell_surface.c', ] protocols = { diff --git a/src/libds/shell.c b/src/libds/shell.c new file mode 100644 index 0000000..3adb519 --- /dev/null +++ b/src/libds/shell.c @@ -0,0 +1,175 @@ +#include +#include +#include + +#include "libds/log.h" +#include "libds/shell.h" + +#include "shell.h" + +#define WL_SHELL_VERSION 1 +#define SHELL_PING_TIMEOUT 10000 + +static void shell_handle_display_destroy(struct wl_listener *listener, + void *data); +static void shell_bind(struct wl_client *wl_client, void *data, + uint32_t verison, uint32_t id); + +WL_EXPORT struct ds_shell * +ds_shell_create(struct wl_display *display) +{ + struct ds_shell *shell; + + shell = calloc(1, sizeof *shell); + if (!shell) { + return NULL; + } + + shell->global = wl_global_create(display, &wl_shell_interface, + WL_SHELL_VERSION, shell, shell_bind); + if (!shell->global) { + free(shell); + return NULL; + } + + wl_list_init(&shell->clients); + + shell->display_destroy.notify = shell_handle_display_destroy; + wl_display_add_destroy_listener(display, &shell->display_destroy); + + wl_signal_init(&shell->events.destroy); + wl_signal_init(&shell->events.new_surface); + + shell->ping_timeout = SHELL_PING_TIMEOUT; + + ds_inf("Global created: xdg_wm_base shell(%p)", shell); + + return shell; +} + +WL_EXPORT void +ds_shell_add_destroy_listener(struct ds_shell *shell, + struct wl_listener *listener) +{ + wl_signal_add(&shell->events.destroy, listener); +} + +WL_EXPORT void +ds_shell_add_new_surface_listener(struct ds_shell *shell, + struct wl_listener *listener) +{ + wl_signal_add(&shell->events.new_surface, listener); +} + +static void +shell_handle_display_destroy(struct wl_listener *listener, void *data) +{ + struct ds_shell *shell; + + shell = wl_container_of(listener, shell, display_destroy); + + ds_inf("Global destroy: xdg_wm_base shell(%p)", shell); + + wl_signal_emit(&shell->events.destroy, shell); + wl_list_remove(&shell->display_destroy.link); + wl_global_destroy(shell->global); + free(shell); +} + +static void +shell_handle_get_shell_surface(struct wl_client *wl_client, + struct wl_resource *resource, uint32_t id, + struct wl_resource *surface_resource) +{ + struct ds_shell_client *client; + struct ds_surface *surface; + + client = wl_resource_get_user_data(resource); + surface = ds_surface_from_resource(surface_resource); + create_shell_surface(client, surface, id); +} + +static const struct wl_shell_interface shell_impl = +{ + .get_shell_surface = shell_handle_get_shell_surface, +}; + +static void +shell_client_handle_resource_destroy(struct wl_resource *resource) +{ + struct ds_shell_client *client; + struct ds_shell_surface *shell_surface, *tmp; + + client = wl_resource_get_user_data(resource); + + wl_list_for_each_safe(shell_surface, tmp, &client->shell_surfaces, link) + destroy_shell_surface(shell_surface); + + if (client->ping_timer != NULL) + wl_event_source_remove(client->ping_timer); + + wl_list_remove(&client->link); + free(client); +} + +static int +shell_client_handle_ping_timeout(void *user_data) +{ + struct ds_shell_client *client = user_data; + struct ds_shell_surface *surface; + + wl_list_for_each(surface, &client->shell_surfaces, link) + wl_signal_emit(&surface->events.ping_timeout, surface); + + client->ping_serial = 0; + + return 1; +} + +static void +shell_client_init_ping_timer(struct ds_shell_client *client) +{ + struct wl_display *display; + struct wl_event_loop *loop; + + display = wl_client_get_display(client->wl_client); + loop = wl_display_get_event_loop(display); + client->ping_timer = wl_event_loop_add_timer(loop, + shell_client_handle_ping_timeout, client); + if (client->ping_timer == NULL) + wl_client_post_no_memory(client->wl_client); +} + +static void +shell_bind(struct wl_client *wl_client, void *data, uint32_t version, + uint32_t id) +{ + struct ds_shell *shell = data; + struct ds_shell_client *client; + + client = calloc(1, sizeof *client); + if (client == NULL) { + wl_client_post_no_memory(wl_client); + return; + } + + client->wl_client = wl_client; + client->shell = shell; + + wl_list_init(&client->shell_surfaces); + + client->resource = + wl_resource_create(wl_client, &wl_shell_interface, version, id); + if (client->resource == NULL) { + free(client); + wl_client_post_no_memory(wl_client); + return; + } + + wl_resource_set_implementation(client->resource, &shell_impl, client, + shell_client_handle_resource_destroy); + + wl_list_insert(&shell->clients, &client->link); + + shell_client_init_ping_timer(client); +} diff --git a/src/libds/shell.h b/src/libds/shell.h new file mode 100644 index 0000000..c2306af --- /dev/null +++ b/src/libds/shell.h @@ -0,0 +1,157 @@ +#ifndef DS_SHELL_H +#define DS_SHELL_H + +#include + +#include "libds/output.h" + +#include "surface.h" + +enum ds_shell_surface_role +{ + DS_SHELL_SURFACE_ROLE_NONE, + DS_SHELL_SURFACE_ROLE_TOPLEVEL, + DS_SHELL_SURFACE_ROLE_POPUP, +}; + +struct ds_shell +{ + struct wl_global *global; + + struct wl_list clients; + + struct wl_listener display_destroy; + + struct { + struct wl_signal destroy; + struct wl_signal new_surface; + } events; + + uint32_t ping_timeout; +}; + +struct ds_shell_client +{ + struct ds_shell *shell; + + struct wl_resource *resource; + struct wl_client *wl_client; + struct wl_event_source *ping_timer; + + struct wl_list shell_surfaces; + + struct wl_list link; // ds_shell::clients + + uint32_t ping_serial; +}; + +struct ds_shell_toplevel_state +{ + bool maximized, fullscreen, resizing, activated; + uint32_t tiled; + uint32_t width, height; + uint32_t max_width, max_height; + uint32_t min_width, min_height; +}; + +struct ds_shell_toplevel_requested +{ + bool maximized, minimized, fullscreen; + struct ds_output *fullscreen_output; + struct wl_listener fullscreen_output_destroy; +}; + +struct ds_shell_toplevel +{ + struct ds_shell_surface *base; + bool added; + + struct ds_shell_surface *parent; + struct wl_listener parent_unmap; + + struct ds_shell_toplevel_state current, pending; + struct ds_shell_toplevel_requested requested; + + char *title; + char *app_id; + + struct { + struct wl_signal request_maximize; + struct wl_signal request_fullscreen; + struct wl_signal request_minimize; + struct wl_signal request_move; + struct wl_signal request_resize; + struct wl_signal request_show_window_menu; + struct wl_signal set_parent; + struct wl_signal set_title; + struct wl_signal set_app_id; + } events; +}; + +struct ds_xdg_popup +{ + +}; + +struct ds_shell_surface_state +{ + uint32_t configure_serial; + struct { + int x, y; + int width, height; + } geometry; +}; + +struct ds_shell_surface +{ + struct ds_shell_client *client; + struct ds_surface *surface; + + enum ds_shell_surface_role role; + + union { + struct ds_shell_toplevel *toplevel; + struct ds_xdg_popup *popup; + }; + + struct wl_resource *resource; + + struct wl_event_source *configure_idle; + uint32_t scheduled_serial; + struct wl_list configure_list; + + struct ds_shell_surface_state current, pending; + + struct wl_list link; // ds_shell_client::surfaces + + struct { + struct wl_listener surface_destroy; + struct wl_listener surface_commit; + } listener; + + struct { + struct wl_signal destroy; + struct wl_signal ping_timeout; + struct wl_signal new_popup; + struct wl_signal map; + struct wl_signal unmap; + struct wl_signal configure; + } events; + + bool added, configured, mapped; +}; + +struct ds_shell_surface_configure +{ + struct ds_shell_surface *shell_surface; + struct wl_list link; + uint32_t serial; +}; + +struct ds_shell_surface * +create_shell_surface(struct ds_shell_client *client, struct ds_surface *surface, + uint32_t id); + +void destroy_shell_surface(struct ds_shell_surface *surface); + +#endif diff --git a/src/libds/shell_surface.c b/src/libds/shell_surface.c new file mode 100644 index 0000000..73c498b --- /dev/null +++ b/src/libds/shell_surface.c @@ -0,0 +1,540 @@ +#include +#include +#include + +#include "libds/log.h" + +#include "shell.h" + +static const struct wl_shell_surface_interface shell_surface_impl; + +static void reset_shell_surface(struct ds_shell_surface *shell_surface); +static void shell_surface_handle_surface_destroy(struct wl_listener *listener, + void *data); +static void shell_surface_handle_surface_commit(struct wl_listener *listener, + void *data); +static void shell_surface_handle_resource_destroy(struct wl_resource *resource); +static void shell_surface_configure_destroy(struct ds_shell_surface_configure *configure); +static void surface_send_configure(void *user_data); +static void handle_shell_surface_commit(struct ds_surface *surface); + +WL_EXPORT void +ds_shell_surface_add_destroy_listener(struct ds_shell_surface *shell_surface, + struct wl_listener *listener) +{ + wl_signal_add(&shell_surface->events.destroy, listener); +} + +WL_EXPORT void +ds_shell_surface_add_map_listener(struct ds_shell_surface *shell_surface, + struct wl_listener *listener) +{ + wl_signal_add(&shell_surface->events.map, listener); +} + +WL_EXPORT void +ds_shell_surface_add_unmap_listener(struct ds_shell_surface *shell_surface, + struct wl_listener *listener) +{ + wl_signal_add(&shell_surface->events.unmap, listener); +} + +WL_EXPORT struct ds_surface * +ds_shell_surface_get_surface(struct ds_shell_surface *shell_surface) +{ + return shell_surface->surface; +} + +static const struct ds_surface_role shell_surface_role = +{ + .name = "shell_surface", + .commit = handle_shell_surface_commit, +}; + +struct ds_shell_surface * +create_shell_surface(struct ds_shell_client *client, struct ds_surface *surface, + uint32_t id) +{ + struct ds_shell_surface *shell_surface; + + shell_surface = calloc(1, sizeof *shell_surface); + if (!shell_surface) { + wl_client_post_no_memory(client->wl_client); + return NULL; + } + + shell_surface->client = client; + shell_surface->role = DS_SHELL_SURFACE_ROLE_NONE; + shell_surface->surface = surface; + shell_surface->resource = wl_resource_create(client->wl_client, + &wl_shell_surface_interface, wl_resource_get_version(client->resource), + id); + if (!shell_surface->resource) { + free(shell_surface); + wl_client_post_no_memory(client->wl_client); + return NULL; + } + + if (!ds_surface_set_role(shell_surface->surface, &shell_surface_role, + shell_surface, shell_surface->resource, -1)) { + free(shell_surface); + return NULL; + } + + wl_list_init(&shell_surface->configure_list); + + wl_signal_init(&shell_surface->events.destroy); + wl_signal_init(&shell_surface->events.ping_timeout); + wl_signal_init(&shell_surface->events.new_popup); + wl_signal_init(&shell_surface->events.map); + wl_signal_init(&shell_surface->events.unmap); + wl_signal_init(&shell_surface->events.configure); + + shell_surface->listener.surface_destroy.notify = + shell_surface_handle_surface_destroy; + ds_surface_add_destroy_listener(surface, + &shell_surface->listener.surface_destroy); + + shell_surface->listener.surface_commit.notify = + shell_surface_handle_surface_commit; + ds_surface_add_commit_listener(surface, + &shell_surface->listener.surface_commit); + + wl_resource_set_implementation(shell_surface->resource, &shell_surface_impl, + shell_surface, shell_surface_handle_resource_destroy); + + wl_list_insert(&client->shell_surfaces, &shell_surface->link); + + ds_inf("New shell_surface %p (res %p)", shell_surface, shell_surface->resource); + + return shell_surface; +} + +void +destroy_shell_surface(struct ds_shell_surface *shell_surface) +{ + reset_shell_surface(shell_surface); + + wl_resource_set_user_data(shell_surface->resource, NULL); + + ds_surface_reset_role_data(shell_surface->surface); + + wl_list_remove(&shell_surface->link); + wl_list_remove(&shell_surface->listener.surface_destroy.link); + wl_list_remove(&shell_surface->listener.surface_commit.link); + + free(shell_surface); +} + +static void +unmap_shell_surface(struct ds_shell_surface *shell_surface) +{ + struct ds_shell_surface_configure *configure, *tmp; + + // TODO handle popup + + if (shell_surface->mapped) + wl_signal_emit(&shell_surface->events.unmap, shell_surface); + + switch (shell_surface->role) { + case DS_SHELL_SURFACE_ROLE_TOPLEVEL: + if (shell_surface->toplevel->parent) { + wl_list_remove(&shell_surface->toplevel->parent_unmap.link); + shell_surface->toplevel->parent = NULL; + } + free(shell_surface->toplevel->title); + shell_surface->toplevel->title = NULL; + free(shell_surface->toplevel->app_id); + shell_surface->toplevel->app_id = NULL; + break; + case DS_SHELL_SURFACE_ROLE_POPUP: + // TODO + break; + case DS_SHELL_SURFACE_ROLE_NONE: + assert(false && "not reached"); + } + + wl_list_for_each_safe(configure, tmp, &shell_surface->configure_list, link) + shell_surface_configure_destroy(configure); + + if (shell_surface->configure_idle) { + wl_event_source_remove(shell_surface->configure_idle); + shell_surface->configure_idle = NULL; + } + + shell_surface->configured = false; + shell_surface->mapped = false; +} + +static void +reset_shell_surface(struct ds_shell_surface *shell_surface) +{ + struct ds_shell_toplevel_requested *req; + + if (shell_surface->role != DS_SHELL_SURFACE_ROLE_NONE) + unmap_shell_surface(shell_surface); + + if (shell_surface->added) { + wl_signal_emit(&shell_surface->events.destroy, shell_surface); + shell_surface->added = false; + } + + switch (shell_surface->role) { + case DS_SHELL_SURFACE_ROLE_TOPLEVEL: + req = &shell_surface->toplevel->requested; + if (req->fullscreen_output) + wl_list_remove(&req->fullscreen_output_destroy.link); + free(shell_surface->toplevel); + shell_surface->toplevel = NULL; + break; + case DS_SHELL_SURFACE_ROLE_POPUP: + // TODO + break; + case DS_SHELL_SURFACE_ROLE_NONE: + // This space is intentionally left blank + break; + } + + shell_surface->role = DS_SHELL_SURFACE_ROLE_NONE; +} + +static uint32_t +ds_shell_surface_schedule_configure(struct ds_shell_surface *shell_surface) +{ + struct wl_display *display; + struct wl_event_loop *loop; + + display = wl_client_get_display(shell_surface->client->wl_client); + loop = wl_display_get_event_loop(display); + + if (!shell_surface->configure_idle) { + shell_surface->scheduled_serial = wl_display_next_serial(display); + shell_surface->configure_idle = wl_event_loop_add_idle(loop, + surface_send_configure, shell_surface); + if (!shell_surface->configure_idle) + wl_client_post_no_memory(shell_surface->client->wl_client); + } + + return shell_surface->scheduled_serial; +} + +static void +handle_shell_surface_commit(struct ds_surface *surface) +{ + struct ds_shell_surface *shell_surface; + + shell_surface = ds_surface_get_role_data(surface); + shell_surface->current = shell_surface->pending; + + switch (shell_surface->role) { + case DS_SHELL_SURFACE_ROLE_NONE: + // inert toplevel or popup + break; + case DS_SHELL_SURFACE_ROLE_TOPLEVEL: + if (!shell_surface->toplevel->added) { + ds_shell_surface_schedule_configure(shell_surface); + shell_surface->toplevel->added = true; + } + // TODO + break; + case DS_SHELL_SURFACE_ROLE_POPUP: + // TODO + break; + } + + if (!shell_surface->added) { + shell_surface->added = true; + wl_signal_emit(&shell_surface->client->shell->events.new_surface, shell_surface); + } + + if (shell_surface->configured && + ds_surface_has_buffer(shell_surface->surface) && + !shell_surface->mapped) { + shell_surface->mapped = true; + wl_signal_emit(&shell_surface->events.map, shell_surface); + } +} + +void handle_shell_surface_precommit(struct ds_surface *surface) +{ + struct ds_shell_surface *shell_surface; + + shell_surface = ds_surface_get_role_data(surface); + + // TODO + (void)shell_surface; +} + +void +ds_shell_surface_ping(struct ds_shell_surface *shell_surface) +{ +} + +static void +shell_surface_handle_surface_destroy(struct wl_listener *listener, void *data) +{ + struct ds_shell_surface *shell_surface; + + shell_surface = wl_container_of(listener, shell_surface, listener.surface_destroy); + destroy_shell_surface(shell_surface); +} + +static void +shell_surface_handle_surface_commit(struct wl_listener *listener, void *data) +{ + struct ds_shell_surface *shell_surface; + + shell_surface = wl_container_of(listener, shell_surface, listener.surface_commit); + + if (ds_surface_has_buffer(shell_surface->surface) && + !shell_surface->configured) { + wl_resource_post_error(shell_surface->resource, + -1, + "shell_surface has never been configured"); + return; + } + + if (!ds_surface_get_role(shell_surface->surface)) { + wl_resource_post_error(shell_surface->resource, + -1, + "shell_surface must have a role"); + return; + } +} + +static void +shell_surface_handle_resource_destroy(struct wl_resource *resource) +{ + struct ds_shell_surface *shell_surface; + + shell_surface = wl_resource_get_user_data(resource); + if (!shell_surface) + return; + + destroy_shell_surface(shell_surface); +} + +static void +shell_surface_configure_destroy(struct ds_shell_surface_configure *configure) +{ + wl_list_remove(&configure->link); + free(configure); +} + +static void +create_shell_surface_toplevel(struct ds_shell_surface *shell_surface) +{ + assert(shell_surface->toplevel == NULL); + + shell_surface->toplevel = calloc(1, sizeof *shell_surface->toplevel); + if (!shell_surface->toplevel) { + wl_resource_post_no_memory(shell_surface->resource); + return; + } + + shell_surface->toplevel->base = shell_surface; + + wl_signal_init(&shell_surface->toplevel->events.request_maximize); + wl_signal_init(&shell_surface->toplevel->events.request_fullscreen); + wl_signal_init(&shell_surface->toplevel->events.request_minimize); + wl_signal_init(&shell_surface->toplevel->events.request_move); + wl_signal_init(&shell_surface->toplevel->events.request_resize); + wl_signal_init(&shell_surface->toplevel->events.request_show_window_menu); + wl_signal_init(&shell_surface->toplevel->events.set_parent); + wl_signal_init(&shell_surface->toplevel->events.set_title); + wl_signal_init(&shell_surface->toplevel->events.set_app_id); + + shell_surface->role = DS_SHELL_SURFACE_ROLE_TOPLEVEL; +} + +static void +shell_surface_handle_pong(struct wl_client *wl_client, + struct wl_resource *resource, uint32_t serial) +{ + struct ds_shell_surface *shell_surface; + struct ds_shell_client *client; + + shell_surface = wl_resource_get_user_data(resource); + + client = shell_surface->client; + if (client->ping_serial != serial) + return; + + wl_event_source_timer_update(client->ping_timer, 0); + client->ping_serial = 0; +} + +static void +shell_surface_handle_move(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *seat_resource, + uint32_t serial) +{ + struct ds_shell_surface *shell_surface; + + shell_surface = wl_resource_get_user_data(resource); + + // TODO + (void)shell_surface; +} + +static void +shell_surface_handle_resize(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *seat_resource, + uint32_t serial, uint32_t edges) +{ + struct ds_shell_surface *shell_surface; + + shell_surface = wl_resource_get_user_data(resource); + + // TODO + (void)shell_surface; +} + +static void +shell_surface_handle_set_toplevel(struct wl_client *client, struct wl_resource *resource) +{ + struct ds_shell_surface *shell_surface; + + shell_surface = wl_resource_get_user_data(resource); + create_shell_surface_toplevel(shell_surface); +} + +static void +shell_surface_handle_set_transient(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *parent_resource, + int32_t x, int32_t y, uint32_t flags) +{ + struct ds_shell_surface *shell_surface; + + shell_surface = wl_resource_get_user_data(resource); + + // TODO + (void)shell_surface; + ds_err("Not implemented yet."); +} + +static void +shell_surface_handle_set_fullscreen(struct wl_client *client, + struct wl_resource *resource, uint32_t method, uint32_t framerate, + struct wl_resource *output_resource) +{ + struct ds_shell_surface *shell_surface; + + shell_surface = wl_resource_get_user_data(resource); + + // TODO + (void)shell_surface; + ds_err("Not implemented yet."); +} + +static void +shell_surface_handle_set_popup(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *seat_resource, + uint32_t serial, struct wl_resource *parent_resource, + int32_t x, int32_t y, uint32_t flags) +{ + struct ds_shell_surface *shell_surface; + + shell_surface = wl_resource_get_user_data(resource); + + // TODO + (void)shell_surface; + ds_err("Not implemented yet."); +} + +static void +shell_surface_handle_set_maximized(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *output_resource) +{ + struct ds_shell_surface *shell_surface; + + shell_surface = wl_resource_get_user_data(resource); + + shell_surface->toplevel->requested.maximized = true; + wl_signal_emit(&shell_surface->toplevel->events.request_maximize, shell_surface); + ds_shell_surface_schedule_configure(shell_surface); +} + +static void +shell_surface_handle_set_title(struct wl_client *client, + struct wl_resource *resource, const char *title) +{ + struct ds_shell_surface *shell_surface; + char *tmp; + + shell_surface = wl_resource_get_user_data(resource); + tmp = strdup(title); + if (!tmp) { + wl_resource_post_no_memory(resource); + return; + } + + if (shell_surface->toplevel->title) + free(shell_surface->toplevel->title); + + shell_surface->toplevel->title = tmp; + wl_signal_emit(&shell_surface->toplevel->events.set_title, shell_surface); +} + +static void +shell_surface_handle_set_class(struct wl_client *client, + struct wl_resource *resource, const char *clas) +{ + struct ds_shell_surface *shell_surface; + + shell_surface = wl_resource_get_user_data(resource); + + // TODO + (void)shell_surface; + ds_err("Not implemented yet."); +} + +static const struct wl_shell_surface_interface shell_surface_impl = +{ + .pong = shell_surface_handle_pong, + .move = shell_surface_handle_move, + .resize = shell_surface_handle_resize, + .set_toplevel = shell_surface_handle_set_toplevel, + .set_transient = shell_surface_handle_set_transient, + .set_fullscreen = shell_surface_handle_set_fullscreen, + .set_popup = shell_surface_handle_set_popup, + .set_maximized = shell_surface_handle_set_maximized, + .set_title = shell_surface_handle_set_title, + .set_class = shell_surface_handle_set_class, +}; + +static void +surface_send_configure(void *user_data) +{ + struct ds_shell_surface *shell_surface; + struct ds_shell_surface_configure *configure; + uint32_t width, height; + uint32_t edges = 0; + + shell_surface = user_data; + shell_surface->configure_idle = NULL; + + // TDOO: Not sure if shell needs the struct ds_shell_surface_configure. + configure = calloc(1, sizeof *configure); + if (!configure) { + wl_client_post_no_memory(shell_surface->client->wl_client); + return; + } + + wl_list_insert(shell_surface->configure_list.prev, &configure->link); + configure->serial = shell_surface->scheduled_serial; + configure->shell_surface = shell_surface; + + wl_signal_emit(&shell_surface->events.configure, configure); + + edges = (WL_SHELL_SURFACE_RESIZE_TOP | WL_SHELL_SURFACE_RESIZE_LEFT); // fixed default value + width = shell_surface->current.geometry.width; + height = shell_surface->current.geometry.height; + + wl_shell_surface_send_configure(shell_surface->resource, edges, width, height); + + shell_surface->configured = true; + + // TDOO: Not sure if shell needs the struct ds_shell_surface_configure. + shell_surface_configure_destroy(configure); +} -- 2.7.4 From 4cb5ea8865251643d44ac600a3a7701bb208f68e Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Thu, 19 May 2022 10:38:44 +0900 Subject: [PATCH 04/16] client: add simple-shm-shell sample This is a simple wayland-client which use wl_shm and wl_shell interface. Change-Id: I48cfeebde8e6a5e6621942c2f0f7c642f5372111 --- packaging/libds.spec | 1 + src/clients/meson.build | 12 ++ src/clients/simple-shm-shell.c | 339 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 352 insertions(+) create mode 100644 src/clients/simple-shm-shell.c diff --git a/packaging/libds.spec b/packaging/libds.spec index 2ffdca0..5258295 100644 --- a/packaging/libds.spec +++ b/packaging/libds.spec @@ -103,6 +103,7 @@ ninja -C builddir install %{_bindir}/tinyds-tdm %{_bindir}/ds-simple-tbm %{_bindir}/tinyds-tdm-libinput +%{_bindir}/ds-simple-shm-shell %files tizen-keyrouter %manifest %{name}.manifest diff --git a/src/clients/meson.build b/src/clients/meson.build index 360c425..009016c 100644 --- a/src/clients/meson.build +++ b/src/clients/meson.build @@ -1,3 +1,15 @@ +simple_shm_shell_files = ['simple-shm-shell.c'] +simple_shm_shell_deps = [ + dependency('wayland-client', required: true), +] + +executable('ds-simple-shm-shell', + simple_shm_shell_files, + dependencies: simple_shm_shell_deps, + install_dir: libds_bindir, + install: true, +) + wayland_tbm_client = dependency('wayland-tbm-client', required: false) libtbm = dependency('libtbm', required: false) diff --git a/src/clients/simple-shm-shell.c b/src/clients/simple-shm-shell.c new file mode 100644 index 0000000..52d9ed2 --- /dev/null +++ b/src/clients/simple-shm-shell.c @@ -0,0 +1,339 @@ +/* +Copyright (C) 2015 - 2016 Samsung Electronics co., Ltd. All Rights Reserved. + +Contact: + SooChan Lim + Changyeon Lee + JunKyeong Kim + Boram Park + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the next +paragraph) shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define BUF_WIDTH 1920 +#define BUF_HEIGHT 1080 + +#define RETURN_VAL_IF_FAIL(c,v) {\ + if(!((c))){\ + fprintf(stderr, "[%s(%d)] '%s' failed.", __func__, __LINE__, #c);\ + return (v);\ + }\ +} + +#define GOTO_IF_FAIL(c,l) {\ + if(!(c)) {\ + fprintf(stderr, "[%s(%d)] '%s' failed.", __func__, __LINE__, #c);\ + goto l;\ + }\ +} + +#define EXIT_IF_FAIL(c) {\ + if(!(c)) {\ + fprintf (stderr, "[%s(%d)] '%s' failed.\n",__func__,__LINE__,#c);\ + exit(0);\ + }\ +} + +struct wl_test_info { + int width; + int height; + int stride; + int format; + int size; + + struct wl_display *display; + struct wl_registry *registry; + + /* global objects */ + struct wl_compositor *compositor; + struct wl_shm *shm; + struct wl_shell *shell; + struct wl_shm_pool *shm_pool; + + /* objects */ + struct wl_surface *surface; + struct wl_shell_surface *shell_surface; + struct wl_buffer *buffer; +}; + +static int +_create_anonymous_file (off_t size) +{ + static const char template[] = + "/shooter-XXXXXX"; + const char *path; + char *name = NULL; + int fd = -1; + int ret = -1; + + path = getenv("XDG_RUNTIME_DIR"); + if (!path) { + errno = ENOENT; + return -1; + } + + name = malloc(strlen(path) + sizeof(template)); + GOTO_IF_FAIL(name != NULL, fail); + + strcpy(name, path); + strcat(name, template); + + fd = mkstemp(name); + if (fd >= 0) + unlink(name); + + ret = ftruncate(fd, size); + GOTO_IF_FAIL(ret >= 0, fail); + + free(name); + + return fd; +fail: + if (fd >= 0) + close(fd); + + if (name) + free(name); + + return -1; +} + +static void +_destroy_anonymous_file(int fd) +{ + if (fd < 0) return; + + close(fd); +} + + +static struct wl_test_info * +_create_wl_test_info (void) +{ + struct wl_test_info *test_info = NULL; + + test_info = calloc(1, sizeof(struct wl_test_info)); + RETURN_VAL_IF_FAIL(test_info != NULL, NULL); + + return test_info; +} + +static void +_destroy_wl_test_info (struct wl_test_info *test_info) +{ + if (!test_info) return; + + free(test_info); +} + +static struct wl_shm_pool * +_create_shm_pool(struct wl_shm *shm, int size) +{ + struct wl_shm_pool *shm_pool = NULL; + void *data = NULL; + int fd = -1; + + fd = _create_anonymous_file(size); + GOTO_IF_FAIL(fd >= 0, fail); + + data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + GOTO_IF_FAIL(data != NULL, fail); + + memset(data, 0xff, size); + munmap(data, size); + + shm_pool = wl_shm_create_pool(shm, fd, size); + GOTO_IF_FAIL(shm_pool != NULL, fail); + + _destroy_anonymous_file(fd); + + return shm_pool; + +fail: + if (fd > 0) + _destroy_anonymous_file(fd); + + return NULL; +} + +void +_destroy_shm_pool(struct wl_shm_pool *shm_pool) +{ + if (!shm_pool) return; + + wl_shm_pool_destroy(shm_pool); +} + +static void +handle_global(void *data, struct wl_registry *registry, uint32_t name, + const char *interface, uint32_t version) +{ + struct wl_test_info *ti = (struct wl_test_info *)data; + + if (strcmp(interface, "wl_compositor") == 0) { + ti->compositor = wl_registry_bind(registry, name, + &wl_compositor_interface, 3); + if (!ti->compositor) + printf("%s(%d): Error. fail to bind %s.\n", + __func__, __LINE__, interface); + else + printf("%s(%d): bind %s.\n", __func__, __LINE__, interface); + } else if (strcmp(interface, "wl_shm") == 0) { + ti->shm = wl_registry_bind(registry, name, &wl_shm_interface, 1); + if (!ti->shm) + printf("%s(%d): Error. fail to bind %s.\n", + __func__, __LINE__, interface); + else + printf("%s(%d): bind %s.\n", __func__, __LINE__, interface); + + ti->shm_pool = _create_shm_pool(ti->shm, ti->size); + if (!ti->shm_pool) + printf("%s(%d): Error. fail to create wl_shm_pool.\n", + __func__, __LINE__); + else + printf("%s(%d): success to create wl_shm_pool.\n", + __func__, __LINE__); + + } else if (strcmp(interface, "wl_shell") == 0) { + ti->shell = wl_registry_bind(registry, name, &wl_shell_interface, 1); + if (!ti->shell) + printf("%s(%d): Error. fail to bind %s.\n", + __func__, __LINE__, interface); + else + printf("%s(%d): bind %s.\n", __func__, __LINE__, interface); + } else { + printf("%s(%d): Not bind %s.\n", __func__, __LINE__, interface); + } +} + +static void +handle_global_remove(void *data, struct wl_registry *registry, uint32_t name) +{ + +} + +static const struct wl_registry_listener registry_listener = { + handle_global, + handle_global_remove +}; + +int main (void) +{ + struct wl_test_info *ti = NULL; + int ret = 0; + + /* create test info */ + ti = _create_wl_test_info (); + GOTO_IF_FAIL(ti != NULL, fail); + + /* init */ + ti->width = BUF_WIDTH; + ti->height = BUF_HEIGHT; + ti->stride = ti->width * 4; + ti->format = WL_SHM_FORMAT_XRGB8888; + ti->size = ti->stride * ti->height; + + /* connect display */ + ti->display = wl_display_connect(NULL); + GOTO_IF_FAIL(ti->display != NULL, fail); + + /* get the registry */ + ti->registry = wl_display_get_registry(ti->display); + GOTO_IF_FAIL(ti->registry != NULL, fail); + + /* get the global objects */ + wl_registry_add_listener(ti->registry, ®istry_listener, ti); + wl_display_dispatch(ti->display); + wl_display_roundtrip(ti->display); + + /* check the global objects */ + GOTO_IF_FAIL(ti->compositor != NULL, fail); + GOTO_IF_FAIL(ti->shm != NULL, fail); + GOTO_IF_FAIL(ti->shell != NULL, fail); + GOTO_IF_FAIL(ti->shm_pool != NULL, fail); + + /* create objects */ + ti->surface = wl_compositor_create_surface(ti->compositor); + GOTO_IF_FAIL(ti->surface != NULL, fail); + + ti->shell_surface = wl_shell_get_shell_surface(ti->shell, ti->surface); + GOTO_IF_FAIL(ti->shell_surface != NULL, fail); + + wl_shell_surface_set_toplevel(ti->shell_surface); + + ti->buffer = wl_shm_pool_create_buffer(ti->shm_pool, 0, + ti->width, ti->height, ti->stride, ti->format); + GOTO_IF_FAIL(ti->buffer != NULL, fail); + + wl_surface_attach(ti->surface, ti->buffer, 0, 0); + wl_surface_damage(ti->surface, 0, 0, ti->width, ti->height); + wl_surface_commit(ti->surface); + + wl_display_roundtrip(ti->display); + + /* main loop */ + printf("%s(%d): loop start.\n", __func__, __LINE__); + while (ret >= 0) { + ret = wl_display_dispatch(ti->display); + printf("%s(%d): loop running(ret=%d).\n", __func__, __LINE__, ret); + } + printf("%s(%d): loop end.\n", __func__, __LINE__); + +fail: + /* destory objects */ + if (ti->shell_surface) + wl_shell_surface_destroy(ti->shell_surface); + if (ti->surface) + wl_surface_destroy(ti->surface); + if (ti->buffer) + wl_buffer_destroy(ti->buffer); + + /* destroy global objects */ + if (ti->shell) + wl_shell_destroy(ti->shell); + if (ti->shm_pool) + _destroy_shm_pool(ti->shm_pool); + if (ti->shm) + wl_shm_destroy(ti->shm); + if (ti->compositor) + wl_compositor_destroy(ti->compositor); + + /* destory registry and display */ + if (ti->registry) + wl_registry_destroy(ti->registry); + if (ti->display) + wl_display_disconnect(ti->display); + + /* destroy test_info */ + if (ti) + _destroy_wl_test_info(ti); + + return 0; +} -- 2.7.4 From 3909f200f7443473f4810a00de45125ee1f67549 Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Fri, 27 May 2022 11:39:45 +0900 Subject: [PATCH 05/16] add review-bot as a reviewer Change-Id: Ida05f30c7edcc66605593a600e27901ced3f71c6 --- CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODEOWNERS b/CODEOWNERS index d52bfc2..06c492b 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. -* @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 @review-bot -- 2.7.4 From 7eac7a77a9cefbc6b6a82875ff89de69c3c78b04 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Thu, 2 Jun 2022 13:14:29 +0900 Subject: [PATCH 06/16] security: Remove meaningless double check In the function tizen_security_check_privilege(), it double-checks a g_cynara to see if it exists and then return different value if it doesn't exist which is contradictory. Let's just return false if initializing the cynara has been failed or not been initialized. Change-Id: If141f0e9bcc75ee0804cfa65bb136121d4d23fcc --- src/libds-tizen/util/security.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/libds-tizen/util/security.c b/src/libds-tizen/util/security.c index ad19027..8544951 100644 --- a/src/libds-tizen/util/security.c +++ b/src/libds-tizen/util/security.c @@ -55,11 +55,6 @@ tizen_security_check_privilege(pid_t pid, uid_t uid, const char *privilege) int len = -1; int ret = -1; - /* If cynara_initialize() has been (retried) and failed, we suppose that cynara is not available. */ - /* Then we return true as if there is no security check available. */ - if (!g_cynara) - return true; - if (!g_cynara) { ds_err("security has not been initialized.\n"); return false; -- 2.7.4 From 9825b7f921f4b093f81ab4ff657ca81875cc5fe8 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Thu, 2 Jun 2022 13:50:54 +0900 Subject: [PATCH 07/16] security: Refactor implementation for cynara No functional changes Change-Id: I8cfe200969f71ad761dae5c06bfa3227ca89ffd5 --- src/libds-tizen/util.h | 2 +- src/libds-tizen/util/security.c | 180 +++++++++++++++++++++++----------------- 2 files changed, 104 insertions(+), 78 deletions(-) diff --git a/src/libds-tizen/util.h b/src/libds-tizen/util.h index 18ad811..82e178b 100644 --- a/src/libds-tizen/util.h +++ b/src/libds-tizen/util.h @@ -5,7 +5,7 @@ #define MIN(a,b) ((a)<(b)?(a):(b)) -int +bool tizen_security_init(void); void diff --git a/src/libds-tizen/util/security.c b/src/libds-tizen/util/security.c index 8544951..9983e24 100644 --- a/src/libds-tizen/util/security.c +++ b/src/libds-tizen/util/security.c @@ -1,4 +1,3 @@ - #include #include #include @@ -8,20 +7,61 @@ #include "util.h" #ifdef HAVE_CYNARA +#include +#include + #include #include #include #include -#include -#include #define CYNARA_BUFSIZE 128 -static cynara *g_cynara = NULL; -static int g_cynara_refcount = 0; +struct ds_cynara +{ + cynara *handle; + int references; +}; + +static struct ds_cynara ds_cynara; + +static bool ds_cynara_init(void); +static void ds_cynara_finish(void); +static bool ds_cynara_check_privilege(pid_t pid, uid_t uid, + const char *privilege); +#endif + +bool +tizen_security_check_privilege(pid_t pid, uid_t uid, const char *privilege) +{ +#ifdef HAVE_CYNARA + return ds_cynara_check_privilege(pid, uid, privilege); +#else + return true; +#endif +} + +bool +tizen_security_init(void) +{ +#ifdef HAVE_CYNARA + return ds_cynara_init(); +#else + return true; +#endif +} + +void +tizen_security_finish(void) +{ +#ifdef HAVE_CYNARA + ds_cynara_finish(); +#endif +} +#ifdef HAVE_CYNARA static void -__security_log_print(int err, const char *fmt, ...) +print_cynara_error(int err, const char *fmt, ...) { int ret; va_list args; @@ -42,12 +82,56 @@ __security_log_print(int err, const char *fmt, ...) ds_err("%s is failed. (%s)\n", tmp, buf); } -#endif -bool -tizen_security_check_privilege(pid_t pid, uid_t uid, const char *privilege) +static bool +ds_cynara_init(void) +{ + int ret = CYNARA_API_SUCCESS; + int retry_cnt = 0; + + if (++ds_cynara.references != 1) + return true; + + for (retry_cnt = 0; retry_cnt < 5; retry_cnt++) { + ds_dbg("Retry cynara initialize: %d\n", retry_cnt + 1); + + ret = cynara_initialize(&ds_cynara.handle, NULL); + + if (CYNARA_API_SUCCESS == ret) { + ds_dbg("Succeed to initialize cynara !\n"); + return true; + } + + print_cynara_error(ret, "cynara_initialize"); + } + + ds_err("Failed to initialize cynara! (error:%d, retry_cnt=%d)\n", + ret, retry_cnt); + + --ds_cynara.references; + + return false; + +} + +static void +ds_cynara_finish(void) +{ + if (ds_cynara.references < 1) { + ds_err("%s called without ds_cynara_init\n", __FUNCTION__); + return; + } + + if (--ds_cynara.references != 0) + return; + + cynara_finish(ds_cynara.handle); + ds_cynara.handle = NULL; +} + +static bool +ds_cynara_check_privilege(pid_t pid, uid_t uid, const char *privilege) { -#ifdef HAVE_CYNARA bool res = false; char *client_smack = NULL; char *client_session = NULL; @@ -55,8 +139,8 @@ tizen_security_check_privilege(pid_t pid, uid_t uid, const char *privilege) int len = -1; int ret = -1; - if (!g_cynara) { - ds_err("security has not been initialized.\n"); + if (!ds_cynara.handle) { + ds_err("ds_cynara has not been initialized.\n"); return false; } @@ -70,86 +154,28 @@ tizen_security_check_privilege(pid_t pid, uid_t uid, const char *privilege) if (!client_session) goto finish; - ret = cynara_check(g_cynara, client_smack, client_session, - uid_str, privilege); + ret = cynara_check(ds_cynara.handle, client_smack, client_session, + uid_str, privilege); if (ret == CYNARA_API_ACCESS_ALLOWED) res = true; else - __security_log_print(ret, "privilege: %s, client_smack: %s, pid: %d", privilege, client_smack, pid); + print_cynara_error(ret, "privilege: %s, client_smack: %s, pid: %d", + privilege, client_smack, pid); finish: - ds_dbg("Privilege Check For '%s' %s pid:%u uid:%u client_smack:%s(len:%d) client_session:%s ret:%d", + ds_dbg("Privilege Check For '%s' %s pid:%u uid:%u client_smack:%s(len:%d) " + "client_session:%s ret:%d", privilege, res ? "SUCCESS" : "FAIL", pid, uid, client_smack ? client_smack : "N/A", len, client_session ? client_session: "N/A", ret); if (client_session) free(client_session); + if (client_smack) free(client_smack); return res; -#else - return true; -#endif } - -int -tizen_security_init(void) -{ -#ifdef HAVE_CYNARA - int ret = CYNARA_API_SUCCESS; - int retry_cnt = 0; - static bool retried = false; - - if (++g_cynara_refcount != 1) - return g_cynara_refcount; - - if (!g_cynara && false == retried) { - retried = true; - - for (retry_cnt = 0; retry_cnt < 5; retry_cnt++) { - ds_dbg("Retry cynara initialize: %d\n", retry_cnt + 1); - - ret = cynara_initialize(&g_cynara, NULL); - - if (CYNARA_API_SUCCESS == ret) { - ds_dbg("Succeed to initialize cynara !\n"); - return 1; - } - - __security_log_print(ret, "cynara_initialize"); - g_cynara = NULL; - } - } - - ds_err("Failed to initialize _security ! (error:%d, retry_cnt=%d)\n", - ret, retry_cnt); - --g_cynara_refcount; - - return 0; -#else - return 1; #endif -} - -void -tizen_security_finish(void) -{ -#ifdef HAVE_CYNARA - if (g_cynara_refcount < 1) { - ds_err("%s called without tizen_security_init\n", __FUNCTION__); - return; - } - - if (--g_cynara_refcount != 0) - return; - - if (g_cynara) { - cynara_finish(g_cynara); - g_cynara = NULL; - } -#endif -} - -- 2.7.4 From 8a30c383a95bbe32229ed178ee4b3d4d7aa661fc Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Thu, 2 Jun 2022 13:53:14 +0900 Subject: [PATCH 08/16] tizen-util: Include an appropriate header Change-Id: I3ee70dc2ed75a4ef04ac7d8c604d5be8521651d0 --- src/libds-tizen/util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libds-tizen/util.h b/src/libds-tizen/util.h index 82e178b..126467c 100644 --- a/src/libds-tizen/util.h +++ b/src/libds-tizen/util.h @@ -1,7 +1,7 @@ #ifndef DS_UTIL_H #define DS_UTIL_H -#include +#include #define MIN(a,b) ((a)<(b)?(a):(b)) -- 2.7.4 From cb42d11df4a866350f457d729786ba8478b0a5f3 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Thu, 2 Jun 2022 14:22:55 +0900 Subject: [PATCH 09/16] security: Enable cynara to be built This patch also removes conditional compilation for cynara. This should be considered again if it gets needed. Change-Id: I0597b3914780c30ce2b1835dd7089b6bc8f47888 --- packaging/libds.spec | 3 +++ src/libds-tizen/util/meson.build | 5 +++++ src/libds-tizen/util/security.c | 26 +++++--------------------- 3 files changed, 13 insertions(+), 21 deletions(-) diff --git a/packaging/libds.spec b/packaging/libds.spec index 5258295..ed21c53 100644 --- a/packaging/libds.spec +++ b/packaging/libds.spec @@ -23,6 +23,9 @@ BuildRequires: pkgconfig(libtbm) BuildRequires: pkgconfig(wayland-tbm-server) BuildRequires: pkgconfig(wayland-tbm-client) BuildRequires: pkgconfig(tizen-dpms-server) +BuildRequires: pkgconfig(cynara-client) +BuildRequires: pkgconfig(cynara-session) +BuildRequires: pkgconfig(libsmack) %description Wayland Compositor Library diff --git a/src/libds-tizen/util/meson.build b/src/libds-tizen/util/meson.build index 3d34ab8..0ec6a9d 100644 --- a/src/libds-tizen/util/meson.build +++ b/src/libds-tizen/util/meson.build @@ -1 +1,6 @@ libds_tizen_files += files('security.c') +libds_tizen_deps += [ + dependency('cynara-client', required: true), + dependency('cynara-session', required: true), + dependency('libsmack', required: true) +] diff --git a/src/libds-tizen/util/security.c b/src/libds-tizen/util/security.c index 9983e24..b592577 100644 --- a/src/libds-tizen/util/security.c +++ b/src/libds-tizen/util/security.c @@ -1,20 +1,17 @@ +#include +#include #include #include #include -#include "libds/log.h" - -#include "util.h" - -#ifdef HAVE_CYNARA -#include -#include - #include #include #include #include +#include "libds/log.h" +#include "util.h" + #define CYNARA_BUFSIZE 128 struct ds_cynara @@ -29,37 +26,25 @@ static bool ds_cynara_init(void); static void ds_cynara_finish(void); static bool ds_cynara_check_privilege(pid_t pid, uid_t uid, const char *privilege); -#endif bool tizen_security_check_privilege(pid_t pid, uid_t uid, const char *privilege) { -#ifdef HAVE_CYNARA return ds_cynara_check_privilege(pid, uid, privilege); -#else - return true; -#endif } bool tizen_security_init(void) { -#ifdef HAVE_CYNARA return ds_cynara_init(); -#else - return true; -#endif } void tizen_security_finish(void) { -#ifdef HAVE_CYNARA ds_cynara_finish(); -#endif } -#ifdef HAVE_CYNARA static void print_cynara_error(int err, const char *fmt, ...) { @@ -178,4 +163,3 @@ finish: return res; } -#endif -- 2.7.4 From a13252f49dbe4abb56b6f957688189530b048c3f Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Fri, 3 Jun 2022 18:05:12 +0900 Subject: [PATCH 10/16] keyrouter: Fix wrong return value According to implementation of pepper keyrouter which is a reference of libds keyrouter, keyrouter_grab_check_grabbed() is supposed to return true if a list of MODE_EXCLUSIVE is not empty. This error seems to have been introduced by mistake during the migration from pepper. Change-Id: I18f3b133cb44e983d929da1c525c8bf878cdd5c6 --- src/libds-tizen/keyrouter/keyrouter_grab.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libds-tizen/keyrouter/keyrouter_grab.c b/src/libds-tizen/keyrouter/keyrouter_grab.c index f5467ae..053b3e8 100644 --- a/src/libds-tizen/keyrouter/keyrouter_grab.c +++ b/src/libds-tizen/keyrouter/keyrouter_grab.c @@ -79,9 +79,9 @@ keyrouter_grab_check_grabbed(struct ds_tizen_keyrouter_grab *keyrouter_grab, switch(type) { case TIZEN_KEYROUTER_MODE_EXCLUSIVE: if (wl_list_empty(list) == false) - ret = false; - else ret = true; + else + ret = false; break; case TIZEN_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE: ret = keyrouter_grab_check_duplicated_data(list, data); -- 2.7.4 From af0d265c90ca3824e2373b8c8c50b6d4b810b316 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Fri, 3 Jun 2022 18:12:29 +0900 Subject: [PATCH 11/16] keyrouter: Return an appropriate value The return value of keyrouter_grab_check_grabbed() is boolean. So let's make it right. Change-Id: I27048b419ad8e5b13060b5d87f2948b6e3c15d80 --- src/libds-tizen/keyrouter/keyrouter_grab.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libds-tizen/keyrouter/keyrouter_grab.c b/src/libds-tizen/keyrouter/keyrouter_grab.c index 053b3e8..a836292 100644 --- a/src/libds-tizen/keyrouter/keyrouter_grab.c +++ b/src/libds-tizen/keyrouter/keyrouter_grab.c @@ -93,7 +93,7 @@ keyrouter_grab_check_grabbed(struct ds_tizen_keyrouter_grab *keyrouter_grab, ret = keyrouter_grab_check_duplicated_data(list, data); break; default: - ret = TIZEN_KEYROUTER_ERROR_INVALID_MODE; + ret = true; break; } -- 2.7.4 From 402b30f8013e1231d5032103fc1b3493cd5abf96 Mon Sep 17 00:00:00 2001 From: Junkyeong Kim Date: Tue, 7 Jun 2022 13:29:44 +0900 Subject: [PATCH 12/16] dpms: fix build error Change-Id: I06c768d97d26ccee3ca85825e653c6cc56538539 Signed-off-by: Junkyeong Kim --- include/libds-tizen/dpms.h | 2 +- src/libds-tizen/dpms.c | 15 ++++++++------- src/libds-tizen/meson.build | 2 ++ 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/include/libds-tizen/dpms.h b/include/libds-tizen/dpms.h index 3293ae8..10df4c1 100644 --- a/include/libds-tizen/dpms.h +++ b/include/libds-tizen/dpms.h @@ -30,7 +30,7 @@ enum ds_tizen_dpms_error struct ds_tizen_dpms_event { //struct ds_output *output; - ds_tizen_dpms_mode mode; + enum ds_tizen_dpms_mode mode; }; struct ds_tizen_dpms * diff --git a/src/libds-tizen/dpms.c b/src/libds-tizen/dpms.c index c5bcabb..315d6c0 100644 --- a/src/libds-tizen/dpms.c +++ b/src/libds-tizen/dpms.c @@ -3,9 +3,10 @@ #include #include #include "libds/log.h" -#include "libds-tizen/dpms.h" #include "libds/output.h" +#include "libds-tizen/dpms.h" #include "tizen-dpms-server-protocol.h" +#include "util.h" struct ds_tizen_dpms { @@ -53,8 +54,8 @@ ds_tizen_dpms_create(struct wl_display *display) wl_signal_init(&dpms->events.set_dpms); wl_signal_init(&dpms->events.get_dpms); - dpms->display_destroy.notify = dpms_handle_display_destroy; - wl_display_add_destroy_listener(display, &dpms->display_destroy); + dpms->destroy.notify = dpms_handle_display_destroy; + wl_display_add_destroy_listener(display, &dpms->destroy); ds_inf("global create : tizen_dpms_manager(%p)", dpms); @@ -103,12 +104,12 @@ dpms_handle_display_destroy(struct wl_listener *listener, void *data) { struct ds_tizen_dpms *dpms; - dpms = wl_container_of(listener, dpms, display_destroy); + dpms = wl_container_of(listener, dpms, destroy); ds_inf("global destroy : tizen_dpms_manager(%p)", dpms); wl_signal_emit(&dpms->events.destroy, dpms); - wl_list_remove(&dpms->display_destroy.link); + wl_list_remove(&dpms->destroy.link); wl_resource_set_user_data(dpms->res, NULL); wl_global_destroy(dpms->global); free(dpms); @@ -132,8 +133,8 @@ _tizen_dpms_manager_handle_set_dpms(struct wl_client *client, if (mode > DS_TIZEN_DPMS_MODE_OFF) { ds_err("set dpms error : not supported mode(%d)", mode); - tizen_dpms_manager_send_set_state(resource, E_DPMS_MODE_OFF, - E_DPMS_MANAGER_ERROR_INVALID_PARAMETER); + tizen_dpms_manager_send_set_state(resource, DS_TIZEN_DPMS_MODE_OFF, + DS_TIZEN_DPMS_ERROR_INVALID_PARAMETER); return; } diff --git a/src/libds-tizen/meson.build b/src/libds-tizen/meson.build index 0d780a3..6779a72 100644 --- a/src/libds-tizen/meson.build +++ b/src/libds-tizen/meson.build @@ -1,6 +1,7 @@ libds_tizen_files = [ 'pixel_format.c', 'tbm_server.c', + 'dpms.c', ] libds_tizen_deps = [ @@ -8,6 +9,7 @@ libds_tizen_deps = [ dependency('libdrm', required: true), dependency('libtbm', required: true), dependency('wayland-tbm-server', required: true), + dependency('tizen-dpms-server', required: true), ] subdir('allocator') -- 2.7.4 From 2d2ba4d16f5fcbaf9eb97f0905dbae4740076bf2 Mon Sep 17 00:00:00 2001 From: Junkyeong Kim Date: Tue, 7 Jun 2022 13:31:32 +0900 Subject: [PATCH 13/16] example: add tinyds-tdm-dpms Change-Id: Ic63b2893120fc46865559a49e0dc34c376f3a1ca Signed-off-by: Junkyeong Kim --- packaging/libds.spec | 1 + src/examples/meson.build | 13 + src/examples/tinyds-tdm-dpms.c | 672 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 686 insertions(+) create mode 100644 src/examples/tinyds-tdm-dpms.c diff --git a/packaging/libds.spec b/packaging/libds.spec index ed21c53..aefff95 100644 --- a/packaging/libds.spec +++ b/packaging/libds.spec @@ -107,6 +107,7 @@ ninja -C builddir install %{_bindir}/ds-simple-tbm %{_bindir}/tinyds-tdm-libinput %{_bindir}/ds-simple-shm-shell +%{_bindir}/tinyds-tdm-dpms %files tizen-keyrouter %manifest %{name}.manifest diff --git a/src/examples/meson.build b/src/examples/meson.build index 5c5c437..aad893e 100644 --- a/src/examples/meson.build +++ b/src/examples/meson.build @@ -82,4 +82,17 @@ if get_option('tizen') install_dir: libds_bindir, install : true ) + executable('tinyds-tdm-dpms', + 'tinyds-tdm-dpms.c', + 'pixman-helper.c', + 'pixman-tbm-helper.c', + 'tinyds-tdm-renderer.c', + dependencies: [ + common_deps, + dependency('pixman-1', required: true), + dependency('threads', required: true), + ], + install_dir: libds_bindir, + install : true + ) endif diff --git a/src/examples/tinyds-tdm-dpms.c b/src/examples/tinyds-tdm-dpms.c new file mode 100644 index 0000000..dc32e8f --- /dev/null +++ b/src/examples/tinyds-tdm-dpms.c @@ -0,0 +1,672 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define USE_TDM_BUFFER_QUEUE + +#ifdef USE_TDM_BUFFER_QUEUE +#include "pixman-tbm-helper.h" +#include "tinyds-tdm-renderer.h" +#else +#include +#endif + +#include "pixman-helper.h" + +#define TINYDS_UNUSED __attribute__((unused)) + +struct tinyds_output +{ + struct tinyds_server *server; + struct ds_output *ds_output; + struct ds_allocator *allocator; +#ifdef USE_TDM_BUFFER_QUEUE + struct tinyds_renderer renderer; + struct ds_tdm_buffer_queue *buffer_queue; + struct wl_listener buffer_queue_acquirable; +#else + struct ds_swapchain *swapchain; +#endif + struct ds_buffer *front_buffer; + + struct wl_listener output_destroy; + struct wl_listener output_frame; + + int width, height; + + bool drawable; + bool damaged; +}; + +struct tinyds_dpms +{ + struct ds_tizen_dpms *ds_dpms; + struct tinyds_server *server; + + struct wl_listener destroy; + struct wl_listener set_dpms; + struct wl_listener get_dpms; +}; + +struct tinyds_server +{ + struct ds_tbm_server *tbm_server; + + struct wl_display *display; + + struct ds_backend *backend; + struct ds_compositor *compositor; + struct ds_xdg_shell *xdg_shell; + + struct tinyds_output *output; + struct tinyds_dpms *dpms; + struct wl_event_source *stdin_source; + + struct wl_list views; + + struct wl_listener new_output; + struct wl_listener new_xdg_surface; +}; + +struct tinyds_view +{ + struct tinyds_server *server; + + struct tinyds_texture *texture; + struct ds_xdg_surface *xdg_surface; + + struct wl_listener xdg_surface_map; + struct wl_listener xdg_surface_unmap; + struct wl_listener xdg_surface_destroy; + struct wl_listener surface_commit; + struct wl_list link; // tinyds_server::views + + int x, y; + bool mapped; +}; + +struct tinyds_server tinyds; + +static bool init_server(struct tinyds_server *server, struct wl_display *display); +static int server_dispatch_stdin(int fd, uint32_t mask, void *data); +static void output_handle_destroy(struct wl_listener *listener, void *data); +static void output_handle_frame(struct wl_listener *listener, void *data); +static void draw_server_with_damage(struct tinyds_server *server); +static void draw_output(struct tinyds_output *output); +static void output_swap_buffer(struct tinyds_output *output, + struct ds_buffer *buffer); +static void view_send_frame_done(struct tinyds_view *view); +#ifdef USE_TDM_BUFFER_QUEUE +static void output_buffer_queue_init(struct tinyds_output *output); +static void output_renderer_init(struct tinyds_output *output); +static void output_draw_with_renderer(struct tinyds_output *output); +#else +static void output_swapchain_init(struct tinyds_output *output, + int width, int height, uint32_t format); +static void output_draw_with_swapchain(struct tinyds_output *output); +static void draw_view(struct tinyds_view *view, pixman_image_t *dst_image); +#endif +static void dpms_handle_destroy(struct wl_listener *listener, void *data); +static void dpms_handle_set_dpms(struct wl_listener *listener, void *data); +static void dpms_handle_get_dpms(struct wl_listener *listener, void *data); + + +int +main(void) +{ + struct tinyds_server *server = &tinyds; + struct wl_display *display; + struct wl_event_loop *loop; + const char *socket; + bool res; + + ds_log_init(DS_INF, NULL); + + display = wl_display_create(); + assert(display); + + res = init_server(server, display); + assert(res); + + socket = wl_display_add_socket_auto(display); + assert(socket); + + ds_backend_start(server->backend); + + setenv("WAYLAND_DISPLAY", socket, true); + + ds_inf("Running Wayland compositor on WAYLAND_DISPLAY=%s", socket); + + loop = wl_display_get_event_loop(display); + server->stdin_source = wl_event_loop_add_fd(loop, STDIN_FILENO, + WL_EVENT_READABLE, server_dispatch_stdin, server); + + wl_display_run(display); + + wl_display_destroy_clients(display); + wl_display_destroy(display); + + return 0; +} + +static void +view_handle_xdg_surface_map(struct wl_listener *listener, + void *data TINYDS_UNUSED) +{ + struct tinyds_view *view; + + view = wl_container_of(listener, view, xdg_surface_map); + view->mapped = true; +} + +static void +view_handle_xdg_surface_unmap(struct wl_listener *listener, + void *data TINYDS_UNUSED) +{ + struct tinyds_view *view; + + view = wl_container_of(listener, view, xdg_surface_unmap); + view->mapped = false; +} + +static void +view_handle_xdg_surface_destroy(struct wl_listener *listener, + void *data TINYDS_UNUSED) +{ + struct tinyds_view *view; + struct tinyds_server *server; + + view = wl_container_of(listener, view, xdg_surface_destroy); + server = view->server; + + wl_list_remove(&view->xdg_surface_destroy.link); + wl_list_remove(&view->xdg_surface_map.link); + wl_list_remove(&view->xdg_surface_unmap.link); + wl_list_remove(&view->surface_commit.link); + wl_list_remove(&view->link); + free(view); + + draw_server_with_damage(server); +} + +static void +view_handle_surface_commit(struct wl_listener *listener, + void *data TINYDS_UNUSED) +{ + struct tinyds_view *view; + + view = wl_container_of(listener, view, surface_commit); + draw_server_with_damage(view->server); +} + +static void +server_new_xdg_surface(struct wl_listener *listener, void *data) +{ + struct tinyds_server *server; + struct tinyds_view *view; + struct ds_xdg_surface *xdg_surface; + + server = wl_container_of(listener, server, new_xdg_surface); + xdg_surface = data; + + ds_inf("New xdg_surface(%p)", (void *)xdg_surface); + + view = calloc(1, sizeof *view); + assert(view); + + view->server = server; + view->xdg_surface = xdg_surface; + + view->xdg_surface_map.notify = view_handle_xdg_surface_map; + ds_xdg_surface_add_map_listener(xdg_surface, + &view->xdg_surface_map); + + view->xdg_surface_unmap.notify = view_handle_xdg_surface_unmap; + ds_xdg_surface_add_unmap_listener(xdg_surface, + &view->xdg_surface_unmap); + + view->xdg_surface_destroy.notify = view_handle_xdg_surface_destroy; + ds_xdg_surface_add_destroy_listener(xdg_surface, + &view->xdg_surface_destroy); + + view->surface_commit.notify = view_handle_surface_commit; + ds_surface_add_commit_listener( + ds_xdg_surface_get_surface(xdg_surface), + &view->surface_commit); + + wl_list_insert(server->views.prev, &view->link); + + view->x = rand() % 1000; + view->y = rand() % 500; +} + +static void +backend_handle_new_output(struct wl_listener *listener, void *data) +{ + struct tinyds_server *server; + struct tinyds_output *output; + struct ds_output *ds_output; + const struct ds_output_mode *mode; + + server = wl_container_of(listener, server, new_output); + ds_output = data; + + ds_inf("New output(%p)", ds_output); + + if (server->output) + return; + + mode = ds_output_get_preferred_mode(ds_output); + ds_output_set_mode(ds_output, mode); + + output = calloc(1, sizeof *output); + if (!output) + return; + + output->server = server; + output->ds_output = ds_output; + output->width = mode->width; + output->height = mode->height; + output->drawable = true; + output->damaged = true; + +#ifdef USE_TDM_BUFFER_QUEUE + output_buffer_queue_init(output); + output_renderer_init(output); +#else + output_swapchain_init(output, mode->width, mode->height, + DRM_FORMAT_XRGB8888); +#endif + + output->output_destroy.notify = output_handle_destroy; + ds_output_add_destroy_listener(ds_output, &output->output_destroy); + + output->output_frame.notify = output_handle_frame; + ds_output_add_frame_listener(ds_output, &output->output_frame); + + server->output = output; + + draw_output(output); +} + +static bool +add_new_dpms(struct tinyds_server *server) +{ + struct tinyds_dpms *dpms; + + dpms = calloc(1, sizeof *dpms); + if (!dpms) + return false; + + dpms->ds_dpms = ds_tizen_dpms_create(server->display); + if (!dpms->ds_dpms) + return false; + + dpms->destroy.notify = dpms_handle_destroy; + ds_tizen_dpms_add_destroy_listener(dpms->ds_dpms, &dpms->destroy); + + dpms->set_dpms.notify = dpms_handle_set_dpms; + ds_tizen_dpms_add_set_dpms_listener(dpms->ds_dpms, &dpms->set_dpms); + + dpms->get_dpms.notify = dpms_handle_get_dpms; + ds_tizen_dpms_add_get_dpms_listener(dpms->ds_dpms, &dpms->get_dpms); + + server->dpms = dpms; + + ds_inf("Dpms (%p) added", dpms); + + return true; +} + +static bool +init_server(struct tinyds_server *server, struct wl_display *display) +{ + server->display = display; + + wl_list_init(&server->views); + + if (wl_display_init_shm(display) != 0) + return false; + + server->backend = ds_tdm_backend_create(display); + if (!server->backend) + return false; + + server->new_output.notify = backend_handle_new_output; + ds_backend_add_new_output_listener(server->backend, + &server->new_output); + + server->compositor = ds_compositor_create(display); + if (!server->compositor) { + ds_backend_destroy(server->backend); + 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); + return false; + } + + server->new_xdg_surface.notify = server_new_xdg_surface; + ds_xdg_shell_add_new_surface_listener(server->xdg_shell, + &server->new_xdg_surface); + + if (!add_new_dpms(server)) { + ds_backend_destroy(server->backend); + return false; + } + + return true; +} + +static void +output_handle_destroy(struct wl_listener *listener, void *data TINYDS_UNUSED) +{ + struct tinyds_output *output = + wl_container_of(listener, output, output_destroy); + + wl_list_remove(&output->output_destroy.link); + wl_list_remove(&output->output_frame.link); + + if (output->front_buffer) + ds_buffer_unlock(output->front_buffer); + +#ifdef USE_TDM_BUFFER_QUEUE + fini_renderer(&output->renderer); +#else + if (output->swapchain) + ds_swapchain_destroy(output->swapchain); + + if (output->allocator) + ds_allocator_destroy(output->allocator); +#endif + + wl_display_terminate(output->server->display); + + output->server->output = NULL; + + free(output); +} + +static void +output_handle_frame(struct wl_listener *listener, void *data TINYDS_UNUSED) +{ + struct tinyds_output *output = + wl_container_of(listener, output, output_frame); + + output->drawable = true; + draw_output(output); +} + +static void +draw_server_with_damage(struct tinyds_server *server) +{ + server->output->damaged = true; + draw_output(server->output); +} + +#ifdef USE_TDM_BUFFER_QUEUE +static void +output_handle_buffer_queue_acquirable(struct wl_listener *listener, + void *data TINYDS_UNUSED) +{ + struct tinyds_output *output; + struct ds_buffer *buffer; + + output = wl_container_of(listener, output, buffer_queue_acquirable); + + buffer = ds_tdm_buffer_queue_acquire(output->buffer_queue); + assert(buffer); + + output_swap_buffer(output, buffer); +} + +static void +output_buffer_queue_init(struct tinyds_output *output) +{ + struct ds_tdm_output *tdm_output; + + tdm_output = ds_tdm_output_from_output(output->ds_output); + assert(tdm_output); + + output->buffer_queue = ds_tdm_output_get_buffer_queue(tdm_output); + assert(output->buffer_queue); + + output->buffer_queue_acquirable.notify = + output_handle_buffer_queue_acquirable; + ds_tdm_buffer_queue_add_acquirable_listener(output->buffer_queue, + &output->buffer_queue_acquirable); +} + +static void +output_renderer_init(struct tinyds_output *output) +{ + init_renderer(&output->renderer); + + renderer_set_surface_queue(&output->renderer, + ds_tdm_buffer_queue_get_native_queue(output->buffer_queue)); + + renderer_set_bg_color(&output->renderer, 80, 80, 80); +} + +static void +output_draw_with_renderer(struct tinyds_output *output) +{ + struct tinyds_view *view; + + ds_dbg(">> BEGIN UPDATE TEXTURES"); + + wl_list_for_each(view, &output->server->views, link) { + struct ds_buffer *ds_buffer; + struct ds_tbm_client_buffer *tbm_buffer; + tbm_surface_h surface; + + if (!view->mapped) + continue; + + ds_buffer = ds_surface_get_buffer( + ds_xdg_surface_get_surface(view->xdg_surface)); + assert(ds_buffer); + + tbm_buffer = ds_tbm_client_buffer_from_buffer(ds_buffer); + assert(tbm_buffer); + + surface = ds_tbm_client_buffer_get_tbm_surface(tbm_buffer); + + renderer_add_texture(&output->renderer, surface, view->x, view->y); + + view_send_frame_done(view); + } + + ds_dbg("<< END UPDATE TEXTURES"); + + renderer_draw(&output->renderer); + +} +#else +static void +output_swapchain_init(struct tinyds_output *output, + int width, int height, uint32_t format); + +{ + output->allocator = ds_tbm_allocator_create(); + assert(output->allocator); + + output->swapchain = ds_swapchain_create(output->allocator, + width, height, format); + assert(output->swapchain); +} + +static void +output_draw_with_swapchain(struct tinyds_output *output) +{ + struct tinyds_view *view; + struct ds_buffer *output_buffer; + pixman_image_t *output_image; + + output_buffer = ds_swapchain_acquire(output->swapchain, NULL); + if (!output_buffer) + return; + + output_image = pixman_image_from_buffer(output_buffer, + DS_BUFFER_DATA_PTR_ACCESS_WRITE); + if (!output_image) { + ds_buffer_unlock(output_buffer); + return; + } + + pixman_image_fill_color(output_image, 80, 80, 80); + + wl_list_for_each(view, &output->server->views, link) { + if (!view->mapped) + continue; + draw_view(view, output_image); + } + pixman_image_unref(output_image); + + output_swap_buffer(output, output_buffer); +} + +static void +draw_view(struct tinyds_view *view, pixman_image_t *dst_image) +{ + struct ds_buffer *buffer; + pixman_image_t *src_image; + + buffer = ds_surface_get_buffer( + ds_xdg_surface_get_surface(view->xdg_surface)); + if (!buffer) + return; + + src_image = pixman_image_from_buffer(buffer, + DS_BUFFER_DATA_PTR_ACCESS_READ); + pixman_image_composite32(PIXMAN_OP_OVER, + src_image, + NULL, + dst_image, + 0, 0, 0, 0, + view->x, view->y, + pixman_image_get_width(src_image), + pixman_image_get_height(src_image)); + pixman_image_unref(src_image); + + view_send_frame_done(view); +} +#endif + +static void +draw_output(struct tinyds_output *output) +{ + + if (!output->drawable || !output->damaged) + return; + +#ifdef USE_TDM_BUFFER_QUEUE + output_draw_with_renderer(output); +#else + output_draw_with_swapchain(output); +#endif + + output->drawable = false; + output->damaged = false; +} + +static void +output_swap_buffer(struct tinyds_output *output, struct ds_buffer *buffer) +{ + ds_output_attach_buffer(output->ds_output, buffer); + ds_output_commit(output->ds_output); + + if (output->front_buffer) + ds_buffer_unlock(output->front_buffer); + output->front_buffer = buffer; +} + +static void +view_send_frame_done(struct tinyds_view *view) +{ + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + ds_surface_send_frame_done(ds_xdg_surface_get_surface(view->xdg_surface), + &now); +} + +static int +server_dispatch_stdin(int fd, uint32_t mask, void *data) +{ + struct tinyds_server *server = data; + + wl_display_terminate(server->display); + + return 1; +} + +static void +dpms_handle_destroy(struct wl_listener *listener, void *data) +{ + struct tinyds_dpms *dpms; + + dpms = wl_container_of(listener, dpms, destroy); + + ds_inf("Dpms(%p) destroyed", dpms); + + wl_list_remove(&dpms->destroy.link); + wl_list_remove(&dpms->set_dpms.link); + wl_list_remove(&dpms->get_dpms.link); + + free(dpms); +} + +static void +dpms_handle_set_dpms(struct wl_listener *listener, void *data) +{ + struct tinyds_dpms *dpms; + struct ds_tizen_dpms_event *event = data; + + dpms = wl_container_of(listener, dpms, set_dpms); + + ds_inf("Dpms(%p) set dpms : %d", dpms, event->mode); + + //To do + //set dpms mode to output + ds_tizen_dpms_send_set_result(dpms->ds_dpms, event->mode, + DS_TIZEN_DPMS_ERROR_NONE); +} + +static void +dpms_handle_get_dpms(struct wl_listener *listener, void *data) +{ + struct tinyds_dpms *dpms; + + dpms = wl_container_of(listener, dpms, get_dpms); + + ds_inf("Dpms(%p) get dpms", dpms); + + //To do + //get dpms mode from output + ds_tizen_dpms_send_get_result(dpms->ds_dpms, DS_TIZEN_DPMS_MODE_ON, + DS_TIZEN_DPMS_ERROR_NONE); +} \ No newline at end of file -- 2.7.4 From ae1d36fed10e73a03f3e80259e4b3a0012cdea7a Mon Sep 17 00:00:00 2001 From: Junkyeong Kim Date: Tue, 7 Jun 2022 13:34:43 +0900 Subject: [PATCH 14/16] client: add simple-dpms Change-Id: Ibd038539152aaee0f8f6a78f9eee88d7a542afcc Signed-off-by: Junkyeong Kim --- packaging/libds.spec | 2 + src/clients/meson.build | 10 ++ src/clients/simple-dpms.c | 239 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 251 insertions(+) create mode 100644 src/clients/simple-dpms.c diff --git a/packaging/libds.spec b/packaging/libds.spec index aefff95..6260ed2 100644 --- a/packaging/libds.spec +++ b/packaging/libds.spec @@ -23,6 +23,7 @@ BuildRequires: pkgconfig(libtbm) BuildRequires: pkgconfig(wayland-tbm-server) BuildRequires: pkgconfig(wayland-tbm-client) BuildRequires: pkgconfig(tizen-dpms-server) +BuildRequires: pkgconfig(tizen-dpms-client) BuildRequires: pkgconfig(cynara-client) BuildRequires: pkgconfig(cynara-session) BuildRequires: pkgconfig(libsmack) @@ -108,6 +109,7 @@ ninja -C builddir install %{_bindir}/tinyds-tdm-libinput %{_bindir}/ds-simple-shm-shell %{_bindir}/tinyds-tdm-dpms +%{_bindir}/ds-simple-dpms %files tizen-keyrouter %manifest %{name}.manifest diff --git a/src/clients/meson.build b/src/clients/meson.build index 009016c..6fcd3f8 100644 --- a/src/clients/meson.build +++ b/src/clients/meson.build @@ -55,3 +55,13 @@ executable('ds-simple-tbm', install_dir: libds_bindir, install: true, ) + +executable('ds-simple-dpms', + 'simple-dpms.c', + dependencies: [ + dependency('wayland-client', required: true), + dependency('tizen-dpms-client', required: true), + ], + install_dir: libds_bindir, + install: true, +) diff --git a/src/clients/simple-dpms.c b/src/clients/simple-dpms.c new file mode 100644 index 0000000..9b4d22c --- /dev/null +++ b/src/clients/simple-dpms.c @@ -0,0 +1,239 @@ +/* +Copyright (C) 2015 - 2016 Samsung Electronics co., Ltd. All Rights Reserved. + +Contact: + SooChan Lim + Changyeon Lee + JunKyeong Kim + Boram Park + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the next +paragraph) shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +struct wl_dpms_info { + char *app_name; + + struct wl_display *display; + struct wl_registry *registry; + struct wl_output *output; + struct tizen_dpms_manager *tz_dpms_mng; + int got_dpms_state; +}; + +void +usage(const char *app_name) +{ + printf("usage: %s \n", app_name); + printf("%s output_num option(set1/get0) state\nex)\n", app_name); + printf("%s 1 0 => set dpms_on\n", app_name); + printf("%s 1 3 => set dpms_off\n", app_name); + printf("%s 0 0 => get state\n", app_name); +} + +static struct wl_dpms_info * +_create_wl_dpms_info (void) +{ + struct wl_dpms_info *test_info = NULL; + + test_info = calloc(1, sizeof(struct wl_dpms_info)); + if (test_info == NULL) { + printf("alloc fail"); + return NULL; + } + + return test_info; +} + +static void +_destroy_wl_dpms_info (struct wl_dpms_info *test_info) +{ + if (!test_info) return; + + if (test_info->app_name) + free(test_info->app_name); + if (test_info->tz_dpms_mng) + tizen_dpms_manager_destroy(test_info->tz_dpms_mng); + if (test_info->registry) + wl_registry_destroy(test_info->registry); + if (test_info->display) + wl_display_disconnect(test_info->display); + + free(test_info); +} + +static void +dpms_handle_set_state(void *data, struct tizen_dpms_manager *tz_dpms, uint32_t mode, uint32_t error) +{ + struct wl_dpms_info *test_info = (struct wl_dpms_info *)data; + printf("dpms_set_state_cb - mode:%d, error:%d\n", mode, error); + test_info->got_dpms_state = 1; +} + +static void +dpms_handle_get_state(void *data, struct tizen_dpms_manager *tz_dpms, uint32_t mode, uint32_t error) +{ + struct wl_dpms_info *test_info = (struct wl_dpms_info *)data; + printf("dpms_get_state_cb - mode:%d, error:%d\n", mode, error); + test_info->got_dpms_state = 1; +} + +static const struct tizen_dpms_manager_listener dpms_listener = { + dpms_handle_set_state, + dpms_handle_get_state +}; + +static void +handle_global(void *data, struct wl_registry *registry, + uint32_t name, const char *interface, uint32_t version) +{ + struct wl_dpms_info *test_info = (struct wl_dpms_info *)data; + + if (strcmp(interface, "wl_output") == 0) { + test_info->output = wl_registry_bind(registry, name, &wl_output_interface, 2); + if (!test_info->output) + printf("bind wl_output fail\n"); + else + printf("bind wl_output\n"); + } else if (strcmp(interface, "tizen_dpms_manager") == 0) { + test_info->tz_dpms_mng = wl_registry_bind(registry, name, &tizen_dpms_manager_interface, 1); + if (!test_info->tz_dpms_mng) + printf("bind tizen_dpms_manager fail\n"); + else { + tizen_dpms_manager_add_listener(test_info->tz_dpms_mng, &dpms_listener, test_info); + printf("bind tizen_dpms_manager\n"); + } + } +} + +static void +handle_global_remove(void *data, struct wl_registry *registry, uint32_t name) +{ +} + +static const struct wl_registry_listener registry_listener = { + handle_global, + handle_global_remove +}; + +int +main(int argc, char *argv[]) +{ + struct wl_dpms_info *test_info = NULL; + char *opt = NULL; + int option; + char *sta = NULL; + int state = 0; + + test_info = _create_wl_dpms_info(); + if (test_info == NULL) return 0; + + test_info->app_name = strdup(argv[0]); + if (test_info->app_name == NULL) { + printf("alloc fail"); + goto done; + } + if (argc != 3) { + usage(test_info->app_name); + goto done; + } + + opt = strdup(argv[1]); + if (opt == NULL) { + printf("alloc fail"); + goto done; + } + option = opt[0] - '0'; + free(opt); + if (!(option == 0 || option == 1)) { + usage(test_info->app_name); + goto done; + } + + if (option == 1) { + sta = strdup(argv[2]); + if (sta == NULL) { + printf("alloc fail"); + goto done; + } + state = sta [0] - '0'; + free(sta); + if (!(state == 0 || state == 1 || state == 2 || state == 3)) { + usage(test_info->app_name); + goto done; + } + } + + test_info->display = wl_display_connect(NULL); + if (test_info->display == NULL) { + printf("wl_display_connect fail"); + goto done; + } + + test_info->registry = wl_display_get_registry(test_info->display); + if (test_info->registry == NULL) { + printf("wl_display_get_registry fail"); + goto done; + } + + wl_registry_add_listener(test_info->registry, ®istry_listener, test_info); + wl_display_roundtrip(test_info->display); + + if (!test_info->output || !test_info->tz_dpms_mng) { + printf("bind fail\n"); + goto done; + } + + if (option == 1) { + tizen_dpms_manager_set_dpms(test_info->tz_dpms_mng, test_info->output, state); + printf("set dpms %d\n", state); + } else { + tizen_dpms_manager_get_dpms(test_info->tz_dpms_mng, test_info->output); + printf("get dpms\n"); + } + + test_info->got_dpms_state = 0; + while (!test_info->got_dpms_state) { + wl_display_roundtrip(test_info->display); + } + +done: + _destroy_wl_dpms_info(test_info); + + return 0; +} + -- 2.7.4 From 01e84ec6aeafb34bd44eb0966f9547884df3ac51 Mon Sep 17 00:00:00 2001 From: Junkyeong Kim Date: Tue, 7 Jun 2022 13:35:51 +0900 Subject: [PATCH 15/16] dpms: set ds_tizen_dpms enum value by tizen dpms protocol enum value Change-Id: I55c31d0be7d92f4c85ffcd9c712bc61e54058073 Signed-off-by: Junkyeong Kim --- include/libds-tizen/dpms.h | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/include/libds-tizen/dpms.h b/include/libds-tizen/dpms.h index 10df4c1..c614e66 100644 --- a/include/libds-tizen/dpms.h +++ b/include/libds-tizen/dpms.h @@ -3,6 +3,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { @@ -12,19 +13,19 @@ struct ds_tizen_dpms; enum ds_tizen_dpms_mode { - DS_TIZEN_DPMS_MODE_ON = 0, - DS_TIZEN_DPMS_MODE_STANDBY = 1, - DS_TIZEN_DPMS_MODE_SUSPEND = 2, - DS_TIZEN_DPMS_MODE_OFF = 3, + DS_TIZEN_DPMS_MODE_ON = TIZEN_DPMS_MANAGER_MODE_ON, + DS_TIZEN_DPMS_MODE_STANDBY = TIZEN_DPMS_MANAGER_MODE_STANDBY, + DS_TIZEN_DPMS_MODE_SUSPEND = TIZEN_DPMS_MANAGER_MODE_SUSPEND, + DS_TIZEN_DPMS_MODE_OFF = TIZEN_DPMS_MANAGER_MODE_OFF, }; enum ds_tizen_dpms_error { - DS_TIZEN_DPMS_ERROR_NONE = 0, - DS_TIZEN_DPMS_ERROR_INVALID_PERMISSION = 1, - DS_TIZEN_DPMS_ERROR_INVALID_PARAMETER = 2, - DS_TIZEN_DPMS_ERROR_NOT_SUPPORTED = 3, - DS_TIZEN_DPMS_ERROR_ALREADY_DONE = 4, + DS_TIZEN_DPMS_ERROR_NONE = TIZEN_DPMS_MANAGER_ERROR_NONE, + DS_TIZEN_DPMS_ERROR_INVALID_PERMISSION = TIZEN_DPMS_MANAGER_ERROR_INVALID_PERMISSION, + DS_TIZEN_DPMS_ERROR_INVALID_PARAMETER = TIZEN_DPMS_MANAGER_ERROR_INVALID_PARAMETER, + DS_TIZEN_DPMS_ERROR_NOT_SUPPORTED = TIZEN_DPMS_MANAGER_ERROR_NOT_SUPPORTED, + DS_TIZEN_DPMS_ERROR_ALREADY_DONE = TIZEN_DPMS_MANAGER_ERROR_ALREADY_DONE, }; struct ds_tizen_dpms_event -- 2.7.4 From 6352c4116e2746ea0bd1f1f18398bba225037863 Mon Sep 17 00:00:00 2001 From: "duna.oh" Date: Tue, 7 Jun 2022 19:38:39 +0900 Subject: [PATCH 16/16] devicemgr: implement libds-tizen-input-devicemgr Change-Id: I7b5d45cd96122bb4f5d7926bd6d3d830475f5696 --- include/libds-tizen/input-devicemgr.h | 40 + include/libds/input_device.h | 3 + include/libds/interfaces/backend.h | 3 +- packaging/libds.spec | 30 + src/clients/input-generator.c | 540 +++++++++++ src/clients/meson.build | 15 + src/clients/simple-tbm.c | 84 +- src/examples/meson.build | 1 + src/examples/tinyds-tdm-libinput.c | 141 ++- src/libds-tizen/backend/tdm/backend.c | 2 +- src/libds-tizen/input-devicemgr/input-devicemgr.c | 1063 +++++++++++++++++++++ src/libds-tizen/input-devicemgr/input-devicemgr.h | 59 ++ src/libds-tizen/input-devicemgr/meson.build | 30 + src/libds-tizen/meson.build | 1 + src/libds/backend.c | 2 + src/libds/backend/libinput/backend.c | 4 +- src/libds/backend/libinput/input.c | 2 + src/libds/backend/wayland/backend.c | 2 +- src/libds/input_device.c | 9 + src/libds/seat/seat_keyboard.c | 2 +- 20 files changed, 2018 insertions(+), 15 deletions(-) create mode 100644 include/libds-tizen/input-devicemgr.h create mode 100644 src/clients/input-generator.c create mode 100644 src/libds-tizen/input-devicemgr/input-devicemgr.c create mode 100644 src/libds-tizen/input-devicemgr/input-devicemgr.h create mode 100644 src/libds-tizen/input-devicemgr/meson.build diff --git a/include/libds-tizen/input-devicemgr.h b/include/libds-tizen/input-devicemgr.h new file mode 100644 index 0000000..a9ed808 --- /dev/null +++ b/include/libds-tizen/input-devicemgr.h @@ -0,0 +1,40 @@ +#ifndef LIBDS_TIZEN_INPUT_DEVICEMGR_H +#define LIBDS_TIZEN_INPUT_DEVICEMGR_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct ds_tizen_input_devicemgr; +struct ds_backend; +struct ds_seat; + +struct ds_tizen_input_devicemgr_keymap_data +{ + char *name; + int keycode; + + struct wl_list link; +}; + +struct ds_tizen_input_devicemgr * +ds_tizen_input_devicemgr_create(struct ds_backend *backend, + struct ds_seat *seat); + +void +ds_tizen_input_devicemgr_add_destroy_listener( + struct ds_tizen_input_devicemgr *devicemgr, + struct wl_listener *listener); + +bool +ds_tizen_input_devicemgr_set_keymap_list( + struct ds_tizen_input_devicemgr *devicemgr, + struct wl_list *list); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/libds/input_device.h b/include/libds/input_device.h index 1a3652b..55aabbd 100644 --- a/include/libds/input_device.h +++ b/include/libds/input_device.h @@ -25,6 +25,9 @@ enum ds_input_device_type enum ds_input_device_type ds_input_device_get_type(struct ds_input_device *dev); +const char * +ds_input_device_get_name(struct ds_input_device *dev); + struct ds_pointer * ds_input_device_get_pointer(struct ds_input_device *dev); diff --git a/include/libds/interfaces/backend.h b/include/libds/interfaces/backend.h index bad37a0..55a2475 100644 --- a/include/libds/interfaces/backend.h +++ b/include/libds/interfaces/backend.h @@ -29,7 +29,8 @@ struct ds_backend }; void -ds_backend_init(struct ds_backend *backend, const struct ds_backend_interface *iface); +ds_backend_init(struct ds_backend *backend, struct wl_display *display, + const struct ds_backend_interface *iface); void ds_backend_finish(struct ds_backend *backend); diff --git a/packaging/libds.spec b/packaging/libds.spec index 6260ed2..f53efa9 100644 --- a/packaging/libds.spec +++ b/packaging/libds.spec @@ -12,6 +12,7 @@ BuildRequires: pkgconfig(wayland-server) BuildRequires: pkgconfig(wayland-client) BuildRequires: pkgconfig(wayland-protocols) BuildRequires: pkgconfig(tizen-extension-server) +BuildRequires: pkgconfig(tizen-extension-client) BuildRequires: pkgconfig(pixman-1) BuildRequires: pkgconfig(libdrm) BuildRequires: pkgconfig(xkbcommon) @@ -59,6 +60,20 @@ Group: Development/Libraries %description tizen-keyrouter-devel Keyrouter Development package for Wayland Compositor Library +%package tizen-input-devicemgr +Summary: Library for tizen input devicemgr +Group: Development/Libraries + +%description tizen-input-devicemgr +Library for tizen input devicemgr + +%package tizen-input-devicemgr-devel +Summary: Development package for tizen input devicemgr +Group: Development/Libraries + +%description tizen-input-devicemgr-devel +Development package for tizen input devicemgr + %prep %setup -q cp %{SOURCE1001} . @@ -110,6 +125,7 @@ ninja -C builddir install %{_bindir}/ds-simple-shm-shell %{_bindir}/tinyds-tdm-dpms %{_bindir}/ds-simple-dpms +%{_bindir}/input-generator %files tizen-keyrouter %manifest %{name}.manifest @@ -124,3 +140,17 @@ ninja -C builddir install %{_includedir}/libds-tizen/keyrouter.h %{_libdir}/pkgconfig/libds-tizen-keyrouter.pc %{_libdir}/libds-tizen-keyrouter.so + +%files tizen-input-devicemgr +%manifest %{name}.manifest +%defattr(-,root,root,-) +%license LICENSE +%{_libdir}/libds-tizen-input-devicemgr.so.* + +%files tizen-input-devicemgr-devel +%manifest %{name}.manifest +%defattr(-,root,root,-) +%license LICENSE +%{_includedir}/libds-tizen/input-devicemgr.h +%{_libdir}/pkgconfig/libds-tizen-input-devicemgr.pc +%{_libdir}/libds-tizen-input-devicemgr.so diff --git a/src/clients/input-generator.c b/src/clients/input-generator.c new file mode 100644 index 0000000..f61e84b --- /dev/null +++ b/src/clients/input-generator.c @@ -0,0 +1,540 @@ +#include +#include +#include +#include +#include + +#include +#include + +#define MAX_STR 1024 +#define SIZE_EPOLL 16 + +enum enum_key_type +{ + KEY_UP = 0, + KEY_DOWN, + KEY_ALL +}; + +enum enum_touch_type +{ + TOUCH_BEGIN = 0, + TOUCH_UPDATE, + TOUCH_END, + TOUCH_ALL +}; + +struct display +{ + struct wl_display *display; + struct wl_registry *registry; + struct wl_compositor *compositor; + + struct tizen_input_device_manager *devicemgr; + enum tizen_input_device_manager_clas clas; + struct wl_event_queue *queue; + + int run; + int fd_epoll; + int fd_display; + + int request_notified; + int init; + + int enable_log; +}; + +struct display data_wl; + +static void +usage(void) +{ + printf(" Supported commands: init (Initialize input generator)\n"); + printf(" : deinit (Deinitialize input generator)\n"); + printf(" : key (Generate key events)\n"); + printf(" : touch (Generate touch events)\n"); + printf(" : help (Print this help text)\n"); + printf(" : q/quit (Quit program)\n"); + printf(" : log (Print detailed logs)\n"); + printf("init {device type}\n"); + printf(" : device type:\n"); + printf(" - default: all\n"); + printf(" - key/keyboard: keyboard\n"); + printf(" - touch: touch screen\n"); + printf(" - all: all of devices\n"); + printf(" : ex> init keyboard / init\n"); + printf("\n"); + printf("deinit\n"); + printf(" : ex> deinit\n"); + printf("\n"); + printf("key [keyname] {pressed}\n"); + printf(" : pressed:\n"); + printf(" - default: down&up pair\n"); + printf(" - key down: 1\n"); + printf(" - key up: 0\n"); + printf(" : ex> key XF86Back 1\n"); + printf("\n"); + printf("touch {index} {type} {x} {y}\n"); + printf(" : index:\n"); + printf(" - default: first finger(0)\n"); + printf(" - first finger is 0\n"); + printf(" : type:\n"); + printf(" - default: generate sample touch events\n"); + printf(" - touch begin: 1\n"); + printf(" - touch update: 2\n"); + printf(" - touch end: 3\n"); + printf(" : x/y:\n"); + printf(" - default: 0\n"); + printf(" : ex> touch / touch 0 1 100 100\n"); + printf("\n"); +} + +static void +init_input_generator(enum tizen_input_device_manager_clas clas) +{ + if (data_wl.init) { + printf("Already init input generator\n"); + return; + } + + tizen_input_device_manager_init_generator(data_wl.devicemgr, clas); + + while (data_wl.request_notified == -1) + wl_display_dispatch_queue(data_wl.display, data_wl.queue); + + if (data_wl.request_notified == TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE) { + data_wl.init = 1; + printf("Success to init input generator\n"); + } else { + printf("Failed to init input generator: %d\n", data_wl.request_notified); + } + + data_wl.clas = clas; + data_wl.request_notified = -1; +} + +static void +deinit_input_generator(void) +{ + if (!data_wl.init) { + printf("input generator is not initialized\n"); + return; + } + + tizen_input_device_manager_deinit_generator(data_wl.devicemgr, data_wl.clas); + + while (data_wl.request_notified == -1) + wl_display_dispatch_queue(data_wl.display, data_wl.queue); + + if (data_wl.request_notified == TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE) { + data_wl.init = 0; + printf("Success to deinit input generator\n"); + } else { + printf("Failed to deinit input generator: %d\n", data_wl.request_notified); + } + + data_wl.request_notified = -1; +} + +static void +input_generator_key(char *name, int type) +{ + tizen_input_device_manager_generate_key(data_wl.devicemgr, name, !!type); + + while (data_wl.request_notified == -1) + wl_display_dispatch_queue(data_wl.display, data_wl.queue); + + if (data_wl.request_notified == TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE) { + if (data_wl.enable_log) { + printf("Success to generate key: %s key %s\n", name, type?"down":"up"); + } + } else { + printf("Failed to generate %s key %s: %d\n", name, type?"down":"up", data_wl.request_notified); + } + + data_wl.request_notified = -1; +} + +static void +key_generate(char *name, int type) +{ + printf("name: %s, type: %d\n", name, type); + + if (!data_wl.init) { + printf("Input genrator is not initialized\n"); + return; + } + + if (!name) { + printf("Type which key is generated\n"); + return; + } + + if (type == KEY_ALL) { + input_generator_key(name, 1); + input_generator_key(name, 0); + } else { + input_generator_key(name, !!type); + } +} + +static char * +touch_type_string_get(int type) +{ + switch (type) { + case TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_BEGIN: + return "begin"; + case TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_UPDATE: + return "update"; + case TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_END: + return "end"; + default: + return "Unknown"; + } +} + +static void +input_generator_touch(int idx, int type, int x, int y) +{ + tizen_input_device_manager_generate_touch(data_wl.devicemgr, type, x, y, idx); + + while (data_wl.request_notified == -1) + wl_display_dispatch_queue(data_wl.display, data_wl.queue); + + if (data_wl.request_notified == TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE) { + if (data_wl.enable_log) { + printf("Success to generate touch: %d finger %s on (%d, %d)\n", idx, touch_type_string_get(type), x, y); + } + } else { + printf("Failed to generate touch(%d finger %s on (%d, %d)): %d\n", idx, touch_type_string_get(type), x, y, data_wl.request_notified); + } + + data_wl.request_notified = -1; +} + +static void +touch_generate(int idx, int type, int x, int y) +{ + if (!data_wl.init) { + printf("Input genrator is not initialized\n"); + return; + } + + if (type == TOUCH_ALL) { + input_generator_touch(0, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_BEGIN, 100, 100); + input_generator_touch(1, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_BEGIN, 200, 200); + input_generator_touch(2, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_BEGIN, 300, 300); + + input_generator_touch(0, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_UPDATE, 110, 110); + input_generator_touch(1, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_UPDATE, 210, 210); + input_generator_touch(2, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_UPDATE, 310, 310); + + input_generator_touch(0, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_UPDATE, 120, 120); + input_generator_touch(1, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_UPDATE, 220, 220); + input_generator_touch(2, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_UPDATE, 320, 320); + + input_generator_touch(0, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_END, 120, 120); + input_generator_touch(1, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_END, 220, 220); + input_generator_touch(2, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_END, 320, 320); + } else { + input_generator_touch(idx, type, x, y); + } +} + +static void +stdin_read(void) +{ + int c; + char buf[MAX_STR] = {0, }, *tmp, *buf_ptr, key_name[MAX_STR] = {0, }; + int count = 0; + int key_type = KEY_ALL, touch_idx = 0, touch_type = TOUCH_ALL, touch_x = 0, touch_y = 0; + + while ((c = getchar()) != EOF) { + if (c == '\n') break; + if (count >= MAX_STR) break; + + buf[count] = c; + count++; + } + + count = 0; + tmp = strtok_r(buf, " ", &buf_ptr); + if (!tmp) return; + + if (!strncmp(tmp, "init", sizeof("init"))) { + while (tmp) { + tmp = strtok_r(NULL, " ", &buf_ptr); + if (tmp) { + switch (count) { + case 0: + if (!strncmp("keyboard", tmp, MAX_STR-1)) + init_input_generator(TIZEN_INPUT_DEVICE_MANAGER_CLAS_KEYBOARD); + else if (!strncmp("touch", tmp, MAX_STR-1)) + init_input_generator(TIZEN_INPUT_DEVICE_MANAGER_CLAS_TOUCHSCREEN); + break; + default: + break; + } + } + count++; + } + } else if (!strncmp(tmp, "deinit", sizeof("deinit"))) { + deinit_input_generator(); + } else if (!strncmp(tmp, "key", sizeof("key"))) { + while (tmp) { + tmp = strtok_r(NULL, " ", &buf_ptr); + if (tmp) { + switch (count) { + case 0: + strncpy(key_name, tmp, MAX_STR-1); + break; + case 1: + key_type = atoi(tmp); + break; + default: + break; + } + } + count++; + } + key_generate(key_name, key_type); + } else if (!strncmp(tmp, "touch", sizeof("touch"))) { + while (tmp) { + tmp = strtok_r(NULL, " ", &buf_ptr); + if (tmp) { + switch (count) { + case 0: + touch_idx = atoi(tmp); + break; + case 1: + touch_type = atoi(tmp); + break; + case 2: + touch_x = atoi(tmp); + break; + case 3: + touch_y = atoi(tmp); + break; + default: + break; + } + } + count++; + } + touch_generate(touch_idx, touch_type, touch_x, touch_y); + } else if (!strncmp(buf, "q", MAX_STR) || !strncmp(buf, "quit", MAX_STR)) { + data_wl.run = 0; + } else if (!strncmp(buf, "help", MAX_STR)) { + usage(); + } else if (!strncmp(buf, "log", MAX_STR)) { + if (data_wl.enable_log) + printf("Disable detailed logs\n"); + else + printf("Enable detailed logs\n"); + + data_wl.enable_log = !data_wl.enable_log; + } else { + printf("Invalid arguments\n"); + usage(); + } +} + +static void +input_device_manager_handle_error(void *data, + struct tizen_input_device_manager *tizen_input_device_manager, + uint32_t errorcode) +{ + if (data_wl.enable_log) + printf("errorcode: %d\n", errorcode); + data_wl.request_notified = errorcode; +} + +static const struct tizen_input_device_manager_listener _input_device_manager_listener = +{ + .device_add = NULL, + .device_remove = NULL, + .error = input_device_manager_handle_error, + .block_expired = NULL, +}; + +static void +registry_handle_global(void * data, struct wl_registry * registry, uint32_t id, + const char * interface, uint32_t version) +{ + if (strcmp(interface, "wl_compositor") == 0) { + data_wl.compositor = wl_registry_bind(registry, id, + &wl_compositor_interface, version); + if (!data_wl.compositor) { + printf("Failed to bind compositor."); + return; + } + if (data_wl.enable_log) + printf("Success to bind compositor."); + } else if (strcmp(interface, "tizen_input_device_manager") == 0) { + data_wl.devicemgr = wl_registry_bind(registry, id, + &tizen_input_device_manager_interface, version); + if (!data_wl.devicemgr) { + printf("Failed to bind input device manager"); + return; + } + if (data_wl.enable_log) + printf("Success to bind tizen input device manager."); + tizen_input_device_manager_add_listener(data_wl.devicemgr, + &_input_device_manager_listener, data_wl.display); + } +} + +static void +registry_handle_global_remove(void * data, struct wl_registry * registry, uint32_t id) +{ + if (data_wl.enable_log) + printf("registry is removed. id: %d !\n", id); +} + +static const struct wl_registry_listener _registry_listener = { + registry_handle_global, + registry_handle_global_remove +}; + +static int +wayland_init(void) +{ + memset(&data_wl, 0, sizeof(struct display)); + data_wl.request_notified = -1; + + data_wl.display = wl_display_connect(NULL); + if (!data_wl.display) { + printf("Failed to connect wayland display\n"); + return 0; + } + + data_wl.queue = wl_display_create_queue(data_wl.display); + if (!data_wl.queue) { + printf("Failed to create queue\n"); + return 0; + } + + data_wl.registry = wl_display_get_registry(data_wl.display); + if (!data_wl.registry) { + printf("Failed to get registry\n"); + return 0; + } + + wl_proxy_set_queue((struct wl_proxy*)data_wl.registry, data_wl.queue); + wl_registry_add_listener(data_wl.registry, &_registry_listener, NULL); + + if (wl_display_dispatch_queue(data_wl.display, data_wl.queue) == -1) { + printf("Failed to dispatch display\n"); + return 0; + } + if (wl_display_roundtrip_queue(data_wl.display, data_wl.queue) == -1) { + printf("Failed to roundtrip display\n"); + return 0; + } + + return 1; +} + +static void +wayland_deinit(void) +{ + if (data_wl.enable_log) + printf("Shutdown wayland system\n"); + + if (data_wl.init) deinit_input_generator(); + + if (data_wl.queue) wl_event_queue_destroy(data_wl.queue); + if (data_wl.devicemgr) tizen_input_device_manager_destroy(data_wl.devicemgr); + if (data_wl.display) { + wl_registry_destroy(data_wl.registry); + wl_display_flush(data_wl.display); + wl_display_disconnect(data_wl.display); + } +} + +static int +epoll_init(void) +{ + struct epoll_event ep[2]; + + data_wl.fd_epoll = epoll_create(SIZE_EPOLL); + if (data_wl.fd_epoll <= 0) { + printf("Failed to epoll create: %d\n", SIZE_EPOLL); + return 0; + } + + data_wl.fd_display = wl_display_get_fd(data_wl.display); + + memset(ep, 0, sizeof(struct epoll_event)*2); + + ep[0].events = EPOLLIN | EPOLLERR | EPOLLHUP; + ep[0].data.fd = data_wl.fd_display; + epoll_ctl(data_wl.fd_epoll, EPOLL_CTL_ADD, data_wl.fd_display, &ep[0]); + ep[1].events = EPOLLIN | EPOLLERR | EPOLLHUP; + ep[1].data.fd = STDIN_FILENO; + epoll_ctl(data_wl.fd_epoll, EPOLL_CTL_ADD, 0, &ep[1]); + + return 1; +} + +static void +mainloop(void) +{ + struct epoll_event ep[SIZE_EPOLL]; + int res, count, i; + + res = epoll_init(); + if (!res) { + printf("Failed to init epoll\n"); + return; + } + + data_wl.run = 1; + while (data_wl.run) { + res = wl_display_dispatch_queue_pending(data_wl.display, data_wl.queue); + if (res < 0) { + printf("Failed to dispatch pending. result: %d\n", res); + data_wl.run = 0; + break; + } + res = wl_display_flush(data_wl.display); + if (res < 0) { + printf("Failed to flush display. result: %d\n", res); + data_wl.run = 0; + break; + } + + count = epoll_wait(data_wl.fd_epoll, ep, SIZE_EPOLL, -1); + for (i = 0; i < count; i++) { + if (ep[i].events & EPOLLIN) { + if (ep[i].data.fd == data_wl.fd_display) { + wl_display_dispatch_queue(data_wl.display, data_wl.queue); + } else { + stdin_read(); + } + } + if (ep[i].events & EPOLLERR) { + data_wl.run = 0; + } + if (ep[i].events & EPOLLHUP) { + data_wl.run = 0; + } + } + } +} + +int +main(int argc, char **argv) +{ + int res; + + res = wayland_init(); + if (!res) return 0; + + mainloop(); + + wayland_deinit(); + + return 0; +} diff --git a/src/clients/meson.build b/src/clients/meson.build index 6fcd3f8..ba09b32 100644 --- a/src/clients/meson.build +++ b/src/clients/meson.build @@ -12,6 +12,7 @@ executable('ds-simple-shm-shell', wayland_tbm_client = dependency('wayland-tbm-client', required: false) libtbm = dependency('libtbm', required: false) +tizen_extension_client = dependency('tizen-extension-client', required: true) if not wayland_tbm_client.found() or not libtbm.found() subdir_done() @@ -22,6 +23,7 @@ simple_tbm_deps = [ dependency('wayland-client', required: true), wayland_tbm_client, libtbm, + tizen_extension_client, ] protocols = { @@ -65,3 +67,16 @@ executable('ds-simple-dpms', install_dir: libds_bindir, install: true, ) + +input_generator_files = ['input-generator.c'] +input_generator_deps = [ + dependency('wayland-client', required: true), + tizen_extension_client, +] + +executable('input-generator', + input_generator_files, + dependencies: input_generator_deps, + install_dir: libds_bindir, + install: true, +) diff --git a/src/clients/simple-tbm.c b/src/clients/simple-tbm.c index 4fd9847..c82349f 100644 --- a/src/clients/simple-tbm.c +++ b/src/clients/simple-tbm.c @@ -38,6 +38,7 @@ #include #include #include "xdg-shell-client-protocol.h" +#include static uint64_t buffer_info_key; #define BUFFER_INFO_KEY (unsigned long)(&buffer_info_key) @@ -51,6 +52,10 @@ struct display { struct wl_seat *seat; struct wayland_tbm_client *wl_tbm; bool has_xrgb; + + struct tizen_input_device_manager *devicemgr; + int notified; + bool blocked; }; struct window { @@ -385,12 +390,43 @@ static void touch_handle_down(void *data, struct wl_touch *wl_touch, { fprintf(stderr, "touch_handle_down id:%d, x:%d, y:%d\n", id, wl_fixed_to_int(x), wl_fixed_to_int(y)); + + struct display *d = data; + + tizen_input_device_manager_block_events(d->devicemgr, 0, TIZEN_INPUT_DEVICE_MANAGER_CLAS_KEYBOARD, 50000); + + while (d->notified == -1) + wl_display_roundtrip(d->display); + + if (d->notified == TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE) { + printf("Success to block keyboard events\n"); + } else { + printf("Failed to block keyboard events: %d\n", d->notified); + } + d->notified = -1; + d->blocked = true; } static void touch_handle_up(void *data, struct wl_touch *wl_touch, uint32_t serial, uint32_t time, int32_t id) { fprintf(stderr, "touch_handle_up id:%d\n", id); + + struct display *d = data; + + if (!d->blocked) return; + tizen_input_device_manager_unblock_events(d->devicemgr, 0); + + while (d->notified == -1) + wl_display_roundtrip(d->display); + + if (d->notified == TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE) { + printf("Success to unblock keyboard events\n"); + } else { + printf("Failed to unblock keyboard events: %d\n", d->notified); + } + d->notified = -1; + d->blocked = false; } static void touch_handle_motion(void *data, struct wl_touch *wl_touch, @@ -446,9 +482,9 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) { if (state == WL_KEYBOARD_KEY_STATE_PRESSED) { - fprintf(stderr, "keyboard_handle_key: PRESSED\n"); + fprintf(stderr, "keyboard_handle_key: key:%d, PRESSED\n", key); } else { - fprintf(stderr, "keyboard_handle_key: RELEASED\n"); + fprintf(stderr, "keyboard_handle_key: key:%d, RELEASED\n", key); } } @@ -464,6 +500,7 @@ static struct wl_keyboard_listener keyboard_listener = { static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, enum wl_seat_capability caps) { + struct display *d = data; if ((caps & WL_SEAT_CAPABILITY_KEYBOARD)) { struct wl_keyboard *keyboard = wl_seat_get_keyboard(wl_seat); wl_keyboard_add_listener(keyboard, &keyboard_listener, NULL); @@ -476,7 +513,7 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, } if ((caps & WL_SEAT_CAPABILITY_TOUCH)) { struct wl_touch *touch = wl_seat_get_touch(wl_seat); - wl_touch_add_listener(touch, &touch_listener, NULL); + wl_touch_add_listener(touch, &touch_listener, d); fprintf(stderr, "seat_handle_capabilities: touch\n"); } } @@ -493,6 +530,31 @@ const struct wl_seat_listener seat_listener = { }; static void +input_device_manager_handle_error(void *data, + struct tizen_input_device_manager *tizen_input_device_manager, + uint32_t errorcode) +{ + struct display *d = data; + fprintf(stderr, "errorcode: %d\n", errorcode); + d->notified = errorcode; +} + +static void +input_device_manager_handle_block_expired(void *data, + struct tizen_input_device_manager *tizen_input_device_manager) +{ + fprintf(stderr, "block expired\n"); +} + +static const struct tizen_input_device_manager_listener _input_device_manager_listener = +{ + .device_add = NULL, + .device_remove = NULL, + .error = input_device_manager_handle_error, + .block_expired = input_device_manager_handle_block_expired, +}; + +static void registry_handle_global(void *data, struct wl_registry *registry, uint32_t id, const char *interface, uint32_t version) { @@ -515,7 +577,13 @@ registry_handle_global(void *data, struct wl_registry *registry, id, &wl_seat_interface, 7); wl_seat_add_listener(d->seat, &seat_listener, d); fprintf(stderr, "wl_seat bound!\n"); - } + } else if (strcmp(interface, "tizen_input_device_manager") == 0) { + d->devicemgr = wl_registry_bind(registry, + id, &tizen_input_device_manager_interface, version); + tizen_input_device_manager_add_listener(d->devicemgr, + &_input_device_manager_listener, d); + fprintf(stderr, "tizen input device manager bound!\n"); + } } static void @@ -605,12 +673,20 @@ create_display(void) exit(1); } + display->notified = -1; + return display; } static void destroy_display(struct display *display) { + if (display->seat) + wl_seat_destroy(display->seat); + + if (display->devicemgr) + tizen_input_device_manager_destroy(display->devicemgr); + if (display->shm) wl_shm_destroy(display->shm); diff --git a/src/examples/meson.build b/src/examples/meson.build index aad893e..eb9ae29 100644 --- a/src/examples/meson.build +++ b/src/examples/meson.build @@ -76,6 +76,7 @@ if get_option('tizen') tinyds_tdm_libinput_files, dependencies: [ common_deps, + dep_libds_tizen_input_devicemgr, dependency('pixman-1', required: true), dependency('threads', required: true), ], diff --git a/src/examples/tinyds-tdm-libinput.c b/src/examples/tinyds-tdm-libinput.c index f4e9319..5634707 100644 --- a/src/examples/tinyds-tdm-libinput.c +++ b/src/examples/tinyds-tdm-libinput.c @@ -23,6 +23,9 @@ #include #include #include +#include +#include +#include #define USE_TDM_BUFFER_QUEUE @@ -36,6 +39,7 @@ #include "pixman-helper.h" #define TINYDS_UNUSED __attribute__((unused)) +struct tinyds_keyboard; struct tinyds_output { @@ -73,6 +77,7 @@ struct tinyds_server struct ds_seat *seat; uint32_t seat_caps; double output_x, output_y; + struct ds_tizen_input_devicemgr *devicemgr; struct tinyds_output *output; struct wl_event_source *stdin_source; @@ -82,6 +87,8 @@ struct tinyds_server struct wl_listener new_output; struct wl_listener new_input; struct wl_listener new_xdg_surface; + + struct tinyds_keyboard *keyboard; }; struct tinyds_view @@ -206,9 +213,18 @@ view_handle_xdg_surface_map(struct wl_listener *listener, void *data TINYDS_UNUSED) { struct tinyds_view *view; - + struct ds_keyboard *keyboard; view = wl_container_of(listener, view, xdg_surface_map); view->mapped = true; + + if (!view->server->keyboard) return; + keyboard = ds_input_device_get_keyboard(view->server->keyboard->dev); + if (keyboard != NULL) { + ds_seat_keyboard_notify_enter(view->server->seat, + ds_xdg_surface_get_surface(view->xdg_surface), + keyboard->keycodes, keyboard->num_keycodes, + &keyboard->modifiers); + } } static void @@ -373,6 +389,59 @@ backend_handle_new_input(struct wl_listener *listener, void *data) ds_seat_set_capabilities(server->seat, server->seat_caps); } +static void +devicemgr_add_keymap_data(struct wl_list *list, const char *name, int keycode) +{ + struct ds_tizen_input_devicemgr_keymap_data *data; + + data = calloc(1, sizeof *data); + if (!data) { + ds_err("Failed to alloc memory\n"); + return; + } + + data->name = strdup(name); + data->keycode = keycode; + + wl_list_insert(list, &data->link); +} + +static void +devicemgr_remove_keymap_data(struct wl_list *list, int keycode) +{ + struct ds_tizen_input_devicemgr_keymap_data *data, *tmp; + + wl_list_for_each_safe(data, tmp, list, link) { + if (data->keycode == keycode) { + wl_list_remove(&data->link); + free(data); + } + } +} + +static void +devicemgr_set_keymap(struct ds_tizen_input_devicemgr *devicemgr) +{ + struct wl_list keymap_list; + bool res; + + wl_list_init(&keymap_list); + + devicemgr_add_keymap_data(&keymap_list, "XF86VolumeRaise", 455); + devicemgr_add_keymap_data(&keymap_list, "XF86VolumeLower", 456); + devicemgr_add_keymap_data(&keymap_list, "XF86LightOn", 457); + devicemgr_add_keymap_data(&keymap_list, "XF86LightOff", 458); + + res = ds_tizen_input_devicemgr_set_keymap_list(devicemgr, &keymap_list); + if (!res) + ds_inf("Failed to set keymap"); + + devicemgr_remove_keymap_data(&keymap_list, 455); + devicemgr_remove_keymap_data(&keymap_list, 456); + devicemgr_remove_keymap_data(&keymap_list, 457); + devicemgr_remove_keymap_data(&keymap_list, 458); +} + static bool init_server(struct tinyds_server *server, struct wl_display *display) { @@ -388,8 +457,10 @@ init_server(struct tinyds_server *server, struct wl_display *display) return false; server->input_backend = ds_libinput_backend_create(display); - if (!server->input_backend) + if (!server->input_backend) { + ds_backend_destroy(server->backend); return false; + } server->new_output.notify = backend_handle_new_output; ds_backend_add_new_output_listener(server->backend, @@ -419,6 +490,13 @@ init_server(struct tinyds_server *server, struct wl_display *display) goto err; server->seat_caps = 0; + server->devicemgr = ds_tizen_input_devicemgr_create( + server->input_backend, server->seat); + if (!server->devicemgr) { + goto err; + } + + devicemgr_set_keymap(server->devicemgr); return true; err: @@ -683,14 +761,35 @@ keyboard_handle_device_destroy(struct wl_listener *listener, void *data) wl_list_remove(&kbd->destroy.link); wl_list_remove(&kbd->key.link); + kbd->server->keyboard = NULL; + 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; + int nsyms; + bool handled = false; kbd = wl_container_of(listener, kbd, key); @@ -698,14 +797,32 @@ keyboard_handle_key(struct wl_listener *listener, void *data) "update_state(%d)", kbd->dev, event->keycode, event->state, event->time_msec, event->update_state); - //TODO: - //ds_seat_keyboard_notify_key() + + ds_keyboard = ds_input_device_get_keyboard(kbd->dev); + + if (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++) { + handled = server_handle_keybinding(kbd->server, syms[i]); + } + } + } + + if (!handled) { + ds_seat_keyboard_notify_key(kbd->server->seat, event->time_msec, + event->keycode, event->state); + } } static void server_add_keyboard(struct tinyds_server *server, struct ds_input_device *dev) { struct tinyds_keyboard *kbd; + struct xkb_context *context; + struct xkb_keymap *keymap; kbd = calloc(1, sizeof *kbd); assert(kbd); @@ -713,12 +830,28 @@ server_add_keyboard(struct tinyds_server *server, struct ds_input_device *dev) kbd->dev = dev; kbd->server = server; + context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + keymap = xkb_keymap_new_from_names(context, NULL, + XKB_KEYMAP_COMPILE_NO_FLAGS); + + if (!keymap) { + ds_err("Failed to compile keymap"); + xkb_context_unref(context); + } + + ds_keyboard_set_keymap(ds_input_device_get_keyboard(dev), keymap); + + xkb_keymap_unref(keymap); + xkb_context_unref(context); + 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); + server->keyboard = kbd; + ds_inf("Keyboard(%p) added", kbd); } diff --git a/src/libds-tizen/backend/tdm/backend.c b/src/libds-tizen/backend/tdm/backend.c index e756ac1..21fb025 100644 --- a/src/libds-tizen/backend/tdm/backend.c +++ b/src/libds-tizen/backend/tdm/backend.c @@ -25,7 +25,7 @@ ds_tdm_backend_create(struct wl_display *display) if (!tdm) return NULL; - ds_backend_init(&tdm->base, &tdm_backend_iface); + ds_backend_init(&tdm->base, display, &tdm_backend_iface); tdm->wl_display = display; tdm->clock = CLOCK_MONOTONIC; // FIXME diff --git a/src/libds-tizen/input-devicemgr/input-devicemgr.c b/src/libds-tizen/input-devicemgr/input-devicemgr.c new file mode 100644 index 0000000..84700d7 --- /dev/null +++ b/src/libds-tizen/input-devicemgr/input-devicemgr.c @@ -0,0 +1,1063 @@ +#include +#include // gettimeofday() +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "input-devicemgr.h" +#include "src/libds/seat.h" + +#define TIZEN_INPUT_DEVICEMGR_VERSION 4 +#define TIZEN_PRIV_INPUT_GENERATOR "http://tizen.org/privilege/inputgenerator" +#define TIZEN_PRIV_INPUT_BLOCK "http://tizen.org/privilege/internal/inputdevice.block" + +static const struct ds_keyboard_grab_interface devicemgr_keyboard_grab_iface; + +//listeners +static void +backend_handle_destroy(struct wl_listener *listener, void *data); +static void +backend_handle_input_device_add(struct wl_listener *listener, void *data); +static void +seat_handle_destroy(struct wl_listener *listener, void *data); + +//tizen_input_device_manager bind/unbind +static void +device_manager_handle_bind(struct wl_client *client, void *data, + uint32_t version, uint32_t id); +static void +device_manager_client_handle_resource_destroy(struct wl_resource *resource); + +//tizen_input_device_manager's handlers for requests +static void +device_manager_handle_block_events(struct wl_client *client, + struct wl_resource *resource, uint32_t serial, + uint32_t clas, uint32_t duration); +static void +device_manager_handle_unblock_events(struct wl_client *client, + struct wl_resource *resource, uint32_t serial); +static void +device_manager_handle_init_generator(struct wl_client *client, + struct wl_resource *resource, uint32_t clas); +static void +device_manager_handle_init_generator_with_name(struct wl_client *client, + struct wl_resource *resource, uint32_t clas, const char *name); +static void +device_manager_handle_deinit_generator(struct wl_client *client, + struct wl_resource *resource, uint32_t clas); +static void +device_manager_handle_generate_key(struct wl_client *client, + struct wl_resource *resource, + const char *keyname, uint32_t pressed); +static void +device_manager_handle_destroy(struct wl_client *client, + struct wl_resource *resource); + +// +static void tz_devicemgr_destroy(struct ds_tizen_input_devicemgr *tz_devicemgr); +static int +tz_devicemgr_init_generator(struct ds_tizen_input_devicemgr *tz_devicemgr, + struct wl_resource *resource, const char *name); +static int +tz_devicemgr_deinit_generator(struct ds_tizen_input_devicemgr *tz_devicemgr, + struct wl_resource *resource); +static bool +tz_devicemgr_generate_key(struct ds_input_device *device, int keycode, + int pressed); +static bool +tz_devicemgr_pressed_keys_update(struct ds_tizen_input_devicemgr *tz_devicemgr, + int keycode, bool pressed); +static void +tz_devicemgr_pressed_keys_cleanup(struct ds_tizen_input_devicemgr *tz_devicemgr); +static void +tz_devicemgr_keymap_list_cleanup(struct ds_tizen_input_devicemgr *tz_devicemgr); +static int +tz_devicemgr_keyname_to_keycode(struct wl_list *list, const char *name); + +static bool +tz_devicemgr_check_privilege(struct ds_tizen_input_devicemgr *tz_devicemgr, + struct wl_client *client, const char *rule); + +static void +tz_devicemgr_grab_keyboard(struct ds_tizen_input_devicemgr *tz_devicemgr); +static void +tz_devicemgr_ungrab_keyboard(struct ds_tizen_input_devicemgr *tz_devicemgr); +static void +tz_devicemgr_ungrab_keyboard_check(struct ds_tizen_input_devicemgr *tz_devicemgr); +static void +tz_devicemgr_blocked_keys_cleanup(struct ds_tizen_input_devicemgr *tz_devicemgr); + +WL_EXPORT struct ds_tizen_input_devicemgr * +ds_tizen_input_devicemgr_create(struct ds_backend *backend, + struct ds_seat *seat) +{ + struct ds_tizen_input_devicemgr *tz_devicemgr; + + tz_devicemgr = calloc(1, sizeof *tz_devicemgr); + if (!tz_devicemgr) { + ds_err("Fail to allocate ds_tizen_input_devicemgr"); + return NULL; + } + + tz_devicemgr->backend = backend; + tz_devicemgr->backend_destroy.notify = backend_handle_destroy; + ds_backend_add_destroy_listener(backend, &tz_devicemgr->backend_destroy); + + tz_devicemgr->seat = seat; + tz_devicemgr->seat_destroy.notify = seat_handle_destroy; + ds_seat_add_destroy_listener(seat, &tz_devicemgr->seat_destroy); + + tz_devicemgr->new_input.notify = backend_handle_input_device_add; + ds_backend_add_new_input_listener(backend, &tz_devicemgr->new_input); + + tz_devicemgr->global = wl_global_create(backend->display, + &tizen_input_device_manager_interface, + TIZEN_INPUT_DEVICEMGR_VERSION, + tz_devicemgr, device_manager_handle_bind); + if (!tz_devicemgr->global) { + goto err_global; + } + + tz_devicemgr->devices.kbd = calloc(1, + sizeof(struct ds_tizen_input_devicemgr_device)); + if (!tz_devicemgr->devices.kbd) { + goto err_kbd; + } + + tz_devicemgr->grab = calloc(1, sizeof(struct ds_seat_keyboard_grab)); + if (!tz_devicemgr->grab) + { + goto err_grab; + } + + tz_devicemgr->grab->iface = &devicemgr_keyboard_grab_iface; + tz_devicemgr->grab->seat = tz_devicemgr->seat; + tz_devicemgr->grab->data = tz_devicemgr; + + wl_signal_init(&tz_devicemgr->events.destroy); + wl_list_init(&tz_devicemgr->clients); + wl_list_init(&tz_devicemgr->pressed_keys); + wl_list_init(&tz_devicemgr->keymap_list); + wl_list_init(&tz_devicemgr->blocked_keys); + + if (!tizen_security_init()) { + ds_inf("tizen_security_init() is failed. go on without security"); + } + + ds_inf("Global created: ds_tizen_input_devicemgr(%p) ", tz_devicemgr); + return tz_devicemgr; +err_grab: + free(tz_devicemgr->devices.kbd); +err_kbd: + wl_global_destroy(tz_devicemgr->global); +err_global: + wl_list_remove(&tz_devicemgr->backend_destroy.link); + wl_list_remove(&tz_devicemgr->seat_destroy.link); + wl_list_remove(&tz_devicemgr->new_input.link); + free(tz_devicemgr); + return NULL; +} + +WL_EXPORT void +ds_tizen_input_devicemgr_add_destroy_listener( + struct ds_tizen_input_devicemgr *tz_devicemgr, + struct wl_listener *listener) +{ + wl_signal_add(&tz_devicemgr->events.destroy, listener); +} + +WL_EXPORT bool +ds_tizen_input_devicemgr_set_keymap_list( + struct ds_tizen_input_devicemgr *tz_devicemgr, struct wl_list *list) +{ + struct ds_tizen_input_devicemgr_keymap_data *data, *new_data; + + if (!tz_devicemgr || !list) { + ds_err("Please insert correct data\n"); + return false; + } + + wl_list_for_each(data, list, link) { + new_data = calloc(1, sizeof *data); + if (!new_data) { + ds_err("Failed to alloc memory"); + return false; + } + new_data->name = strdup(data->name); + new_data->keycode = data->keycode; + wl_list_insert(&tz_devicemgr->keymap_list, &new_data->link); + } + ds_inf("keymap set. length:%d", + wl_list_length(&tz_devicemgr->keymap_list)); + + return true; +} + +static void +tz_devicemgr_destroy(struct ds_tizen_input_devicemgr *tz_devicemgr) +{ + struct ds_tizen_input_devicemgr_client *client_data, *tmp; + + tizen_security_finish(); + + tz_devicemgr_keymap_list_cleanup(tz_devicemgr); + tz_devicemgr_blocked_keys_cleanup(tz_devicemgr); + tz_devicemgr_ungrab_keyboard(tz_devicemgr); + + wl_signal_emit(&tz_devicemgr->events.destroy, tz_devicemgr); + wl_list_remove(&tz_devicemgr->backend_destroy.link); + wl_list_remove(&tz_devicemgr->seat_destroy.link); + wl_list_remove(&tz_devicemgr->new_input.link); + + wl_global_destroy(tz_devicemgr->global); + + wl_list_for_each_safe(client_data, tmp, &tz_devicemgr->clients, link) { + wl_list_remove(&client_data->link); + tz_devicemgr_deinit_generator(tz_devicemgr, client_data->resource); + + wl_resource_set_user_data(client_data->resource, NULL); + free(client_data); + } + + free(tz_devicemgr->devices.kbd); + free(tz_devicemgr->grab); + free(tz_devicemgr); +} + +static void +backend_handle_destroy(struct wl_listener *listener, void *data) +{ + struct ds_tizen_input_devicemgr *tz_devicemgr; + + tz_devicemgr = wl_container_of(listener, tz_devicemgr, backend_destroy); + + ds_inf("Global destroy: ds_tizen_input_devicemgr(%p)", tz_devicemgr); + + tz_devicemgr_destroy(tz_devicemgr); +} + +static void +seat_handle_destroy(struct wl_listener *listener, void *data) +{ + struct ds_tizen_input_devicemgr *tz_devicemgr; + + tz_devicemgr = wl_container_of(listener, tz_devicemgr, backend_destroy); + + wl_list_remove(&tz_devicemgr->seat_destroy.link); + wl_list_init(&tz_devicemgr->seat_destroy.link); + tz_devicemgr->seat = NULL; +} + +static void +backend_handle_input_device_add(struct wl_listener *listener, void *data) +{ + struct ds_input_device *dev = data; + struct ds_tizen_input_devicemgr *tz_devicemgr; + enum ds_input_device_type dev_type; + + tz_devicemgr = wl_container_of(listener, tz_devicemgr, new_input); + + dev_type = ds_input_device_get_type(dev); + if (dev_type == DS_INPUT_DEVICE_KEYBOARD) { + if (tz_devicemgr->devices.kbd->input_device) return; + ds_inf("devicemgr's kbd device is set"); + tz_devicemgr->devices.kbd->input_device = dev; + } + else if (dev_type == DS_INPUT_DEVICE_POINTER) { + //TODO: assign input_device 'dev' to devices.ptr + } + else if (dev_type == DS_INPUT_DEVICE_TOUCH) { + //TODO: assign input_device 'dev' to devices.ptr + } +} + +static const struct tizen_input_device_manager_interface _devicemgr_impl = { + .block_events = device_manager_handle_block_events, + .unblock_events = device_manager_handle_unblock_events, + .init_generator = device_manager_handle_init_generator, + .deinit_generator = device_manager_handle_deinit_generator, + .generate_key = device_manager_handle_generate_key, + .generate_pointer = NULL, + .generate_touch = NULL, + .pointer_warp = NULL, + .init_generator_with_name = + device_manager_handle_init_generator_with_name, // v2 + .destroy = device_manager_handle_destroy, // v3 + .generate_axis = NULL, // v3 + .set_touch_count = NULL, // v4 +}; + +static void +device_manager_client_handle_resource_destroy(struct wl_resource *resource) +{ + struct ds_tizen_input_devicemgr *tz_devicemgr; + struct ds_tizen_input_devicemgr_client *client_data, *tmp; + + tz_devicemgr = wl_resource_get_user_data(resource); + + tz_devicemgr_deinit_generator(tz_devicemgr, resource); + + if (resource == tz_devicemgr->block_resource) { + tz_devicemgr_ungrab_keyboard_check(tz_devicemgr); + if (tz_devicemgr->timer) { + wl_event_source_remove(tz_devicemgr->timer); + tz_devicemgr->timer = NULL; + } + } + + wl_list_for_each_safe(client_data, tmp, &tz_devicemgr->clients, link) { + if (client_data->resource == resource) { + wl_list_remove(&client_data->link); + free(client_data); + } + } +} + +static void +device_manager_handle_bind(struct wl_client *client, void *data, + uint32_t version, uint32_t id) +{ + struct ds_tizen_input_devicemgr *tz_devicemgr = data; + struct ds_tizen_input_devicemgr_client *client_data; + + client_data = calloc(1, sizeof *client_data); + if (!client_data) { + ds_err("Failed to allocate memory !\n"); + wl_client_post_no_memory(client); + return; + } + + client_data->resource = wl_resource_create(client, + &tizen_input_device_manager_interface, MIN(version,4), id); + if (!client_data->resource) { + ds_err("Failed to create resource! (ver. :%d, id:%d)", version, id); + free(client_data); + wl_client_post_no_memory(client); + return; + } + + client_data->init = false; + wl_list_init(&client_data->link); + wl_list_insert(&tz_devicemgr->clients, &client_data->link); + + wl_resource_set_implementation(client_data->resource, &_devicemgr_impl, + tz_devicemgr, device_manager_client_handle_resource_destroy); +} + +static void +device_manager_handle_init_generator(struct wl_client *client, + struct wl_resource *resource, uint32_t clas) +{ + struct ds_tizen_input_devicemgr *tz_devicemgr; + int ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NO_SYSTEM_RESOURCES; + + tz_devicemgr = wl_resource_get_user_data(resource); + + if (!tz_devicemgr_check_privilege(tz_devicemgr, client, + TIZEN_PRIV_INPUT_GENERATOR)) { + ds_err("No permission to input generate"); + ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NO_PERMISSION; + goto finish; + } + + if (clas != TIZEN_INPUT_DEVICE_MANAGER_CLAS_KEYBOARD) { + ds_err("only support keyboard device. (requested: 0x%x)\n", clas); + ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_INVALID_PARAMETER; + goto finish; + } + + ret = tz_devicemgr_init_generator(tz_devicemgr, resource, + "Input Generator"); + if (ret != TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE) { + ds_err("Failed to init input generator\n"); + goto finish; + } + +finish: + tizen_input_device_manager_send_error(resource, ret); +} + +static void +device_manager_handle_init_generator_with_name(struct wl_client *client, + struct wl_resource *resource, uint32_t clas, const char *name) +{ + struct ds_tizen_input_devicemgr *tz_devicemgr; + int ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NO_SYSTEM_RESOURCES; + + tz_devicemgr = wl_resource_get_user_data(resource); + + if (!name) { + ds_err("no name for device"); + ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_INVALID_PARAMETER; + goto finish; + } + + if (!tz_devicemgr_check_privilege(tz_devicemgr, client, + TIZEN_PRIV_INPUT_GENERATOR)) { + ds_err("No permission to input generate"); + ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NO_PERMISSION; + goto finish; + } + + if (clas != TIZEN_INPUT_DEVICE_MANAGER_CLAS_KEYBOARD) { + ds_err("only support keyboard device. (requested: 0x%x)\n", clas); + ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_INVALID_PARAMETER; + goto finish; + } + + ret = tz_devicemgr_init_generator(tz_devicemgr, resource, + name); + if (ret != TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE) { + ds_err("Failed to init input generator\n"); + goto finish; + } + +finish: + tizen_input_device_manager_send_error(resource, ret); +} + +static void +device_manager_handle_deinit_generator(struct wl_client *client, + struct wl_resource *resource, uint32_t clas) +{ + struct ds_tizen_input_devicemgr *tz_devicemgr; + int ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NO_SYSTEM_RESOURCES; + + tz_devicemgr = wl_resource_get_user_data(resource); + + if (!tz_devicemgr_check_privilege(tz_devicemgr, client, + TIZEN_PRIV_INPUT_GENERATOR)) { + ds_err("No permission to input generate"); + ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NO_PERMISSION; + goto finish; + } + + if (clas != TIZEN_INPUT_DEVICE_MANAGER_CLAS_KEYBOARD) { + ds_err("only support keyboard device. (requested: 0x%x)\n", clas); + ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_INVALID_PARAMETER; + goto finish; + } + + ret = tz_devicemgr_deinit_generator(tz_devicemgr, resource); + if (ret != TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE) { + ds_err("Failed to deinit input generator\n"); + goto finish; + } + +finish: + tizen_input_device_manager_send_error(resource, ret); +} + +struct keycode_map{ + xkb_keysym_t keysym; + xkb_keycode_t keycode; +}; + +static void +find_keycode(struct xkb_keymap *keymap, xkb_keycode_t key, void *data) +{ + struct keycode_map *found_keycodes = (struct keycode_map *)data; + xkb_keysym_t keysym = found_keycodes->keysym; + int nsyms = 0; + const xkb_keysym_t *syms_out = NULL; + + if (found_keycodes->keycode) return; + + nsyms = xkb_keymap_key_get_syms_by_level(keymap, key, 0, 0, &syms_out); + if (nsyms && syms_out) { + if (*syms_out == keysym) { + found_keycodes->keycode = key; + } + } +} + +static void +tz_devicemgr_xkb_keycode_from_keysym(struct xkb_keymap *keymap, + xkb_keysym_t keysym, xkb_keycode_t *keycode) +{ + struct keycode_map found_keycodes = {0,}; + found_keycodes.keysym = keysym; + xkb_keymap_key_for_each(keymap, find_keycode, &found_keycodes); + + *keycode = found_keycodes.keycode; +} + +static int +tz_devicemgr_xkb_keyname_to_keycode(struct xkb_keymap *keymap, + const char *name) +{ + xkb_keysym_t keysym = 0x0; + xkb_keycode_t keycode = 0; + + if (!strncmp(name, "Keycode-", sizeof("Keycode-")-1)) { + keycode = atoi(name + 8); + } else { + keysym = xkb_keysym_from_name(name, XKB_KEYSYM_NO_FLAGS); + tz_devicemgr_xkb_keycode_from_keysym(keymap, keysym, &keycode); + } + + return keycode; +} + +static void +device_manager_handle_generate_key(struct wl_client *client, + struct wl_resource *resource, const char *keyname, uint32_t pressed) +{ + struct ds_tizen_input_devicemgr *tz_devicemgr; + int ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NO_SYSTEM_RESOURCES; + int keycode = 0; + bool res; + struct ds_keyboard *kbd; + + tz_devicemgr = wl_resource_get_user_data(resource); + + if (!tz_devicemgr->devices.kbd || + !tz_devicemgr->devices.kbd->input_device) { + ds_err("Keyboard device is not initialized\n"); + goto finish; + } + + if (!tz_devicemgr_check_privilege(tz_devicemgr, client, + TIZEN_PRIV_INPUT_GENERATOR)) { + ds_err("No permission to input generate"); + ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NO_PERMISSION; + goto finish; + } + + // keyname to keycode using xkb_info + kbd = ds_input_device_get_keyboard( + tz_devicemgr->devices.kbd->input_device); + if (kbd->keymap) { + keycode = tz_devicemgr_xkb_keyname_to_keycode(kbd->keymap, keyname); + } + + if (keycode <= 0) { + keycode = tz_devicemgr_keyname_to_keycode(&tz_devicemgr->keymap_list, + keyname); + } + if (keycode <= 0) + goto finish; + + res = tz_devicemgr_generate_key(tz_devicemgr->devices.kbd->input_device, + keycode, pressed); + if (!res) { + ds_err("Generating key is failed. key: %s, pressed: %d", + keyname, pressed); + goto finish; + } + res = tz_devicemgr_pressed_keys_update(tz_devicemgr, keycode, pressed); + if (!res) { + ds_err("Updating pressed keys is failed. key: %s, pressed: %d", + keyname, pressed); + goto finish; + } + ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE; + +finish: + tizen_input_device_manager_send_error(resource, ret); +} + +static void +device_manager_handle_destroy(struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static bool +tz_devicemgr_check_privilege(struct ds_tizen_input_devicemgr *tz_devicemgr, + struct wl_client *client, const char *rule) +{ + pid_t pid = 0; + uid_t uid = 0; + gid_t gid = 0; + + if (!client) return false; + + wl_client_get_credentials(client, &pid, &uid, &gid); + + return tizen_security_check_privilege(pid, uid, rule); +} + +static const struct ds_input_device_interface input_device_iface = +{ + .destroy = NULL, +}; + +static struct ds_keyboard * +create_ds_keyboard() +{ + struct ds_keyboard *kbd; + kbd = calloc(1, sizeof *kbd); + if (!kbd) { + ds_err("Could not allocate memory"); + return NULL; + } + ds_keyboard_init(kbd, NULL); + + return kbd; +} + +static int +tz_devicemgr_init_generator(struct ds_tizen_input_devicemgr *tz_devicemgr, + struct wl_resource *resource, const char *name) +{ + int ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NO_SYSTEM_RESOURCES; + struct ds_tizen_input_devicemgr_client *client_data; + struct ds_tizen_input_devicemgr_device *kbd; + + ds_inf("Init generator. name:%s", name); + + kbd = tz_devicemgr->devices.kbd; + if (strlen(kbd->name) > 0) { + ds_inf("devices.kbd already has name. name:%s", kbd->name); + return TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE; + } + + if (kbd->input_device) { + ds_inf("devices.kbd is already set. name:%s", + ds_input_device_get_name(kbd->input_device)); + return TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE; + } + + //input_device create + kbd->input_device = calloc(1, sizeof(struct ds_input_device)); + if(!kbd->input_device) { + ds_err("Failed to create input device !\n"); + return ret; + } + + ds_input_device_init(kbd->input_device, DS_INPUT_DEVICE_KEYBOARD, + &input_device_iface, name, -1, -1); + kbd->input_device->keyboard = create_ds_keyboard(); + + wl_signal_emit(&tz_devicemgr->backend->events.new_input, + kbd->input_device); + + kbd->created = true; + strncpy(kbd->name, name, UINPUT_MAX_NAME_SIZE); + + wl_list_for_each(client_data, &tz_devicemgr->clients, link) { + if (client_data->resource == resource) { + if (client_data->init == false) { + client_data->init = true; + tz_devicemgr->ref++; + } + break; + } + } + + ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE; + + return ret; +} + +static int +tz_devicemgr_keyname_to_keycode(struct wl_list *list, const char *name) +{ + struct ds_tizen_input_devicemgr_keymap_data *data; + + if (!wl_list_empty(list)) { + wl_list_for_each(data, list, link) { + if (!strcmp(data->name, name)) { + return data->keycode; + } + } + } + + return 0; +} + +static bool +tz_devicemgr_generate_key(struct ds_input_device *device, int keycode, + int pressed) +{ + struct ds_event_keyboard_key ds_event; + struct timeval time; + unsigned int timestamp; + struct ds_keyboard *kbd; + + kbd = ds_input_device_get_keyboard(device); + if (!kbd) { + ds_err("No ds_keyboard to notify event"); + return false; + } + + gettimeofday(&time, NULL); + timestamp = time.tv_sec * 1000 + time.tv_usec / 1000; + + ds_event.time_msec = timestamp; + ds_event.keycode = keycode - 8; + if (pressed) + ds_event.state = WL_KEYBOARD_KEY_STATE_PRESSED; + else + ds_event.state = WL_KEYBOARD_KEY_STATE_RELEASED; + + ds_inf("Generate key. kbd:%p, key:%d, state:%s", kbd, ds_event.keycode, + (ds_event.state == WL_KEYBOARD_KEY_STATE_PRESSED) ? + "PRESSED" : "RELEASED"); + + ds_keyboard_notify_key(kbd, &ds_event); + + return true; +} + +static bool +tz_devicemgr_pressed_keys_update(struct ds_tizen_input_devicemgr *tz_devicemgr, + int keycode, bool pressed) +{ + struct ds_tizen_input_devicemgr_key_info *key, *tmp; + + if (pressed) { + key = calloc(1, sizeof(*key)); + if (!key) { + ds_err("Failed to alloc keydata memory.\n"); + return false; + } + key->keycode = keycode; + wl_list_init(&key->link); + wl_list_insert(&tz_devicemgr->pressed_keys, &key->link); + } + else { + wl_list_for_each_safe(key, tmp, &tz_devicemgr->pressed_keys, link) { + if (key->keycode == keycode) { + wl_list_remove(&key->link); + free(key); + break; + } + } + } + + ds_inf("Update pressed keys. length: %d, keycode:%d, pressed:%d", + wl_list_length(&tz_devicemgr->pressed_keys), keycode, pressed); + + return true; +} + +static void +tz_devicemgr_pressed_keys_cleanup(struct ds_tizen_input_devicemgr *tz_devicemgr) +{ + struct ds_tizen_input_devicemgr_key_info *keydata, *tmp; + + ds_inf("Clean up the pressed_keys. length: %d", + wl_list_length(&tz_devicemgr->pressed_keys)); + + wl_list_for_each_safe(keydata, tmp, &tz_devicemgr->pressed_keys, link) { + if (tz_devicemgr->devices.kbd) + tz_devicemgr_generate_key(tz_devicemgr->devices.kbd->input_device, + keydata->keycode, false); + wl_list_remove(&keydata->link); + free(keydata); + } +} + +static void +tz_devicemgr_keymap_list_cleanup(struct ds_tizen_input_devicemgr *tz_devicemgr) +{ + struct ds_tizen_input_devicemgr_keymap_data *keymap, *tmp; + + ds_inf("Clean up the keymap_list. length: %d", + wl_list_length(&tz_devicemgr->keymap_list)); + + wl_list_for_each_safe(keymap, tmp, &tz_devicemgr->keymap_list, link) { + free(keymap->name); + wl_list_remove(&keymap->link); + free(keymap); + } +} + +static void +tz_devicemgr_keyboard_close(struct ds_tizen_input_devicemgr *tz_devicemgr) +{ + if (!tz_devicemgr->devices.kbd->input_device) return; + ds_input_device_destroy(tz_devicemgr->devices.kbd->input_device); + tz_devicemgr->devices.kbd->input_device = NULL; + tz_devicemgr->devices.kbd->created = false; +} + +static int +tz_devicemgr_deinit_generator(struct ds_tizen_input_devicemgr *tz_devicemgr, + struct wl_resource *resource) +{ + int ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE; + struct ds_tizen_input_devicemgr_client *client_data; + + ds_inf("Deinit generator."); + wl_list_for_each(client_data, &tz_devicemgr->clients, link) { + if (client_data->resource == resource) { + if (client_data->init == true) { + client_data->init = false; + tz_devicemgr->ref--; + if (tz_devicemgr->ref < 0) tz_devicemgr->ref = 0; + break; + } else { + return ret; + } + } + } + + if (tz_devicemgr->ref <= 0) { + tz_devicemgr_pressed_keys_cleanup(tz_devicemgr); + + if (!tz_devicemgr->devices.kbd) + return TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE; + + if (tz_devicemgr->devices.kbd->created) + tz_devicemgr_keyboard_close(tz_devicemgr); + memset(tz_devicemgr->devices.kbd->name, 0, UINPUT_MAX_NAME_SIZE); + } + + return ret; +} + +static void +devicemgr_keyboard_grab_iface_enter(struct ds_seat_keyboard_grab *grab, + struct ds_surface *surface, uint32_t keycodes[], + size_t num_keycodes, struct ds_keyboard_modifiers *modifiers) +{ + ds_inf("devicemgr. keyboard_grab_iface_enter"); +} + +static void +devicemgr_keyboard_grab_iface_clear_focus(struct ds_seat_keyboard_grab *grab) +{ + ds_inf("devicemgr. keyboard_grab_iface_clear_focus"); +} + +static void +tz_devicemgr_blocked_keys_cleanup(struct ds_tizen_input_devicemgr *tz_devicemgr) +{ + struct ds_tizen_input_devicemgr_key_info *keydata, *tmp; + + ds_inf("Clean up the blocked keys. length: %d", + wl_list_length(&tz_devicemgr->blocked_keys)); + + wl_list_for_each_safe(keydata, tmp, &tz_devicemgr->blocked_keys, link) { + wl_list_remove(&keydata->link); + free(keydata); + } +} + +static void +devicemgr_keyboard_grab_iface_key(struct ds_seat_keyboard_grab *grab, + uint32_t time_msec, uint32_t key, uint32_t state) +{ + struct ds_tizen_input_devicemgr *devicemgr = grab->data; + struct ds_tizen_input_devicemgr_key_info *keydata, *tmp; + bool key_blocked = false; + + ds_inf("devicemgr. keyboard_grab_iface_key"); + + if (!devicemgr->block_resource) { + if (state == WL_KEYBOARD_KEY_STATE_PRESSED) { + goto finish; + } + else { + wl_list_for_each_safe(keydata, tmp, &devicemgr->blocked_keys, link) { + if (keydata->keycode == (int)key) { + wl_list_remove(&keydata->link); + free(keydata); + key_blocked = true; + break; + } + } + if (wl_list_empty(&devicemgr->blocked_keys)) { + tz_devicemgr_ungrab_keyboard(devicemgr); + } + if (key_blocked) { + goto finish; + } + } + } + + if (state == WL_KEYBOARD_KEY_STATE_PRESSED) { + keydata = calloc(1, sizeof (*keydata)); + if (!keydata) + goto finish; + keydata->keycode = key; + wl_list_init(&keydata->link); + wl_list_insert(&devicemgr->blocked_keys, &keydata->link); + key_blocked = true; + } + else { + if (wl_list_empty(&devicemgr->blocked_keys)) + goto finish; + wl_list_for_each_safe(keydata, tmp, &devicemgr->blocked_keys, link) { + if (keydata->keycode == (int)key) { + wl_list_remove(&keydata->link); + free(keydata); + key_blocked = true; + } + } + } + +finish: + if (!key_blocked) + ds_inf("block key event: (%d %s)\n", key, (state ? "press" : "release")); +} + +static void +devicemgr_modifiers_grab_iface_key(struct ds_seat_keyboard_grab *grab, + struct ds_keyboard_modifiers *modifiers) +{ + ds_inf("devicemgr. modifiers_grab_iface_key"); +} + +static void +devicemgr_cancel_grab_iface_key(struct ds_seat_keyboard_grab *grab) +{ + ds_inf("devicemgr. cancel_grab_iface_key"); +} + +static const struct ds_keyboard_grab_interface devicemgr_keyboard_grab_iface = { + .enter = devicemgr_keyboard_grab_iface_enter, + .clear_focus = devicemgr_keyboard_grab_iface_clear_focus, + .key = devicemgr_keyboard_grab_iface_key, + .modifiers = devicemgr_modifiers_grab_iface_key, + .cancel = devicemgr_cancel_grab_iface_key, +}; + +static void +tz_devicemgr_grab_keyboard(struct ds_tizen_input_devicemgr *tz_devicemgr) +{ + ds_seat_keyboard_start_grab(tz_devicemgr->seat, tz_devicemgr->grab); +} + +static void +tz_devicemgr_ungrab_keyboard(struct ds_tizen_input_devicemgr *tz_devicemgr) +{ + ds_seat_keyboard_end_grab(tz_devicemgr->seat); +} + +static void +tz_devicemgr_ungrab_keyboard_check(struct ds_tizen_input_devicemgr *tz_devicemgr) +{ + if (wl_list_empty(&tz_devicemgr->blocked_keys)) + tz_devicemgr_ungrab_keyboard(tz_devicemgr); + + tz_devicemgr->block_resource = NULL; +} + +static bool +devicemgr_add_timer(struct ds_tizen_input_devicemgr *tz_devicemgr, + wl_event_loop_timer_func_t func, int time) +{ + struct wl_event_loop *event_loop; + + event_loop = wl_display_get_event_loop(tz_devicemgr->backend->display); + if (!event_loop) { + ds_err("Failed to get event_loop from display: %p", + tz_devicemgr->backend->display); + return false; + } + + tz_devicemgr->timer = wl_event_loop_add_timer(event_loop, func, + tz_devicemgr); + if (!tz_devicemgr->timer) { + ds_err("Failed to timer"); + return false; + } + wl_event_source_timer_update(tz_devicemgr->timer, time); + + return true; +} + +static int +devicemgr_block_timer(void *data) +{ + struct ds_tizen_input_devicemgr *devicemgr = data; + + tizen_input_device_manager_send_block_expired(devicemgr->block_resource); + + tz_devicemgr_ungrab_keyboard_check(devicemgr); + + wl_event_source_remove(devicemgr->timer); + devicemgr->timer = NULL; + + return 1; +} + +static void +device_manager_handle_block_events(struct wl_client *client, + struct wl_resource *resource, uint32_t serial, uint32_t clas, + uint32_t duration) +{ + struct ds_tizen_input_devicemgr *tz_devicemgr; + int ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NO_SYSTEM_RESOURCES; + bool res; + + tz_devicemgr = wl_resource_get_user_data(resource); + + if (!tz_devicemgr_check_privilege(tz_devicemgr, client, + TIZEN_PRIV_INPUT_BLOCK)) { + ds_err("No permission to input generate"); + ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NO_PERMISSION; + goto finish; + } + + if (clas != TIZEN_INPUT_DEVICE_MANAGER_CLAS_KEYBOARD) { + ds_err("only support keyboard device. (requested: 0x%x)\n", clas); + ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_INVALID_PARAMETER; + goto finish; + } + + if(tz_devicemgr->block_resource) { + ds_err("currently the input system is already blocked\n"); + ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_INVALID_PARAMETER; + goto finish; + } + + res = devicemgr_add_timer(tz_devicemgr, devicemgr_block_timer, duration); + if (!res) { + ds_err("Failed to add a timer\n"); + goto finish; + } + + tz_devicemgr_grab_keyboard(tz_devicemgr); + tz_devicemgr->block_resource = resource; + ds_inf("Block events. clas: %d, duration:%d", clas, duration); + ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE; + +finish: + tizen_input_device_manager_send_error(resource, ret); +} + +static void +device_manager_handle_unblock_events(struct wl_client *client, + struct wl_resource *resource, uint32_t serial) +{ + struct ds_tizen_input_devicemgr *tz_devicemgr; + int ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NO_SYSTEM_RESOURCES; + + tz_devicemgr = wl_resource_get_user_data(resource); + + if (!tz_devicemgr_check_privilege(tz_devicemgr, client, + TIZEN_PRIV_INPUT_BLOCK)) { + ds_err("No permission to input generate"); + ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NO_PERMISSION; + goto finish; + } + + if (tz_devicemgr->block_resource != resource) { + ds_err("currently the input system is blocked by another resource"); + ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_INVALID_PARAMETER; + goto finish; + } + + tz_devicemgr_ungrab_keyboard_check(tz_devicemgr); + tz_devicemgr->block_resource = NULL; + ds_inf("Unblock events."); + ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE; + + if (tz_devicemgr->timer) { + wl_event_source_remove(tz_devicemgr->timer); + tz_devicemgr->timer = NULL; + } + +finish: + tizen_input_device_manager_send_error(resource, ret); +} \ No newline at end of file diff --git a/src/libds-tizen/input-devicemgr/input-devicemgr.h b/src/libds-tizen/input-devicemgr/input-devicemgr.h new file mode 100644 index 0000000..8418b16 --- /dev/null +++ b/src/libds-tizen/input-devicemgr/input-devicemgr.h @@ -0,0 +1,59 @@ +#ifndef DS_TIZEN_DEVICEMGR_H +#define DS_TIZEN_DEVICEMGR_H + +#include +#include +#include +#include +#include "libds/interfaces/input_device.h" +#include + +struct ds_tizen_input_devicemgr_device { + char name[UINPUT_MAX_NAME_SIZE + 1]; + struct ds_input_device *input_device; + bool created; +}; + +struct ds_tizen_input_devicemgr { + struct wl_global *global; + struct wl_display *display; + struct ds_backend *backend; + struct ds_seat *seat; + + struct { + struct wl_signal destroy; + } events; + + struct wl_listener new_input; + struct wl_listener backend_destroy; + struct wl_listener seat_destroy; + struct { + struct ds_tizen_input_devicemgr_device *kbd; + struct ds_tizen_input_devicemgr_device *ptr; + struct ds_tizen_input_devicemgr_device *touch; + } devices; + + struct wl_list clients; + int ref; + + struct wl_list pressed_keys; + struct wl_list keymap_list; + + struct wl_list blocked_keys; + struct wl_resource *block_resource; + struct wl_event_source *timer; + struct ds_seat_keyboard_grab *grab; +}; + +struct ds_tizen_input_devicemgr_client { + struct wl_resource *resource; + bool init; + struct wl_list link; // ds_tizen_input_devicemgr::clients +}; + +struct ds_tizen_input_devicemgr_key_info { + int keycode; + struct wl_list link; // ds_tizen_input_devicemgr::pressed_keys; +}; + +#endif diff --git a/src/libds-tizen/input-devicemgr/meson.build b/src/libds-tizen/input-devicemgr/meson.build new file mode 100644 index 0000000..30924a4 --- /dev/null +++ b/src/libds-tizen/input-devicemgr/meson.build @@ -0,0 +1,30 @@ +libds_tizen_input_devicemgr_files = [ + 'input-devicemgr.c', +] + +libds_tizen_input_devicemgr_deps = [ + dep_libds, + dep_libds_tizen, + dependency('tizen-extension-server', required: true), +] + +lib_libds_tizen_input_devicemgr = shared_library('ds-tizen-input-devicemgr', libds_tizen_input_devicemgr_files, + dependencies: libds_tizen_input_devicemgr_deps, + include_directories: [ common_inc, include_directories('.'), include_directories('..') ], + version: meson.project_version(), + install: true +) + +dep_libds_tizen_input_devicemgr = declare_dependency( + link_with: lib_libds_tizen_input_devicemgr, + dependencies: libds_tizen_input_devicemgr_deps, + include_directories: [ common_inc, include_directories('.') ], +) + +pkgconfig = import('pkgconfig') +pkgconfig.generate(lib_libds_tizen_input_devicemgr, + version: meson.project_version(), + filebase: 'libds-tizen-input-devicemgr', + name: 'libds-tizen-input-devicemgr', + description: 'tizen input devicemgr extension of libds-tizen for tizen platform', +) diff --git a/src/libds-tizen/meson.build b/src/libds-tizen/meson.build index 6779a72..8c7673b 100644 --- a/src/libds-tizen/meson.build +++ b/src/libds-tizen/meson.build @@ -38,4 +38,5 @@ pkgconfig.generate(lib_libds_tizen, ) subdir('keyrouter') +subdir('input-devicemgr') diff --git a/src/libds/backend.c b/src/libds/backend.c index 641374a..dee97ca 100644 --- a/src/libds/backend.c +++ b/src/libds/backend.c @@ -50,9 +50,11 @@ ds_backend_add_new_input_listener(struct ds_backend *backend, void ds_backend_init(struct ds_backend *backend, + struct wl_display *display, const struct ds_backend_interface *iface) { backend->iface = iface; + backend->display = display; wl_signal_init(&backend->events.destroy); wl_signal_init(&backend->events.new_output); wl_signal_init(&backend->events.new_input); diff --git a/src/libds/backend/libinput/backend.c b/src/libds/backend/libinput/backend.c index b6dc4f1..b7e1bc4 100644 --- a/src/libds/backend/libinput/backend.c +++ b/src/libds/backend/libinput/backend.c @@ -25,7 +25,7 @@ ds_libinput_backend_create(struct wl_display *display) return NULL; } - ds_backend_init(&libinput_backend->base, &libinput_backend_interface); + ds_backend_init(&libinput_backend->base, display, &libinput_backend_interface); libinput_backend->display = display; wl_list_init(&libinput_backend->devices); @@ -52,9 +52,7 @@ void destroy_libinput_input_device(struct ds_libinput_input_device *dev) { ds_input_device_destroy(&dev->base); - libinput_device_unref(dev->handle); wl_list_remove(&dev->link); - free(dev); } static void diff --git a/src/libds/backend/libinput/input.c b/src/libds/backend/libinput/input.c index 2457a06..b6e943f 100644 --- a/src/libds/backend/libinput/input.c +++ b/src/libds/backend/libinput/input.c @@ -25,6 +25,8 @@ input_device_iface_destroy(struct ds_input_device *ds_dev) dev = get_libinput_input_device_from_input_device(ds_dev); + libinput_device_unref(dev->handle); + free(dev); } diff --git a/src/libds/backend/wayland/backend.c b/src/libds/backend/wayland/backend.c index 5719e09..fd663f4 100644 --- a/src/libds/backend/wayland/backend.c +++ b/src/libds/backend/wayland/backend.c @@ -33,7 +33,7 @@ ds_wl_backend_create(struct wl_display *display, const char *server_name) return NULL; } - ds_backend_init(&wl_backend->base, &wl_backend_interface); + ds_backend_init(&wl_backend->base, display, &wl_backend_interface); wl_backend->display = display; wl_list_init(&wl_backend->buffers); diff --git a/src/libds/input_device.c b/src/libds/input_device.c index ad18e71..534bced 100644 --- a/src/libds/input_device.c +++ b/src/libds/input_device.c @@ -15,6 +15,12 @@ ds_input_device_get_type(struct ds_input_device *dev) return dev->type; } +WL_EXPORT const char * +ds_input_device_get_name(struct ds_input_device *dev) +{ + return dev->name; +} + WL_EXPORT struct ds_pointer * ds_input_device_get_pointer(struct ds_input_device *dev) { @@ -81,6 +87,9 @@ ds_input_device_destroy(struct ds_input_device *dev) case DS_INPUT_DEVICE_KEYBOARD: ds_keyboard_destroy(dev->keyboard); break; + case DS_INPUT_DEVICE_TOUCH: + ds_touch_destroy(dev->touch); + break; default: ds_err("Warning: leaking memory %p %p %d", dev->_device, dev, dev->type); diff --git a/src/libds/seat/seat_keyboard.c b/src/libds/seat/seat_keyboard.c index 381e2d6..8931a5c 100644 --- a/src/libds/seat/seat_keyboard.c +++ b/src/libds/seat/seat_keyboard.c @@ -362,7 +362,7 @@ seat_client_send_keyboard_leave_raw(struct ds_seat_client *seat_client, struct wl_resource *resource; uint32_t serial; - serial = wl_display_next_serial(seat_client->seat->display); + serial = wl_display_next_serial(wl_client_get_display(seat_client->wl_client)); wl_resource_for_each(resource, &seat_client->keyboards) { wl_keyboard_send_leave(resource, serial, ds_surface_get_wl_resource(surface)); -- 2.7.4