1 #include "evas_common_private.h"
2 #include "evas_private.h"
3 
4 /* private calls */
5 
6 /* FIXME: this is not optimal, but works. i should have a hash of keys per */
7 /* Evas and then a linked lists of grabs for that key and what */
8 /* modifiers/not_modifers they use */
9 
10 static Evas_Key_Grab *evas_key_grab_new  (Evas_Object *eo_obj, Evas_Object_Protected_Data *obj, const char *keyname, Evas_Modifier_Mask modifiers, Evas_Modifier_Mask not_modifiers, Eina_Bool exclusive);
11 static Evas_Key_Grab *evas_key_grab_find (Evas_Object *eo_obj, Evas_Object_Protected_Data *obj, const char *keyname, Evas_Modifier_Mask modifiers, Evas_Modifier_Mask not_modifiers);
12 
13 static Evas_Key_Grab *
evas_key_grab_new(Evas_Object * eo_obj,Evas_Object_Protected_Data * obj,const char * keyname,Evas_Modifier_Mask modifiers,Evas_Modifier_Mask not_modifiers,Eina_Bool exclusive)14 evas_key_grab_new(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj, const char *keyname, Evas_Modifier_Mask modifiers, Evas_Modifier_Mask not_modifiers, Eina_Bool exclusive)
15 {
16    /* MEM OK */
17    Eina_List *l;
18    Evas_Key_Grab *g;
19    Eina_Bool have_exclusion = EINA_FALSE;
20 
21    EINA_LIST_FOREACH(obj->layer->evas->grabs, l, g)
22      {
23         if ((g->modifiers == modifiers) &&
24             (g->not_modifiers == not_modifiers) &&
25             (!strcmp(g->keyname, keyname)) &&
26             (g->exclusive))
27           {
28              have_exclusion = EINA_TRUE;
29              break;
30           }
31      }
32 
33    if (have_exclusion && exclusive) return NULL;
34 
35    g = calloc(1, sizeof(Evas_Key_Grab));
36    if (!g) return NULL;
37    g->object = eo_obj;
38    g->modifiers = modifiers;
39    g->not_modifiers = not_modifiers;
40    g->exclusive = exclusive;
41    g->keyname = strdup(keyname);
42    if (obj->layer->evas->walking_grabs)
43      g->just_added = EINA_TRUE;
44    g->is_active = EINA_TRUE;
45    if (!g->keyname)
46      {
47         free(g);
48         return NULL;
49      }
50 
51    if (exclusive)
52      {
53         Evas_Key_Grab *ge;
54         EINA_LIST_FOREACH(obj->layer->evas->grabs, l, ge)
55           {
56              if ((ge->modifiers == modifiers) &&
57                  (ge->not_modifiers == not_modifiers) &&
58                  (!strcmp(ge->keyname, keyname)))
59                {
60                   ge->is_active = EINA_FALSE;
61                }
62           }
63      }
64    if (have_exclusion) g->is_active = EINA_FALSE;
65 
66    obj->grabs = eina_list_append(obj->grabs, g);
67    obj->layer->evas->grabs = eina_list_append(obj->layer->evas->grabs, g);
68    return g;
69 }
70 
71 static Evas_Key_Grab *
evas_key_grab_find(Evas_Object * eo_obj,Evas_Object_Protected_Data * obj,const char * keyname,Evas_Modifier_Mask modifiers,Evas_Modifier_Mask not_modifiers)72 evas_key_grab_find(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj, const char *keyname, Evas_Modifier_Mask modifiers, Evas_Modifier_Mask not_modifiers)
73 {
74    /* MEM OK */
75    Eina_List *l;
76    Evas_Key_Grab *g;
77 
78    EINA_LIST_FOREACH(obj->layer->evas->grabs, l, g)
79      {
80         if ((g->modifiers == modifiers) &&
81             (g->not_modifiers == not_modifiers) &&
82             (!strcmp(g->keyname, keyname)))
83           {
84              if (eo_obj == g->object) return g;
85           }
86      }
87    return NULL;
88 }
89 
90 /* local calls */
91 
92 void
evas_object_grabs_cleanup(Evas_Object * eo_obj EINA_UNUSED,Evas_Object_Protected_Data * obj)93 evas_object_grabs_cleanup(Evas_Object *eo_obj EINA_UNUSED, Evas_Object_Protected_Data *obj)
94 {
95    if ((!obj->layer) || (!obj->layer->evas)) return;
96    if (obj->layer->evas->walking_grabs)
97      {
98         Eina_List *l;
99         Evas_Key_Grab *g;
100 
101         EINA_LIST_FOREACH(obj->grabs, l, g)
102           g->delete_me = EINA_TRUE;
103      }
104    else
105      {
106         while (obj->grabs)
107           {
108              Evas_Key_Grab *g = obj->grabs->data;
109              obj->layer->evas->grabs =
110                eina_list_remove(obj->layer->evas->grabs, g);
111              obj->grabs = eina_list_remove(obj->grabs, g);
112              if (g->keyname) free(g->keyname);
113              free(g);
114           }
115      }
116 }
117 
118 void
evas_key_grab_free(Evas_Object * eo_obj,Evas_Object_Protected_Data * obj,const char * keyname,Evas_Modifier_Mask modifiers,Evas_Modifier_Mask not_modifiers)119 evas_key_grab_free(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj, const char *keyname, Evas_Modifier_Mask modifiers, Evas_Modifier_Mask not_modifiers)
120 {
121    /* MEM OK */
122    Evas_Key_Grab *g;
123 
124    g = evas_key_grab_find(eo_obj, obj, keyname, modifiers, not_modifiers);
125    if (!g) return;
126    Evas_Object_Protected_Data *g_object = efl_data_scope_get(g->object, EFL_CANVAS_OBJECT_CLASS);
127    g_object->grabs = eina_list_remove(g_object->grabs, g);
128    obj->layer->evas->grabs = eina_list_remove(obj->layer->evas->grabs, g);
129    if (g->keyname) free(g->keyname);
130    free(g);
131 }
132 
133 // Legacy implementation. TODO: remove use of Evas_Modifier_Mask
134 
135 static Eina_Bool
_object_key_grab(Eo * eo_obj,Evas_Object_Protected_Data * obj,const char * keyname,Evas_Modifier_Mask modifiers,Evas_Modifier_Mask not_modifiers,Eina_Bool exclusive)136 _object_key_grab(Eo *eo_obj, Evas_Object_Protected_Data *obj, const char *keyname,
137                  Evas_Modifier_Mask modifiers, Evas_Modifier_Mask not_modifiers,
138                  Eina_Bool exclusive)
139 {
140    /* MEM OK */
141    Evas_Key_Grab *g;
142 
143    if (((modifiers == not_modifiers) && (modifiers != 0)) || (!keyname)) return EINA_FALSE;
144    g = evas_key_grab_new(eo_obj, obj, keyname, modifiers, not_modifiers, exclusive);
145    return ((!g) ? EINA_FALSE : EINA_TRUE);
146 }
147 
148 static void
_object_key_ungrab(Eo * eo_obj,Evas_Object_Protected_Data * obj,const char * keyname,Evas_Modifier_Mask modifiers,Evas_Modifier_Mask not_modifiers)149 _object_key_ungrab(Eo *eo_obj, Evas_Object_Protected_Data *obj, const char *keyname,
150                    Evas_Modifier_Mask modifiers, Evas_Modifier_Mask not_modifiers)
151 {
152    /* MEM OK */
153    Evas_Key_Grab *g;
154    Eina_List *l;
155 
156    if (!keyname) return;
157    g = evas_key_grab_find(eo_obj, obj, keyname, modifiers, not_modifiers);
158    if (!g) return;
159    Evas_Object_Protected_Data *g_object = efl_data_scope_get(g->object, EFL_CANVAS_OBJECT_CLASS);
160    if (g_object->layer->evas->walking_grabs)
161      {
162         if (!g->delete_me)
163           {
164              g_object->layer->evas->delete_grabs++;
165              g->delete_me = EINA_TRUE;
166           }
167      }
168    else
169      {
170         if (g->exclusive)
171           {
172              Evas_Key_Grab *ge;
173              EINA_LIST_FOREACH(obj->layer->evas->grabs, l, ge)
174                {
175                   if ((ge->modifiers == modifiers) &&
176                      (ge->not_modifiers == not_modifiers) &&
177                      (!strcmp(ge->keyname, keyname)))
178                     {
179                        if (!ge->is_active) ge->is_active = EINA_TRUE;
180                     }
181                }
182           }
183 
184         evas_key_grab_free(g->object, g_object, keyname, modifiers, not_modifiers);
185      }
186 }
187 
188 static inline Evas_Modifier_Mask
_efl_input_modifier_to_evas_modifier_mask(Evas_Public_Data * e,Efl_Input_Modifier in)189 _efl_input_modifier_to_evas_modifier_mask(Evas_Public_Data *e, Efl_Input_Modifier in)
190 {
191    Evas_Modifier_Mask out = 0;
192    size_t i;
193 
194    static const Efl_Input_Modifier mods[] = {
195       EFL_INPUT_MODIFIER_ALT,
196       EFL_INPUT_MODIFIER_CONTROL,
197       EFL_INPUT_MODIFIER_SHIFT,
198       EFL_INPUT_MODIFIER_META,
199       EFL_INPUT_MODIFIER_ALTGR,
200       EFL_INPUT_MODIFIER_HYPER,
201       EFL_INPUT_MODIFIER_SUPER
202    };
203 
204    for (i = 0; i < EINA_C_ARRAY_LENGTH(mods); i++)
205      if (in & mods[i])
206        {
207           out |= evas_key_modifier_mask_get
208                 (e->evas, _efl_input_modifier_to_string(mods[i]));
209        }
210 
211    return out;
212 }
213 
214 // EO API
215 
216 EOLIAN Eina_Bool
_efl_canvas_object_key_grab(Eo * eo_obj,Evas_Object_Protected_Data * obj,const char * keyname,Efl_Input_Modifier mod,Efl_Input_Modifier not_mod,Eina_Bool exclusive)217 _efl_canvas_object_key_grab(Eo *eo_obj, Evas_Object_Protected_Data *obj,
218                             const char *keyname, Efl_Input_Modifier mod,
219                             Efl_Input_Modifier not_mod, Eina_Bool exclusive)
220 {
221    Evas_Modifier_Mask modifiers, not_modifiers;
222 
223    EVAS_OBJECT_DATA_VALID_CHECK(obj, EINA_FALSE);
224    modifiers = _efl_input_modifier_to_evas_modifier_mask(obj->layer->evas, mod);
225    not_modifiers = _efl_input_modifier_to_evas_modifier_mask(obj->layer->evas, not_mod);
226 
227    return _object_key_grab(eo_obj, obj, keyname, modifiers, not_modifiers, exclusive);
228 }
229 
230 EOLIAN void
_efl_canvas_object_key_ungrab(Eo * eo_obj,Evas_Object_Protected_Data * obj,const char * keyname,Efl_Input_Modifier mod,Efl_Input_Modifier not_mod)231 _efl_canvas_object_key_ungrab(Eo *eo_obj, Evas_Object_Protected_Data *obj,
232                               const char *keyname, Efl_Input_Modifier mod,
233                               Efl_Input_Modifier not_mod)
234 {
235    Evas_Modifier_Mask modifiers, not_modifiers;
236 
237    EVAS_OBJECT_DATA_VALID_CHECK(obj);
238    modifiers = _efl_input_modifier_to_evas_modifier_mask(obj->layer->evas, mod);
239    not_modifiers = _efl_input_modifier_to_evas_modifier_mask(obj->layer->evas, not_mod);
240 
241    _object_key_ungrab(eo_obj, obj, keyname, modifiers, not_modifiers);
242 }
243 
244 // Legacy API
245 
246 EAPI Eina_Bool
evas_object_key_grab(Evas_Object * eo_obj,const char * keyname,Evas_Modifier_Mask modifiers,Evas_Modifier_Mask not_modifiers,Eina_Bool exclusive)247 evas_object_key_grab(Evas_Object *eo_obj, const char *keyname,
248                      Evas_Modifier_Mask modifiers, Evas_Modifier_Mask not_modifiers,
249                      Eina_Bool exclusive)
250 {
251    Evas_Object_Protected_Data *obj;
252 
253    obj = EVAS_OBJECT_DATA_SAFE_GET(eo_obj);
254    EVAS_OBJECT_DATA_VALID_CHECK(obj, EINA_FALSE);
255 
256    return _object_key_grab(eo_obj, obj, keyname, modifiers, not_modifiers, exclusive);
257 }
258 
259 EAPI void
evas_object_key_ungrab(Efl_Canvas_Object * eo_obj,const char * keyname,Evas_Modifier_Mask modifiers,Evas_Modifier_Mask not_modifiers)260 evas_object_key_ungrab(Efl_Canvas_Object *eo_obj, const char *keyname,
261                        Evas_Modifier_Mask modifiers, Evas_Modifier_Mask not_modifiers)
262 {
263    Evas_Object_Protected_Data *obj;
264 
265    obj = EVAS_OBJECT_DATA_SAFE_GET(eo_obj);
266    EVAS_OBJECT_DATA_VALID_CHECK(obj);
267 
268    _object_key_ungrab(eo_obj, obj, keyname, modifiers, not_modifiers);
269 }
270