implement the libds-tizen-keyrouter 86/278186/1
authorSooChan Lim <sc1.lim@samsung.com>
Wed, 11 May 2022 07:48:55 +0000 (16:48 +0900)
committerSooChan Lim <sc1.lim@samsung.com>
Mon, 18 Jul 2022 05:58:36 +0000 (14:58 +0900)
libds-tizen-keyrouter supports the tizen_keyrouter extension.
This is the first impelemtaion for it. It can be added the additional
apis onward.

Change-Id: I9c819b03e38c5a1d7f8abb0257040502608e9131

include/libds-tizen/keyrouter.h [new file with mode: 0644]
meson_options.txt
packaging/libds.spec
src/libds-tizen/keyrouter/keyrouter.c [new file with mode: 0644]
src/libds-tizen/keyrouter/keyrouter.h [new file with mode: 0644]
src/libds-tizen/keyrouter/keyrouter_grab.c [new file with mode: 0644]
src/libds-tizen/keyrouter/meson.build [new file with mode: 0644]
src/libds-tizen/meson.build

diff --git a/include/libds-tizen/keyrouter.h b/include/libds-tizen/keyrouter.h
new file mode 100644 (file)
index 0000000..a870003
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef LIBDS_TIZEN_KEYROUTER_H
+#define LIBDS_TIZEN_KEYROUTER_H
+
+#include <wayland-server.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ds_tizen_keyrouter;
+
+struct ds_tizen_keyrouter *
+ds_tizen_keyrouter_create(struct wl_display *display);
+
+void
+ds_tizen_keyrouter_add_destroy_listener(struct ds_tizen_keyrouter *keyrouter,
+        struct wl_listener *listener);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
index 6ef6c8e..1d6ff21 100644 (file)
@@ -1 +1,2 @@
 option('tizen', type: 'boolean', value: false, description: 'Build Tizen features')
+option('keylayout_dir', type: 'string', value: '', description: 'Directory where tizen key layout file is')
\ No newline at end of file
index efba8cb..bee3972 100644 (file)
@@ -11,6 +11,7 @@ BuildRequires:  meson
 BuildRequires:  pkgconfig(wayland-server)
 BuildRequires:  pkgconfig(wayland-client)
 BuildRequires:  pkgconfig(wayland-protocols)
+BuildRequires:  pkgconfig(tizen-extension-server)
 BuildRequires:  pkgconfig(pixman-1)
 BuildRequires:  pkgconfig(libdrm)
 BuildRequires:  pkgconfig(xkbcommon)
@@ -37,6 +38,20 @@ Summary: Wayland Compositor development package on Tizen
 %description tizen-devel
 Wayland Compositor development library for Tizen platform
 
+%package tizen-keyrouter
+Summary: Wayland Compositor Library for keyrouter
+Group:   Development/Libraries
+
+%description tizen-keyrouter
+Wayland Compositor Library for tizen keyrouter
+
+%package tizen-keyrouter-devel
+Summary: Keyrouter Development package for Wayland Compositor Library
+Group:   Development/Libraries
+
+%description tizen-keyrouter-devel
+Keyrouter Development package for Wayland Compositor Library
+
 %prep
 %setup -q
 cp %{SOURCE1001} .
@@ -47,7 +62,8 @@ meson setup \
     --libdir %{_libdir} \
     --bindir %{_bindir} \
     builddir \
-    -Dtizen=true
+    -Dtizen=true \
+    -Dkeylayout_dir="%{TZ_SYS_RO_SHARE}/X11/xkb/tizen_key_layout.txt"
 ninja -C builddir all
 
 %install
@@ -58,7 +74,8 @@ ninja -C builddir install
 %manifest %{name}.manifest
 %defattr(-,root,root,-)
 %license LICENSE
