remove xcb support in ecore_x and evas engines as per mailing list
[platform/upstream/efl.git] / src / lib / ecore_x / ecore_x_keygrab.c
1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif /* ifdef HAVE_CONFIG_H */
4
5 #include <stdlib.h>
6
7
8 #ifdef LOGRT
9 #include <dlfcn.h>
10 #endif /* ifdef LOGRT */
11
12 #include "ecore_x_private.h"
13 #include "Ecore_X.h"
14 #include "Ecore_X_Atoms.h"
15
16
17 //////////////////////////////////////////////////////////////////////////////
18 // This api and structure only for the key router and window client side
19 // Application do not use this
20
21 //this mask is defined by key router.
22 //after discussing with keyrouter module, this mask can be changed
23 #define GRAB_MASK 0xffff00
24 #define OVERRIDE_EXCLUSIVE_GRAB 0xf00000
25 #define EXCLUSIVE_GRAB 0x0f0000
26 #define TOPMOST_GRAB 0x00f000
27 #define SHARED_GRAB 0x000f00
28
29 //if _ecore_keyrouter = 0, not yet check keyrouter
30 //if _ecore_keyrouter = -1, keyrouter not exist
31 //if _ecore_keyrouter = 1, keyrouter exist
32 int _ecore_keyrouter = 0;
33
34 struct _Ecore_X_Window_Key_Table
35 {
36    Ecore_X_Window       win;       //windo ID
37    int                 *key_list;  //list of key
38    unsigned long        key_cnt;   // the number of key
39 };
40
41 typedef struct _Ecore_X_Window_Key_Table             Ecore_X_Window_Key_Table;
42
43 static int       _ecore_x_window_keytable_key_search(Ecore_X_Window_Key_Table *keytable, int key);
44 static Eina_Bool _ecore_x_window_keytable_key_del(Ecore_X_Window_Key_Table *key_table, int key, Ecore_X_Atom keytable_atom);
45
46 static Eina_Bool _ecore_x_window_keytable_key_add(Ecore_X_Window_Key_Table *keytable,
47                                  int keycode,
48                                  Ecore_X_Win_Keygrab_Mode grab_mode);
49
50 static Eina_Bool _ecore_x_window_keygrab_set_internal(Ecore_X_Window win, const char *key, Ecore_X_Win_Keygrab_Mode grab_mode);
51 static Eina_Bool _ecore_x_window_keygrab_unset_internal(Ecore_X_Window win, const char *key);
52 static Eina_Bool _ecore_x_window_keytable_get(Ecore_X_Window win, Ecore_X_Window_Key_Table *keytable);
53
54
55 //(Below Atom and exclusiveness_get/set functions) should be changed after keyrouter finds the solution to avoid race condition
56 //solution 1. window manages two key table. keytable and keytable result
57 //solution 2. using client messabe between the window client and the key router.
58
59 static Atom _atom_grab_excl_win = None;
60 #define STR_ATOM_GRAB_EXCL_WIN "_GRAB_EXCL_WIN_KEYCODE"
61
62 static void
63 _keytable_free(Ecore_X_Window_Key_Table *keytable)
64 {
65    if (keytable->key_list)
66      free(keytable->key_list);
67    keytable->key_list = NULL;
68    keytable->win = 0;
69    keytable->key_cnt = 0;
70 }
71
72 static int
73 _keytable_property_list_get(Ecore_X_Window win,
74                             Ecore_X_Atom atom,
75                             unsigned int **plst)
76 {
77    unsigned char *prop_ret;
78    Atom type_ret;
79    unsigned long bytes_after, num_ret;
80    int format_ret;
81    unsigned int i, *val;
82    int num;
83
84    *plst = NULL;
85    prop_ret = NULL;
86    if (XGetWindowProperty(_ecore_x_disp, win, atom, 0, 0x7fffffff, False,
87                           XA_CARDINAL, &type_ret, &format_ret, &num_ret,
88                           &bytes_after, &prop_ret) != Success)
89      {
90         WRN("XGetWindowProperty failed");
91         return -1;
92      }
93    else if ((num_ret == 0) || (!prop_ret))
94      num = 0;
95    else
96      {
97         val = malloc(num_ret * sizeof(unsigned int));
98         if (!val)
99           {
100              if (prop_ret) XFree(prop_ret);
101              WRN("Memory alloc failed");
102              return -1;
103           }
104         for (i = 0; i < num_ret; i++)
105           val[i] = ((unsigned long *)prop_ret)[i];
106         num = num_ret;
107         *plst = val;
108      }
109
110    if (_ecore_xlib_sync) ecore_x_sync();
111    if (prop_ret)
112      XFree(prop_ret);
113    return num;
114 }
115
116 static Eina_Bool
117 _ecore_x_window_keytable_possible_global_exclusiveness_get(int keycode)
118 {
119    int ret = 0;
120
121    Ecore_X_Window_Key_Table keytable;
122
123    keytable.win = ecore_x_window_root_first_get();
124    keytable.key_list = NULL;
125    keytable.key_cnt = 0;
126
127    if(_atom_grab_excl_win == None )
128      _atom_grab_excl_win = XInternAtom(_ecore_x_disp, STR_ATOM_GRAB_EXCL_WIN, False);
129
130    ret = _keytable_property_list_get(keytable.win, _atom_grab_excl_win,
131                                      (unsigned int **)&(keytable.key_list));
132
133    if (ret < 0)
134      {
135             return EINA_FALSE;
136      }
137
138    keytable.key_cnt = ret;
139
140    if (keytable.key_cnt == 0)
141      {
142         WRN("There is no keygrab entry in the table");
143         return EINA_TRUE;
144      }
145
146    //check keycode exists in the global exclusiveness keytable
147
148    ret = _ecore_x_window_keytable_key_search(&keytable, keycode);
149    if (ret != -1)
150      {
151         WRN("Can't search keygrab entry in the table");
152         _keytable_free(&keytable);
153         return EINA_FALSE;
154      }
155    _keytable_free(&keytable);
156    return EINA_TRUE;
157 }
158
159 static Eina_Bool
160 _ecore_x_window_keytable_possible_global_exclusiveness_set(int keycode)
161 {
162    int ret = 0;
163
164    Ecore_X_Window_Key_Table keytable;
165
166    keytable.win = ecore_x_window_root_first_get();
167    keytable.key_list = NULL;
168    keytable.key_cnt = 0;
169
170    if(_atom_grab_excl_win == None )
171      _atom_grab_excl_win = XInternAtom(_ecore_x_disp, STR_ATOM_GRAB_EXCL_WIN, False);
172
173    ret = _keytable_property_list_get(keytable.win, _atom_grab_excl_win,
174                                      (unsigned int **)&(keytable.key_list));
175    if (ret < 0) return EINA_FALSE;
176
177    keytable.key_cnt = ret;
178
179    if (keytable.key_cnt == 0)
180      {
181         XChangeProperty(_ecore_x_disp, keytable.win, _atom_grab_excl_win, XA_CARDINAL, 32,
182                         PropModeReplace, (unsigned char *)&keycode, 1);
183         XSync(_ecore_x_disp, False);
184         _keytable_free(&keytable);
185         return EINA_TRUE;
186      }
187
188    //check keycode exists in the global exclusiveness keytable
189    ret = _ecore_x_window_keytable_key_search(&keytable, keycode);
190    if (ret != -1)
191      {
192         XChangeProperty(_ecore_x_disp, keytable.win, _atom_grab_excl_win, XA_CARDINAL, 32,
193                         PropModeAppend, (unsigned char *)&keycode, 1);
194         XSync(_ecore_x_disp, False);
195         _keytable_free(&keytable);
196         return EINA_TRUE;
197      }
198    WRN("Already key is grabbed");
199    _keytable_free(&keytable);
200    return EINA_FALSE;
201 }
202
203 static Eina_Bool
204 _ecore_x_window_keytable_possible_global_exclusiveness_unset(int keycode)
205 {
206    int ret = 0;
207
208    Ecore_X_Window_Key_Table keytable;
209
210    keytable.win = ecore_x_window_root_first_get();
211    keytable.key_list = NULL;
212    keytable.key_cnt = 0;
213
214    if(_atom_grab_excl_win == None )
215      _atom_grab_excl_win = XInternAtom(_ecore_x_disp, STR_ATOM_GRAB_EXCL_WIN, False);
216
217    ret = _keytable_property_list_get(keytable.win, _atom_grab_excl_win,
218                                      (unsigned int **)&(keytable.key_list));
219    if (ret <= 0) return EINA_FALSE;
220
221    keytable.key_cnt = ret;
222
223    //check keycode exists in the global exclusiveness keytable
224    ret = _ecore_x_window_keytable_key_search(&keytable, keycode);
225    if (ret == -1)
226      {
227         WRN("Already key exists");
228         _keytable_free(&keytable);
229         return EINA_FALSE;
230      }
231    else
232      ret = _ecore_x_window_keytable_key_del(&keytable, keycode, _atom_grab_excl_win);
233
234    _keytable_free(&keytable);
235    return EINA_FALSE;
236 }
237
238 static Eina_Bool
239 _ecore_x_window_keytable_keycode_decode(int keycode_encoded,
240                                         int *keycode,
241                                         Ecore_X_Win_Keygrab_Mode *grab_mode)
242 {
243    int key_mask = 0;
244
245    *keycode = keycode_encoded & (~GRAB_MASK);
246    key_mask = keycode_encoded & GRAB_MASK;
247
248    if (key_mask == SHARED_GRAB)
249      {
250         *grab_mode = ECORE_X_WIN_KEYGRAB_SHARED;
251         return EINA_TRUE;
252      }
253    else if (key_mask == TOPMOST_GRAB)
254      {
255         *grab_mode = ECORE_X_WIN_KEYGRAB_TOPMOST;
256         return EINA_TRUE;
257      }
258    else if (key_mask == EXCLUSIVE_GRAB)
259      {
260         *grab_mode = ECORE_X_WIN_KEYGRAB_EXCLUSIVE;
261         return EINA_TRUE;
262      }
263    else if (key_mask == OVERRIDE_EXCLUSIVE_GRAB)
264      {
265         *grab_mode = ECORE_X_WIN_KEYGRAB_OVERRIDE_EXCLUSIVE;
266         return EINA_TRUE;
267      }
268    else
269      {
270         *grab_mode = ECORE_X_WIN_KEYGRAB_UNKNOWN;
271         WRN("Keycode decoding failed. Unknown Keygrab mode");
272         return EINA_FALSE;
273      }
274 }
275
276 static Eina_Bool
277 _ecore_x_window_keytable_keycode_encode(int keycode,
278                                         Ecore_X_Win_Keygrab_Mode grab_mode,
279                                         int *keycode_encoded)
280 {
281    if ((grab_mode <= ECORE_X_WIN_KEYGRAB_UNKNOWN) || (grab_mode > ECORE_X_WIN_KEYGRAB_OVERRIDE_EXCLUSIVE))
282      {
283         *keycode_encoded = 0;
284         WRN("Keycode encoding failed. Unknown Keygrab mode");
285         return EINA_FALSE;
286      }
287    if (grab_mode == ECORE_X_WIN_KEYGRAB_SHARED)
288      *keycode_encoded = keycode | SHARED_GRAB;
289    else if (grab_mode == ECORE_X_WIN_KEYGRAB_TOPMOST)
290      *keycode_encoded = keycode | TOPMOST_GRAB;
291    else if (grab_mode == ECORE_X_WIN_KEYGRAB_EXCLUSIVE)
292      *keycode_encoded = keycode | EXCLUSIVE_GRAB;
293    else if (grab_mode == ECORE_X_WIN_KEYGRAB_OVERRIDE_EXCLUSIVE)
294      *keycode_encoded = keycode | OVERRIDE_EXCLUSIVE_GRAB;
295    return EINA_TRUE;
296 }
297
298 static Eina_Bool
299 _ecore_x_window_keytable_get(Ecore_X_Window win,
300                              Ecore_X_Window_Key_Table *keytable)
301 {
302    int ret = 0;
303
304    ret = _keytable_property_list_get(win, ECORE_X_ATOM_E_KEYROUTER_WINDOW_KEYTABLE,
305                                      (unsigned int **)&(keytable->key_list));
306    if (ret < 0) return EINA_FALSE;
307
308    keytable->key_cnt = ret;
309
310    return EINA_TRUE;
311 }
312
313 static int
314 _ecore_x_window_keytable_key_search(Ecore_X_Window_Key_Table *keytable,
315                                     int key)
316 {
317    int  i;
318    int keycode = 0;
319    unsigned long key_cnt;
320    int *key_list = NULL;
321
322    keycode = key & (~GRAB_MASK);
323    key_cnt = keytable->key_cnt;
324    key_list = keytable->key_list;
325
326    for (i = key_cnt - 1; i >= 0; i--)
327      {
328         if ((key_list[i] & (~GRAB_MASK)) == keycode) break;
329      }
330    return i;
331 }
332
333
334 static Eina_Bool
335 _ecore_x_window_keytable_key_add(Ecore_X_Window_Key_Table *keytable,
336                                  int keycode,
337                                  Ecore_X_Win_Keygrab_Mode grab_mode)
338 {
339    int i = 0;
340    int keycode_masked = 0;
341
342    Ecore_Window   win;
343    unsigned long  key_cnt;
344
345    win = keytable->win;
346    key_cnt = keytable->key_cnt;
347
348    if (!_ecore_x_window_keytable_keycode_encode(keycode, grab_mode, &keycode_masked))
349      return EINA_FALSE;
350
351    if (key_cnt == 0)
352      {
353         XChangeProperty(_ecore_x_disp, win, ECORE_X_ATOM_E_KEYROUTER_WINDOW_KEYTABLE, XA_CARDINAL, 32,
354                         PropModeReplace, (unsigned char *)&keycode_masked, 1);
355         XSync(_ecore_x_disp, False);
356         return EINA_TRUE;
357      }
358    else
359      {
360         i = _ecore_x_window_keytable_key_search(keytable, keycode_masked);
361         if ( i != -1 )
362           {
363              //already exist key in key table
364              WRN("Already key exists");
365              return EINA_FALSE;
366           }
367         XChangeProperty(_ecore_x_disp, win, ECORE_X_ATOM_E_KEYROUTER_WINDOW_KEYTABLE, XA_CARDINAL, 32,
368                         PropModeAppend, (unsigned char *)&keycode_masked, 1);
369         XSync(_ecore_x_disp, False);
370         return EINA_TRUE;
371      }
372 }
373
374 static Eina_Bool
375 _ecore_x_window_keytable_key_del(Ecore_X_Window_Key_Table *key_table,
376                                  int key,
377                                  Ecore_X_Atom keytable_atom)
378 {
379    int i;
380    int *new_key_list = NULL;
381    unsigned long key_cnt = 0;
382
383    // Only one element is exists in the list of grabbed key
384    i = _ecore_x_window_keytable_key_search(key_table, key);
385
386    if (i == -1)
387      {
388         WRN("Key doesn't exist in the key table.");
389         return EINA_FALSE;
390      }
391
392    (key_table->key_cnt)--;
393    key_cnt = key_table->key_cnt;
394
395    if (key_cnt == 0)
396      {
397         XDeleteProperty(_ecore_x_disp, key_table->win, keytable_atom);
398         XSync(_ecore_x_disp, False);
399         return EINA_TRUE;
400      }
401
402    // Shrink the buffer
403    new_key_list = malloc((key_cnt) * sizeof(int));
404
405    if (new_key_list == NULL)
406      return EINA_FALSE;
407
408    // copy head
409    if (i > 0)
410      memcpy(new_key_list, key_table->key_list, sizeof(int) * i);
411
412    // copy tail
413    if ((key_cnt) - i > 0)
414      {
415         memcpy(new_key_list + i,
416                key_table->key_list + i + 1,
417                sizeof(int) * (key_cnt - i));
418      }
419
420    XChangeProperty(_ecore_x_disp, key_table->win, keytable_atom, XA_CARDINAL, 32,
421                    PropModeReplace, (unsigned char *)new_key_list, key_cnt);
422    XSync(_ecore_x_disp, False);
423
424    free(new_key_list);
425    return EINA_TRUE;
426 }
427
428 static Eina_Bool
429 _ecore_x_window_keygrab_set_internal(Ecore_X_Window win,
430                                      const char *key,
431                                      Ecore_X_Win_Keygrab_Mode grab_mode)
432 {
433    KeyCode keycode = 0;
434    KeySym keysym;
435
436    Eina_Bool ret = EINA_FALSE;
437    Ecore_X_Window_Key_Table keytable;
438
439    keytable.win = win;
440    keytable.key_list = NULL;
441    keytable.key_cnt = 0;
442
443
444    //check the key string
445    if (!strncmp(key, "Keycode-", 8))
446      keycode = atoi(key + 8);
447    else
448      {
449         keysym = XStringToKeysym(key);
450         if (keysym == NoSymbol)
451           {
452              WRN("Keysym of key(\"%s\") doesn't exist", key);
453              return ret;
454           }
455         keycode = XKeysymToKeycode(_ecore_x_disp, keysym);
456      }
457
458    if (keycode == 0)
459      {
460         WRN("Keycode of key(\"%s\") doesn't exist", key);
461         return ret;
462      }
463
464    if(grab_mode == ECORE_X_WIN_KEYGRAB_EXCLUSIVE)
465      {
466         //Only one window can grab this key;
467         //keyrouter should avoid race condition
468         if (!_ecore_x_window_keytable_possible_global_exclusiveness_get(keycode))
469           return EINA_FALSE;
470      }
471
472    if (!_ecore_x_window_keytable_get(win, &keytable))
473      return EINA_FALSE;
474
475    ret = _ecore_x_window_keytable_key_add(&keytable, keycode, grab_mode);
476
477
478    if (!ret)
479      {
480         WRN("Key(\"%s\") add failed", key);
481         goto error;
482      }
483
484    if(grab_mode == ECORE_X_WIN_KEYGRAB_EXCLUSIVE)
485      {
486         //Only one window can grab this key;
487         if(!_ecore_x_window_keytable_possible_global_exclusiveness_set(keycode))
488           {
489              _ecore_x_window_keytable_key_del(&keytable, keycode, ECORE_X_ATOM_E_KEYROUTER_WINDOW_KEYTABLE);
490              WRN("Key(\"%s\") already is grabbed", key);
491              goto error;
492           }
493      }
494
495    _keytable_free(&keytable);
496    return EINA_TRUE;
497 error:
498    _keytable_free(&keytable);
499    return EINA_FALSE;
500 }
501
502 static Eina_Bool
503 _ecore_x_window_keygrab_unset_internal(Ecore_X_Window win,
504                                        const char *key)
505 {
506    KeyCode keycode = 0;
507    KeySym keysym;
508
509    int i;
510    int key_masked = 0;
511    int key_decoded = 0;
512
513    Eina_Bool ret = EINA_FALSE;
514
515    Ecore_X_Window_Key_Table keytable;
516    Ecore_X_Win_Keygrab_Mode grab_mode = ECORE_X_WIN_KEYGRAB_UNKNOWN;
517
518    keytable.win = win;
519    keytable.key_list = NULL;
520    keytable.key_cnt = 0;
521
522    if (!strncmp(key, "Keycode-", 8))
523      keycode = atoi(key + 8);
524    else
525      {
526         keysym = XStringToKeysym(key);
527         if (keysym == NoSymbol)
528           {
529              WRN("Keysym of key(\"%s\") doesn't exist", key);
530              return EINA_FALSE;
531           }
532         keycode = XKeysymToKeycode(_ecore_x_disp, keysym);
533      }
534
535    if (keycode == 0)
536      {
537         WRN("Keycode of key(\"%s\") doesn't exist", key);
538         return EINA_FALSE;
539      }
540
541    //construct the keytable structure using Xproperty
542    if (!_ecore_x_window_keytable_get(win, &keytable))
543       return EINA_FALSE;
544
545    if (keytable.key_cnt <= 0)
546      return EINA_FALSE;
547
548    i = _ecore_x_window_keytable_key_search(&keytable, keycode);
549
550    if (i == -1) //cannot find key in keytable
551      {
552         WRN("Key(\"%s\") doesn't exist", key);
553         goto error;
554      }
555
556    //find key in keytable
557    key_masked = keytable.key_list[i];
558
559    ret = _ecore_x_window_keytable_keycode_decode(key_masked, &key_decoded, &grab_mode);
560
561    if (!ret)
562      goto error;
563
564    ret = _ecore_x_window_keytable_key_del(&keytable, key_masked, ECORE_X_ATOM_E_KEYROUTER_WINDOW_KEYTABLE);
565    if (!ret)
566      goto error;
567
568    if (grab_mode == ECORE_X_WIN_KEYGRAB_EXCLUSIVE)
569      {
570         ret = _ecore_x_window_keytable_possible_global_exclusiveness_unset(keycode);
571      }
572
573    _keytable_free(&keytable);
574    return EINA_TRUE;
575 error:
576    _keytable_free(&keytable);
577    return EINA_FALSE;
578 }
579
580 EAPI Eina_Bool
581 ecore_x_window_keygrab_set(Ecore_X_Window win,
582                            const char *key,
583                            int mod EINA_UNUSED,
584                            int not_mod EINA_UNUSED,
585                            int priority EINA_UNUSED,
586                            Ecore_X_Win_Keygrab_Mode grab_mode)
587 {
588    if (_ecore_keyrouter == 0)
589      {
590         if(ecore_x_e_keyrouter_get(win))
591           _ecore_keyrouter = 1;
592         else
593           {
594              WRN("Keyrouter is not supported");
595              _ecore_keyrouter = -1;
596           }
597      }
598    if (_ecore_keyrouter < 0)
599      return EINA_FALSE;
600
601    return _ecore_x_window_keygrab_set_internal(win, key, grab_mode);
602 }
603
604 EAPI Eina_Bool
605 ecore_x_window_keygrab_unset(Ecore_X_Window win,
606                              const char *key,
607                              int mod EINA_UNUSED,
608                              int any_mod EINA_UNUSED)
609 {
610    if (_ecore_keyrouter != 1)
611      {
612         WRN("Keyrouter is not supported");
613         return EINA_FALSE;
614      }
615
616    return _ecore_x_window_keygrab_unset_internal(win, key);
617 }
618