From c49af600426ccafcf15855060ea33d07773e74f4 Mon Sep 17 00:00:00 2001 From: Ji-Youn Park Date: Wed, 13 May 2015 20:47:36 +0900 Subject: ecore_x: Add key router feature related with client side. Currently app only grab key using Xgrabkey. Keyrouter will support several keygrab mode and apps can use it. Change-Id: I051185968c00dc45002c1608ce16415285273dd4 Signed-off-by: Jiyoun Park Conflicts: src/lib/ecore_x/Ecore_X.h src/lib/ecore_x/Ecore_X_Atoms.h src/lib/ecore_x/ecore_x_atoms_decl.h src/lib/ecore_x/xlib/ecore_x_e.c origin: upstream --- src/Makefile_Ecore_X.am | 1 + src/lib/ecore_x/Ecore_X.h | 20 ++ src/lib/ecore_x/Ecore_X_Atoms.h | 4 + src/lib/ecore_x/ecore_x_atoms_decl.h | 4 + src/lib/ecore_x/xlib/ecore_x_e.c | 38 ++ src/lib/ecore_x/xlib/ecore_x_keygrab.c | 617 +++++++++++++++++++++++++++++++++ 6 files changed, 684 insertions(+) create mode 100644 src/lib/ecore_x/xlib/ecore_x_keygrab.c diff --git a/src/Makefile_Ecore_X.am b/src/Makefile_Ecore_X.am index 43c06478b2..38727f13ed 100644 --- a/src/Makefile_Ecore_X.am +++ b/src/Makefile_Ecore_X.am @@ -82,6 +82,7 @@ lib/ecore_x/xlib/ecore_x_composite.c \ lib/ecore_x/xlib/ecore_x_error.c \ lib/ecore_x/xlib/ecore_x_events.c \ lib/ecore_x/xlib/ecore_x_icccm.c \ +lib/ecore_x/xlib/ecore_x_keygrab.c \ lib/ecore_x/xlib/ecore_x_netwm.c \ lib/ecore_x/xlib/ecore_x_mwm.c \ lib/ecore_x/xlib/ecore_x_e.c \ diff --git a/src/lib/ecore_x/Ecore_X.h b/src/lib/ecore_x/Ecore_X.h index 521e5c48dd..0850a67809 100644 --- a/src/lib/ecore_x/Ecore_X.h +++ b/src/lib/ecore_x/Ecore_X.h @@ -2716,6 +2716,26 @@ EAPI void ecore_x_e_virtual_keyboard_on_prepare EAPI void ecore_x_e_virtual_keyboard_off_prepare_request_send(Ecore_X_Window win); EAPI void ecore_x_e_virtual_keyboard_off_prepare_done_send(Ecore_X_Window root, Ecore_X_Window win); +//this enum and API for keyrouter and client window side +//keycode (8~255) +typedef enum +{ + ECORE_X_WIN_KEYGRAB_UNKNOWN = 0, /**< Unknown keygrab mode */ + ECORE_X_WIN_KEYGRAB_SHARED = (1 << 8), /**< Getting the grabbed-key together with the other client windows */ + ECORE_X_WIN_KEYGRAB_TOPMOST = (1 << 9), /**< Getting the grabbed-key only when window is top of the stack */ + ECORE_X_WIN_KEYGRAB_EXCLUSIVE = (1 << 10), /**< Getting the grabbed-key exclusively regardless of window's position */ + ECORE_X_WIN_KEYGRAB_OVERRIDE_EXCLUSIVE = (1 << 11) /**< Getting the grabbed-key exclusively regardless of window's position. Being overrided the grab by the other client window */ +} Ecore_X_Win_Keygrab_Mode; + +//add mod, anymod, priority for the future. +//we will support modifier and priority feature later. +EAPI Eina_Bool ecore_x_window_keygrab_set(Ecore_X_Window win, const char *key, int mod, int any_mod, int priority, Ecore_X_Win_Keygrab_Mode grab_mode); +EAPI Eina_Bool ecore_x_window_keygrab_unset(Ecore_X_Window win, const char *key, int mod, int any_mod); + +//this API for keyrouter protocol +EAPI void ecore_x_e_keyrouter_set(Ecore_X_Window root, Eina_Bool on); //Key router set keyrouter flag using this +EAPI Eina_Bool ecore_x_e_keyrouter_get(Ecore_X_Window root); //Client check the existance of keyrouter using this + #ifdef __cplusplus } #endif // ifdef __cplusplus diff --git a/src/lib/ecore_x/Ecore_X_Atoms.h b/src/lib/ecore_x/Ecore_X_Atoms.h index ca418cdc6c..4f2485780a 100644 --- a/src/lib/ecore_x/Ecore_X_Atoms.h +++ b/src/lib/ecore_x/Ecore_X_Atoms.h @@ -344,4 +344,8 @@ EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_ON_PREPARE_REQUEST; EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_ON_PREPARE_DONE; EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_OFF_PREPARE_REQUEST; EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_OFF_PREPARE_DONE; + +/* E keyrouter protocol */ +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_KEYROUTER_SUPPORTED; /**< @since 1.15 */ +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_KEYROUTER_WINDOW_KEYTABLE; /**< @since 1.15 */ #endif /* _ECORE_X_ATOMS_H */ diff --git a/src/lib/ecore_x/ecore_x_atoms_decl.h b/src/lib/ecore_x/ecore_x_atoms_decl.h index 6581530513..29d453a8e4 100644 --- a/src/lib/ecore_x/ecore_x_atoms_decl.h +++ b/src/lib/ecore_x/ecore_x_atoms_decl.h @@ -374,6 +374,10 @@ EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_ON_PREPARE_DONE = 0; EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_OFF_PREPARE_REQUEST = 0; EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_OFF_PREPARE_DONE = 0; +/* E keyrouter protocol */ +EAPI Ecore_X_Atom ECORE_X_ATOM_E_KEYROUTER_SUPPORTED = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_KEYROUTER_WINDOW_KEYTABLE = 0; + typedef struct _Atom_Item Atom_Item; struct _Atom_Item diff --git a/src/lib/ecore_x/xlib/ecore_x_e.c b/src/lib/ecore_x/xlib/ecore_x_e.c index 433770c18d..a7b771179b 100644 --- a/src/lib/ecore_x/xlib/ecore_x_e.c +++ b/src/lib/ecore_x/xlib/ecore_x_e.c @@ -2457,3 +2457,41 @@ ecore_x_e_virtual_keyboard_off_prepare_done_send(Ecore_X_Window root, SubstructureRedirectMask | SubstructureNotifyMask, &xev); } + +/* + * Does keyrouter exist? + */ +EAPI void +ecore_x_e_keyrouter_set(Ecore_X_Window win EINA_UNUSED, + Eina_Bool on) +{ + //key router call this api when it start running + unsigned int val; + Ecore_X_Window root; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + root = DefaultRootWindow(_ecore_x_disp); + + val = (on) ? 1 : 0; + ecore_x_window_prop_card32_set(root, ECORE_X_ATOM_E_KEYROUTER_SUPPORTED, + &val, 1); +} + +EAPI Eina_Bool +ecore_x_e_keyrouter_get(Ecore_X_Window win EINA_UNUSED) +{ + //check the existance of keyrouter + int ret; + unsigned int val; + Ecore_X_Window root; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + root = DefaultRootWindow(_ecore_x_disp); + + ret = ecore_x_window_prop_card32_get(root, ECORE_X_ATOM_E_KEYROUTER_SUPPORTED, + &val, 1); + if (ret != 1) return EINA_FALSE; + + return val == 1 ? EINA_TRUE : EINA_FALSE; +} diff --git a/src/lib/ecore_x/xlib/ecore_x_keygrab.c b/src/lib/ecore_x/xlib/ecore_x_keygrab.c new file mode 100644 index 0000000000..b0dbd29a81 --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x_keygrab.c @@ -0,0 +1,617 @@ +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + +#include + + +#ifdef LOGRT +#include +#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); +} + -- cgit v1.2.1