-%{_libdir}/*.so.*
+%{_libdir}/libds.so.*
+%{_libdir}/libds-tizen.so.*
 
 %files devel
 %manifest %{name}.manifest
@@ -81,3 +98,17 @@ ninja -C builddir install
 %{_bindir}/tdm-backend
 %{_bindir}/tinyds-tdm
 %{_bindir}/ds-simple-tbm
+
+%files tizen-keyrouter
+%manifest %{name}.manifest
+%defattr(-,root,root,-)
+%license LICENSE
+%{_libdir}/libds-tizen-keyrouter.so.*
+
+%files tizen-keyrouter-devel
+%manifest %{name}.manifest
+%defattr(-,root,root,-)
+%license LICENSE
+%{_includedir}/libds-tizen/keyrouter.h
+%{_libdir}/pkgconfig/libds-tizen-keyrouter.pc
+%{_libdir}/libds-tizen-keyrouter.so
diff --git a/src/libds-tizen/keyrouter/keyrouter.c b/src/libds-tizen/keyrouter/keyrouter.c
new file mode 100644 (file)
index 0000000..eaa831a
--- /dev/null
@@ -0,0 +1,430 @@
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "libds/log.h"
+#include "libds-tizen/keyrouter.h"
+
+#include "util.h"
+#include "keyrouter.h"
+
+static void
+tizen_keyrouter_bind(struct wl_client *client, void *data, uint32_t version,
+        uint32_t id);
+static bool
+keyrouter_check_privilege(struct ds_tizen_keyrouter_client *keyrouter_client,
+        struct wl_client *client, uint32_t mode, uint32_t keycode);
+static void
+tizen_keyrouter_options_set(struct ds_tizen_keyrouter *keyrouter);
+
+static void
+keyrouter_handle_display_destroy(struct wl_listener *listener, void *data)
+{
+    struct ds_tizen_keyrouter *keyrouter;
+
+    keyrouter = wl_container_of(listener, keyrouter, display_destroy);
+
+    ds_inf("Global destroy: ds_tizen_keyrouter(%p)", keyrouter);
+
+    wl_signal_emit(&keyrouter->events.destroy, keyrouter);
+
+    tizen_security_finish();
+
+    free(keyrouter->opts);
+
+    wl_list_remove(&keyrouter->display_destroy.link);
+
+    wl_global_destroy(keyrouter->global);
+
+    tizen_keyrouter_grab_destroy(keyrouter->keyrouter_grab);
+
+    free(keyrouter);
+}
+
+WL_EXPORT struct ds_tizen_keyrouter *
+ds_tizen_keyrouter_create(struct wl_display *display)
+{
+    struct ds_tizen_keyrouter *keyrouter;
+
+    keyrouter = calloc(1, sizeof *keyrouter);
+    if (!keyrouter) {
+        return NULL;
+    }
+
+    keyrouter->keyrouter_grab = tizen_keyrouter_grab_create();
+    if (keyrouter->keyrouter_grab == NULL) {
+        ds_err("Failed to create keyrouter.");
+        free(keyrouter);
+        return NULL;
+    }
+
+    keyrouter->global = wl_global_create(display, &tizen_keyrouter_interface,
+            2, keyrouter, tizen_keyrouter_bind);
+    if (!keyrouter->global) {
+        tizen_keyrouter_grab_destroy(keyrouter->keyrouter_grab);
+        free(keyrouter);
+        return NULL;
+    }
+
+    wl_list_init(&keyrouter->clients);
+
+    wl_signal_init(&keyrouter->events.destroy);
+
+    keyrouter->display_destroy.notify = keyrouter_handle_display_destroy;
+    wl_display_add_destroy_listener(display, &keyrouter->display_destroy);
+
+    tizen_keyrouter_options_set(keyrouter);
+
+    if (!tizen_security_init()) {
+        ds_inf("tizen_security_init() is not sucessful. keyrouter works without security.");
+    }
+
+    ds_inf("Global created: ds_tizen_keyrouter(%p)", keyrouter);
+
+    return keyrouter;
+}
+
+WL_EXPORT void
+ds_tizen_keyrouter_add_destroy_listener(struct ds_tizen_keyrouter *keyrouter,
+        struct wl_listener *listener)
+{
+    wl_signal_add(&keyrouter->events.destroy, listener);
+}
+
+static void
+keyrouter_handle_keygrab_set(struct wl_client *client,
+        struct wl_resource *resource, struct wl_resource *surface,
+        uint32_t key, uint32_t mode)
+{
+    struct ds_tizen_keyrouter_client *keyrouter_client;
+    struct ds_tizen_keyrouter *keyrouter;
+    int res = TIZEN_KEYROUTER_ERROR_NONE;
+    bool ret;
+
+    keyrouter_client = wl_resource_get_user_data(resource);
+    keyrouter = keyrouter_client->keyrouter;
+
+    ret = keyrouter_check_privilege(keyrouter_client, client, mode, key);
+    if (ret == false) {
+        tizen_keyrouter_send_keygrab_notify(resource, surface,
+            key, mode, TIZEN_KEYROUTER_ERROR_NO_PERMISSION);
+        return;
+    }
+
+    res = tizen_keyrouter_grab_grab_key(keyrouter->keyrouter_grab,
+        mode, key, (void *)client);
+    if (res == TIZEN_KEYROUTER_ERROR_NONE && keyrouter_client->grabbed != true)
+        keyrouter_client->grabbed = true;
+
+    tizen_keyrouter_send_keygrab_notify(resource, surface, key, mode, res);
+}
+
+static void
+keyrouter_handle_keygrab_unset(struct wl_client *client,
+        struct wl_resource *resource, struct wl_resource *surface,  uint32_t key)
+{
+    struct ds_tizen_keyrouter_client *keyrouter_client;
+    struct ds_tizen_keyrouter *keyrouter;
+    int res = TIZEN_KEYROUTER_ERROR_NONE;
+    bool ret;
+
+    keyrouter_client = wl_resource_get_user_data(resource);
+    keyrouter = keyrouter_client->keyrouter;
+
+    /* ungrab TOP POSITION grab first, this grab mode is not check privilege */
+    tizen_keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab,
+        TIZEN_KEYROUTER_MODE_TOPMOST, key, (void *)client);
+
+    ret = keyrouter_check_privilege(keyrouter_client,
+        client, TIZEN_KEYROUTER_MODE_NONE, key);
+    if (ret == false) {
+        tizen_keyrouter_send_keygrab_notify(resource, surface, key,
+            TIZEN_KEYROUTER_MODE_NONE, TIZEN_KEYROUTER_ERROR_NO_PERMISSION);
+        return;
+    }
+
+    tizen_keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab,
+        TIZEN_KEYROUTER_MODE_EXCLUSIVE, key, (void *)client);
+    tizen_keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab,
+        TIZEN_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE, key, (void *)client);
+    tizen_keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab,
+        TIZEN_KEYROUTER_MODE_TOPMOST, key, (void *)client);
+    tizen_keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab,
+        TIZEN_KEYROUTER_MODE_SHARED, key, (void *)client);
+
+    tizen_keyrouter_send_keygrab_notify(resource, surface, key, TIZEN_KEYROUTER_MODE_NONE, res);
+}
+
+static void
+keyrouter_handle_get_keygrab_status(struct wl_client *client,
+        struct wl_resource *resource, struct wl_resource *surface, uint32_t key)
+{
+    tizen_keyrouter_send_keygrab_notify(resource, surface, key,
+            TIZEN_KEYROUTER_MODE_NONE, TIZEN_KEYROUTER_ERROR_NO_PERMISSION);
+}
+
+static int
+keyrouter_get_array_length(const struct wl_array *array)
+{
+    int *data = NULL;
+    int count = 0;
+
+    wl_array_for_each(data, array) {
+        count++;
+    }
+
+    return count;
+}
+
+static void
+keyrouter_handle_keygrab_set_list(struct wl_client *client,
+        struct wl_resource *resource, struct wl_resource *surface, struct wl_array *grab_list)
+{
+    struct ds_tizen_keyrouter_client *keyrouter_client;
+    struct ds_tizen_keyrouter *keyrouter;
+    struct wl_array *return_list;
+    struct ds_tizen_grab_data *grab_data = NULL;
+    int res = TIZEN_KEYROUTER_ERROR_NONE;
+    bool ret;
+
+    keyrouter_client = wl_resource_get_user_data(resource);
+    keyrouter = keyrouter_client->keyrouter;
+
+    if ((keyrouter_get_array_length(grab_list) % 3) != 0) {
+        ds_err("Invalid keycode and grab mode pair. Check arguments in a list.");
+        tizen_keyrouter_send_keygrab_notify_list(resource, surface, NULL);
+        return;
+    }
+
+    wl_array_for_each(grab_data, grab_list) {
+        ret = keyrouter_check_privilege(keyrouter_client, client, grab_data->mode, grab_data->key);
+        if (ret == false) {
+            grab_data->err = TIZEN_KEYROUTER_ERROR_NO_PERMISSION;
+        } else {
+            res = tizen_keyrouter_grab_grab_key(keyrouter->keyrouter_grab,
+                grab_data->mode, grab_data->key, (void *)client);
+            if (res == TIZEN_KEYROUTER_ERROR_NONE && keyrouter_client->grabbed != true)
+                keyrouter_client->grabbed = true;
+
+            grab_data->err = res;
+        }
+    }
+
+    return_list = grab_list;
+
+    tizen_keyrouter_send_keygrab_notify_list(resource, surface, return_list);
+}
+
+static void
+keyrouter_handle_keygrab_unset_list(struct wl_client *client,
+        struct wl_resource *resource, struct wl_resource *surface,
+        struct wl_array *ungrab_list)
+{
+    struct ds_tizen_keyrouter_client *keyrouter_client;
+    struct ds_tizen_keyrouter *keyrouter;
+    struct wl_array *return_list = NULL;
+    struct ds_tizen_ungrab_data *ungrab_data = NULL;
+    bool ret;
+
+    keyrouter_client = wl_resource_get_user_data(resource);
+    keyrouter = keyrouter_client->keyrouter;
+
+    if ((keyrouter_get_array_length(ungrab_list) % 3) != 0) {
+        ds_err("Invalid keycode and grab mode pair. Check arguments in a list.");
+        tizen_keyrouter_send_keygrab_notify_list(resource, surface, NULL);
+        return;
+    }
+
+    wl_array_for_each(ungrab_data, ungrab_list) {
+        tizen_keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab,
+            TIZEN_KEYROUTER_MODE_TOPMOST, ungrab_data->key, (void *)client);
+
+        ret = keyrouter_check_privilege(keyrouter_client, client,
+            TIZEN_KEYROUTER_MODE_TOPMOST, ungrab_data->key);
+        if (!ret) {
+            ungrab_data->err = TIZEN_KEYROUTER_ERROR_NO_PERMISSION;
+        } else {
+            tizen_keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab,
+                TIZEN_KEYROUTER_MODE_EXCLUSIVE, ungrab_data->key, (void *)client);
+
+            tizen_keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab,
+                TIZEN_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE, ungrab_data->key, (void *)client);
+
+            tizen_keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab,
+                TIZEN_KEYROUTER_MODE_TOPMOST, ungrab_data->key, (void *)client);
+
+            tizen_keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab,
+                TIZEN_KEYROUTER_MODE_SHARED, ungrab_data->key, (void *)client);
+
+            ungrab_data->err = TIZEN_KEYROUTER_ERROR_NONE;
+        }
+    }
+
+    return_list = ungrab_list;
+
+    tizen_keyrouter_send_keygrab_notify_list(resource, surface, return_list);
+}
+
+static void
+keyrouter_handle_get_keygrab_list(struct wl_client *client,
+        struct wl_resource *resource, struct wl_resource *surface)
+{
+    tizen_keyrouter_send_getgrab_notify_list(resource, surface, NULL);
+}
+
+static void
+keyrouter_handle_set_register_none_key(struct wl_client *client,
+        struct wl_resource *resource, struct wl_resource *surface,
+        uint32_t data)
+{
+    tizen_keyrouter_send_set_register_none_key_notify(resource, NULL, 0);
+}
+
+static void
+keyrouter_handle_get_keyregister_status(struct wl_client *client,
+        struct wl_resource *resource, uint32_t key)
+{
+    tizen_keyrouter_send_keyregister_notify(resource, (int)false);
+}
+
+static void
+keyrouter_handle_set_input_config(struct wl_client *client,
+        struct wl_resource *resource, struct wl_resource *surface,
+        uint32_t config_mode, uint32_t value)
+{
+    tizen_keyrouter_send_set_input_config_notify(resource, (int)false);
+}
+
+static void
+keyrouter_handle_destory(struct wl_client *client,
+        struct wl_resource *resource)
+{
+    wl_resource_destroy(resource);
+}
+
+static const struct tizen_keyrouter_interface tizen_keyrouter_impl = {
+   keyrouter_handle_keygrab_set,
+   keyrouter_handle_keygrab_unset,
+   keyrouter_handle_get_keygrab_status,
+   keyrouter_handle_keygrab_set_list,
+   keyrouter_handle_keygrab_unset_list,
+   keyrouter_handle_get_keygrab_list,
+   keyrouter_handle_set_register_none_key,
+   keyrouter_handle_get_keyregister_status,
+   keyrouter_handle_set_input_config,
+   keyrouter_handle_destory
+};
+
+static void
+keyrouter_handle_resource_destory(struct wl_resource *resource)
+{
+    struct ds_tizen_keyrouter_client *keyrouter_client = wl_resource_get_user_data(resource);
+
+    wl_list_remove(&keyrouter_client->link);
+    free(keyrouter_client);
+}
+
+static void
+tizen_keyrouter_bind(struct wl_client *client, void *data, uint32_t version,
+        uint32_t id)
+{
+    struct ds_tizen_keyrouter *keyrouter = data;
+    struct ds_tizen_keyrouter_client *keyrouter_client;
+
+    keyrouter_client = calloc(1, sizeof *keyrouter_client);
+    if (keyrouter_client == NULL) {
+        wl_client_post_no_memory(client);
+        return;
+    }
+
+    keyrouter_client->resource =
+        wl_resource_create(client, &tizen_keyrouter_interface, MIN(version, 2), id);
+    if (keyrouter_client->resource == NULL) {
+        ds_err("wl_resource_create() failed.(version :%d, id:%d)", version, id);
+        free(keyrouter_client);
+        wl_client_post_no_memory(client);
+        return;
+    }
+
+    wl_resource_set_implementation(keyrouter_client->resource, &tizen_keyrouter_impl,
+        keyrouter_client, keyrouter_handle_resource_destory);
+
+    wl_list_insert(&keyrouter->clients, &keyrouter_client->link);
+}
+
+static bool
+keyrouter_check_privilege(struct ds_tizen_keyrouter_client *keyrouter_client,
+        struct wl_client *client, uint32_t mode, uint32_t keycode)
+{
+    struct ds_tizen_keyrouter *keyrouter = keyrouter_client->keyrouter;
+
+    pid_t pid = 0;
+    uid_t uid = 0;
+    gid_t gid = 0;
+
+    /* Top position grab is always allowed. This mode do not need privilege.*/
+    if (mode == TIZEN_KEYROUTER_MODE_TOPMOST)
+        return true;
+
+    // check no privilege option on the keycode
+    if (keyrouter->opts) {
+        if (keyrouter->opts[keycode].no_privilege)
+            return true;
+    }
+
+    // grabbed client is already checked the privilege before.
+    if (keyrouter_client->grabbed)
+        return true;
+
+    wl_client_get_credentials(client, &pid, &uid, &gid);
+
+    return tizen_security_check_privilege(pid, uid, "http://tizen.org/privilege/keygrab");
+}
+
+static void
+tizen_keyrouter_options_set(struct ds_tizen_keyrouter *keyrouter)
+{
+    FILE *file;
+    int keycode;
+    char *ret, *tmp, *buf_ptr, buf[1024] = {0,};
+
+    keyrouter->opts = calloc(KEYROUTER_MAX_KEYS,
+        sizeof(struct ds_tizen_keyrouter_key_options));
+    if (!keyrouter->opts) {
+        return;
+    }
+
+    file = fopen(KEYLAYOUT_DIR, "r");
+    if (!file) {
+        ds_err("Failed to open key layout file(%s): (err msg: %m)\n", KEYLAYOUT_DIR);
+        free(keyrouter->opts);
+        keyrouter->opts = NULL;
+        return;
+    }
+
+    while (!feof(file)) {
+        ret = fgets(buf, 1024, file);
+        if (!ret) continue;
+
+        tmp = strtok_r(buf, " ", &buf_ptr);
+        tmp = strtok_r(NULL, " ", &buf_ptr);
+        if (!tmp) continue;
+        keycode = atoi(tmp);
+        if ((0 >= keycode) || (keycode >= KEYROUTER_MAX_KEYS)) {
+            ds_err("Currently %d key is invalid to support\n", keycode);
+            continue;
+        }
+
+        keyrouter->opts[keycode].enabled = true;
+
+        if (strstr(buf_ptr, "no_priv") != NULL) {
+            keyrouter->opts[keycode].no_privilege = true;
+        }
+    }
+
+    fclose(file);
+}
diff --git a/src/libds-tizen/keyrouter/keyrouter.h b/src/libds-tizen/keyrouter/keyrouter.h
new file mode 100644 (file)
index 0000000..c8dfa0f
--- /dev/null
@@ -0,0 +1,108 @@
+#ifndef DS_TIZEN_KEYROUTER_H
+#define DS_TIZEN_KEYROUTER_H
+
+#include <stdbool.h>
+#include <wayland-server.h>
+#include <tizen-extension-server-protocol.h>
+
+#define KEYROUTER_MAX_KEYS 512
+
+struct ds_tizen_keyrouter_key_info
+{
+       void *data;
+       struct wl_list link;
+};
+
+struct ds_tizen_keyrouter_grabbed
+{
+    int keycode;
+
+    struct {
+        struct wl_list excl;
+        struct wl_list or_excl;
+        struct wl_list top;
+        struct wl_list shared;
+    } grab;
+
+    struct wl_list pressed;
+};
+
+struct ds_tizen_keyrouter_grab
+{
+    struct ds_tizen_keyrouter_grabbed *hard_keys;
+
+    void *focus_client;
+    void *top_client;
+};
+
+struct ds_tizen_keyrouter_key_options
+{
+    bool enabled;
+    bool no_privilege;
+};
+
+struct ds_tizen_keyrouter
+{
+    struct wl_global *global;
+
+    struct wl_list clients;
+
+    struct wl_listener display_destroy;
+
+    struct {
+        struct wl_signal destroy;
+    } events;
+
+    struct ds_tizen_keyrouter_key_options *opts;
+
+    struct ds_tizen_keyrouter_grab *keyrouter_grab;
+};
+
+struct ds_tizen_keyrouter_client
+{
+    struct ds_tizen_keyrouter *keyrouter;
+
+    struct wl_resource *resource;
+
+    bool grabbed;
+
+    struct wl_list link; // ds_tizen_keyrouter::clients
+};
+
+struct ds_tizen_grab_data
+{
+       int key;
+       int mode;
+       int err;
+};
+
+struct ds_tizen_ungrab_data
+{
+       int key;
+       int err;
+};
+
+struct ds_tizen_keyrouter_grab *
+tizen_keyrouter_grab_create(void);
+void
+tizen_keyrouter_grab_destroy(struct ds_tizen_keyrouter_grab *keyrouter_grab);
+int
+tizen_keyrouter_grab_grab_key(struct ds_tizen_keyrouter_grab *keyrouter_grab,
+        int type, int keycode, void *data);
+void
+tizen_keyrouter_grab_ungrab_key(struct ds_tizen_keyrouter_grab *keyrouter_grab,
+        int type, int keycode, void *data);
+int
+tizen_keyrouter_grab_key_process(struct ds_tizen_keyrouter_grab *keyrouter_grab,
+        int keycode, int pressed, struct wl_list *delivery_list);
+void
+tizen_keyrouter_grab_set_focus_client(struct ds_tizen_keyrouter_grab *keyrouter_grab,
+        void *focus_client);
+void
+tizen_keyrouter_grab_set_top_client(struct ds_tizen_keyrouter_grab *keyrouter_grab,
+        void *top_client);
+bool
+tizen_keyrouter_grab_check_grabbed_key(struct ds_tizen_keyrouter_grab *keyrouter_grab,
+        int keycode);
+
+#endif
diff --git a/src/libds-tizen/keyrouter/keyrouter_grab.c b/src/libds-tizen/keyrouter/keyrouter_grab.c
new file mode 100644 (file)
index 0000000..873f4b1
--- /dev/null
@@ -0,0 +1,351 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "libds/log.h"
+
+#include "keyrouter.h"
+
+static struct wl_list *
+keyrouter_grab_get_grabbed_list(struct ds_tizen_keyrouter_grab *keyrouter_grab,
+        int type, int keycode)
+{
+    switch(type) {
+        case TIZEN_KEYROUTER_MODE_EXCLUSIVE:
+            return &keyrouter_grab->hard_keys[keycode].grab.excl;
+        case TIZEN_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE:
+            return &keyrouter_grab->hard_keys[keycode].grab.or_excl;
+        case TIZEN_KEYROUTER_MODE_TOPMOST:
+            return &keyrouter_grab->hard_keys[keycode].grab.top;
+        case TIZEN_KEYROUTER_MODE_SHARED:
+            return &keyrouter_grab->hard_keys[keycode].grab.shared;
+        default:
+            return NULL;
+    }
+}
+
+bool
+tizen_keyrouter_grab_check_grabbed_key(struct ds_tizen_keyrouter_grab *keyrouter_grab, int keycode)
+{
+    struct wl_list *list;
+
+    list = keyrouter_grab_get_grabbed_list(keyrouter_grab, TIZEN_KEYROUTER_MODE_EXCLUSIVE, keycode);
+    if (list && !wl_list_empty(list))
+        return true;
+
+    list = keyrouter_grab_get_grabbed_list(keyrouter_grab, TIZEN_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE, keycode);
+    if (list && !wl_list_empty(list))
+        return true;
+
+    list = keyrouter_grab_get_grabbed_list(keyrouter_grab, TIZEN_KEYROUTER_MODE_TOPMOST, keycode);
+    if (list && !wl_list_empty(list))
+        return true;
+
+    list = keyrouter_grab_get_grabbed_list(keyrouter_grab, TIZEN_KEYROUTER_MODE_SHARED, keycode);
+    if (list && !wl_list_empty(list))
+        return true;
+
+    return false;
+}
+
+static bool
+keyrouter_grab_check_duplicated_data(struct wl_list *list, void *data)
+{
+    struct ds_tizen_keyrouter_key_info *info;
+
+    if (wl_list_empty(list))
+        return false;
+
+    wl_list_for_each(info, list, link) {
+        if (info->data == data)
+            return true;
+    }
+
+    return false;
+}
+
+static bool
+keyrouter_grab_check_grabbed(struct ds_tizen_keyrouter_grab *keyrouter_grab,
+        int type, int keycode, void *data)
+{
+    struct wl_list *list;
+    bool ret;
+
+    list = keyrouter_grab_get_grabbed_list(keyrouter_grab, type, keycode);
+    if (list == NULL) {
+        ds_err("keycode(%d) had no list for type(%d).", keycode, type);
+        return false;
+    }
+
+    switch(type) {
+        case TIZEN_KEYROUTER_MODE_EXCLUSIVE:
+            if (wl_list_empty(list) == false)
+                ret = false;
+            else
+                ret = true;
+            break;
+        case TIZEN_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE:
+            ret = keyrouter_grab_check_duplicated_data(list, data);
+            break;
+        case TIZEN_KEYROUTER_MODE_TOPMOST:
+            ret = keyrouter_grab_check_duplicated_data(list, data);
+            break;
+        case TIZEN_KEYROUTER_MODE_SHARED:
+            ret = keyrouter_grab_check_duplicated_data(list, data);
+            break;
+        default:
+            ret = TIZEN_KEYROUTER_ERROR_INVALID_MODE;
+            break;
+    }
+
+    return ret;
+}
+
+void
+tizen_keyrouter_grab_set_focus_client(struct ds_tizen_keyrouter_grab *keyrouter_grab,
+        void *focus_client)
+{
+    keyrouter_grab->focus_client = focus_client;
+
+    if (focus_client)
+        ds_dbg("[%s] focus client has been set. (focus_client=0x%p)", __FUNCTION__, focus_client);
+    else
+        ds_dbg("[%s] focus client has been set to NULL.", __FUNCTION__);
+}
+
+void
+tizen_keyrouter_grab_set_top_client(struct ds_tizen_keyrouter_grab *keyrouter_grab, void *top_client)
+{
+    keyrouter_grab->top_client = top_client;
+
+    if (top_client)
+        ds_dbg("[%s] top client has been set. (top_client=0x%p)", __FUNCTION__, top_client);
+    else
+        ds_dbg("[%s] top client has been set to NULL.", __FUNCTION__);
+}
+
+int
+tizen_keyrouter_grab_key_process(struct ds_tizen_keyrouter_grab *keyrouter_grab,
+        int keycode, int pressed, struct wl_list *delivery_list)
+{
+    struct ds_tizen_keyrouter_key_info *info, *delivery;
+    int count = 0;
+
+    if (keycode <= 0 && keycode >= KEYROUTER_MAX_KEYS) {
+        ds_err("Invalid keycode(%d)", keycode);
+        return 0;
+    }
+
+    if (!wl_list_empty(&keyrouter_grab->hard_keys[keycode].grab.excl)) {
+        info = wl_container_of(keyrouter_grab->hard_keys[keycode].grab.excl.next, info, link);
+        if (info) {
+            delivery = calloc(1, sizeof(struct ds_tizen_keyrouter_key_info));
+            if (delivery == NULL) {
+                ds_err("Failed to allocate memory.");
+                return 0;
+            }
+            delivery->data = info->data;
+            wl_list_insert(delivery_list, &delivery->link);
+            ds_dbg("Exclusive Mode: keycode: %d to data: %p", keycode, info->data);
+            return 1;
+        }
+    } else if (!wl_list_empty(&keyrouter_grab->hard_keys[keycode].grab.or_excl)) {
+        info = wl_container_of(keyrouter_grab->hard_keys[keycode].grab.or_excl.next, info, link);
+        if (info) {
+            delivery = calloc(1, sizeof(struct ds_tizen_keyrouter_key_info));
+            if (delivery == NULL) {
+                ds_err("Failed to allocate memory.");
+                return 0;
+            }
+            delivery->data = info->data;
+            wl_list_insert(delivery_list, &delivery->link);
+            ds_dbg("OR-Excl Mode: keycode: %d to data: %p", keycode, info->data);
+            return 1;
+        }
+    } else if (!wl_list_empty(&keyrouter_grab->hard_keys[keycode].grab.top)) {
+        wl_list_for_each(info, &keyrouter_grab->hard_keys[keycode].grab.top, link) {
+            if (keyrouter_grab->top_client && keyrouter_grab->top_client == info->data) {
+                delivery = calloc(1, sizeof(struct ds_tizen_keyrouter_key_info));
+                if (delivery == NULL) {
+                    ds_err("Failed to allocate memory.");
+                    return 0;
+                }
+                delivery->data = info->data;
+                wl_list_insert(delivery_list, &delivery->link);
+                ds_dbg("Topmost Mode: keycode: %d to data: %p", keycode, info->data);
+                return 1;
+            }
+        }
+    }
+
+    if (keyrouter_grab->focus_client) {
+        delivery = calloc(1, sizeof(struct ds_tizen_keyrouter_key_info));
+        if (delivery == NULL) {
+            ds_err("Failed to allocate memory.");
+            return 0;
+        }
+        delivery->data = keyrouter_grab->focus_client;
+        wl_list_insert(delivery_list, &delivery->link);
+        count++;
+        ds_dbg("Focus: keycode: %d to data: %p, count: %d", keycode, delivery->data, count);
+    }
+
+    if (!wl_list_empty(&keyrouter_grab->hard_keys[keycode].grab.shared)) {
+        wl_list_for_each(info, &keyrouter_grab->hard_keys[keycode].grab.shared, link) {
+            if (keyrouter_grab->focus_client && keyrouter_grab->focus_client == info->data)
+                continue;
+            delivery = calloc(1, sizeof(struct ds_tizen_keyrouter_key_info));
+            if (delivery == NULL) {
+                ds_err("Failed to allocate memory.");
+                return 0;
+            }
+            delivery->data = info->data;
+            wl_list_insert(delivery_list, &delivery->link);
+            count++;
+            ds_dbg("Shared: keycode: %d to data: %p, count: %d", keycode, info->data, count);
+        }
+    }
+
+    return count;
+}
+
+int
+tizen_keyrouter_grab_grab_key(struct ds_tizen_keyrouter_grab *keyrouter_grab,
+        int type, int keycode, void *data)
+{
+    struct ds_tizen_keyrouter_key_info *info = NULL;
+    struct wl_list *list = NULL;
+
+    if (keycode <= 0 && keycode >= KEYROUTER_MAX_KEYS) {
+        ds_err("Invalid keycode(%d)", keycode);
+        return TIZEN_KEYROUTER_ERROR_INVALID_KEY;
+    }
+
+    if (keyrouter_grab_check_grabbed(keyrouter_grab, type, keycode, data))
+        return TIZEN_KEYROUTER_ERROR_GRABBED_ALREADY;
+
+    info = calloc(1, sizeof(struct ds_tizen_keyrouter_key_info));
+    if (info == NULL) {
+        ds_err("Failed to allocate memory.");
+        return TIZEN_KEYROUTER_ERROR_NO_SYSTEM_RESOURCES;
+    }
+    info->data = data;
+
+    wl_list_init(&info->link);
+
+    list = keyrouter_grab_get_grabbed_list(keyrouter_grab, type, keycode);
+    if (!list) {
+        ds_err("keycode(%d) had no list for type(%d)", keycode, type);
+        free(info);
+        return TIZEN_KEYROUTER_ERROR_INVALID_MODE;
+    }
+
+    if (!keyrouter_grab->hard_keys[keycode].keycode)
+        keyrouter_grab->hard_keys[keycode].keycode = keycode;
+
+    wl_list_insert(list, &info->link);
+
+    return TIZEN_KEYROUTER_ERROR_NONE;
+}
+
+static void
+keyrouter_list_remove_data(struct wl_list *list, void *data)
+{
+    struct ds_tizen_keyrouter_key_info *info, *tmp;
+
+    if (wl_list_empty(list))
+        return;
+
+    wl_list_for_each_safe(info ,tmp, list, link) {
+        if (info->data == data) {
+            wl_list_remove(&info->link);
+            free(info);
+        }
+    }
+}
+
+void
+tizen_keyrouter_grab_ungrab_key(struct ds_tizen_keyrouter_grab *keyrouter_grab,
+        int type, int keycode, void *data)
+{
+    struct wl_list *list;
+
+    if (keycode <= 0 && keycode >= KEYROUTER_MAX_KEYS) {
+        ds_err("Invalid keycode(%d)", keycode);
+        return;
+    }
+
+    if (keyrouter_grab->hard_keys[keycode].keycode == 0)
+        return;
+
+    list = keyrouter_grab_get_grabbed_list(keyrouter_grab, type, keycode);
+    if (list == NULL) {
+        ds_err("keycode(%d) had no list for type(%d)", keycode, type);
+        return;
+    }
+
+    keyrouter_list_remove_data(list, data);
+}
+
+struct ds_tizen_keyrouter_grab *
+tizen_keyrouter_grab_create(void)
+{
+    struct ds_tizen_keyrouter_grab *keyrouter_grab = NULL;
+    int i;
+
+    keyrouter_grab = calloc(1, sizeof(struct ds_tizen_keyrouter_grab));
+    if (keyrouter_grab == NULL) {
+        ds_err("Failed to allocate memory.");
+        return NULL;
+    }
+
+    /* FIXME: Who defined max keycode? */
+    keyrouter_grab->hard_keys = calloc(KEYROUTER_MAX_KEYS, sizeof(struct ds_tizen_keyrouter_grabbed));
+    if (keyrouter_grab == NULL) {
+        ds_err("Failed to allocate memory.");
+        free(keyrouter_grab);
+        return NULL;
+    }
+
+    for (i = 0; i < KEYROUTER_MAX_KEYS; i++) {
+        /* Enable all of keys to grab */
+        //keyrouter_grab->hard_keys[i].keycode = i;
+        wl_list_init(&keyrouter_grab->hard_keys[i].grab.excl);
+        wl_list_init(&keyrouter_grab->hard_keys[i].grab.or_excl);
+        wl_list_init(&keyrouter_grab->hard_keys[i].grab.top);
+        wl_list_init(&keyrouter_grab->hard_keys[i].grab.shared);
+        wl_list_init(&keyrouter_grab->hard_keys[i].pressed);
+    }
+
+    return keyrouter_grab;
+}
+
+static void
+keyrouter_grab_delete_list(struct wl_list *list)
+{
+    struct ds_tizen_keyrouter_key_info *info, *tmp;
+
+    if (wl_list_empty(list))
+        return;
+
+    wl_list_for_each_safe(info, tmp, list, link) {
+        wl_list_remove(&info->link);
+        free(info);
+    }
+}
+
+void
+tizen_keyrouter_grab_destroy(struct ds_tizen_keyrouter_grab *keyrouter_grab)
+{
+    int i;
+
+    for (i = 0; i < KEYROUTER_MAX_KEYS; i++) {
+        keyrouter_grab_delete_list(&keyrouter_grab->hard_keys[i].grab.excl);
+        keyrouter_grab_delete_list(&keyrouter_grab->hard_keys[i].grab.or_excl);
+        keyrouter_grab_delete_list(&keyrouter_grab->hard_keys[i].grab.top);
+        keyrouter_grab_delete_list(&keyrouter_grab->hard_keys[i].grab.shared);
+        keyrouter_grab_delete_list(&keyrouter_grab->hard_keys[i].pressed);
+    }
+
+    free(keyrouter_grab->hard_keys);
+    free(keyrouter_grab);
+}
diff --git a/src/libds-tizen/keyrouter/meson.build b/src/libds-tizen/keyrouter/meson.build
new file mode 100644 (file)
index 0000000..7b27d3b
--- /dev/null
@@ -0,0 +1,34 @@
+libds_tizen_keyrouter_files = [
+  'keyrouter_grab.c',
+  'keyrouter.c',
+]
+
+libds_tizen_keyrouter_deps = [
+  dep_libds,
+  dep_libds_tizen,
+  dependency('tizen-extension-server', required: true),
+]
+
+keylayout_dir = get_option('keylayout_dir')
+
+lib_libds_tizen_keyrouter = shared_library('ds-tizen-keyrouter', libds_tizen_keyrouter_files,
+  dependencies: libds_tizen_keyrouter_deps,
+  include_directories: [ common_inc, include_directories('.'), include_directories('..') ],
+  version: meson.project_version(),
+  c_args: [ '-DKEYLAYOUT_DIR="@0@"'.format(keylayout_dir) ],
+  install: true
+)
+
+dep_libds_tizen_keyrouter = declare_dependency(
+  link_with: lib_libds_tizen_keyrouter,
+  dependencies: libds_tizen_keyrouter_deps,
+  include_directories: [ common_inc, include_directories('.') ],
+)
+
+pkgconfig = import('pkgconfig')
+pkgconfig.generate(lib_libds_tizen_keyrouter,
+  version: meson.project_version(),
+  filebase: 'libds-tizen-keyrouter',
+  name: 'libds-tizen-keyrouter',
+  description: 'tizen keyrouter extension of libds-tizen for tizen platform',
+)
\ No newline at end of file
index 81370e6..0d780a3 100644 (file)
@@ -34,3 +34,6 @@ pkgconfig.generate(lib_libds_tizen,
   name: 'libds-tizen',
   description: 'extension of libds for tizen platform',
 )
+
+subdir('keyrouter')
+