evas: Fix dangling references with input devices

This solves issues with efl_input_dup() which didn't properly give a
reference to the caller, resulting in dangling eo ids.

Note: This may trigger leaks (instead of invalid refs), but this now
actually reflects the meaning of @owned. This should work with bindings
and C API users should know to call efl_unref().

This patch is the reason for the previous improvements on eo_debug.

@fix
This commit is contained in:
Jean-Philippe Andre 2017-09-28 11:27:56 +09:00
parent 3dc140abfb
commit 96d94e0076
8 changed files with 51 additions and 33 deletions

View File

@ -114,7 +114,7 @@ struct _Efl_Input_Focus_Data
{
Eo *eo;
Efl_Input_Device *device; //The seat
Eo *object; //The focused object - Efl.Canvas.Object or Efl.Canvas.
Eo *object_wref; // wref on the focused object - Efl.Canvas.Object or Efl.Canvas.
double timestamp;
};

View File

@ -31,8 +31,15 @@ mixin Efl.Input.Event (Efl.Interface, Efl.Object)
[[Resets the internal data to 0 or default values.]]
}
dup @pure_virtual {
[[Creates a copy of this event.]]
return: Efl.Input.Event @owned; [[Event copy]]
[[Creates a copy of this event.
The returned event object is similar to the given object in most
ways except that @.fake will be $true.
Note: A reference is given to the caller. In order to avoid leaks
the C API users should call $efl_unref() after use.
]]
return: Efl.Input.Event @owned; [[Event copy, marked as @.fake.]]
}
@property device @pure_virtual {
[[Input device that originated this event.]]

View File

@ -39,6 +39,7 @@ _del_hook(Eo *evt)
static void
_efl_input_focus_free(Efl_Input_Focus_Data *pd)
{
efl_wref_del_safe(&pd->object_wref);
efl_unref(pd->device);
}
@ -71,13 +72,13 @@ EOLIAN static void
_efl_input_focus_object_set(Eo *obj EINA_UNUSED, Efl_Input_Focus_Data *pd,
Efl_Object *object)
{
pd->object = object;
pd->object_wref = object;
}
EOLIAN static Efl_Object *
_efl_input_focus_object_get(Eo *obj EINA_UNUSED, Efl_Input_Focus_Data *pd)
{
return pd->object;
return pd->object_wref;
}
EOLIAN static void
@ -111,18 +112,20 @@ _efl_input_focus_efl_input_event_timestamp_get(Eo *obj EINA_UNUSED,
}
EOLIAN static Efl_Input_Focus *
_efl_input_focus_efl_input_event_dup(Eo *obj, Efl_Input_Focus_Data *pd)
_efl_input_focus_efl_input_event_dup(Eo *obj EINA_UNUSED, Efl_Input_Focus_Data *pd)
{
Efl_Input_Focus_Data *ev;
Efl_Input_Focus *evt;
evt = efl_input_instance_get(MY_CLASS, efl_parent_get(obj), (void **) &ev);
if (!evt || !ev) return NULL;
evt = efl_add(MY_CLASS, NULL);
ev = efl_data_scope_get(evt, MY_CLASS);
if (!ev) return NULL;
memcpy(ev, pd, sizeof(*ev));
ev->eo = evt;
ev->object = pd->object;
ev->device = efl_ref(pd->device);
ev->timestamp = pd->timestamp;
efl_wref_add(ev->object_wref, &ev->object_wref);
return evt;
}

View File

@ -101,17 +101,19 @@ _efl_input_hold_efl_input_event_reset(Eo *obj, Efl_Input_Hold_Data *pd)
}
EOLIAN static Efl_Input_Event *
_efl_input_hold_efl_input_event_dup(Eo *obj, Efl_Input_Hold_Data *pd)
_efl_input_hold_efl_input_event_dup(Eo *obj EINA_UNUSED, Efl_Input_Hold_Data *pd)
{
Efl_Input_Hold_Data *ev;
Efl_Input_Event *evt = efl_add(EFL_INPUT_HOLD_CLASS, efl_parent_get(obj));
Efl_Input_Hold *evt;
evt = efl_add(MY_CLASS, NULL);
ev = efl_data_scope_get(evt, MY_CLASS);
if (!ev) return NULL;
memcpy(ev, pd, sizeof(*ev));
ev->eo = evt;
ev->timestamp = pd->timestamp;
ev->data = pd->data;
ev->hold = pd->hold;
ev->legacy = NULL;
ev->evas_done = 0;
ev->device = efl_ref(pd->device);
return evt;

View File

@ -188,13 +188,14 @@ _efl_input_key_efl_input_event_reset(Eo *obj EINA_UNUSED, Efl_Input_Key_Data *pd
}
EOLIAN static Efl_Input_Event *
_efl_input_key_efl_input_event_dup(Eo *obj, Efl_Input_Key_Data *pd)
_efl_input_key_efl_input_event_dup(Eo *obj EINA_UNUSED, Efl_Input_Key_Data *pd)
{
Efl_Input_Key_Data *ev;
Efl_Input_Key *evt;
evt = efl_input_instance_get(MY_CLASS, efl_parent_get(obj), (void **) &ev);
if (!evt || !ev) return NULL;
evt = efl_add(MY_CLASS, NULL);
ev = efl_data_scope_get(evt, MY_CLASS);
if (!ev) return NULL;
memcpy(ev, pd, sizeof(*ev));
ev->eo = evt;

View File

@ -143,13 +143,14 @@ _efl_input_pointer_efl_input_event_reset(Eo *obj, Efl_Input_Pointer_Data *pd)
}
EOLIAN static Efl_Input_Event *
_efl_input_pointer_efl_input_event_dup(Eo *obj, Efl_Input_Pointer_Data *pd)
_efl_input_pointer_efl_input_event_dup(Eo *obj EINA_UNUSED, Efl_Input_Pointer_Data *pd)
{
Efl_Input_Pointer_Data *ev;
Efl_Input_Pointer *evt;
Efl_Input_Focus *evt;
evt = efl_input_instance_get(MY_CLASS, efl_parent_get(obj), (void **) &ev);
if (!evt) return NULL;
evt = efl_add(MY_CLASS, NULL);
ev = efl_data_scope_get(evt, MY_CLASS);
if (!ev) return NULL;
memcpy(ev, pd, sizeof(*ev));
ev->eo = evt;
@ -157,7 +158,6 @@ _efl_input_pointer_efl_input_event_dup(Eo *obj, Efl_Input_Pointer_Data *pd)
ev->evas_done = 0;
ev->win_fed = 0;
ev->fake = 1;
ev->legacy = NULL;
ev->device = efl_ref(pd->device);
return evt;

View File

@ -460,7 +460,7 @@ evas_device_seat_id_get(const Evas_Device *dev)
void
_evas_device_cleanup(Evas *eo_e)
{
Eina_List *cpy;
Eina_List *cpy, *deleted = NULL;
Evas_Device *dev;
Evas_Public_Data *e = efl_data_scope_get(eo_e, EVAS_CANVAS_CLASS);
@ -473,19 +473,26 @@ _evas_device_cleanup(Evas *eo_e)
}
/* If the device is deleted, _del_cb will remove the device
from the devices list. */
* from the devices list. Ensure we delete them only once, and only if this
* Evas is the owner, otherwise we would kill external references (eg.
* from efl_input_dup()). */
again:
e->devices_modified = EINA_FALSE;
cpy = eina_list_clone(e->devices);
EINA_LIST_FREE(cpy, dev)
{
evas_device_del(dev);
if (e->devices_modified)
if (!eina_list_data_find(deleted, dev) && (efl_parent_get(dev) == eo_e))
{
eina_list_free(cpy);
goto again;
evas_device_del(dev);
deleted = eina_list_append(deleted, dev);
if (e->devices_modified)
{
eina_list_free(cpy);
goto again;
}
}
}
eina_list_free(deleted);
/* Not all devices were deleted. The user probably will unref them later.
Since Evas will be deleted, remove the del callback from them and
@ -493,9 +500,7 @@ again:
*/
EINA_LIST_FREE(e->devices, dev)
{
efl_event_callback_call(e->evas,
EFL_CANVAS_EVENT_DEVICE_REMOVED,
dev);
efl_event_callback_call(e->evas, EFL_CANVAS_EVENT_DEVICE_REMOVED, dev);
efl_event_callback_del(dev, EFL_EVENT_DEL, _del_cb, e);
}
}

View File

@ -80,7 +80,7 @@ _evas_focus_dispatch_event(Evas_Object_Protected_Data *obj, Efl_Input_Device *se
if (!evt) return;
ev_data->device = efl_ref(seat);
ev_data->object = obj->object;
efl_wref_add(obj->object, &ev_data->object_wref);
ev_data->timestamp = time(NULL);
if (in)