ecore-xcb: Implement missing keyrouter and keygrab functions for xcb

This patch implements missing API functions (in ecore xcb) for
ecore_x_window_keygrab_set, ecore_x_window_keygrab_unset,
ecore_x_e_keyrouter_set, ecore_x_e_keyrouter_get. These
were missing from the initial commit of keygrab/keyrouter code.

Fixes T3377

ref 5c3a08433a

@fix

Signed-off-by: Chris Michael <cpmichael@osg.samsung.com>
This commit is contained in:
Chris Michael 2016-04-04 08:54:45 -04:00
parent 0482c38131
commit 0ed9d246e5
3 changed files with 474 additions and 0 deletions

View File

@ -58,6 +58,7 @@ lib/ecore_x/xcb/ecore_xcb_selection.c \
lib/ecore_x/xcb/ecore_xcb_textlist.c \
lib/ecore_x/xcb/ecore_xcb_events.c \
lib/ecore_x/xcb/ecore_xcb_keymap.c \
lib/ecore_x/xcb/ecore_xcb_keygrab.c \
lib/ecore_x/xcb/ecore_xcb_netwm.c \
lib/ecore_x/xcb/ecore_xcb_icccm.c \
lib/ecore_x/xcb/ecore_xcb_window.c \

View File

@ -2233,3 +2233,34 @@ ecore_x_e_window_rotation_change_done_send(Ecore_X_Window root,
(XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY), (const char *)&ev);
}
EAPI void
ecore_x_e_keyrouter_set(Ecore_X_Window win EINA_UNUSED, Eina_Bool on)
{
Ecore_X_Window root;
unsigned int val;
CHECK_XCB_CONN;
root = ((xcb_screen_t *)_ecore_xcb_screen)->root;
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)
{
Ecore_X_Window root;
int ret;
unsigned int val;
CHECK_XCB_CONN;
root = ((xcb_screen_t *)_ecore_xcb_screen)->root;
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;
}

View File

