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; Eo *eo;
Efl_Input_Device *device; //The seat 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; 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.]] [[Resets the internal data to 0 or default values.]]
} }
dup @pure_virtual { dup @pure_virtual {
[[Creates a copy of this event.]] [[Creates a copy of this event.
return: Efl.Input.Event @owned; [[Event copy]]
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 { @property device @pure_virtual {
[[Input device that originated this event.]] [[Input device that originated this event.]]

View File

@ -39,6 +39,7 @@ _del_hook(Eo *evt)
static void static void
_efl_input_focus_free(Efl_Input_Focus_Data *pd) _efl_input_focus_free(Efl_Input_Focus_Data *pd)
{ {
efl_wref_del_safe(&pd->object_wref);
efl_unref(pd->device); 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_input_focus_object_set(Eo *obj EINA_UNUSED, Efl_Input_Focus_Data *pd,
Efl_Object *object) Efl_Object *object)
{ {
pd->object = object; pd->object_wref = object;
} }
EOLIAN static Efl_Object * EOLIAN static Efl_Object *
_efl_input_focus_object_get(Eo *obj EINA_UNUSED, Efl_Input_Focus_Data *pd) _efl_input_focus_object_get(Eo *obj EINA_UNUSED, Efl_Input_Focus_Data *pd)
{ {
return pd->object; return pd->object_wref;
} }
EOLIAN static void EOLIAN static void
@ -111,18 +112,20 @@ _efl_input_focus_efl_input_event_timestamp_get(Eo *obj EINA_UNUSED,
} }
EOLIAN static Efl_Input_Focus * 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_Data *ev;
Efl_Input_Focus *evt; Efl_Input_Focus *evt;
evt = efl_input_instance_get(MY_CLASS, efl_parent_get(obj), (void **) &ev); evt = efl_add(MY_CLASS, NULL);
if (!evt || !ev) return NULL; ev = efl_data_scope_get(evt, MY_CLASS);
if (!ev) return NULL;
memcpy(ev, pd, sizeof(*ev));
ev->eo = evt; ev->eo = evt;
ev->object = pd->object;
ev->device = efl_ref(pd->device); ev->device = efl_ref(pd->device);
ev->timestamp = pd->timestamp; efl_wref_add(ev->object_wref, &ev->object_wref);
return evt; 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 * 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_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); ev = efl_data_scope_get(evt, MY_CLASS);
if (!ev) return NULL; if (!ev) return NULL;
memcpy(ev, pd, sizeof(*ev));
ev->eo = evt; ev->eo = evt;
ev->timestamp = pd->timestamp; ev->legacy = NULL;
ev->data = pd->data; ev->evas_done = 0;
ev->hold = pd->hold;
ev->device = efl_ref(pd->device); ev->device = efl_ref(pd->device);
return evt; 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 * 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_Data *ev;
Efl_Input_Key *evt; Efl_Input_Key *evt;
evt = efl_input_instance_get(MY_CLASS, efl_parent_get(obj), (void **) &ev); evt = efl_add(MY_CLASS, NULL);
if (!evt || !ev) return NULL; ev = efl_data_scope_get(evt, MY_CLASS);
if (!ev) return NULL;
memcpy(ev, pd, sizeof(*ev)); memcpy(ev, pd, sizeof(*ev));
ev->eo = evt; 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 * 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_Data *ev;
Efl_Input_Pointer *evt; Efl_Input_Focus *evt;
evt = efl_input_instance_get(MY_CLASS, efl_parent_get(obj), (void **) &ev); evt = efl_add(MY_CLASS, NULL);
if (!evt) return NULL; ev = efl_data_scope_get(evt, MY_CLASS);
if (!ev) return NULL;
memcpy(ev, pd, sizeof(*ev)); memcpy(ev, pd, sizeof(*ev));
ev->eo = evt; 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->evas_done = 0;
ev->win_fed = 0; ev->win_fed = 0;
ev->fake = 1; ev->fake = 1;
ev->legacy = NULL;
ev->device = efl_ref(pd->device); ev->device = efl_ref(pd->device);
return evt; return evt;

View File

@ -460,7 +460,7 @@ evas_device_seat_id_get(const Evas_Device *dev)
void void
_evas_device_cleanup(Evas *eo_e) _evas_device_cleanup(Evas *eo_e)
{ {
Eina_List *cpy; Eina_List *cpy, *deleted = NULL;
Evas_Device *dev; Evas_Device *dev;
Evas_Public_Data *e = efl_data_scope_get(eo_e, EVAS_CANVAS_CLASS); 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 /* 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: again:
e->devices_modified = EINA_FALSE; e->devices_modified = EINA_FALSE;
cpy = eina_list_clone(e->devices); cpy = eina_list_clone(e->devices);
EINA_LIST_FREE(cpy, dev) EINA_LIST_FREE(cpy, dev)
{ {
evas_device_del(dev); if (!eina_list_data_find(deleted, dev) && (efl_parent_get(dev) == eo_e))
if (e->devices_modified)
{ {
eina_list_free(cpy); evas_device_del(dev);
goto again; 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. /* Not all devices were deleted. The user probably will unref them later.
Since Evas will be deleted, remove the del callback from them and Since Evas will be deleted, remove the del callback from them and
@ -493,9 +500,7 @@ again:
*/ */
EINA_LIST_FREE(e->devices, dev) EINA_LIST_FREE(e->devices, dev)
{ {
efl_event_callback_call(e->evas, efl_event_callback_call(e->evas, EFL_CANVAS_EVENT_DEVICE_REMOVED, dev);
EFL_CANVAS_EVENT_DEVICE_REMOVED,
dev);
efl_event_callback_del(dev, EFL_EVENT_DEL, _del_cb, e); 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; if (!evt) return;
ev_data->device = efl_ref(seat); 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); ev_data->timestamp = time(NULL);
if (in) if (in)