From: SooChan Lim Date: Wed, 6 Jul 2022 05:10:33 +0000 (+0900) Subject: add missing files X-Git-Tag: submit/tizen/20220720.024540~6 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=0f72718246529b64ae641457786f47d3d5c734e3;p=platform%2Fcore%2Fuifw%2Flibds-tizen.git add missing files Change-Id: Ifd75994c3ae705441947e2b225adfb08bacc0466 --- diff --git a/include/libds-tizen/input_devicemgr.h b/include/libds-tizen/input_devicemgr.h new file mode 100644 index 0000000..fc1060e --- /dev/null +++ b/include/libds-tizen/input_devicemgr.h @@ -0,0 +1,44 @@ +#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); + +bool +ds_tizen_input_devicemgr_set_output_width_height( + struct ds_tizen_input_devicemgr *devicemgr, + uint32_t width, uint32_t height); +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/libds-tizen/tbm_server.h b/include/libds-tizen/tbm_server.h new file mode 100644 index 0000000..6e3b148 --- /dev/null +++ b/include/libds-tizen/tbm_server.h @@ -0,0 +1,33 @@ +#ifndef LIBDS_TIZEN_TBM_SERVER_H +#define LIBDS_TIZEN_TBM_SERVER_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct ds_tbm_server; + +struct ds_tbm_client_buffer; + +struct ds_tbm_server * +ds_tbm_server_create(struct wl_display *display); + +void +ds_tbm_server_add_destroy_listener(struct ds_tbm_server *tbm, + struct wl_listener *listener); + +struct ds_tbm_client_buffer * +ds_tbm_client_buffer_from_buffer(struct ds_buffer *ds_buffer); + +tbm_surface_h +ds_tbm_client_buffer_get_tbm_surface(struct ds_tbm_client_buffer *buffer); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/input_devicemgr/input_devicemgr.c b/src/input_devicemgr/input_devicemgr.c new file mode 100644 index 0000000..f690fe7 --- /dev/null +++ b/src/input_devicemgr/input_devicemgr.c @@ -0,0 +1,1551 @@ +#include +#include // gettimeofday() +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "security.h" +#include "input_devicemgr.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" +#define TIZEN_INPUT_DEVICEMGR_MAX_BTN 16 + +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_generate_touch(struct wl_client *client, + struct wl_resource *resource, uint32_t type, uint32_t x, uint32_t y, + uint32_t finger); +static void +device_manager_handle_generate_pointer(struct wl_client *client, + struct wl_resource *resource, uint32_t type, uint32_t x, uint32_t y, + uint32_t button); +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, uint32_t clas, 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_generate_touch_move(struct ds_input_device *device, double x, double y, + uint32_t finger); +static bool +tz_devicemgr_generate_touch_down(struct ds_input_device *device, double x, double y, + uint32_t finger); +static bool +tz_devicemgr_generate_touch_up(struct ds_input_device *device, uint32_t finger); +static bool +tz_devicemgr_generate_mouse_move(struct ds_input_device *device, double x, double y); +static bool +tz_devicemgr_generate_mouse_button(struct ds_input_device *device, uint32_t button, bool state); + +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->devices.ptr = calloc(1, + sizeof(struct ds_tizen_input_devicemgr_device)); + if (!tz_devicemgr->devices.ptr) { + goto err_ptr; + } + tz_devicemgr->devices.touch = calloc(1, + sizeof(struct ds_tizen_input_devicemgr_device)); + if (!tz_devicemgr->devices.touch) { + goto err_touch; + } + tz_devicemgr->touch_max_count = 5;//TODO: make this variable configurable + + tz_devicemgr->grab = ds_seat_create_keyboard_grab( + tz_devicemgr->seat, &devicemgr_keyboard_grab_iface, tz_devicemgr); + if (!tz_devicemgr->grab) { + goto err_grab; + } + + wl_signal_init(&tz_devicemgr->events.destroy); + wl_list_init(&tz_devicemgr->clients); + wl_list_init(&tz_devicemgr->devices.kbd->key.pressed); + 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.touch); +err_touch: + free(tz_devicemgr->devices.ptr); +err_ptr: + 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; +} + +WL_EXPORT bool +ds_tizen_input_devicemgr_set_output_width_height( + struct ds_tizen_input_devicemgr *tz_devicemgr, + uint32_t width, uint32_t height) +{ + if (!tz_devicemgr) return false; + + tz_devicemgr->output.width = width; + tz_devicemgr->output.height = height; + + ds_inf("output's width: %d, height:%d", width, height); + + 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); + ds_seat_keyboard_destroy_grab(tz_devicemgr->grab); + + 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.touch); + free(tz_devicemgr->devices.ptr); + free(tz_devicemgr->devices.kbd); + 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, seat_destroy); + + wl_list_remove(&tz_devicemgr->seat_destroy.link); + wl_list_init(&tz_devicemgr->seat_destroy.link); + tz_devicemgr->seat = NULL; +} + +static void +tz_devicemgr_device_close(struct ds_tizen_input_devicemgr_device *dev) +{ + if (!dev->input_device) return; + ds_input_device_destroy(dev->input_device); + dev->input_device = 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 to dev(%p)", dev); + tz_devicemgr->devices.kbd->input_device = dev; + } + else if (dev_type == DS_INPUT_DEVICE_POINTER) { + if (tz_devicemgr->devices.ptr->input_device) return; + ds_inf("devicemgr's ptr device is set to dev(%p)", dev); + tz_devicemgr->devices.ptr->input_device = dev; + } + else if (dev_type == DS_INPUT_DEVICE_TOUCH) { + if (tz_devicemgr->devices.touch->input_device) return; + ds_inf("devicemgr's touch device is set to dev(%p)", dev); + tz_devicemgr->devices.touch->input_device = dev; + } +} + +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 = device_manager_handle_generate_pointer, + .generate_touch = device_manager_handle_generate_touch, + .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; + } + + ret = tz_devicemgr_init_generator(tz_devicemgr, resource, clas, + "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; + } + + ret = tz_devicemgr_init_generator(tz_devicemgr, resource, clas, + 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 __attribute__((unused))) +{ + 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; + } + + 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 uint32_t +tz_devicemgr_client_get_device_clas(struct ds_tizen_input_devicemgr *tz_devicemgr, + struct wl_resource *resource) +{ + struct ds_tizen_input_devicemgr_client *client_data; + + wl_list_for_each(client_data, &tz_devicemgr->clients, link) { + if (client_data->resource == resource) + return client_data->clas; + } + return 0; +} + +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; + uint32_t clas; + + tz_devicemgr = wl_resource_get_user_data(resource); + + clas = tz_devicemgr_client_get_device_clas(tz_devicemgr, resource); + if ((clas & TIZEN_INPUT_DEVICE_MANAGER_CLAS_KEYBOARD) == 0) + { + ds_err("Keyboard generator is not initialized by client"); + goto finish; + } + + 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_generate_pointer(struct wl_client *client, + struct wl_resource *resource, uint32_t type, uint32_t x, uint32_t y, + uint32_t button) +{ + struct ds_tizen_input_devicemgr *tz_devicemgr; + int ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NO_SYSTEM_RESOURCES; + bool res; + bool state; + uint32_t clas; + + tz_devicemgr = wl_resource_get_user_data(resource); + + clas = tz_devicemgr_client_get_device_clas(tz_devicemgr, resource); + if ((clas & TIZEN_INPUT_DEVICE_MANAGER_CLAS_MOUSE) == 0) + { + ds_err("Pointer generator is not initialized by client"); + goto finish; + } + + if (!tz_devicemgr->devices.ptr || + !tz_devicemgr->devices.ptr->input_device) { + ds_err("Pointer 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; + } + + if (button <= 0 || button >= TIZEN_INPUT_DEVICEMGR_MAX_BTN) + { + ds_err("Invalid button: %d\n", button); + ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_INVALID_PARAMETER; + goto finish; + } + + if (type == TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_UPDATE) { + res = tz_devicemgr_generate_mouse_move( + tz_devicemgr->devices.ptr->input_device, (double)x, (double)y); + if (!res) goto finish; + ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE; + } + else { + state = (type == TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_BEGIN) ? + true : false; + res = tz_devicemgr_generate_mouse_button( + tz_devicemgr->devices.ptr->input_device, button, state); + if (!res) goto finish; + if (state) tz_devicemgr->devices.ptr->mouse.pressed |= 1 << (button - 1); + else tz_devicemgr->devices.ptr->mouse.pressed &= ~(1 << (button - 1)); + ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE; + } + +finish: + tizen_input_device_manager_send_error(resource, ret); +} + +static void +device_manager_handle_generate_touch(struct wl_client *client, + struct wl_resource *resource, uint32_t type, uint32_t x, uint32_t y, + uint32_t finger) +{ + struct ds_tizen_input_devicemgr *tz_devicemgr; + double transformed_x = .0, transformed_y = .0; + int ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NO_SYSTEM_RESOURCES; + bool res; + uint32_t clas; + + tz_devicemgr = wl_resource_get_user_data(resource); + + clas = tz_devicemgr_client_get_device_clas(tz_devicemgr, resource); + if ((clas & TIZEN_INPUT_DEVICE_MANAGER_CLAS_TOUCHSCREEN) == 0) + { + ds_err("Touch generator is not initialized by client"); + goto finish; + } + + if (!tz_devicemgr->devices.touch || + !tz_devicemgr->devices.touch->input_device) { + ds_err("Touch 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; + } + + if (finger >= tz_devicemgr->touch_max_count) + { + ds_err("Invalid fingers: %d\n", finger); + ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_INVALID_PARAMETER; + goto finish; + } + + if (tz_devicemgr->output.width != 0 && tz_devicemgr->output.height != 0) { + transformed_x = x / (double)tz_devicemgr->output.width; + transformed_y = y / (double)tz_devicemgr->output.height; + } + + switch(type) { + case TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_BEGIN: // 0 + res = tz_devicemgr_generate_touch_move( + tz_devicemgr->devices.touch->input_device, transformed_x, transformed_y, finger); + if (!res) break; + res= tz_devicemgr_generate_touch_down( + tz_devicemgr->devices.touch->input_device, transformed_x, transformed_y, finger); + if (!res) break; + tz_devicemgr->devices.touch->touch.pressed |= 1 << finger; + ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE; + break; + case TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_END: // 2 + res = tz_devicemgr_generate_touch_up( + tz_devicemgr->devices.touch->input_device, finger); + if (!res) break; + tz_devicemgr->devices.touch->touch.pressed &= ~(1 << finger); + ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE; + break; + case TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_UPDATE: // 1 + res = tz_devicemgr_generate_touch_move( + tz_devicemgr->devices.touch->input_device, transformed_x, transformed_y, finger); + if (!res) break; + ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE; + break; + default: + break; + } + +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 struct ds_pointer * +create_ds_pointer() +{ + struct ds_pointer *pointer; + pointer = calloc(1, sizeof *pointer); + if (!pointer) { + ds_err("Could not allocate memory"); + return NULL; + } + ds_pointer_init(pointer, NULL); + + return pointer; +} + +static struct ds_touch * +create_ds_touch() +{ + struct ds_touch *touch; + touch = calloc(1, sizeof *touch); + if (!touch) { + ds_err("Could not allocate memory"); + return NULL; + } + ds_touch_init(touch, NULL); + + return touch; +} + +static int +tz_devicemgr_create_device(struct ds_tizen_input_devicemgr_device *dev, + uint32_t clas, const char *name) +{ + int ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NO_SYSTEM_RESOURCES; + const char *dev_name; + + if (dev->name && strlen(dev->name) > 0) { + ds_inf("device already has name. name:%s", dev->name); + return TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE; + } + + if (dev->input_device) { + dev_name = ds_input_device_get_name(dev->input_device); + ds_inf("device was already set. name:%s", dev_name); + dev->name = strdup(dev_name); + return TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE; + } + + //input_device create + dev->input_device = calloc(1, sizeof(struct ds_input_device)); + if(!dev->input_device) { + ds_err("Failed to create input device !\n"); + return ret; + } + + if (clas & TIZEN_INPUT_DEVICE_MANAGER_CLAS_KEYBOARD) + { + ds_input_device_init(dev->input_device, DS_INPUT_DEVICE_KEYBOARD, + &input_device_iface, name, -1, -1); + dev->input_device->keyboard = create_ds_keyboard(); + } + else if (clas & TIZEN_INPUT_DEVICE_MANAGER_CLAS_MOUSE) + { + ds_input_device_init(dev->input_device, DS_INPUT_DEVICE_POINTER, + &input_device_iface, name, -1, -1); + dev->input_device->pointer = create_ds_pointer(); + } + else if (clas & TIZEN_INPUT_DEVICE_MANAGER_CLAS_TOUCHSCREEN) + { + ds_input_device_init(dev->input_device, DS_INPUT_DEVICE_TOUCH, + &input_device_iface, name, -1, -1); + dev->input_device->touch = create_ds_touch(); + } + + dev->created = true; + dev->name = strdup(name); + + return TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE; +} + +static int +tz_devicemgr_init_generator(struct ds_tizen_input_devicemgr *tz_devicemgr, + struct wl_resource *resource, uint32_t clas, 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 *dev; + bool inited = false; + + ds_inf("Init generator. name:%s", name); + + if (clas & TIZEN_INPUT_DEVICE_MANAGER_CLAS_KEYBOARD) { + dev = tz_devicemgr->devices.kbd; + ret = tz_devicemgr_create_device(dev, clas, name); + if (ret == TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE) { + inited = true; + tz_devicemgr->devices.kbd->ref++; + } + if (dev->created) { + wl_signal_emit(&tz_devicemgr->backend->events.new_input, + dev->input_device); + } + } + if (clas & TIZEN_INPUT_DEVICE_MANAGER_CLAS_MOUSE) { + dev = tz_devicemgr->devices.ptr; + ret = tz_devicemgr_create_device(dev, clas, name); + if (ret == TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE) { + inited = true; + tz_devicemgr->devices.ptr->ref++; + } + if (dev->created) { + wl_signal_emit(&tz_devicemgr->backend->events.new_input, + dev->input_device); + } + } + if (clas & TIZEN_INPUT_DEVICE_MANAGER_CLAS_TOUCHSCREEN) { + dev = tz_devicemgr->devices.touch; + ret = tz_devicemgr_create_device(dev, clas, name); + if (ret == TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE) { + inited = true; + tz_devicemgr->devices.touch->ref++; + } + if (dev->created) { + wl_signal_emit(&tz_devicemgr->backend->events.new_input, + dev->input_device); + } + } + + if (inited) { + wl_list_for_each(client_data, &tz_devicemgr->clients, link) { + if (client_data->resource == resource) { + if (client_data->init == false) { + client_data->init = true; + client_data->clas = clas; + } + break; + } + } + } + + return ret; +} + +static int +tz_devicemgr_deinit_generator(struct ds_tizen_input_devicemgr *tz_devicemgr, + struct wl_resource *resource) +{ + int ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NO_SYSTEM_RESOURCES; + struct ds_tizen_input_devicemgr_client *client_data; + struct ds_tizen_input_devicemgr_device *dev; + uint32_t clas = 0; + int i = 0; + bool res; + + 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; + clas = client_data->clas; + break; + } else { + return ret; + } + } + } + if (clas & TIZEN_INPUT_DEVICE_MANAGER_CLAS_KEYBOARD) { + dev = tz_devicemgr->devices.kbd; + dev->ref--; + if (dev->ref<= 0) { + dev->ref = 0; + tz_devicemgr_pressed_keys_cleanup(tz_devicemgr); + + if (dev->created) { + tz_devicemgr_device_close(dev); + dev->created = false; + } + free(dev->name); + dev->name = NULL; + } + } + if (clas & TIZEN_INPUT_DEVICE_MANAGER_CLAS_MOUSE) { + dev = tz_devicemgr->devices.ptr; + dev->ref--; + if (dev->ref <= 0) { + dev->ref = 0; + while(dev->mouse.pressed) + { + if (dev->mouse.pressed & (1 << i)) + { + res = tz_devicemgr_generate_mouse_button(dev->input_device, + i + 1, false); + if (!res) break; + dev->mouse.pressed &= ~(1 << i); + } + i++; + if (i >= TIZEN_INPUT_DEVICEMGR_MAX_BTN) break; + } + + if (dev->created) + { + tz_devicemgr_device_close(dev); + dev->created = false; + } + free(dev->name); + dev->name = NULL; + } + } + if (clas & TIZEN_INPUT_DEVICE_MANAGER_CLAS_TOUCHSCREEN) { + dev = tz_devicemgr->devices.touch; + dev->ref--; + if (dev->ref <= 0) { + dev->ref = 0; + while(dev->touch.pressed) + { + if (dev->touch.pressed & (1 << i)) + { + res = tz_devicemgr_generate_touch_up(dev->input_device, + i); + if (!res) break; + dev->touch.pressed &= ~(1 << i); + } + i++; + if (i >= tz_devicemgr->touch_max_count) break; + } + + if (dev->created) + { + tz_devicemgr_device_close(dev); + dev->created = false; + } + free(dev->name); + dev->name = NULL; + } + } + + return TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE; +} + +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->devices.kbd->key.pressed, &key->link); + } + else { + wl_list_for_each_safe(key, tmp, &tz_devicemgr->devices.kbd->key.pressed, 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->devices.kbd->key.pressed), 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 kbd.pressed_keys. length: %d", + wl_list_length(&tz_devicemgr->devices.kbd->key.pressed)); + + wl_list_for_each_safe(keydata, tmp, &tz_devicemgr->devices.kbd->key.pressed, 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 bool +tz_devicemgr_generate_touch_move(struct ds_input_device *device, double x, double y, + uint32_t finger) +{ + struct ds_event_touch_motion ds_event; + struct timeval time; + unsigned int timestamp; + struct ds_touch *touch; + + touch = ds_input_device_get_touch(device); + if (!touch) { + ds_err("No ds_touch to notify event"); + return false; + } + + gettimeofday(&time, NULL); + timestamp = time.tv_sec * 1000 + time.tv_usec / 1000; + + ds_event.time_msec = timestamp; + ds_event.id = finger; + ds_event.x = x; + ds_event.y = y; + ds_inf("Generate touch motion. touch:%p, id:%d (%d, %d)", touch, ds_event.id, x, y); + + wl_signal_emit(&touch->events.motion, &ds_event); + + return true; +} + +static bool +tz_devicemgr_generate_touch_down(struct ds_input_device *device, double x, double y, + uint32_t finger) +{ + struct ds_event_touch_down ds_event; + struct timeval time; + unsigned int timestamp; + struct ds_touch *touch; + + touch = ds_input_device_get_touch(device); + if (!touch) { + ds_err("No ds_touch to notify event"); + return false; + } + + gettimeofday(&time, NULL); + timestamp = time.tv_sec * 1000 + time.tv_usec / 1000; + + ds_event.time_msec = timestamp; + ds_event.id = finger; + ds_event.x = x; + ds_event.y = y; + ds_inf("Generate touch down. touch:%p, id:%d (%d, %d)", touch, ds_event.id, x, y); + + wl_signal_emit(&touch->events.down, &ds_event); + + return true; +} + +static bool +tz_devicemgr_generate_touch_up(struct ds_input_device *device, uint32_t finger) +{ + struct ds_event_touch_up ds_event; + struct timeval time; + unsigned int timestamp; + struct ds_touch *touch; + + touch = ds_input_device_get_touch(device); + if (!touch) { + ds_err("No ds_touch to notify event"); + return false; + } + + gettimeofday(&time, NULL); + timestamp = time.tv_sec * 1000 + time.tv_usec / 1000; + + ds_event.time_msec = timestamp; + ds_event.id = finger; + ds_inf("Generate touch up. touch:%p, id:%d", touch, ds_event.id); + + wl_signal_emit(&touch->events.up, &ds_event); + + return true; +} + +static bool +tz_devicemgr_generate_mouse_move(struct ds_input_device *device, double x, double y) +{ + struct ds_event_pointer_motion ds_event; + struct timeval time; + unsigned int timestamp; + struct ds_pointer *pointer; + + pointer = ds_input_device_get_pointer(device); + if (!pointer) { + ds_err("No ds_pointer to notify event"); + return false; + } + + gettimeofday(&time, NULL); + timestamp = time.tv_sec * 1000 + time.tv_usec / 1000; + + ds_event.time_msec = timestamp; + ds_event.delta_x = x; + ds_event.delta_y = y; + ds_inf("Generate mouse motion. pointer:%p, x:%f, y:%f", pointer, ds_event.delta_x, ds_event.delta_y); + + wl_signal_emit(&pointer->events.motion, &ds_event); + + return true; +} + +static bool +tz_devicemgr_generate_mouse_button(struct ds_input_device *device, uint32_t button, bool state) +{ + struct ds_event_pointer_button ds_event; + struct timeval time; + unsigned int timestamp; + struct ds_pointer *pointer; + + pointer = ds_input_device_get_pointer(device); + if (!pointer) { + ds_err("No ds_pointer to notify event"); + return false; + } + + gettimeofday(&time, NULL); + timestamp = time.tv_sec * 1000 + time.tv_usec / 1000; + + ds_event.time_msec = timestamp; + ds_event.button = button; + if (state) + ds_event.state = DS_BUTTON_PRESSED; + else + ds_event.state = DS_BUTTON_RELEASED; + ds_inf("Generate mouse button. pointer:%p, button:%d, state:%s", pointer, ds_event.button, state ? "PRESSED" : "RELEASED"); + + wl_signal_emit(&pointer->events.button, &ds_event); + + return true; +} + +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; + struct ds_tizen_input_devicemgr_key_info *keydata, *tmp; + bool key_blocked = false; + + ds_inf("devicemgr. keyboard_grab_iface_key"); + + devicemgr = ds_seat_keyboard_grab_get_data(grab); + 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); +} + diff --git a/src/input_devicemgr/input_devicemgr.h b/src/input_devicemgr/input_devicemgr.h new file mode 100644 index 0000000..a4428ee --- /dev/null +++ b/src/input_devicemgr/input_devicemgr.h @@ -0,0 +1,78 @@ +#ifndef DS_TIZEN_DEVICEMGR_H +#define DS_TIZEN_DEVICEMGR_H + +#include +#include +#include +#include +#include +#include + +struct ds_tizen_input_devicemgr_device { + char *name; + struct ds_input_device *input_device; + int ref; + + bool created; + + struct { + struct wl_list pressed; + } key; + + struct { + unsigned int pressed; + } touch; + + struct { + unsigned int pressed; + } mouse; +}; + +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; + + 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; + int touch_max_count; + + struct { + uint32_t width; + uint32_t height; + } output; +}; + +struct ds_tizen_input_devicemgr_client { + struct wl_resource *resource; + bool init; + uint32_t clas; + 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/input_devicemgr/meson.build b/src/input_devicemgr/meson.build new file mode 100644 index 0000000..ea8a94f --- /dev/null +++ b/src/input_devicemgr/meson.build @@ -0,0 +1,32 @@ +libds_tizen_input_devicemgr_files = [ + tizen_security_files, + 'input_devicemgr.c', +] + +libds_tizen_input_devicemgr_deps = [ + deps_libds_tizen, + deps_tizen_security, + dependency('tizen-extension-server', required: true), + dependency('xkbcommon', 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 +) + +deps_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/tbm_server/meson.build b/src/tbm_server/meson.build new file mode 100644 index 0000000..795576a --- /dev/null +++ b/src/tbm_server/meson.build @@ -0,0 +1,32 @@ +libds_tizen_tbm_server_files = [ + 'pixel_format.c', + 'tbm_server.c', +] + +libds_tizen_tbm_server_deps = [ + deps_libds_tizen, + dependency('libdrm', required: true), + dependency('libtbm', required: true), + dependency('wayland-tbm-server', required: true), +] + +lib_libds_tizen_tbm_server = shared_library('ds-tizen-tbm-server', libds_tizen_tbm_server_files, + dependencies: libds_tizen_tbm_server_deps, + include_directories: [ common_inc, include_directories('.'), include_directories('..') ], + version: meson.project_version(), + install: true +) + +deps_libds_tizen_tbm_server = declare_dependency( + link_with: lib_libds_tizen_tbm_server, + dependencies: libds_tizen_tbm_server_deps, + include_directories: [ common_inc, include_directories('.') ], +) + +pkgconfig = import('pkgconfig') +pkgconfig.generate(lib_libds_tizen_tbm_server, + version: meson.project_version(), + filebase: 'libds-tizen-tbm-server', + name: 'libds-tizen-tbm-server', + description: 'wayland-tbm extension of libds-tizen for tizen platform', +) diff --git a/src/tbm_server/pixel_format.c b/src/tbm_server/pixel_format.c new file mode 100644 index 0000000..030f211 --- /dev/null +++ b/src/tbm_server/pixel_format.c @@ -0,0 +1,61 @@ +#include +#include +#include + +#include +#include "pixel_format.h" + +#ifdef ARRAY_LENGTH +#undef ARRAY_LENGTH +#endif + +#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) + +struct ds_tbm_format +{ + uint32_t drm_format; + uint32_t tbm_format; +}; + +static const struct ds_tbm_format formats[] = +{ + { + .drm_format = DRM_FORMAT_ARGB8888, + .tbm_format = TBM_FORMAT_ARGB8888, + }, + { + .drm_format = DRM_FORMAT_XRGB8888, + .tbm_format = TBM_FORMAT_XRGB8888, + }, + /* TODO more format */ +}; + +uint32_t +convert_drm_format_to_tbm(uint32_t fmt) +{ + size_t i; + + for (i = 0; i < ARRAY_LENGTH(formats); i++) { + if (formats[i].drm_format == fmt) + return formats[i].tbm_format; + } + + ds_err("DRM format 0x%"PRIX32" has no TBM equivalent", fmt); + + return 0; +} + +uint32_t +convert_tbm_format_to_drm(uint32_t fmt) +{ + size_t i; + + for (i = 0; i < ARRAY_LENGTH(formats); i++) { + if (formats[i].tbm_format == fmt) + return formats[i].drm_format; + } + + ds_err("TBM format 0x%"PRIX32" has no DRM equivalent", fmt); + + return 0; +} diff --git a/src/tbm_server/pixel_format.h b/src/tbm_server/pixel_format.h new file mode 100644 index 0000000..a63d096 --- /dev/null +++ b/src/tbm_server/pixel_format.h @@ -0,0 +1,10 @@ +#ifndef DS_TIZEN_PIXEL_FORMAT_H +#define DS_TIZEN_PIXEL_FORMAT_H + +#include + +uint32_t convert_drm_format_to_tbm(uint32_t fmt); + +uint32_t convert_tbm_format_to_drm(uint32_t fmt); + +#endif diff --git a/src/tbm_server/tbm_server.c b/src/tbm_server/tbm_server.c new file mode 100644 index 0000000..0fd25cd --- /dev/null +++ b/src/tbm_server/tbm_server.c @@ -0,0 +1,268 @@ +#include +#include +#include + +#include + +#include +#include "pixel_format.h" +#include "tbm_server.h" + +static const struct ds_buffer_resource_interface tbm_buffer_resource_iface; +static const struct ds_buffer_interface tbm_client_buffer_iface; + +static void tbm_server_handle_display_destroy(struct wl_listener *listener, + void *data); + +WL_EXPORT struct ds_tbm_server * +ds_tbm_server_create(struct wl_display *display) +{ + struct ds_tbm_server *tbm; + tbm_bufmgr bufmgr; + + tbm = calloc(1, sizeof *tbm); + if (!tbm) + return NULL; + + wl_signal_init(&tbm->events.destroy); + + tbm->wl_tbm = wayland_tbm_server_init(display, NULL, -1, 0); + if (!tbm->wl_tbm) { + goto err_wl_tbm; + } + + bufmgr = wayland_tbm_server_get_bufmgr(tbm->wl_tbm); + if (!bufmgr) { + goto err_bind; + } + + if (!tbm_bufmgr_bind_native_display(bufmgr, (void *)display)) { + goto err_bind; + } + + tbm->display_destroy.notify = tbm_server_handle_display_destroy; + wl_display_add_destroy_listener(display, &tbm->display_destroy); + + ds_buffer_register_resource_interface(&tbm_buffer_resource_iface); + + return tbm; + +err_bind: + wayland_tbm_server_deinit(tbm->wl_tbm); +err_wl_tbm: + free(tbm); + + return NULL; +} + +WL_EXPORT void +ds_tbm_server_add_destroy_listener(struct ds_tbm_server *tbm, + struct wl_listener *listener) +{ + wl_signal_add(&tbm->events.destroy, listener); +} + +WL_EXPORT struct ds_tbm_client_buffer * +ds_tbm_client_buffer_from_buffer(struct ds_buffer *ds_buffer) +{ + if (ds_buffer->iface != &tbm_client_buffer_iface) + return NULL; + return (struct ds_tbm_client_buffer *)ds_buffer; +} + +WL_EXPORT tbm_surface_h +ds_tbm_client_buffer_get_tbm_surface(struct ds_tbm_client_buffer *buffer) +{ + if (buffer->base.iface != &tbm_client_buffer_iface) + return NULL; + return buffer->surface; +} + +static void +tbm_server_handle_display_destroy(struct wl_listener *listener, void *data) +{ + struct ds_tbm_server *tbm; + + tbm = wl_container_of(listener, tbm, display_destroy); + + wl_signal_emit(&tbm->events.destroy, tbm); + + wayland_tbm_server_deinit(tbm->wl_tbm); + free(tbm); +} + +static void +tbm_client_buffer_handle_release(struct wl_listener *listener, void *data) +{ + struct ds_tbm_client_buffer *buffer; + + buffer = wl_container_of(listener, buffer, buffer_release); + if (buffer->resource) + wl_buffer_send_release(buffer->resource); +} + +static void +tbm_client_buffer_handle_resource_destroy(struct wl_listener *listener, + void *data) +{ + struct ds_tbm_client_buffer *buffer; + + buffer = wl_container_of(listener, buffer, resource_destroy); + + buffer->resource = NULL; + buffer->surface = NULL; + wl_list_remove(&buffer->resource_destroy.link); + wl_list_init(&buffer->resource_destroy.link); + + ds_buffer_drop(&buffer->base); +} + +static struct ds_tbm_client_buffer * +tbm_client_buffer_from_buffer(struct ds_buffer *ds_buffer) +{ + assert(ds_buffer->iface == &tbm_client_buffer_iface); + return (struct ds_tbm_client_buffer *)ds_buffer; +} + +static void +tbm_client_buffer_iface_destroy(struct ds_buffer *ds_buffer) +{ + struct ds_tbm_client_buffer *buffer; + + buffer = tbm_client_buffer_from_buffer(ds_buffer); + + ds_inf("Destroy TBM client buffer(%p)", buffer); + + wl_list_remove(&buffer->resource_destroy.link); + wl_list_remove(&buffer->buffer_release.link); + free(buffer); +} + +static bool +tbm_client_buffer_iface_begin_data_ptr_access(struct ds_buffer *ds_buffer, + enum ds_buffer_data_ptr_access_flag flags, void **data, + uint32_t *format, size_t *stride) +{ + struct ds_tbm_client_buffer *buffer; + tbm_surface_info_s info; + tbm_bo_access_option op = TBM_OPTION_NONE; + int err; + + buffer = tbm_client_buffer_from_buffer(ds_buffer); + + if (flags & DS_BUFFER_DATA_PTR_ACCESS_READ) + op |= TBM_OPTION_READ; + + if (flags & DS_BUFFER_DATA_PTR_ACCESS_WRITE) + op |= TBM_OPTION_WRITE; + + err = tbm_surface_map(buffer->surface, op, &info); + if (err != TBM_SURFACE_ERROR_NONE) { + ds_err("Failed tbm_surface_map()"); + return false; + } + + *format = convert_tbm_format_to_drm(buffer->format); + *stride = info.planes[0].stride; + *data = info.planes[0].ptr; + + return true; +} + +static void +tbm_client_buffer_iface_end_ptr_access(struct ds_buffer *ds_buffer) +{ + struct ds_tbm_client_buffer *buffer; + + buffer = tbm_client_buffer_from_buffer(ds_buffer); + + tbm_surface_unmap(buffer->surface); +} + +static const struct ds_buffer_interface tbm_client_buffer_iface = { + .destroy = tbm_client_buffer_iface_destroy, + .begin_data_ptr_access = tbm_client_buffer_iface_begin_data_ptr_access, + .end_data_ptr_access = tbm_client_buffer_iface_end_ptr_access, +}; + +static struct ds_tbm_client_buffer * +tbm_client_buffer_create(struct wl_resource *resource) +{ + struct ds_tbm_client_buffer *buffer; + tbm_surface_h surface; + int32_t width, height; + + surface = wayland_tbm_server_get_surface(NULL, resource); + if (!surface) { + ds_err("Could not get tbm_surface from wl_resource@%d", + wl_resource_get_id(resource)); + return NULL; + } + + width = tbm_surface_get_width(surface); + height = tbm_surface_get_height(surface); + + buffer = calloc(1, sizeof *buffer); + if (!buffer) + return NULL; + + ds_buffer_init(&buffer->base, &tbm_client_buffer_iface, width, height); + + buffer->resource = resource; + buffer->surface = surface; + buffer->format = tbm_surface_get_format(surface); + + buffer->buffer_release.notify = tbm_client_buffer_handle_release; + ds_buffer_add_release_listener(&buffer->base, &buffer->buffer_release); + + buffer->resource_destroy.notify = + tbm_client_buffer_handle_resource_destroy; + wl_resource_add_destroy_listener(resource, &buffer->resource_destroy); + + ds_inf("TBM client buffer(%p) created", buffer); + + return buffer; +} + +static struct ds_tbm_client_buffer * +tbm_client_buffer_get_or_create(struct wl_resource *resource) +{ + struct ds_tbm_client_buffer *buffer; + struct wl_listener *resource_destroy_listener; + + resource_destroy_listener = wl_resource_get_destroy_listener(resource, + tbm_client_buffer_handle_resource_destroy);; + if (resource_destroy_listener) { + buffer = wl_container_of(resource_destroy_listener, + buffer, resource_destroy); + return buffer; + } + + return tbm_client_buffer_create(resource); +} + +static bool +tbm_buffer_resource_iface_is_instance(struct wl_resource *resource) +{ + return !!wayland_tbm_server_get_surface(NULL, resource); +} + +static struct ds_buffer * +tbm_buffer_resource_iface_from_resource(struct wl_resource *resource) +{ + struct ds_tbm_client_buffer *buffer; + + buffer = tbm_client_buffer_get_or_create(resource); + if (!buffer) { + ds_err("Could not get or create ds_tbm_client_buffer"); + return NULL; + } + + return &buffer->base; +} + +static const struct ds_buffer_resource_interface tbm_buffer_resource_iface = { + .name = "tbm", + .is_instance = tbm_buffer_resource_iface_is_instance, + .from_resource = tbm_buffer_resource_iface_from_resource, +}; diff --git a/src/tbm_server/tbm_server.h b/src/tbm_server/tbm_server.h new file mode 100644 index 0000000..58e391b --- /dev/null +++ b/src/tbm_server/tbm_server.h @@ -0,0 +1,34 @@ +#ifndef DS_TIZEN_TBM_SERVER_H +#define DS_TIZEN_TBM_SERVER_H + +#include +#include +#include +#include + +struct ds_tbm_server +{ + struct wayland_tbm_server *wl_tbm; + + struct wl_listener display_destroy; + + struct { + struct wl_signal destroy; + } events; +}; + +struct ds_tbm_client_buffer +{ + struct ds_buffer base; + + tbm_surface_h surface; + struct wl_resource *resource; + + struct wl_listener buffer_release; + struct wl_listener resource_destroy; + + uint32_t format; + size_t stride; +}; + +#endif diff --git a/tests/test_backend.c b/tests/test_backend.c new file mode 100644 index 0000000..69417b6 --- /dev/null +++ b/tests/test_backend.c @@ -0,0 +1,80 @@ +#include +#include +#include + +#include +#include + +static struct ds_backend * +create_possible_wl_backend(struct wl_display *display) +{ + struct ds_backend *backend; + char wl_name[512]; + + for (int i = 0; i < 5; i++) { + snprintf(wl_name, sizeof wl_name, "wayland-%d", i); + backend = ds_wl_backend_create(display, wl_name); + if (backend) + break; + } + + return backend; +} + +static void +test_wl_backend_create(void) +{ + struct wl_display *display; + struct ds_backend *backend; + + display = wl_display_create(); + + backend = create_possible_wl_backend(display); + assert(backend); + + ds_backend_destroy(backend); +} + +struct test +{ + struct wl_listener backend_destroy; + bool cb_called; +}; + +static void +cb_backend_destroy(struct wl_listener *listener, void *data) +{ + struct test *test; + + test = wl_container_of(listener, test, backend_destroy); + test->cb_called = true; +} + +static void +test_wl_backend_destroy_signal(void) +{ + struct wl_display *display; + struct ds_backend *backend; + struct test test; + + display = wl_display_create(); + + backend = create_possible_wl_backend(display); + assert(backend); + + test.cb_called = false; + test.backend_destroy.notify = cb_backend_destroy; + ds_backend_add_destroy_listener(backend, &test.backend_destroy); + + wl_display_destroy(display); + assert(test.cb_called); +} + +int +main(void) +{ + test_wl_backend_create(); + test_wl_backend_destroy_signal(); + + return 0; +} diff --git a/tests/test_compositor.c b/tests/test_compositor.c new file mode 100644 index 0000000..b5883a5 --- /dev/null +++ b/tests/test_compositor.c @@ -0,0 +1,63 @@ +#include +#include + +#include +#include +#include + +static void +test_compositor_create(void) +{ + struct wl_display *display; + struct ds_compositor *compositor; + + display = wl_display_create(); + compositor = ds_compositor_create(display); + assert(compositor); + + wl_display_destroy(display); +} + +struct test +{ + struct wl_listener compositor_destroy; + bool destroyed; +}; + +static void +cb_compositor_destroy(struct wl_listener *listener, void *data) +{ + struct test *test; + + test = wl_container_of(listener, test, compositor_destroy); + test->destroyed = true; +} + +static void +test_compositor_destroy_signal(void) +{ + struct wl_display *display; + struct ds_compositor *compositor; + struct test test; + + display = wl_display_create(); + compositor = ds_compositor_create(display); + assert(compositor); + + test.destroyed = false; + test.compositor_destroy.notify = cb_compositor_destroy; + ds_compositor_add_destroy_listener(compositor, + &test.compositor_destroy); + + wl_display_destroy(display); + assert(test.destroyed == true); +} + +int +main(void) +{ + test_compositor_create(); + test_compositor_destroy_signal(); + + return 0; +} diff --git a/tests/test_subsurface.c b/tests/test_subsurface.c new file mode 100644 index 0000000..98e830d --- /dev/null +++ b/tests/test_subsurface.c @@ -0,0 +1,211 @@ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +struct server_base +{ + struct wl_display *display; + struct ds_compositor *compositor; + const char *socket; +}; + +const char * +test_server_init(struct server_base *server) +{ + server->display = wl_display_create(); + assert(server->display); + server->compositor = ds_compositor_create(server->display); + assert(server->compositor); + server->socket = wl_display_add_socket_auto(server->display); + assert(server->socket); + + return server->socket; +} + +void +test_server_finish(struct server_base *server) +{ + wl_display_destroy(server->display); +} + +struct client +{ + struct wl_display *display; + struct wl_registry *registry; + struct wl_compositor *compositor; + struct wl_subcompositor *subcompositor; + struct wl_surface *surface; + struct wl_subsurface *subsurface; +}; + +static void +handle_global(void *data, struct wl_registry *registry, uint32_t id, + const char *interface, uint32_t version) +{ + struct client *client = data; + + if (strcmp(interface, "wl_compositor") == 0) { + client->compositor = + wl_registry_bind(registry, id, &wl_compositor_interface, version); + } + else if (strcmp(interface, "wl_subcompositor") == 0) { + client->subcompositor = + wl_registry_bind(registry, id, &wl_subcompositor_interface, version); + } +} + +static const struct wl_registry_listener registry_listener = { + .global = handle_global, +}; + +void +test_client_init(struct client *client, const char *name) +{ + client->display = wl_display_connect(name); + assert(client->display); + client->registry = wl_display_get_registry(client->display); + assert(client->registry); + + wl_registry_add_listener(client->registry, ®istry_listener, client); + + wl_display_roundtrip(client->display); + + assert(client->compositor); + assert(client->subcompositor); +} + +void +test_client_finish(struct client *client) +{ + wl_subcompositor_destroy(client->subcompositor); + wl_compositor_destroy(client->compositor); + wl_registry_destroy(client->registry); + wl_display_disconnect(client->display); +} + +struct test_server +{ + struct server_base base; + bool cb_called; + + struct wl_listener new_surface; + struct wl_listener new_subsurface1; + struct wl_listener new_subsurface2; +}; + +static void +cb_new_subsurface1(struct wl_listener *listener, void *data) +{ + struct ds_subsurface *subsurface = data; + struct test_server *server; + + assert(subsurface); + + server = wl_container_of(listener, server, new_subsurface1); + server->cb_called = true; + wl_display_terminate(server->base.display); +} + +static void +cb_new_subsurface2(struct wl_listener *listener, void *data) +{ + struct ds_subsurface *subsurface = data; + struct test_server *server; + + assert(subsurface); + + server = wl_container_of(listener, server, new_subsurface2); + server->cb_called = true; + wl_display_terminate(server->base.display); +} + +static void +cb_new_surface(struct wl_listener *listener, void *data) +{ + struct ds_surface *surface = data; + struct test_server *server; + + server = wl_container_of(listener, server, new_surface); + if (!server->new_subsurface1.notify) { + server->new_subsurface1.notify = cb_new_subsurface1; + ds_surface_add_new_subsurface_listener(surface, + &server->new_subsurface1); + } + else { + server->new_subsurface2.notify = cb_new_subsurface2; + ds_surface_add_new_subsurface_listener(surface, + &server->new_subsurface2); + } +} + +static void +run_client(const char *name) +{ + struct client client; + + test_client_init(&client, name); + + struct wl_surface *surface = + wl_compositor_create_surface(client.compositor); + + struct wl_surface *child_surface = + wl_compositor_create_surface(client.compositor); + + struct wl_subsurface *subsurface = + wl_subcompositor_get_subsurface(client.subcompositor, + child_surface, surface); + + wl_display_roundtrip(client.display); + + wl_subsurface_destroy(subsurface); + wl_surface_destroy(child_surface); + wl_surface_destroy(surface); + + test_client_finish(&client); +} + +static void +test_subsurface_create(void) +{ + struct test_server server = { + .new_subsurface1 = { .notify = NULL }, + .cb_called = false + }; + pid_t pid; + + const char *socket_name = test_server_init(&server.base); + + pid = fork(); + assert(pid != -1); + + if (pid == 0) { + run_client(socket_name); + exit(0); + } + + server.new_surface.notify = cb_new_surface; + ds_compositor_add_new_surface_listener(server.base.compositor, + &server.new_surface); + + wl_display_run(server.base.display); + + assert(server.cb_called); + + test_server_finish(&server.base); +} + +int +main(void) +{ + test_subsurface_create(); + return 0; +} diff --git a/tests/test_surface.c b/tests/test_surface.c new file mode 100644 index 0000000..eab2b77 --- /dev/null +++ b/tests/test_surface.c @@ -0,0 +1,162 @@ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +struct server_base +{ + struct wl_display *display; + struct ds_compositor *compositor; + const char *socket; +}; + +void +test_server_init(struct server_base *server) +{ + server->display = wl_display_create(); + assert(server->display); + server->compositor = ds_compositor_create(server->display); + assert(server->compositor); + server->socket = wl_display_add_socket_auto(server->display); + assert(server->socket); +} + +void +test_server_finish(struct server_base *server) +{ + wl_display_destroy(server->display); +} + +struct client +{ + struct wl_display *display; + struct wl_registry *registry; + struct wl_compositor *compositor; + struct wl_surface *surface; +}; + +static void +handle_global(void *data, struct wl_registry *registry, uint32_t id, + const char *interface, uint32_t version) +{ + struct client *client = data; + + if (strcmp(interface, "wl_compositor") == 0) { + client->compositor = + wl_registry_bind(registry, id, &wl_compositor_interface, version); + } +} + +static const struct wl_registry_listener registry_listener = { + .global = handle_global, +}; + +void +test_client_init(struct client *client, const char *name) +{ + client->display = wl_display_connect(name); + assert(client->display); + client->registry = wl_display_get_registry(client->display); + assert(client->registry); + + wl_registry_add_listener(client->registry, ®istry_listener, client); + + wl_display_roundtrip(client->display); + + assert(client->compositor); +} + +void +test_client_finish(struct client *client) +{ + wl_compositor_destroy(client->compositor); + wl_registry_destroy(client->registry); + wl_display_disconnect(client->display); +} + +struct test_server { + struct server_base base; + bool cb_called; + + struct wl_listener new_surface; + struct wl_listener surface_destroy; +}; + +static void +cb_surface_destroy(struct wl_listener *listener, void *data) +{ + struct test_server *server; + + server = wl_container_of(listener, server, surface_destroy); + server->cb_called = true; + wl_display_terminate(server->base.display); +} + +static void +cb_new_surface(struct wl_listener *listener, void *data) +{ + struct ds_surface *surface = data; + struct test_server *server; + + server = wl_container_of(listener, server, new_surface); + server->surface_destroy.notify = cb_surface_destroy; + ds_surface_add_destroy_listener(surface, &server->surface_destroy); +} + +static void +run_client(const char *name) +{ + struct client client; + + test_client_init(&client, name); + + struct wl_surface *surface = + wl_compositor_create_surface(client.compositor); + + wl_display_roundtrip(client.display); + + wl_surface_destroy(surface); + + test_client_finish(&client); +} + +static void +test_surface_create_and_destroy(void) +{ + struct test_server server = { .cb_called = false }; + pid_t pid; + + test_server_init(&server.base); + + pid = fork(); + assert(pid != -1); + + if (pid == 0) { + run_client(server.base.socket); + exit(0); + } + + server.new_surface.notify = cb_new_surface; + ds_compositor_add_new_surface_listener(server.base.compositor, + &server.new_surface); + + wl_display_run(server.base.display); + + assert(server.cb_called); + + test_server_finish(&server.base); +} + +int +main(void) +{ + test_surface_create_and_destroy(); + return 0; +}