--- /dev/null
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* ifdef HAVE_CONFIG_H */
+
+#include <stdlib.h>
+
+
+#ifdef LOGRT
+#include <dlfcn.h>
+#endif /* ifdef LOGRT */
+
+#include "ecore_x_private.h"
+#include "Ecore_X.h"
+#include "Ecore_X_Atoms.h"
+
+
+//////////////////////////////////////////////////////////////////////////////
+// This api and structure only for the key router and window client side
+// Application do not use this
+
+//this mask is defined by key router.
+//after discussing with keyrouter module, this mask can be changed
+#define GRAB_MASK 0xffff00
+#define OVERRIDE_EXCLUSIVE_GRAB 0xf00000
+#define EXCLUSIVE_GRAB 0x0f0000
+#define TOPMOST_GRAB 0x00f000
+#define SHARED_GRAB 0x000f00
+
+//if _ecore_keyrouter = 0, not yet check keyrouter
+//if _ecore_keyrouter = -1, keyrouter not exist
+//if _ecore_keyrouter = 1, keyrouter exist
+int _ecore_keyrouter = 0;
+
+struct _Ecore_X_Window_Key_Table
+{
+ Ecore_X_Window win; //windo ID
+ int *key_list; //list of key
+ unsigned long key_cnt; // the number of key
+};
+
+typedef struct _Ecore_X_Window_Key_Table Ecore_X_Window_Key_Table;
+
+static int _ecore_x_window_keytable_key_search(Ecore_X_Window_Key_Table *keytable, int key);
+static Eina_Bool _ecore_x_window_keytable_key_del(Ecore_X_Window_Key_Table *key_table, int key, Ecore_X_Atom keytable_atom);
+
+static Eina_Bool _ecore_x_window_keytable_key_add(Ecore_X_Window_Key_Table *keytable,
+ int keycode,
+ Ecore_X_Win_Keygrab_Mode grab_mode);
+
+static Eina_Bool _ecore_x_window_keygrab_set_internal(Ecore_X_Window win, const char *key, Ecore_X_Win_Keygrab_Mode grab_mode);
+static Eina_Bool _ecore_x_window_keygrab_unset_internal(Ecore_X_Window win, const char *key);
+static Eina_Bool _ecore_x_window_keytable_get(Ecore_X_Window win, Ecore_X_Window_Key_Table *keytable);
+
+
+//(Below Atom and exclusiveness_get/set functions) should be changed after keyrouter finds the solution to avoid race condition
+//solution 1. window manages two key table. keytable and keytable result
+//solution 2. using client messabe between the window client and the key router.
+
+static Atom _atom_grab_excl_win = None;
+#define STR_ATOM_GRAB_EXCL_WIN "_GRAB_EXCL_WIN_KEYCODE"
+
+static void
+_keytable_free(Ecore_X_Window_Key_Table *keytable)
+{
+ if (keytable->key_list)
+ free(keytable->key_list);
+ keytable->key_list = NULL;
+ keytable->win = 0;
+ keytable->key_cnt = 0;
+}
+
+static int
+_keytable_property_list_get(Ecore_X_Window win,
+ Ecore_X_Atom atom,
+ unsigned int **plst)
+{
+ unsigned char *prop_ret;
+ Atom type_ret;
+ unsigned long bytes_after, num_ret;
+ int format_ret;
+ unsigned int i, *val;
+ int num;
+
+ *plst = NULL;
+ prop_ret = NULL;
+ if (XGetWindowProperty(_ecore_x_disp, win, atom, 0, 0x7fffffff, False,
+ XA_CARDINAL, &type_ret, &format_ret, &num_ret,
+ &bytes_after, &prop_ret) != Success)
+ {
+ WRN("XGetWindowProperty failed");
+ return -1;
+ }
+ else if ((num_ret == 0) || (!prop_ret))
+ num = 0;
+ else
+ {
+ val = malloc(num_ret * sizeof(unsigned int));
+ if (!val)
+ {
+ if (prop_ret) XFree(prop_ret);
+ WRN("Memory alloc failed");
+ return -1;
+ }
+ for (i = 0; i < num_ret; i++)
+ val[i] = ((unsigned long *)prop_ret)[i];
+ num = num_ret;
+ *plst = val;
+ }
+
+ if (_ecore_xlib_sync) ecore_x_sync();
+ if (prop_ret)
+ XFree(prop_ret);
+ return num;
+}
+
+static Eina_Bool
+_ecore_x_window_keytable_possible_global_exclusiveness_get(int keycode)
+{
+ int ret = 0;
+
+ Ecore_X_Window_Key_Table keytable;
+
+ keytable.win = ecore_x_window_root_first_get();
+ keytable.key_list = NULL;
+ keytable.key_cnt = 0;
+
+ if(_atom_grab_excl_win == None )
+ _atom_grab_excl_win = XInternAtom(_ecore_x_disp, STR_ATOM_GRAB_EXCL_WIN, False);
+
+ ret = _keytable_property_list_get(keytable.win, _atom_grab_excl_win,
+ (unsigned int **)&(keytable.key_list));
+
+ if (ret < 0)
+ {
+ return EINA_FALSE;
+ }
+
+ keytable.key_cnt = ret;
+
+ if (keytable.key_cnt == 0)
+ {
+ WRN("There is no keygrab entry in the table");
+ return EINA_TRUE;
+ }
+
+ //check keycode exists in the global exclusiveness keytable
+
+ ret = _ecore_x_window_keytable_key_search(&keytable, keycode);
+ if (ret != -1)
+ {
+ WRN("Can't search keygrab entry in the table");
+ _keytable_free(&keytable);
+ return EINA_FALSE;
+ }
+ _keytable_free(&keytable);
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_ecore_x_window_keytable_possible_global_exclusiveness_set(int keycode)
+{
+ int ret = 0;
+
+ Ecore_X_Window_Key_Table keytable;
+
+ keytable.win = ecore_x_window_root_first_get();
+ keytable.key_list = NULL;
+ keytable.key_cnt = 0;
+
+ if(_atom_grab_excl_win == None )
+ _atom_grab_excl_win = XInternAtom(_ecore_x_disp, STR_ATOM_GRAB_EXCL_WIN, False);
+
+ ret = _keytable_property_list_get(keytable.win, _atom_grab_excl_win,
+ (unsigned int **)&(keytable.key_list));
+ if (ret < 0) return EINA_FALSE;
+
+ keytable.key_cnt = ret;
+
+ if (keytable.key_cnt == 0)
+ {
+ XChangeProperty(_ecore_x_disp, keytable.win, _atom_grab_excl_win, XA_CARDINAL, 32,
+ PropModeReplace, (unsigned char *)&keycode, 1);
+ XSync(_ecore_x_disp, False);
+ _keytable_free(&keytable);
+ return EINA_TRUE;
+ }
+
+ //check keycode exists in the global exclusiveness keytable
+ ret = _ecore_x_window_keytable_key_search(&keytable, keycode);
+ if (ret != -1)
+ {
+ XChangeProperty(_ecore_x_disp, keytable.win, _atom_grab_excl_win, XA_CARDINAL, 32,
+ PropModeAppend, (unsigned char *)&keycode, 1);
+ XSync(_ecore_x_disp, False);
+ _keytable_free(&keytable);
+ return EINA_TRUE;
+ }
+ WRN("Already key is grabbed");
+ _keytable_free(&keytable);
+ return EINA_FALSE;
+}
+
+static Eina_Bool
+_ecore_x_window_keytable_possible_global_exclusiveness_unset(int keycode)
+{
+ int ret = 0;
+
+ Ecore_X_Window_Key_Table keytable;
+
+ keytable.win = ecore_x_window_root_first_get();
+ keytable.key_list = NULL;
+ keytable.key_cnt = 0;
+
+ if(_atom_grab_excl_win == None )
+ _atom_grab_excl_win = XInternAtom(_ecore_x_disp, STR_ATOM_GRAB_EXCL_WIN, False);
+
+ ret = _keytable_property_list_get(keytable.win, _atom_grab_excl_win,
+ (unsigned int **)&(keytable.key_list));
+ if (ret <= 0) return EINA_FALSE;
+
+ keytable.key_cnt = ret;
+
+ //check keycode exists in the global exclusiveness keytable
+ ret = _ecore_x_window_keytable_key_search(&keytable, keycode);
+ if (ret == -1)
+ {
+ WRN("Already key exists");
+ _keytable_free(&keytable);
+ return EINA_FALSE;
+ }
+ else
+ ret = _ecore_x_window_keytable_key_del(&keytable, keycode, _atom_grab_excl_win);
+
+ _keytable_free(&keytable);
+ return EINA_FALSE;
+}
+
+static Eina_Bool
+_ecore_x_window_keytable_keycode_decode(int keycode_encoded,
+ int *keycode,
+ Ecore_X_Win_Keygrab_Mode *grab_mode)
+{
+ int key_mask = 0;
+
+ *keycode = keycode_encoded & (~GRAB_MASK);
+ key_mask = keycode_encoded & GRAB_MASK;
+
+ if (key_mask == SHARED_GRAB)
+ {
+ *grab_mode = ECORE_X_WIN_KEYGRAB_SHARED;
+ return EINA_TRUE;
+ }
+ else if (key_mask == TOPMOST_GRAB)
+ {
+ *grab_mode = ECORE_X_WIN_KEYGRAB_TOPMOST;
+ return EINA_TRUE;
+ }
+ else if (key_mask == EXCLUSIVE_GRAB)
+ {
+ *grab_mode = ECORE_X_WIN_KEYGRAB_EXCLUSIVE;
+ return EINA_TRUE;
+ }
+ else if (key_mask == OVERRIDE_EXCLUSIVE_GRAB)
+ {
+ *grab_mode = ECORE_X_WIN_KEYGRAB_OVERRIDE_EXCLUSIVE;
+ return EINA_TRUE;
+ }
+ else
+ {
+ *grab_mode = ECORE_X_WIN_KEYGRAB_UNKNOWN;
+ WRN("Keycode decoding failed. Unknown Keygrab mode");
+ return EINA_FALSE;
+ }
+}
+
+static Eina_Bool
+_ecore_x_window_keytable_keycode_encode(int keycode,
+ Ecore_X_Win_Keygrab_Mode grab_mode,
+ int *keycode_encoded)
+{
+ if ((grab_mode <= ECORE_X_WIN_KEYGRAB_UNKNOWN) || (grab_mode > ECORE_X_WIN_KEYGRAB_OVERRIDE_EXCLUSIVE))
+ {
+ *keycode_encoded = 0;
+ WRN("Keycode encoding failed. Unknown Keygrab mode");
+ return EINA_FALSE;
+ }
+ if (grab_mode == ECORE_X_WIN_KEYGRAB_SHARED)
+ *keycode_encoded = keycode | SHARED_GRAB;
+ else if (grab_mode == ECORE_X_WIN_KEYGRAB_TOPMOST)
+ *keycode_encoded = keycode | TOPMOST_GRAB;
+ else if (grab_mode == ECORE_X_WIN_KEYGRAB_EXCLUSIVE)
+ *keycode_encoded = keycode | EXCLUSIVE_GRAB;
+ else if (grab_mode == ECORE_X_WIN_KEYGRAB_OVERRIDE_EXCLUSIVE)
+ *keycode_encoded = keycode | OVERRIDE_EXCLUSIVE_GRAB;
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_ecore_x_window_keytable_get(Ecore_X_Window win,
+ Ecore_X_Window_Key_Table *keytable)
+{
+ int ret = 0;
+
+ ret = _keytable_property_list_get(win, ECORE_X_ATOM_E_KEYROUTER_WINDOW_KEYTABLE,
+ (unsigned int **)&(keytable->key_list));
+ if (ret < 0) return EINA_FALSE;
+
+ keytable->key_cnt = ret;
+
+ return EINA_TRUE;
+}
+
+static int
+_ecore_x_window_keytable_key_search(Ecore_X_Window_Key_Table *keytable,
+ int key)
+{
+ int i;
+ int keycode = 0;
+ unsigned long key_cnt;
+ int *key_list = NULL;
+
+ keycode = key & (~GRAB_MASK);
+ key_cnt = keytable->key_cnt;
+ key_list = keytable->key_list;
+
+ for (i = key_cnt - 1; i >= 0; i--)
+ {
+ if ((key_list[i] & (~GRAB_MASK)) == keycode) break;
+ }
+ return i;
+}
+
+
+static Eina_Bool
+_ecore_x_window_keytable_key_add(Ecore_X_Window_Key_Table *keytable,
+ int keycode,
+ Ecore_X_Win_Keygrab_Mode grab_mode)
+{
+ int i = 0;
+ int keycode_masked = 0;
+
+ Ecore_Window win;
+ unsigned long key_cnt;
+
+ win = keytable->win;
+ key_cnt = keytable->key_cnt;
+
+ if (!_ecore_x_window_keytable_keycode_encode(keycode, grab_mode, &keycode_masked))
+ return EINA_FALSE;
+
+ if (key_cnt == 0)
+ {
+ XChangeProperty(_ecore_x_disp, win, ECORE_X_ATOM_E_KEYROUTER_WINDOW_KEYTABLE, XA_CARDINAL, 32,
+ PropModeReplace, (unsigned char *)&keycode_masked, 1);
+ XSync(_ecore_x_disp, False);
+ return EINA_TRUE;
+ }
+ else
+ {
+ i = _ecore_x_window_keytable_key_search(keytable, keycode_masked);
+ if ( i != -1 )
+ {
+ //already exist key in key table
+ WRN("Already key exists");
+ return EINA_FALSE;
+ }
+ XChangeProperty(_ecore_x_disp, win, ECORE_X_ATOM_E_KEYROUTER_WINDOW_KEYTABLE, XA_CARDINAL, 32,
+ PropModeAppend, (unsigned char *)&keycode_masked, 1);
+ XSync(_ecore_x_disp, False);
+ return EINA_TRUE;
+ }
+}
+
+static Eina_Bool
+_ecore_x_window_keytable_key_del(Ecore_X_Window_Key_Table *key_table,
+ int key,
+ Ecore_X_Atom keytable_atom)
+{
+ int i;
+ int *new_key_list = NULL;
+ unsigned long key_cnt = 0;
+
+ // Only one element is exists in the list of grabbed key
+ i = _ecore_x_window_keytable_key_search(key_table, key);
+
+ if (i == -1)
+ {
+ WRN("Key doesn't exist in the key table.");
+ return EINA_FALSE;
+ }
+
+ (key_table->key_cnt)--;
+ key_cnt = key_table->key_cnt;
+
+ if (key_cnt == 0)
+ {
+ XDeleteProperty(_ecore_x_disp, key_table->win, keytable_atom);
+ XSync(_ecore_x_disp, False);
+ return EINA_TRUE;
+ }
+
+ // Shrink the buffer
+ new_key_list = malloc((key_cnt) * sizeof(int));
+
+ if (new_key_list == NULL)
+ return EINA_FALSE;
+
+ // copy head
+ if (i > 0)
+ memcpy(new_key_list, key_table->key_list, sizeof(int) * i);
+
+ // copy tail
+ if ((key_cnt) - i > 0)
+ {
+ memcpy(new_key_list + i,
+ key_table->key_list + i + 1,
+ sizeof(int) * (key_cnt - i));
+ }
+
+ XChangeProperty(_ecore_x_disp, key_table->win, keytable_atom, XA_CARDINAL, 32,
+ PropModeReplace, (unsigned char *)new_key_list, key_cnt);
+ XSync(_ecore_x_disp, False);
+
+ free(new_key_list);
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_ecore_x_window_keygrab_set_internal(Ecore_X_Window win,
+ const char *key,
+ Ecore_X_Win_Keygrab_Mode grab_mode)
+{
+ KeyCode keycode = 0;
+ KeySym keysym;
+
+ Eina_Bool ret = EINA_FALSE;
+ Ecore_X_Window_Key_Table keytable;
+
+ keytable.win = win;
+ keytable.key_list = NULL;
+ keytable.key_cnt = 0;
+
+
+ //check the key string
+ if (!strncmp(key, "Keycode-", 8))
+ keycode = atoi(key + 8);
+ else
+ {
+ keysym = XStringToKeysym(key);
+ if (keysym == NoSymbol)
+ {
+ WRN("Keysym of key(\"%s\") doesn't exist", key);
+ return ret;
+ }
+ keycode = XKeysymToKeycode(_ecore_x_disp, keysym);
+ }
+
+ if (keycode == 0)
+ {
+ WRN("Keycode of key(\"%s\") doesn't exist", key);
+ return ret;
+ }
+
+ if(grab_mode == ECORE_X_WIN_KEYGRAB_EXCLUSIVE)
+ {
+ //Only one window can grab this key;
+ //keyrouter should avoid race condition
+ if (!_ecore_x_window_keytable_possible_global_exclusiveness_get(keycode))
+ return EINA_FALSE;
+ }
+
+ if (!_ecore_x_window_keytable_get(win, &keytable))
+ return EINA_FALSE;
+
+ ret = _ecore_x_window_keytable_key_add(&keytable, keycode, grab_mode);
+
+
+ if (!ret)
+ {
+ WRN("Key(\"%s\") add failed", key);
+ return ret;
+ }
+
+ if(grab_mode == ECORE_X_WIN_KEYGRAB_EXCLUSIVE)
+ {
+ //Only one window can grab this key;
+ if(!_ecore_x_window_keytable_possible_global_exclusiveness_set(keycode))
+ {
+ _ecore_x_window_keytable_key_del(&keytable, keycode, ECORE_X_ATOM_E_KEYROUTER_WINDOW_KEYTABLE);
+ WRN("Key(\"%s\") already is grabbed", key);
+ goto error;
+ }
+ }
+
+ _keytable_free(&keytable);
+ return EINA_TRUE;
+error:
+ _keytable_free(&keytable);
+ return EINA_FALSE;
+}
+
+static Eina_Bool
+_ecore_x_window_keygrab_unset_internal(Ecore_X_Window win,
+ const char *key)
+{
+ KeyCode keycode = 0;
+ KeySym keysym;
+
+ int i;
+ int key_masked = 0;
+ int key_decoded = 0;
+
+ Eina_Bool ret = EINA_FALSE;
+
+ Ecore_X_Window_Key_Table keytable;
+ Ecore_X_Win_Keygrab_Mode grab_mode = ECORE_X_WIN_KEYGRAB_UNKNOWN;
+
+ keytable.win = win;
+ keytable.key_list = NULL;
+ keytable.key_cnt = 0;
+
+ if (!strncmp(key, "Keycode-", 8))
+ keycode = atoi(key + 8);
+ else
+ {
+ keysym = XStringToKeysym(key);
+ if (keysym == NoSymbol)
+ {
+ WRN("Keysym of key(\"%s\") doesn't exist", key);
+ return EINA_FALSE;
+ }
+ keycode = XKeysymToKeycode(_ecore_x_disp, keysym);
+ }
+
+ if (keycode == 0)
+ {
+ WRN("Keycode of key(\"%s\") doesn't exist", key);
+ return EINA_FALSE;
+ }
+
+ //construct the keytable structure using Xproperty
+ if (!_ecore_x_window_keytable_get(win, &keytable))
+ return EINA_FALSE;
+
+ if (keytable.key_cnt <= 0)
+ return EINA_FALSE;
+
+ i = _ecore_x_window_keytable_key_search(&keytable, keycode);
+
+ if (i == -1) //cannot find key in keytable
+ {
+ WRN("Key(\"%s\") doesn't exist", key);
+ goto error;
+ }
+
+ //find key in keytable
+ key_masked = keytable.key_list[i];
+
+ ret = _ecore_x_window_keytable_keycode_decode(key_masked, &key_decoded, &grab_mode);
+
+ if (!ret)
+ goto error;
+
+ ret = _ecore_x_window_keytable_key_del(&keytable, key_masked, ECORE_X_ATOM_E_KEYROUTER_WINDOW_KEYTABLE);
+ if (!ret)
+ goto error;
+
+ if (grab_mode == ECORE_X_WIN_KEYGRAB_EXCLUSIVE)
+ {
+ ret = _ecore_x_window_keytable_possible_global_exclusiveness_unset(keycode);
+ }
+
+ return EINA_TRUE;
+error:
+ _keytable_free(&keytable);
+ return EINA_FALSE;
+}
+
+EAPI Eina_Bool
+ecore_x_window_keygrab_set(Ecore_X_Window win,
+ const char *key,
+ int mod EINA_UNUSED,
+ int not_mod EINA_UNUSED,
+ int priority EINA_UNUSED,
+ Ecore_X_Win_Keygrab_Mode grab_mode)
+{
+ if (_ecore_keyrouter == 0)
+ {
+ if(ecore_x_e_keyrouter_get(win))
+ _ecore_keyrouter = 1;
+ else
+ {
+ WRN("Keyrouter is not supported");
+ _ecore_keyrouter = -1;
+ }
+ }
+ if (_ecore_keyrouter < 0)
+ return EINA_FALSE;
+
+ return _ecore_x_window_keygrab_set_internal(win, key, grab_mode);
+}
+
+EAPI Eina_Bool
+ecore_x_window_keygrab_unset(Ecore_X_Window win,
+ const char *key,
+ int mod EINA_UNUSED,
+ int any_mod EINA_UNUSED)
+{
+ if (_ecore_keyrouter != 1)
+ {
+ WRN("Keyrouter is not supported");
+ return EINA_FALSE;
+ }
+
+ return _ecore_x_window_keygrab_unset_internal(win, key);
+}
+