add missing files 41/278241/1
authorSooChan Lim <sc1.lim@samsung.com>
Wed, 6 Jul 2022 05:10:33 +0000 (14:10 +0900)
committerSooChan Lim <sc1.lim@samsung.com>
Mon, 18 Jul 2022 05:59:16 +0000 (14:59 +0900)
Change-Id: Ifd75994c3ae705441947e2b225adfb08bacc0466

14 files changed:
include/libds-tizen/input_devicemgr.h [new file with mode: 0644]
include/libds-tizen/tbm_server.h [new file with mode: 0644]
src/input_devicemgr/input_devicemgr.c [new file with mode: 0644]
src/input_devicemgr/input_devicemgr.h [new file with mode: 0644]
src/input_devicemgr/meson.build [new file with mode: 0644]
src/tbm_server/meson.build [new file with mode: 0644]
src/tbm_server/pixel_format.c [new file with mode: 0644]
src/tbm_server/pixel_format.h [new file with mode: 0644]
src/tbm_server/tbm_server.c [new file with mode: 0644]
src/tbm_server/tbm_server.h [new file with mode: 0644]
tests/test_backend.c [new file with mode: 0644]
tests/test_compositor.c [new file with mode: 0644]
tests/test_subsurface.c [new file with mode: 0644]
tests/test_surface.c [new file with mode: 0644]

