e_keyrouter: take keyrouter functions to enlightenment's core 82/174682/4
authorJengHyun Kang <jhyuni.kang@samsung.com>
Tue, 3 Apr 2018 11:02:38 +0000 (20:02 +0900)
committerJeongHyun Kang <jhyuni.kang@samsung.com>
Thu, 12 Apr 2018 08:41:42 +0000 (08:41 +0000)
  - To send keys through keyrouter's policy

Change-Id: I2c864c708c46347e61ccbc420b6f5455feb84efe

12 files changed:
src/bin/Makefile.mk
src/bin/e_comp_canvas.c
src/bin/e_comp_wl.c
src/bin/e_comp_wl.h
src/bin/e_keyrouter.c
src/bin/e_keyrouter.h
src/bin/e_keyrouter_conf.c [new file with mode: 0644]
src/bin/e_keyrouter_events.c [new file with mode: 0644]
src/bin/e_keyrouter_list.c [new file with mode: 0644]
src/bin/e_keyrouter_private.h [new file with mode: 0644]
src/bin/e_keyrouter_wl.c [new file with mode: 0644]
src/bin/e_main.c

index 0544650..62d6ff9 100644 (file)
@@ -124,6 +124,7 @@ src/bin/e_process.h \
 src/bin/e_privilege.h \
 src/bin/e_security.h \
 src/bin/e_keyrouter.h \
+src/bin/e_keyrouter_private.h \
 src/bin/e_gesture.h \
 src/bin/e_input.h
 
@@ -226,6 +227,10 @@ src/bin/e_policy_wl_display.c \
 src/bin/e_process.c \
 src/bin/e_privilege.c \
 src/bin/e_security.c \
+src/bin/e_keyrouter_events.c \
+src/bin/e_keyrouter_list.c \
+src/bin/e_keyrouter_conf.c \
+src/bin/e_keyrouter_wl.c \
 src/bin/e_keyrouter.c \
 src/bin/e_gesture.c \
 src/bin/e_input_private.h \
index acdfd60..638ac85 100644 (file)
@@ -63,20 +63,6 @@ _e_comp_canvas_cb_mouse_wheel(void *d EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Obj
    ;
 }
 
-static Eina_Bool
-_e_comp_cb_key_down(void *data EINA_UNUSED, int ev_type EINA_UNUSED, Ecore_Event_Key *ev)
-{
-   e_screensaver_notidle();
-   return !e_comp_wl_key_down(ev);
-}
-
-static Eina_Bool
-_e_comp_cb_key_up(void *data EINA_UNUSED, int ev_type EINA_UNUSED, Ecore_Event_Key *ev)
-{
-   e_screensaver_notidle();
-   return !e_comp_wl_key_up(ev);
-}
-
 ////////////////////////////////////
 
 static Eina_Bool
@@ -199,8 +185,6 @@ e_comp_canvas_init(int w, int h)
    E_LIST_HANDLER_APPEND(handlers, E_EVENT_ZONE_ADD, _e_comp_cb_zone_change, NULL);
    E_LIST_HANDLER_APPEND(handlers, E_EVENT_ZONE_DEL, _e_comp_cb_zone_change, NULL);
    E_LIST_HANDLER_APPEND(handlers, E_EVENT_COMPOSITOR_ENABLE,    _e_comp_cb_compositor_enabled, NULL);
-   E_LIST_HANDLER_APPEND(handlers, ECORE_EVENT_KEY_DOWN, _e_comp_cb_key_down, NULL);
-   E_LIST_HANDLER_APPEND(handlers, ECORE_EVENT_KEY_UP, _e_comp_cb_key_up, NULL);
 
    ecore_evas_callback_pre_render_set(e_comp->ee, _e_comp_canvas_prerender);
    ecore_evas_callback_resize_set(e_comp->ee, _e_comp_canvas_resize);
index 49b4a8c..40b56ee 100644 (file)
@@ -59,8 +59,6 @@ static Eina_Bool need_send_motion = EINA_TRUE;
 static int _e_comp_wl_hooks_delete = 0;
 static int _e_comp_wl_hooks_walking = 0;
 
-static Eina_Hash *_last_keydev_hash = NULL;
-
 static Eina_Inlist *_e_comp_wl_hooks[] =
 {
    [E_COMP_WL_HOOK_SHELL_SURFACE_READY] = NULL,
@@ -4724,52 +4722,6 @@ _e_comp_wl_gl_shutdown(void)
    e_comp_wl->wl.gl = NULL;
 }
 
-static void
-_e_comp_wl_client_cb_destroy(struct wl_listener *l, void *data)
-{
-   struct wl_client *client = (struct wl_client *)data;
-
-   eina_hash_del_by_key(_last_keydev_hash, client);
-
-   wl_list_remove(&l->link);
-   E_FREE(l);
-}
-
-static void
-_e_comp_wl_client_destroy_listener_add(struct wl_client *client)
-{
-   struct wl_listener *destroy_listener;
-
-   EINA_SAFETY_ON_NULL_RETURN(client);
-   destroy_listener = wl_client_get_destroy_listener(client, _e_comp_wl_client_cb_destroy);
-   if (destroy_listener) return;
-
-   destroy_listener = E_NEW(struct wl_listener, 1);
-   EINA_SAFETY_ON_NULL_RETURN(destroy_listener);
-
-   destroy_listener->notify = _e_comp_wl_client_cb_destroy;
-   wl_client_add_destroy_listener(client, destroy_listener);
-}
-
-static Eina_Bool
-_e_comp_wl_keydev_hash_free(const Eina_Hash *hash, const void *key, void *data, void *fdata)
-{
-   struct wl_listener *destroy_listener;
-   struct wl_client *wc;
-
-   wc = (struct wl_client *)key;
-
-   destroy_listener = wl_client_get_destroy_listener(wc, _e_comp_wl_client_cb_destroy);
-
-   if (destroy_listener)
-     {
-        wl_list_remove(&destroy_listener->link);
-        E_FREE(destroy_listener);
-     }
-
-   return EINA_TRUE;
-}
-
 /* public functions */
 
 /**
@@ -4827,7 +4779,6 @@ e_comp_wl_init(void)
    E_LIST_HOOK_APPEND(hooks, E_CLIENT_HOOK_UNICONIFY,    _e_comp_wl_client_cb_uniconify,    NULL);
 
    E_EVENT_WAYLAND_GLOBAL_ADD = ecore_event_type_new();
-   _last_keydev_hash = eina_hash_pointer_new(NULL);
 
    TRACE_DS_END();
    return EINA_TRUE;
@@ -4868,9 +4819,6 @@ e_comp_wl_shutdown(void)
 #endif
    e_comp_wl_remote_surface_shutdown();
 
-   eina_hash_foreach(_last_keydev_hash, _e_comp_wl_keydev_hash_free, NULL);
-   eina_hash_free(_last_keydev_hash);
-
    e_pixmap_shutdown();
 
    e_comp_wl_shell_shutdown();
@@ -5382,13 +5330,12 @@ e_comp_wl_output_remove(const char *id)
 }
 
 static void
-_e_comp_wl_key_send(Ecore_Event_Key *ev, enum wl_keyboard_key_state state, Eina_List *key_list, Eina_Bool focused)
+_e_comp_wl_key_send(Ecore_Event_Key *ev, enum wl_keyboard_key_state state, Eina_List *key_list, E_Client *ec)
 {
    struct wl_resource *res;
    Eina_List *l;
    uint32_t serial, keycode;
-   struct wl_client *wc;
-   Ecore_Device *last_dev;
+   struct wl_client *wc = NULL;
    E_Comp_Config *comp_conf = NULL;
 
    keycode = (ev->keycode - 8);
@@ -5397,23 +5344,15 @@ _e_comp_wl_key_send(Ecore_Event_Key *ev, enum wl_keyboard_key_state state, Eina_
 
    comp_conf = e_comp_config_get();
 
+   if (ec && ec->comp_data && ec->comp_data->surface)
+     wc = wl_resource_get_client(ec->comp_data->surface);
+
    EINA_LIST_FOREACH(key_list, l, res)
      {
-        wc = wl_resource_get_client(res);
-        if (!focused && wc != ev->data) continue;
+        if (wl_resource_get_client(res) != wc) continue;
+
         TRACE_INPUT_BEGIN(_e_comp_wl_key_send);
-        last_dev = eina_hash_find(_last_keydev_hash, wc);
-        if (!last_dev)
-          {
-             _e_comp_wl_client_destroy_listener_add(wc);
-             eina_hash_direct_add(_last_keydev_hash, wc, ev->dev);
-             _e_comp_wl_send_event_device(ev->data, ev->timestamp, ev->dev, serial);
-          }
-        else if (last_dev != ev->dev)
-          {
-             eina_hash_modify(_last_keydev_hash, wc, ev->dev);
-             _e_comp_wl_send_event_device(ev->data, ev->timestamp, ev->dev, serial);
-          }
+        _e_comp_wl_send_event_device(ev->data, ev->timestamp, ev->dev, serial);
 
         if (comp_conf && comp_conf->input_log_enable)
           INF("[Server] Key %s (time: %d)\n", (state ? "Down" : "Up"), ev->timestamp);
@@ -5428,7 +5367,6 @@ EINTERN Eina_Bool
 e_comp_wl_key_down(Ecore_Event_Key *ev)
 {
    E_Client *ec = NULL;
-   struct wl_client *wc = NULL;
    uint32_t keycode;
    E_Comp_Wl_Key_Data *end, *k;
 
@@ -5453,60 +5391,6 @@ e_comp_wl_key_down(Ecore_Event_Key *ev)
      }
 #endif
 
-   ec = e_client_focused_get();
-   if (ec && ec->comp_data && ec->comp_data->surface)
-     wc = wl_resource_get_client(ec->comp_data->surface);
-
-   if (ev->data)
-     {
-        if ((wc != ev->data) && (ev->data != (void *)0x1))
-          {
-             _e_comp_wl_key_send(ev, WL_KEYBOARD_KEY_STATE_PRESSED, e_comp_wl->kbd.resources, EINA_FALSE);
-          }
-        else
-          {
-             ec = NULL;
-             end = (E_Comp_Wl_Key_Data *)e_comp_wl->kbd.routed_keys.data + (e_comp_wl->kbd.routed_keys.size / sizeof(*k));
-
-             for (k = e_comp_wl->kbd.routed_keys.data; k < end; k++)
-               {
-                  /* ignore server-generated key repeats */
-                  if (k->key == keycode)
-                    {
-                       return EINA_FALSE;
-                    }
-               }
-
-             if (ev->data == (void *)0x1) return EINA_FALSE;
-
-             if ((!e_client_action_get()) && (!e_comp->input_key_grabs))
-               {
-                  ec = e_client_focused_get();
-                  if (ec && ec->comp_data && ec->comp_data->surface && e_comp_wl->kbd.focused)
-                    {
-                       _e_comp_wl_key_send(ev, WL_KEYBOARD_KEY_STATE_PRESSED, e_comp_wl->kbd.focused, EINA_TRUE);
-
-                       /* A key only sent to clients is added to the list */
-                       e_comp_wl->kbd.routed_keys.size = (const char *)end - (const char *)e_comp_wl->kbd.routed_keys.data;
-                       if (!(k = wl_array_add(&e_comp_wl->kbd.routed_keys, sizeof(*k))))
-                         {
-                            DBG("wl_array_add: Out of memory\n");
-                            return EINA_FALSE;
-                         }
-                       k->key = keycode;
-                       k->dev = ev->dev;
-                    }
-               }
-
-             /* update modifier state */
-             e_comp_wl_input_keyboard_state_update(keycode, EINA_TRUE);
-          }
-
-        return !!ec;
-     }
-
-   ec = NULL;
-
    end = (E_Comp_Wl_Key_Data *)e_comp_wl->kbd.keys.data + (e_comp_wl->kbd.keys.size / sizeof(*k));
 
    for (k = e_comp_wl->kbd.keys.data; k < end; k++)
@@ -5523,8 +5407,7 @@ e_comp_wl_key_down(Ecore_Event_Key *ev)
         ec = e_client_focused_get();
         if (ec && ec->comp_data && ec->comp_data->surface && e_comp_wl->kbd.focused)
           {
-             ev->data = wc;
-             _e_comp_wl_key_send(ev, WL_KEYBOARD_KEY_STATE_PRESSED, e_comp_wl->kbd.focused, EINA_TRUE);
+             _e_comp_wl_key_send(ev, WL_KEYBOARD_KEY_STATE_PRESSED, e_comp_wl->kbd.focused, ec);
 
              /* A key only sent to clients is added to the list */
              e_comp_wl->kbd.keys.size = (const char *)end - (const char *)e_comp_wl->kbd.keys.data;
@@ -5548,7 +5431,6 @@ EINTERN Eina_Bool
 e_comp_wl_key_up(Ecore_Event_Key *ev)
 {
    E_Client *ec = NULL;
-   struct wl_client *wc = NULL;
    uint32_t keycode, delivered_key;
    E_Comp_Wl_Key_Data *end, *k;
 
@@ -5565,52 +5447,6 @@ e_comp_wl_key_up(Ecore_Event_Key *ev)
         return EINA_FALSE;
      }
 
-   ec = e_client_focused_get();
-
-   if (ec && ec->comp_data && ec->comp_data->surface)
-     wc = wl_resource_get_client(ec->comp_data->surface);
-
-   if (ev->data)
-     {
-        end = (E_Comp_Wl_Key_Data *)e_comp_wl->kbd.routed_keys.data + (e_comp_wl->kbd.routed_keys.size / sizeof(*k));
-        for (k = e_comp_wl->kbd.routed_keys.data; k < end; k++)
-          {
-             if (k->key == keycode)
-               {
-                  *k = *--end;
-                  delivered_key = 1;
-               }
-          }
-        e_comp_wl->kbd.routed_keys.size =
-          (const char *)end - (const char *)e_comp_wl->kbd.routed_keys.data;
-
-        if (wc != ev->data)
-          {
-             _e_comp_wl_key_send(ev, WL_KEYBOARD_KEY_STATE_RELEASED, e_comp_wl->kbd.resources, EINA_FALSE);
-          }
-        else
-          {
-             ec = NULL;
-
-             if ((delivered_key) ||
-                 ((!e_client_action_get()) && (!e_comp->input_key_grabs)))
-               {
-                  ec = e_client_focused_get();
-
-                  if (e_comp_wl->kbd.focused)
-                    {
-                       _e_comp_wl_key_send(ev, WL_KEYBOARD_KEY_STATE_RELEASED, e_comp_wl->kbd.focused, EINA_FALSE);
-                    }
-               }
-
-             /* update modifier state */
-             e_comp_wl_input_keyboard_state_update(keycode, EINA_FALSE);
-          }
-        return !!ec;
-     }
-
-   ec = NULL;
-
    end = (E_Comp_Wl_Key_Data *)e_comp_wl->kbd.keys.data + (e_comp_wl->kbd.keys.size / sizeof(*k));
    for (k = e_comp_wl->kbd.keys.data; k < end; k++)
      {
@@ -5632,8 +5468,7 @@ e_comp_wl_key_up(Ecore_Event_Key *ev)
 
         if (e_comp_wl->kbd.focused)
           {
-             ev->data = wc;
-             _e_comp_wl_key_send(ev, WL_KEYBOARD_KEY_STATE_RELEASED, e_comp_wl->kbd.focused, EINA_TRUE);
+             _e_comp_wl_key_send(ev, WL_KEYBOARD_KEY_STATE_RELEASED, e_comp_wl->kbd.focused, ec);
           }
      }
 
@@ -5644,6 +5479,23 @@ e_comp_wl_key_up(Ecore_Event_Key *ev)
 }
 
 E_API Eina_Bool
