2013-12-25 06:13:41 -08:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include <config.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <Eina.h>
|
2016-04-20 02:26:35 -07:00
|
|
|
#include <fnmatch.h>
|
2013-12-25 06:13:41 -08:00
|
|
|
|
2018-05-03 16:32:11 -07:00
|
|
|
#include <Eo.h>
|
|
|
|
|
|
|
|
#include "eo_internal.h"
|
|
|
|
|
2013-12-25 06:13:41 -08:00
|
|
|
#include "eo_ptr_indirection.h"
|
|
|
|
#include "eo_private.h"
|
2017-08-25 15:53:15 -07:00
|
|
|
#include "eina_promise_private.h"
|
2013-12-25 06:13:41 -08:00
|
|
|
|
2018-05-18 07:41:45 -07:00
|
|
|
EAPI const Efl_Event_Description _EFL_EVENT_CALLBACK_ADD =
|
|
|
|
EFL_EVENT_DESCRIPTION_HOT("callback,add");
|
|
|
|
|
|
|
|
EAPI const Efl_Event_Description _EFL_EVENT_CALLBACK_DEL =
|
|
|
|
EFL_EVENT_DESCRIPTION_HOT("callback,del");
|
|
|
|
|
2013-12-25 06:13:41 -08:00
|
|
|
static int event_freeze_count = 0;
|
|
|
|
|
2016-12-02 04:26:07 -08:00
|
|
|
typedef struct _Eo_Callback_Description Eo_Callback_Description;
|
|
|
|
typedef struct _Efl_Event_Callback_Frame Efl_Event_Callback_Frame;
|
2013-12-25 06:13:41 -08:00
|
|
|
|
2016-12-02 04:26:07 -08:00
|
|
|
struct _Efl_Event_Callback_Frame
|
|
|
|
{
|
|
|
|
Efl_Event_Callback_Frame *next;
|
|
|
|
unsigned int idx;
|
|
|
|
unsigned int inserted_before;
|
|
|
|
unsigned short generation;
|
|
|
|
};
|
2016-11-30 04:07:51 -08:00
|
|
|
|
2016-04-19 01:21:21 -07:00
|
|
|
typedef struct
|
|
|
|
{
|
2016-05-17 08:00:13 -07:00
|
|
|
const char *name;
|
2016-04-19 01:40:11 -07:00
|
|
|
const char *comment;
|
2016-05-05 08:08:08 -07:00
|
|
|
Eo *composite_parent;
|
2016-04-23 22:38:02 -07:00
|
|
|
Eina_Inlist *generic_data;
|
|
|
|
Eo ***wrefs;
|
2019-07-11 14:53:19 -07:00
|
|
|
Eina_Hash *providers;
|
2019-10-16 16:47:10 -07:00
|
|
|
Eina_Hash *schedulers;
|
2016-08-09 06:10:05 -07:00
|
|
|
} Efl_Object_Extension;
|
2016-04-19 01:21:21 -07:00
|
|
|
|
2019-10-17 12:09:14 -07:00
|
|
|
#define EFL_OBJECT_EVENT_CALLBACK(Event) Eina_Bool event_cb_##Event : 1;
|
|
|
|
|
2018-05-12 22:14:53 -07:00
|
|
|
struct _Efl_Object_Data
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
2016-05-17 02:25:31 -07:00
|
|
|
Eina_Inlist *children;
|
2016-04-19 01:40:11 -07:00
|
|
|
Eo *parent;
|
|
|
|
|
2016-11-17 00:15:46 -08:00
|
|
|
Efl_Object_Extension *ext;
|
2016-04-20 15:50:46 -07:00
|
|
|
|
|
|
|
Eina_Inlist *current;
|
|
|
|
|
2016-12-02 04:26:07 -08:00
|
|
|
Efl_Event_Callback_Frame *event_frame;
|
2016-08-31 17:15:35 -07:00
|
|
|
Eo_Callback_Description **callbacks;
|
2019-10-15 17:04:32 -07:00
|
|
|
#ifdef EFL64
|
|
|
|
uint64_t callbacks_mask;
|
|
|
|
#else
|
|
|
|
uint32_t callbacks_mask;
|
|
|
|
#endif
|
2017-08-25 15:53:15 -07:00
|
|
|
Eina_Inlist *pending_futures;
|
2016-12-02 02:39:57 -08:00
|
|
|
unsigned int callbacks_count;
|
2016-11-30 04:07:51 -08:00
|
|
|
|
2016-04-19 01:40:11 -07:00
|
|
|
unsigned short event_freeze_count;
|
2019-10-17 12:09:14 -07:00
|
|
|
|
|
|
|
EFL_OBJECT_EVENT_CALLBACK(EFL_EVENT_CALLBACK_ADD);
|
|
|
|
EFL_OBJECT_EVENT_CALLBACK(EFL_EVENT_CALLBACK_DEL);
|
|
|
|
EFL_OBJECT_EVENT_CALLBACK(EFL_EVENT_DEL);
|
|
|
|
EFL_OBJECT_EVENT_CALLBACK(EFL_EVENT_NOREF);
|
|
|
|
|
|
|
|
EFL_OBJECT_EVENT_CALLBACK(EFL_EVENT_INVALIDATE);
|
2019-11-13 15:01:00 -08:00
|
|
|
EFL_OBJECT_EVENT_CALLBACK(EFL_EVENT_DESTRUCT); // No proper count: minor optimization triggered at destruction only
|
2016-06-20 02:37:02 -07:00
|
|
|
Eina_Bool callback_stopped : 1;
|
2016-12-01 03:40:36 -08:00
|
|
|
Eina_Bool need_cleaning : 1;
|
2019-10-17 12:09:14 -07:00
|
|
|
|
2017-09-28 00:38:00 -07:00
|
|
|
Eina_Bool allow_parent_unref : 1; // Allows unref to zero even with a parent
|
2018-05-12 22:14:53 -07:00
|
|
|
};
|
2013-12-25 06:13:41 -08:00
|
|
|
|
2016-12-02 04:26:07 -08:00
|
|
|
typedef enum
|
|
|
|
{
|
|
|
|
DATA_PTR,
|
|
|
|
DATA_OBJ,
|
|
|
|
DATA_OBJ_WEAK,
|
|
|
|
DATA_VAL
|
2016-04-29 05:43:36 -07:00
|
|
|
} Eo_Generic_Data_Node_Type;
|
|
|
|
|
2013-12-25 06:13:41 -08:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
EINA_INLIST;
|
2016-07-07 02:41:23 -07:00
|
|
|
const Eo *obj;
|
2016-04-19 01:40:11 -07:00
|
|
|
Eina_Stringshare *key;
|
2016-04-29 05:08:07 -07:00
|
|
|
union {
|
2016-07-07 02:41:23 -07:00
|
|
|
Eina_Value *val;
|
|
|
|
Eo *obj;
|
|
|
|
void *ptr;
|
2016-04-29 05:08:07 -07:00
|
|
|
} d;
|
2016-04-29 05:43:36 -07:00
|
|
|
Eo_Generic_Data_Node_Type d_type;
|
2013-12-25 06:13:41 -08:00
|
|
|
} Eo_Generic_Data_Node;
|
|
|
|
|
2017-08-25 15:53:15 -07:00
|
|
|
typedef struct _Efl_Future_Pending
|
|
|
|
{
|
|
|
|
EINA_INLIST;
|
2018-04-18 11:17:03 -07:00
|
|
|
const Eo *o;
|
2017-08-25 15:53:15 -07:00
|
|
|
Eina_Future *future;
|
|
|
|
Efl_Future_Cb_Desc desc;
|
|
|
|
} Efl_Future_Pending;
|
|
|
|
|
|
|
|
|
2016-04-20 15:50:46 -07:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
EINA_INLIST;
|
2016-08-09 06:10:05 -07:00
|
|
|
const Efl_Event_Description *desc;
|
2016-08-31 17:15:35 -07:00
|
|
|
unsigned int current;
|
2016-04-20 15:50:46 -07:00
|
|
|
} Eo_Current_Callback_Description;
|
2016-04-19 01:21:21 -07:00
|
|
|
|
2016-12-02 04:26:07 -08:00
|
|
|
#define EVENT_STACK_PUSH(pd, fr) do { \
|
|
|
|
(fr)->next = (pd)->event_frame; \
|
|
|
|
(pd)->event_frame = (fr); \
|
|
|
|
} while (0)
|
|
|
|
#define EVENT_STACK_POP(pd) do { \
|
|
|
|
if ((pd)->event_frame) (pd)->event_frame = (pd)->event_frame->next; \
|
|
|
|
} while (0)
|
2016-11-30 04:07:51 -08:00
|
|
|
|
2016-11-23 18:49:43 -08:00
|
|
|
static int _eo_nostep_alloc = -1;
|
|
|
|
|
2018-04-02 17:18:46 -07:00
|
|
|
static void
|
|
|
|
_efl_pending_futures_clear(Efl_Object_Data *pd)
|
|
|
|
{
|
|
|
|
while (pd->pending_futures)
|
|
|
|
{
|
|
|
|
Efl_Future_Pending *pending = EINA_INLIST_CONTAINER_GET(pd->pending_futures, Efl_Future_Pending);
|
|
|
|
Eina_Future *future = *pending->desc.storage;
|
|
|
|
assert(future);
|
|
|
|
eina_future_cancel(future);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-11 14:53:19 -07:00
|
|
|
static inline void
|
|
|
|
_efl_object_extension_free(Efl_Object_Extension *ext)
|
|
|
|
{
|
|
|
|
eina_freeq_ptr_main_add(ext, free, sizeof(*ext));
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline Efl_Object_Extension *
|
|
|
|
_efl_object_extension_need(Efl_Object_Data *pd)
|
|
|
|
{
|
|
|
|
if (!pd->ext) pd->ext = calloc(1, sizeof(Efl_Object_Extension));
|
|
|
|
return pd->ext;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
_efl_object_extension_noneed(Efl_Object_Data *pd)
|
|
|
|
{
|
|
|
|
Efl_Object_Extension *ext = pd->ext;
|
|
|
|
if ((!ext) ||
|
|
|
|
(ext->name) ||
|
|
|
|
(ext->comment) ||
|
|
|
|
(ext->generic_data) ||
|
|
|
|
(ext->wrefs) ||
|
|
|
|
(ext->composite_parent) ||
|
2019-10-16 16:47:10 -07:00
|
|
|
(ext->providers) ||
|
|
|
|
(ext->schedulers)) return;
|
2019-07-11 14:53:19 -07:00
|
|
|
_efl_object_extension_free(pd->ext);
|
|
|
|
pd->ext = NULL;
|
|
|
|
}
|
|
|
|
|
2018-04-02 17:18:46 -07:00
|
|
|
static void
|
2018-04-04 15:37:11 -07:00
|
|
|
_efl_object_invalidate(Eo *obj_id, Efl_Object_Data *pd)
|
2018-04-02 17:18:46 -07:00
|
|
|
{
|
|
|
|
_efl_pending_futures_clear(pd);
|
2018-04-24 11:37:48 -07:00
|
|
|
|
2019-07-11 14:53:19 -07:00
|
|
|
if (pd->ext && pd->ext->providers)
|
|
|
|
{
|
|
|
|
eina_hash_free(pd->ext->providers);
|
|
|
|
pd->ext->providers = NULL;
|
|
|
|
_efl_object_extension_noneed(pd);
|
|
|
|
}
|
2019-10-16 16:47:10 -07:00
|
|
|
if (pd->ext && pd->ext->schedulers)
|
|
|
|
{
|
|
|
|
eina_hash_free(pd->ext->schedulers);
|
|
|
|
pd->ext->schedulers = NULL;
|
|
|
|
_efl_object_extension_noneed(pd);
|
|
|
|
}
|
2019-07-11 14:53:19 -07:00
|
|
|
|
2018-09-21 00:54:51 -07:00
|
|
|
EO_OBJ_POINTER_RETURN(obj_id, obj);
|
2018-04-04 15:37:11 -07:00
|
|
|
|
2018-05-01 16:24:19 -07:00
|
|
|
// Finally invalidate itself if it wasn't done already
|
|
|
|
// I am not sure this is a good idea, but it force the
|
|
|
|
// behavior of calling directly efl_invalidate to be the
|
|
|
|
// same as efl_parent_set(NULL).
|
|
|
|
if (!obj->is_invalidating)
|
|
|
|
efl_parent_set(obj_id, NULL);
|
2018-04-04 15:37:11 -07:00
|
|
|
|
|
|
|
EO_OBJ_DONE(obj_id);
|
2018-04-02 17:18:46 -07:00
|
|
|
}
|
|
|
|
|
2018-05-09 20:07:01 -07:00
|
|
|
// Generate the invalidate event in all case and make sure it happens
|
|
|
|
// before any user code can change the children invalidate state. This
|
|
|
|
// make sure that the entire tree of object is valid at the time of
|
|
|
|
// the invalidate event.
|
|
|
|
void
|
|
|
|
_efl_invalidate(_Eo_Object *obj)
|
|
|
|
{
|
|
|
|
Eina_Array stash = { 0 };
|
|
|
|
Efl_Object_Data *pd;
|
|
|
|
_Eo_Object *child;
|
|
|
|
Eo *id;
|
|
|
|
|
|
|
|
if (obj->is_invalidating) return ;
|
|
|
|
obj->is_invalidating = EINA_TRUE;
|
|
|
|
if (obj->invalidate) return;
|
|
|
|
|
|
|
|
id = _eo_obj_id_get(obj);
|
|
|
|
|
|
|
|
efl_event_callback_call(id, EFL_EVENT_INVALIDATE, NULL);
|
|
|
|
|
|
|
|
pd = efl_data_scope_get(id, EFL_OBJECT_CLASS);
|
|
|
|
|
|
|
|
efl_invalidate(id);
|
|
|
|
|
|
|
|
eina_array_step_set(&stash, sizeof (stash), 4);
|
|
|
|
|
|
|
|
// Invalidate all children too
|
|
|
|
EINA_INLIST_FOREACH(pd->children, child)
|
|
|
|
eina_array_push(&stash, _efl_ref(child));
|
|
|
|
|
|
|
|
while ((child = eina_array_pop(&stash)))
|
|
|
|
{
|
|
|
|
Eo *child_id = _eo_obj_id_get(child);
|
|
|
|
|
|
|
|
efl_parent_set(child_id, NULL);
|
|
|
|
_efl_unref(child);
|
|
|
|
}
|
|
|
|
|
|
|
|
eina_array_flush(&stash);
|
2018-05-12 22:14:53 -07:00
|
|
|
|
|
|
|
obj->invalidate = EINA_TRUE;
|
2018-05-09 20:07:01 -07:00
|
|
|
}
|
|
|
|
|
2016-08-30 05:34:10 -07:00
|
|
|
static void _key_generic_cb_del(void *data, const Efl_Event *event);
|
2016-04-23 22:38:02 -07:00
|
|
|
|
2013-12-25 06:13:41 -08:00
|
|
|
static void
|
|
|
|
_eo_generic_data_node_free(Eo_Generic_Data_Node *node)
|
|
|
|
{
|
2016-04-29 05:20:21 -07:00
|
|
|
switch (node->d_type)
|
|
|
|
{
|
2016-07-07 02:41:23 -07:00
|
|
|
case DATA_PTR:
|
|
|
|
break;
|
2016-04-29 05:20:21 -07:00
|
|
|
case DATA_OBJ:
|
2018-01-09 22:23:29 -08:00
|
|
|
// FIXME: should this use "destruct" event instead?
|
2016-08-09 06:10:05 -07:00
|
|
|
efl_event_callback_del(node->d.obj, EFL_EVENT_DEL, _key_generic_cb_del, node);
|
2016-08-15 06:44:41 -07:00
|
|
|
efl_unref(node->d.obj);
|
2016-07-07 02:41:23 -07:00
|
|
|
break;
|
|
|
|
case DATA_OBJ_WEAK:
|
2018-01-09 22:23:29 -08:00
|
|
|
// FIXME: should this use "destruct" event instead?
|
2016-08-09 06:10:05 -07:00
|
|
|
efl_event_callback_del(node->d.obj, EFL_EVENT_DEL, _key_generic_cb_del, node);
|
2016-07-07 02:41:23 -07:00
|
|
|
break;
|
2016-04-29 05:20:21 -07:00
|
|
|
case DATA_VAL:
|
2016-07-07 02:41:23 -07:00
|
|
|
eina_value_free(node->d.val);
|
|
|
|
break;
|
2016-04-29 05:20:21 -07:00
|
|
|
}
|
2013-12-25 06:13:41 -08:00
|
|
|
eina_stringshare_del(node->key);
|
2016-11-04 03:13:53 -07:00
|
|
|
eina_freeq_ptr_main_add(node, free, sizeof(*node));
|
2013-12-25 06:13:41 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2016-08-09 06:10:05 -07:00
|
|
|
_eo_generic_data_del_all(Eo *obj EINA_UNUSED, Efl_Object_Data *pd)
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
2016-04-12 09:04:11 -07:00
|
|
|
Eo_Generic_Data_Node *node;
|
2016-08-09 06:10:05 -07:00
|
|
|
Efl_Object_Extension *ext = pd->ext;
|
2013-12-25 06:13:41 -08:00
|
|
|
|
2016-04-23 22:38:02 -07:00
|
|
|
if (!ext) return;
|
2016-04-29 05:20:21 -07:00
|
|
|
|
2016-04-23 22:38:02 -07:00
|
|
|
while (ext->generic_data)
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
2016-04-23 22:38:02 -07:00
|
|
|
node = (Eo_Generic_Data_Node *)ext->generic_data;
|
|
|
|
ext->generic_data = eina_inlist_remove(ext->generic_data,
|
2016-04-29 05:20:21 -07:00
|
|
|
EINA_INLIST_GET(node));
|
|
|
|
|
2013-12-25 06:13:41 -08:00
|
|
|
_eo_generic_data_node_free(node);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-17 09:02:37 -07:00
|
|
|
static void
|
2016-08-09 06:10:05 -07:00
|
|
|
_eo_key_generic_direct_del(Efl_Object_Data *pd, Eo_Generic_Data_Node *node, Eina_Bool call_free)
|
2016-07-07 02:41:23 -07:00
|
|
|
{
|
2016-08-09 06:10:05 -07:00
|
|
|
Efl_Object_Extension *ext = pd->ext;
|
2016-07-07 02:41:23 -07:00
|
|
|
|
|
|
|
ext->generic_data = eina_inlist_remove
|
|
|
|
(ext->generic_data, EINA_INLIST_GET(node));
|
|
|
|
if (call_free) _eo_generic_data_node_free(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2016-08-09 06:10:05 -07:00
|
|
|
_eo_key_generic_del(const Eo *obj EINA_UNUSED, Efl_Object_Data *pd, const char *key, Eina_Bool call_free)
|
2016-04-12 09:04:11 -07:00
|
|
|
{
|
|
|
|
Eo_Generic_Data_Node *node;
|
2016-08-09 06:10:05 -07:00
|
|
|
Efl_Object_Extension *ext = pd->ext;
|
2016-04-12 09:04:11 -07:00
|
|
|
|
2016-04-23 22:38:02 -07:00
|
|
|
EINA_INLIST_FOREACH(ext->generic_data, node)
|
2016-04-12 09:04:11 -07:00
|
|
|
{
|
|
|
|
if (!strcmp(node->key, key))
|
|
|
|
{
|
2016-04-23 22:38:02 -07:00
|
|
|
ext->generic_data = eina_inlist_remove
|
|
|
|
(ext->generic_data, EINA_INLIST_GET(node));
|
2016-07-07 02:41:23 -07:00
|
|
|
if (call_free) _eo_generic_data_node_free(node);
|
2016-04-12 09:04:11 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-29 05:43:36 -07:00
|
|
|
/* Return TRUE if the object was newly added. */
|
2016-07-07 02:41:23 -07:00
|
|
|
static Eo_Generic_Data_Node *
|
2016-08-09 06:10:05 -07:00
|
|
|
_key_generic_set(const Eo *obj, Efl_Object_Data *pd, const char *key, const void *data, Eo_Generic_Data_Node_Type d_type, Eina_Bool call_free)
|
2016-04-12 09:04:11 -07:00
|
|
|
{
|
|
|
|
Eo_Generic_Data_Node *node;
|
2016-08-09 06:10:05 -07:00
|
|
|
Efl_Object_Extension *ext = pd->ext;
|
2013-12-25 06:13:41 -08:00
|
|
|
|
2016-07-07 02:41:23 -07:00
|
|
|
if (!key) return NULL;
|
2016-04-23 22:38:02 -07:00
|
|
|
if (ext)
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
2016-05-17 09:02:37 -07:00
|
|
|
if (!data)
|
|
|
|
{
|
2016-07-07 02:41:23 -07:00
|
|
|
_eo_key_generic_del(obj, pd, key, call_free);
|
|
|
|
return NULL;
|
2016-05-17 09:02:37 -07:00
|
|
|
}
|
2016-04-23 22:38:02 -07:00
|
|
|
EINA_INLIST_FOREACH(ext->generic_data, node)
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
2016-04-23 22:38:02 -07:00
|
|
|
if (!strcmp(node->key, key))
|
2016-04-12 09:04:11 -07:00
|
|
|
{
|
2016-04-29 05:43:36 -07:00
|
|
|
if ((node->d_type == d_type) && (node->d.ptr == data))
|
2016-07-07 20:26:07 -07:00
|
|
|
return NULL;
|
2016-04-23 22:38:02 -07:00
|
|
|
ext->generic_data = eina_inlist_remove
|
|
|
|
(ext->generic_data, EINA_INLIST_GET(node));
|
|
|
|
_eo_generic_data_node_free(node);
|
|
|
|
break;
|
2016-04-12 09:04:11 -07:00
|
|
|
}
|
2013-12-25 06:13:41 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-13 17:07:47 -07:00
|
|
|
ext = _efl_object_extension_need(pd);
|
2016-04-23 22:38:02 -07:00
|
|
|
if (ext)
|
|
|
|
{
|
|
|
|
node = calloc(1, sizeof(Eo_Generic_Data_Node));
|
2016-07-07 20:26:07 -07:00
|
|
|
if (!node) return NULL;
|
2016-07-07 02:41:23 -07:00
|
|
|
node->obj = obj;
|
2016-04-23 22:38:02 -07:00
|
|
|
node->key = eina_stringshare_add(key);
|
2016-04-29 05:43:36 -07:00
|
|
|
node->d.ptr = (void *) data;
|
|
|
|
node->d_type = d_type;
|
2016-04-23 22:38:02 -07:00
|
|
|
ext->generic_data = eina_inlist_prepend
|
|
|
|
(ext->generic_data, EINA_INLIST_GET(node));
|
2016-07-07 02:41:23 -07:00
|
|
|
return node;
|
2016-04-23 22:38:02 -07:00
|
|
|
}
|
2016-04-29 05:43:36 -07:00
|
|
|
|
2016-07-07 02:41:23 -07:00
|
|
|
return NULL;
|
2016-04-12 09:04:11 -07:00
|
|
|
}
|
|
|
|
|
2016-04-29 05:43:36 -07:00
|
|
|
static void *
|
2016-08-09 06:10:05 -07:00
|
|
|
_key_generic_get(const Eo *obj, Efl_Object_Data *pd, const char *key, Eo_Generic_Data_Node_Type d_type)
|
2016-04-12 09:04:11 -07:00
|
|
|
{
|
|
|
|
Eo_Generic_Data_Node *node;
|
2016-08-09 06:10:05 -07:00
|
|
|
Efl_Object_Extension *ext = pd->ext;
|
2016-04-12 09:04:11 -07:00
|
|
|
|
|
|
|
if (!key) return NULL;
|
2016-04-23 22:38:02 -07:00
|
|
|
if (!ext) return NULL;
|
|
|
|
EINA_INLIST_FOREACH(ext->generic_data, node)
|
2016-04-12 09:04:11 -07:00
|
|
|
{
|
2016-11-27 16:08:58 -08:00
|
|
|
if (node->key && !strcmp(node->key, key))
|
2016-04-12 09:04:11 -07:00
|
|
|
{
|
2016-04-29 05:43:36 -07:00
|
|
|
if (node->d_type == d_type)
|
2016-04-12 09:04:11 -07:00
|
|
|
{
|
2016-04-23 22:38:02 -07:00
|
|
|
ext->generic_data = eina_inlist_promote
|
|
|
|
(ext->generic_data, EINA_INLIST_GET(node));
|
2016-04-29 05:43:36 -07:00
|
|
|
return node->d.ptr;
|
2016-04-12 09:04:11 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-04-29 05:43:36 -07:00
|
|
|
ERR("Object %p key '%s' asked for %d but is %d'",
|
|
|
|
obj, key, d_type, node->d_type);
|
2016-04-12 09:04:11 -07:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-12-25 06:13:41 -08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-07-07 02:41:23 -07:00
|
|
|
static void
|
2016-08-30 05:34:10 -07:00
|
|
|
_key_generic_cb_del(void *data, const Efl_Event *event EINA_UNUSED)
|
2016-07-07 02:41:23 -07:00
|
|
|
{
|
|
|
|
Eo_Generic_Data_Node *node = data;
|
2016-08-15 06:44:41 -07:00
|
|
|
Efl_Object_Data *pd = efl_data_scope_get(node->obj, EFL_OBJECT_CLASS);
|
2016-07-07 02:41:23 -07:00
|
|
|
_eo_key_generic_direct_del(pd, node, EINA_FALSE);
|
|
|
|
}
|
|
|
|
|
2016-04-19 02:25:15 -07:00
|
|
|
EOLIAN static void
|
2016-08-09 06:10:05 -07:00
|
|
|
_efl_object_key_data_set(Eo *obj, Efl_Object_Data *pd, const char *key, const void *data)
|
2016-04-19 02:25:15 -07:00
|
|
|
{
|
2016-07-07 02:41:23 -07:00
|
|
|
_key_generic_set(obj, pd, key, data, DATA_PTR, EINA_TRUE);
|
2016-04-29 05:43:36 -07:00
|
|
|
}
|
2016-04-19 02:25:15 -07:00
|
|
|
|
2017-04-26 07:18:49 -07:00
|
|
|
EOAPI EFL_VOID_FUNC_BODYV(efl_key_data_set, EFL_FUNC_CALL(key, data),
|
|
|
|
const char *key, const void *data);
|
|
|
|
|
2016-04-29 05:43:36 -07:00
|
|
|
EOLIAN static void *
|
2016-08-09 06:10:05 -07:00
|
|
|
_efl_object_key_data_get(Eo *obj, Efl_Object_Data *pd, const char *key)
|
2016-04-29 05:43:36 -07:00
|
|
|
{
|
|
|
|
return _key_generic_get(obj, pd, key, DATA_PTR);
|
|
|
|
}
|
2016-04-19 02:25:15 -07:00
|
|
|
|
2017-04-26 07:18:49 -07:00
|
|
|
EOAPI EFL_FUNC_BODYV_CONST(efl_key_data_get, void *, NULL, EFL_FUNC_CALL(key),
|
|
|
|
const char *key);
|
|
|
|
|
2016-04-29 05:43:36 -07:00
|
|
|
EOLIAN static void
|
2016-08-09 06:10:05 -07:00
|
|
|
_efl_object_key_ref_set(Eo *obj EINA_UNUSED, Efl_Object_Data *pd, const char *key, const Eo *objdata)
|
2016-04-29 05:43:36 -07:00
|
|
|
{
|
2016-07-07 02:41:23 -07:00
|
|
|
Eo_Generic_Data_Node *node;
|
|
|
|
|
2016-09-07 01:53:33 -07:00
|
|
|
if (!_eo_id_domain_compatible(obj, objdata)) return;
|
2016-07-07 02:41:23 -07:00
|
|
|
node = _key_generic_set(obj, pd, key, objdata, DATA_OBJ, EINA_TRUE);
|
|
|
|
if (node)
|
|
|
|
{
|
2016-08-15 06:44:41 -07:00
|
|
|
efl_ref(objdata);
|
2016-08-09 06:10:05 -07:00
|
|
|
efl_event_callback_add((Eo *)objdata, EFL_EVENT_DEL, _key_generic_cb_del, node);
|
2016-07-07 02:41:23 -07:00
|
|
|
}
|
2016-04-29 05:43:36 -07:00
|
|
|
}
|
|
|
|
|
2017-04-26 07:18:49 -07:00
|
|
|
EOAPI EFL_VOID_FUNC_BODYV(efl_key_ref_set, EFL_FUNC_CALL(key, objdata),
|
|
|
|
const char *key, const Efl_Object *objdata);
|
|
|
|
|
2016-04-29 05:43:36 -07:00
|
|
|
EOLIAN static Eo *
|
2016-08-09 06:10:05 -07:00
|
|
|
_efl_object_key_ref_get(Eo *obj, Efl_Object_Data *pd, const char *key)
|
2016-04-29 05:43:36 -07:00
|
|
|
{
|
|
|
|
return _key_generic_get(obj, pd, key, DATA_OBJ);
|
|
|
|
}
|
|
|
|
|
2017-04-26 07:18:49 -07:00
|
|
|
EOAPI EFL_FUNC_BODYV_CONST(efl_key_ref_get, Efl_Object *, NULL,
|
|
|
|
EFL_FUNC_CALL(key), const char *key);
|
|
|
|
|
2016-07-07 02:41:23 -07:00
|
|
|
EOLIAN static void
|
2016-08-09 06:10:05 -07:00
|
|
|
_efl_object_key_wref_set(Eo *obj, Efl_Object_Data *pd, const char * key, const Efl_Object *objdata)
|
2016-07-07 02:41:23 -07:00
|
|
|
{
|
|
|
|
Eo_Generic_Data_Node *node;
|
|
|
|
|
2016-09-07 01:53:33 -07:00
|
|
|
if (!_eo_id_domain_compatible(obj, objdata)) return;
|
2016-07-07 02:41:23 -07:00
|
|
|
node = _key_generic_set(obj, pd, key, objdata, DATA_OBJ_WEAK, EINA_TRUE);
|
|
|
|
if (node)
|
|
|
|
{
|
2016-08-09 06:10:05 -07:00
|
|
|
efl_event_callback_add((Eo *)objdata, EFL_EVENT_DEL, _key_generic_cb_del, node);
|
2016-07-07 02:41:23 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-26 07:18:49 -07:00
|
|
|
EOAPI EFL_VOID_FUNC_BODYV(efl_key_wref_set, EFL_FUNC_CALL(key, objdata),
|
|
|
|
const char *key, const Efl_Object *objdata);
|
|
|
|
|
2016-07-07 02:41:23 -07:00
|
|
|
EOLIAN static Eo *
|
2016-08-09 06:10:05 -07:00
|
|
|
_efl_object_key_wref_get(Eo *obj, Efl_Object_Data *pd, const char * key)
|
2016-07-07 02:41:23 -07:00
|
|
|
{
|
|
|
|
return _key_generic_get(obj, pd, key, DATA_OBJ_WEAK);
|
|
|
|
}
|
|
|
|
|
2017-04-26 07:18:49 -07:00
|
|
|
EOAPI EFL_FUNC_BODYV_CONST(efl_key_wref_get, Efl_Object *, NULL,
|
|
|
|
EFL_FUNC_CALL(key), const char *key);
|
|
|
|
|
2016-04-29 05:43:36 -07:00
|
|
|
EOLIAN static void
|
2016-08-09 06:10:05 -07:00
|
|
|
_efl_object_key_value_set(Eo *obj EINA_UNUSED, Efl_Object_Data *pd, const char *key, Eina_Value *value)
|
2016-04-29 05:43:36 -07:00
|
|
|
{
|
2016-07-07 02:41:23 -07:00
|
|
|
_key_generic_set(obj, pd, key, value, DATA_VAL, EINA_TRUE);
|
2016-04-19 02:25:15 -07:00
|
|
|
}
|
|
|
|
|
2017-04-26 07:18:49 -07:00
|
|
|
EOAPI EFL_VOID_FUNC_BODYV(efl_key_value_set, EFL_FUNC_CALL(key, value),
|
|
|
|
const char *key, Eina_Value *value);
|
|
|
|
|
2016-04-19 02:25:15 -07:00
|
|
|
EOLIAN static Eina_Value *
|
2016-08-09 06:10:05 -07:00
|
|
|
_efl_object_key_value_get(Eo *obj, Efl_Object_Data *pd, const char *key)
|
2016-04-19 02:25:15 -07:00
|
|
|
{
|
2016-04-29 05:43:36 -07:00
|
|
|
return _key_generic_get(obj, pd, key, DATA_VAL);
|
2016-04-19 02:25:15 -07:00
|
|
|
}
|
|
|
|
|
2017-04-26 07:18:49 -07:00
|
|
|
EOAPI EFL_FUNC_BODYV_CONST(efl_key_value_get, Eina_Value *, NULL,
|
|
|
|
EFL_FUNC_CALL(key), const char *key);
|
|
|
|
|
2016-04-19 00:34:53 -07:00
|
|
|
EOLIAN static void
|
2016-08-09 06:10:05 -07:00
|
|
|
_efl_object_name_set(Eo *obj EINA_UNUSED, Efl_Object_Data *pd, const char *name)
|
2016-04-19 00:34:53 -07:00
|
|
|
{
|
2016-05-17 08:00:13 -07:00
|
|
|
if ((name) && (!name[0])) name = NULL;
|
|
|
|
if (name)
|
2016-04-19 01:21:21 -07:00
|
|
|
{
|
2016-08-09 06:10:05 -07:00
|
|
|
_efl_object_extension_need(pd);
|
2016-05-17 08:00:13 -07:00
|
|
|
if (pd->ext) eina_stringshare_replace(&(pd->ext->name), name);
|
2016-04-19 01:21:21 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-04-23 22:38:02 -07:00
|
|
|
if (!pd->ext) return;
|
2016-05-17 08:00:13 -07:00
|
|
|
if (pd->ext->name)
|
2016-04-19 01:21:21 -07:00
|
|
|
{
|
2016-05-17 08:00:13 -07:00
|
|
|
eina_stringshare_replace(&(pd->ext->name), name);
|
2016-08-09 06:10:05 -07:00
|
|
|
_efl_object_extension_noneed(pd);
|
2016-04-19 01:21:21 -07:00
|
|
|
}
|
|
|
|
}
|
2016-04-19 00:34:53 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
EOLIAN static const char *
|
2018-04-17 11:09:44 -07:00
|
|
|
_efl_object_name_get(const Eo *obj EINA_UNUSED, Efl_Object_Data *pd)
|
2016-04-19 00:34:53 -07:00
|
|
|
{
|
2016-04-23 22:38:02 -07:00
|
|
|
if (!pd->ext) return NULL;
|
2016-05-17 08:00:13 -07:00
|
|
|
return pd->ext->name;
|
2016-04-19 01:21:21 -07:00
|
|
|
}
|
|
|
|
|
2016-04-20 02:26:35 -07:00
|
|
|
static inline Eina_Bool
|
2016-05-17 08:00:13 -07:00
|
|
|
_name_match(const char *match, Eina_Bool is_glob, const char *str)
|
2016-04-20 02:26:35 -07:00
|
|
|
{
|
|
|
|
if (str)
|
|
|
|
{
|
|
|
|
if (is_glob)
|
|
|
|
{
|
|
|
|
// if match string is empty - then it matches - same as "*"
|
|
|
|
if (!match[0]) return EINA_TRUE;
|
|
|
|
// if match string is "*" special case it and match
|
|
|
|
if ((match[0] == '*') && (match[1] == 0)) return EINA_TRUE;
|
|
|
|
// actual compare
|
|
|
|
if (!fnmatch(match, str, 0)) return EINA_TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// if match string is empty - then it matches - same as "*"
|
|
|
|
if (!match[0]) return EINA_TRUE;
|
|
|
|
// if pointers are the same they must be the same
|
|
|
|
if (match == str) return EINA_TRUE;
|
|
|
|
// actual compare
|
|
|
|
if (!strcmp(match, str)) return EINA_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline Eina_Bool
|
|
|
|
_matchall(const char *match)
|
|
|
|
{
|
|
|
|
if ((match[0] == 0) || ((match[0] == '*') && (match[1] == 0)))
|
|
|
|
return EINA_TRUE;
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Eina_Bool
|
|
|
|
_hasglob(const char *match)
|
|
|
|
{
|
|
|
|
if (strpbrk(match, "*?[")) return EINA_TRUE;
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Eina_Bool
|
|
|
|
_ismultiglob(const char *match)
|
|
|
|
{
|
|
|
|
if ((match[0] == '*') && (match[1] == '*') && (match[2] == 0))
|
|
|
|
return EINA_TRUE;
|
|
|
|
if ((match[0] == '*') && (match[1] == '*') && (match[2] == '/'))
|
|
|
|
return EINA_TRUE;
|
|
|
|
if ((match[0] == '/') && (match[1] == '*') && (match[2] == '*') && (match[3] == 0))
|
|
|
|
return EINA_TRUE;
|
|
|
|
if ((match[0] == '/') && (match[1] == '*') && (match[2] == '*') && (match[3] == '/'))
|
|
|
|
return EINA_TRUE;
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
2016-08-09 06:10:05 -07:00
|
|
|
EOLIAN static Efl_Object *
|
2017-08-23 04:33:54 -07:00
|
|
|
_efl_object_name_find(const Eo *obj EINA_UNUSED, Efl_Object_Data *pd, const char *search)
|
2016-04-20 02:26:35 -07:00
|
|
|
{
|
|
|
|
Eo *child;
|
2016-05-17 02:25:31 -07:00
|
|
|
_Eo_Object *child_eo;
|
2016-05-17 08:00:13 -07:00
|
|
|
const char *name, *p, *klass_name;
|
2016-04-20 02:26:35 -07:00
|
|
|
|
|
|
|
// notes:
|
|
|
|
// if search contains NO "/" char, then its just a name search.
|
|
|
|
// if there is one or more "/" chars, then these are explicitly object
|
|
|
|
// delimiters.
|
|
|
|
// a name of "**" means 0 or more objects in the heirachy chain
|
|
|
|
// if the string has no "/" char at the start, it implies "/**/"
|
|
|
|
// a name can be a name or the form "class:name" where the object must
|
|
|
|
// be of class named "class" and name "name". if "name" is empty like:
|
|
|
|
// "class:" then an object of any name will match like "class:*". an
|
|
|
|
// empty class like ":name" is the sanme as "*:name" which is the same
|
|
|
|
// as "name". class ane name of course can be basic globs but not **
|
|
|
|
|
|
|
|
// search string NULL or "" is invalid
|
|
|
|
if (!search) return NULL;
|
|
|
|
if (!search[0]) return NULL;
|
|
|
|
|
|
|
|
if (strchr(search, '/'))
|
|
|
|
{
|
|
|
|
ERR("Looking up object by path '%s' is not supported", search);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// if this is a multi glob - "**" then we don't have a name or
|
|
|
|
// class to match at all so just don't look
|
|
|
|
if (_ismultiglob(search)) return NULL;
|
|
|
|
// check if this is "class:name" or just "name"
|
|
|
|
if ((p = strchr(search, ':')))
|
|
|
|
{
|
|
|
|
// "class:name"
|
2016-05-16 09:41:59 -07:00
|
|
|
char *klass;
|
2016-05-17 08:00:13 -07:00
|
|
|
char *search_name;
|
2016-05-16 09:41:59 -07:00
|
|
|
size_t colon_location = p - search;
|
2016-04-20 02:26:35 -07:00
|
|
|
Eina_Bool klass_glob = EINA_FALSE;
|
|
|
|
Eina_Bool name_glob = EINA_FALSE;
|
|
|
|
|
|
|
|
// split class:name into 2 strings dropping :
|
2016-05-16 09:41:59 -07:00
|
|
|
klass = alloca(strlen(search) + 1);
|
|
|
|
strcpy(klass, search);
|
|
|
|
klass[colon_location] = '\0';
|
2016-05-17 08:00:13 -07:00
|
|
|
search_name = klass + colon_location + 1;
|
2016-04-20 02:26:35 -07:00
|
|
|
|
|
|
|
// figure out if class or name are globs
|
|
|
|
klass_glob = _hasglob(klass);
|
2016-05-17 08:00:13 -07:00
|
|
|
name_glob = _hasglob(search_name);
|
2016-05-17 02:25:31 -07:00
|
|
|
EINA_INLIST_FOREACH(pd->children, child_eo)
|
2016-04-20 02:26:35 -07:00
|
|
|
{
|
2016-05-17 02:29:14 -07:00
|
|
|
child = _eo_obj_id_get(child_eo);
|
2016-08-09 06:10:05 -07:00
|
|
|
name = efl_name_get(child);
|
2016-08-15 06:44:41 -07:00
|
|
|
klass_name = efl_class_name_get(efl_class_get(child));
|
2016-05-17 08:00:13 -07:00
|
|
|
if (_name_match(klass, klass_glob, klass_name) &&
|
|
|
|
(((!_matchall(klass)) && (!name) && (_matchall(search_name))) ||
|
|
|
|
((name) && _name_match(search_name, name_glob, name))))
|
2016-04-20 02:26:35 -07:00
|
|
|
return child;
|
2016-08-09 06:10:05 -07:00
|
|
|
child = efl_name_find(child, search);
|
2016-04-20 02:26:35 -07:00
|
|
|
if (child) return child;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (_hasglob(search))
|
|
|
|
{
|
|
|
|
// we have a glob - fnmatch
|
2016-05-17 02:25:31 -07:00
|
|
|
EINA_INLIST_FOREACH(pd->children, child_eo)
|
2016-04-20 02:26:35 -07:00
|
|
|
{
|
2016-05-17 02:29:14 -07:00
|
|
|
child = _eo_obj_id_get(child_eo);
|
2016-08-09 06:10:05 -07:00
|
|
|
name = efl_name_get(child);
|
2016-05-17 08:00:13 -07:00
|
|
|
if ((name) && (_name_match(search, EINA_TRUE, name)))
|
2016-04-20 02:26:35 -07:00
|
|
|
return child;
|
2016-08-09 06:10:05 -07:00
|
|
|
child = efl_name_find(child, search);
|
2016-04-20 02:26:35 -07:00
|
|
|
if (child) return child;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// fast path for simple "name"
|
2016-05-17 02:25:31 -07:00
|
|
|
EINA_INLIST_FOREACH(pd->children, child_eo)
|
2016-04-20 02:26:35 -07:00
|
|
|
{
|
2016-05-17 02:29:14 -07:00
|
|
|
child = _eo_obj_id_get(child_eo);
|
2016-08-09 06:10:05 -07:00
|
|
|
name = efl_name_get(child);
|
2016-05-17 08:00:13 -07:00
|
|
|
if ((name) && (_name_match(search, EINA_FALSE, name)))
|
2016-04-20 02:26:35 -07:00
|
|
|
return child;
|
2016-08-09 06:10:05 -07:00
|
|
|
child = efl_name_find(child, search);
|
2016-04-20 02:26:35 -07:00
|
|
|
if (child) return child;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-04-19 01:21:21 -07:00
|
|
|
EOLIAN static void
|
2016-08-09 06:10:05 -07:00
|
|
|
_efl_object_comment_set(Eo *obj EINA_UNUSED, Efl_Object_Data *pd, const char *comment)
|
2016-04-19 01:21:21 -07:00
|
|
|
{
|
|
|
|
if ((comment) && (!comment[0])) comment = NULL;
|
|
|
|
if (comment)
|
|
|
|
{
|
2016-08-09 06:10:05 -07:00
|
|
|
_efl_object_extension_need(pd);
|
2016-04-23 22:38:02 -07:00
|
|
|
if (pd->ext) eina_stringshare_replace(&(pd->ext->comment), comment);
|
2016-04-19 01:21:21 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-04-23 22:38:02 -07:00
|
|
|
if (!pd->ext) return;
|
|
|
|
if (pd->ext->comment)
|
2016-04-19 01:21:21 -07:00
|
|
|
{
|
2016-04-23 22:38:02 -07:00
|
|
|
eina_stringshare_replace(&(pd->ext->comment), comment);
|
2016-08-09 06:10:05 -07:00
|
|
|
_efl_object_extension_noneed(pd);
|
2016-04-19 01:21:21 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
EOLIAN static const char *
|
2018-04-17 11:09:44 -07:00
|
|
|
_efl_object_comment_get(const Eo *obj EINA_UNUSED, Efl_Object_Data *pd)
|
2016-04-19 01:21:21 -07:00
|
|
|
{
|
2016-04-23 22:38:02 -07:00
|
|
|
if (!pd->ext) return NULL;
|
|
|
|
return pd->ext->comment;
|
2016-04-19 00:34:53 -07:00
|
|
|
}
|
|
|
|
|
2017-10-12 18:54:54 -07:00
|
|
|
EOLIAN static void
|
|
|
|
_efl_object_debug_name_override(Eo *obj_id EINA_UNUSED, Efl_Object_Data *pd EINA_UNUSED, Eina_Strbuf *sb EINA_UNUSED)
|
2017-07-13 23:57:36 -07:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2018-05-07 10:50:30 -07:00
|
|
|
EAPI void
|
|
|
|
efl_del(const Eo *obj)
|
Revert "Eo: Remove eo_del() and make eo_unref() the replacement."
This reverts commit 546ff7bbba788ec834c5608361c0834853f2d5d7.
It seems that eo_del() is useful and removing it was creating bugs.
The issue is that the way we defined parents in eo, both the parent and
the programmer share a reference to the object. When we eo_unref() that
reference as the programmer, eo has no way to know it's this specific
reference we are freeing, and not a general one, so in some
circumstances, for example:
eo_ref(child);
eo_unref(child); // trying to delete here
eo_unref(container); // container is deleted here
eo_unref(child); // child already has 0 refs before this point.
We would have an issue with references and objects being freed too soon
and in general, issue with the references.
Having eo_del() solves that, because this one explicitly unparents if
there is a parent, meaning the reference ownership is explicitly taken
by the programmer.
eo_del() is essentially a convenience function around "check if has
parent, and if so unparent, otherwise, unref". Which should be used when
you want to delete an object although it has a parent, and is equivalent
to eo_unref() when it doesn't have one.
2016-06-01 05:14:30 -07:00
|
|
|
{
|
2018-05-07 10:50:30 -07:00
|
|
|
if (!obj) return ;
|
2018-05-12 22:11:33 -07:00
|
|
|
EO_OBJ_POINTER_RETURN(obj, oid);
|
|
|
|
_efl_ref(oid);
|
2016-08-09 06:10:05 -07:00
|
|
|
if (efl_parent_get((Eo *) obj))
|
Revert "Eo: Remove eo_del() and make eo_unref() the replacement."
This reverts commit 546ff7bbba788ec834c5608361c0834853f2d5d7.
It seems that eo_del() is useful and removing it was creating bugs.
The issue is that the way we defined parents in eo, both the parent and
the programmer share a reference to the object. When we eo_unref() that
reference as the programmer, eo has no way to know it's this specific
reference we are freeing, and not a general one, so in some
circumstances, for example:
eo_ref(child);
eo_unref(child); // trying to delete here
eo_unref(container); // container is deleted here
eo_unref(child); // child already has 0 refs before this point.
We would have an issue with references and objects being freed too soon
and in general, issue with the references.
Having eo_del() solves that, because this one explicitly unparents if
there is a parent, meaning the reference ownership is explicitly taken
by the programmer.
eo_del() is essentially a convenience function around "check if has
parent, and if so unparent, otherwise, unref". Which should be used when
you want to delete an object although it has a parent, and is equivalent
to eo_unref() when it doesn't have one.
2016-06-01 05:14:30 -07:00
|
|
|
{
|
2016-08-09 06:10:05 -07:00
|
|
|
efl_parent_set((Eo *) obj, NULL);
|
Revert "Eo: Remove eo_del() and make eo_unref() the replacement."
This reverts commit 546ff7bbba788ec834c5608361c0834853f2d5d7.
It seems that eo_del() is useful and removing it was creating bugs.
The issue is that the way we defined parents in eo, both the parent and
the programmer share a reference to the object. When we eo_unref() that
reference as the programmer, eo has no way to know it's this specific
reference we are freeing, and not a general one, so in some
circumstances, for example:
eo_ref(child);
eo_unref(child); // trying to delete here
eo_unref(container); // container is deleted here
eo_unref(child); // child already has 0 refs before this point.
We would have an issue with references and objects being freed too soon
and in general, issue with the references.
Having eo_del() solves that, because this one explicitly unparents if
there is a parent, meaning the reference ownership is explicitly taken
by the programmer.
eo_del() is essentially a convenience function around "check if has
parent, and if so unparent, otherwise, unref". Which should be used when
you want to delete an object although it has a parent, and is equivalent
to eo_unref() when it doesn't have one.
2016-06-01 05:14:30 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-03-01 16:21:14 -08:00
|
|
|
ERR("Calling efl_del on object %s with no parent is not advised any more.", efl_debug_name_get(obj));
|
2016-08-15 06:44:41 -07:00
|
|
|
efl_unref(obj);
|
Revert "Eo: Remove eo_del() and make eo_unref() the replacement."
This reverts commit 546ff7bbba788ec834c5608361c0834853f2d5d7.
It seems that eo_del() is useful and removing it was creating bugs.
The issue is that the way we defined parents in eo, both the parent and
the programmer share a reference to the object. When we eo_unref() that
reference as the programmer, eo has no way to know it's this specific
reference we are freeing, and not a general one, so in some
circumstances, for example:
eo_ref(child);
eo_unref(child); // trying to delete here
eo_unref(container); // container is deleted here
eo_unref(child); // child already has 0 refs before this point.
We would have an issue with references and objects being freed too soon
and in general, issue with the references.
Having eo_del() solves that, because this one explicitly unparents if
there is a parent, meaning the reference ownership is explicitly taken
by the programmer.
eo_del() is essentially a convenience function around "check if has
parent, and if so unparent, otherwise, unref". Which should be used when
you want to delete an object although it has a parent, and is equivalent
to eo_unref() when it doesn't have one.
2016-06-01 05:14:30 -07:00
|
|
|
}
|
2018-05-12 22:11:33 -07:00
|
|
|
_efl_unref(oid);
|
|
|
|
EO_OBJ_DONE(obj);
|
Revert "Eo: Remove eo_del() and make eo_unref() the replacement."
This reverts commit 546ff7bbba788ec834c5608361c0834853f2d5d7.
It seems that eo_del() is useful and removing it was creating bugs.
The issue is that the way we defined parents in eo, both the parent and
the programmer share a reference to the object. When we eo_unref() that
reference as the programmer, eo has no way to know it's this specific
reference we are freeing, and not a general one, so in some
circumstances, for example:
eo_ref(child);
eo_unref(child); // trying to delete here
eo_unref(container); // container is deleted here
eo_unref(child); // child already has 0 refs before this point.
We would have an issue with references and objects being freed too soon
and in general, issue with the references.
Having eo_del() solves that, because this one explicitly unparents if
there is a parent, meaning the reference ownership is explicitly taken
by the programmer.
eo_del() is essentially a convenience function around "check if has
parent, and if so unparent, otherwise, unref". Which should be used when
you want to delete an object although it has a parent, and is equivalent
to eo_unref() when it doesn't have one.
2016-06-01 05:14:30 -07:00
|
|
|
}
|
|
|
|
|
2018-03-08 14:59:12 -08:00
|
|
|
void
|
2018-05-01 16:58:29 -07:00
|
|
|
_efl_object_reuse(_Eo_Object *obj)
|
2018-03-08 14:59:12 -08:00
|
|
|
{
|
2018-05-01 13:32:12 -07:00
|
|
|
obj->is_invalidating = EINA_FALSE;
|
2018-04-04 15:37:11 -07:00
|
|
|
obj->invalidate = EINA_FALSE;
|
2018-03-08 14:59:12 -08:00
|
|
|
}
|
|
|
|
|
2018-05-12 22:14:53 -07:00
|
|
|
EOLIAN void
|
2016-08-09 06:10:05 -07:00
|
|
|
_efl_object_parent_set(Eo *obj, Efl_Object_Data *pd, Eo *parent_id)
|
2013-12-26 12:11:48 -08:00
|
|
|
{
|
2016-10-21 07:02:27 -07:00
|
|
|
Eo *prev_parent = pd->parent;
|
2018-05-01 16:27:46 -07:00
|
|
|
Eina_Bool bad_parent = EINA_FALSE;
|
|
|
|
|
2016-09-28 23:29:34 -07:00
|
|
|
if ((pd->parent == parent_id) ||
|
|
|
|
((parent_id) && (!_eo_id_domain_compatible(parent_id, obj))))
|
2013-12-26 12:11:48 -08:00
|
|
|
return;
|
|
|
|
|
2018-05-01 16:27:46 -07:00
|
|
|
if (parent_id != NULL)
|
|
|
|
{
|
|
|
|
EO_OBJ_POINTER_GOTO(parent_id, parent_obj, err_impossible);
|
2018-06-29 14:10:26 -07:00
|
|
|
bad_parent = parent_obj->invalidate || (obj == parent_id);
|
2018-05-01 16:27:46 -07:00
|
|
|
EO_OBJ_DONE(parent_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bad_parent) goto err_parent;
|
|
|
|
|
2018-04-09 16:53:28 -07:00
|
|
|
EO_OBJ_POINTER_GOTO(obj, eo_obj, err_impossible);
|
|
|
|
|
2018-03-07 10:56:53 -08:00
|
|
|
// Invalidated object can not be bring back to life
|
2018-05-17 12:06:44 -07:00
|
|
|
if (eo_obj->invalidate)
|
2018-03-08 14:05:25 -08:00
|
|
|
{
|
2018-05-09 17:23:20 -07:00
|
|
|
ERR("Call of efl_parent_set(%p, %p) when object of clas '%s' is already invalidated.\n", obj, parent_id, efl_class_name_get(obj));
|
2018-04-04 15:37:11 -07:00
|
|
|
goto err_impossible;
|
2018-03-08 14:05:25 -08:00
|
|
|
}
|
2018-03-07 10:56:53 -08:00
|
|
|
|
2018-05-09 20:03:06 -07:00
|
|
|
if (!parent_id)
|
|
|
|
{
|
|
|
|
if (prev_parent) _efl_invalidate(eo_obj);
|
|
|
|
}
|
|
|
|
|
2013-12-26 12:11:48 -08:00
|
|
|
if (pd->parent)
|
|
|
|
{
|
2016-09-28 23:29:34 -07:00
|
|
|
Efl_Object_Data *old_parent_pd = efl_data_scope_get(pd->parent,
|
|
|
|
EFL_OBJECT_CLASS);
|
2013-12-26 12:11:48 -08:00
|
|
|
|
|
|
|
if (old_parent_pd)
|
2016-09-28 23:29:34 -07:00
|
|
|
old_parent_pd->children = eina_inlist_remove(old_parent_pd->children,
|
|
|
|
EINA_INLIST_GET(eo_obj));
|
|
|
|
// this error is highly unlikely so move it out of the normal
|
|
|
|
// instruction path to avoid l1 cache pollution
|
|
|
|
else goto err_impossible;
|
2013-12-26 12:11:48 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Set new parent */
|
|
|
|
if (parent_id)
|
|
|
|
{
|
2016-09-28 23:29:34 -07:00
|
|
|
Efl_Object_Data *parent_pd = efl_data_scope_get(parent_id,
|
|
|
|
EFL_OBJECT_CLASS);
|
2013-12-26 12:11:48 -08:00
|
|
|
|
|
|
|
if (EINA_LIKELY(parent_pd != NULL))
|
|
|
|
{
|
|
|
|
pd->parent = parent_id;
|
2016-05-17 02:25:31 -07:00
|
|
|
parent_pd->children = eina_inlist_append(parent_pd->children,
|
2016-09-28 23:29:34 -07:00
|
|
|
EINA_INLIST_GET(eo_obj));
|
2018-05-15 15:35:48 -07:00
|
|
|
if (!prev_parent) efl_ref(obj);
|
2013-12-26 12:11:48 -08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pd->parent = NULL;
|
2016-10-21 07:02:27 -07:00
|
|
|
if (prev_parent) efl_unref(obj);
|
2016-09-28 23:29:34 -07:00
|
|
|
// unlikely this error happens, so move it out of execution path
|
|
|
|
// to improve l1 cache efficiency
|
2018-06-25 03:38:07 -07:00
|
|
|
goto err_parent_done;
|
2013-12-26 12:11:48 -08:00
|
|
|
}
|
2018-05-03 11:36:28 -07:00
|
|
|
|
|
|
|
eo_obj->parent = EINA_TRUE;
|
2013-12-26 12:11:48 -08:00
|
|
|
}
|
2016-10-21 07:02:27 -07:00
|
|
|
else
|
|
|
|
{
|
2018-04-24 11:37:48 -07:00
|
|
|
pd->parent = NULL;
|
2018-05-03 11:36:28 -07:00
|
|
|
eo_obj->parent = EINA_FALSE;
|
|
|
|
|
2016-10-21 07:02:27 -07:00
|
|
|
if (prev_parent && !eo_obj->del_triggered) efl_unref(obj);
|
|
|
|
}
|
2016-09-28 23:29:34 -07:00
|
|
|
|
2016-09-27 21:25:26 -07:00
|
|
|
EO_OBJ_DONE(obj);
|
2016-09-28 23:29:34 -07:00
|
|
|
return;
|
2016-10-06 00:19:12 -07:00
|
|
|
|
2018-06-25 03:38:07 -07:00
|
|
|
err_parent_done:
|
|
|
|
EO_OBJ_DONE(obj);
|
2016-09-28 23:29:34 -07:00
|
|
|
err_parent:
|
2018-06-29 14:10:26 -07:00
|
|
|
if (obj == parent_id)
|
|
|
|
ERR("New parent %p for object %p will not be set: THIS IS THE SAME OBJECT.",
|
|
|
|
parent_id, obj);
|
|
|
|
else
|
|
|
|
ERR("New parent %p for object %p is not a valid Eo object.",
|
|
|
|
parent_id, obj);
|
2016-09-28 23:29:34 -07:00
|
|
|
return;
|
2016-10-06 00:19:12 -07:00
|
|
|
|
2016-09-28 23:29:34 -07:00
|
|
|
err_impossible:
|
|
|
|
ERR("CONTACT DEVS!!! SHOULD NEVER HAPPEN!!! Old parent %p for object %p is not a valid Eo object.",
|
|
|
|
pd->parent, obj);
|
2013-12-26 12:11:48 -08:00
|
|
|
}
|
|
|
|
|
2014-06-03 03:23:53 -07:00
|
|
|
EOLIAN static Eo *
|
2018-04-17 11:09:44 -07:00
|
|
|
_efl_object_parent_get(const Eo *obj EINA_UNUSED, Efl_Object_Data *pd)
|
2013-12-26 12:11:48 -08:00
|
|
|
{
|
|
|
|
return pd->parent;
|
|
|
|
}
|
|
|
|
|
2014-08-29 01:55:02 -07:00
|
|
|
EOLIAN static Eina_Bool
|
2018-04-17 11:09:44 -07:00
|
|
|
_efl_object_finalized_get(const Eo *obj_id, Efl_Object_Data *pd EINA_UNUSED)
|
2014-08-29 01:55:02 -07:00
|
|
|
{
|
2016-09-27 21:25:26 -07:00
|
|
|
Eina_Bool finalized;
|
2014-08-29 01:55:02 -07:00
|
|
|
EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, EINA_FALSE);
|
2016-09-27 21:25:26 -07:00
|
|
|
finalized = obj->finalized;
|
2016-10-05 19:55:03 -07:00
|
|
|
EO_OBJ_DONE(obj_id);
|
2016-09-27 21:25:26 -07:00
|
|
|
return finalized;
|
2014-08-29 01:55:02 -07:00
|
|
|
}
|
|
|
|
|
2018-03-07 10:56:53 -08:00
|
|
|
EOLIAN static Eina_Bool
|
2018-05-23 19:35:03 -07:00
|
|
|
_efl_object_invalidated_get(const Eo *obj_id, Efl_Object_Data *pd)
|
2018-03-07 10:56:53 -08:00
|
|
|
{
|
2018-04-04 15:37:11 -07:00
|
|
|
Eina_Bool invalidate;
|
|
|
|
EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, EINA_TRUE);
|
2018-05-28 21:38:51 -07:00
|
|
|
invalidate = obj->invalidate;
|
2018-04-04 15:37:11 -07:00
|
|
|
EO_OBJ_DONE(obj_id);
|
2018-05-23 19:35:03 -07:00
|
|
|
if (!invalidate && pd && pd->parent)
|
|
|
|
return efl_invalidated_get(pd->parent);
|
2018-04-04 15:37:11 -07:00
|
|
|
return invalidate;
|
2018-03-07 10:56:53 -08:00
|
|
|
}
|
|
|
|
|
2018-08-20 10:15:56 -07:00
|
|
|
EOLIAN static Eina_Bool
|
|
|
|
_efl_object_invalidating_get(const Eo *obj_id, Efl_Object_Data *pd EINA_UNUSED)
|
|
|
|
{
|
|
|
|
Eina_Bool invalidating;
|
|
|
|
EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, EINA_TRUE);
|
|
|
|
invalidating = obj->is_invalidating;
|
|
|
|
EO_OBJ_DONE(obj_id);
|
|
|
|
return invalidating;
|
|
|
|
}
|
|
|
|
|
2016-08-09 06:10:05 -07:00
|
|
|
EOLIAN static Efl_Object *
|
2018-03-08 14:05:25 -08:00
|
|
|
_efl_object_provider_find(const Eo *obj, Efl_Object_Data *pd, const Efl_Object *klass)
|
2016-04-20 23:15:13 -07:00
|
|
|
{
|
2018-04-04 15:37:11 -07:00
|
|
|
Eina_Bool invalidate;
|
2019-07-11 14:53:19 -07:00
|
|
|
Efl_Object *r = NULL;
|
2018-04-04 15:37:11 -07:00
|
|
|
|
|
|
|
invalidate = _efl_object_invalidated_get((Eo*) obj, NULL);
|
|
|
|
if (invalidate)
|
2018-03-08 14:05:25 -08:00
|
|
|
{
|
|
|
|
ERR("Calling efl_provider_find(%p) after the object was invalidated.", obj);
|
2018-05-01 13:32:12 -07:00
|
|
|
return NULL;
|
2018-03-08 14:05:25 -08:00
|
|
|
}
|
2019-07-11 14:53:19 -07:00
|
|
|
|
|
|
|
if (efl_isa(obj, klass)) return (Eo *) obj;
|
|
|
|
|
|
|
|
if (pd->ext) r = eina_hash_find(pd->ext->providers, &klass);
|
|
|
|
if (r) return r;
|
|
|
|
|
2016-08-09 06:10:05 -07:00
|
|
|
if (pd->parent) return efl_provider_find(pd->parent, klass);
|
2016-04-20 23:15:13 -07:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2019-07-11 14:53:19 -07:00
|
|
|
static Eina_Bool
|
|
|
|
_efl_object_provider_register(Eo *obj EINA_UNUSED, Efl_Object_Data *pd, const Efl_Class *klass, const Efl_Object *provider)
|
|
|
|
{
|
|
|
|
// The passed object does not provide that said class.
|
|
|
|
if (!efl_isa(provider, klass)) return EINA_FALSE;
|
|
|
|
|
|
|
|
_efl_object_extension_need(pd);
|
|
|
|
if (!pd->ext) return EINA_FALSE;
|
|
|
|
if (!pd->ext->providers) pd->ext->providers = eina_hash_pointer_new(EINA_FREE_CB(efl_unref));
|
|
|
|
|
|
|
|
// Prevent double insertion for the same class
|
|
|
|
if (eina_hash_find(pd->ext->providers, &klass)) return EINA_FALSE;
|
|
|
|
|
|
|
|
// Note: I would prefer to use efl_xref here, but I can't figure a nice way to
|
|
|
|
// call efl_xunref on hash destruction.
|
|
|
|
return eina_hash_add(pd->ext->providers, &klass, efl_ref(provider));
|
|
|
|
}
|
|
|
|
|
|
|
|
static Eina_Bool
|
|
|
|
_efl_object_provider_unregister(Eo *obj EINA_UNUSED, Efl_Object_Data *pd, const Efl_Class *klass, const Efl_Object *provider)
|
|
|
|
{
|
|
|
|
Eina_Bool r;
|
|
|
|
|
|
|
|
if (!pd->ext) return EINA_FALSE;
|
|
|
|
r = eina_hash_del(pd->ext->providers, &klass, provider);
|
|
|
|
|
|
|
|
if (eina_hash_population(pd->ext->providers) != 0) return r;
|
|
|
|
eina_hash_free(pd->ext->providers);
|
|
|
|
pd->ext->providers = NULL;
|
|
|
|
_efl_object_extension_noneed(pd);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2013-12-26 12:11:48 -08:00
|
|
|
/* Children accessor */
|
|
|
|
typedef struct _Eo_Children_Iterator Eo_Children_Iterator;
|
|
|
|
struct _Eo_Children_Iterator
|
|
|
|
{
|
|
|
|
Eina_Iterator iterator;
|
2016-05-17 02:25:31 -07:00
|
|
|
Eina_Inlist *current;
|
2013-12-26 12:11:48 -08:00
|
|
|
_Eo_Object *obj;
|
|
|
|
Eo *obj_id;
|
|
|
|
};
|
|
|
|
|
|
|
|
static Eina_Bool
|
2016-08-09 06:10:05 -07:00
|
|
|
_efl_children_iterator_next(Eo_Children_Iterator *it, void **data)
|
2013-12-26 12:11:48 -08:00
|
|
|
{
|
|
|
|
if (!it->current) return EINA_FALSE;
|
|
|
|
|
2016-05-17 02:25:31 -07:00
|
|
|
if (data)
|
|
|
|
{
|
|
|
|
_Eo_Object *eo_obj = EINA_INLIST_CONTAINER_GET(it->current, _Eo_Object);
|
2016-05-17 02:29:14 -07:00
|
|
|
*data = _eo_obj_id_get(eo_obj);
|
2016-05-17 02:25:31 -07:00
|
|
|
}
|
|
|
|
it->current = it->current->next;
|
2013-12-26 12:11:48 -08:00
|
|
|
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Eo *
|
2016-08-09 06:10:05 -07:00
|
|
|
_efl_children_iterator_container(Eo_Children_Iterator *it)
|
2013-12-26 12:11:48 -08:00
|
|
|
{
|
|
|
|
return it->obj_id;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2016-08-09 06:10:05 -07:00
|
|
|
_efl_children_iterator_free(Eo_Children_Iterator *it)
|
2013-12-26 12:11:48 -08:00
|
|
|
{
|
2016-08-09 06:10:05 -07:00
|
|
|
_Efl_Class *klass;
|
2013-12-26 12:11:48 -08:00
|
|
|
_Eo_Object *obj;
|
|
|
|
|
2016-08-09 06:10:05 -07:00
|
|
|
klass = (_Efl_Class*) it->obj->klass;
|
2013-12-26 12:11:48 -08:00
|
|
|
obj = it->obj;
|
|
|
|
|
|
|
|
eina_spinlock_take(&klass->iterators.trash_lock);
|
|
|
|
if (klass->iterators.trash_count < 8)
|
|
|
|
{
|
|
|
|
klass->iterators.trash_count++;
|
|
|
|
eina_trash_push(&klass->iterators.trash, it);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-11-04 03:13:53 -07:00
|
|
|
eina_freeq_ptr_main_add(it, free, sizeof(*it));
|
2013-12-26 12:11:48 -08:00
|
|
|
}
|
|
|
|
eina_spinlock_release(&klass->iterators.trash_lock);
|
|
|
|
|
2016-08-15 06:44:41 -07:00
|
|
|
_efl_unref(obj);
|
2013-12-26 12:11:48 -08:00
|
|
|
}
|
|
|
|
|
2014-06-03 03:23:53 -07:00
|
|
|
EOLIAN static Eina_Iterator *
|
2016-08-09 06:10:05 -07:00
|
|
|
_efl_object_children_iterator_new(Eo *obj_id, Efl_Object_Data *pd)
|
2013-12-26 12:11:48 -08:00
|
|
|
{
|
2016-08-09 06:10:05 -07:00
|
|
|
_Efl_Class *klass;
|
2016-09-28 23:29:34 -07:00
|
|
|
Eo_Children_Iterator *it = NULL;
|
2013-12-26 12:11:48 -08:00
|
|
|
|
|
|
|
EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, NULL);
|
|
|
|
|
2016-09-28 23:29:34 -07:00
|
|
|
if (pd->children)
|
2013-12-26 12:11:48 -08:00
|
|
|
{
|
2016-09-28 23:29:34 -07:00
|
|
|
klass = (_Efl_Class *)obj->klass;
|
2013-12-26 12:11:48 -08:00
|
|
|
|
2016-09-28 23:29:34 -07:00
|
|
|
eina_spinlock_take(&klass->iterators.trash_lock);
|
|
|
|
it = eina_trash_pop(&klass->iterators.trash);
|
|
|
|
if (it)
|
|
|
|
{
|
|
|
|
klass->iterators.trash_count--;
|
|
|
|
memset(it, 0, sizeof (Eo_Children_Iterator));
|
|
|
|
}
|
|
|
|
else it = calloc(1, sizeof (Eo_Children_Iterator));
|
|
|
|
eina_spinlock_release(&klass->iterators.trash_lock);
|
|
|
|
// very unlikely to not allocate the iterator to move this error
|
|
|
|
// handling out of l1 instruction cache
|
|
|
|
if (!it) goto done;
|
|
|
|
|
|
|
|
EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
|
|
|
|
it->current = pd->children;
|
|
|
|
it->obj = _efl_ref(obj);
|
|
|
|
it->obj_id = obj_id;
|
|
|
|
it->iterator.next = FUNC_ITERATOR_NEXT(_efl_children_iterator_next);
|
|
|
|
it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_efl_children_iterator_container);
|
|
|
|
it->iterator.free = FUNC_ITERATOR_FREE(_efl_children_iterator_free);
|
|
|
|
}
|
|
|
|
done:
|
2016-09-27 21:25:26 -07:00
|
|
|
EO_OBJ_DONE(obj_id);
|
2013-12-26 12:11:48 -08:00
|
|
|
return (Eina_Iterator *)it;
|
|
|
|
}
|
|
|
|
|
2014-06-03 03:23:53 -07:00
|
|
|
EOLIAN static void
|
2016-08-09 06:10:05 -07:00
|
|
|
_efl_object_dbg_info_get(Eo *obj EINA_UNUSED, Efl_Object_Data *pd EINA_UNUSED, Efl_Dbg_Info *root_node EINA_UNUSED)
|
2013-12-25 06:13:41 -08:00
|
|
|
{ /* No info required in the meantime */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-04-21 08:58:38 -07:00
|
|
|
EOAPI EFL_VOID_FUNC_BODYV(efl_dbg_info_get, EFL_FUNC_CALL(root_node), Efl_Dbg_Info *root_node);
|
|
|
|
|
2013-12-25 06:13:41 -08:00
|
|
|
/* Weak reference. */
|
|
|
|
|
|
|
|
static inline size_t
|
2016-08-09 06:10:05 -07:00
|
|
|
_wref_count(Efl_Object_Data *pd)
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
2016-04-23 22:38:02 -07:00
|
|
|
Eo ***itr;
|
2013-12-25 06:13:41 -08:00
|
|
|
size_t count = 0;
|
2016-08-09 06:10:05 -07:00
|
|
|
Efl_Object_Extension *ext = pd->ext;
|
2013-12-25 06:13:41 -08:00
|
|
|
|
2016-04-23 22:38:02 -07:00
|
|
|
if ((!ext) || (!ext->wrefs)) return 0;
|
|
|
|
for (itr = ext->wrefs; *itr; itr++) count++;
|
2013-12-25 06:13:41 -08:00
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2014-06-03 03:23:53 -07:00
|
|
|
EOLIAN static void
|
2016-08-09 06:10:05 -07:00
|
|
|
_efl_object_wref_add(Eo *obj, Efl_Object_Data *pd, Eo **wref)
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
|
|
|
size_t count;
|
2013-12-26 11:56:59 -08:00
|
|
|
Eo ***tmp;
|
2016-08-09 06:10:05 -07:00
|
|
|
Efl_Object_Extension *ext;
|
2013-12-25 06:13:41 -08:00
|
|
|
|
|
|
|
count = _wref_count(pd);
|
|
|
|
count += 1; /* New wref. */
|
|
|
|
|
2016-07-13 17:07:47 -07:00
|
|
|
ext = _efl_object_extension_need(pd);
|
2016-09-28 23:29:34 -07:00
|
|
|
if (ext)
|
|
|
|
{
|
|
|
|
tmp = realloc(ext->wrefs, sizeof(*ext->wrefs) * (count + 1));
|
|
|
|
if (tmp)
|
|
|
|
{
|
|
|
|
ext->wrefs = tmp;
|
|
|
|
ext->wrefs[count - 1] = wref;
|
|
|
|
ext->wrefs[count] = NULL;
|
|
|
|
*wref = obj;
|
|
|
|
}
|
|
|
|
}
|
2013-12-25 06:13:41 -08:00
|
|
|
}
|
|
|
|
|
2017-04-26 06:01:44 -07:00
|
|
|
EOAPI EFL_VOID_FUNC_BODYV(efl_wref_add, EFL_FUNC_CALL(wref), Efl_Object **wref);
|
|
|
|
|
2016-01-12 22:19:07 -08:00
|
|
|
EOLIAN static void
|
2016-08-09 06:10:05 -07:00
|
|
|
_efl_object_wref_del(Eo *obj, Efl_Object_Data *pd, Eo **wref)
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
|
|
|
size_t count;
|
2016-08-09 06:10:05 -07:00
|
|
|
Efl_Object_Extension *ext = pd->ext;
|
2013-12-25 06:13:41 -08:00
|
|
|
|
2016-09-28 23:29:34 -07:00
|
|
|
// very unlikely so improve l1 instr cache by using goto
|
|
|
|
if (*wref != obj) goto err_wref_not_obj;
|
2013-12-25 06:13:41 -08:00
|
|
|
|
2016-09-28 23:29:34 -07:00
|
|
|
// very unlikely so improve l1 instr cache by using goto
|
|
|
|
if ((!ext) || (!ext->wrefs)) goto err_wref_none;
|
2013-12-25 06:13:41 -08:00
|
|
|
|
|
|
|
/* Move the last item in the array instead of the current wref. */
|
|
|
|
count = _wref_count(pd);
|
|
|
|
|
|
|
|
{
|
|
|
|
Eo ***itr;
|
2016-04-23 22:38:02 -07:00
|
|
|
for (itr = ext->wrefs; *itr; itr++)
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
|
|
|
if (*itr == wref)
|
|
|
|
{
|
2016-04-23 22:38:02 -07:00
|
|
|
*itr = ext->wrefs[count - 1];
|
2013-12-25 06:13:41 -08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2016-09-28 23:29:34 -07:00
|
|
|
// very unlikely so improve l1 instr cache by using goto
|
|
|
|
if (!*itr) goto err_noiter;
|
2013-12-25 06:13:41 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (count > 1)
|
|
|
|
{
|
2013-12-26 11:56:59 -08:00
|
|
|
Eo ***tmp;
|
2016-04-23 22:38:02 -07:00
|
|
|
// No count--; because of the NULL that is not included in the count
|
|
|
|
tmp = realloc(ext->wrefs, sizeof(*ext->wrefs) * count);
|
2013-12-26 11:56:59 -08:00
|
|
|
if (!tmp) return;
|
2016-04-23 22:38:02 -07:00
|
|
|
ext->wrefs = tmp;
|
|
|
|
ext->wrefs[count - 1] = NULL;
|
2016-09-28 23:29:34 -07:00
|
|
|
*wref = NULL;
|
|
|
|
return;
|
2013-12-25 06:13:41 -08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-11-04 03:13:53 -07:00
|
|
|
eina_freeq_ptr_main_add(ext->wrefs, free, 0);
|
2016-04-23 22:38:02 -07:00
|
|
|
ext->wrefs = NULL;
|
2016-08-09 06:10:05 -07:00
|
|
|
_efl_object_extension_noneed(pd);
|
2013-12-25 06:13:41 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
*wref = NULL;
|
2016-09-28 23:29:34 -07:00
|
|
|
return;
|
|
|
|
|
|
|
|
err_noiter:
|
|
|
|
ERR("Wref %p is not associated with object %p", wref, obj);
|
|
|
|
goto err_null;
|
|
|
|
err_wref_none:
|
|
|
|
ERR("There are no weak refs for object %p", obj);
|
|
|
|
err_null:
|
|
|
|
*wref = NULL;
|
|
|
|
return;
|
|
|
|
err_wref_not_obj:
|
|
|
|
ERR("Wref is a weak ref to %p, while this function was called on %p.",
|
|
|
|
*wref, obj);
|
|
|
|
return;
|
2013-12-25 06:13:41 -08:00
|
|
|
}
|
|
|
|
|
2017-04-26 06:01:44 -07:00
|
|
|
EOAPI EFL_VOID_FUNC_BODYV(efl_wref_del, EFL_FUNC_CALL(wref), Efl_Object **wref);
|
|
|
|
|
2013-12-25 06:13:41 -08:00
|
|
|
static inline void
|
2016-08-09 06:10:05 -07:00
|
|
|
_wref_destruct(Efl_Object_Data *pd)
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
|
|
|
Eo ***itr;
|
2016-08-09 06:10:05 -07:00
|
|
|
Efl_Object_Extension *ext = pd->ext;
|
2013-12-25 06:13:41 -08:00
|
|
|
|
2016-04-23 22:38:02 -07:00
|
|
|
if ((!ext) || (!ext->wrefs)) return;
|
|
|
|
for (itr = ext->wrefs; *itr; itr++) **itr = NULL;
|
2016-11-04 03:13:53 -07:00
|
|
|
eina_freeq_ptr_main_add(ext->wrefs, free, 0);
|
2016-04-23 22:38:02 -07:00
|
|
|
ext->wrefs = NULL;
|
2013-12-25 06:13:41 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* EOF Weak reference. */
|
|
|
|
|
|
|
|
/* Event callbacks */
|
|
|
|
|
|
|
|
/* Callbacks */
|
|
|
|
|
2014-05-19 07:17:08 -07:00
|
|
|
/* XXX: Legacy support, remove when legacy is dead. */
|
|
|
|
static Eina_Hash *_legacy_events_hash = NULL;
|
|
|
|
|
2016-08-09 06:10:05 -07:00
|
|
|
EAPI const Efl_Event_Description *
|
|
|
|
efl_object_legacy_only_event_description_get(const char *_event_name)
|
2014-05-19 07:17:08 -07:00
|
|
|
{
|
2016-03-04 06:17:55 -08:00
|
|
|
Eina_Stringshare *event_name = eina_stringshare_add(_event_name);
|
2016-08-09 06:10:05 -07:00
|
|
|
Efl_Event_Description *event_desc = eina_hash_find(_legacy_events_hash, event_name);
|
2014-05-19 07:17:08 -07:00
|
|
|
if (!event_desc)
|
|
|
|
{
|
2016-08-09 06:10:05 -07:00
|
|
|
event_desc = calloc(1, sizeof(Efl_Event_Description));
|
2014-05-19 07:17:08 -07:00
|
|
|
event_desc->name = event_name;
|
2015-10-16 03:42:37 -07:00
|
|
|
event_desc->legacy_is = EINA_TRUE;
|
2019-09-19 00:27:59 -07:00
|
|
|
event_desc->unfreezable = EINA_TRUE;
|
2014-05-29 01:24:28 -07:00
|
|
|
eina_hash_add(_legacy_events_hash, event_name, event_desc);
|
2014-05-19 07:17:08 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
eina_stringshare_del(event_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
return event_desc;
|
|
|
|
}
|
|
|
|
|
2015-10-16 03:42:37 -07:00
|
|
|
static inline Eina_Bool
|
2016-08-09 06:10:05 -07:00
|
|
|
_legacy_event_desc_is(const Efl_Event_Description *desc)
|
2015-09-28 16:45:34 -07:00
|
|
|
{
|
2015-10-16 03:42:37 -07:00
|
|
|
return desc->legacy_is;
|
2015-09-28 16:45:34 -07:00
|
|
|
}
|
|
|
|
|
2014-05-19 07:17:08 -07:00
|
|
|
static void
|
|
|
|
_legacy_events_hash_free_cb(void *_desc)
|
|
|
|
{
|
2016-08-09 06:10:05 -07:00
|
|
|
Efl_Event_Description *desc = _desc;
|
2014-05-19 07:17:08 -07:00
|
|
|
eina_stringshare_del(desc->name);
|
2016-11-04 03:13:53 -07:00
|
|
|
eina_freeq_ptr_main_add(desc, free, sizeof(*desc));
|
2014-05-19 07:17:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* EOF Legacy */
|
2013-12-25 06:13:41 -08:00
|
|
|
struct _Eo_Callback_Description
|
|
|
|
{
|
|
|
|
union
|
|
|
|
{
|
2016-08-09 06:10:05 -07:00
|
|
|
Efl_Callback_Array_Item item;
|
|
|
|
const Efl_Callback_Array_Item *item_array;
|
2013-12-25 06:13:41 -08:00
|
|
|
} items;
|
|
|
|
|
|
|
|
void *func_data;
|
2016-08-09 06:10:05 -07:00
|
|
|
Efl_Callback_Priority priority;
|
2013-12-25 06:13:41 -08:00
|
|
|
|
2016-12-02 02:39:57 -08:00
|
|
|
unsigned short generation;
|
2016-12-01 03:40:36 -08:00
|
|
|
|
2013-12-25 06:13:41 -08:00
|
|
|
Eina_Bool delete_me : 1;
|
|
|
|
Eina_Bool func_array : 1;
|
|
|
|
};
|
|
|
|
|
2016-08-28 23:36:48 -07:00
|
|
|
static Eina_Mempool *_eo_callback_mempool = NULL;
|
2017-08-25 15:53:15 -07:00
|
|
|
static Eina_Mempool *_efl_pending_future_mempool = NULL;
|
2019-10-16 16:47:10 -07:00
|
|
|
static Eina_Mempool *_efl_future_scheduler_entry_mempool = NULL;
|
2016-08-28 23:36:48 -07:00
|
|
|
|
2017-08-25 15:53:15 -07:00
|
|
|
static void
|
|
|
|
_eo_callback_free(Eo_Callback_Description *cb)
|
|
|
|
{
|
2018-01-08 15:03:21 -08:00
|
|
|
eina_mempool_free(_eo_callback_mempool, cb);
|
2017-08-25 15:53:15 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static Eo_Callback_Description *
|
|
|
|
_eo_callback_new(void)
|
|
|
|
{
|
2018-01-08 15:03:21 -08:00
|
|
|
return eina_mempool_calloc(_eo_callback_mempool,
|
2017-08-25 15:53:15 -07:00
|
|
|
sizeof(Eo_Callback_Description));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_efl_pending_future_free(Efl_Future_Pending *pending)
|
|
|
|
{
|
2018-01-08 15:03:21 -08:00
|
|
|
eina_mempool_free(_efl_pending_future_mempool, pending);
|
2017-08-25 15:53:15 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static Efl_Future_Pending *
|
|
|
|
_efl_pending_future_new(void)
|
|
|
|
{
|
2018-01-08 15:03:21 -08:00
|
|
|
return eina_mempool_calloc(_efl_pending_future_mempool,
|
2017-08-25 15:53:15 -07:00
|
|
|
sizeof(Efl_Future_Pending));
|
|
|
|
}
|
|
|
|
|
efl object events - track del, cb add and cb del callback counts
so hunting another callback issue i noticed some of THE most popular
callbacks are:
1411 tick
1961 move
4157 pointer,move
7524 dirty
8090 damage
13052 render,flush,post
13052 render,flush,pre
13205 render,post
13205 render,pre
21706 recalc
21875 idle
27224 resize
27779 del
31011 idle,enter
31011 idle,exit
60461 callback,del
104546 callback,add
126400 animator,tick
as you can see callback del, add and the general obj del cb's are
right up there... so it is very likely a good idea to CHECK to see if
anyone is listening before calling the callback for these very very
very common calls.
this is ifdef'd and turned on for now. it can be turned off. it
shouldnt use more memory due to the way memory alignment works (likely
all allocations will be multiples of 8 bytes anyway) so we're using
spare unused space. the only q is - is management of the counts AND
checking them worth it in general? it's really hard to tell given we
dont have a lot of benchmarks that cover a lot of use cases... it
doesnt seem to slow or speed anything up much in the genlist bounce
test... so i think i need something more specific.
@optimize
2016-11-17 01:32:18 -08:00
|
|
|
#define CB_COUNT_INC(cnt) do { if ((cnt) != 0xffff) (cnt)++; } while(0)
|
|
|
|
#define CB_COUNT_DEC(cnt) do { if ((cnt) != 0xffff) (cnt)--; } while(0)
|
|
|
|
|
2019-10-15 17:04:32 -07:00
|
|
|
static inline unsigned char
|
|
|
|
_pointer_hash(const uintptr_t val)
|
|
|
|
{
|
2019-10-31 09:48:27 -07:00
|
|
|
static unsigned char shift = 0;
|
|
|
|
|
|
|
|
/* Sadly LLVM doesn't have log2 in its compile time optimization. So
|
|
|
|
we can not use static const here for portability sake. */
|
|
|
|
if (EINA_UNLIKELY((!shift)))
|
|
|
|
shift = (unsigned char) log2(1 + sizeof (Efl_Event_Description));
|
2019-10-15 17:04:32 -07:00
|
|
|
#ifdef EFL64
|
|
|
|
return (unsigned char)(((val) >> shift) & 0x3F);
|
|
|
|
#else
|
|
|
|
return (unsigned char)(((val) >> shift) & 0x1F);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2019-11-13 16:01:55 -08:00
|
|
|
#define EFL_OBJECT_EVENT_CB_INC(Obj, It, Pd, Event, Update_Hash) \
|
|
|
|
if (It->desc == Event && !Pd->event_cb_##Event) \
|
|
|
|
{ \
|
|
|
|
Update_Hash = EINA_FALSE; \
|
|
|
|
Pd->event_cb_##Event = EINA_TRUE; \
|
2019-10-17 12:09:14 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#define EFL_OBJECT_EVENT_CB_DEC(Obj, It, Pd, Event) \
|
|
|
|
if (It->desc == Event && Pd->event_cb_##Event) \
|
|
|
|
{ \
|
|
|
|
if (!efl_event_callback_count(Obj, Event)) \
|
|
|
|
Pd->event_cb_##Event = EINA_FALSE; \
|
|
|
|
}
|
|
|
|
|
efl object events - track del, cb add and cb del callback counts
so hunting another callback issue i noticed some of THE most popular
callbacks are:
1411 tick
1961 move
4157 pointer,move
7524 dirty
8090 damage
13052 render,flush,post
13052 render,flush,pre
13205 render,post
13205 render,pre
21706 recalc
21875 idle
27224 resize
27779 del
31011 idle,enter
31011 idle,exit
60461 callback,del
104546 callback,add
126400 animator,tick
as you can see callback del, add and the general obj del cb's are
right up there... so it is very likely a good idea to CHECK to see if
anyone is listening before calling the callback for these very very
very common calls.
this is ifdef'd and turned on for now. it can be turned off. it
shouldnt use more memory due to the way memory alignment works (likely
all allocations will be multiples of 8 bytes anyway) so we're using
spare unused space. the only q is - is management of the counts AND
checking them worth it in general? it's really hard to tell given we
dont have a lot of benchmarks that cover a lot of use cases... it
doesnt seem to slow or speed anything up much in the genlist bounce
test... so i think i need something more specific.
@optimize
2016-11-17 01:32:18 -08:00
|
|
|
static inline void
|
2019-01-23 16:29:47 -08:00
|
|
|
_special_event_count_inc(Eo *obj_id, Efl_Object_Data *pd, const Efl_Callback_Array_Item *it)
|
efl object events - track del, cb add and cb del callback counts
so hunting another callback issue i noticed some of THE most popular
callbacks are:
1411 tick
1961 move
4157 pointer,move
7524 dirty
8090 damage
13052 render,flush,post
13052 render,flush,pre
13205 render,post
13205 render,pre
21706 recalc
21875 idle
27224 resize
27779 del
31011 idle,enter
31011 idle,exit
60461 callback,del
104546 callback,add
126400 animator,tick
as you can see callback del, add and the general obj del cb's are
right up there... so it is very likely a good idea to CHECK to see if
anyone is listening before calling the callback for these very very
very common calls.
this is ifdef'd and turned on for now. it can be turned off. it
shouldnt use more memory due to the way memory alignment works (likely
all allocations will be multiples of 8 bytes anyway) so we're using
spare unused space. the only q is - is management of the counts AND
checking them worth it in general? it's really hard to tell given we
dont have a lot of benchmarks that cover a lot of use cases... it
doesnt seem to slow or speed anything up much in the genlist bounce
test... so i think i need something more specific.
@optimize
2016-11-17 01:32:18 -08:00
|
|
|
{
|
2019-11-13 16:01:55 -08:00
|
|
|
Eina_Bool update_hash = EINA_TRUE;
|
2019-10-15 17:04:32 -07:00
|
|
|
|
2019-11-13 16:01:55 -08:00
|
|
|
EFL_OBJECT_EVENT_CB_INC(obj_id, it, pd, EFL_EVENT_CALLBACK_ADD, update_hash)
|
|
|
|
else EFL_OBJECT_EVENT_CB_INC(obj_id, it, pd, EFL_EVENT_CALLBACK_DEL, update_hash)
|
|
|
|
else EFL_OBJECT_EVENT_CB_INC(obj_id, it, pd, EFL_EVENT_DEL, update_hash)
|
|
|
|
else EFL_OBJECT_EVENT_CB_INC(obj_id, it, pd, EFL_EVENT_INVALIDATE, update_hash)
|
|
|
|
else EFL_OBJECT_EVENT_CB_INC(obj_id, it, pd, EFL_EVENT_DESTRUCT, update_hash)
|
2019-10-17 12:09:14 -07:00
|
|
|
else if (it->desc == EFL_EVENT_NOREF && !pd->event_cb_EFL_EVENT_NOREF)
|
2019-01-23 16:29:47 -08:00
|
|
|
{
|
2019-11-13 16:01:55 -08:00
|
|
|
update_hash = EINA_FALSE;
|
2019-11-17 03:09:23 -08:00
|
|
|
EO_OBJ_POINTER_RETURN(obj_id, obj);
|
|
|
|
obj->noref_event = EINA_TRUE;
|
|
|
|
EO_OBJ_DONE(obj_id);
|
|
|
|
pd->event_cb_EFL_EVENT_NOREF = EINA_TRUE;
|
2019-01-23 16:29:47 -08:00
|
|
|
}
|
2019-05-23 11:41:57 -07:00
|
|
|
else if (it->desc == EFL_EVENT_OWNERSHIP_SHARED || it->desc == EFL_EVENT_OWNERSHIP_UNIQUE)
|
|
|
|
{
|
|
|
|
EO_OBJ_POINTER_RETURN(obj_id, obj);
|
|
|
|
obj->ownership_track = EINA_TRUE;
|
|
|
|
EO_OBJ_DONE(obj_id);
|
|
|
|
}
|
2019-11-13 16:01:55 -08:00
|
|
|
|
|
|
|
if (update_hash)
|
|
|
|
{
|
|
|
|
unsigned char event_hash;
|
|
|
|
|
|
|
|
event_hash = _pointer_hash((uintptr_t) it->desc);
|
|
|
|
|
|
|
|
pd->callbacks_mask |= 1ULL << event_hash;
|
|
|
|
}
|
efl object events - track del, cb add and cb del callback counts
so hunting another callback issue i noticed some of THE most popular
callbacks are:
1411 tick
1961 move
4157 pointer,move
7524 dirty
8090 damage
13052 render,flush,post
13052 render,flush,pre
13205 render,post
13205 render,pre
21706 recalc
21875 idle
27224 resize
27779 del
31011 idle,enter
31011 idle,exit
60461 callback,del
104546 callback,add
126400 animator,tick
as you can see callback del, add and the general obj del cb's are
right up there... so it is very likely a good idea to CHECK to see if
anyone is listening before calling the callback for these very very
very common calls.
this is ifdef'd and turned on for now. it can be turned off. it
shouldnt use more memory due to the way memory alignment works (likely
all allocations will be multiples of 8 bytes anyway) so we're using
spare unused space. the only q is - is management of the counts AND
checking them worth it in general? it's really hard to tell given we
dont have a lot of benchmarks that cover a lot of use cases... it
doesnt seem to slow or speed anything up much in the genlist bounce
test... so i think i need something more specific.
@optimize
2016-11-17 01:32:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
2019-01-23 16:29:47 -08:00
|
|
|
_special_event_count_dec(Eo *obj_id, Efl_Object_Data *pd, const Efl_Callback_Array_Item *it)
|
efl object events - track del, cb add and cb del callback counts
so hunting another callback issue i noticed some of THE most popular
callbacks are:
1411 tick
1961 move
4157 pointer,move
7524 dirty
8090 damage
13052 render,flush,post
13052 render,flush,pre
13205 render,post
13205 render,pre
21706 recalc
21875 idle
27224 resize
27779 del
31011 idle,enter
31011 idle,exit
60461 callback,del
104546 callback,add
126400 animator,tick
as you can see callback del, add and the general obj del cb's are
right up there... so it is very likely a good idea to CHECK to see if
anyone is listening before calling the callback for these very very
very common calls.
this is ifdef'd and turned on for now. it can be turned off. it
shouldnt use more memory due to the way memory alignment works (likely
all allocations will be multiples of 8 bytes anyway) so we're using
spare unused space. the only q is - is management of the counts AND
checking them worth it in general? it's really hard to tell given we
dont have a lot of benchmarks that cover a lot of use cases... it
doesnt seem to slow or speed anything up much in the genlist bounce
test... so i think i need something more specific.
@optimize
2016-11-17 01:32:18 -08:00
|
|
|
{
|
2019-10-17 12:09:14 -07:00
|
|
|
EFL_OBJECT_EVENT_CB_DEC(obj_id, it, pd, EFL_EVENT_CALLBACK_ADD)
|
|
|
|
else EFL_OBJECT_EVENT_CB_DEC(obj_id, it, pd, EFL_EVENT_CALLBACK_DEL)
|
|
|
|
else EFL_OBJECT_EVENT_CB_DEC(obj_id, it, pd, EFL_EVENT_DEL)
|
|
|
|
else EFL_OBJECT_EVENT_CB_DEC(obj_id, it, pd, EFL_EVENT_INVALIDATE)
|
|
|
|
else if (it->desc == EFL_EVENT_NOREF && pd->event_cb_EFL_EVENT_NOREF)
|
2019-01-23 16:29:47 -08:00
|
|
|
{
|
2019-10-17 12:09:14 -07:00
|
|
|
if (efl_event_callback_count(obj_id, EFL_EVENT_NOREF) == 0)
|
2019-01-23 16:29:47 -08:00
|
|
|
{
|
|
|
|
EO_OBJ_POINTER_RETURN(obj_id, obj);
|
|
|
|
obj->noref_event = EINA_FALSE;
|
|
|
|
EO_OBJ_DONE(obj_id);
|
2019-10-17 12:09:14 -07:00
|
|
|
|
|
|
|
pd->event_cb_EFL_EVENT_NOREF = EINA_FALSE;
|
2019-01-23 16:29:47 -08:00
|
|
|
}
|
|
|
|
}
|
efl object events - track del, cb add and cb del callback counts
so hunting another callback issue i noticed some of THE most popular
callbacks are:
1411 tick
1961 move
4157 pointer,move
7524 dirty
8090 damage
13052 render,flush,post
13052 render,flush,pre
13205 render,post
13205 render,pre
21706 recalc
21875 idle
27224 resize
27779 del
31011 idle,enter
31011 idle,exit
60461 callback,del
104546 callback,add
126400 animator,tick
as you can see callback del, add and the general obj del cb's are
right up there... so it is very likely a good idea to CHECK to see if
anyone is listening before calling the callback for these very very
very common calls.
this is ifdef'd and turned on for now. it can be turned off. it
shouldnt use more memory due to the way memory alignment works (likely
all allocations will be multiples of 8 bytes anyway) so we're using
spare unused space. the only q is - is management of the counts AND
checking them worth it in general? it's really hard to tell given we
dont have a lot of benchmarks that cover a lot of use cases... it
doesnt seem to slow or speed anything up much in the genlist bounce
test... so i think i need something more specific.
@optimize
2016-11-17 01:32:18 -08:00
|
|
|
}
|
|
|
|
|
2013-12-25 06:13:41 -08:00
|
|
|
/* Actually remove, doesn't care about walking list, or delete_me */
|
|
|
|
static void
|
2019-01-23 16:29:47 -08:00
|
|
|
_eo_callback_remove(Eo *obj, Efl_Object_Data *pd, Eo_Callback_Description **cb)
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
2019-10-17 12:09:14 -07:00
|
|
|
Eo_Callback_Description *tmp = *cb;
|
2016-08-31 17:15:35 -07:00
|
|
|
unsigned int length;
|
efl object events - track del, cb add and cb del callback counts
so hunting another callback issue i noticed some of THE most popular
callbacks are:
1411 tick
1961 move
4157 pointer,move
7524 dirty
8090 damage
13052 render,flush,post
13052 render,flush,pre
13205 render,post
13205 render,pre
21706 recalc
21875 idle
27224 resize
27779 del
31011 idle,enter
31011 idle,exit
60461 callback,del
104546 callback,add
126400 animator,tick
as you can see callback del, add and the general obj del cb's are
right up there... so it is very likely a good idea to CHECK to see if
anyone is listening before calling the callback for these very very
very common calls.
this is ifdef'd and turned on for now. it can be turned off. it
shouldnt use more memory due to the way memory alignment works (likely
all allocations will be multiples of 8 bytes anyway) so we're using
spare unused space. the only q is - is management of the counts AND
checking them worth it in general? it's really hard to tell given we
dont have a lot of benchmarks that cover a lot of use cases... it
doesnt seem to slow or speed anything up much in the genlist bounce
test... so i think i need something more specific.
@optimize
2016-11-17 01:32:18 -08:00
|
|
|
const Efl_Callback_Array_Item *it;
|
|
|
|
|
2016-08-31 17:15:35 -07:00
|
|
|
length = pd->callbacks_count - (cb - pd->callbacks);
|
2016-11-22 18:48:35 -08:00
|
|
|
if (length > 1)
|
|
|
|
memmove(cb, cb + 1, (length - 1) * sizeof(Eo_Callback_Description *));
|
2016-08-31 17:15:35 -07:00
|
|
|
pd->callbacks_count--;
|
2016-11-23 17:54:50 -08:00
|
|
|
|
2016-11-23 18:49:43 -08:00
|
|
|
if (_eo_nostep_alloc) pd->callbacks = realloc(pd->callbacks, pd->callbacks_count * sizeof (Eo_Callback_Description*));
|
|
|
|
|
2016-11-23 17:54:50 -08:00
|
|
|
if (pd->callbacks_count == 0)
|
|
|
|
{
|
|
|
|
free(pd->callbacks);
|
|
|
|
pd->callbacks = NULL;
|
|
|
|
}
|
2019-10-17 12:09:14 -07:00
|
|
|
|
|
|
|
if (tmp->func_array)
|
|
|
|
{
|
|
|
|
for (it = tmp->items.item_array; it->func; it++)
|
|
|
|
_special_event_count_dec(obj, pd, it);
|
|
|
|
}
|
|
|
|
else _special_event_count_dec(obj, pd, &(tmp->items.item));
|
|
|
|
|
|
|
|
_eo_callback_free(tmp);
|
2013-12-25 06:13:41 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Actually remove, doesn't care about walking list, or delete_me */
|
|
|
|
static void
|
2016-08-09 06:10:05 -07:00
|
|
|
_eo_callback_remove_all(Efl_Object_Data *pd)
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
2016-08-31 17:15:35 -07:00
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
for (i = 0; i < pd->callbacks_count; i++)
|
|
|
|
_eo_callback_free(pd->callbacks[i]);
|
|
|
|
|
2016-11-04 03:13:53 -07:00
|
|
|
eina_freeq_ptr_main_add(pd->callbacks, free, 0);
|
2016-09-06 06:12:23 -07:00
|
|
|
pd->callbacks = NULL;
|
2016-08-31 17:15:35 -07:00
|
|
|
pd->callbacks_count = 0;
|
2019-11-13 15:01:00 -08:00
|
|
|
pd->event_cb_EFL_EVENT_DESTRUCT = EINA_FALSE;
|
2019-10-17 12:09:14 -07:00
|
|
|
pd->event_cb_EFL_EVENT_CALLBACK_ADD = EINA_FALSE;
|
|
|
|
pd->event_cb_EFL_EVENT_CALLBACK_DEL = EINA_FALSE;
|
|
|
|
pd->event_cb_EFL_EVENT_DEL = EINA_FALSE;
|
|
|
|
pd->event_cb_EFL_EVENT_NOREF = EINA_FALSE;
|
|
|
|
pd->event_cb_EFL_EVENT_INVALIDATE = EINA_FALSE;
|
2013-12-25 06:13:41 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-01-23 16:29:47 -08:00
|
|
|
_eo_callbacks_clear(Eo *obj, Efl_Object_Data *pd)
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
2016-11-22 18:48:35 -08:00
|
|
|
Eo_Callback_Description **itr;
|
2016-08-31 17:15:35 -07:00
|
|
|
unsigned int i = 0;
|
eo: ensure the generation is correctly clamped
Summary:
when a few recursive event emissions are happening, and in some deep
recursive level a subscription to the same object is happening, the
subscription would just be executed when the complete recursion is done.
that is wrong. The subscription needs to be executed when the event is
called after the subscription is added, undepended from any recursive
level. That fixes that and adds a regression test for it.
This was discovered in e, since e gives a lot of error messages about a eo object
that is already freed. It turned out this object is returned from evas, and exactly
the above happened to the EFL_EVENT_DEL subscription of that object.
Test Plan: make check
Reviewers: tasn, cedric, stefan_schmidt
Subscribers: stefan_schmidt, netstar, zmike, raster, jpeg
Differential Revision: https://phab.enlightenment.org/D4656
Signed-off-by: Cedric BAIL <cedric@osg.samsung.com>
2017-02-16 13:37:16 -08:00
|
|
|
Eina_Bool remove_callbacks;
|
|
|
|
unsigned int generation_clamp;
|
2013-12-25 06:13:41 -08:00
|
|
|
|
|
|
|
/* If there are no deletions waiting. */
|
2016-12-01 03:40:36 -08:00
|
|
|
if (!pd->need_cleaning) return;
|
2013-12-25 06:13:41 -08:00
|
|
|
|
eo: ensure the generation is correctly clamped
Summary:
when a few recursive event emissions are happening, and in some deep
recursive level a subscription to the same object is happening, the
subscription would just be executed when the complete recursion is done.
that is wrong. The subscription needs to be executed when the event is
called after the subscription is added, undepended from any recursive
level. That fixes that and adds a regression test for it.
This was discovered in e, since e gives a lot of error messages about a eo object
that is already freed. It turned out this object is returned from evas, and exactly
the above happened to the EFL_EVENT_DEL subscription of that object.
Test Plan: make check
Reviewers: tasn, cedric, stefan_schmidt
Subscribers: stefan_schmidt, netstar, zmike, raster, jpeg
Differential Revision: https://phab.enlightenment.org/D4656
Signed-off-by: Cedric BAIL <cedric@osg.samsung.com>
2017-02-16 13:37:16 -08:00
|
|
|
|
|
|
|
if (pd->event_frame)
|
|
|
|
{
|
|
|
|
/* there is still a event emission going on ... do not delete anything! */
|
|
|
|
remove_callbacks = EINA_FALSE;
|
|
|
|
/* if we are in event subscription we need to clamp the generations at the current frame otherwise we are possiblity not executing that later */
|
|
|
|
generation_clamp = pd->event_frame->generation;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* no event emission running */
|
|
|
|
/* remove deleted callbacks */
|
|
|
|
remove_callbacks = EINA_TRUE;
|
|
|
|
/* clap to 0 generation */
|
|
|
|
generation_clamp = 0;
|
|
|
|
/* we dont need to clean later */
|
|
|
|
pd->need_cleaning = EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
2016-08-31 17:15:35 -07:00
|
|
|
while (i < pd->callbacks_count)
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
2016-08-31 17:15:35 -07:00
|
|
|
itr = pd->callbacks + i;
|
eo: ensure the generation is correctly clamped
Summary:
when a few recursive event emissions are happening, and in some deep
recursive level a subscription to the same object is happening, the
subscription would just be executed when the complete recursion is done.
that is wrong. The subscription needs to be executed when the event is
called after the subscription is added, undepended from any recursive
level. That fixes that and adds a regression test for it.
This was discovered in e, since e gives a lot of error messages about a eo object
that is already freed. It turned out this object is returned from evas, and exactly
the above happened to the EFL_EVENT_DEL subscription of that object.
Test Plan: make check
Reviewers: tasn, cedric, stefan_schmidt
Subscribers: stefan_schmidt, netstar, zmike, raster, jpeg
Differential Revision: https://phab.enlightenment.org/D4656
Signed-off-by: Cedric BAIL <cedric@osg.samsung.com>
2017-02-16 13:37:16 -08:00
|
|
|
if (remove_callbacks && (*itr)->delete_me)
|
|
|
|
{
|
2019-01-23 16:29:47 -08:00
|
|
|
_eo_callback_remove(obj, pd, itr);
|
eo: ensure the generation is correctly clamped
Summary:
when a few recursive event emissions are happening, and in some deep
recursive level a subscription to the same object is happening, the
subscription would just be executed when the complete recursion is done.
that is wrong. The subscription needs to be executed when the event is
called after the subscription is added, undepended from any recursive
level. That fixes that and adds a regression test for it.
This was discovered in e, since e gives a lot of error messages about a eo object
that is already freed. It turned out this object is returned from evas, and exactly
the above happened to the EFL_EVENT_DEL subscription of that object.
Test Plan: make check
Reviewers: tasn, cedric, stefan_schmidt
Subscribers: stefan_schmidt, netstar, zmike, raster, jpeg
Differential Revision: https://phab.enlightenment.org/D4656
Signed-off-by: Cedric BAIL <cedric@osg.samsung.com>
2017-02-16 13:37:16 -08:00
|
|
|
}
|
2016-12-01 03:40:36 -08:00
|
|
|
else
|
|
|
|
{
|
eo: ensure the generation is correctly clamped
Summary:
when a few recursive event emissions are happening, and in some deep
recursive level a subscription to the same object is happening, the
subscription would just be executed when the complete recursion is done.
that is wrong. The subscription needs to be executed when the event is
called after the subscription is added, undepended from any recursive
level. That fixes that and adds a regression test for it.
This was discovered in e, since e gives a lot of error messages about a eo object
that is already freed. It turned out this object is returned from evas, and exactly
the above happened to the EFL_EVENT_DEL subscription of that object.
Test Plan: make check
Reviewers: tasn, cedric, stefan_schmidt
Subscribers: stefan_schmidt, netstar, zmike, raster, jpeg
Differential Revision: https://phab.enlightenment.org/D4656
Signed-off-by: Cedric BAIL <cedric@osg.samsung.com>
2017-02-16 13:37:16 -08:00
|
|
|
if ((*itr)->generation > generation_clamp)
|
|
|
|
(*itr)->generation = generation_clamp;
|
2016-12-01 03:40:36 -08:00
|
|
|
i++;
|
|
|
|
}
|
2013-12-25 06:13:41 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-31 17:15:35 -07:00
|
|
|
static inline unsigned int
|
|
|
|
_eo_callback_search_sorted_near(const Efl_Object_Data *pd, const Eo_Callback_Description *look)
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
2016-08-31 17:15:35 -07:00
|
|
|
unsigned int start, last, middle;
|
2016-09-28 23:29:34 -07:00
|
|
|
const Eo_Callback_Description *p;
|
|
|
|
int cmp;
|
2016-08-28 23:36:48 -07:00
|
|
|
|
2016-11-22 18:48:35 -08:00
|
|
|
if (pd->callbacks_count == 0) return 0;
|
2016-09-28 23:29:34 -07:00
|
|
|
else if (pd->callbacks_count == 1) return 0;
|
2013-12-25 06:13:41 -08:00
|
|
|
|
2016-08-31 17:15:35 -07:00
|
|
|
start = 0;
|
|
|
|
last = pd->callbacks_count - 1;
|
|
|
|
do
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
2016-11-22 18:48:35 -08:00
|
|
|
middle = start + ((last - start) / 2);
|
2016-08-31 17:15:35 -07:00
|
|
|
p = pd->callbacks[middle];
|
|
|
|
|
|
|
|
cmp = p->priority - look->priority;
|
2016-11-22 18:48:35 -08:00
|
|
|
if (cmp == 0) return middle;
|
|
|
|
else if (cmp > 0) start = middle + 1;
|
|
|
|
else if (middle > 0) last = middle - 1;
|
2016-09-28 23:29:34 -07:00
|
|
|
else break;
|
2013-12-25 06:13:41 -08:00
|
|
|
}
|
2016-08-31 17:15:35 -07:00
|
|
|
while (start <= last);
|
|
|
|
return middle;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_eo_callbacks_sorted_insert(Efl_Object_Data *pd, Eo_Callback_Description *cb)
|
|
|
|
{
|
|
|
|
Eo_Callback_Description **itr;
|
|
|
|
unsigned int length, j;
|
2016-12-02 04:26:07 -08:00
|
|
|
Efl_Event_Callback_Frame *frame;
|
2016-08-31 17:15:35 -07:00
|
|
|
|
|
|
|
// Do a dichotomic searh
|
|
|
|
j = _eo_callback_search_sorted_near(pd, cb);
|
|
|
|
// Adjust for both case of length == 0 and when priority is equal.
|
2016-11-22 18:48:35 -08:00
|
|
|
while ((j < pd->callbacks_count) &&
|
|
|
|
(pd->callbacks[j]->priority >= cb->priority)) j++;
|
2016-08-31 17:15:35 -07:00
|
|
|
|
|
|
|
// Increase the callbacks storage by 16 entries at a time
|
2016-11-23 18:49:43 -08:00
|
|
|
if (_eo_nostep_alloc || (pd->callbacks_count & 0xF) == 0x0)
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
2016-08-31 17:15:35 -07:00
|
|
|
Eo_Callback_Description **tmp;
|
2016-09-05 08:22:33 -07:00
|
|
|
unsigned int new_len = (pd->callbacks_count | 0xF) + 1;
|
2016-08-31 17:15:35 -07:00
|
|
|
|
2016-11-23 18:49:43 -08:00
|
|
|
if (_eo_nostep_alloc) new_len = pd->callbacks_count + 1;
|
|
|
|
|
2016-11-22 18:48:35 -08:00
|
|
|
tmp = realloc(pd->callbacks,
|
|
|
|
new_len * sizeof(Eo_Callback_Description *));
|
2018-01-08 15:03:21 -08:00
|
|
|
if (EINA_UNLIKELY(!tmp)) return;
|
2016-08-31 17:15:35 -07:00
|
|
|
pd->callbacks = tmp;
|
2013-12-25 06:13:41 -08:00
|
|
|
}
|
2016-08-31 17:15:35 -07:00
|
|
|
|
|
|
|
// FIXME: Potential improvement, merge single callback description of the same priority
|
|
|
|
// into an array when possible
|
|
|
|
itr = pd->callbacks + j;
|
|
|
|
length = pd->callbacks_count - j;
|
2016-11-22 18:48:35 -08:00
|
|
|
if (length > 0) memmove(itr + 1, itr,
|
|
|
|
length * sizeof(Eo_Callback_Description *));
|
2016-08-31 17:15:35 -07:00
|
|
|
*itr = cb;
|
|
|
|
|
|
|
|
pd->callbacks_count++;
|
2016-11-30 04:07:51 -08:00
|
|
|
|
2016-12-02 04:26:07 -08:00
|
|
|
// Update possible event emissions
|
|
|
|
for (frame = pd->event_frame; frame; frame = frame->next)
|
|
|
|
{
|
2017-02-10 20:13:19 -08:00
|
|
|
if ((itr - pd->callbacks) < (ptrdiff_t)frame->idx)
|
|
|
|
frame->inserted_before++;
|
2016-12-02 04:26:07 -08:00
|
|
|
}
|
2013-12-25 06:13:41 -08:00
|
|
|
}
|
|
|
|
|
2018-01-08 15:03:21 -08:00
|
|
|
static unsigned short
|
2016-12-01 03:40:36 -08:00
|
|
|
_efl_event_generation(Efl_Object_Data *pd)
|
|
|
|
{
|
|
|
|
if (!pd->event_frame) return 0;
|
|
|
|
|
|
|
|
return ((Efl_Event_Callback_Frame*)pd->event_frame)->generation;
|
|
|
|
}
|
|
|
|
|
2016-01-27 11:42:48 -08:00
|
|
|
EOLIAN static Eina_Bool
|
2016-08-09 06:10:05 -07:00
|
|
|
_efl_object_event_callback_priority_add(Eo *obj, Efl_Object_Data *pd,
|
2016-09-28 23:29:34 -07:00
|
|
|
const Efl_Event_Description *desc,
|
|
|
|
Efl_Callback_Priority priority,
|
|
|
|
Efl_Event_Cb func,
|
|
|
|
const void *user_data)
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
2018-02-27 04:19:17 -08:00
|
|
|
const Efl_Callback_Array_Item_Full arr[] =
|
|
|
|
{ {desc, priority, func, (void *)user_data}, {NULL, 0, NULL, NULL}};
|
2016-08-28 23:36:48 -07:00
|
|
|
Eo_Callback_Description *cb = _eo_callback_new();
|
2019-10-18 09:24:47 -07:00
|
|
|
#ifdef EO_DEBUG
|
|
|
|
unsigned int idx, r = 0, entries = 0;
|
|
|
|
|
|
|
|
for (idx = pd->callbacks_count ; idx > 0; idx--)
|
|
|
|
{
|
|
|
|
Eo_Callback_Description **cb;
|
|
|
|
|
|
|
|
cb = pd->callbacks + idx - 1;
|
|
|
|
if (!(*cb)->func_array)
|
|
|
|
{
|
|
|
|
if (((*cb)->items.item.desc == desc) &&
|
|
|
|
((*cb)->items.item.func == func) &&
|
|
|
|
((*cb)->priority == priority) &&
|
|
|
|
((*cb)->generation == _efl_event_generation(pd)))
|
|
|
|
r++;
|
|
|
|
}
|
|
|
|
entries++;
|
|
|
|
}
|
|
|
|
if (r > 1) INF("Object '%s' got %i callback with event '%s' registered.",
|
|
|
|
efl_debug_name_get(obj), r, desc->name);
|
|
|
|
if (entries > 10) INF("Object '%s' got %i callbacks.",
|
|
|
|
efl_debug_name_get(obj), entries);
|
|
|
|
#endif
|
2013-12-25 06:13:41 -08:00
|
|
|
|
2016-09-28 23:29:34 -07:00
|
|
|
// very unlikely so improve l1 instr cache by using goto
|
2018-01-08 15:03:21 -08:00
|
|
|
if (EINA_UNLIKELY(!cb || !desc || !func)) goto err;
|
2013-12-25 06:13:41 -08:00
|
|
|
cb->items.item.desc = desc;
|
|
|
|
cb->items.item.func = func;
|
2016-11-22 18:48:35 -08:00
|
|
|
cb->func_data = (void *)user_data;
|
2013-12-25 06:13:41 -08:00
|
|
|
cb->priority = priority;
|
2016-12-01 03:40:36 -08:00
|
|
|
cb->generation = _efl_event_generation(pd);
|
2018-01-08 15:03:21 -08:00
|
|
|
if (cb->generation) pd->need_cleaning = EINA_TRUE;
|
2016-12-01 03:40:36 -08:00
|
|
|
|
2013-12-25 06:13:41 -08:00
|
|
|
_eo_callbacks_sorted_insert(pd, cb);
|
2019-01-23 16:29:47 -08:00
|
|
|
_special_event_count_inc(obj, pd, &(cb->items.item));
|
2013-12-25 06:13:41 -08:00
|
|
|
|
2016-08-09 06:10:05 -07:00
|
|
|
efl_event_callback_call(obj, EFL_EVENT_CALLBACK_ADD, (void *)arr);
|
2016-01-27 11:42:48 -08:00
|
|
|
|
|
|
|
return EINA_TRUE;
|
2016-09-28 23:29:34 -07:00
|
|
|
|
2018-01-08 15:03:21 -08:00
|
|
|
err: EINA_COLD
|
2017-12-04 23:31:14 -08:00
|
|
|
ERR("Tried adding callback with invalid values: cb: %p desc: %p func: %p", cb, desc, func);
|
2016-09-28 23:29:34 -07:00
|
|
|
_eo_callback_free(cb);
|
|
|
|
return EINA_FALSE;
|
2013-12-25 06:13:41 -08:00
|
|
|
}
|
|
|
|
|
2017-04-20 09:24:38 -07:00
|
|
|
EOAPI EFL_FUNC_BODYV(efl_event_callback_priority_add,
|
|
|
|
Eina_Bool, 0, EFL_FUNC_CALL(desc, priority, cb, data),
|
|
|
|
const Efl_Event_Description *desc,
|
|
|
|
Efl_Callback_Priority priority,
|
|
|
|
Efl_Event_Cb cb, const void *data);
|
|
|
|
|
2016-11-21 13:06:19 -08:00
|
|
|
static void
|
|
|
|
_efl_object_event_callback_clean(Eo *obj, Efl_Object_Data *pd,
|
2018-02-27 04:19:17 -08:00
|
|
|
const Efl_Callback_Array_Item_Full *array,
|
2016-11-21 13:06:19 -08:00
|
|
|
Eo_Callback_Description **cb)
|
|
|
|
{
|
|
|
|
(*cb)->delete_me = EINA_TRUE;
|
2016-11-30 04:07:51 -08:00
|
|
|
if (pd->event_frame)
|
2016-12-01 03:40:36 -08:00
|
|
|
pd->need_cleaning = EINA_TRUE;
|
2016-11-21 13:06:19 -08:00
|
|
|
else
|
2019-01-23 16:29:47 -08:00
|
|
|
_eo_callback_remove(obj, pd, cb);
|
2016-11-21 13:06:19 -08:00
|
|
|
|
|
|
|
efl_event_callback_call(obj, EFL_EVENT_CALLBACK_DEL, (void *)array);
|
|
|
|
}
|
|
|
|
|
2016-01-27 11:42:48 -08:00
|
|
|
EOLIAN static Eina_Bool
|
2016-08-09 06:10:05 -07:00
|
|
|
_efl_object_event_callback_del(Eo *obj, Efl_Object_Data *pd,
|
2016-11-22 18:48:35 -08:00
|
|
|
const Efl_Event_Description *desc,
|
|
|
|
Efl_Event_Cb func,
|
|
|
|
const void *user_data)
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
2016-08-31 17:15:35 -07:00
|
|
|
Eo_Callback_Description **cb;
|
|
|
|
unsigned int i;
|
2013-12-25 06:13:41 -08:00
|
|
|
|
2016-08-31 17:15:35 -07:00
|
|
|
for (cb = pd->callbacks, i = 0;
|
|
|
|
i < pd->callbacks_count;
|
|
|
|
cb++, i++)
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
2016-08-31 17:15:35 -07:00
|
|
|
if (!(*cb)->delete_me &&
|
|
|
|
((*cb)->items.item.desc == desc) &&
|
|
|
|
((*cb)->items.item.func == func) &&
|
|
|
|
((*cb)->func_data == user_data))
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
2018-02-27 04:19:17 -08:00
|
|
|
const Efl_Callback_Array_Item_Full arr[] =
|
|
|
|
{ {desc, (*cb)->priority, func, (*cb)->func_data}, {NULL, 0, NULL, NULL}};
|
2013-12-25 06:13:41 -08:00
|
|
|
|
2016-11-21 13:06:19 -08:00
|
|
|
_efl_object_event_callback_clean(obj, pd, arr, cb);
|
2016-01-27 11:42:48 -08:00
|
|
|
return EINA_TRUE;
|
2013-12-25 06:13:41 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DBG("Callback of object %p with function %p and data %p not found.", obj, func, user_data);
|
2016-01-27 11:42:48 -08:00
|
|
|
return EINA_FALSE;
|
2013-12-25 06:13:41 -08:00
|
|
|
}
|
|
|
|
|
2017-04-20 09:24:38 -07:00
|
|
|
EOAPI EFL_FUNC_BODYV(efl_event_callback_del,
|
|
|
|
Eina_Bool, 0, EFL_FUNC_CALL(desc, func, user_data),
|
|
|
|
const Efl_Event_Description *desc,
|
|
|
|
Efl_Event_Cb func, const void *user_data);
|
|
|
|
|
2016-01-27 11:42:48 -08:00
|
|
|
EOLIAN static Eina_Bool
|
2016-08-09 06:10:05 -07:00
|
|
|
_efl_object_event_callback_array_priority_add(Eo *obj, Efl_Object_Data *pd,
|
2016-09-28 23:29:34 -07:00
|
|
|
const Efl_Callback_Array_Item *array,
|
|
|
|
Efl_Callback_Priority priority,
|
|
|
|
const void *user_data)
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
2016-08-28 23:36:48 -07:00
|
|
|
Eo_Callback_Description *cb = _eo_callback_new();
|
2016-08-31 14:12:02 -07:00
|
|
|
const Efl_Callback_Array_Item *it;
|
2018-02-27 04:19:17 -08:00
|
|
|
unsigned int num, i;
|
|
|
|
Efl_Callback_Array_Item_Full *ev_array;
|
efl object events - track del, cb add and cb del callback counts
so hunting another callback issue i noticed some of THE most popular
callbacks are:
1411 tick
1961 move
4157 pointer,move
7524 dirty
8090 damage
13052 render,flush,post
13052 render,flush,pre
13205 render,post
13205 render,pre
21706 recalc
21875 idle
27224 resize
27779 del
31011 idle,enter
31011 idle,exit
60461 callback,del
104546 callback,add
126400 animator,tick
as you can see callback del, add and the general obj del cb's are
right up there... so it is very likely a good idea to CHECK to see if
anyone is listening before calling the callback for these very very
very common calls.
this is ifdef'd and turned on for now. it can be turned off. it
shouldnt use more memory due to the way memory alignment works (likely
all allocations will be multiples of 8 bytes anyway) so we're using
spare unused space. the only q is - is management of the counts AND
checking them worth it in general? it's really hard to tell given we
dont have a lot of benchmarks that cover a lot of use cases... it
doesnt seem to slow or speed anything up much in the genlist bounce
test... so i think i need something more specific.
@optimize
2016-11-17 01:32:18 -08:00
|
|
|
#ifdef EO_DEBUG
|
2016-08-31 14:12:02 -07:00
|
|
|
const Efl_Callback_Array_Item *prev;
|
2019-10-18 09:24:47 -07:00
|
|
|
unsigned int idx, r = 0, entries = 0;
|
2016-08-31 14:12:02 -07:00
|
|
|
#endif
|
2013-12-25 06:13:41 -08:00
|
|
|
|
2016-09-28 23:29:34 -07:00
|
|
|
// very unlikely so improve l1 instr cache by using goto
|
|
|
|
if (!cb || !array) goto err;
|
2016-08-31 14:12:02 -07:00
|
|
|
#ifdef EO_DEBUG
|
|
|
|
prev = array;
|
|
|
|
for (it = prev + 1; prev->func && it->func; it++, prev++)
|
|
|
|
{
|
|
|
|
if (efl_callbacks_cmp(prev, it) > 0)
|
|
|
|
{
|
|
|
|
ERR("Trying to insert a non sorted array callbacks (%p).", array);
|
|
|
|
_eo_callback_free(cb);
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-12-25 06:13:41 -08:00
|
|
|
cb->func_data = (void *) user_data;
|
|
|
|
cb->priority = priority;
|
|
|
|
cb->items.item_array = array;
|
|
|
|
cb->func_array = EINA_TRUE;
|
2016-12-01 03:40:36 -08:00
|
|
|
cb->generation = _efl_event_generation(pd);
|
|
|
|
if (!!cb->generation) pd->need_cleaning = EINA_TRUE;
|
|
|
|
|
2019-10-18 09:24:47 -07:00
|
|
|
#ifdef EO_DEBUG
|
|
|
|
for (idx = pd->callbacks_count ; idx > 0; idx--)
|
|
|
|
{
|
|
|
|
Eo_Callback_Description **cb;
|
|
|
|
|
|
|
|
cb = pd->callbacks + idx - 1;
|
|
|
|
if ((*cb)->func_array)
|
|
|
|
{
|
|
|
|
if (((*cb)->items.item_array == array) &&
|
|
|
|
((*cb)->priority == priority) &&
|
|
|
|
((*cb)->generation == _efl_event_generation(pd)))
|
|
|
|
r++;
|
|
|
|
}
|
|
|
|
entries++;
|
|
|
|
}
|
|
|
|
if (r > 1)
|
|
|
|
{
|
|
|
|
Eina_Strbuf *buf = eina_strbuf_new();
|
|
|
|
Eina_Bool first = EINA_TRUE;
|
|
|
|
|
|
|
|
for (it = array; it->func; it++)
|
|
|
|
{
|
|
|
|
if (first) eina_strbuf_append(buf, it->desc->name);
|
|
|
|
else eina_strbuf_append_printf(buf, ", %s", it->desc->name);
|
|
|
|
first = EINA_FALSE;
|
|
|
|
}
|
|
|
|
INF("Object '%s' got %i callback with events array %s registered.",
|
|
|
|
efl_debug_name_get(obj), r, eina_strbuf_string_get(buf));
|
|
|
|
eina_strbuf_free(buf);
|
|
|
|
}
|
|
|
|
if (entries > 10) INF("Object '%s' got %i callbacks.",
|
|
|
|
efl_debug_name_get(obj), entries);
|
|
|
|
#endif
|
|
|
|
|
2013-12-25 06:13:41 -08:00
|
|
|
_eo_callbacks_sorted_insert(pd, cb);
|
efl object events - track del, cb add and cb del callback counts
so hunting another callback issue i noticed some of THE most popular
callbacks are:
1411 tick
1961 move
4157 pointer,move
7524 dirty
8090 damage
13052 render,flush,post
13052 render,flush,pre
13205 render,post
13205 render,pre
21706 recalc
21875 idle
27224 resize
27779 del
31011 idle,enter
31011 idle,exit
60461 callback,del
104546 callback,add
126400 animator,tick
as you can see callback del, add and the general obj del cb's are
right up there... so it is very likely a good idea to CHECK to see if
anyone is listening before calling the callback for these very very
very common calls.
this is ifdef'd and turned on for now. it can be turned off. it
shouldnt use more memory due to the way memory alignment works (likely
all allocations will be multiples of 8 bytes anyway) so we're using
spare unused space. the only q is - is management of the counts AND
checking them worth it in general? it's really hard to tell given we
dont have a lot of benchmarks that cover a lot of use cases... it
doesnt seem to slow or speed anything up much in the genlist bounce
test... so i think i need something more specific.
@optimize
2016-11-17 01:32:18 -08:00
|
|
|
for (it = cb->items.item_array; it->func; it++)
|
2019-01-23 16:29:47 -08:00
|
|
|
_special_event_count_inc(obj, pd, it);
|
2013-12-25 06:13:41 -08:00
|
|
|
|
2018-02-27 04:19:17 -08:00
|
|
|
num = 0;
|
|
|
|
for (it = cb->items.item_array; it->func; it++) num++;
|
|
|
|
ev_array = alloca((num + 1) * sizeof(Efl_Callback_Array_Item_Full));
|
|
|
|
for (i = 0, it = cb->items.item_array; it->func; it++, i++)
|
|
|
|
{
|
|
|
|
ev_array[i].desc = cb->items.item_array[i].desc;
|
|
|
|
ev_array[i].priority = cb->priority;
|
|
|
|
ev_array[i].func = cb->items.item_array[i].func;
|
|
|
|
ev_array[i].user_data = cb->func_data;
|
|
|
|
}
|
|
|
|
ev_array[i].desc = NULL;
|
|
|
|
ev_array[i].priority = 0;
|
|
|
|
ev_array[i].func = NULL;
|
|
|
|
ev_array[i].user_data = NULL;
|
|
|
|
efl_event_callback_call(obj, EFL_EVENT_CALLBACK_ADD, ev_array);
|
2016-01-27 11:42:48 -08:00
|
|
|
|
|
|
|
return EINA_TRUE;
|
2016-09-28 23:29:34 -07:00
|
|
|
|
|
|
|
err:
|
|
|
|
ERR("Tried adding array of callbacks with invalid values: cb: %p array: %p.", cb, array);
|
|
|
|
_eo_callback_free(cb);
|
|
|
|
return EINA_FALSE;
|
2013-12-25 06:13:41 -08:00
|
|
|
}
|
|
|
|
|
2017-04-20 09:24:38 -07:00
|
|
|
EOAPI EFL_FUNC_BODYV(efl_event_callback_array_priority_add,
|
|
|
|
Eina_Bool, 0, EFL_FUNC_CALL(array, priority, data),
|
|
|
|
const Efl_Callback_Array_Item *array,
|
|
|
|
Efl_Callback_Priority priority, const void *data);
|
|
|
|
|
2016-01-27 11:42:48 -08:00
|
|
|
EOLIAN static Eina_Bool
|
2016-08-09 06:10:05 -07:00
|
|
|
_efl_object_event_callback_array_del(Eo *obj, Efl_Object_Data *pd,
|
2016-09-28 23:29:34 -07:00
|
|
|
const Efl_Callback_Array_Item *array,
|
|
|
|
const void *user_data)
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
2016-08-31 17:15:35 -07:00
|
|
|
Eo_Callback_Description **cb;
|
2018-02-27 04:19:17 -08:00
|
|
|
unsigned int j;
|
2013-12-25 06:13:41 -08:00
|
|
|
|
2018-02-27 04:19:17 -08:00
|
|
|
for (cb = pd->callbacks, j = 0;
|
|
|
|
j < pd->callbacks_count;
|
|
|
|
cb++, j++)
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
2016-08-31 17:15:35 -07:00
|
|
|
if (!(*cb)->delete_me &&
|
|
|
|
((*cb)->items.item_array == array) &&
|
|
|
|
((*cb)->func_data == user_data))
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
2018-02-27 04:19:17 -08:00
|
|
|
const Efl_Callback_Array_Item *it;
|
|
|
|
unsigned int num, i;
|
|
|
|
Efl_Callback_Array_Item_Full *ev_array;
|
|
|
|
|
|
|
|
num = 0;
|
|
|
|
for (it = (*cb)->items.item_array; it->func; it++) num++;
|
|
|
|
ev_array = alloca((num + 1) * sizeof(Efl_Callback_Array_Item_Full));
|
|
|
|
for (i = 0, it = (*cb)->items.item_array; it->func; it++, i++)
|
|
|
|
{
|
|
|
|
ev_array[i].desc = (*cb)->items.item_array[i].desc;
|
|
|
|
ev_array[i].priority = (*cb)->priority;
|
|
|
|
ev_array[i].func = (*cb)->items.item_array[i].func;
|
|
|
|
ev_array[i].user_data = (*cb)->func_data;
|
|
|
|
}
|
|
|
|
ev_array[i].desc = NULL;
|
|
|
|
ev_array[i].priority = 0;
|
|
|
|
ev_array[i].func = NULL;
|
|
|
|
ev_array[i].user_data = NULL;
|
|
|
|
_efl_object_event_callback_clean(obj, pd, ev_array, cb);
|
2016-01-27 11:42:48 -08:00
|
|
|
return EINA_TRUE;
|
2013-12-25 06:13:41 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DBG("Callback of object %p with function array %p and data %p not found.", obj, array, user_data);
|
2016-01-27 11:42:48 -08:00
|
|
|
return EINA_FALSE;
|
2013-12-25 06:13:41 -08:00
|
|
|
}
|
|
|
|
|
2017-04-20 09:24:38 -07:00
|
|
|
EOAPI EFL_FUNC_BODYV(efl_event_callback_array_del,
|
|
|
|
Eina_Bool, 0, EFL_FUNC_CALL(array, user_data),
|
|
|
|
const Efl_Callback_Array_Item *array,
|
|
|
|
const void *user_data);
|
|
|
|
|
2019-10-16 16:47:10 -07:00
|
|
|
typedef struct _Efl_Future_Scheduler Efl_Future_Scheduler;
|
|
|
|
typedef struct _Efl_Future_Scheduler_Entry Efl_Future_Scheduler_Entry;
|
|
|
|
|
|
|
|
struct _Efl_Future_Scheduler
|
|
|
|
{
|
|
|
|
Eina_Future_Scheduler scheduler;
|
|
|
|
|
|
|
|
const Efl_Callback_Array_Item *array;
|
|
|
|
const Eo *self;
|
|
|
|
|
|
|
|
Eina_List *futures;
|
|
|
|
|
|
|
|
Eina_Bool listener : 1;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct _Efl_Future_Scheduler_Entry
|
|
|
|
{
|
|
|
|
Eina_Future_Schedule_Entry base;
|
|
|
|
Eina_Future_Scheduler_Cb cb;
|
|
|
|
Eina_Future *future;
|
|
|
|
Eina_Value value;
|
|
|
|
};
|
|
|
|
|
|
|
|
static Eina_Trash *schedulers_trash = NULL;
|
|
|
|
static unsigned char schedulers_count = 0;
|
|
|
|
|
|
|
|
static void
|
|
|
|
_future_scheduler_cleanup(Efl_Object_Data *pd)
|
|
|
|
{
|
|
|
|
if (eina_hash_population(pd->ext->schedulers)) return ;
|
|
|
|
|
|
|
|
eina_hash_free(pd->ext->schedulers);
|
|
|
|
pd->ext->schedulers = NULL;
|
|
|
|
_efl_object_extension_noneed(pd);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_futures_dispatch_cb(void *data, const Efl_Event *ev EINA_UNUSED)
|
|
|
|
{
|
|
|
|
Efl_Future_Scheduler *sched = data;
|
|
|
|
Eina_List *entries = sched->futures;
|
|
|
|
Efl_Future_Scheduler_Entry *entry;
|
|
|
|
|
|
|
|
sched->futures = NULL;
|
|
|
|
|
|
|
|
efl_event_callback_array_del((Eo *) sched->self, sched->array, sched);
|
|
|
|
sched->listener = EINA_FALSE;
|
|
|
|
|
|
|
|
// Now trigger callbacks
|
|
|
|
EINA_LIST_FREE(entries, entry)
|
|
|
|
{
|
|
|
|
entry->cb(entry->future, entry->value);
|
|
|
|
eina_mempool_free(_efl_future_scheduler_entry_mempool, entry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_futures_cancel_cb(void *data)
|
|
|
|
{
|
|
|
|
Efl_Future_Scheduler *sched = data;
|
|
|
|
Eina_List *entries = sched->futures;
|
|
|
|
Efl_Future_Scheduler_Entry *entry;
|
|
|
|
|
|
|
|
efl_event_callback_array_del((Eo *) sched->self, sched->array, sched);
|
|
|
|
sched->listener = EINA_FALSE;
|
|
|
|
sched->futures = NULL;
|
|
|
|
|
|
|
|
EINA_LIST_FREE(entries, entry)
|
|
|
|
{
|
|
|
|
eina_future_cancel(entry->future);
|
|
|
|
eina_value_flush(&entry->value);
|
|
|
|
eina_mempool_free(_efl_future_scheduler_entry_mempool, entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (schedulers_count > 8)
|
|
|
|
{
|
|
|
|
free(sched);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
eina_trash_push(&schedulers_trash, sched);
|
|
|
|
schedulers_count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static Eina_Future_Schedule_Entry *
|
|
|
|
_efl_event_future_scheduler(Eina_Future_Scheduler *s_sched,
|
|
|
|
Eina_Future_Scheduler_Cb cb,
|
|
|
|
Eina_Future *future,
|
|
|
|
Eina_Value value)
|
|
|
|
{
|
|
|
|
Efl_Future_Scheduler *sched = (Efl_Future_Scheduler *)s_sched;
|
|
|
|
Efl_Future_Scheduler_Entry *entry;
|
|
|
|
|
|
|
|
entry = eina_mempool_malloc(_efl_future_scheduler_entry_mempool, sizeof(*entry));
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(entry, NULL);
|
|
|
|
|
|
|
|
entry->base.scheduler = &sched->scheduler;
|
|
|
|
entry->cb = cb;
|
|
|
|
entry->future = future;
|
|
|
|
entry->value = value;
|
|
|
|
|
|
|
|
if (!sched->listener)
|
|
|
|
{
|
|
|
|
efl_event_callback_array_add((Eo *) sched->self, sched->array, sched);
|
|
|
|
sched->listener = EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
sched->futures = eina_list_append(sched->futures, entry);
|
|
|
|
return &entry->base;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_efl_event_future_recall(Eina_Future_Schedule_Entry *s_entry)
|
|
|
|
{
|
|
|
|
Efl_Future_Scheduler_Entry *entry = (Efl_Future_Scheduler_Entry *)s_entry;
|
|
|
|
Efl_Future_Scheduler *sched;
|
|
|
|
Eina_List *lookup;
|
|
|
|
|
|
|
|
sched = (Efl_Future_Scheduler *) entry->base.scheduler;
|
|
|
|
|
|
|
|
lookup = eina_list_data_find_list(sched->futures, entry);
|
|
|
|
if (!lookup) return;
|
|
|
|
|
|
|
|
sched->futures = eina_list_remove_list(sched->futures, lookup);
|
|
|
|
if (!sched->futures)
|
|
|
|
{
|
|
|
|
Efl_Object_Data *pd = efl_data_scope_get(sched->self, EFL_OBJECT_CLASS);
|
|
|
|
|
|
|
|
_future_scheduler_cleanup(pd);
|
|
|
|
}
|
|
|
|
|
|
|
|
eina_value_flush(&entry->value);
|
|
|
|
eina_mempool_free(_efl_future_scheduler_entry_mempool, entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
EOLIAN static Eina_Future_Scheduler *
|
|
|
|
_efl_object_event_future_scheduler_get(const Eo *obj, Efl_Object_Data *pd, Efl_Callback_Array_Item *array)
|
|
|
|
{
|
|
|
|
Efl_Object_Extension *ext;
|
|
|
|
Efl_Future_Scheduler *sched;
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
if (!array) return NULL;
|
|
|
|
|
|
|
|
ext = _efl_object_extension_need(pd);
|
|
|
|
|
|
|
|
// First lookup for an existing scheduler that match the provided array
|
|
|
|
if (!ext->schedulers) ext->schedulers = eina_hash_pointer_new(_futures_cancel_cb);
|
|
|
|
sched = eina_hash_find(ext->schedulers, &array);
|
|
|
|
if (sched) return &sched->scheduler;
|
|
|
|
|
|
|
|
// Define all the callback in the array to point to our internal callback,
|
|
|
|
// making the array ready to use.
|
|
|
|
for (i = 0; array[i].desc; i++)
|
|
|
|
array[i].func = _futures_dispatch_cb;
|
|
|
|
|
|
|
|
if (schedulers_count)
|
|
|
|
{
|
|
|
|
// Take one out of the trash for faster cycling
|
|
|
|
sched = eina_trash_pop(&schedulers_trash);
|
|
|
|
schedulers_count--;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Need to allocate a new scheduler as none are on standby.
|
|
|
|
sched = calloc(1, sizeof (Efl_Future_Scheduler));
|
|
|
|
}
|
|
|
|
sched->scheduler.schedule = _efl_event_future_scheduler;
|
|
|
|
sched->scheduler.recall = _efl_event_future_recall;
|
|
|
|
sched->array = array;
|
|
|
|
sched->self = obj;
|
|
|
|
|
|
|
|
eina_hash_add(ext->schedulers, &array, sched);
|
|
|
|
|
|
|
|
return &sched->scheduler;
|
|
|
|
}
|
|
|
|
|
|
|
|
EOAPI EFL_FUNC_BODYV_CONST(efl_event_future_scheduler_get,
|
|
|
|
Eina_Future_Scheduler *, 0, EFL_FUNC_CALL(array),
|
|
|
|
Efl_Callback_Array_Item *array);
|
|
|
|
|
2019-10-17 12:09:14 -07:00
|
|
|
EOAPI unsigned int
|
|
|
|
_efl_object_event_callback_count(const Eo *obj EINA_UNUSED,
|
|
|
|
Efl_Object_Data *pd,
|
|
|
|
const Efl_Event_Description *desc)
|
|
|
|
{
|
|
|
|
unsigned int r = 0;
|
|
|
|
unsigned int idx;
|
|
|
|
|
|
|
|
for (idx = pd->callbacks_count ; idx > 0; idx--)
|
|
|
|
{
|
|
|
|
Eo_Callback_Description **cb;
|
|
|
|
|
|
|
|
cb = pd->callbacks + idx - 1;
|
|
|
|
|
|
|
|
if ((*cb)->func_array)
|
|
|
|
{
|
|
|
|
const Efl_Callback_Array_Item *it;
|
|
|
|
|
|
|
|
for (it = (*cb)->items.item_array; it->func; it++)
|
|
|
|
{
|
|
|
|
if (it->desc > desc) break;
|
|
|
|
if (it->desc == desc) r++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ((*cb)->items.item.desc == desc) r++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
EOAPI EFL_FUNC_BODYV_CONST(efl_event_callback_count,
|
|
|
|
unsigned int, 0, EFL_FUNC_CALL(desc),
|
|
|
|
const Efl_Event_Description *desc);
|
|
|
|
|
2014-05-19 07:28:49 -07:00
|
|
|
static Eina_Bool
|
2016-08-22 15:40:39 -07:00
|
|
|
_cb_desc_match(const Efl_Event_Description *a, const Efl_Event_Description *b, Eina_Bool legacy_compare)
|
2014-05-19 07:28:49 -07:00
|
|
|
{
|
2015-10-15 04:04:05 -07:00
|
|
|
/* If one is legacy and the other is not, strcmp. Else, pointer compare. */
|
2016-09-28 23:29:34 -07:00
|
|
|
if (!EINA_UNLIKELY(legacy_compare && (_legacy_event_desc_is(a) != _legacy_event_desc_is(b))))
|
|
|
|
return (a == b);
|
|
|
|
return !strcmp(a->name, b->name);
|
2014-05-19 07:28:49 -07:00
|
|
|
}
|
|
|
|
|
2019-11-13 16:01:55 -08:00
|
|
|
#define EFL_OBJECT_EVENT_CALLBACK_BLOCK(Pd, Desc, Event, Need_Hash) \
|
|
|
|
if (Desc == Event) \
|
|
|
|
{ \
|
|
|
|
if (!(Pd->event_cb_##Event)) return EINA_TRUE; \
|
|
|
|
Need_Hash = EINA_FALSE; \
|
|
|
|
} \
|
2019-10-17 12:09:14 -07:00
|
|
|
|
2016-08-22 15:40:39 -07:00
|
|
|
static inline Eina_Bool
|
|
|
|
_event_callback_call(Eo *obj_id, Efl_Object_Data *pd,
|
2016-09-28 23:29:34 -07:00
|
|
|
const Efl_Event_Description *desc,
|
|
|
|
void *event_info,
|
|
|
|
Eina_Bool legacy_compare)
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
2016-08-31 17:15:35 -07:00
|
|
|
Eo_Callback_Description **cb;
|
2016-11-16 23:49:52 -08:00
|
|
|
Eo_Current_Callback_Description *lookup, saved;
|
2016-08-30 05:34:10 -07:00
|
|
|
Efl_Event ev;
|
2016-08-31 17:15:35 -07:00
|
|
|
unsigned int idx;
|
2016-11-16 23:49:52 -08:00
|
|
|
Eina_Bool callback_already_stopped, ret;
|
2018-01-08 15:03:21 -08:00
|
|
|
Efl_Event_Callback_Frame frame = {
|
|
|
|
.next = NULL,
|
|
|
|
.idx = 0,
|
|
|
|
.inserted_before = 0,
|
|
|
|
.generation = 1,
|
|
|
|
};
|
2019-11-13 16:01:55 -08:00
|
|
|
Eina_Bool need_hash = EINA_TRUE;
|
2016-11-16 23:49:52 -08:00
|
|
|
|
2019-11-07 10:58:04 -08:00
|
|
|
if (pd->callbacks_count == 0) return EINA_TRUE;
|
2019-11-13 16:01:55 -08:00
|
|
|
else EFL_OBJECT_EVENT_CALLBACK_BLOCK(pd, desc, EFL_EVENT_CALLBACK_ADD, need_hash)
|
|
|
|
else EFL_OBJECT_EVENT_CALLBACK_BLOCK(pd, desc, EFL_EVENT_CALLBACK_DEL, need_hash)
|
|
|
|
else EFL_OBJECT_EVENT_CALLBACK_BLOCK(pd, desc, EFL_EVENT_DEL, need_hash)
|
|
|
|
else EFL_OBJECT_EVENT_CALLBACK_BLOCK(pd, desc, EFL_EVENT_INVALIDATE, need_hash)
|
|
|
|
else EFL_OBJECT_EVENT_CALLBACK_BLOCK(pd, desc, EFL_EVENT_NOREF, need_hash)
|
|
|
|
else EFL_OBJECT_EVENT_CALLBACK_BLOCK(pd, desc, EFL_EVENT_DESTRUCT, need_hash)
|
2016-11-16 23:49:52 -08:00
|
|
|
|
2019-11-13 16:01:55 -08:00
|
|
|
if (EINA_LIKELY(!legacy_compare && need_hash))
|
2019-10-15 17:04:32 -07:00
|
|
|
{
|
2019-11-13 16:01:55 -08:00
|
|
|
unsigned char event_hash;
|
|
|
|
|
2019-10-15 17:04:32 -07:00
|
|
|
event_hash = _pointer_hash((uintptr_t) desc);
|
eo: fix UB in the eo event code (edje_cc hangs etc.)
Today I started experiencing mysterious hanging of edje_cc
during build. "The French are at it again" I thought, and
after spending a while bisecting, I found the culprit.
It's 7f53d9158395504151e1ff3dcae715a799d913a8.
So, what is happening in here?
The idea here was fundamentally sound; compute a special
hash value for event descriptors, taking range between 0
and 63 (on 64-bit systems) and 0 and 31 (on 32-bit systems),
then use a mask sized 32-bit or 64-bit (depending on your
system) and check early if to bail out from callback_call,
saving some resources. So far so good.
The problem is in the way the mask is handled. We're applying
the hash as the shift value like, `x |= (1 << hash)`. On 32-bit
systems this is okay, but on 64-bit systems, C's dumb silent
coercion rules kick in, since the left side of the expression
is 1, a literal with type signed int; that means our shifting
range is limited to 31 and what we get is... undefined behavior.
This is obviously not what we want, so take a 1ULL value as a
base. The previous thing seemingly worked on x86_64 (nobody
reported any issues) and interestingly it worked for me too
for a while (on ppc64le), but undefined behavior can be
unpredictable, so...
This shouldn't need a commit message as long as this, but I'm
making it proportional to the amount of time I wasted on this.
2019-11-13 19:02:09 -08:00
|
|
|
if (!(pd->callbacks_mask & (1ULL << event_hash)))
|
2019-11-07 10:58:04 -08:00
|
|
|
return EINA_TRUE;
|
2019-10-15 17:04:32 -07:00
|
|
|
}
|
|
|
|
|
2016-12-02 02:31:45 -08:00
|
|
|
if (pd->event_frame)
|
|
|
|
frame.generation = ((Efl_Event_Callback_Frame*)pd->event_frame)->generation + 1;
|
|
|
|
|
2016-11-30 04:07:51 -08:00
|
|
|
EVENT_STACK_PUSH(pd, &frame);
|
|
|
|
|
2016-11-16 23:49:52 -08:00
|
|
|
lookup = NULL;
|
|
|
|
callback_already_stopped = pd->callback_stopped;
|
2018-12-19 11:57:38 -08:00
|
|
|
pd->callback_stopped = EINA_FALSE;
|
2016-11-16 23:49:52 -08:00
|
|
|
ret = EINA_TRUE;
|
2016-04-20 15:50:46 -07:00
|
|
|
|
2016-05-18 08:17:36 -07:00
|
|
|
ev.object = obj_id;
|
2016-02-29 01:12:35 -08:00
|
|
|
ev.desc = desc;
|
2016-04-12 07:23:55 -07:00
|
|
|
ev.info = event_info;
|
2013-12-25 06:13:41 -08:00
|
|
|
|
2016-04-20 15:50:46 -07:00
|
|
|
// Handle event that require to restart where we were in the nested list walking
|
2016-09-28 23:29:34 -07:00
|
|
|
// relatively unlikely so improve l1 instr cache by using goto
|
|
|
|
if (desc->restart) goto restart;
|
|
|
|
else idx = pd->callbacks_count;
|
|
|
|
restart_back:
|
2016-04-20 15:50:46 -07:00
|
|
|
|
2016-08-31 17:15:35 -07:00
|
|
|
for (; idx > 0; idx--)
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
2016-11-30 04:07:51 -08:00
|
|
|
frame.idx = idx;
|
2016-08-31 17:15:35 -07:00
|
|
|
cb = pd->callbacks + idx - 1;
|
|
|
|
if (!(*cb)->delete_me)
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
2016-12-01 03:40:36 -08:00
|
|
|
if ((*cb)->generation >= frame.generation)
|
|
|
|
continue;
|
|
|
|
|
2016-08-31 17:15:35 -07:00
|
|
|
if ((*cb)->func_array)
|
2015-11-09 06:06:39 -08:00
|
|
|
{
|
2016-08-09 06:10:05 -07:00
|
|
|
const Efl_Callback_Array_Item *it;
|
2013-12-25 06:13:41 -08:00
|
|
|
|
2016-08-31 17:15:35 -07:00
|
|
|
for (it = (*cb)->items.item_array; it->func; it++)
|
2015-11-09 06:06:39 -08:00
|
|
|
{
|
2016-08-31 14:12:02 -07:00
|
|
|
// Array callbacks are sorted, break if we are getting to high.
|
|
|
|
if (!legacy_compare &&
|
2017-05-04 11:22:06 -07:00
|
|
|
((const unsigned char *) desc < (const unsigned char *) it->desc))
|
2016-08-31 14:12:02 -07:00
|
|
|
break;
|
2016-08-22 15:40:39 -07:00
|
|
|
if (!_cb_desc_match(it->desc, desc, legacy_compare))
|
2015-11-09 06:06:39 -08:00
|
|
|
continue;
|
|
|
|
if (!it->desc->unfreezable &&
|
|
|
|
(event_freeze_count || pd->event_freeze_count))
|
|
|
|
continue;
|
|
|
|
|
2016-04-20 15:50:46 -07:00
|
|
|
// Handle nested restart of walking list
|
2016-08-31 17:15:35 -07:00
|
|
|
if (lookup) lookup->current = idx - 1;
|
2019-11-07 10:58:04 -08:00
|
|
|
|
2016-08-31 17:15:35 -07:00
|
|
|
it->func((void *) (*cb)->func_data, &ev);
|
2015-11-09 06:06:39 -08:00
|
|
|
/* Abort callback calling if the func says so. */
|
2016-06-20 02:37:02 -07:00
|
|
|
if (pd->callback_stopped)
|
2015-11-09 06:06:39 -08:00
|
|
|
{
|
|
|
|
ret = EINA_FALSE;
|
|
|
|
goto end;
|
|
|
|
}
|
2016-04-20 15:50:46 -07:00
|
|
|
// We have actually walked this list during a nested call
|
|
|
|
if (lookup &&
|
2016-08-31 17:15:35 -07:00
|
|
|
lookup->current == 0)
|
2016-04-20 15:50:46 -07:00
|
|
|
goto end;
|
2015-11-09 06:06:39 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
2016-08-31 17:15:35 -07:00
|
|
|
if (!_cb_desc_match((*cb)->items.item.desc, desc, legacy_compare))
|
2015-11-09 06:06:39 -08:00
|
|
|
continue;
|
2016-08-31 17:15:35 -07:00
|
|
|
if (!(*cb)->items.item.desc->unfreezable &&
|
2015-11-09 06:06:39 -08:00
|
|
|
(event_freeze_count || pd->event_freeze_count))
|
2013-12-25 06:13:41 -08:00
|
|
|
continue;
|
|
|
|
|
2016-04-20 15:50:46 -07:00
|
|
|
// Handle nested restart of walking list
|
2016-08-31 17:15:35 -07:00
|
|
|
if (lookup) lookup->current = idx - 1;
|
2019-11-07 10:58:04 -08:00
|
|
|
|
2016-08-31 17:15:35 -07:00
|
|
|
(*cb)->items.item.func((void *) (*cb)->func_data, &ev);
|
2013-12-25 06:13:41 -08:00
|
|
|
/* Abort callback calling if the func says so. */
|
2016-06-20 02:37:02 -07:00
|
|
|
if (pd->callback_stopped)
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
|
|
|
ret = EINA_FALSE;
|
|
|
|
goto end;
|
|
|
|
}
|
2016-04-20 15:50:46 -07:00
|
|
|
// We have actually walked this list during a nested call
|
|
|
|
if (lookup &&
|
2016-08-31 17:15:35 -07:00
|
|
|
lookup->current == 0)
|
2016-04-20 15:50:46 -07:00
|
|
|
goto end;
|
2013-12-25 06:13:41 -08:00
|
|
|
}
|
|
|
|
}
|
2016-11-30 04:07:51 -08:00
|
|
|
idx += frame.inserted_before;
|
|
|
|
frame.inserted_before = 0;
|
2013-12-25 06:13:41 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
end:
|
2016-04-20 15:50:46 -07:00
|
|
|
// Handling restarting list walking complete exit.
|
2016-08-31 17:15:35 -07:00
|
|
|
if (lookup) lookup->current = 0;
|
2016-04-20 15:50:46 -07:00
|
|
|
if (lookup == &saved)
|
|
|
|
{
|
|
|
|
pd->current = eina_inlist_remove(pd->current, EINA_INLIST_GET(lookup));
|
|
|
|
}
|
|
|
|
|
2016-11-30 04:07:51 -08:00
|
|
|
EVENT_STACK_POP(pd);
|
|
|
|
|
2019-01-23 16:29:47 -08:00
|
|
|
_eo_callbacks_clear(obj_id, pd);
|
2013-12-25 06:13:41 -08:00
|
|
|
|
2016-06-20 02:37:02 -07:00
|
|
|
pd->callback_stopped = callback_already_stopped;
|
|
|
|
|
2013-12-25 06:13:41 -08:00
|
|
|
return ret;
|
2016-09-28 23:29:34 -07:00
|
|
|
restart:
|
|
|
|
EINA_INLIST_FOREACH(pd->current, lookup)
|
|
|
|
{
|
|
|
|
if (lookup->desc == desc) break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is the first event to trigger it, so register it here
|
|
|
|
if (!lookup)
|
|
|
|
{
|
|
|
|
// This following trick get us a zero allocation list
|
|
|
|
saved.desc = desc;
|
|
|
|
saved.current = 0;
|
|
|
|
lookup = &saved;
|
|
|
|
// Ideally there will most of the time be only one item in this list
|
|
|
|
// But just to speed up things, prepend so we find it fast at the end
|
|
|
|
// of this function
|
|
|
|
pd->current = eina_inlist_prepend(pd->current, EINA_INLIST_GET(lookup));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!lookup->current) lookup->current = pd->callbacks_count;
|
|
|
|
idx = lookup->current;
|
|
|
|
goto restart_back;
|
2013-12-25 06:13:41 -08:00
|
|
|
}
|
|
|
|
|
2016-08-22 15:40:39 -07:00
|
|
|
EOLIAN static Eina_Bool
|
|
|
|
_efl_object_event_callback_call(Eo *obj_id, Efl_Object_Data *pd,
|
|
|
|
const Efl_Event_Description *desc,
|
|
|
|
void *event_info)
|
|
|
|
{
|
|
|
|
return _event_callback_call(obj_id, pd, desc, event_info, EINA_FALSE);
|
|
|
|
}
|
|
|
|
|
2017-04-20 09:24:38 -07:00
|
|
|
EOAPI EFL_FUNC_BODYV(efl_event_callback_call,
|
|
|
|
Eina_Bool, 0, EFL_FUNC_CALL(desc, event_info),
|
|
|
|
const Efl_Event_Description *desc, void *event_info);
|
|
|
|
|
2016-08-22 15:40:39 -07:00
|
|
|
EOLIAN static Eina_Bool
|
|
|
|
_efl_object_event_callback_legacy_call(Eo *obj_id, Efl_Object_Data *pd,
|
|
|
|
const Efl_Event_Description *desc,
|
|
|
|
void *event_info)
|
|
|
|
{
|
|
|
|
return _event_callback_call(obj_id, pd, desc, event_info, EINA_TRUE);
|
|
|
|
}
|
|
|
|
|
2017-04-20 09:24:38 -07:00
|
|
|
EOAPI EFL_FUNC_BODYV(efl_event_callback_legacy_call,
|
|
|
|
Eina_Bool, 0, EFL_FUNC_CALL(desc, event_info),
|
|
|
|
const Efl_Event_Description *desc, void *event_info);
|
|
|
|
|
2016-06-20 02:37:02 -07:00
|
|
|
EOLIAN static void
|
2016-08-09 06:10:05 -07:00
|
|
|
_efl_object_event_callback_stop(Eo *obj EINA_UNUSED, Efl_Object_Data *pd)
|
2016-06-20 02:37:02 -07:00
|
|
|
{
|
|
|
|
pd->callback_stopped = EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2016-08-30 05:34:10 -07:00
|
|
|
_efl_event_forwarder_callback(void *data, const Efl_Event *event)
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
|
|
|
Eo *new_obj = (Eo *) data;
|
2013-07-25 17:34:46 -07:00
|
|
|
Eina_Bool ret = EINA_FALSE;
|
2013-12-25 06:13:41 -08:00
|
|
|
|
2016-08-09 06:10:05 -07:00
|
|
|
ret = efl_event_callback_call(new_obj, event->desc, event->info);
|
2016-06-20 02:37:02 -07:00
|
|
|
if (!ret)
|
|
|
|
{
|
2016-08-09 06:10:05 -07:00
|
|
|
efl_event_callback_stop(event->object);
|
2016-06-20 02:37:02 -07:00
|
|
|
}
|
2013-12-25 06:13:41 -08:00
|
|
|
}
|
|
|
|
|
2014-06-03 03:23:53 -07:00
|
|
|
EOLIAN static void
|
2018-12-12 14:07:52 -08:00
|
|
|
_efl_object_event_callback_forwarder_priority_add(Eo *obj, Efl_Object_Data *pd EINA_UNUSED,
|
|
|
|
const Efl_Event_Description *desc,
|
|
|
|
short priority,
|
|
|
|
Eo *new_obj)
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
2018-12-12 14:07:52 -08:00
|
|
|
EO_OBJ_POINTER_RETURN(new_obj, new_data);
|
|
|
|
EO_OBJ_DONE(new_obj);
|
2013-12-25 06:13:41 -08:00
|
|
|
|
2018-12-12 14:07:52 -08:00
|
|
|
efl_event_callback_priority_add(obj, desc, priority, _efl_event_forwarder_callback, new_obj);
|
2013-12-25 06:13:41 -08:00
|
|
|
}
|
|
|
|
|
2014-06-03 03:23:53 -07:00
|
|
|
EOLIAN static void
|
2016-08-09 06:10:05 -07:00
|
|
|
_efl_object_event_callback_forwarder_del(Eo *obj, Efl_Object_Data *pd EINA_UNUSED,
|
2018-12-12 14:07:52 -08:00
|
|
|
const Efl_Event_Description *desc,
|
|
|
|
Eo *new_obj)
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
2018-12-12 14:07:52 -08:00
|
|
|
EO_OBJ_POINTER_RETURN(new_obj, new_data);
|
|
|
|
EO_OBJ_DONE(new_obj);
|
2013-12-25 06:13:41 -08:00
|
|
|
|
2016-08-09 06:10:05 -07:00
|
|
|
efl_event_callback_del(obj, desc, _efl_event_forwarder_callback, new_obj);
|
2013-12-25 06:13:41 -08:00
|
|
|
}
|
|
|
|
|
2014-06-03 03:23:53 -07:00
|
|
|
EOLIAN static void
|
2016-08-09 06:10:05 -07:00
|
|
|
_efl_object_event_freeze(Eo *obj EINA_UNUSED, Efl_Object_Data *pd)
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
|
|
|
pd->event_freeze_count++;
|
|
|
|
}
|
|
|
|
|
2014-06-03 03:23:53 -07:00
|
|
|
EOLIAN static void
|
2016-08-09 06:10:05 -07:00
|
|
|
_efl_object_event_thaw(Eo *obj, Efl_Object_Data *pd)
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
|
|
|
if (pd->event_freeze_count > 0)
|
|
|
|
{
|
|
|
|
pd->event_freeze_count--;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ERR("Events for object %p have already been thawed.", obj);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-03 03:23:53 -07:00
|
|
|
EOLIAN static int
|
2018-04-17 11:09:44 -07:00
|
|
|
_efl_object_event_freeze_count_get(const Eo *obj EINA_UNUSED, Efl_Object_Data *pd)
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
|
|
|
return pd->event_freeze_count;
|
|
|
|
}
|
|
|
|
|
2014-06-03 03:23:53 -07:00
|
|
|
EOLIAN static void
|
2019-02-09 09:45:27 -08:00
|
|
|
_efl_object_event_global_freeze(void)
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
|
|
|
event_freeze_count++;
|
|
|
|
}
|
|
|
|
|
2014-06-03 03:23:53 -07:00
|
|
|
EOLIAN static void
|
2019-02-09 09:45:27 -08:00
|
|
|
_efl_object_event_global_thaw(void)
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
|
|
|
if (event_freeze_count > 0)
|
|
|
|
{
|
|
|
|
event_freeze_count--;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ERR("Global events have already been thawed.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-03 03:23:53 -07:00
|
|
|
EOLIAN static int
|
2019-02-09 09:45:27 -08:00
|
|
|
_efl_object_event_global_freeze_count_get(void)
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
|
|
|
return event_freeze_count;
|
|
|
|
}
|
|
|
|
|
2014-10-21 04:37:00 -07:00
|
|
|
EOLIAN static Eina_Bool
|
2016-08-09 06:10:05 -07:00
|
|
|
_efl_object_composite_attach(Eo *parent_id, Efl_Object_Data *pd EINA_UNUSED, Eo *comp_obj_id)
|
2014-10-21 04:37:00 -07:00
|
|
|
{
|
2017-04-17 22:16:31 -07:00
|
|
|
Efl_Object_Optional *opt;
|
2016-10-06 00:27:28 -07:00
|
|
|
Eo *emb_obj_id = NULL;
|
|
|
|
|
2014-10-21 04:37:00 -07:00
|
|
|
EO_OBJ_POINTER_RETURN_VAL(comp_obj_id, comp_obj, EINA_FALSE);
|
2016-10-06 00:27:28 -07:00
|
|
|
EO_OBJ_POINTER_GOTO(parent_id, parent, err_parent);
|
|
|
|
|
|
|
|
/* FIXME: composite should fail if domains are different */
|
2016-09-28 23:29:34 -07:00
|
|
|
|
2016-05-05 08:08:08 -07:00
|
|
|
/* Don't composite if we already have a composite object of this type */
|
2014-10-21 04:37:00 -07:00
|
|
|
{
|
|
|
|
Eina_List *itr;
|
2017-04-17 22:16:31 -07:00
|
|
|
EINA_LIST_FOREACH(parent->opt->composite_objects, itr, emb_obj_id)
|
2014-10-21 04:37:00 -07:00
|
|
|
{
|
2016-10-06 00:27:28 -07:00
|
|
|
EO_OBJ_POINTER_GOTO(emb_obj_id, emb_obj, err_klass);
|
|
|
|
if (EINA_UNLIKELY(emb_obj->klass == comp_obj->klass)) goto err_klass;
|
2014-10-21 04:37:00 -07:00
|
|
|
}
|
2016-10-06 00:27:28 -07:00
|
|
|
emb_obj_id = NULL;
|
2014-10-21 04:37:00 -07:00
|
|
|
}
|
|
|
|
|
2016-09-28 23:29:34 -07:00
|
|
|
Efl_Object_Data *comp_pd = efl_data_scope_get(comp_obj_id, EFL_OBJECT_CLASS);
|
|
|
|
|
2016-08-09 06:10:05 -07:00
|
|
|
if (efl_composite_part_is(comp_obj_id))
|
2016-09-27 21:25:26 -07:00
|
|
|
efl_composite_detach(comp_pd->ext->composite_parent, comp_obj_id);
|
2016-05-05 08:08:08 -07:00
|
|
|
|
|
|
|
/* Set the parent comp on the child. */
|
2016-08-09 06:10:05 -07:00
|
|
|
_efl_object_extension_need(comp_pd);
|
2016-05-05 08:08:08 -07:00
|
|
|
comp_pd->ext->composite_parent = parent_id;
|
2014-10-21 04:37:00 -07:00
|
|
|
|
2017-04-17 22:16:31 -07:00
|
|
|
opt = EO_OPTIONAL_COW_WRITE(parent);
|
|
|
|
opt->composite_objects = eina_list_prepend(opt->composite_objects, comp_obj_id);
|
|
|
|
EO_OPTIONAL_COW_END(opt, parent);
|
2014-10-21 04:37:00 -07:00
|
|
|
|
2016-10-06 00:27:28 -07:00
|
|
|
if (emb_obj_id) EO_OBJ_DONE(emb_obj_id);
|
2016-09-27 21:25:26 -07:00
|
|
|
EO_OBJ_DONE(parent_id);
|
|
|
|
EO_OBJ_DONE(comp_obj_id);
|
2014-10-21 04:37:00 -07:00
|
|
|
return EINA_TRUE;
|
2016-09-28 23:29:34 -07:00
|
|
|
|
|
|
|
err_klass:
|
2016-10-06 00:27:28 -07:00
|
|
|
if (emb_obj_id) EO_OBJ_DONE(emb_obj_id);
|
2016-09-28 23:29:34 -07:00
|
|
|
EO_OBJ_DONE(parent_id);
|
|
|
|
err_parent:
|
|
|
|
EO_OBJ_DONE(comp_obj_id);
|
|
|
|
return EINA_FALSE;
|
2014-10-21 04:37:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
EOLIAN static Eina_Bool
|
2016-08-09 06:10:05 -07:00
|
|
|
_efl_object_composite_detach(Eo *parent_id, Efl_Object_Data *pd EINA_UNUSED, Eo *comp_obj_id)
|
2014-10-21 04:37:00 -07:00
|
|
|
{
|
2017-04-17 22:16:31 -07:00
|
|
|
Efl_Object_Optional *opt;
|
|
|
|
|
2014-10-21 04:37:00 -07:00
|
|
|
EO_OBJ_POINTER_RETURN_VAL(comp_obj_id, comp_obj, EINA_FALSE);
|
2016-10-06 00:27:28 -07:00
|
|
|
EO_OBJ_POINTER_GOTO(parent_id, parent, err_parent);
|
2014-10-21 04:37:00 -07:00
|
|
|
|
2016-09-28 23:29:34 -07:00
|
|
|
// unlikely so improve l1 instr cache by using goto
|
|
|
|
if (!efl_composite_part_is(comp_obj_id)) goto err_part;
|
2014-10-21 04:37:00 -07:00
|
|
|
|
2017-04-17 22:16:31 -07:00
|
|
|
opt = EO_OPTIONAL_COW_WRITE(parent);
|
|
|
|
opt->composite_objects = eina_list_remove(opt->composite_objects, comp_obj_id);
|
|
|
|
EO_OPTIONAL_COW_END(opt, parent);
|
|
|
|
|
2016-05-05 08:08:08 -07:00
|
|
|
/* Clear the comp parent on the child. */
|
|
|
|
{
|
2016-08-15 06:44:41 -07:00
|
|
|
Efl_Object_Data *comp_pd = efl_data_scope_get(comp_obj_id, EFL_OBJECT_CLASS);
|
2016-05-05 08:08:08 -07:00
|
|
|
comp_pd->ext->composite_parent = NULL;
|
2016-08-09 06:10:05 -07:00
|
|
|
_efl_object_extension_noneed(comp_pd);
|
2016-05-05 08:08:08 -07:00
|
|
|
}
|
2014-10-21 04:37:00 -07:00
|
|
|
|
2016-09-27 21:25:26 -07:00
|
|
|
EO_OBJ_DONE(parent_id);
|
|
|
|
EO_OBJ_DONE(comp_obj_id);
|
2014-10-21 04:37:00 -07:00
|
|
|
return EINA_TRUE;
|
2016-09-28 23:29:34 -07:00
|
|
|
|
|
|
|
err_part:
|
|
|
|
EO_OBJ_DONE(parent_id);
|
|
|
|
err_parent:
|
|
|
|
EO_OBJ_DONE(comp_obj_id);
|
|
|
|
return EINA_FALSE;
|
2014-10-21 04:37:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
EOLIAN static Eina_Bool
|
2016-08-09 06:10:05 -07:00
|
|
|
_efl_object_composite_part_is(Eo *comp_obj_id EINA_UNUSED, Efl_Object_Data *pd)
|
2014-10-21 04:37:00 -07:00
|
|
|
{
|
2016-05-05 08:08:08 -07:00
|
|
|
return pd->ext && pd->ext->composite_parent;
|
2014-10-21 04:37:00 -07:00
|
|
|
}
|
|
|
|
|
2013-12-25 06:13:41 -08:00
|
|
|
/* Eo_Dbg */
|
|
|
|
EAPI void
|
2016-08-15 06:44:41 -07:00
|
|
|
efl_dbg_info_free(Efl_Dbg_Info *info)
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
|
|
|
eina_value_flush(&(info->value));
|
2016-11-04 03:13:53 -07:00
|
|
|
eina_freeq_ptr_main_add(info, free, sizeof(*info));
|
2013-12-25 06:13:41 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static Eina_Bool
|
|
|
|
_eo_dbg_info_setup(const Eina_Value_Type *type, void *mem)
|
|
|
|
{
|
|
|
|
memset(mem, 0, type->value_size);
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Eina_Bool
|
|
|
|
_eo_dbg_info_flush(const Eina_Value_Type *type EINA_UNUSED, void *_mem)
|
|
|
|
{
|
2016-08-09 06:10:05 -07:00
|
|
|
Efl_Dbg_Info *mem = *(Efl_Dbg_Info **) _mem;
|
2013-12-25 06:13:41 -08:00
|
|
|
eina_stringshare_del(mem->name);
|
|
|
|
eina_value_flush(&(mem->value));
|
2016-11-04 03:13:53 -07:00
|
|
|
eina_freeq_ptr_main_add(mem, free, sizeof(*mem));
|
2013-12-25 06:13:41 -08:00
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Eina_Bool
|
|
|
|
_eo_dbg_info_copy(const Eina_Value_Type *type EINA_UNUSED, const void *_src, void *_dst)
|
|
|
|
{
|
2016-08-09 06:10:05 -07:00
|
|
|
const Efl_Dbg_Info **src = (const Efl_Dbg_Info **) _src;
|
|
|
|
Efl_Dbg_Info **dst = _dst;
|
2013-12-26 11:56:59 -08:00
|
|
|
|
2016-08-09 06:10:05 -07:00
|
|
|
*dst = calloc(1, sizeof(Efl_Dbg_Info));
|
2013-12-26 11:56:59 -08:00
|
|
|
if (!*dst) return EINA_FALSE;
|
2013-12-25 06:13:41 -08:00
|
|
|
(*dst)->name = eina_stringshare_ref((*src)->name);
|
|
|
|
eina_value_copy(&((*src)->value), &((*dst)->value));
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Eina_Bool
|
|
|
|
_eo_dbg_info_convert_to(const Eina_Value_Type *type EINA_UNUSED, const Eina_Value_Type *convert, const void *type_mem, void *convert_mem)
|
|
|
|
{
|
|
|
|
/* FIXME: For the meanwhile, just use the inner type for the value. */
|
2016-08-09 06:10:05 -07:00
|
|
|
const Efl_Dbg_Info **src = (const Efl_Dbg_Info **) type_mem;
|
2013-12-25 06:13:41 -08:00
|
|
|
if (convert == EINA_VALUE_TYPE_STRINGSHARE ||
|
|
|
|
convert == EINA_VALUE_TYPE_STRING)
|
|
|
|
{
|
|
|
|
Eina_Bool ret;
|
|
|
|
const char *other_mem;
|
|
|
|
char *inner_val = eina_value_to_string(&(*src)->value);
|
|
|
|
other_mem = inner_val;
|
|
|
|
ret = eina_value_type_pset(convert, convert_mem, &other_mem);
|
2016-11-04 03:13:53 -07:00
|
|
|
eina_freeq_ptr_main_add(inner_val, free, 0);
|
2013-12-25 06:13:41 -08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
eina_error_set(EINA_ERROR_VALUE_FAILED);
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Eina_Bool
|
|
|
|
_eo_dbg_info_pset(const Eina_Value_Type *type EINA_UNUSED, void *_mem, const void *_ptr)
|
|
|
|
{
|
2016-08-09 06:10:05 -07:00
|
|
|
Efl_Dbg_Info **mem = _mem;
|
2016-11-04 03:13:53 -07:00
|
|
|
if (*mem) free(*mem);
|
2013-12-25 06:13:41 -08:00
|
|
|
*mem = (void *) _ptr;
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Eina_Bool
|
|
|
|
_eo_dbg_info_pget(const Eina_Value_Type *type EINA_UNUSED, const void *_mem, void *_ptr)
|
|
|
|
{
|
2016-08-09 06:10:05 -07:00
|
|
|
Efl_Dbg_Info **ptr = _ptr;
|
2013-12-25 06:13:41 -08:00
|
|
|
*ptr = (void *) _mem;
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
2016-08-15 06:44:41 -07:00
|
|
|
static const Eina_Value_Type _EFL_DBG_INFO_TYPE = {
|
2013-12-25 06:13:41 -08:00
|
|
|
EINA_VALUE_TYPE_VERSION,
|
2016-08-09 06:10:05 -07:00
|
|
|
sizeof(Efl_Dbg_Info *),
|
|
|
|
"Efl_Dbg_Info_Ptr",
|
2013-12-25 06:13:41 -08:00
|
|
|
_eo_dbg_info_setup,
|
|
|
|
_eo_dbg_info_flush,
|
|
|
|
_eo_dbg_info_copy,
|
|
|
|
NULL,
|
|
|
|
_eo_dbg_info_convert_to,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
_eo_dbg_info_pset,
|
|
|
|
_eo_dbg_info_pget
|
|
|
|
};
|
|
|
|
|
2016-08-15 06:44:41 -07:00
|
|
|
EAPI const Eina_Value_Type *EFL_DBG_INFO_TYPE = &_EFL_DBG_INFO_TYPE;
|
2013-12-25 06:13:41 -08:00
|
|
|
|
|
|
|
|
|
|
|
/* EOF event callbacks */
|
|
|
|
|
2016-08-09 06:10:05 -07:00
|
|
|
/* EFL_OBJECT_CLASS stuff */
|
|
|
|
#define MY_CLASS EFL_OBJECT_CLASS
|
2013-12-25 06:13:41 -08:00
|
|
|
|
2017-08-25 15:53:15 -07:00
|
|
|
static Eina_Value
|
|
|
|
_efl_future_cb(void *data, const Eina_Value value, const Eina_Future *dead_future)
|
|
|
|
{
|
|
|
|
Efl_Future_Pending *pending = data;
|
|
|
|
Eina_Value ret = value;
|
2018-04-18 11:17:03 -07:00
|
|
|
const Eo *o;
|
2017-08-25 15:53:15 -07:00
|
|
|
Efl_Object_Data *pd;
|
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_GOTO(pending, err);
|
|
|
|
o = pending->o;
|
|
|
|
pd = efl_data_scope_get(o, EFL_OBJECT_CLASS);
|
|
|
|
EINA_SAFETY_ON_NULL_GOTO(pd, err);
|
|
|
|
|
|
|
|
pd->pending_futures = eina_inlist_remove(pd->pending_futures,
|
|
|
|
EINA_INLIST_GET(pending));
|
|
|
|
efl_ref(o);
|
2018-12-07 03:15:16 -08:00
|
|
|
EASY_FUTURE_DISPATCH(ret, value, dead_future, &pending->desc, (void*) o, (void*) pending->desc.data);
|
2017-08-25 15:53:15 -07:00
|
|
|
efl_unref(o);
|
|
|
|
_efl_pending_future_free(pending);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
err:
|
|
|
|
eina_value_setup(&ret, EINA_VALUE_TYPE_ERROR);
|
|
|
|
eina_value_set(&ret, ENOMEM);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
EOAPI Eina_Future_Desc
|
2018-04-18 11:17:03 -07:00
|
|
|
efl_future_cb_from_desc(const Eo *o, const Efl_Future_Cb_Desc desc)
|
2017-08-25 15:53:15 -07:00
|
|
|
{
|
|
|
|
Efl_Future_Pending *pending = NULL;
|
|
|
|
Eina_Future **storage = NULL;
|
|
|
|
Efl_Object_Data *pd;
|
2018-04-04 15:37:11 -07:00
|
|
|
Eina_Bool invalidate;
|
2017-08-25 15:53:15 -07:00
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_GOTO(o, end);
|
|
|
|
pd = efl_data_scope_get(o, EFL_OBJECT_CLASS);
|
|
|
|
EINA_SAFETY_ON_NULL_GOTO(pd, end);
|
2018-04-04 15:37:11 -07:00
|
|
|
EO_OBJ_POINTER_GOTO(o, eo_obj, end);
|
|
|
|
invalidate = eo_obj->invalidate;
|
|
|
|
EO_OBJ_DONE(o);
|
|
|
|
EINA_SAFETY_ON_TRUE_GOTO(invalidate, end);
|
2017-08-25 15:53:15 -07:00
|
|
|
pending = _efl_pending_future_new();
|
|
|
|
EINA_SAFETY_ON_NULL_GOTO(pending, end);
|
|
|
|
memcpy(&pending->desc, &desc, sizeof(Efl_Future_Cb_Desc));
|
|
|
|
pending->o = o;
|
|
|
|
pending->future = NULL;
|
|
|
|
if (!pending->desc.storage) pending->desc.storage = &pending->future;
|
|
|
|
pd->pending_futures = eina_inlist_append(pd->pending_futures,
|
|
|
|
EINA_INLIST_GET(pending));
|
|
|
|
storage = pending->desc.storage;
|
|
|
|
end:
|
|
|
|
return (Eina_Future_Desc){ .cb = _efl_future_cb, .data = pending, .storage = storage };
|
|
|
|
}
|
|
|
|
|
|
|
|
EOAPI Eina_Future *
|
|
|
|
efl_future_chain_array(Eo *obj,
|
|
|
|
Eina_Future *prev,
|
|
|
|
const Efl_Future_Cb_Desc descs[])
|
|
|
|
{
|
|
|
|
ssize_t i = -1;
|
|
|
|
Eina_Future *f = prev;
|
|
|
|
|
|
|
|
for (i = 0; descs[i].success || descs[i].error || descs[i].free || descs[i].success_type; i++)
|
|
|
|
{
|
|
|
|
Eina_Future_Desc eina_desc = efl_future_cb_from_desc(obj, descs[i]);
|
|
|
|
f = eina_future_then_from_desc(f, eina_desc);
|
|
|
|
EINA_SAFETY_ON_NULL_GOTO(f, err);
|
|
|
|
}
|
|
|
|
|
|
|
|
return f;
|
|
|
|
|
|
|
|
err:
|
|
|
|
/*
|
|
|
|
There's no need to cancel the futures, since eina_future_then_from_desc()
|
|
|
|
will cancel the whole chain in case of failure.
|
|
|
|
All we need to do is to free the remaining descs
|
|
|
|
*/
|
|
|
|
for (i = i + 1; descs[i].error || descs[i].free; i++)
|
|
|
|
{
|
|
|
|
if (descs[i].error)
|
|
|
|
{
|
2018-12-07 03:15:16 -08:00
|
|
|
Eina_Value r = descs[i].error(obj, (void*) descs[i].data, ENOMEM);
|
2017-08-25 15:53:15 -07:00
|
|
|
eina_value_flush(&r);
|
|
|
|
}
|
2018-12-07 03:15:16 -08:00
|
|
|
if (descs[i].free) descs[i].free(obj, (void*) descs[i].data, NULL);
|
2017-08-25 15:53:15 -07:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-05-19 03:41:27 -07:00
|
|
|
EOLIAN static Eo *
|
2016-08-09 06:10:05 -07:00
|
|
|
_efl_object_constructor(Eo *obj, Efl_Object_Data *pd EINA_UNUSED)
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
2016-08-15 06:44:41 -07:00
|
|
|
DBG("%p - %s.", obj, efl_class_name_get(obj));
|
2013-12-25 06:13:41 -08:00
|
|
|
|
|
|
|
_eo_condtor_done(obj);
|
2015-05-19 03:41:27 -07:00
|
|
|
|
|
|
|
return obj;
|
2013-12-25 06:13:41 -08:00
|
|
|
}
|
|
|
|
|
2014-07-24 07:01:36 -07:00
|
|
|
EOLIAN static void
|
2016-08-09 06:10:05 -07:00
|
|
|
_efl_object_destructor(Eo *obj, Efl_Object_Data *pd)
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
2018-05-01 14:23:04 -07:00
|
|
|
_Eo_Object *obj_child;
|
|
|
|
Eina_Inlist *l;
|
2016-08-09 06:10:05 -07:00
|
|
|
Efl_Object_Extension *ext;
|
2016-09-28 23:29:34 -07:00
|
|
|
_Eo_Object *obj_data2 = NULL;
|
2013-11-08 04:24:40 -08:00
|
|
|
|
2016-08-15 06:44:41 -07:00
|
|
|
DBG("%p - %s.", obj, efl_class_name_get(obj));
|
2013-12-25 06:13:41 -08:00
|
|
|
|
2015-08-18 01:23:16 -07:00
|
|
|
// special removal - remove from children list by hand after getting
|
|
|
|
// child handle in case unparent method is overridden and does
|
|
|
|
// extra things like removes other children too later on in the list
|
2016-09-28 23:29:34 -07:00
|
|
|
// this is a goto because more often than not objects do not have children
|
|
|
|
// so it's unlikely they will need the child cleanup code to so to have
|
|
|
|
// better l1 cache instruction coherency, move this to the end
|
|
|
|
if (pd->children) goto children;
|
|
|
|
children_back:
|
2015-08-21 09:19:47 -07:00
|
|
|
|
2016-09-28 23:29:34 -07:00
|
|
|
// If we are a composite object, detach children. it is quite unlikely
|
|
|
|
// we are a composite object, so put the core of this handling
|
|
|
|
// at the end out of l1 cache prefetch
|
2016-05-05 08:08:08 -07:00
|
|
|
{
|
|
|
|
EO_OBJ_POINTER_RETURN(obj, obj_data);
|
2016-09-28 23:29:34 -07:00
|
|
|
obj_data2 = obj_data;
|
2017-04-17 22:16:31 -07:00
|
|
|
if (obj_data->opt->composite_objects) goto composite_obj;
|
2016-09-28 23:29:34 -07:00
|
|
|
composite_obj_back:
|
2016-09-27 21:25:26 -07:00
|
|
|
EO_OBJ_DONE(obj);
|
2016-05-05 08:08:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (pd->ext && pd->ext->composite_parent)
|
2016-09-28 23:29:34 -07:00
|
|
|
efl_composite_detach(pd->ext->composite_parent, obj);
|
2016-05-05 08:08:08 -07:00
|
|
|
|
2016-09-28 23:29:34 -07:00
|
|
|
// parent still being here is unlikely, so move error handling out of the
|
|
|
|
// code execution path
|
|
|
|
if (pd->parent) goto err_parent;
|
|
|
|
err_parent_back:
|
2013-11-08 04:24:40 -08:00
|
|
|
|
2018-01-09 22:23:29 -08:00
|
|
|
// this isn't 100% correct, as the object is still "slightly" alive at this
|
|
|
|
// point (so efl_destructed_is() returns false), but triggering the
|
|
|
|
// "destruct" event here is the simplest, safest solution.
|
2019-11-13 15:01:00 -08:00
|
|
|
if (EINA_UNLIKELY(pd->event_cb_EFL_EVENT_DESTRUCT))
|
2018-01-09 22:23:29 -08:00
|
|
|
_event_callback_call(obj, pd, EFL_EVENT_DESTRUCT, NULL, EINA_FALSE);
|
|
|
|
|
|
|
|
// remove generic data after this final event, in case they are used in a cb
|
|
|
|
_eo_generic_data_del_all(obj, pd);
|
2014-06-03 03:23:53 -07:00
|
|
|
_eo_callback_remove_all(pd);
|
2013-12-25 06:13:41 -08:00
|
|
|
|
2018-05-22 14:10:48 -07:00
|
|
|
_wref_destruct(pd);
|
|
|
|
|
2016-04-23 22:38:02 -07:00
|
|
|
ext = pd->ext;
|
2016-09-28 23:29:34 -07:00
|
|
|
// it is rather likely we dont have any extension section for most objects
|
|
|
|
// so return immediately here to avoid pulling in more instructions to
|
|
|
|
// the 1l cache if we can
|
|
|
|
if (!ext)
|
2016-04-19 01:21:21 -07:00
|
|
|
{
|
2016-09-28 23:29:34 -07:00
|
|
|
_eo_condtor_done(obj);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
eina_stringshare_del(ext->name);
|
|
|
|
ext->name = NULL;
|
|
|
|
eina_stringshare_del(ext->comment);
|
|
|
|
ext->comment = NULL;
|
|
|
|
_efl_object_extension_noneed(pd);
|
|
|
|
_eo_condtor_done(obj);
|
|
|
|
return;
|
2016-07-13 17:07:47 -07:00
|
|
|
|
2016-09-28 23:29:34 -07:00
|
|
|
children:
|
2018-05-09 17:23:20 -07:00
|
|
|
ERR("Object %p of type '%s' is still holding child at time of destruction.\n",
|
|
|
|
obj, efl_class_name_get(obj));
|
2018-05-01 14:23:04 -07:00
|
|
|
EINA_INLIST_FOREACH_SAFE(pd->children, l, obj_child)
|
2016-09-28 23:29:34 -07:00
|
|
|
{
|
2018-05-01 14:23:04 -07:00
|
|
|
Eo *child;
|
|
|
|
|
|
|
|
child = _eo_obj_id_get(obj_child);
|
2016-09-28 23:29:34 -07:00
|
|
|
efl_parent_set(child, NULL);
|
2016-04-19 01:21:21 -07:00
|
|
|
}
|
2016-09-28 23:29:34 -07:00
|
|
|
goto children_back;
|
2016-04-19 00:34:53 -07:00
|
|
|
|
2016-09-28 23:29:34 -07:00
|
|
|
composite_obj:
|
|
|
|
{
|
|
|
|
Eina_List *itr, *next;
|
|
|
|
Eo *emb_obj_id;
|
2017-04-17 22:16:31 -07:00
|
|
|
|
|
|
|
EINA_LIST_FOREACH_SAFE(obj_data2->opt->composite_objects, itr, next, emb_obj_id)
|
2016-09-28 23:29:34 -07:00
|
|
|
{
|
|
|
|
efl_composite_detach(obj, emb_obj_id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
goto composite_obj_back;
|
|
|
|
|
|
|
|
err_parent:
|
2017-09-28 00:38:00 -07:00
|
|
|
if (EINA_LIKELY(!pd->allow_parent_unref))
|
2018-05-01 14:24:05 -07:00
|
|
|
ERR("Object '%p' of type '%s' still has a parent at the time of destruction.", obj, efl_class_name_get(obj));
|
2016-09-28 23:29:34 -07:00
|
|
|
efl_parent_set(obj, NULL);
|
|
|
|
goto err_parent_back;
|
2013-12-25 06:13:41 -08:00
|
|
|
}
|
|
|
|
|
2017-09-28 00:38:00 -07:00
|
|
|
EOLIAN static void
|
2018-05-03 16:32:11 -07:00
|
|
|
_efl_object_allow_parent_unref_set(Eo *obj_id, Efl_Object_Data *pd, Eina_Bool allow)
|
2017-09-28 00:38:00 -07:00
|
|
|
{
|
2018-05-03 16:32:11 -07:00
|
|
|
EO_OBJ_POINTER_RETURN(obj_id, obj);
|
|
|
|
obj->allow_parent_unref = !!allow;
|
2017-09-28 00:38:00 -07:00
|
|
|
pd->allow_parent_unref = !!allow;
|
2018-05-03 16:32:11 -07:00
|
|
|
EO_OBJ_DONE(obj_id);
|
2017-09-28 00:38:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
EOLIAN static Eina_Bool
|
2018-04-17 11:09:44 -07:00
|
|
|
_efl_object_allow_parent_unref_get(const Eo *obj_id EINA_UNUSED, Efl_Object_Data *pd)
|
2017-09-28 00:38:00 -07:00
|
|
|
{
|
|
|
|
return pd->allow_parent_unref;
|
|
|
|
}
|
|
|
|
|
2017-12-04 21:31:22 -08:00
|
|
|
EAPI void
|
|
|
|
___efl_auto_unref_set(Eo *obj_id, Eina_Bool enable)
|
2017-10-13 01:18:41 -07:00
|
|
|
{
|
|
|
|
// Write-only property
|
2018-04-16 11:24:27 -07:00
|
|
|
EO_OBJ_POINTER_RETURN(obj_id, obj);
|
2017-12-04 21:31:22 -08:00
|
|
|
obj->auto_unref = enable ? 1 : 0;
|
2018-04-16 11:24:27 -07:00
|
|
|
EO_OBJ_DONE(obj_id);
|
2017-10-13 01:18:41 -07:00
|
|
|
}
|
|
|
|
|
2014-07-24 07:01:36 -07:00
|
|
|
EOLIAN static Eo *
|
2016-08-09 06:10:05 -07:00
|
|
|
_efl_object_finalize(Eo *obj, Efl_Object_Data *pd EINA_UNUSED)
|
2014-05-30 03:17:36 -07:00
|
|
|
{
|
2015-05-20 06:56:45 -07:00
|
|
|
return obj;
|
2014-05-30 03:17:36 -07:00
|
|
|
}
|
|
|
|
|
2014-07-24 07:01:36 -07:00
|
|
|
EOLIAN static void
|
2016-08-09 06:10:05 -07:00
|
|
|
_efl_object_class_constructor(Efl_Class *klass EINA_UNUSED)
|
2013-12-25 06:13:41 -08:00
|
|
|
{
|
|
|
|
event_freeze_count = 0;
|
2014-05-19 07:17:08 -07:00
|
|
|
_legacy_events_hash = eina_hash_stringshared_new(_legacy_events_hash_free_cb);
|
2018-01-08 15:03:21 -08:00
|
|
|
|
|
|
|
_eo_callback_mempool =
|
|
|
|
eina_mempool_add("chained_mempool", NULL, NULL,
|
|
|
|
sizeof(Eo_Callback_Description), 256);
|
|
|
|
|
|
|
|
_efl_pending_future_mempool =
|
|
|
|
eina_mempool_add("chained_mempool", NULL, NULL,
|
|
|
|
sizeof(Efl_Future_Pending), 256);
|
|
|
|
|
2019-10-16 16:47:10 -07:00
|
|
|
_efl_future_scheduler_entry_mempool =
|
|
|
|
eina_mempool_add("chained_mempool", NULL, NULL,
|
|
|
|
sizeof(Efl_Future_Scheduler_Entry), 256);
|
|
|
|
|
2018-01-08 15:03:21 -08:00
|
|
|
_eo_nostep_alloc = !!getenv("EO_NOSTEP_ALLOC");
|
2014-05-19 07:17:08 -07:00
|
|
|
}
|
|
|
|
|
2014-07-24 07:01:36 -07:00
|
|
|
EOLIAN static void
|
2016-08-09 06:10:05 -07:00
|
|
|
_efl_object_class_destructor(Efl_Class *klass EINA_UNUSED)
|
2014-05-19 07:17:08 -07:00
|
|
|
{
|
2019-10-16 16:47:10 -07:00
|
|
|
eina_mempool_del(_efl_future_scheduler_entry_mempool);
|
2018-01-08 15:03:21 -08:00
|
|
|
eina_mempool_del(_efl_pending_future_mempool);
|
|
|
|
eina_mempool_del(_eo_callback_mempool);
|
2014-05-19 07:17:08 -07:00
|
|
|
eina_hash_free(_legacy_events_hash);
|
2013-12-25 06:13:41 -08:00
|
|
|
}
|
|
|
|
|
2017-04-20 09:24:38 -07:00
|
|
|
#define EFL_OBJECT_EXTRA_OPS \
|
|
|
|
EFL_OBJECT_OP_FUNC(efl_event_callback_priority_add, _efl_object_event_callback_priority_add), \
|
|
|
|
EFL_OBJECT_OP_FUNC(efl_event_callback_del, _efl_object_event_callback_del), \
|
|
|
|
EFL_OBJECT_OP_FUNC(efl_event_callback_array_priority_add, _efl_object_event_callback_array_priority_add), \
|
|
|
|
EFL_OBJECT_OP_FUNC(efl_event_callback_array_del, _efl_object_event_callback_array_del), \
|
|
|
|
EFL_OBJECT_OP_FUNC(efl_event_callback_call, _efl_object_event_callback_call), \
|
2017-04-21 08:58:38 -07:00
|
|
|
EFL_OBJECT_OP_FUNC(efl_event_callback_legacy_call, _efl_object_event_callback_legacy_call), \
|
2019-10-16 16:47:10 -07:00
|
|
|
EFL_OBJECT_OP_FUNC(efl_event_future_scheduler_get, _efl_object_event_future_scheduler_get), \
|
2019-10-17 12:09:14 -07:00
|
|
|
EFL_OBJECT_OP_FUNC(efl_event_callback_count, _efl_object_event_callback_count), \
|
2017-04-26 05:25:37 -07:00
|
|
|
EFL_OBJECT_OP_FUNC(efl_dbg_info_get, _efl_object_dbg_info_get), \
|
2017-04-26 06:01:44 -07:00
|
|
|
EFL_OBJECT_OP_FUNC(efl_wref_add, _efl_object_wref_add), \
|
2017-04-26 07:18:49 -07:00
|
|
|
EFL_OBJECT_OP_FUNC(efl_wref_del, _efl_object_wref_del), \
|
|
|
|
EFL_OBJECT_OP_FUNC(efl_key_data_set, _efl_object_key_data_set), \
|
|
|
|
EFL_OBJECT_OP_FUNC(efl_key_data_get, _efl_object_key_data_get), \
|
|
|
|
EFL_OBJECT_OP_FUNC(efl_key_ref_set, _efl_object_key_ref_set), \
|
|
|
|
EFL_OBJECT_OP_FUNC(efl_key_ref_get, _efl_object_key_ref_get), \
|
|
|
|
EFL_OBJECT_OP_FUNC(efl_key_wref_set, _efl_object_key_wref_set), \
|
|
|
|
EFL_OBJECT_OP_FUNC(efl_key_wref_get, _efl_object_key_wref_get), \
|
|
|
|
EFL_OBJECT_OP_FUNC(efl_key_value_set, _efl_object_key_value_set), \
|
|
|
|
EFL_OBJECT_OP_FUNC(efl_key_value_get, _efl_object_key_value_get) \
|
2017-04-20 09:24:38 -07:00
|
|
|
|
2016-08-09 06:10:05 -07:00
|
|
|
#include "efl_object.eo.c"
|