diff --git a/include/libds-tizen/input_devicemgr.h b/include/libds-tizen/input_devicemgr.h
new file mode 100644 (file)
index 0000000..fc1060e
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef LIBDS_TIZEN_INPUT_DEVICEMGR_H
+#define LIBDS_TIZEN_INPUT_DEVICEMGR_H
+
+#include <wayland-server.h>
+
+#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 (file)
index 0000000..6e3b148
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef LIBDS_TIZEN_TBM_SERVER_H
+#define LIBDS_TIZEN_TBM_SERVER_H
+
+#include <wayland-server.h>
+#include <tbm_surface.h>
+#include <libds/buffer.h>
+
+#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 (file)
index 0000000..f690fe7
--- /dev/null
@@ -0,0 +1,1551 @@
+#include <stdlib.h>
+#include <time.h> // gettimeofday()
+#include <libds/backend.h>
+#include <libds/log.h>
+#include <libds-tizen/input_devicemgr.h>
+#include <libds/interfaces/backend.h>
+#include <libds/interfaces/keyboard.h>
+#include <libds/interfaces/pointer.h>
+#include <libds/interfaces/touch.h>
+
+#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 (file)
index 0000000..a4428ee
--- /dev/null
@@ -0,0 +1,78 @@
+#ifndef DS_TIZEN_DEVICEMGR_H
+#define DS_TIZEN_DEVICEMGR_H
+
+#include <stdbool.h>
+#include <linux/uinput.h>
+#include <wayland-server.h>
+#include <tizen-extension-server-protocol.h>
+#include <libds/interfaces/input_device.h>
+#include <libds/seat.h>
+
+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 (file)
index 0000000..ea8a94f
--- /dev/null
@@ -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 (file)
index 0000000..795576a
--- /dev/null
@@ -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 (file)
index 0000000..030f211
--- /dev/null
@@ -0,0 +1,61 @@
+#include <inttypes.h>
+#include <drm_fourcc.h>
+#include <tbm_type.h>
+
+#include <libds/log.h>
+#include "pixel_format.h"
+
+#ifdef ARRAY_LENGTH
+#undef ARRAY_LENGTH
+#endif
+
+#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
+
+struct ds_tbm_format
+{
+    uint32_t drm_format;
+    uint32_t tbm_format;
+};
+
+static const struct ds_tbm_format formats[] =
+{
+    {
+        .drm_format = DRM_FORMAT_ARGB8888,
+        .tbm_format = TBM_FORMAT_ARGB8888,
+    },
+    {
+        .drm_format = DRM_FORMAT_XRGB8888,
+        .tbm_format = TBM_FORMAT_XRGB8888,
+    },
+    /* TODO more format */
+};
+
+uint32_t
+convert_drm_format_to_tbm(uint32_t fmt)
+{
+    size_t i;
+
+    for (i = 0; i < ARRAY_LENGTH(formats); i++) {
+        if (formats[i].drm_format == fmt)
+            return formats[i].tbm_format;
+    }
+
+    ds_err("DRM format 0x%"PRIX32" has no TBM equivalent", fmt);
+
+    return 0;
+}
+
+uint32_t
+convert_tbm_format_to_drm(uint32_t fmt)
+{
+    size_t i;
+
+    for (i = 0; i < ARRAY_LENGTH(formats); i++) {
+        if (formats[i].tbm_format == fmt)
+            return formats[i].drm_format;
+    }
+
+    ds_err("TBM format 0x%"PRIX32" has no DRM equivalent", fmt);
+
+    return 0;
+}
diff --git a/src/tbm_server/pixel_format.h b/src/tbm_server/pixel_format.h
new file mode 100644 (file)
index 0000000..a63d096
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef DS_TIZEN_PIXEL_FORMAT_H
+#define DS_TIZEN_PIXEL_FORMAT_H
+
+#include <stdint.h>
+
+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 (file)
index 0000000..0fd25cd
--- /dev/null
@@ -0,0 +1,268 @@
+#include <assert.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include <tbm_bufmgr.h>
+
+#include <libds/log.h>
+#include "pixel_format.h"
+#include "tbm_server.h"
+
+static const struct ds_buffer_resource_interface tbm_buffer_resource_iface;
+static const struct ds_buffer_interface tbm_client_buffer_iface;
+
+static void tbm_server_handle_display_destroy(struct wl_listener *listener,
+        void *data);
+
+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 (file)
index 0000000..58e391b
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef DS_TIZEN_TBM_SERVER_H
+#define DS_TIZEN_TBM_SERVER_H
+
+#include <wayland-server.h>
+#include <wayland-tbm-server.h>
+#include <tbm_surface.h>
+#include <libds/interfaces/buffer.h>
+
+struct ds_tbm_server
+{
+    struct wayland_tbm_server *wl_tbm;
+
+    struct wl_listener display_destroy;
+
+    struct {
+        struct wl_signal destroy;
+    } events;
+};
+
+struct ds_tbm_client_buffer
+{
+    struct ds_buffer base;
+
+    tbm_surface_h surface;
+    struct wl_resource *resource;
+
+    struct wl_listener buffer_release;
+    struct wl_listener resource_destroy;
+
+    uint32_t format;
+    size_t stride;
+};
+
+#endif
diff --git a/tests/test_backend.c b/tests/test_backend.c
new file mode 100644 (file)
index 0000000..69417b6
--- /dev/null
@@ -0,0 +1,80 @@
+#include <assert.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+#include <wayland-server.h>
+#include <libds/backend/wayland.h>
+
+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 (file)
index 0000000..b5883a5
--- /dev/null
@@ -0,0 +1,63 @@
+#include <assert.h>
+#include <stdbool.h>
+
+#include <wayland-server.h>
+#include <libds/compositor.h>
+#include <libds/log.h>
+
+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 (file)
index 0000000..98e830d
--- /dev/null
@@ -0,0 +1,211 @@
+#include <assert.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <wayland-server.h>
+#include <wayland-client.h>
+#include <libds/compositor.h>
+#include <libds/surface.h>
+#include <libds/subsurface.h>
+#include <libds/log.h>
+
+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, &registry_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 (file)
index 0000000..eab2b77
--- /dev/null
@@ -0,0 +1,162 @@
+#include <assert.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <wayland-server.h>
+#include <wayland-client.h>
+#include <libds/compositor.h>
+#include <libds/surface.h>
+#include <libds/log.h>
+
+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, &registry_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;
+}