+e_comp_wl_key_process(Ecore_Event_Key *ev, int type)
+{
+   Eina_Bool res = EINA_FALSE;
+
+   if (type == ECORE_EVENT_KEY_DOWN)
+     {
+        res = e_comp_wl_key_down(ev);
+     }
+   else if (type == ECORE_EVENT_KEY_UP)
+     {
+        res = e_comp_wl_key_up(ev);
+     }
+
+   return res;
+}
+
+E_API Eina_Bool
 e_comp_wl_evas_handle_mouse_button(E_Client *ec, uint32_t timestamp, uint32_t button_id, uint32_t state)
 {
    Eina_List *l;
index 12985d7..9c6ca39 100644 (file)
@@ -586,6 +586,7 @@ EINTERN Eina_Bool e_comp_wl_mouse_in_send(E_Client *ec, int x, int y, Ecore_Devi
 EINTERN Eina_Bool e_comp_wl_mouse_out_send(E_Client *ec, Ecore_Device *dev, uint32_t time);
 EINTERN void e_comp_wl_mouse_in_renew(E_Client *ec, int buttons, int x, int y, void *data, Evas_Modifier *modifiers, Evas_Lock *locks, unsigned int timestamp, Evas_Event_Flags event_flags, Evas_Device *dev, Evas_Object *event_src);
 EINTERN void e_comp_wl_mouse_out_renew(E_Client *ec, int buttons, int x, int y, void *data, Evas_Modifier *modifiers, Evas_Lock *locks, unsigned int timestamp, Evas_Event_Flags event_flags, Evas_Device *dev, Evas_Object *event_src);
+E_API Eina_Bool e_comp_wl_key_process(Ecore_Event_Key *ev, int type);
 
 EINTERN Eina_Bool e_comp_wl_cursor_hide(E_Client *ec);
 
index 9deb5bf..12e8744 100644 (file)
@@ -1,5 +1,6 @@
 #include "e.h"
 #include "e_keyrouter.h"
+#include "e_keyrouter_private.h"
 
 static int _e_keyrouter_intercept_hooks_delete = 0;
 static int _e_keyrouter_intercept_hooks_walking = 0;
@@ -10,7 +11,10 @@ static Eina_Inlist *_e_keyrouter_intercept_hooks[] =
    [E_KEYROUTER_INTERCEPT_HOOK_DELIVER_FOCUS] = NULL,
 };
 
+int _keyrouter_log_dom = -1;
+
 E_API E_Keyrouter_Info e_keyrouter;
+E_KeyrouterPtr krt;
 
 E_API E_Keyrouter_Intercept_Hook *
 e_keyrouter_intercept_hook_add(E_Keyrouter_Intercept_Hook_Point hookpoint, E_Keyrouter_Intercept_Hook_Cb func, const void *data)
@@ -75,3 +79,440 @@ e_keyrouter_intercept_hook_call(E_Keyrouter_Intercept_Hook_Point hookpoint, int
 
    return res;
 }
+
+static void
+_e_keyrouter_keygrab_status_print(FILE *log_fl, Eina_List *list)
+{
+   Eina_List *l;
+   E_Keyrouter_Key_List_NodePtr kdata;
+   int pid;
+   char *cmd;
+
+   EINA_LIST_FOREACH(list, l, kdata)
+     {
+        pid = e_keyrouter_util_get_pid(kdata->wc, kdata->surface);
+        cmd = e_keyrouter_util_cmd_get_from_pid(pid);
+        fprintf(log_fl, "                [surface: %p, client: %p, pid: %d(%s)]\n", kdata->surface, kdata->wc, pid, cmd ?: "Unknown");
+        if(cmd) E_FREE(cmd);
+        if (kdata->surface)
+          {
+             fprintf(log_fl, "                    -- Surface Information --\n");
+             fprintf(log_fl, "                        = client: %p\n", wl_resource_get_client(kdata->surface));
+             fprintf(log_fl, "                        = resource: %s(%d)\n", wl_resource_get_class(kdata->surface), wl_resource_get_id(kdata->surface));
+          }
+        else
+          {
+             fprintf(log_fl, "                    -- Client Information --\n");
+             fprintf(log_fl, "                        = connected fd: %d\n", wl_client_get_fd(kdata->wc));
+          }
+     }
+}
+
+static void
+_e_keyrouter_info_print(void *data, const char *log_path)
+{
+   char *keyname;
+   int  i;
+   FILE *log_fl;
+
+   log_fl = fopen(log_path, "a");
+   if (!log_fl)
+     {
+        KLERR("failed: open file(%s)", log_path);
+        return;
+     }
+
+   setvbuf(log_fl, NULL, _IOLBF, 512);
+
+   fprintf(log_fl, "\n===== Keyrouter Information =====\n");
+   fprintf(log_fl, "    ----- Grabbable Keys -----\n");
+   for (i = 8; i <= krt->max_tizen_hwkeys; i++)
+     {
+        if (!krt->HardKeys[i].keycode) continue;
+
+        keyname = e_keyrouter_util_keyname_get_from_keycode(i);
+
+        fprintf(log_fl, "         Key [%3d], Keyname: %s\n", i, keyname);
+
+        free(keyname);
+        keyname = NULL;
+     }
+   fprintf(log_fl, "    ----- End -----\n\n");
+
+   fclose(log_fl);
+   log_fl = NULL;
+}
+
+static void
+_e_keyrouter_keygrab_print(void *data, const char *log_path)
+{
+   Eina_List *l;
+   E_Keyrouter_Key_List_NodePtr kdata;
+   E_Client *ec_focus;
+   struct wl_resource *surface_focus;
+   struct wl_client *wc_focus;
+   int pid_focus, pid, i;
+   char *cmd_focus, *cmd, *keyname;
+   FILE *log_fl;
+
+   (void) data;
+
+   log_fl = fopen(log_path, "a");
+   if (!log_fl)
+     {
+        KLERR("failed: open file(%s)", log_path);
+        return;
+     }
+
+   setvbuf(log_fl, NULL, _IOLBF, 512);
+
+   fprintf(log_fl, "\n===== Keygrab Status =====\n");
+
+   ec_focus = e_client_focused_get();
+   fprintf(log_fl, "    ----- Focus Window Info -----\n");
+   if (ec_focus)
+     {
+        surface_focus = e_keyrouter_util_get_surface_from_eclient(ec_focus);
+        wc_focus = wl_resource_get_client(surface_focus);
+        pid_focus = e_keyrouter_util_get_pid(NULL, surface_focus);
+        cmd_focus = e_keyrouter_util_cmd_get_from_pid(pid_focus);
+
+        fprintf(log_fl, "        Focus Client: E_Client: %p\n", ec_focus);
+        fprintf(log_fl, "                      Surface: %p, Client: %p\n", surface_focus, wc_focus);
+        fprintf(log_fl, "                      pid: %d, cmd: %s\n", pid_focus, cmd_focus ?: "Unknown");
+        if(cmd_focus) E_FREE(cmd_focus);
+     }
+   else
+     {
+        fprintf(log_fl, "        No Focus Client\n");
+     }
+   fprintf(log_fl, "    ----- End -----\n\n");
+
+   fprintf(log_fl, "    ----- Grabbed keys Info -----\n\n");
+   for (i = 8; i <= krt->max_tizen_hwkeys; i++)
+     {
+        if (!krt->HardKeys[i].keycode) continue;
+        if (!krt->HardKeys[i].excl_ptr &&
+            !krt->HardKeys[i].or_excl_ptr &&
+            !krt->HardKeys[i].top_ptr &&
+            !krt->HardKeys[i].shared_ptr)
+          continue;
+
+        keyname = e_keyrouter_util_keyname_get_from_keycode(i);
+
+        fprintf(log_fl, "        [ Keycode: %d, Keyname: %s ]\n", i, keyname);
+
+        free(keyname);
+        keyname = NULL;
+
+        if (krt->HardKeys[i].excl_ptr)
+          {
+             fprintf(log_fl, "            == Exclusive Grab ==\n");
+             EINA_LIST_FOREACH(krt->HardKeys[i].excl_ptr, l, kdata)
+               {
+                  pid = e_keyrouter_util_get_pid(kdata->wc, kdata->surface);
+                  cmd = e_keyrouter_util_cmd_get_from_pid(pid);
+                  fprintf(log_fl, "                [surface: %p, client: %p, pid: %d(%s)]\n", kdata->surface, kdata->wc, pid, cmd ?: "Unknown");
+                  if(cmd) E_FREE(cmd);
+                  if (kdata->surface)
+                    {
+                       fprintf(log_fl, "                    -- Surface Information --\n");
+                       fprintf(log_fl, "                        = wl_client: %p\n", wl_resource_get_client(kdata->surface));
+                       fprintf(log_fl, "                        = resource: %s(%d)\n", wl_resource_get_class(kdata->surface), wl_resource_get_id(kdata->surface));
+                    }
+                  else
+                    {
+                       fprintf(log_fl, "                    -- Client Information --\n");
+                       fprintf(log_fl, "                        = connected fd: %d\n", wl_client_get_fd(kdata->wc));
+                    }
+               }
+            }
+
+        if (krt->HardKeys[i].or_excl_ptr)
+          {
+             fprintf(log_fl, "            == Overidable Exclusive Grab ==\n");
+             _e_keyrouter_keygrab_status_print(log_fl, krt->HardKeys[i].or_excl_ptr);
+          }
+
+        if (krt->HardKeys[i].top_ptr)
+          {
+             fprintf(log_fl, "            == Top Position Grab ==\n");
+             _e_keyrouter_keygrab_status_print(log_fl, krt->HardKeys[i].top_ptr);
+          }
+
+        if (krt->HardKeys[i].shared_ptr)
+          {
+             fprintf(log_fl, "            == Shared Grab ==\n");
+             _e_keyrouter_keygrab_status_print(log_fl, krt->HardKeys[i].shared_ptr);
+          }
+
+        fprintf(log_fl, "\n");
+     }
+
+   fprintf(log_fl, "    ----- End -----\n\n");
+
+   fclose(log_fl);
+   log_fl = NULL;
+}
+
+static Eina_Bool
+_e_keyrouter_cb_key_down(void *data, int type, void *event)
+{
+   Ecore_Event_Key *ev;
+   Eina_Bool res = ECORE_CALLBACK_PASS_ON;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(event, ECORE_CALLBACK_PASS_ON);
+
+   ev = (Ecore_Event_Key *)event;
+
+   TRACE_INPUT_BEGIN(_e_keyrouter_cb_key_down:KEY_PRESS(%d), ev->keycode);
+   TRACE_INPUT_END();
+
+   res = e_keyrouter_event_process(event, type);
+   
+   return res;
+}
+
+static Eina_Bool
+_e_keyrouter_cb_key_up(void *data, int type, void *event)
+{
+   Ecore_Event_Key *ev;
+   Eina_Bool res = ECORE_CALLBACK_PASS_ON;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(event, ECORE_CALLBACK_PASS_ON);
+
+   ev = (Ecore_Event_Key *)event;
+
+   TRACE_INPUT_BEGIN(_e_keyrouter_cb_key_down:KEY_RELEASE(%d), ev->keycode);
+   TRACE_INPUT_END();
+
+   res = e_keyrouter_event_process(event, type);
+   
+   return res;
+}
+
+static Eina_Bool
+_e_keyrouter_client_cb_stack(void *data, int type, void *event)
+{
+   E_Event_Client *ev = event;
+   E_Client *ec = ev->ec;
+
+   (void) data;
+   (void) type;
+   (void) event;
+   (void) ev;
+   (void) ec;
+
+   //KLDBG("ec: %p, visibile: %d, focused: %d, take_focus: %d, want_focus: %d, bordername: %s, input_only: %d",
+   //        ec, ec->visible, ec->focused, ec->take_focus, ec->want_focus, ec->bordername, ec->input_only);
+
+   krt->isWindowStackChanged = EINA_TRUE;
+
+   return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_e_keyrouter_client_cb_remove(void *data, int type, void *event)
+{
+   E_Event_Client *ev = event;
+   E_Client *ec = ev->ec;
+
+   (void) data;
+   (void) type;
+   (void) ev;
+   (void) ec;
+
+   /* FIXME: Remove this callback or do something others.
+    *             It was moved to _e_keyrouter_wl_surface_cb_destroy() where it had here.
+    */
+
+   return ECORE_CALLBACK_PASS_ON;
+}
+
+static void
+_e_keyrouter_init_handlers(void)
+{
+   E_LIST_HANDLER_APPEND(krt->handlers, E_EVENT_CLIENT_STACK, _e_keyrouter_client_cb_stack, NULL);
+   E_LIST_HANDLER_APPEND(krt->handlers, E_EVENT_CLIENT_REMOVE, _e_keyrouter_client_cb_remove, NULL);
+   E_LIST_HANDLER_APPEND(krt->handlers, ECORE_EVENT_KEY_DOWN, _e_keyrouter_cb_key_down, NULL);
+   E_LIST_HANDLER_APPEND(krt->handlers, ECORE_EVENT_KEY_UP, _e_keyrouter_cb_key_up, NULL);
+
+   e_info_server_hook_set("keyrouter", _e_keyrouter_info_print, NULL);
+   e_info_server_hook_set("keygrab", _e_keyrouter_keygrab_print, NULL);
+}
+
+static void
+_e_keyrouter_deinit_handlers(void)
+{
+   Ecore_Event_Handler *h = NULL;
+
+   if (!krt ||  !krt->handlers) return;
+
+   EINA_LIST_FREE(krt->handlers, h)
+     ecore_event_handler_del(h);
+
+   e_info_server_hook_set("keyrouter", NULL, NULL);
+   e_info_server_hook_set("keygrab", NULL, NULL);
+}
+
+static Eina_Bool
+_e_keyrouter_query_tizen_key_table(void)
+{
+   E_Keyrouter_Conf_Edd *kconf = krt->conf->conf;
+   Eina_List *l;
+   E_Keyrouter_Tizen_HWKey *data;
+   int res;
+   struct xkb_rule_names names={0,};
+
+   /* TODO: Make struct in HardKeys to pointer.
+                  If a key is defined, allocate memory to pointer,
+                  that makes to save unnecessary memory */
+   krt->HardKeys = E_NEW(E_Keyrouter_Grabbed_Key, kconf->max_keycode + 1);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(krt->HardKeys, EINA_FALSE);
+
+   krt->numTizenHWKeys = kconf->num_keycode;
+   krt->max_tizen_hwkeys = kconf->max_keycode;
+
+   EINA_LIST_FOREACH(kconf->KeyList, l, data)
+     {
+        if (!data) continue;
+
+        if (0 > data->keycode || krt->max_tizen_hwkeys < data->keycode)
+          {
+             KLWRN("Given keycode(%d) is invalid. It must be bigger than zero, smaller than the maximum value(%d) or equal to it.", data->keycode, kconf->max_keycode);
+             continue;
+          }
+
+        KLINF("[jeon] keycode: %d, name: %s, no_priv: %d, repeat: %d\n", data->keycode, data->name, data->no_privcheck, data->repeat);
+
+        krt->HardKeys[data->keycode].keycode = data->keycode;
+        krt->HardKeys[data->keycode].keyname = (char *)eina_stringshare_add(data->name);
+        krt->HardKeys[data->keycode].no_privcheck = data->no_privcheck ? EINA_TRUE : EINA_FALSE;
+        krt->HardKeys[data->keycode].repeat = data->repeat ? EINA_TRUE : EINA_FALSE;
+
+        if (e_comp_wl_input_keymap_cache_file_use_get() == EINA_FALSE)
+          {
+             if (krt->HardKeys[data->keycode].repeat == EINA_FALSE)
+               {
+                  res = xkb_keymap_key_set_repeats(e_comp_wl->xkb.keymap, data->keycode, 0);
+                  if (!res)
+                    {
+                       KLWRN("Failed to set repeat key(%d), value(%d)", data->keycode, 0);
+                    }
+               }
+          }
+     }
+
+   if (e_comp_wl_input_keymap_cache_file_use_get() == EINA_FALSE)
+     {
+        KLINF("Server create a new cache file: %s", e_comp_wl_input_keymap_path_get(names));
+        res = unlink(e_comp_wl_input_keymap_path_get(names));
+
+        e_comp_wl_input_keymap_set(NULL, NULL, NULL, NULL, NULL, xkb_context_ref(e_comp_wl->xkb.context), xkb_keymap_ref(e_comp_wl->xkb.keymap));
+     }
+   else
+     KLINF("Currently cache file is exist. Do not change it.");
+
+   return EINA_TRUE;
+}
+
+static void *
+_e_keyrouter_keygrab_list_get(void)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(krt, NULL);
+   return krt->HardKeys;
+}
+
+static int
+_e_keyrouter_max_keycode_get(void)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(krt, 0);
+   return krt->max_tizen_hwkeys;
+}
+
+E_API int
+e_keyrouter_init(void)
+{
+   E_Keyrouter_Config_Data *kconfig = NULL;
+   Eina_Bool res = EINA_FALSE;
+
+   TRACE_INPUT_BEGIN(e_keyrouter_init);
+
+   EINA_SAFETY_ON_NULL_GOTO(e_comp, err);
+
+   _keyrouter_log_dom = eina_log_domain_register("e-keyrouter", EINA_COLOR_RED);
+   EINA_SAFETY_ON_FALSE_GOTO(_keyrouter_log_dom >= 0, err);
+   eina_log_domain_level_set("e-keyrouter", EINA_LOG_LEVEL_INFO);
+
+   krt = E_NEW(E_Keyrouter, 1);
+   EINA_SAFETY_ON_NULL_GOTO(krt, err);
+
+   kconfig = E_NEW(E_Keyrouter_Config_Data, 1);
+   EINA_SAFETY_ON_NULL_GOTO(kconfig, err);
+
+   e_keyrouter_conf_init(kconfig);
+   EINA_SAFETY_ON_NULL_GOTO(kconfig->conf, err);
+   krt->conf = kconfig;
+   krt->pictureoff_disabled = !!kconfig->conf->pictureoff_disabled;
+
+   res = e_keyrouter_wl_init();
+   EINA_SAFETY_ON_FALSE_GOTO(res, err);
+
+   /* Get keyname and keycode pair from Tizen Key Layout file */
+   res = _e_keyrouter_query_tizen_key_table();
+   EINA_SAFETY_ON_FALSE_GOTO(res, err);
+
+   //ecore handler add for power callback registration
+//   if (!krt->pictureoff_disabled)
+//     ecore_idle_enterer_add(_e_keyrouter_cb_idler, NULL);
+   _e_keyrouter_init_handlers();
+
+   e_keyrouter.keygrab_list_get = _e_keyrouter_keygrab_list_get;
+   e_keyrouter.max_keycode_get = _e_keyrouter_max_keycode_get;
+
+   TRACE_INPUT_END();
+   return EINA_TRUE;
+
+err:
+   if (kconfig)
+     {
+        e_keyrouter_conf_deinit(kconfig);
+        E_FREE(kconfig);
+     }
+   _e_keyrouter_deinit_handlers();
+   e_keyrouter_wl_shutdown();
+   eina_log_domain_unregister(_keyrouter_log_dom);
+   _keyrouter_log_dom = -1;
+   if (krt) E_FREE(krt);
+
+   TRACE_INPUT_END();
+   return EINA_FALSE;
+}
+
+E_API int
+e_keyrouter_shutdown(void)
+{
+   int i;
+   E_Keyrouter_Config_Data *kconfig = krt->conf;
+
+   e_keyrouter_conf_deinit(kconfig);
+   E_FREE(kconfig);
+
+   _e_keyrouter_deinit_handlers();
+
+   for (i = 0; i < krt->max_tizen_hwkeys+1; i++)
+     {
+        if (krt->HardKeys[i].keyname)
+          eina_stringshare_del(krt->HardKeys[i].keyname);
+     }
+   E_FREE(krt->HardKeys);
+
+   e_keyrouter_wl_shutdown();
+
+   E_FREE(krt);
+   /* TODO: free allocated memory */
+
+   eina_log_domain_unregister(_keyrouter_log_dom);
+
+   return EINA_TRUE;
+}
index 66cecb3..fe54f88 100644 (file)
@@ -79,7 +79,6 @@ struct _E_Keyrouter_Grabbed_Key
    Eina_List *top_ptr;
    Eina_List *shared_ptr;
    Eina_List *press_ptr;
