1 #define EFL_INTERNAL_UNSTABLE
2 #define EFL_INPUT_EVENT_PROTECTED
3 
4 #include "evas_common_private.h"
5 #include "evas_private.h"
6 
7 static int evas_focus_log_domain = -1;
8 
9 #define F_CRI(...) EINA_LOG_DOM_CRIT(evas_focus_log_domain, __VA_ARGS__)
10 #define F_ERR(...) EINA_LOG_DOM_ERR(evas_focus_log_domain, __VA_ARGS__)
11 #define F_WRN(...) EINA_LOG_DOM_WARN(evas_focus_log_domain, __VA_ARGS__)
12 #define F_INF(...) EINA_LOG_DOM_INFO(evas_focus_log_domain, __VA_ARGS__)
13 #define F_DBG(...) EINA_LOG_DOM_DBG(evas_focus_log_domain, __VA_ARGS__)
14 
15 /* private calls */
16 
17 /* local calls */
18 
19 /* public calls */
20 
21 void
evas_focus_init(void)22 evas_focus_init(void)
23 {
24    evas_focus_log_domain = eina_log_domain_register("evas-focus", "red");
25 }
26 
27 void
evas_focus_shutdown(void)28 evas_focus_shutdown(void)
29 {
30    eina_log_domain_unregister(evas_focus_log_domain);
31    evas_focus_log_domain = -1;
32 }
33 
34 static Eina_Bool
_already_focused(Eina_List * seats,Efl_Input_Device * seat)35 _already_focused(Eina_List *seats, Efl_Input_Device *seat)
36 {
37    Eina_List *l;
38    const Efl_Input_Device *s;
39 
40    EINA_LIST_FOREACH(seats, l, s)
41      {
42         if (s == seat)
43           return EINA_TRUE;
44      }
45 
46    return EINA_FALSE;
47 }
48 
49 static Efl_Input_Device *
_default_seat_get(const Eo * evas_obj)50 _default_seat_get(const Eo *evas_obj)
51 {
52    Evas_Public_Data *edata;
53    Evas *evas = evas_object_evas_get((Evas_Object *)evas_obj);
54 
55    edata = efl_data_scope_get(evas, EVAS_CANVAS_CLASS);
56    if (!edata) return NULL;
57    return edata->default_seat;
58 }
59 
60 #define DEBUG_TUPLE(v) v, (v ? efl_class_name_get(v) : "(null)")
61 
62 static void
_evas_focus_set(Eo * evas_obj,Efl_Input_Device * key,Eina_Bool focus)63 _evas_focus_set(Eo *evas_obj, Efl_Input_Device *key, Eina_Bool focus)
64 {
65    Evas_Public_Data *edata;
66    Evas *evas = evas_object_evas_get(evas_obj);
67 
68    EINA_SAFETY_ON_NULL_RETURN(evas);
69    edata = efl_data_scope_get(evas, EVAS_CANVAS_CLASS);
70 
71    F_DBG("Focus moved in %d from (%p,%s) to (%p,%s)", efl_input_device_seat_id_get(key), DEBUG_TUPLE(eina_hash_find(edata->focused_objects, &key)), DEBUG_TUPLE(evas_obj));
72 
73    if (focus)
74      {
75         Eo *foc;
76 
77         foc = eina_hash_set(edata->focused_objects, &key, evas_obj);
78         if (foc)
79           {
80              F_ERR("Element %p was focused while a other object was unfocused, this is not expected! No unfocus event will be sent to it", foc);
81           }
82      }
83    else
84      eina_hash_del_by_key(edata->focused_objects, &key);
85 }
86 
87 static Eo *
_current_focus_get(Eo * evas_obj,Efl_Input_Device * key)88 _current_focus_get(Eo *evas_obj, Efl_Input_Device *key)
89 {
90    Evas_Public_Data *edata;
91    Evas *evas = evas_object_evas_get(evas_obj);
92 
93    EINA_SAFETY_ON_NULL_RETURN_VAL(evas, NULL);
94    edata = efl_data_scope_get(evas, EVAS_CANVAS_CLASS);
95 
96    return eina_hash_find(edata->focused_objects, &key);
97 }
98 
99 void
_evas_focus_dispatch_event(Evas_Object_Protected_Data * obj,Efl_Input_Device * seat,Eina_Bool in)100 _evas_focus_dispatch_event(Evas_Object_Protected_Data *obj, Efl_Input_Device *seat, Eina_Bool in)
101 {
102    Efl_Input_Focus_Data *ev_data;
103    Efl_Input_Focus *evt;
104    Evas_Callback_Type cb_evas, cb_obj_evas;
105    const Efl_Event_Description *efl_object_focus_event;
106 
107    EVAS_OBJECT_DATA_VALID_CHECK(obj);
108    evt = efl_input_focus_instance_get(
109                                 efl_provider_find(obj->object, EVAS_CANVAS_CLASS),
110                                 (void **) &ev_data);
111    if (!evt) return;
112 
113    ev_data->device = efl_ref(seat);
114    efl_wref_add(obj->object, &ev_data->object_wref);
115    ev_data->timestamp = time(NULL);
116 
117    if (in)
118      {
119         cb_obj_evas = EVAS_CALLBACK_FOCUS_IN;
120         cb_evas = EVAS_CALLBACK_CANVAS_OBJECT_FOCUS_IN;
121         efl_object_focus_event = EFL_EVENT_FOCUS_IN;
122      }
123    else
124      {
125         cb_obj_evas = EVAS_CALLBACK_FOCUS_OUT;
126         cb_evas = EVAS_CALLBACK_CANVAS_OBJECT_FOCUS_OUT;
127         efl_object_focus_event = EFL_EVENT_FOCUS_OUT;
128      }
129 
130    evas_object_event_callback_call(obj->object, obj,
131                                    cb_obj_evas,
132                                    evt, _evas_object_event_new(),
133                                    efl_object_focus_event);
134    evas_event_callback_call(obj->layer->evas->evas, cb_evas, evt);
135    efl_unref(evt);
136 }
137 
138 static void
_evas_object_unfocus(Evas_Object_Protected_Data * obj,Efl_Input_Device * seat)139 _evas_object_unfocus(Evas_Object_Protected_Data *obj, Efl_Input_Device *seat)
140 {
141    int event_id = _evas_event_counter;
142 
143    EVAS_OBJECT_DATA_VALID_CHECK(obj);
144    EINA_COW_WRITE_BEGIN(evas_object_events_cow, obj->events, Evas_Object_Events_Data, events)
145      events->focused_by_seats = eina_list_remove(events->focused_by_seats, seat);
146    EINA_COW_WRITE_END(evas_object_events_cow, obj->events, events);
147 
148    _evas_focus_set(obj->object, seat, EINA_FALSE);
149    _evas_focus_dispatch_event(obj, seat, EINA_FALSE);
150    _evas_post_event_callback_call(obj->layer->evas->evas, obj->layer->evas, event_id);
151 }
152 
153 void
_evas_focus_device_invalidate_cb(void * data,const Efl_Event * ev)154 _evas_focus_device_invalidate_cb(void *data, const Efl_Event *ev)
155 {
156    _evas_object_unfocus(data, ev->object);
157 }
158 
159 EOLIAN Eina_Bool
_efl_canvas_object_seat_focus_del(Eo * eo_obj,Evas_Object_Protected_Data * obj,Efl_Input_Device * seat)160 _efl_canvas_object_seat_focus_del(Eo *eo_obj,
161                                   Evas_Object_Protected_Data *obj,
162                                   Efl_Input_Device *seat)
163 {
164    Eina_List *l;
165    Efl_Input_Device *dev;
166    Eo *default_seat;
167 
168    MAGIC_CHECK(eo_obj, Evas_Object, MAGIC_OBJ);
169    return EINA_FALSE;
170    MAGIC_CHECK_END();
171 
172    if (seat) default_seat = _default_seat_get(eo_obj);
173    else default_seat = seat = _default_seat_get(eo_obj);
174 
175    if ((!seat) && obj->layer)
176      {
177         if (obj->layer->evas->pending_default_focus_obj == eo_obj)
178           obj->layer->evas->pending_default_focus_obj = NULL;
179      }
180 
181    EINA_LIST_FOREACH(obj->events->focused_by_seats, l, dev)
182      {
183         if (dev != seat)
184           continue;
185         if (obj->interceptors && obj->interceptors->focus_set.func && obj->interceptors->device_focus_set.func)
186           {
187              CRI("Your object is trying to use both focus_set and device_focus_set intercept! Sad!");
188              return EINA_FALSE;
189           }
190         if (obj->interceptors && obj->interceptors->focus_set.func && (seat == default_seat))
191           {
192              if (_evas_object_intercept_call_evas(obj, EVAS_OBJECT_INTERCEPT_CB_FOCUS_SET,
193                                                   1, EINA_FALSE))
194                {
195                   return EINA_FALSE;
196                }
197           }
198         else if (_evas_object_intercept_call_evas(obj, EVAS_OBJECT_INTERCEPT_CB_DEVICE_FOCUS_SET,
199                                              1, EINA_FALSE, seat))
200           {
201              return EINA_FALSE;
202           }
203 
204         efl_event_callback_del(dev, EFL_EVENT_INVALIDATE,
205                                _evas_focus_device_invalidate_cb, obj);
206         _evas_object_unfocus(obj, dev);
207         return EINA_TRUE;
208      }
209 
210    return EINA_FALSE;
211 }
212 
213 EOLIAN Eina_Bool
_efl_canvas_object_seat_focus_add(Eo * eo_obj,Evas_Object_Protected_Data * obj,Efl_Input_Device * seat)214 _efl_canvas_object_seat_focus_add(Eo *eo_obj,
215                                   Evas_Object_Protected_Data *obj,
216                                   Efl_Input_Device *seat)
217 {
218    Eo *current_focus;
219    int event_id;
220    Eo *default_seat;
221 
222    MAGIC_CHECK(eo_obj, Evas_Object, MAGIC_OBJ);
223    return EINA_FALSE;
224    MAGIC_CHECK_END();
225 
226    EINA_SAFETY_ON_FALSE_RETURN_VAL(!efl_invalidating_get(eo_obj) && !efl_invalidated_get(eo_obj), EINA_FALSE);
227 
228    event_id = _evas_event_counter;
229    if (seat) default_seat = _default_seat_get(eo_obj);
230    else default_seat = seat = _default_seat_get(eo_obj);
231 
232    if (seat && (efl_input_device_type_get(seat) != EFL_INPUT_DEVICE_TYPE_SEAT))
233      return EINA_FALSE;
234 
235    if (obj->layer && (!seat))
236      {
237         obj->layer->evas->pending_default_focus_obj = eo_obj;
238         return EINA_TRUE; //questionable return
239      }
240 
241    if (!efl_input_seat_event_filter_get(eo_obj, seat))
242      return EINA_FALSE;
243 
244    if (_already_focused(obj->events->focused_by_seats, seat))
245      goto end;
246 
247    if (obj->interceptors && obj->interceptors->focus_set.func && obj->interceptors->device_focus_set.func)
248      {
249         CRI("Your object is trying to use both focus_set and device_focus_set intercept! Sad!");
250         return EINA_FALSE;
251      }
252    if (obj->interceptors && obj->interceptors->focus_set.func && (seat == default_seat))
253      {
254         if (_evas_object_intercept_call_evas(obj, EVAS_OBJECT_INTERCEPT_CB_FOCUS_SET,
255                                              1, EINA_TRUE))
256           {
257              return EINA_FALSE;
258           }
259      }
260    else if (_evas_object_intercept_call_evas(obj, EVAS_OBJECT_INTERCEPT_CB_DEVICE_FOCUS_SET,
261                                         1, EINA_TRUE, seat))
262      {
263         return EINA_FALSE;
264      }
265    current_focus = _current_focus_get(eo_obj, seat);
266    if (current_focus)
267      efl_canvas_object_seat_focus_del(current_focus, seat);
268 
269    //In case intercept focus callback focused object we should return.
270    if (_current_focus_get(eo_obj, seat)) goto end;
271 
272    efl_event_callback_add(seat, EFL_EVENT_INVALIDATE, _evas_focus_device_invalidate_cb, obj);
273 
274    EINA_COW_WRITE_BEGIN(evas_object_events_cow, obj->events, Evas_Object_Events_Data, events)
275      events->focused_by_seats = eina_list_append(events->focused_by_seats, seat);
276    EINA_COW_WRITE_END(evas_object_events_cow, obj->events, events);
277 
278    _evas_focus_set(eo_obj, seat, EINA_TRUE);
279 
280    _evas_focus_dispatch_event(obj, seat, EINA_TRUE);
281  end:
282    if (obj->layer)
283      _evas_post_event_callback_call(obj->layer->evas->evas, obj->layer->evas, event_id);
284    return EINA_TRUE;
285 }
286 
287 EOLIAN Eina_Bool
_efl_canvas_object_seat_focus_check(const Eo * eo_obj,Evas_Object_Protected_Data * obj,Efl_Input_Device * seat)288 _efl_canvas_object_seat_focus_check(const Eo *eo_obj,
289                                     Evas_Object_Protected_Data *obj,
290                                     Efl_Input_Device *seat)
291 {
292    Eina_List *l;
293    Efl_Input_Device *s;
294 
295    MAGIC_CHECK(eo_obj, Evas_Object, MAGIC_OBJ);
296    return EINA_FALSE;
297    MAGIC_CHECK_END();
298 
299    if (!seat) seat = _default_seat_get(eo_obj);
300 
301    EINA_LIST_FOREACH(obj->events->focused_by_seats, l, s)
302      {
303         if (s == seat)
304           return EINA_TRUE;
305      }
306    return EINA_FALSE;
307 }
308 
309 EOLIAN void
_efl_canvas_object_key_focus_set(Eo * eo_obj,Evas_Object_Protected_Data * obj,Eina_Bool focus)310 _efl_canvas_object_key_focus_set(Eo *eo_obj, Evas_Object_Protected_Data *obj, Eina_Bool focus)
311 {
312    MAGIC_CHECK(eo_obj, Evas_Object, MAGIC_OBJ);
313    return;
314    MAGIC_CHECK_END();
315 
316    if (_efl_canvas_object_seat_focus_check(eo_obj, obj, NULL) == focus) return;
317 
318    if (focus)
319      _efl_canvas_object_seat_focus_add(eo_obj, obj, NULL);
320    else
321      _efl_canvas_object_seat_focus_del(eo_obj, obj, NULL);
322 }
323 
324 EOLIAN Eina_Bool
_efl_canvas_object_seat_focus_get(const Eo * eo_obj,Evas_Object_Protected_Data * obj)325 _efl_canvas_object_seat_focus_get(const Eo *eo_obj, Evas_Object_Protected_Data *obj)
326 {
327    MAGIC_CHECK(eo_obj, Evas_Object, MAGIC_OBJ);
328    return EINA_FALSE;
329    MAGIC_CHECK_END();
330 
331    return eina_list_count(obj->events->focused_by_seats) ? EINA_TRUE : EINA_FALSE;
332 }
333 
334 EOLIAN Eina_Bool
_efl_canvas_object_key_focus_get(const Eo * eo_obj,Evas_Object_Protected_Data * obj)335 _efl_canvas_object_key_focus_get(const Eo *eo_obj, Evas_Object_Protected_Data *obj)
336 {
337    return _efl_canvas_object_seat_focus_check(eo_obj, obj, NULL);
338 }
339 
340 EOLIAN Evas_Object *
_evas_canvas_seat_focus_get(const Eo * eo_obj EINA_UNUSED,Evas_Public_Data * e,Efl_Input_Device * seat)341 _evas_canvas_seat_focus_get(const Eo *eo_obj EINA_UNUSED, Evas_Public_Data *e,
342                             Efl_Input_Device *seat)
343 {
344    if (!seat)
345      seat = e->default_seat;
346 
347    return eina_hash_find(e->focused_objects, &seat);
348 }
349 
350 EOLIAN Evas_Object*
_evas_canvas_focus_get(const Eo * eo_obj EINA_UNUSED,Evas_Public_Data * e)351 _evas_canvas_focus_get(const Eo *eo_obj EINA_UNUSED, Evas_Public_Data *e)
352 {
353    return _evas_canvas_seat_focus_get(eo_obj, e, NULL);
354 }
355