d4f67821d78da259064f48b52b9f786fa68ec509
[platform/upstream/efl.git] / src / lib / ecore_x / xcb / ecore_xcb_keygrab.c
1 #include "ecore_xcb_private.h"
2
3 //////////////////////////////////////////////////////////////////////////////
4 // This api and structure only for the key router and window client side
5 // Application do not use this
6
7 //this mask is defined by key router.
8 //after discussing with keyrouter module, this mask can be changed
9 #define GRAB_MASK 0xffff00
10 #define OVERRIDE_EXCLUSIVE_GRAB 0xf00000
11 #define EXCLUSIVE_GRAB 0x0f0000
12 #define TOPMOST_GRAB 0x00f000
13 #define SHARED_GRAB 0x000f00
14
15 //if _ecore_keyrouter = 0, not yet check keyrouter
16 //if _ecore_keyrouter = -1, keyrouter not exist
17 //if _ecore_keyrouter = 1, keyrouter exist
18 int _ecore_keyrouter = 0;
19
20 typedef struct _Ecore_X_Window_Key_Table
21 {
22    Ecore_X_Window       win;       //windo ID
23    int                 *key_list;  //list of key
24    unsigned long        key_cnt;   // the number of key
25 } Ecore_X_Window_Key_Table;
26
27 static Ecore_X_Atom _atom_grab_excl_win = XCB_NONE;
28 #define STR_ATOM_GRAB_EXCL_WIN "_GRAB_EXCL_WIN_KEYCODE"
29
30 static void
31 _keytable_free(Ecore_X_Window_Key_Table *keytable)
32 {
33    if (keytable->key_list) free(keytable->key_list);
34    keytable->key_list = NULL;
35    keytable->win = 0;
36    keytable->key_cnt = 0;
37 }
38
39 static int
40 _keytable_property_list_get(Ecore_X_Window win, Ecore_X_Atom atom, unsigned int **plst)
41 {
42    return ecore_x_window_prop_card32_list_get(win, atom, plst);
43 }
44
45 static Eina_Bool
46 _keytable_get(Ecore_X_Window win, Ecore_X_Window_Key_Table *keytable)
47 {
48    int ret = 0;
49
50    ret = _keytable_property_list_get(win, ECORE_X_ATOM_E_KEYROUTER_WINDOW_KEYTABLE,
51                                      (unsigned int **)&(keytable->key_list));
52    if (ret < 0) return EINA_FALSE;
53
54    keytable->key_cnt = ret;
55    return EINA_TRUE;
56 }
57
58 static Eina_Bool
59 _keytable_keycode_decode(int encoded, int *keycode, Ecore_X_Win_Keygrab_Mode *grab_mode)
60 {
61    int mask = 0;
62
63    *keycode = encoded & (~GRAB_MASK);
64    mask = encoded & GRAB_MASK;
65
66    if (mask == SHARED_GRAB)
67      *grab_mode = ECORE_X_WIN_KEYGRAB_SHARED;
68    else if (mask == TOPMOST_GRAB)
69      *grab_mode = ECORE_X_WIN_KEYGRAB_TOPMOST;
70    else if (mask == EXCLUSIVE_GRAB)
71      *grab_mode = ECORE_X_WIN_KEYGRAB_EXCLUSIVE;
72    else if (mask == OVERRIDE_EXCLUSIVE_GRAB)
73      *grab_mode = ECORE_X_WIN_KEYGRAB_OVERRIDE_EXCLUSIVE;
74    else
75      {
76         *grab_mode = ECORE_X_WIN_KEYGRAB_UNKNOWN;
77         WRN("Keycode decoding failed. Unknown Keygrab mode");
78         return EINA_FALSE;
79      }
80
81    return EINA_TRUE;
82 }
83
84 static Eina_Bool
85 _keytable_keycode_encode(int keycode, Ecore_X_Win_Keygrab_Mode grab_mode, int *encoded)
86 {
87    if ((grab_mode <= ECORE_X_WIN_KEYGRAB_UNKNOWN) ||
88        (grab_mode > ECORE_X_WIN_KEYGRAB_OVERRIDE_EXCLUSIVE))
89      {
90         *encoded = 0;
91         WRN("Keycode encoding failed. Unknown Keygrab mode");
92         return EINA_FALSE;
93      }
94
95    if (grab_mode == ECORE_X_WIN_KEYGRAB_SHARED)
96      *encoded = keycode | SHARED_GRAB;
97    else if (grab_mode == ECORE_X_WIN_KEYGRAB_TOPMOST)
98      *encoded = keycode | TOPMOST_GRAB;
99    else if (grab_mode == ECORE_X_WIN_KEYGRAB_EXCLUSIVE)
100      *encoded = keycode | EXCLUSIVE_GRAB;
101    else if (grab_mode == ECORE_X_WIN_KEYGRAB_OVERRIDE_EXCLUSIVE)
102      *encoded = keycode | OVERRIDE_EXCLUSIVE_GRAB;
103
104    return EINA_TRUE;
105 }
106
107 static int
108 _keytable_key_search(Ecore_X_Window_Key_Table *keytable, int key)
109 {
110    int i, code = 0, *list = NULL;
111    unsigned long count;
112
113    code = key & (~GRAB_MASK);
114    count = keytable->key_cnt;
115    list = keytable->key_list;
116
117    for (i = count - 1; i >= 0; i--)
118      if ((list[i] & (~GRAB_MASK)) == code) break;
119
120    return i;
121 }
122
123 static Eina_Bool
124 _keytable_key_add(Ecore_X_Window_Key_Table *keytable, int keycode, Ecore_X_Win_Keygrab_Mode grab_mode)
125 {
126    Ecore_X_Window win;
127    unsigned long count;
128    int i = 0, masked = 0;
129
130    win = keytable->win;
131    count = keytable->key_cnt;
132
133    if (!_keytable_keycode_encode(keycode, grab_mode, &masked))
134      return EINA_FALSE;
135
136    if (count == 0)
137      {
138         xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, win,
139                             ECORE_X_ATOM_E_KEYROUTER_WINDOW_KEYTABLE,
140                             ECORE_X_ATOM_CARDINAL, 32, 1,
141                             (unsigned char *)&masked);
142         return EINA_TRUE;
143      }
144    else
145      {
146         i = _keytable_key_search(keytable, masked);
147         if (i != -1)
148           {
149              WRN("Key already exists");
150              return EINA_FALSE;
151           }
152         xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_APPEND, win,
153                             ECORE_X_ATOM_E_KEYROUTER_WINDOW_KEYTABLE,
154                             ECORE_X_ATOM_CARDINAL, 32, 1,
155                             (unsigned char *)&masked);
156         return EINA_TRUE;
157      }
158 }
159
160 static Eina_Bool
161 _keytable_key_del(Ecore_X_Window_Key_Table *keytable, int key, Ecore_X_Atom atom)
162 {
163    int i, *new_key_list = NULL;
164    unsigned long count = 0;
165
166    i = _keytable_key_search(keytable, key);
167    if (i == -1)
168      {
169         WRN("Key does not exist in the key table");
170         return EINA_FALSE;
171      }
172
173    keytable->key_cnt--;
174    count = keytable->key_cnt;
175    if (count == 0)
176      {
177         ecore_x_window_prop_property_del(keytable->win, atom);
178         return EINA_TRUE;
179      }
180
181    new_key_list = malloc(count * sizeof(int));
182    if (!new_key_list) return EINA_FALSE;
183
184    if (i > 0)
185      memcpy(new_key_list, keytable->key_list, sizeof(int) * i);
186
187    if (count - i > 0)
188      memcpy(new_key_list + i, keytable->key_list + i + 1,
189             sizeof(int) * (count - i));
190
191    xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, keytable->win,
192                        atom, ECORE_X_ATOM_CARDINAL, 32, count,
193                        (unsigned char *)new_key_list);
194
195    free(new_key_list);
196    return EINA_TRUE;
197 }
198
199 static Eina_Bool
200 _keytable_possible_global_exclusiveness_get(int keycode)
201 {
202    Ecore_X_Window_Key_Table keytable;
203    int ret = 0;
204
205    keytable.win = ecore_x_window_root_first_get();
206    keytable.key_list = NULL;
207    keytable.key_cnt = 0;
208
209    if (_atom_grab_excl_win == XCB_NONE)
210      _atom_grab_excl_win = ecore_x_atom_get(STR_ATOM_GRAB_EXCL_WIN);
211
212    ret = _keytable_property_list_get(keytable.win, _atom_grab_excl_win,
213                                      (unsigned int **)&(keytable.key_list));
214    if (ret < 0) return EINA_FALSE;
215
216    keytable.key_cnt = ret;
217    if (keytable.key_cnt == 0)
218      {
219         WRN("There is no keygrab entry in the table");
220         return EINA_TRUE;
221      }
222
223    ret = _keytable_key_search(&keytable, keycode);
224    if (ret != -1)
225      {
226         WRN("Can't search keygrab entry in the table");
227         _keytable_free(&keytable);
228         return EINA_FALSE;
229      }
230
231    _keytable_free(&keytable);
232    return EINA_TRUE;
233 }
234
235 static Eina_Bool
236 _keytable_possible_global_exclusiveness_set(int keycode)
237 {
238    Ecore_X_Window_Key_Table keytable;
239    int ret = 0;
240
241    keytable.win = ecore_x_window_root_first_get();
242    keytable.key_list = NULL;
243    keytable.key_cnt = 0;
244
245    if (_atom_grab_excl_win == XCB_NONE)
246      _atom_grab_excl_win = ecore_x_atom_get(STR_ATOM_GRAB_EXCL_WIN);
247
248    ret = _keytable_property_list_get(keytable.win, _atom_grab_excl_win,
249                                      (unsigned int **)&(keytable.key_list));
250    if (ret < 0) return EINA_FALSE;
251
252    keytable.key_cnt = ret;
253    if (keytable.key_cnt == 0)
254      {
255         xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE,
256                             keytable.win, _atom_grab_excl_win,
257                             ECORE_X_ATOM_CARDINAL, 32, 1,
258                             (unsigned char *)&keycode);
259         _keytable_free(&keytable);
260         return EINA_TRUE;
261      }
262
263    ret = _keytable_key_search(&keytable, keycode);
264    if (ret != -1)
265      {
266         xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_APPEND,
267                             keytable.win, _atom_grab_excl_win,
268                             ECORE_X_ATOM_CARDINAL, 32, 1,
269                             (unsigned char *)&keycode);
270         _keytable_free(&keytable);
271         return EINA_TRUE;
272      }
273
274    WRN("Key is already grabbed");
275    _keytable_free(&keytable);
276    return EINA_FALSE;
277 }
278
279 static Eina_Bool
280 _keytable_possible_global_exclusiveness_unset(int keycode)
281 {
282    Ecore_X_Window_Key_Table keytable;
283    int ret = 0;
284
285    keytable.win = ecore_x_window_root_first_get();
286    keytable.key_list = NULL;
287    keytable.key_cnt = 0;
288
289    if (_atom_grab_excl_win == XCB_NONE)
290      _atom_grab_excl_win = ecore_x_atom_get(STR_ATOM_GRAB_EXCL_WIN);
291
292    ret = _keytable_property_list_get(keytable.win, _atom_grab_excl_win,
293                                      (unsigned int **)&(keytable.key_list));
294    if (ret < 0) return EINA_FALSE;
295
296    keytable.key_cnt = ret;
297
298    ret = _keytable_key_search(&keytable, keycode);
299    if (ret == -1)
300      {
301         WRN("Keygrab already exists");
302         _keytable_free(&keytable);
303         return EINA_FALSE;
304      }
305    else
306      ret = _keytable_key_del(&keytable, keycode, _atom_grab_excl_win);
307
308    _keytable_free(&keytable);
309    return EINA_FALSE;
310 }
311
312 static Eina_Bool
313 _ecore_xcb_window_keygrab_set_internal(Ecore_X_Window win, const char *key, Ecore_X_Win_Keygrab_Mode grab_mode)
314 {
315    Ecore_X_Window_Key_Table keytable;
316    xcb_keycode_t keycode = 0;
317    Eina_Bool ret = EINA_FALSE;
318
319    keytable.win = win;
320    keytable.key_list = NULL;
321    keytable.key_cnt = 0;
322
323    keycode = _ecore_xcb_keymap_string_to_keycode(key);
324    if (keycode == XCB_NO_SYMBOL)
325      {
326         WRN("Keycode of key(\"%s\") does not exist", key);
327         return EINA_FALSE;
328      }
329
330    if (grab_mode == ECORE_X_WIN_KEYGRAB_EXCLUSIVE)
331      {
332         if (!_keytable_possible_global_exclusiveness_get(keycode))
333           return EINA_FALSE;
334      }
335
336    if (!_keytable_get(win, &keytable)) return EINA_FALSE;
337
338    ret = _keytable_key_add(&keytable, keycode, grab_mode);
339    if (!ret)
340      {
341         WRN("Key(\"%s\") add failed", key);
342         goto err;
343      }
344
345    if (grab_mode == ECORE_X_WIN_KEYGRAB_EXCLUSIVE)
346      {
347         if (!_keytable_possible_global_exclusiveness_set(keycode))
348           {
349              _keytable_key_del(&keytable, keycode, ECORE_X_ATOM_E_KEYROUTER_WINDOW_KEYTABLE);
350              WRN("Key(\"%s\") already is grabbed", key);
351              goto err;
352           }
353      }
354
355    _keytable_free(&keytable);
356    return EINA_TRUE;
357
358 err:
359    _keytable_free(&keytable);
360    return EINA_FALSE;
361 }
362
363 static Eina_Bool
364 _ecore_xcb_window_keygrab_unset_internal(Ecore_X_Window win, const char *key)
365 {
366    Ecore_X_Window_Key_Table keytable;
367    Ecore_X_Win_Keygrab_Mode grab_mode = ECORE_X_WIN_KEYGRAB_UNKNOWN;
368    xcb_keycode_t keycode = 0;
369    int i, masked = 0, decoded = 0;
370    Eina_Bool ret = EINA_FALSE;
371
372    keytable.win = win;
373    keytable.key_list = NULL;
374    keytable.key_cnt = 0;
375
376    keycode = _ecore_xcb_keymap_string_to_keycode(key);
377    if (keycode == XCB_NO_SYMBOL)
378      {
379         WRN("Keycode of key(\"%s\") does not exist", key);
380         return EINA_FALSE;
381      }
382
383    if (!_keytable_get(win, &keytable)) return EINA_FALSE;
384
385    if (keytable.key_cnt <= 0) return EINA_FALSE;
386
387    i = _keytable_key_search(&keytable, keycode);
388    if (i == -1)
389      {
390         WRN("Key(\"%s\") does not exist", key);
391         goto err;
392      }
393
394    masked = keytable.key_list[i];
395
396    ret = _keytable_keycode_decode(masked, &decoded, &grab_mode);
397    if (!ret) goto err;
398
399    ret = _keytable_key_del(&keytable, masked, ECORE_X_ATOM_E_KEYROUTER_WINDOW_KEYTABLE);
400    if (!ret) goto err;
401
402    if (grab_mode == ECORE_X_WIN_KEYGRAB_EXCLUSIVE)
403      ret = _keytable_possible_global_exclusiveness_unset(keycode);
404
405    _keytable_free(&keytable);
406    return EINA_TRUE;
407
408 err:
409    _keytable_free(&keytable);
410    return EINA_FALSE;
411 }
412
413 EAPI Eina_Bool
414 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)
415 {
416    if (_ecore_keyrouter == 0)
417      {
418         if (ecore_x_e_keyrouter_get(win))
419           _ecore_keyrouter = 1;
420         else
421           {
422              WRN("Keyrouter is not supported");
423              _ecore_keyrouter = -1;
424           }
425      }
426
427    if (_ecore_keyrouter < 0) return EINA_FALSE;
428
429    return _ecore_xcb_window_keygrab_set_internal(win, key, grab_mode);
430 }
431
432 EAPI Eina_Bool
433 ecore_x_window_keygrab_unset(Ecore_X_Window win, const char *key, int mod EINA_UNUSED, int any_mod EINA_UNUSED)
434 {
435    if (_ecore_keyrouter != 1)
436      {
437         WRN("Keyrouter is not supported");
438         return EINA_FALSE;
439      }
440
441    return _ecore_xcb_window_keygrab_unset_internal(win, key);
442 }