diff options
-rw-r--r-- | src/lib/evas/canvas/efl_canvas_object.eo | 53 | ||||
-rw-r--r-- | src/lib/evas/canvas/evas_canvas.eo | 25 | ||||
-rw-r--r-- | src/lib/evas/canvas/evas_events.c | 67 | ||||
-rw-r--r-- | src/lib/evas/canvas/evas_focus.c | 246 | ||||
-rw-r--r-- | src/lib/evas/canvas/evas_main.c | 3 | ||||
-rw-r--r-- | src/lib/evas/canvas/evas_object_main.c | 21 | ||||
-rw-r--r-- | src/lib/evas/include/evas_private.h | 5 |
7 files changed, 366 insertions, 54 deletions
diff --git a/src/lib/evas/canvas/efl_canvas_object.eo b/src/lib/evas/canvas/efl_canvas_object.eo index 84c7f8dd8f..69121114fc 100644 --- a/src/lib/evas/canvas/efl_canvas_object.eo +++ b/src/lib/evas/canvas/efl_canvas_object.eo @@ -209,6 +209,8 @@ abstract Efl.Canvas.Object (Efl.Object, Efl.Gfx, Efl.Gfx.Stack, Efl.Animator, is $true, $obj will be set as the currently focused object and it will receive all keyboard events that are not exclusive key grabs on other objects. + See also @.seat_focus_check, + @.seat_focus_add, @.seat_focus_del. ]] set { legacy: evas_object_focus_set; @@ -220,6 +222,55 @@ abstract Efl.Canvas.Object (Efl.Object, Efl.Gfx, Efl.Gfx.Stack, Efl.Animator, focus: bool; [[$true when set as focused or $false otherwise.]] } } + @property seat_focus { + [[ + Check if this object is focused. + @since 1.19 + ]] + get { + } + values { + focus: bool; [[$true if focused by at least one seat or $false otherwise.]] + } + } + seat_focus_check { + [[ Check if this object is focused by a given seat @since 1.19 ]] + params { + @in seat: Efl.Input.Device; [[The seat to check if the object is focused. Use $null for the default seat.]] + } + return: bool; [[$true if focused or $false otherwise.]] + } + seat_focus_add { + [[ Add a seat to the focus list. + + Evas supports that an Efl.Canvas.Object may be focused by multiple seats + at the same time. This function adds a new seat to the focus list, in other words, + after the seat is added to the list this object will now be also focused by this new seat. + + This function generates an \@ref EFL_CANVAS_OBJECT_EVENT_FOCUS_DEVICE_IN event. + + \@note The old focus APIs ( \@ref evas_object_focus_get, \@ref evas_object_focus_set, + @.key_grab) will still work, however they will only act on the default seat. + + @since 1.19 + ]] + params { + @in seat: Efl.Input.Device; [[The seat that should be added to the focus list. Use $null for the default seat.]] + } + return: bool; [[$true if the focus has been set or $false otherwise.]] + } + seat_focus_del { + [[ Remove a seat from the focus list. + + Removing an seat from the focus list is an unfocus operation, thus it will generate an + \@ref EFL_CANVAS_OBJECT_EVENT_FOCUS_DEVICE_OUT event. + @since 1.19 + ]] + params { + @in seat: Efl.Input.Device; [[The seat that should be removed from the focus list. Use $null for the default seat.]] + } + return: bool; [[$true if the seat was removed from the focus list or $false otherwise.]] + } @property is_frame_object { set { [[@since 1.2]] @@ -568,5 +619,7 @@ abstract Efl.Canvas.Object (Efl.Object, Efl.Gfx, Efl.Gfx.Stack, Efl.Animator, events { focus,in; [[Focus In Event ]] focus,out; [[Focus Out Event ]] + focus,device,in: Efl.Input.Device; [[Focus In event that contains the seat device that this object was focused. @since 1.19]] + focus,device,out: Efl.Input.Device; [[Focus Out event that contains the seat device that this object was unfocused.@since 1.19]] } } diff --git a/src/lib/evas/canvas/evas_canvas.eo b/src/lib/evas/canvas/evas_canvas.eo index 5fcfa63061..6888257a25 100644 --- a/src/lib/evas/canvas/evas_canvas.eo +++ b/src/lib/evas/canvas/evas_canvas.eo @@ -119,9 +119,8 @@ class Evas.Canvas (Efl.Object, Efl.Canvas, Efl.Animator, Efl.Input.Interface) } @property focus { get { - [[Retrieve the object that currently has focus. + [[Retrieve the object focused by the default seat. - Evas can have (at most) one of its objects focused at a time. Focused objects will be the ones having key events delivered to, which the programmer can act upon by means of \@ref evas_object_event_callback_add usage. @@ -136,7 +135,10 @@ class Evas.Canvas (Efl.Object, Efl.Canvas, Efl.Animator, Efl.Input.Interface) See also \@ref evas_object_focus_set, \@ref evas_object_focus_get, \@ref evas_object_key_grab, - \@ref evas_object_key_ungrab. + \@ref evas_object_key_ungrab, @.seat_focus_get, + @.focused_objects.get, @Efl.Canvas.Object.seat_focus_check, + @Efl.Canvas.Object.seat_focus_add, + @Efl.Canvas.Object.seat_focus_del. ]] /* FIXME-doc Example: @@ -154,6 +156,23 @@ class Evas.Canvas (Efl.Object, Efl.Canvas, Efl.Animator, Efl.Input.Interface) or $null if there is not one.]] } } + @property focused_objects { + [[Return an iterator of focused objects. @since 1.19]] + get { + return: free(own(iterator<Eina_Hash_Tuple>), eina_iterator_free); [[An iterator that contains + Eina_Hash_Tuple which the key is an + Efl.Input.Device and the data is an Efl.Canvas.Object or $null on error.]] + } + } + seat_focus_get { + [[Return the focused object by a given seat. @since 1.19]] + params { + @in seat: Efl.Input.Device;[[The seat to fetch the focused + object or $null for the default seat.]] + } + return: Efl.Canvas.Object; [[The object that has the focus or $null if + the seat has no focused object.]] + } @property object_top { get { [[Get the highest (stacked) Evas object on the canvas $e. diff --git a/src/lib/evas/canvas/evas_events.c b/src/lib/evas/canvas/evas_events.c index c3946ca6e7..d199cfc885 100644 --- a/src/lib/evas/canvas/evas_events.c +++ b/src/lib/evas/canvas/evas_events.c @@ -2665,6 +2665,48 @@ evas_event_feed_multi_move(Eo *eo_e, int d, int x, int y, double rad, double rad } static void +_key_event_dispatch(Evas_Public_Data *e, void *event_info, + Efl_Input_Device *device, + const Efl_Event_Description *efl_event_desc, + Evas_Callback_Type evas_event_type, int event_id) +{ + Eo *focused; + + if (!device) + device = e->default_seat; + else + { + const char *name = efl_input_device_name_get(device); + + while ((device = efl_input_device_parent_get(device))) + { + if (efl_input_device_type_get(device) == EFL_INPUT_DEVICE_CLASS_SEAT) + break; + } + if (!device) + { + ERR("Could not find the parent seat from device name '%s'. Using default seat instead", name); + device = e->default_seat; + } + } + + focused = eina_hash_find(e->focused_objects, &device); + + if (!focused) + return; + + Evas_Object_Protected_Data *focused_obj = + efl_data_scope_get(focused, EFL_CANVAS_OBJECT_CLASS); + + if (!e->is_frozen && !evas_event_freezes_through(focused, focused_obj)) + { + evas_object_event_callback_call(focused, focused_obj, + evas_event_type, event_info, + event_id, efl_event_desc); + } +} + +static void _canvas_event_feed_key_down_internal(Evas_Public_Data *e, Efl_Input_Key_Data *ev) { Eina_Bool exclusive = EINA_FALSE; @@ -2738,15 +2780,9 @@ _canvas_event_feed_key_down_internal(Evas_Public_Data *e, Efl_Input_Key_Data *ev } } } - if ((e->focused) && (!exclusive)) - { - Evas_Object_Protected_Data *focused_obj = efl_data_scope_get(e->focused, EFL_CANVAS_OBJECT_CLASS); - if (!e->is_frozen && !evas_event_freezes_through(e->focused, focused_obj)) - { - evas_object_event_callback_call(e->focused, focused_obj, EVAS_CALLBACK_KEY_DOWN, evt, - event_id, EFL_EVENT_KEY_DOWN); - } - } + if (!exclusive) + _key_event_dispatch(e, evt, ev->device, EFL_EVENT_KEY_DOWN, + EVAS_CALLBACK_KEY_DOWN, event_id); _evas_post_event_callback_call(e->evas, e); _evas_unwalk(e); @@ -2828,16 +2864,9 @@ _canvas_event_feed_key_up_internal(Evas_Public_Data *e, Efl_Input_Key_Data *ev) } } } - if ((e->focused) && (!exclusive)) - { - Evas_Object_Protected_Data *focused_obj = efl_data_scope_get(e->focused, EFL_CANVAS_OBJECT_CLASS); - if (!e->is_frozen && !evas_event_freezes_through(e->focused, focused_obj)) - { - evas_object_event_callback_call - (e->focused, focused_obj, EVAS_CALLBACK_KEY_UP, evt, - event_id, EFL_EVENT_KEY_UP); - } - } + if (!exclusive) + _key_event_dispatch(e, evt, ev->device, EFL_EVENT_KEY_UP, + EVAS_CALLBACK_KEY_UP, event_id); _evas_post_event_callback_call(e->evas, e); _evas_unwalk(e); diff --git a/src/lib/evas/canvas/evas_focus.c b/src/lib/evas/canvas/evas_focus.c index 6737589a3a..96cf0ca947 100644 --- a/src/lib/evas/canvas/evas_focus.c +++ b/src/lib/evas/canvas/evas_focus.c @@ -7,51 +7,247 @@ /* public calls */ -EOLIAN void -_efl_canvas_object_key_focus_set(Eo *eo_obj, Evas_Object_Protected_Data *obj, Eina_Bool focus) + +static Eina_Bool +_already_focused(Eina_List *seats, Efl_Input_Device *seat) { + Eina_List *l; + const Efl_Input_Device *s; - int event_id = 0; - MAGIC_CHECK(eo_obj, Evas_Object, MAGIC_OBJ); - return; - MAGIC_CHECK_END(); + EINA_LIST_FOREACH(seats, l, s) + { + if (s == seat) + return EINA_TRUE; + } + + return EINA_FALSE; +} + +static Efl_Input_Device * +_default_seat_get(Eo *evas_obj) +{ + Evas_Public_Data *edata; + Evas *evas = evas_object_evas_get(evas_obj); + + edata = efl_data_scope_get(evas, EVAS_CANVAS_CLASS); + return edata->default_seat; +} + +static void +_evas_focus_set(Eo *evas_obj, Efl_Input_Device *key, Eina_Bool focus) +{ + Evas_Public_Data *edata; + Evas *evas = evas_object_evas_get(evas_obj); + + edata = efl_data_scope_get(evas, EVAS_CANVAS_CLASS); - event_id = _evas_object_event_new(); - if (obj->focused == focus) goto end; - if (_evas_object_intercept_call(eo_obj, EVAS_OBJECT_INTERCEPT_CB_FOCUS_SET, 1, focus)) return; if (focus) + eina_hash_add(edata->focused_objects, &key, evas_obj); + else + eina_hash_del_by_key(edata->focused_objects, &key); +} + +static Eo * +_current_focus_get(Eo *evas_obj, Efl_Input_Device *key) +{ + Evas_Public_Data *edata; + Evas *evas = evas_object_evas_get(evas_obj); + + edata = efl_data_scope_get(evas, EVAS_CANVAS_CLASS); + + return eina_hash_find(edata->focused_objects, &key); +} + +static void +_evas_object_unfocus(Evas_Object_Protected_Data *obj, Efl_Input_Device *seat) +{ + obj->focused_by_seats = eina_list_remove(obj->focused_by_seats, seat); + _evas_focus_set(obj->object, seat, EINA_FALSE); + + //Legacy events... + if (seat == obj->layer->evas->default_seat) { - if (obj->layer->evas->focused) - evas_object_focus_set(obj->layer->evas->focused, 0); - - if (obj->layer->evas->focused) goto end; - obj->focused = 1; - obj->layer->evas->focused = eo_obj; - evas_object_event_callback_call(eo_obj, obj, EVAS_CALLBACK_FOCUS_IN, NULL, event_id, EFL_CANVAS_OBJECT_EVENT_FOCUS_IN); + evas_object_event_callback_call(obj->object, obj, + EVAS_CALLBACK_FOCUS_OUT, + NULL, _evas_object_event_new(), + EFL_CANVAS_OBJECT_EVENT_FOCUS_OUT); evas_event_callback_call(obj->layer->evas->evas, - EVAS_CALLBACK_CANVAS_OBJECT_FOCUS_IN, eo_obj); + EVAS_CALLBACK_CANVAS_OBJECT_FOCUS_OUT, + obj->object); } - else + efl_event_callback_call(obj->object, + EFL_CANVAS_OBJECT_EVENT_FOCUS_DEVICE_OUT, + seat); + _evas_post_event_callback_call(obj->layer->evas->evas, + obj->layer->evas); +} + +void +_evas_focus_device_del_cb(void *data, const Efl_Event *ev) +{ + _evas_object_unfocus(data, ev->object); +} + +EOLIAN Eina_Bool +_efl_canvas_object_seat_focus_del(Eo *eo_obj, + Evas_Object_Protected_Data *obj, + Efl_Input_Device *seat) +{ + Eina_List *l; + Efl_Input_Device *dev, *def; + + MAGIC_CHECK(eo_obj, Evas_Object, MAGIC_OBJ); + return EINA_FALSE; + MAGIC_CHECK_END(); + + def = _default_seat_get(eo_obj); + if (!seat) + seat = def; + + EINA_LIST_FOREACH(obj->focused_by_seats, l, dev) + { + if (dev != seat) + continue; + if (_evas_object_intercept_call(eo_obj, + EVAS_OBJECT_INTERCEPT_CB_FOCUS_SET, + 1, EINA_FALSE)) + { + return EINA_FALSE; + } + + efl_event_callback_del(dev, EFL_EVENT_DEL, + _evas_focus_device_del_cb, obj); + _evas_object_unfocus(obj, dev); + return EINA_TRUE; + } + + return EINA_FALSE; +} + +EOLIAN Eina_Bool +_efl_canvas_object_seat_focus_add(Eo *eo_obj, + Evas_Object_Protected_Data *obj, + Efl_Input_Device *seat) +{ + Eo *current_focus; + Efl_Input_Device *def; + + MAGIC_CHECK(eo_obj, Evas_Object, MAGIC_OBJ); + return EINA_FALSE; + MAGIC_CHECK_END(); + + def = _default_seat_get(eo_obj); + if (!seat) + seat = def; + + EINA_SAFETY_ON_NULL_RETURN_VAL(seat, EINA_FALSE); + if (efl_input_device_type_get(seat) != EFL_INPUT_DEVICE_CLASS_SEAT) + return EINA_FALSE; + + if (_already_focused(obj->focused_by_seats, seat)) + goto end; + + if (_evas_object_intercept_call(eo_obj, EVAS_OBJECT_INTERCEPT_CB_FOCUS_SET, + 1, EINA_TRUE)) { - obj->focused = 0; - obj->layer->evas->focused = NULL; - evas_object_event_callback_call(eo_obj, obj, EVAS_CALLBACK_FOCUS_OUT, NULL, event_id, EFL_CANVAS_OBJECT_EVENT_FOCUS_OUT); + return EINA_FALSE; + } + + current_focus = _current_focus_get(eo_obj, seat); + if (current_focus) + efl_canvas_object_seat_focus_del(current_focus, seat); + + efl_event_callback_add(seat, EFL_EVENT_DEL, _evas_focus_device_del_cb, obj); + + obj->focused_by_seats = eina_list_append(obj->focused_by_seats, seat); + _evas_focus_set(eo_obj, seat, EINA_TRUE); + //Legacy events... + if (seat == def) + { + evas_object_event_callback_call(eo_obj, obj, EVAS_CALLBACK_FOCUS_IN, + NULL, _evas_object_event_new(), + EFL_CANVAS_OBJECT_EVENT_FOCUS_IN); evas_event_callback_call(obj->layer->evas->evas, - EVAS_CALLBACK_CANVAS_OBJECT_FOCUS_OUT, eo_obj); + EVAS_CALLBACK_CANVAS_OBJECT_FOCUS_IN, eo_obj); } + efl_event_callback_call(eo_obj, + EFL_CANVAS_OBJECT_EVENT_FOCUS_DEVICE_IN, seat); end: _evas_post_event_callback_call(obj->layer->evas->evas, obj->layer->evas); + return EINA_TRUE; } EOLIAN Eina_Bool -_efl_canvas_object_key_focus_get(Eo *eo_obj EINA_UNUSED, Evas_Object_Protected_Data *obj) +_efl_canvas_object_seat_focus_check(Eo *eo_obj, + Evas_Object_Protected_Data *obj, + Efl_Input_Device *seat) { - return obj->focused; + Eina_List *l; + Efl_Input_Device *s; + + MAGIC_CHECK(eo_obj, Evas_Object, MAGIC_OBJ); + return EINA_FALSE; + MAGIC_CHECK_END(); + + if (!seat) + seat = _default_seat_get(eo_obj); + + EINA_LIST_FOREACH(obj->focused_by_seats, l, s) + { + if (s == seat) + return EINA_TRUE; + } + return EINA_FALSE; +} + +EOLIAN void +_efl_canvas_object_key_focus_set(Eo *eo_obj, Evas_Object_Protected_Data *obj, Eina_Bool focus) +{ + MAGIC_CHECK(eo_obj, Evas_Object, MAGIC_OBJ); + return; + MAGIC_CHECK_END(); + + if (focus) + _efl_canvas_object_seat_focus_add(eo_obj, obj, NULL); + else + _efl_canvas_object_seat_focus_del(eo_obj, obj, NULL); +} + +EOLIAN Eina_Bool +_efl_canvas_object_seat_focus_get(Eo *eo_obj, Evas_Object_Protected_Data *obj) +{ + MAGIC_CHECK(eo_obj, Evas_Object, MAGIC_OBJ); + return EINA_FALSE; + MAGIC_CHECK_END(); + + return eina_list_count(obj->focused_by_seats) ? EINA_TRUE : EINA_FALSE; +} + +EOLIAN Eina_Bool +_efl_canvas_object_key_focus_get(Eo *eo_obj, Evas_Object_Protected_Data *obj) +{ + return _efl_canvas_object_seat_focus_check(eo_obj, obj, NULL); +} + +EOLIAN Evas_Object * +_evas_canvas_seat_focus_get(Eo *eo_obj EINA_UNUSED, Evas_Public_Data *e, + Efl_Input_Device *seat) +{ + if (!seat) + seat = e->default_seat; + + return eina_hash_find(e->focused_objects, &seat); } EOLIAN Evas_Object* _evas_canvas_focus_get(Eo *eo_obj EINA_UNUSED, Evas_Public_Data *e) { - return e->focused; + return _evas_canvas_seat_focus_get(eo_obj, e, NULL); +} + +EOLIAN Eina_Iterator * +_evas_canvas_focused_objects_get(Eo *eo_obj EINA_UNUSED, Evas_Public_Data *e) +{ + return eina_hash_iterator_tuple_new(e->focused_objects); } diff --git a/src/lib/evas/canvas/evas_main.c b/src/lib/evas/canvas/evas_main.c index 8155bc8e97..822b387d22 100644 --- a/src/lib/evas/canvas/evas_main.c +++ b/src/lib/evas/canvas/evas_main.c @@ -212,6 +212,8 @@ _evas_canvas_efl_object_constructor(Eo *eo_obj, Evas_Public_Data *e) _evas_canvas_event_init(eo_obj, e); + e->focused_objects = eina_hash_pointer_new(NULL); + return eo_obj; } @@ -342,6 +344,7 @@ _evas_canvas_efl_object_destructor(Eo *eo_e, Evas_Public_Data *e) eina_array_flush(&e->image_unref_queue); eina_array_flush(&e->glyph_unref_queue); eina_array_flush(&e->texts_unref_queue); + eina_hash_free(e->focused_objects); EINA_LIST_FREE(e->touch_points, touch_point) free(touch_point); diff --git a/src/lib/evas/canvas/evas_object_main.c b/src/lib/evas/canvas/evas_object_main.c index 76c3c2bf66..c74d01dea3 100644 --- a/src/lib/evas/canvas/evas_object_main.c +++ b/src/lib/evas/canvas/evas_object_main.c @@ -696,14 +696,25 @@ _efl_canvas_object_efl_object_destructor(Eo *eo_obj, Evas_Object_Protected_Data Evas_Object *proxy; Eina_List *l, *l2; Evas_Canvas3D_Texture *texture; + Efl_Input_Device *dev; + Evas_Public_Data *edata; + edata = efl_data_scope_get(evas_object_evas_get(eo_obj), EVAS_CANVAS_CLASS); evas_object_hide(eo_obj); - if (obj->focused) + EINA_LIST_FREE (obj->focused_by_seats, dev) { - obj->focused = EINA_FALSE; - if ((obj->layer) && (obj->layer->evas)) - obj->layer->evas->focused = NULL; - evas_object_event_callback_call(eo_obj, obj, EVAS_CALLBACK_FOCUS_OUT, NULL, _evas_object_event_new(), EFL_CANVAS_OBJECT_EVENT_FOCUS_OUT); + efl_event_callback_del(dev, EFL_EVENT_DEL, + _evas_focus_device_del_cb, obj); + eina_hash_del_by_key(edata->focused_objects, &dev); + //default seat - legacy support. + if (dev == edata->default_seat) + { + evas_object_event_callback_call(eo_obj, obj, EVAS_CALLBACK_FOCUS_OUT, + NULL, _evas_object_event_new(), + EFL_CANVAS_OBJECT_EVENT_FOCUS_OUT); + } + efl_event_callback_call(eo_obj, + EFL_CANVAS_OBJECT_EVENT_FOCUS_DEVICE_OUT, dev); if ((obj->layer) && (obj->layer->evas)) _evas_post_event_callback_call(obj->layer->evas->evas, obj->layer->evas); } diff --git a/src/lib/evas/include/evas_private.h b/src/lib/evas/include/evas_private.h index dcbcbecf4e..bb24435567 100644 --- a/src/lib/evas/include/evas_private.h +++ b/src/lib/evas/include/evas_private.h @@ -889,7 +889,7 @@ struct _Evas_Public_Data int in_smart_calc; int smart_calc_count; - Evas_Object *focused; + Eina_Hash *focused_objects; //Key - seat; value - the focused object void *attach_data; Evas_Modifier modifiers; Evas_Lock locks; @@ -1109,6 +1109,7 @@ struct _Evas_Object_Protected_Data const Evas_Object_Map_Data *map; const Evas_Object_3D_Data *data_3d; const Evas_Object_Mask_Data *mask; + Eina_List *focused_by_seats; // Pointer to the Evas_Object itself Evas_Object *object; @@ -1158,7 +1159,6 @@ struct _Evas_Object_Protected_Data Eina_Bool rect_del : 1; Eina_Bool mouse_in : 1; Eina_Bool pre_render_done : 1; - Eina_Bool focused : 1; Eina_Bool in_layer : 1; Eina_Bool no_propagate : 1; @@ -1715,6 +1715,7 @@ void _canvas_font_cache_flush(Eo *e, void *_pd, va_list *list); void _canvas_font_cache_set(Eo *e, void *_pd, va_list *list); void _canvas_font_cache_get(Eo *e, void *_pd, va_list *list); void _canvas_font_available_list(Eo *e, void *_pd, va_list *list); +void _evas_focus_device_del_cb(void *data, const Efl_Event *ev); void _canvas_key_modifier_get(Eo *e, void *_pd, va_list *list); void _canvas_key_lock_get(Eo *e, void *_pd, va_list *list); |