-   E_Keyrouter_Key_List_Node *registered_ptr;
    Eina_List *pic_off_ptr;
 };
 
@@ -87,6 +86,10 @@ E_API E_Keyrouter_Intercept_Hook *e_keyrouter_intercept_hook_add(E_Keyrouter_Int
 E_API void e_keyrouter_intercept_hook_del(E_Keyrouter_Intercept_Hook *ch);
 E_API Eina_Bool e_keyrouter_intercept_hook_call(E_Keyrouter_Intercept_Hook_Point hookpoint, int type, Ecore_Event_Key *event);
 
+E_API int e_keyrouter_init(void);
+E_API int e_keyrouter_shutdown(void);
+
+
 #endif
 #endif
 
diff --git a/src/bin/e_keyrouter_conf.c b/src/bin/e_keyrouter_conf.c
new file mode 100644 (file)
index 0000000..4de89da
--- /dev/null
@@ -0,0 +1,55 @@
+#include "e_keyrouter_private.h"
+
+void
+e_keyrouter_conf_init(E_Keyrouter_Config_Data *kconfig)
+{
+   kconfig->conf_hwkeys_edd= E_CONFIG_DD_NEW("E_Keyrouter_Config_Key",
+                                               E_Keyrouter_Tizen_HWKey);
+#undef T
+#undef D
+#define T E_Keyrouter_Tizen_HWKey
+#define D kconfig->conf_hwkeys_edd
+   E_CONFIG_VAL(D, T, name, STR);
+   E_CONFIG_VAL(D, T, keycode, INT);
+   E_CONFIG_VAL(D, T, no_privcheck, INT);
+   E_CONFIG_VAL(D, T, repeat, INT);
+
+   kconfig->conf_edd = E_CONFIG_DD_NEW("Keyrouter_Config", E_Keyrouter_Conf_Edd);
+#undef T
+#undef D
+#define T E_Keyrouter_Conf_Edd
+#define D kconfig->conf_edd
+   E_CONFIG_VAL(D, T, num_keycode, INT);
+   E_CONFIG_VAL(D, T, max_keycode, INT);
+   E_CONFIG_VAL(D, T, pictureoff_disabled, INT);
+   E_CONFIG_LIST(D, T, KeyList, kconfig->conf_hwkeys_edd);
+
+#undef T
+#undef D
+   kconfig->conf = e_config_domain_load("module.keyrouter", kconfig->conf_edd);
+
+   if (!kconfig->conf)
+     {
+        KLDBG("Failed to find module.keyrouter config file.");
+     }
+}
+
+void
+e_keyrouter_conf_deinit(E_Keyrouter_Config_Data *kconfig)
+{
+   E_Keyrouter_Tizen_HWKey *kdata;
+
+   if (kconfig->conf)
+     {
+        EINA_LIST_FREE(kconfig->conf->KeyList, kdata)
+          {
+             eina_stringshare_del(kdata->name);
+             free(kdata);
+          }
+        free(kconfig->conf);
+     }
+
+   E_CONFIG_DD_FREE(kconfig->conf_hwkeys_edd);
+   E_CONFIG_DD_FREE(kconfig->conf_edd);
+}
+
diff --git a/src/bin/e_keyrouter_events.c b/src/bin/e_keyrouter_events.c
new file mode 100644 (file)
index 0000000..208c59c
--- /dev/null
@@ -0,0 +1,572 @@
+#include "e_keyrouter_private.h"
+
+static Eina_Bool _e_keyrouter_send_key_events(int type, Ecore_Event_Key *ev);
+static Eina_Bool _e_keyrouter_send_key_events_press(int type, Ecore_Event_Key *ev);
+static Eina_Bool _e_keyrouter_send_key_events_release(int type, Ecore_Event_Key *ev);
+static Eina_Bool _e_keyrouter_send_key_event(int type, struct wl_resource *surface, struct wl_client *wc, Ecore_Event_Key *ev, Eina_Bool focused, unsigned int mode);
+
+static Eina_Bool _e_keyrouter_send_key_events_focus(int type, struct wl_resource *surface, Ecore_Event_Key *ev, struct wl_resource **delivered_surface);
+
+static Eina_Bool _e_keyrouter_is_key_grabbed(int key);
+static Eina_Bool _e_keyrouter_check_top_visible_window(E_Client *ec_focus, int arr_idx);
+
+static Eina_Bool
+_e_keyrouter_is_key_grabbed(int key)
+{
+   if (!krt->HardKeys[key].keycode)
+     {
+        return EINA_FALSE;
+     }
+   if (krt->HardKeys[key].excl_ptr ||
+        krt->HardKeys[key].or_excl_ptr ||
+        krt->HardKeys[key].top_ptr ||
+        krt->HardKeys[key].shared_ptr)
+     {
+        return EINA_TRUE;
+     }
+
+   return EINA_FALSE;
+}
+
+static Eina_Bool
+_e_keyrouter_event_routed_key_check(Ecore_Event_Key *ev, int type)
+{
+   if (ev->data)
+     {
+        KLDBG("data is exist send to compositor: %p", ev->data);
+        return EINA_FALSE;
+     }
+
+   if (ev->modifiers != 0)
+     {
+        KLDBG("Modifier key delivered to Focus window : Key %s(%d)", ((ECORE_EVENT_KEY_DOWN == type) ? "Down" : "Up"), ev->keycode);
+        return EINA_FALSE;
+     }
+
+   if (krt->max_tizen_hwkeys < ev->keycode)
+     {
+        KLWRN("The key(%d) is too larger to process keyrouting: Invalid keycode", ev->keycode);
+        return EINA_FALSE;
+     }
+
+   if (!krt->HardKeys[ev->keycode].keycode) return EINA_FALSE;
+
+   return EINA_TRUE;
+}
+
+/* Function for checking the existing grab for a key and sending key event(s) */
+Eina_Bool
+e_keyrouter_event_process(void *event, int type)
+{
+   Eina_Bool res = EINA_FALSE;
+   Ecore_Event_Key *ev = event;
+
+   KLDBG("[%s] keyname: %s, key: %s, keycode: %d", (type == ECORE_EVENT_KEY_DOWN) ? "KEY_PRESS" : "KEY_RELEASE", ev->keyname, ev->key, ev->keycode);
+
+   e_screensaver_notidle();
+
+   if (!_e_keyrouter_event_routed_key_check(event, type))
+     {
+        goto finish;
+     }
+
+   if (!e_keyrouter_intercept_hook_call(E_KEYROUTER_INTERCEPT_HOOK_BEFORE_KEYROUTING, type, ev))
+     {
+        goto finish;
+     }
+
+   if ((ECORE_EVENT_KEY_UP == type) && (!krt->HardKeys[ev->keycode].press_ptr))
+     {
+        KLDBG("The release key(%d) isn't a processed by keyrouter!", ev->keycode);
+        goto finish;
+     }
+
+   //KLDBG("The key(%d) is going to be sent to the proper wl client(s) !", ev->keycode);
+   KLDBG("[%s] keyname: %s, key: %s, keycode: %d", (type == ECORE_EVENT_KEY_DOWN) ? "KEY_PRESS" : "KEY_RELEASE", ev->keyname, ev->key, ev->keycode);
+   res = _e_keyrouter_send_key_events(type, ev);
+   if (res) return EINA_FALSE;
+
+finish:
+   res = e_comp_wl_key_process(event, type);
+   return res;
+}
+
+/* Function for sending key events to wl_client(s) */
+static Eina_Bool
+_e_keyrouter_send_key_events(int type, Ecore_Event_Key *ev)
+{
+   Eina_Bool res;
+   if (ECORE_EVENT_KEY_DOWN == type)
+     {
+        res = _e_keyrouter_send_key_events_press(type, ev);
+     }
+  else
+     {
+        res = _e_keyrouter_send_key_events_release(type, ev);
+     }
+  return res;
+}
+
+static Eina_Bool
+_e_keyrouter_send_key_events_release(int type, Ecore_Event_Key *ev)
+{
+   int pid = 0;
+   char *pname = NULL, *cmd = NULL;
+   E_Keyrouter_Key_List_NodePtr key_node_data;
+   Eina_Bool res = EINA_TRUE, ret = EINA_TRUE;
+
+   /* Deliver release  clean up pressed key list */
+   EINA_LIST_FREE(krt->HardKeys[ev->keycode].press_ptr, key_node_data)
+     {
+        if (key_node_data->status == E_KRT_CSTAT_ALIVE)
+          {
+             res = _e_keyrouter_send_key_event(type, key_node_data->surface, key_node_data->wc, ev,
+                                               key_node_data->focused, TIZEN_KEYROUTER_MODE_PRESSED);
+
+             pid = e_keyrouter_util_get_pid(key_node_data->wc, key_node_data->surface);
+             cmd = e_keyrouter_util_cmd_get_from_pid(pid);
+             pname = e_keyrouter_util_process_name_get_from_cmd(cmd);
+             KLINF("Release Pair : %s(%s:%d)(Focus: %d)(Status: %d) => wl_surface (%p) wl_client (%p) (pid: %d) (pname: %s)",
+                      ((ECORE_EVENT_KEY_DOWN == type) ? "Down" : "Up"), ev->keyname, ev->keycode, key_node_data->focused,
+                      key_node_data->status, key_node_data->surface, key_node_data->wc, pid, pname ?: "Unknown");
+             if(pname) E_FREE(pname);
+             if(cmd) E_FREE(cmd);
+          }
+        else
+          {
+             if (key_node_data->focused == EINA_TRUE)
+               {
+                  res = EINA_FALSE;
+                  if (key_node_data->status == E_KRT_CSTAT_DEAD)
+                    {
+                       ev->data = key_node_data->wc;
+                    }
+                  else
+                    {
+                       ev->data = (void *)0x1;
+                    }
+               }
+             KLINF("Release Pair : %s(%s:%d)(Focus: %d)(Status: %d) => wl_surface (%p) wl_client (%p) process is ungrabbed / dead",
+                      ((ECORE_EVENT_KEY_DOWN == type) ? "Down" : "Up"), ev->keyname, ev->keycode, key_node_data->focused,
+                      key_node_data->status, key_node_data->surface, key_node_data->wc);
+          }
+
+        E_FREE(key_node_data);
+        if (res == EINA_FALSE) ret = EINA_FALSE;
+     }
+   krt->HardKeys[ev->keycode].press_ptr = NULL;
+
+   return ret;
+}
+
+static Eina_Bool
+_e_keyrouter_send_key_events_press(int type, Ecore_Event_Key *ev)
+{
+   unsigned int keycode = ev->keycode;
+   struct wl_resource *surface_focus = NULL;
+   E_Client *ec_focus = NULL;
+   struct wl_resource *delivered_surface = NULL;
+   Eina_Bool res = EINA_TRUE;
+   int pid = 0;
+   char *pname = NULL, *cmd = NULL;
+
+   E_Keyrouter_Key_List_NodePtr key_node_data;
+   Eina_List *l = NULL;
+
+   ec_focus = e_client_focused_get();
+   surface_focus = e_keyrouter_util_get_surface_from_eclient(ec_focus);
+
+   if (krt->isPictureOffEnabled == 1)
+     {
+       EINA_LIST_FOREACH(krt->HardKeys[keycode].pic_off_ptr, l, key_node_data)
+          {
+            if (key_node_data)
+                {
+                 res = _e_keyrouter_send_key_event(type, key_node_data->surface, key_node_data->wc, ev, key_node_data->focused, TIZEN_KEYROUTER_MODE_SHARED);
+
+                 pid = e_keyrouter_util_get_pid(key_node_data->wc, key_node_data->surface);
+                 cmd = e_keyrouter_util_cmd_get_from_pid(pid);
+                 pname = e_keyrouter_util_process_name_get_from_cmd(cmd);
+                 KLINF("PICTURE OFF : %s(%d) => wl_surface (%p) wl_client (%p) (pid: %d) (pname: %s)",
+                       ((ECORE_EVENT_KEY_DOWN == type) ? "Down" : "Up"), ev->keycode, key_node_data->surface, key_node_data->wc, pid, pname ?: "Unknown");
+                 if(pname) E_FREE(pname);
+                 if(cmd) E_FREE(cmd);
+                }
+          }
+       return res;
+     }
+   if (!_e_keyrouter_is_key_grabbed(ev->keycode))
+     {
+        return res;
+     }
+
+   EINA_LIST_FOREACH(krt->HardKeys[keycode].excl_ptr, l, key_node_data)
+     {
+        if (key_node_data)
+          {
+             res = _e_keyrouter_send_key_event(type, key_node_data->surface, key_node_data->wc, ev,
+                                               key_node_data->focused, TIZEN_KEYROUTER_MODE_EXCLUSIVE);
+
+             pid = e_keyrouter_util_get_pid(key_node_data->wc, key_node_data->surface);
+             cmd = e_keyrouter_util_cmd_get_from_pid(pid);
+             pname = e_keyrouter_util_process_name_get_from_cmd(cmd);
+             KLINF("EXCLUSIVE : %s(%s:%d) => wl_surface (%p) wl_client (%p) (pid: %d) (pname: %s)",
+                      ((ECORE_EVENT_KEY_DOWN == type) ? "Down" : "Up"), ev->keyname, ev->keycode,
+                      key_node_data->surface, key_node_data->wc, pid, pname ?: "Unknown");
+             if(pname) E_FREE(pname);
+             if(cmd) E_FREE(cmd);
+             return res;
+          }
+     }
+
+   EINA_LIST_FOREACH(krt->HardKeys[keycode].or_excl_ptr, l, key_node_data)
+     {
+        if (key_node_data)
+          {
+             res = _e_keyrouter_send_key_event(type, key_node_data->surface, key_node_data->wc, ev,
+                                               key_node_data->focused, TIZEN_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE);
+
+             pid = e_keyrouter_util_get_pid(key_node_data->wc, key_node_data->surface);
+             cmd = e_keyrouter_util_cmd_get_from_pid(pid);
+             pname = e_keyrouter_util_process_name_get_from_cmd(cmd);
+             KLINF("OVERRIDABLE_EXCLUSIVE : %s(%s:%d) => wl_surface (%p) wl_client (%p) (pid: %d) (pname: %s)",
+                     ((ECORE_EVENT_KEY_DOWN == type) ? "Down" : "Up"), ev->keyname, ev->keycode,
+                     key_node_data->surface, key_node_data->wc, pid, pname ?: "Unknown");
+             if(pname) E_FREE(pname);
+             if(cmd) E_FREE(cmd);
+
+             return res;
+          }
+     }
+
+   // Top position grab must need a focus surface.
+   if (surface_focus)
+     {
+        EINA_LIST_FOREACH(krt->HardKeys[keycode].top_ptr, l, key_node_data)
+          {
+             if (key_node_data)
+               {
+                  if ((EINA_FALSE == krt->isWindowStackChanged) && (surface_focus == key_node_data->surface))
+                    {
+                       pid = e_keyrouter_util_get_pid(key_node_data->wc, key_node_data->surface);
+                       cmd = e_keyrouter_util_cmd_get_from_pid(pid);
+                       pname = e_keyrouter_util_process_name_get_from_cmd(cmd);
+
+                       res = _e_keyrouter_send_key_event(type, key_node_data->surface, NULL, ev, key_node_data->focused,
+                                                         TIZEN_KEYROUTER_MODE_TOPMOST);
+                       KLINF("TOPMOST (TOP_POSITION) : %s (%s:%d) => wl_surface (%p) (pid: %d) (pname: %s)",
+                                ((ECORE_EVENT_KEY_DOWN == type) ? "Down" : "Up"), ev->keyname, ev->keycode,
+                                key_node_data->surface, pid, pname ?: "Unknown");
+
+                       if(pname) E_FREE(pname);
+                       if(cmd) E_FREE(cmd);
+                       return res;
+                    }
+                  krt->isWindowStackChanged = EINA_FALSE;
+
+                  if (_e_keyrouter_check_top_visible_window(ec_focus, keycode))
+                    {
+                       E_Keyrouter_Key_List_NodePtr top_key_node_data = eina_list_data_get(krt->HardKeys[keycode].top_ptr);
+                       pid = e_keyrouter_util_get_pid(top_key_node_data->wc, top_key_node_data->surface);
+                       cmd = e_keyrouter_util_cmd_get_from_pid(pid);
+                       pname = e_keyrouter_util_process_name_get_from_cmd(cmd);
+
+                       res = _e_keyrouter_send_key_event(type, top_key_node_data->surface, NULL, ev, top_key_node_data->focused,
+                                                         TIZEN_KEYROUTER_MODE_TOPMOST);
+                       KLINF("TOPMOST (TOP_POSITION) : %s (%s:%d) => wl_surface (%p) (pid: %d) (pname: %s)",
+                             ((ECORE_EVENT_KEY_DOWN == type) ? "Down" : "Up"), ev->keyname, ev->keycode,
+                             top_key_node_data->surface, pid, pname ?: "Unknown");
+
+                       if(pname) E_FREE(pname);
+                       if(cmd) E_FREE(cmd);
+                       return res;
+                    }
+                  break;
+               }
+          }
+       goto need_shared;
+     }
+
+   if (krt->HardKeys[keycode].shared_ptr)
+     {
+need_shared:
+        res = _e_keyrouter_send_key_events_focus(type, surface_focus, ev, &delivered_surface);
+        if (delivered_surface)
+          {
+             res = e_keyrouter_wl_add_surface_destroy_listener(delivered_surface);
+             if (res != TIZEN_KEYROUTER_ERROR_NONE)
+               {
+                  KLWRN("Failed to add wl_surface to destroy listener (res: %d)", res);
+               }
+          }
+        EINA_LIST_FOREACH(krt->HardKeys[keycode].shared_ptr, l, key_node_data)
+          {
+             if (key_node_data)
+               {
+                  if (delivered_surface && key_node_data->surface == delivered_surface)
+                    {
+                       // Check for already delivered surface
+                       // do not deliver double events in this case.
+                       continue;
+                    }
+                  else
+                    {
+                       _e_keyrouter_send_key_event(type, key_node_data->surface, key_node_data->wc, ev, key_node_data->focused, TIZEN_KEYROUTER_MODE_SHARED);
+                       pid = e_keyrouter_util_get_pid(key_node_data->wc, key_node_data->surface);
+                       cmd = e_keyrouter_util_cmd_get_from_pid(pid);
+                       pname = e_keyrouter_util_process_name_get_from_cmd(cmd);
+                       KLINF("SHARED : %s(%s:%d) => wl_surface (%p) wl_client (%p) (pid: %d) (pname: %s)",
+                             ((ECORE_EVENT_KEY_DOWN == type) ? "Down" : "Up"), ev->keyname, ev->keycode, key_node_data->surface, key_node_data->wc, pid, pname ?: "Unknown");
+                       if(pname) E_FREE(pname);
+                       if(cmd) E_FREE(cmd);
+                    }
+               }
+          }
+        return res;
+     }
+
+   return EINA_FALSE;
+}
+
+static Eina_Bool
+_e_keyrouter_send_key_events_focus(int type, struct wl_resource *surface_focus,  Ecore_Event_Key *ev, struct wl_resource **delivered_surface)
+{
+   Eina_Bool res = EINA_TRUE;
+   int pid = 0;
+   char *pname = NULL, *cmd = NULL;
+
+   if (!e_keyrouter_intercept_hook_call(E_KEYROUTER_INTERCEPT_HOOK_DELIVER_FOCUS, type, ev))
+     {
+        if (ev->data)
+          {
+             *delivered_surface = ev->data;
+             ev->data = wl_resource_get_client(ev->data);
+          }
+        return res;
+     }
+
+   pid = e_keyrouter_util_get_pid(NULL, surface_focus);
+   cmd = e_keyrouter_util_cmd_get_from_pid(pid);
+   pname = e_keyrouter_util_process_name_get_from_cmd(cmd);
+
+   res = _e_keyrouter_send_key_event(type, surface_focus, NULL,ev, EINA_TRUE, TIZEN_KEYROUTER_MODE_SHARED);
+   KLINF("FOCUS DIRECT : %s(%s:%d) => wl_surface (%p) (pid: %d) (pname: %s)",
+         ((ECORE_EVENT_KEY_DOWN == type) ? "Down" : "Up"), ev->keyname, ev->keycode, surface_focus, pid, pname ?: "Unknown");
+   *delivered_surface = surface_focus;
+   if(pname) E_FREE(pname);
+   if(cmd) E_FREE(cmd);
+   return res;
+}
+
+static Eina_Bool
+_e_keyrouter_check_top_visible_window(E_Client *ec_focus, int arr_idx)
+{
+   E_Client *ec_top = NULL;
+   Eina_List *l = NULL, *l_next = NULL;
+   E_Keyrouter_Key_List_NodePtr key_node_data = NULL;
+
+   ec_top = e_client_top_get();
+
+   while (ec_top)
+     {
+        if (!ec_top->visible && ec_top == ec_focus)
+          {
+             KLDBG("Top e_client (%p) is invisible(%d) but focus client", ec_top, ec_top->visible);
+             return EINA_FALSE;
+          }
+        if (!ec_top->visible)
+          {
+             ec_top = e_client_below_get(ec_top);
+             continue;
+          }
+
+        /* TODO: Check this client is located inside a display boundary */
+
+        EINA_LIST_FOREACH_SAFE(krt->HardKeys[arr_idx].top_ptr, l, l_next, key_node_data)
+          {
+             if (key_node_data)
+               {
+                  if (ec_top == wl_resource_get_user_data(key_node_data->surface))
+                    {
+                       krt->HardKeys[arr_idx].top_ptr = eina_list_promote_list(krt->HardKeys[arr_idx].top_ptr, l);
+                       KLDBG("Move a client(e_client: %p, wl_surface: %p) to first index of list(key: %d)",
+                                ec_top, key_node_data->surface, arr_idx);
+                       return EINA_TRUE;
+                    }
+               }
+          }
+
+        if (ec_top == ec_focus)
+          {
+             KLDBG("The e_client(%p) is a focus client", ec_top);
+             return EINA_FALSE;
+          }
+
+        ec_top = e_client_below_get(ec_top);
+     }
+   return EINA_FALSE;
+}
+
+/* Function for sending key event to wl_client(s) */
+static Eina_Bool
+_e_keyrouter_send_key_event(int type, struct wl_resource *surface, struct wl_client *wc, Ecore_Event_Key *ev, Eina_Bool focused, unsigned int mode)
+{
+   struct wl_client *wc_send;
+   Eina_Bool pressed = EINA_FALSE;
+
+   if (surface == NULL) wc_send = wc;
+   else wc_send = wl_resource_get_client(surface);
+
+   if (!wc_send)
+     {
+        KLWRN("wl_surface: %p or wl_client: %p returns null wayland client", surface, wc);
+        return EINA_FALSE;
+     }
+
+   if (ECORE_EVENT_KEY_DOWN == type)
+     {
+        pressed = EINA_TRUE;
+        e_keyrouter_prepend_to_keylist(surface, wc, ev->keycode, TIZEN_KEYROUTER_MODE_PRESSED, focused);
+     }
+
+   e_keyrouter_wl_key_send(ev, pressed, wc_send, surface, focused);
+
+   return EINA_TRUE;
+}
+
+struct wl_resource *
+e_keyrouter_util_get_surface_from_eclient(E_Client *client)
+{
+   if (!client || !client->comp_data) return NULL;
+
+   return client->comp_data->wl_surface;
+}
+
+int
+e_keyrouter_util_get_pid(struct wl_client *client, struct wl_resource *surface)
+{
+   pid_t pid = 0;
+   uid_t uid = 0;
+   gid_t gid = 0;
+   struct wl_client *cur_client = NULL;
+
+   if (client) cur_client = client;
+   else if (surface) cur_client = wl_resource_get_client(surface);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(cur_client, 0);
+
+   wl_client_get_credentials(cur_client, &pid, &uid, &gid);
+
+   return pid;
+}
+
+char *
+e_keyrouter_util_cmd_get_from_pid(int pid)
+{
+   Eina_List *l;
+   E_Comp_Connected_Client_Info *cdata;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp, NULL);
+
+   EINA_LIST_FOREACH(e_comp->connected_clients, l, cdata)
+     {
+        if (cdata->pid == pid) return strdup(cdata->name);
+     }
+
+   return NULL;
+}
+
+typedef struct _keycode_map{
+    xkb_keysym_t keysym;
+    xkb_keycode_t keycode;
+}keycode_map;
+
+static void
+find_keycode(struct xkb_keymap *keymap, xkb_keycode_t key, void *data)
+{
+   keycode_map *found_keycodes = (keycode_map *)data;
+   xkb_keysym_t keysym = found_keycodes->keysym;
+   int nsyms = 0;
+   const xkb_keysym_t *syms_out = NULL;
+
+   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;
+          }
+     }
+}
+
+int
+_e_keyrouter_keycode_get_from_keysym(struct xkb_keymap *keymap, xkb_keysym_t keysym)
+{
+   keycode_map found_keycodes = {0,};
+   found_keycodes.keysym = keysym;
+   xkb_keymap_key_for_each(keymap, find_keycode, &found_keycodes);
+
+   return found_keycodes.keycode;
+}
+
+int
+e_keyrouter_util_keycode_get_from_string(char * name)
+{
+   struct xkb_keymap *keymap = NULL;
+   xkb_keysym_t keysym = 0x0;
+   int keycode = 0;
+
+   keymap = e_comp_wl->xkb.keymap;
+   EINA_SAFETY_ON_NULL_GOTO(keymap, finish);
+
+   keysym = xkb_keysym_from_name(name, XKB_KEYSYM_NO_FLAGS);
+   EINA_SAFETY_ON_FALSE_GOTO(keysym != XKB_KEY_NoSymbol, finish);
+
+   keycode = _e_keyrouter_keycode_get_from_keysym(keymap, keysym);
+
+   KLDBG("request name: %s, return value: %d", name, keycode);
+
+   return keycode;
+
+finish:
+   return 0;
+}
+
+char *
+e_keyrouter_util_keyname_get_from_keycode(int keycode)
+{
+   struct xkb_state *state;
+   xkb_keysym_t sym = XKB_KEY_NoSymbol;
+   char name[256] = {0, };
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp_wl, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp_wl->xkb.state, NULL);
+
+   state = e_comp_wl->xkb.state;
+   sym = xkb_state_key_get_one_sym(state, keycode);
+   xkb_keysym_get_name(sym, name, sizeof(name));
+
+   return strdup(name);
+}
+
+char *
+e_keyrouter_util_process_name_get_from_cmd(char *cmd)
+{
+   int len, i;
+   char pbuf = '\0';
+   char *pname = NULL;
+   if (cmd)
+     {
+        len = strlen(cmd);
+        for (i = 0; i < len; i++)
+          {
+             pbuf = cmd[len - i - 1];
+             if (pbuf == '/')
+               {
+                  pname = &cmd[len - i];
+                  return strdup(pname);
+               }
+          }
+     }
+   return NULL;
+}
+
diff --git a/src/bin/e_keyrouter_list.c b/src/bin/e_keyrouter_list.c
new file mode 100644 (file)
index 0000000..61a6444
--- /dev/null
@@ -0,0 +1,543 @@
+#include "e_keyrouter_private.h"
+
+static int _e_keyrouter_find_duplicated_client(struct wl_resource *surface, struct wl_client *wc, uint32_t key, uint32_t mode);
+static Eina_Bool _e_keyrouter_find_key_in_list(struct wl_resource *surface, struct wl_client *wc, int key, int mode);
+static Eina_List **_e_keyrouter_get_list(int mode, int key);
+
+/* add a new key grab info to the list */
+int
+e_keyrouter_set_keygrab_in_list(struct wl_resource *surface, struct wl_client *client, uint32_t key, uint32_t mode)
+{
+   int res = TIZEN_KEYROUTER_ERROR_NONE;
+
+   EINA_SAFETY_ON_FALSE_RETURN_VAL
+     (((mode == TIZEN_KEYROUTER_MODE_EXCLUSIVE) ||
+       (mode == TIZEN_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE) ||
+       (mode == TIZEN_KEYROUTER_MODE_TOPMOST) ||
+       (mode == TIZEN_KEYROUTER_MODE_SHARED)),
+      TIZEN_KEYROUTER_ERROR_INVALID_MODE);
+
+   if (mode == TIZEN_KEYROUTER_MODE_EXCLUSIVE)
+     {
+        EINA_SAFETY_ON_TRUE_RETURN_VAL
+          ((krt->HardKeys[key].excl_ptr != NULL),
+           TIZEN_KEYROUTER_ERROR_GRABBED_ALREADY);
+     }
+
+   if (mode == TIZEN_KEYROUTER_MODE_TOPMOST)
+     {
+        EINA_SAFETY_ON_NULL_RETURN_VAL
+          (surface, TIZEN_KEYROUTER_ERROR_INVALID_SURFACE);
+     }
+
+   res = e_keyrouter_prepend_to_keylist(surface,
+                                   surface ? NULL : client,
+                                   key,
+                                   mode,
+                                   EINA_FALSE);
+
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(res == TIZEN_KEYROUTER_ERROR_NONE, res);
+
+   return res;
+}
+
+/* Function for checking whether the key has been grabbed already by the same wl_surface or not */
+static int
+_e_keyrouter_find_duplicated_client(struct wl_resource *surface, struct wl_client *wc, uint32_t key, uint32_t mode)
+{
+   Eina_List *keylist_ptr = NULL, *l = NULL;
+   E_Keyrouter_Key_List_NodePtr key_node_data = NULL;
+
+   switch(mode)
+     {
+      case TIZEN_KEYROUTER_MODE_EXCLUSIVE:
+         return TIZEN_KEYROUTER_ERROR_NONE;
+
+      case TIZEN_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE:
+         keylist_ptr = krt->HardKeys[key].or_excl_ptr;
+         break;
+
+      case TIZEN_KEYROUTER_MODE_TOPMOST:
+         keylist_ptr = krt->HardKeys[key].top_ptr;
+         break;
+
+      case TIZEN_KEYROUTER_MODE_SHARED:
+         keylist_ptr = krt->HardKeys[key].shared_ptr;
+         break;
+
+      case TIZEN_KEYROUTER_MODE_PRESSED:
+         keylist_ptr = krt->HardKeys[key].press_ptr;
+         break;
+
+     case TIZEN_KEYROUTER_MODE_PICTURE_OFF:
+         keylist_ptr = krt->HardKeys[key].pic_off_ptr;
+         break;
+      default:
+         KLWRN("Unknown key(%d) and grab mode(%d)", key, mode);
+         return TIZEN_KEYROUTER_ERROR_INVALID_MODE;
+     }
+
+   EINA_LIST_FOREACH(keylist_ptr, l, key_node_data)
+     {
+        if (!key_node_data) continue;
+
+        if (surface)
+          {
+             if (key_node_data->surface == surface)
+               {
+                  KLDBG("The key(%d) is already grabbed same mode(%s) on the same wl_surface %p",
+                        key, e_keyrouter_mode_to_string(mode), surface);
+                  return TIZEN_KEYROUTER_ERROR_GRABBED_ALREADY;
+               }
+          }
+        else
+          {
+             if (key_node_data->wc == wc)
+               {
+                  KLDBG("The key(%d) is already grabbed same mode(%s) on the same wl_client %p",
+                        key, e_keyrouter_mode_to_string(mode), wc);
+                  return TIZEN_KEYROUTER_ERROR_GRABBED_ALREADY;
+               }
+          }
+     }
+
+   return TIZEN_KEYROUTER_ERROR_NONE;
+}
+
+static Eina_Bool
+_e_keyrouter_find_key_in_list(struct wl_resource *surface, struct wl_client *wc, int key, int mode)
+{
+   Eina_List **list = NULL;
+   Eina_List *l = NULL, *l_next = NULL;
+   E_Keyrouter_Key_List_NodePtr key_node_data = NULL;
+
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(((!surface) && (!wc)), EINA_FALSE);
+
+   list = _e_keyrouter_get_list(mode, key);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(list, EINA_FALSE);
+
+   EINA_LIST_FOREACH_SAFE(*list, l, l_next, key_node_data)
+     {
+        if (!key_node_data) continue;
+
+        if ((surface) && (surface == key_node_data->surface)) return EINA_TRUE;
+        else if ((wc == key_node_data->wc)) return EINA_TRUE;
+     }
+
+   return EINA_FALSE;
+}
+
+
+/* Function for prepending a new key grab information in the keyrouting list */
+int
+e_keyrouter_prepend_to_keylist(struct wl_resource *surface, struct wl_client *wc, uint32_t key, uint32_t mode, Eina_Bool focused)
+{
+   int res = TIZEN_KEYROUTER_ERROR_NONE;
+
+   res = _e_keyrouter_find_duplicated_client(surface, wc, key, mode);
+   CHECK_ERR_VAL(res);
+
+   E_Keyrouter_Key_List_NodePtr new_keyptr = E_NEW(E_Keyrouter_Key_List_Node, 1);
+
+   if (!new_keyptr)
+     {
+        KLERR("Failled to allocate memory for new_keyptr");
+        return TIZEN_KEYROUTER_ERROR_NO_SYSTEM_RESOURCES;
+     }
+
+   new_keyptr->surface = surface;
+   new_keyptr->wc = wc;
+   new_keyptr->focused = focused;
+   new_keyptr->status = E_KRT_CSTAT_ALIVE;
+
+   switch(mode)
+     {
+      case TIZEN_KEYROUTER_MODE_EXCLUSIVE:
+         krt->HardKeys[key].excl_ptr = eina_list_prepend(krt->HardKeys[key].excl_ptr, new_keyptr);
+         break;
+
+      case TIZEN_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE:
+         krt->HardKeys[key].or_excl_ptr= eina_list_prepend(krt->HardKeys[key].or_excl_ptr, new_keyptr);
+         break;
+
+      case TIZEN_KEYROUTER_MODE_TOPMOST:
+         krt->HardKeys[key].top_ptr = eina_list_prepend(krt->HardKeys[key].top_ptr, new_keyptr);
+         break;
+
+      case TIZEN_KEYROUTER_MODE_SHARED:
+         krt->HardKeys[key].shared_ptr= eina_list_prepend(krt->HardKeys[key].shared_ptr, new_keyptr);
+         break;
+
+      case TIZEN_KEYROUTER_MODE_PRESSED:
+         krt->HardKeys[key].press_ptr = eina_list_prepend(krt->HardKeys[key].press_ptr, new_keyptr);
+         break;
+
+     case TIZEN_KEYROUTER_MODE_PICTURE_OFF:
+         krt->HardKeys[key].pic_off_ptr = eina_list_prepend(krt->HardKeys[key].pic_off_ptr, new_keyptr);
+         break;
+
+      default:
+         KLWRN("Unknown key(%d) and grab mode(%d)", key, mode);
+         E_FREE(new_keyptr);
+         return TIZEN_KEYROUTER_ERROR_INVALID_MODE;
+     }
+
+   if (TIZEN_KEYROUTER_MODE_PRESSED != mode)
+     {
+        if (surface)
+          {
+             e_keyrouter_wl_add_surface_destroy_listener(surface);
+             /* TODO: if failed add surface_destory_listener, remove keygrabs */
+          }
+        else if (wc)
+          {
+             e_keyrouter_wl_add_client_destroy_listener(wc);
+             /* TODO: if failed add client_destory_listener, remove keygrabs */
+          }
+     }
+
+   return TIZEN_KEYROUTER_ERROR_NONE;
+}
+
+/* remove key grab info from the list */
+void
+e_keyrouter_find_and_remove_client_from_list(struct wl_resource *surface, struct wl_client *wc, uint32_t key, uint32_t mode)
+{
+   Eina_List **list = NULL;
+   Eina_List *l = NULL, *l_next = NULL;
+   E_Keyrouter_Key_List_NodePtr key_node_data = NULL;
+
+   list = _e_keyrouter_get_list(mode, key);
+   EINA_SAFETY_ON_NULL_RETURN(list);
+
+   EINA_LIST_FOREACH_SAFE(*list, l, l_next, key_node_data)
+     {
+        if (!key_node_data) continue;
+
+        if (surface)
+          {
+             if (surface == key_node_data->surface)
+               {
+                  if (mode == TIZEN_KEYROUTER_MODE_PRESSED)
+                    {
+                       key_node_data->status = E_KRT_CSTAT_UNGRAB;
+                    }
+                  else
+                    {
+                       *list = eina_list_remove_list(*list, l);
+                       E_FREE(key_node_data);
+                    }
+                  KLDBG("Remove a %s Mode Grabbed key(%d) by surface(%p)", e_keyrouter_mode_to_string(mode), key, surface);
+               }
+          }
+        else if ((wc == key_node_data->wc))
+          {
+             if (mode == TIZEN_KEYROUTER_MODE_PRESSED)
+               {
+                  key_node_data->status = E_KRT_CSTAT_UNGRAB;
+               }
+             else
+               {
+                  *list = eina_list_remove_list(*list, l);
+                  E_FREE(key_node_data);
+               }
+             KLDBG("Remove a %s Mode Grabbed key(%d) by wc(%p)", e_keyrouter_mode_to_string(mode), key, wc);
+          }
+     }
+}
+
+void
+e_keyrouter_remove_client_from_list(struct wl_resource *surface, struct wl_client *wc)
+{
+   int i = 0;
+   Eina_List *l = NULL, *l_next = NULL;
+   E_Keyrouter_Key_List_NodePtr key_node_data = NULL;
+
+   EINA_SAFETY_ON_TRUE_RETURN(((!surface) && (!wc)));
+
+   for (i = 0; i < krt->max_tizen_hwkeys; i++)
+     {
+        if (0 == krt->HardKeys[i].keycode) continue;
+
+        EINA_LIST_FOREACH_SAFE(krt->HardKeys[i].excl_ptr, l, l_next, key_node_data)
+          {
+             if (!key_node_data) continue;
+
+             if (surface)
+               {
+                  if (surface == key_node_data->surface)
+                    {
+                       krt->HardKeys[i].excl_ptr = eina_list_remove_list(krt->HardKeys[i].excl_ptr, l);
+                       E_FREE(key_node_data);
+                       KLDBG("Remove a Exclusive Mode Grabbed key(%d) by wl_surface(%p)", i, surface);
+                    }
+               }
+             else if ((wc == key_node_data->wc))
+               {
+                  krt->HardKeys[i].excl_ptr = eina_list_remove_list(krt->HardKeys[i].excl_ptr, l);
+                  E_FREE(key_node_data);
+                  KLDBG("Remove a Exclusive Mode Grabbed key(%d) by wl_client(%p)", i, wc);
+               }
+          }
+        EINA_LIST_FOREACH_SAFE(krt->HardKeys[i].or_excl_ptr, l, l_next, key_node_data)
+          {
+             if (!key_node_data) continue;
+
+             if (surface)
+               {
+                  if (surface == key_node_data->surface)
+                    {
+                       krt->HardKeys[i].or_excl_ptr = eina_list_remove_list(krt->HardKeys[i].or_excl_ptr, l);
+                       E_FREE(key_node_data);
+                       KLDBG("Remove a Overridable_Exclusive Mode Grabbed key(%d) by wl_surface(%p)", i, surface);
+                    }
+               }
+             else if ((wc == key_node_data->wc))
+               {
+                  krt->HardKeys[i].or_excl_ptr = eina_list_remove_list(krt->HardKeys[i].or_excl_ptr, l);
+                  E_FREE(key_node_data);
+                  KLDBG("Remove a Overridable_Exclusive Mode Grabbed key(%d) by wl_client(%p)", i, wc);
+               }
+          }
+        EINA_LIST_FOREACH_SAFE(krt->HardKeys[i].top_ptr, l, l_next, key_node_data)
+          {
+             if (!key_node_data) continue;
+
+             if (surface)
+               {
+                  if (surface == key_node_data->surface)
+                    {
+                       krt->HardKeys[i].top_ptr = eina_list_remove_list(krt->HardKeys[i].top_ptr, l);
+                       E_FREE(key_node_data);
+                       KLDBG("Remove a Topmost Mode Grabbed key(%d) by wl_surface(%p)", i, surface);
+                    }
+               }
+             else if ((wc == key_node_data->wc))
+               {
+                  krt->HardKeys[i].top_ptr = eina_list_remove_list(krt->HardKeys[i].top_ptr, l);
+                  E_FREE(key_node_data);
+                  KLDBG("Remove a Topmost Mode Grabbed key(%d) by wl_client(%p)", i, wc);
+               }
+          }
+        EINA_LIST_FOREACH_SAFE(krt->HardKeys[i].shared_ptr, l, l_next, key_node_data)
+          {
+             if (!key_node_data) continue;
+
+             if (surface)
+               {
+                  if (surface == key_node_data->surface)
+                    {
+                       krt->HardKeys[i].shared_ptr = eina_list_remove_list(krt->HardKeys[i].shared_ptr, l);
+                       E_FREE(key_node_data);
+                       KLDBG("Remove a Shared Mode Grabbed key(%d) by wl_surface(%p)", i, surface);
+                    }
+               }
+             else if ((wc == key_node_data->wc))
+               {
+                  krt->HardKeys[i].shared_ptr = eina_list_remove_list(krt->HardKeys[i].shared_ptr, l);
+                  E_FREE(key_node_data);
+                  KLDBG("Remove a Shared Mode Grabbed key(%d) by wl_client(%p)", i, wc);
+               }
+          }
+        EINA_LIST_FOREACH_SAFE(krt->HardKeys[i].press_ptr, l, l_next, key_node_data)
+          {
+             if (!key_node_data) continue;
+
+             if (surface)
+               {
+                  if (surface == key_node_data->surface)
+                    {
+                       key_node_data->status = E_KRT_CSTAT_DEAD;
+                       KLDBG("Remove a Pressed  key(%d) by wl_surface(%p)", i, surface);
+                       key_node_data->wc = wl_resource_get_client(surface);
+                    }
+               }
+             else if ((wc == key_node_data->wc))
+               {
+                  key_node_data->status = E_KRT_CSTAT_DEAD;
+                  KLDBG("Remove a Pressed key(%d) by wl_client(%p)", i, wc);
+               }
+          }
+        EINA_LIST_FOREACH_SAFE(krt->HardKeys[i].pic_off_ptr, l, l_next, key_node_data)
+          {
+             if (!key_node_data) continue;
+             if (surface)
+               {
+                  if (surface == key_node_data->surface)
+                    {
+                       krt->HardKeys[i].pic_off_ptr = eina_list_remove_list(krt->HardKeys[i].pic_off_ptr, l);
+                       E_FREE(key_node_data);
+                    }
+               }
+             else if ( wc == key_node_data->wc)
+               {
+                  krt->HardKeys[i].pic_off_ptr = eina_list_remove_list(krt->HardKeys[i].pic_off_ptr, l);
+                  E_FREE(key_node_data);
+               }
+          }
+     }
+}
+
+int
+e_keyrouter_find_key_in_list(struct wl_resource *surface, struct wl_client *wc, uint32_t key)
+{
+   int mode = TIZEN_KEYROUTER_MODE_NONE;
+   Eina_Bool found = EINA_FALSE;
+
+   mode = TIZEN_KEYROUTER_MODE_EXCLUSIVE;
+   found = _e_keyrouter_find_key_in_list(surface, wc, key, mode);
+   if (found) goto finish;
+
+   mode = TIZEN_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE;
+   found = _e_keyrouter_find_key_in_list(surface, wc, key, mode);
+   if (found) goto finish;
+
+   mode = TIZEN_KEYROUTER_MODE_TOPMOST;
+   found = _e_keyrouter_find_key_in_list(surface, wc, key, mode);
+   if (found) goto finish;
+
+   mode = TIZEN_KEYROUTER_MODE_SHARED;
+   found = _e_keyrouter_find_key_in_list(surface, wc, key, mode);
+   if (found) goto finish;
+
+   KLDBG("%d key is not grabbed by (wl_surface: %p, wl_client: %p)", key, surface, wc);
+   return TIZEN_KEYROUTER_MODE_NONE;
+
+finish:
+   KLDBG("Find %d key grabbed by (wl_surface: %p, wl_client: %p) in %s mode",
+         key, surface, wc, e_keyrouter_mode_to_string(mode));
+   return mode;
+}
+
+const char *
+e_keyrouter_mode_to_string(uint32_t mode)
+{
+   const char *str = NULL;
+
+   switch (mode)
+     {
+      case TIZEN_KEYROUTER_MODE_EXCLUSIVE:             str = "Exclusive";             break;
+      case TIZEN_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE: str = "Overridable_Exclusive"; break;
+      case TIZEN_KEYROUTER_MODE_TOPMOST:               str = "Topmost";               break;
+      case TIZEN_KEYROUTER_MODE_SHARED:                str = "Shared";                break;
+      case TIZEN_KEYROUTER_MODE_PRESSED:               str = "Pressed";               break;
+      default: str = "UnknownMode"; break;
+     }
+
+   return str;
+}
+
+static Eina_List **
+_e_keyrouter_get_list(int mode, int key)
+{
+   Eina_List **list = NULL;
+
+   switch (mode)
+     {
+        case TIZEN_KEYROUTER_MODE_EXCLUSIVE:             list = &krt->HardKeys[key].excl_ptr;    break;
+        case TIZEN_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE: list = &krt->HardKeys[key].or_excl_ptr; break;
+        case TIZEN_KEYROUTER_MODE_TOPMOST:               list = &krt->HardKeys[key].top_ptr;     break;
+        case TIZEN_KEYROUTER_MODE_SHARED:                list = &krt->HardKeys[key].shared_ptr;  break;
+        case TIZEN_KEYROUTER_MODE_PRESSED:                list = &krt->HardKeys[key].press_ptr;  break;
+        default: break;
+     }
+
+   return list;
+}
+
+
+int
+e_keyrouter_keygrab_set(struct wl_client *client, struct wl_resource *surface, int key, int mode)
+{
+   int res=0;
+
+#ifdef HAVE_CYNARA
+   if (EINA_FALSE == e_keyrouter_wl_util_do_privilege_check(client, mode, key))
+     {
+        KLINF("No permission for %d grab mode ! (key=%d)", mode, key);
+        return TIZEN_KEYROUTER_ERROR_NO_PERMISSION;
+     }
+#endif
+
+   if (!surface)
+     {
+        /* Regarding topmost mode, a client must request to grab a key with a valid surface. */
+        if (mode == TIZEN_KEYROUTER_MODE_TOPMOST)
+          {
+             KLWRN("Invalid surface for %d grab mode ! (key=%d)", mode, key);
+
+             return TIZEN_KEYROUTER_ERROR_INVALID_SURFACE;
+          }
+     }
+
+   /* Check the given key range */
+   if (krt->max_tizen_hwkeys < key)
+     {
+        KLWRN("Invalid range of key ! (keycode:%d)", key);
+        return TIZEN_KEYROUTER_ERROR_INVALID_KEY;
+     }
+
+   /* Check whether the key can be grabbed or not !
+    * Only key listed in Tizen key layout file can be grabbed. */
+   if (0 == krt->HardKeys[key].keycode)
+     {
+        KLWRN("Invalid key ! Disabled to grab ! (keycode:%d)", key);
+        return TIZEN_KEYROUTER_ERROR_INVALID_KEY;
+     }
+
+   /* Check whether the request key can be grabbed or not */
+   res = e_keyrouter_set_keygrab_in_list(surface, client, key, mode);
+
+   return res;
+}
+
+int
+e_keyrouter_keygrab_unset(struct wl_client *client, struct wl_resource *surface, int key)
+{
+   /* Ungrab top position grabs first. This grab mode do not need privilege */
+   if (!surface)
+     e_keyrouter_find_and_remove_client_from_list(NULL, client, key, TIZEN_KEYROUTER_MODE_TOPMOST);
+   else
+     e_keyrouter_find_and_remove_client_from_list(surface, client, key, TIZEN_KEYROUTER_MODE_TOPMOST);
+
+#ifdef HAVE_CYNARA
+   if (EINA_FALSE == e_keyrouter_wl_util_do_privilege_check(client, TIZEN_KEYROUTER_MODE_NONE, key))
+     {
+        goto finish;
+     }
+#endif
+
+   if (!surface)
+     {
+        /* EXCLUSIVE grab */
+        e_keyrouter_find_and_remove_client_from_list(NULL, client, key, TIZEN_KEYROUTER_MODE_EXCLUSIVE);
+
+        /* OVERRIDABLE_EXCLUSIVE grab */
+        e_keyrouter_find_and_remove_client_from_list(NULL, client, key, TIZEN_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE);
+
+        /* SHARED grab */
+        e_keyrouter_find_and_remove_client_from_list(NULL, client, key, TIZEN_KEYROUTER_MODE_SHARED);
+
+        /* Press List */
+        e_keyrouter_find_and_remove_client_from_list(NULL, client, key, TIZEN_KEYROUTER_MODE_PRESSED);
+     }
+   else
+     {
+        /* EXCLUSIVE grab */
+        e_keyrouter_find_and_remove_client_from_list(surface, client, key, TIZEN_KEYROUTER_MODE_EXCLUSIVE);
+
+        /* OVERRIDABLE_EXCLUSIVE grab */
+        e_keyrouter_find_and_remove_client_from_list(surface, client, key, TIZEN_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE);
+
+        /* SHARED grab */
+        e_keyrouter_find_and_remove_client_from_list(surface, client, key, TIZEN_KEYROUTER_MODE_SHARED);
+
+        /* Press List */
+        e_keyrouter_find_and_remove_client_from_list(surface, client, key, TIZEN_KEYROUTER_MODE_PRESSED);
+     }
+
+finish:
+   e_keyrouter_keycancel_send(client, surface, key);
+
+   return TIZEN_KEYROUTER_ERROR_NONE;
+}
diff --git a/src/bin/e_keyrouter_private.h b/src/bin/e_keyrouter_private.h
new file mode 100644 (file)
index 0000000..9de7dbd
--- /dev/null
@@ -0,0 +1,119 @@
+#include "e.h"
+#include "e_keyrouter.h"
+#ifdef HAVE_CYNARA
+#include <cynara-session.h>
+#include <cynara-client.h>
+#include <cynara-creds-socket.h>
+#include <sys/smack.h>
+#endif
+#include <tizen-extension-server-protocol.h>
+
+#define CHECK_ERR(val) if (TIZEN_KEYROUTER_ERROR_NONE != val) return;
+#define CHECK_ERR_VAL(val) if (TIZEN_KEYROUTER_ERROR_NONE != val) return val;
+#define CHECK_NULL(val) if (!val) return;
+#define CHECK_NULL_VAL(val) if (!val) return val;
+
+#define KLERR(msg, ARG...) ERR(msg, ##ARG)
+#define KLWRN(msg, ARG...) WRN(msg, ##ARG)
+#define KLINF(msg, ARG...) INF(msg, ##ARG)
+#define KLDBG(msg, ARG...) DBG(msg, ##ARG)
+
+typedef struct _E_Keyrouter E_Keyrouter;
+typedef struct _E_Keyrouter* E_KeyrouterPtr;
+typedef struct _E_Keyrouter_Grab_Request E_Keyrouter_Grab_Request;
+typedef struct _E_Keyrouter_Ungrab_Request E_Keyrouter_Ungrab_Request;
+
+typedef struct _E_Keyrouter_Conf_Edd E_Keyrouter_Conf_Edd;
+typedef struct _E_Keyrouter_Config_Data E_Keyrouter_Config_Data;
+
+#define TIZEN_KEYROUTER_MODE_PRESSED        TIZEN_KEYROUTER_MODE_REGISTERED+1
+#define TIZEN_KEYROUTER_MODE_PICTURE_OFF        TIZEN_KEYROUTER_MODE_REGISTERED+2
+
+typedef unsigned long Time;
+
+extern E_KeyrouterPtr krt;
+
+struct _E_Keyrouter_Conf_Edd
+{
+   int num_keycode;          // The numbers of keyrouted keycodes defined by xkb-tizen-data
+   int max_keycode;          // The max value of keycodes
+   int pictureoff_disabled;  // To disable picture_off feature.
+   Eina_List *KeyList;       // The list of routed key data: E_Keyrouter_Tizen_HWKey
+};
+
+struct _E_Keyrouter_Config_Data
+{
+   E_Config_DD *conf_edd;
+   E_Config_DD *conf_hwkeys_edd;
+   E_Keyrouter_Conf_Edd *conf;
+};
+
+struct _E_Keyrouter
+{
+   struct wl_global *global;
+   Ecore_Event_Filter *ef_handler;
+   Eina_List *handlers;
+   Eina_List *resources;
+
+   E_Keyrouter_Config_Data *conf;
+
+   E_Keyrouter_Grabbed_Key *HardKeys;
+   Eina_List *grab_surface_list;
+   Eina_List *grab_client_list;
+
+   Eina_Bool isWindowStackChanged;
+   int numTizenHWKeys;
+   int max_tizen_hwkeys;
+#ifdef HAVE_CYNARA
+   cynara *p_cynara;
+#endif
+   int isPictureOffEnabled;
+   Eina_Bool pictureoff_disabled;
+};
+
+struct _E_Keyrouter_Grab_Request {
+   int key;
+   int mode;
+   int err;
+};
+
+struct _E_Keyrouter_Ungrab_Request {
+   int key;
+   int err;
+};
+
+int e_keyrouter_set_keygrab_in_list(struct wl_resource *surface, struct wl_client *client, uint32_t key, uint32_t mode);
+int e_keyrouter_prepend_to_keylist(struct wl_resource *surface, struct wl_client *wc, uint32_t key, uint32_t mode, Eina_Bool focused);
+void e_keyrouter_find_and_remove_client_from_list(struct wl_resource *surface, struct wl_client *wc, uint32_t key, uint32_t mode);
+void e_keyrouter_remove_client_from_list(struct wl_resource *surface, struct wl_client *wc);
+int e_keyrouter_find_key_in_list(struct wl_resource *surface, struct wl_client *wc, uint32_t key);
+
+Eina_Bool e_keyrouter_process_key_event(void *event, int type);
+
+struct wl_resource *e_keyrouter_util_get_surface_from_eclient(E_Client *client);
+int e_keyrouter_util_get_pid(struct wl_client *client, struct wl_resource *surface);
+char *e_keyrouter_util_cmd_get_from_pid(int pid);
+int e_keyrouter_util_keycode_get_from_string(char *name);
+char *e_keyrouter_util_keyname_get_from_keycode(int keycode);
+char *e_keyrouter_util_process_name_get_from_cmd(char *cmd);
+const char *e_keyrouter_mode_to_string(uint32_t mode);
+
+void e_keyrouter_conf_init(E_Keyrouter_Config_Data *kconfig);
+void e_keyrouter_conf_deinit(E_Keyrouter_Config_Data *kconfig);
+int e_keyrouter_cb_picture_off(const int option, void *data);
+
+Eina_Bool e_keyrouter_wl_init(void);
+void e_keyrouter_wl_shutdown(void);
+int e_keyrouter_wl_add_client_destroy_listener(struct wl_client *client);
+int e_keyrouter_wl_add_surface_destroy_listener(struct wl_resource *surface);
+#ifdef HAVE_CYNARA
+Eina_Bool e_keyrouter_wl_util_do_privilege_check(struct wl_client *client, uint32_t mode, uint32_t keycode);
+#endif
+
+int e_keyrouter_keygrab_set(struct wl_client *client, struct wl_resource *surface, int key, int mode);
+int e_keyrouter_keygrab_unset(struct wl_client *client, struct wl_resource *surface, int key);
+
+Eina_Bool e_keyrouter_event_process(void *event, int type);
+
+Eina_Bool e_keyrouter_wl_key_send(Ecore_Event_Key *ev, Eina_Bool pressed, struct wl_client *client, struct wl_resource *surface, Eina_Bool focused);
+void e_keyrouter_keycancel_send(struct wl_client *client, struct wl_resource *surface, unsigned int key);
diff --git a/src/bin/e_keyrouter_wl.c b/src/bin/e_keyrouter_wl.c
new file mode 100644 (file)
index 0000000..40cb6d0
--- /dev/null
@@ -0,0 +1,625 @@
+#include "e_keyrouter_private.h"
+
+static void
+_e_keyrouter_wl_key_send(Ecore_Event_Key *ev, enum wl_keyboard_key_state state, Eina_List *key_list, Eina_Bool focused, struct wl_client *client, struct wl_resource *surface)
+{
+   struct wl_resource *res;
+   Eina_List *l;
+   uint32_t serial, keycode;
+   struct wl_client *wc;
+   E_Comp_Config *comp_conf = NULL;
+
+   keycode = (ev->keycode - 8);
+
+   serial = wl_display_next_serial(e_comp_wl->wl.disp);
+
+   comp_conf = e_comp_config_get();
+
+   EINA_LIST_FOREACH(key_list, l, res)
+     {
+        wc = wl_resource_get_client(res);
+        if (!focused && wc != client) continue;
+        TRACE_INPUT_BEGIN(_e_comp_wl_key_send);
+//        _e_comp_wl_send_event_device(client, ev->timestamp, ev->dev, serial);
+
+        if (comp_conf && comp_conf->input_log_enable)
+          INF("[Server] Routed Key %s (time: %d)\n", (state ? "Down" : "Up"), ev->timestamp);
+
+        wl_keyboard_send_key(res, serial, ev->timestamp,
+                             keycode, state);
+        TRACE_INPUT_END();
+     }
+}
+
+Eina_Bool
+e_keyrouter_wl_key_send(Ecore_Event_Key *ev, Eina_Bool pressed, struct wl_client *client, struct wl_resource *surface, Eina_Bool focused)
+{
+   E_Client *ec = NULL;
+   struct wl_client *wc = NULL;
+   uint32_t keycode;
+   enum wl_keyboard_key_state state;
+
+   if ((e_comp->comp_type != E_PIXMAP_TYPE_WL) || (ev->window != e_comp->ee_win))
+     {
+        return EINA_FALSE;
+     }
+
+   keycode = (ev->keycode - 8);
+   if (!(e_comp_wl = e_comp->wl_comp_data))
+     {
+        return EINA_FALSE;
+     }
+
+#ifndef E_RELEASE_BUILD
+   if ((ev->modifiers & ECORE_EVENT_MODIFIER_CTRL) &&
+       ((ev->modifiers & ECORE_EVENT_MODIFIER_ALT) ||
+       (ev->modifiers & ECORE_EVENT_MODIFIER_ALTGR)) &&
+       eina_streq(ev->key, "BackSpace"))
+     {
+        exit(0);
+     }
+#endif
+
+   if (pressed) state = WL_KEYBOARD_KEY_STATE_PRESSED;
+   else state = WL_KEYBOARD_KEY_STATE_RELEASED;
+
+   if (!focused)
+     {
+        _e_keyrouter_wl_key_send(ev, state, e_comp_wl->kbd.resources, EINA_FALSE, client, surface);
+        return EINA_FALSE;
+     }
+
+   if ((!e_client_action_get()) && (!e_comp->input_key_grabs))
+     {
+        ec = e_client_focused_get();
+        if (ec && ec->comp_data && ec->comp_data->surface)
+          {
+             if (e_comp_wl->kbd.focused)
+               {
+                  wc = wl_resource_get_client(ec->comp_data->surface);
+                  _e_keyrouter_wl_key_send(ev, state, e_comp_wl->kbd.focused, EINA_TRUE, wc, surface);
+               }
+
+             /* update modifier state */
+             e_comp_wl_input_keyboard_state_update(keycode, pressed);
+          }
+     }
+   return !!ec;
+}
+
+void
+e_keyrouter_keycancel_send(struct wl_client *client, struct wl_resource *surface, unsigned int key)
+{
+   Eina_List *l;
+   struct wl_resource *resource = NULL;
+   struct wl_client *wc = NULL;
+   E_Keyrouter_Key_List_NodePtr data;
+
+   if (surface) wc = wl_resource_get_client(surface);
+   else wc = client;
+
+   EINA_SAFETY_ON_NULL_RETURN(wc);
+
+   EINA_LIST_FOREACH(krt->HardKeys[key].press_ptr, l, data)
+     {
+        if (surface)
+          {
+             if (surface == data->surface)
+               {
+                  EINA_LIST_FOREACH(krt->resources, l, resource)
+                    {
+                       if (wl_resource_get_client(resource) != wc) continue;
+
+                       tizen_keyrouter_send_key_cancel(resource, key-8);
+                    }
+               }
+          }
+        else if (client == data->wc)
+          {
+             EINA_LIST_FOREACH(krt->resources, l, resource)
+               {
+                  if (wl_resource_get_client(resource) != wc) continue;
+
+                  tizen_keyrouter_send_key_cancel(resource, key-8);
+               }
+          }
+     }
+}
+
+static int
+_e_keyrouter_wl_array_length(const struct wl_array *array)
+{
+   int *data = NULL;
+   int count = 0;
+
+   wl_array_for_each(data, array)
+     {
+        count++;
+     }
+
+   return count;
+}
+
+/* tizen_keyrouter_set_keygrab request handler */
+static void
+_e_keyrouter_cb_keygrab_set(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface, uint32_t key, uint32_t mode)
+{
+   int res = 0;
+
+   TRACE_INPUT_BEGIN(_e_keyrouter_cb_keygrab_set);
+
+   res = e_keyrouter_keygrab_set(client, surface, key, mode);
+
+   TRACE_INPUT_END();
+
+   if (res == TIZEN_KEYROUTER_ERROR_NONE)
+     {
+        if (mode == TIZEN_KEYROUTER_MODE_EXCLUSIVE)
+          {
+             KLINF("Success to %d key %s grab request (wl_client: %p, wl_surface: %p, pid: %d)", key, e_keyrouter_mode_to_string(mode),
+                client, surface, e_keyrouter_util_get_pid(client, surface));
+          }
+        else
+          {
+             KLDBG("Success to %d key %s grab request (wl_client: %p, wl_surface: %p, pid: %d)", key, e_keyrouter_mode_to_string(mode),
+                client, surface, e_keyrouter_util_get_pid(client, surface));
+          }
+     }
+   else
+     KLINF("Failed to %d key %s grab request (wl_client: %p, wl_surface: %p, pid: %d): res: %d", key, e_keyrouter_mode_to_string(mode),
+        client, surface, e_keyrouter_util_get_pid(client, surface), res);
+   tizen_keyrouter_send_keygrab_notify(resource, surface, key, mode, res);
+}
+
+/* tizen_keyrouter unset_keygrab request handler */
+static void
+_e_keyrouter_cb_keygrab_unset(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface, uint32_t key)
+{
+   int res = 0;
+
+   TRACE_INPUT_BEGIN(_e_keyrouter_cb_keygrab_unset);
+
+   res = e_keyrouter_keygrab_unset(client, surface, key);
+
+   TRACE_INPUT_END();
+
+   if (res == TIZEN_KEYROUTER_ERROR_NONE)
+     KLDBG("Success to %d key ungrab request (wl_client: %p, wl_surface: %p, pid: %d)", key, client, surface,
+           e_keyrouter_util_get_pid(client, surface));
+   else
+     KLINF("Failed to %d key ungrab request (wl_client: %p, wl_surface: %p, pid: %d): res: %d", key, client, surface,
+           e_keyrouter_util_get_pid(client, surface), res);
+   tizen_keyrouter_send_keygrab_notify(resource, surface, key, TIZEN_KEYROUTER_MODE_NONE, res);
+}
+
+/* tizen_keyrouter get_keygrab_status request handler */
+static void
+_e_keyrouter_cb_get_keygrab_status(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface, uint32_t key)
+{
+   (void) client;
+   (void) resource;
+   (void) surface;
+   (void) key;
+   int mode = TIZEN_KEYROUTER_MODE_NONE;
+
+   TRACE_INPUT_BEGIN(_e_keyrouter_cb_get_keygrab_status);
+   mode = e_keyrouter_find_key_in_list(surface, client, key);
+
+   TRACE_INPUT_END();
+   tizen_keyrouter_send_keygrab_notify(resource, surface, key, mode, TIZEN_KEYROUTER_ERROR_NONE);
+}
+
+static void
+_e_keyrouter_cb_keygrab_set_list(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface, struct wl_array *grab_list)
+{
+   E_Keyrouter_Grab_Request *grab_request = NULL;
+   int res = TIZEN_KEYROUTER_ERROR_NONE;
+   int array_len = 0;
+
+   TRACE_INPUT_BEGIN(_e_keyrouter_cb_keygrab_set_list);
+
+   array_len = _e_keyrouter_wl_array_length(grab_list);
+
+   if (0 != (array_len % 3))
+     {
+        /* FIX ME: Which way is effectively to notify invalid pair to client */
+        KLWRN("Invalid keycode and grab mode pair. Check arguments in a list");
+        TRACE_INPUT_END();
+        tizen_keyrouter_send_keygrab_notify_list(resource, surface, NULL);
+        return;
+     }
+
+   wl_array_for_each(grab_request, grab_list)
+     {
+        res = e_keyrouter_keygrab_set(client, surface, grab_request->key, grab_request->mode);
+        grab_request->err = res;
+        if (res == TIZEN_KEYROUTER_ERROR_NONE)
+          KLDBG("Success to %d key %s grab using list(wl_client: %p, wl_surface: %p, pid: %d)",
+                grab_request->key, e_keyrouter_mode_to_string(grab_request->mode),
+                client, surface, e_keyrouter_util_get_pid(client, surface));
+        else
+          KLINF("Failed to %d key %s grab using list(wl_client: %p, wl_surface: %p, pid: %d): res: %d",
+                grab_request->key, e_keyrouter_mode_to_string(grab_request->mode),
+                client, surface, e_keyrouter_util_get_pid(client, surface), grab_request->err);
+     }
+
+
+   TRACE_INPUT_END();
+   tizen_keyrouter_send_keygrab_notify_list(resource, surface, grab_list);
+}
+
+static void
+_e_keyrouter_cb_keygrab_unset_list(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface, struct wl_array *ungrab_list)
+{
+   E_Keyrouter_Ungrab_Request *ungrab_request = NULL;
+   int res = TIZEN_KEYROUTER_ERROR_NONE;
+   int array_len = 0;
+
+   TRACE_INPUT_BEGIN(_e_keyrouter_cb_keygrab_unset_list);
+
+   array_len = _e_keyrouter_wl_array_length(ungrab_list);
+
+   if (0 != (array_len % 2))
+     {
+        /* FIX ME: Which way is effectively to notify invalid pair to client */
+        KLWRN("Invalid keycode and error pair. Check arguments in a list");
+        TRACE_INPUT_END();
+        tizen_keyrouter_send_keygrab_notify_list(resource, surface, ungrab_list);
+        return;
+     }
+
+   wl_array_for_each(ungrab_request, ungrab_list)
+     {
+        res = e_keyrouter_keygrab_unset(client, surface, ungrab_request->key);
+        ungrab_request->err = res;
+        if (res == TIZEN_KEYROUTER_ERROR_NONE)
+          KLDBG("Success to ungrab using list: %d key (wl_client: %p, wl_surface: %p, pid: %d)",
+                ungrab_request->key, client, surface, e_keyrouter_util_get_pid(client, surface));
+        else
+          KLINF("Failed to ungrab using list: %d key (wl_client: %p, wl_surface: %p, pid: %d): res: %d",
+                ungrab_request->key, client, surface, e_keyrouter_util_get_pid(client, surface), ungrab_request->err);
+     }
+
+   TRACE_INPUT_END();
+   tizen_keyrouter_send_keygrab_notify_list(resource, surface, ungrab_list);
+}
+
+static void
+_e_keyrouter_cb_keygrab_get_list(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface)
+{
+   (void) client;
+
+   tizen_keyrouter_send_getgrab_notify_list(resource, surface, NULL);
+}
+
+static void
+_e_keyrouter_cb_set_register_none_key(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface, uint32_t data)
+{
+   (void) client;
+   (void) data;
+
+   tizen_keyrouter_send_set_register_none_key_notify(resource, NULL, 0);
+}
+
+static void
+_e_keyrouter_cb_get_keyregister_status(struct wl_client *client, struct wl_resource *resource, uint32_t key)
+{
+   (void) client;
+   (void) key;
+
+   tizen_keyrouter_send_keyregister_notify(resource, (int)EINA_FALSE);
+}
+
+static void
+_e_keyrouter_cb_set_input_config(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *surface EINA_UNUSED, uint32_t config_mode EINA_UNUSED, uint32_t value EINA_UNUSED)
+{
+   tizen_keyrouter_send_set_input_config_notify(resource, 0);
+}
+
+static void
+_e_keyrouter_cb_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+   wl_resource_destroy(resource);
+}
+
+static const struct tizen_keyrouter_interface _e_keyrouter_implementation = {
+   _e_keyrouter_cb_keygrab_set,
+   _e_keyrouter_cb_keygrab_unset,
+   _e_keyrouter_cb_get_keygrab_status,
+   _e_keyrouter_cb_keygrab_set_list,
+   _e_keyrouter_cb_keygrab_unset_list,
+   _e_keyrouter_cb_keygrab_get_list,
+   _e_keyrouter_cb_set_register_none_key,
+   _e_keyrouter_cb_get_keyregister_status,
+   _e_keyrouter_cb_set_input_config,
+   _e_keyrouter_cb_destroy,
+};
+
+static void
+_e_keyrouter_cb_unbind(struct wl_resource *resource)
+{
+   krt->resources = eina_list_remove(krt->resources, resource);
+}
+
+/* tizen_keyrouter global object bind function */
+static void
+_e_keyrouter_cb_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id)
+{
+   E_KeyrouterPtr krt_instance = data;
+   struct wl_resource *resource;
+
+   resource = wl_resource_create(client, &tizen_keyrouter_interface, version, id);
+
+   KLDBG("wl_resource_create(...,&tizen_keyrouter_interface,...)");
+
+   if (!resource)
+     {
+        KLERR("Failed to create resource ! (version :%d, id:%d)", version, id);
+        wl_client_post_no_memory(client);
+        return;
+     }
+
+   krt->resources = eina_list_append(krt->resources, resource);
+
+   wl_resource_set_implementation(resource, &_e_keyrouter_implementation, krt_instance, _e_keyrouter_cb_unbind);
+}
+
+static void
+_e_keyrouter_wl_client_cb_destroy(struct wl_listener *l, void *data)
+{
+   struct wl_client *client = data;
+
+   KLDBG("Listener(%p) called: wl_client: %p is died", l, client);
+   e_keyrouter_remove_client_from_list(NULL, client);
+
+   wl_list_remove(&l->link);
+   E_FREE(l);
+
+   krt->grab_client_list = eina_list_remove(krt->grab_client_list, client);
+}
+
+static void
+_e_keyrouter_wl_surface_cb_destroy(struct wl_listener *l, void *data)
+{
+   struct wl_resource *surface = (struct wl_resource *)data;
+
+   KLDBG("Listener(%p) called: surface: %p is died", l, surface);
+   e_keyrouter_remove_client_from_list(surface, NULL);
+
+   wl_list_remove(&l->link);
+   E_FREE(l);
+
+   krt->grab_surface_list = eina_list_remove(krt->grab_surface_list, surface);
+}
+
+int
+e_keyrouter_wl_add_client_destroy_listener(struct wl_client *client)
+{
+   struct wl_listener *destroy_listener = NULL;
+   Eina_List *l;
+   struct wl_client *wc_data;
+
+   if (!client) return TIZEN_KEYROUTER_ERROR_NONE;
+
+   EINA_LIST_FOREACH(krt->grab_client_list, l, wc_data)
+     {
+        if (wc_data)
+          {
+             if (wc_data == client)
+               {
+                  return TIZEN_KEYROUTER_ERROR_NONE;
+               }
+          }
+     }
+
+   destroy_listener = E_NEW(struct wl_listener, 1);
+
+   if (!destroy_listener)
+     {
+        KLERR("Failed to allocate memory for wl_client destroy listener !");
+        return TIZEN_KEYROUTER_ERROR_NO_SYSTEM_RESOURCES;
+     }
+
+   destroy_listener->notify = _e_keyrouter_wl_client_cb_destroy;
+   wl_client_add_destroy_listener(client, destroy_listener);
+   krt->grab_client_list = eina_list_append(krt->grab_client_list, client);
+
+   return TIZEN_KEYROUTER_ERROR_NONE;
+}
+
+/* Function for registering wl_surface destroy listener */
+int
+e_keyrouter_wl_add_surface_destroy_listener(struct wl_resource *surface)
+{
+   struct wl_listener *destroy_listener = NULL;
+   Eina_List *l;
+   struct wl_resource *surface_data;
+
+   if (!surface) return TIZEN_KEYROUTER_ERROR_NONE;
+
+   EINA_LIST_FOREACH(krt->grab_surface_list, l, surface_data)
+     {
+        if (surface_data)
+          {
+             if (surface_data == surface)
+               {
+                  return TIZEN_KEYROUTER_ERROR_NONE;
+               }
+          }
+     }
+
+   destroy_listener = E_NEW(struct wl_listener, 1);
+
+   if (!destroy_listener)
+     {
+        KLERR("Failed to allocate memory for wl_surface destroy listener !");
+        return TIZEN_KEYROUTER_ERROR_NO_SYSTEM_RESOURCES;
+     }
+
+   destroy_listener->notify = _e_keyrouter_wl_surface_cb_destroy;
+   wl_resource_add_destroy_listener(surface, destroy_listener);
+   krt->grab_surface_list = eina_list_append(krt->grab_surface_list, surface);
+
+   return TIZEN_KEYROUTER_ERROR_NONE;
+}
+
+#ifdef HAVE_CYNARA
+static void
+_e_keyrouter_wl_util_cynara_log(const char *func_name, int err)
+{
+#define CYNARA_BUFSIZE 128
+   char buf[CYNARA_BUFSIZE] = "\0";
+   int ret;
+
+   ret = cynara_strerror(err, buf, CYNARA_BUFSIZE);
+   if (ret != CYNARA_API_SUCCESS)
+     {
+        KLWRN("Failed to cynara_strerror: %d (error log about %s: %d)", ret, func_name, err);
+        return;
+     }
+   KLWRN("%s is failed: %s", func_name, buf);
+}
+
+Eina_Bool
+e_keyrouter_wl_util_do_privilege_check(struct wl_client *client, uint32_t mode, uint32_t keycode)
+{
+   int ret, retry_cnt=0, len=0;
+   char *clientSmack=NULL, *client_session=NULL, uid2[16]={0, };
+   Eina_Bool res = EINA_FALSE;
+   Eina_List *l;
+   struct wl_client *wc_data;
+   static Eina_Bool retried = EINA_FALSE;
+   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 EINA_TRUE;
+
+   if (krt->HardKeys[keycode].no_privcheck == EINA_TRUE)
+     return EINA_TRUE;
+
+   if (!client) return EINA_FALSE;
+
+   /* If initialize cynara is failed, allow keygrabs regardless of the previlege permition. */
+   if (krt->p_cynara == NULL)
+     {
+        if (retried == EINA_FALSE)
+          {
+             retried = EINA_TRUE;
+             for(retry_cnt = 0; retry_cnt < 5; retry_cnt++)
+               {
+                  KLDBG("Retry cynara initialize: %d", retry_cnt+1);
+                  ret = cynara_initialize(&krt->p_cynara, NULL);
+                  if (EINA_UNLIKELY(CYNARA_API_SUCCESS != ret))
+                    {
+                      _e_keyrouter_wl_util_cynara_log("cynara_initialize", ret);
+                       krt->p_cynara = NULL;
+                    }
+                  else
+                    {
+                       KLDBG("Success cynara initialize to try %d times", retry_cnt+1);
+                       break;
+                    }
+               }
+          }
+        return EINA_TRUE;
+     }
+
+   EINA_LIST_FOREACH(krt->grab_client_list, l, wc_data)
+     {
+        if (wc_data == client)
+          {
+             res = EINA_TRUE;
+             goto finish;
+          }
+     }
+
+   wl_client_get_credentials(client, &pid, &uid, &gid);
+
+   len = smack_new_label_from_process((int)pid, &clientSmack);
+   if (len <= 0) goto finish;
+
+   snprintf(uid2, 15, "%d", (int)uid);
+   client_session = cynara_session_from_pid(pid);
+
+   ret = cynara_check(krt->p_cynara, clientSmack, client_session, uid2, "http://tizen.org/privilege/keygrab");
+   if (CYNARA_API_ACCESS_ALLOWED == ret)
+     {
+        res = EINA_TRUE;
+     }
+   else
+     {
+        KLINF("Fail to check cynara,  error : %d (pid : %d)", ret, pid);
+     }
+finish:
+   if (client_session) E_FREE(client_session);
+   if (clientSmack) E_FREE(clientSmack);
+
+   return res;
+}
+#endif
+
+Eina_Bool
+e_keyrouter_wl_init(void)
+{
+   int ret;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(krt, EINA_FALSE);
+
+   krt->global = wl_global_create(e_comp_wl->wl.disp, &tizen_keyrouter_interface, 1, krt, _e_keyrouter_cb_bind);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(krt->global, EINA_FALSE);
+
+#ifdef HAVE_CYNARA
+   ret = cynara_initialize(&krt->p_cynara, NULL);
+   if (EINA_UNLIKELY(CYNARA_API_SUCCESS != ret))
+     {
+        _e_keyrouter_wl_util_cynara_log("cynara_initialize", ret);
+        krt->p_cynara = NULL;
+     }
+#endif
+
+   return EINA_TRUE;
+}
+
+void
+e_keyrouter_wl_shutdown(void)
+{
+   Eina_List *l, *l_next;
+   struct wl_resource *resource;
+   struct wl_client *client;
+   struct wl_listener *destroy_listener;
+
+   EINA_SAFETY_ON_NULL_RETURN(krt);
+
+   EINA_LIST_FOREACH_SAFE(krt->grab_client_list, l, l_next, client)
+     {
+        destroy_listener = wl_client_get_destroy_listener(client, _e_keyrouter_wl_client_cb_destroy);
+        if (destroy_listener)
+          {
+             wl_list_remove(&destroy_listener->link);
+             E_FREE(destroy_listener);
+          }
+        krt->grab_client_list = eina_list_remove(krt->grab_client_list, client);
+     }
+   EINA_LIST_FOREACH_SAFE(krt->grab_surface_list, l, l_next, resource)
+     {
+        destroy_listener = wl_resource_get_destroy_listener(resource, _e_keyrouter_wl_surface_cb_destroy);
+        if (destroy_listener)
+          {
+             wl_list_remove(&destroy_listener->link);
+             E_FREE(destroy_listener);
+          }
+        krt->grab_surface_list = eina_list_remove(krt->grab_surface_list, client);
+     }
+
+   EINA_LIST_FREE(krt->resources, resource)
+     wl_resource_destroy(resource);
+   if (krt->global) wl_global_destroy(krt->global);
+   
+#ifdef HAVE_CYNARA
+   if (krt->p_cynara) cynara_finish(krt->p_cynara);
+#endif
+}
index 56f91e0..a8f95a6 100644 (file)
@@ -677,6 +677,15 @@ main(int argc, char **argv)
    _e_main_shutdown_push(_e_main_screens_shutdown);
    TRACE_DS_END();
 
+   TSB("E_Keyrouter Init");
+   if (!e_keyrouter_init())
+     {
+        e_error_message_show(_("Enlightenment cannot set up its keyrouting system.\n"));
+        goto failed;
+     }
+   TSE("E_Keyrouter Init Done");
+   _e_main_shutdown_push(e_keyrouter_shutdown);
+
    if (e_config->eom_enable)
      {
         TSB("Eom Init");