@ -0,0 +1,442 @@
#include "ecore_xcb_private.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;
typedef 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
} Ecore_X_Window_Key_Table;
static Ecore_X_Atom _atom_grab_excl_win = XCB_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)
{
return ecore_x_window_prop_card32_list_get(win, atom, plst);
}
static Eina_Bool
_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 Eina_Bool
_keytable_keycode_decode(int encoded, int *keycode, Ecore_X_Win_Keygrab_Mode *grab_mode)
{
int mask = 0;
*keycode = encoded & (~GRAB_MASK);
mask = encoded & GRAB_MASK;
if (mask == SHARED_GRAB)
*grab_mode = ECORE_X_WIN_KEYGRAB_SHARED;
else if (mask == TOPMOST_GRAB)
*grab_mode = ECORE_X_WIN_KEYGRAB_TOPMOST;
else if (mask == EXCLUSIVE_GRAB)
*grab_mode = ECORE_X_WIN_KEYGRAB_EXCLUSIVE;
else if (mask == OVERRIDE_EXCLUSIVE_GRAB)
*grab_mode = ECORE_X_WIN_KEYGRAB_OVERRIDE_EXCLUSIVE;
else
{
*grab_mode = ECORE_X_WIN_KEYGRAB_UNKNOWN;
WRN("Keycode decoding failed. Unknown Keygrab mode");
return EINA_FALSE;
}
return EINA_TRUE;
}
static Eina_Bool
_keytable_keycode_encode(int keycode, Ecore_X_Win_Keygrab_Mode grab_mode, int *encoded)
{
if ((grab_mode <= ECORE_X_WIN_KEYGRAB_UNKNOWN) ||
(grab_mode > ECORE_X_WIN_KEYGRAB_OVERRIDE_EXCLUSIVE))
{
*encoded = 0;
WRN("Keycode encoding failed. Unknown Keygrab mode");
return EINA_FALSE;
}
if (grab_mode == ECORE_X_WIN_KEYGRAB_SHARED)
*encoded = keycode | SHARED_GRAB;
else if (grab_mode == ECORE_X_WIN_KEYGRAB_TOPMOST)
*encoded = keycode | TOPMOST_GRAB;
else if (grab_mode == ECORE_X_WIN_KEYGRAB_EXCLUSIVE)
*encoded = keycode | EXCLUSIVE_GRAB;
else if (grab_mode == ECORE_X_WIN_KEYGRAB_OVERRIDE_EXCLUSIVE)
*encoded = keycode | OVERRIDE_EXCLUSIVE_GRAB;
return EINA_TRUE;
}
static int
_keytable_key_search(Ecore_X_Window_Key_Table *keytable, int key)
{
int i, code = 0, *list = NULL;
unsigned long count;
code = key & (~GRAB_MASK);
count = keytable->key_cnt;
list = keytable->key_list;
for (i = count - 1; i >= 0; i--)
if ((list[i] & (~GRAB_MASK)) == code) break;
return i;
}
static Eina_Bool
_keytable_key_add(Ecore_X_Window_Key_Table *keytable, int keycode, Ecore_X_Win_Keygrab_Mode grab_mode)
{
Ecore_X_Window win;
unsigned long count;
int i = 0, masked = 0;
win = keytable->win;
count = keytable->key_cnt;
if (!_keytable_keycode_encode(keycode, grab_mode, &masked))
return EINA_FALSE;
if (count == 0)
{
xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, win,
ECORE_X_ATOM_E_KEYROUTER_WINDOW_KEYTABLE,
ECORE_X_ATOM_CARDINAL, 32, 1,
(unsigned char *)&masked);
return EINA_TRUE;
}
else
{
i = _keytable_key_search(keytable, masked);
if (i != -1)
{
WRN("Key already exists");
return EINA_FALSE;
}
xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_APPEND, win,
ECORE_X_ATOM_E_KEYROUTER_WINDOW_KEYTABLE,
ECORE_X_ATOM_CARDINAL, 32, 1,
(unsigned char *)&masked);
return EINA_TRUE;
}
}
static Eina_Bool
_keytable_key_del(Ecore_X_Window_Key_Table *keytable, int key, Ecore_X_Atom atom)
{
int i, *new_key_list = NULL;
unsigned long count = 0;
i = _keytable_key_search(keytable, key);
if (i == -1)
{
WRN("Key does not exist in the key table");
return EINA_FALSE;
}
keytable->key_cnt--;
count = keytable->key_cnt;
if (count == 0)
{
ecore_x_window_prop_property_del(keytable->win, atom);
return EINA_TRUE;
}
new_key_list = malloc(count * sizeof(int));
if (!new_key_list) return EINA_FALSE;
if (i > 0)
memcpy(new_key_list, keytable->key_list, sizeof(int) * i);
if (count - i > 0)
memcpy(new_key_list + i, keytable->key_list + i + 1,
sizeof(int) * (count - i));
xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, keytable->win,
atom, ECORE_X_ATOM_CARDINAL, 32, count,
(unsigned char *)new_key_list);
free(new_key_list);
return EINA_TRUE;
}
static Eina_Bool
_keytable_possible_global_exclusiveness_get(int keycode)
{
Ecore_X_Window_Key_Table keytable;
int ret = 0;
keytable.win = ecore_x_window_root_first_get();
keytable.key_list = NULL;
keytable.key_cnt = 0;
if (_atom_grab_excl_win == XCB_NONE)
_atom_grab_excl_win = ecore_x_atom_get(STR_ATOM_GRAB_EXCL_WIN);
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;
}
ret = _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
_keytable_possible_global_exclusiveness_set(int keycode)
{
Ecore_X_Window_Key_Table keytable;
int ret = 0;
keytable.win = ecore_x_window_root_first_get();
keytable.key_list = NULL;
keytable.key_cnt = 0;
if (_atom_grab_excl_win == XCB_NONE)
_atom_grab_excl_win = ecore_x_atom_get(STR_ATOM_GRAB_EXCL_WIN);
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)
{
xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE,
keytable.win, _atom_grab_excl_win,
ECORE_X_ATOM_CARDINAL, 32, 1,
(unsigned char *)&keycode);
_keytable_free(&keytable);
return EINA_TRUE;
}
ret = _keytable_key_search(&keytable, keycode);
if (ret != -1)
{
xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_APPEND,
keytable.win, _atom_grab_excl_win,
ECORE_X_ATOM_CARDINAL, 32, 1,
(unsigned char *)&keycode);
_keytable_free(&keytable);
return EINA_TRUE;
}
WRN("Key is already grabbed");
_keytable_free(&keytable);
return EINA_FALSE;
}
static Eina_Bool
_keytable_possible_global_exclusiveness_unset(int keycode)
{
Ecore_X_Window_Key_Table keytable;
int ret = 0;
keytable.win = ecore_x_window_root_first_get();
keytable.key_list = NULL;
keytable.key_cnt = 0;
if (_atom_grab_excl_win == XCB_NONE)
_atom_grab_excl_win = ecore_x_atom_get(STR_ATOM_GRAB_EXCL_WIN);
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;
ret = _keytable_key_search(&keytable, keycode);
if (ret == -1)
{
WRN("Keygrab already exists");
_keytable_free(&keytable);
return EINA_FALSE;
}
else
ret = _keytable_key_del(&keytable, keycode, _atom_grab_excl_win);
_keytable_free(&keytable);
return EINA_FALSE;
}
static Eina_Bool
_ecore_xcb_window_keygrab_set_internal(Ecore_X_Window win, const char *key, Ecore_X_Win_Keygrab_Mode grab_mode)
{
Ecore_X_Window_Key_Table keytable;
xcb_keycode_t keycode = 0;
Eina_Bool ret = EINA_FALSE;
keytable.win = win;
keytable.key_list = NULL;
keytable.key_cnt = 0;
keycode = _ecore_xcb_keymap_string_to_keycode(key);
if (keycode == XCB_NO_SYMBOL)
{
WRN("Keycode of key(\"%s\") does not exist", key);
return EINA_FALSE;
}
if (grab_mode == ECORE_X_WIN_KEYGRAB_EXCLUSIVE)
{
if (!_keytable_possible_global_exclusiveness_get(keycode))
return EINA_FALSE;
}
if (!_keytable_get(win, &keytable)) return EINA_FALSE;
ret = _keytable_key_add(&keytable, keycode, grab_mode);
if (!ret)
{
WRN("Key(\"%s\") add failed", key);
goto err;
}
if (grab_mode == ECORE_X_WIN_KEYGRAB_EXCLUSIVE)
{
if (!_keytable_possible_global_exclusiveness_set(keycode))
{
_keytable_key_del(&keytable, keycode, ECORE_X_ATOM_E_KEYROUTER_WINDOW_KEYTABLE);
WRN("Key(\"%s\") already is grabbed", key);
goto err;
}
}
_keytable_free(&keytable);
return EINA_TRUE;
err:
_keytable_free(&keytable);
return EINA_FALSE;
}
static Eina_Bool
_ecore_xcb_window_keygrab_unset_internal(Ecore_X_Window win, const char *key)
{
Ecore_X_Window_Key_Table keytable;
Ecore_X_Win_Keygrab_Mode grab_mode = ECORE_X_WIN_KEYGRAB_UNKNOWN;
xcb_keycode_t keycode = 0;
int i, masked = 0, decoded = 0;
Eina_Bool ret = EINA_FALSE;
keytable.win = win;
keytable.key_list = NULL;
keytable.key_cnt = 0;
keycode = _ecore_xcb_keymap_string_to_keycode(key);
if (keycode == XCB_NO_SYMBOL)
{
WRN("Keycode of key(\"%s\") does not exist", key);
return EINA_FALSE;
}
if (!_keytable_get(win, &keytable)) return EINA_FALSE;
if (keytable.key_cnt <= 0) return EINA_FALSE;
i = _keytable_key_search(&keytable, keycode);
if (i == -1)
{
WRN("Key(\"%s\") does not exist", key);
goto err;
}
masked = keytable.key_list[i];
ret = _keytable_keycode_decode(masked, &decoded, &grab_mode);
if (!ret) goto err;
ret = _keytable_key_del(&keytable, masked, ECORE_X_ATOM_E_KEYROUTER_WINDOW_KEYTABLE);
if (!ret) goto err;
if (grab_mode == ECORE_X_WIN_KEYGRAB_EXCLUSIVE)
ret = _keytable_possible_global_exclusiveness_unset(keycode);
_keytable_free(&keytable);
return EINA_TRUE;
err:
_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_xcb_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_xcb_window_keygrab_unset_internal(win, key);
}