Eo: Keep artifical object ref a bit longer.
[profile/ivi/eobj.git] / lib / eo.c
1 #include <Eina.h>
2
3 #include "Eo.h"
4 #include "eo_private.h"
5
6 #include "config.h"
7
8 typedef size_t Eo_Class_Id;
9
10 /* Used inside the class_get functions of classes, see #EO_DEFINE_CLASS */
11 EAPI Eina_Lock _eo_class_creation_lock;
12 int _eo_log_dom = -1;
13
14 static Eo_Class **_eo_classes;
15 static Eo_Class_Id _eo_classes_last_id;
16 static Eina_Bool _eo_init_count = 0;
17
18 static void _eo_callback_remove_all(Eo *obj);
19 static void _eo_constructor(Eo *obj, const Eo_Class *klass);
20 static void _eo_destructor(Eo *obj, const Eo_Class *klass);
21 static void eo_constructor_error_unset(Eo *obj);
22 static inline void *_eo_data_get(const Eo *obj, const Eo_Class *klass);
23 static inline Eo *_eo_ref(Eo *obj);
24 static inline void _eo_unref(Eo *obj);
25
26 typedef struct _Eo_Callback_Description Eo_Callback_Description;
27
28 typedef struct
29 {
30    Eo_Op op;
31    const Eo_Class **kls_itr;
32 } Eo_Kls_Itr;
33
34 #define EO_EINA_MAGIC 0xa186bc32 /* Nothing magical about this number. */
35 #define EO_EINA_MAGIC_STR "Eo"
36 #define EO_CLASS_EINA_MAGIC 0xa186bb32 /* Nothing magical about this number. */
37 #define EO_CLASS_EINA_MAGIC_STR "Eo Class"
38
39 #define EO_MAGIC_RETURN_VAL(d, magic, ret) \
40    do { \
41         if (!EINA_MAGIC_CHECK(d, magic)) \
42           { \
43              EINA_MAGIC_FAIL(d, magic); \
44              return ret; \
45           } \
46    } while (0)
47
48 #define EO_MAGIC_RETURN(d, magic) \
49    do { \
50         if (!EINA_MAGIC_CHECK(d, magic)) \
51           { \
52              EINA_MAGIC_FAIL(d, magic); \
53              return; \
54           } \
55    } while (0)
56
57 struct _Eo {
58      EINA_MAGIC
59      Eo *parent;
60      const Eo_Class *klass;
61      int refcount;
62 #ifndef NDEBUG
63      Eina_Inlist *xrefs;
64 #endif
65
66      Eina_List *composite_objects;
67
68      Eina_Inlist *callbacks;
69      int walking_list;
70
71      Eo_Kls_Itr mro_itr;
72
73      Eina_Bool del:1;
74      Eina_Bool construct_error:1;
75 };
76
77 /* Start of Dich */
78 /* Dich search, split to 0xff 0xff 0xffff */
79
80 #define DICH_CHAIN1_MASK (0xffff)
81 #define DICH_CHAIN_LAST_MASK (0xffff)
82 #define DICH_CHAIN1(x) (((x) >> 16) & DICH_CHAIN1_MASK)
83 #define DICH_CHAIN_LAST(x) ((x) & DICH_CHAIN_LAST_MASK)
84
85 #define OP_CLASS_OFFSET 16
86 #define OP_CLASS_OFFSET_GET(x) (((x) >> OP_CLASS_OFFSET) & 0xffff)
87 #define OP_CLASS_GET(op) ({ \
88       Eo_Class_Id tmp = OP_CLASS_OFFSET_GET(op); \
89       ID_CLASS_GET(tmp); \
90       })
91 #define OP_SUB_ID_GET(op) ((op) & 0xffff)
92
93 #define ID_CLASS_GET(id) ({ \
94       (Eo_Class *) ((id <= _eo_classes_last_id) && (id > 0)) ? \
95       (_eo_classes[id - 1]) : NULL; \
96       })
97
98 #define EO_ALIGN_SIZE(size) \
99         ((size) + (sizeof(void *) - ((size) % sizeof(void *))))
100
101 /* Structure of Eo_Op is:
102  * 16bit: class
103  * 16bit: op.
104  */
105
106 typedef struct _Dich_Chain1 Dich_Chain1;
107
108 typedef struct
109 {
110    eo_op_func_type func;
111    const Eo_Class *src;
112 } op_type_funcs;
113
114 struct _Dich_Chain1
115 {
116    op_type_funcs *funcs;
117 };
118
119 typedef struct
120 {
121      EINA_INLIST;
122      const Eo_Class *klass;
123 } Eo_Extension_Node;
124
125 typedef struct
126 {
127      const Eo_Class *klass;
128      size_t offset;
129 } Eo_Extension_Data_Offset;
130
131 struct _Eo_Class
132 {
133    EINA_MAGIC
134    Eo_Class_Id class_id;
135    const Eo_Class *parent;
136    const Eo_Class_Description *desc;
137    Dich_Chain1 *chain; /**< The size is class_id */
138    Eina_Inlist *extensions;
139
140    Eo_Extension_Data_Offset *extn_data_off;
141    size_t extn_data_size;
142
143    const Eo_Class **mro;
144
145    size_t data_offset; /* < Offset of the data within object data. */
146
147    Eina_Bool constructed : 1;
148 };
149
150 static inline void
151 _dich_chain_alloc(Dich_Chain1 *chain1, size_t num_ops)
152 {
153    if (!chain1->funcs)
154      {
155         chain1->funcs = calloc(num_ops, sizeof(*(chain1->funcs)));
156      }
157 }
158
159 static inline void
160 _dich_copy_all(Eo_Class *dst, const Eo_Class *src)
161 {
162    if (!src->chain) return;
163
164    if (!dst->chain)
165      {
166         dst->chain = calloc(dst->class_id, sizeof(*dst->chain));
167      }
168
169    Eo_Class_Id i;
170    const Dich_Chain1 *sc1 = src->chain;
171    Dich_Chain1 *dc1 = dst->chain;
172    for (i = 0 ; i < src->class_id ; i++, sc1++, dc1++)
173      {
174         if (sc1->funcs)
175           {
176              size_t j;
177              const Eo_Class *op_klass = ID_CLASS_GET(i + 1);
178              size_t num_ops = op_klass->desc->ops.count;
179              _dich_chain_alloc(dc1, num_ops);
180
181              const op_type_funcs *sf = sc1->funcs;
182              op_type_funcs *df = dc1->funcs;
183              for (j = 0 ; j < num_ops ; j++, df++, sf++)
184                {
185                   if (sf->func)
186                     {
187                        memcpy(df, sf, sizeof(*df));
188                     }
189                }
190           }
191      }
192 }
193
194 static inline const op_type_funcs *
195 _dich_func_get(const Eo_Class *klass, Eo_Op op)
196 {
197    if (!klass->chain) return NULL;
198
199    size_t idx1 = DICH_CHAIN1(op) - 1;
200    if (idx1 >= klass->class_id) return NULL;
201    const Dich_Chain1 *chain1 = &klass->chain[idx1];
202    if (!chain1->funcs) return NULL;
203
204    size_t idxl = DICH_CHAIN_LAST(op);
205    /* num_ops is calculated from the class. */
206    const Eo_Class *op_klass = ID_CLASS_GET(idx1 + 1);
207    if (!op_klass || (idxl >= op_klass->desc->ops.count))
208       return NULL;
209
210    return &chain1->funcs[idxl];
211 }
212
213 static inline void
214 _dich_func_set(Eo_Class *klass, Eo_Op op, eo_op_func_type func)
215 {
216    const Eo_Class *op_klass = OP_CLASS_GET(op);
217    size_t num_ops;
218
219    /* Verify op is valid. */
220    if (op_klass)
221      {
222         /* num_ops is calculated from the class. */
223         num_ops = op_klass->desc->ops.count;
224         if (DICH_CHAIN_LAST(op) >= num_ops)
225           {
226              ERR("OP %x is too big for the domain '%s', expected value < %x.",
227                    op, op_klass->desc->name, op_klass->desc->ops.count);
228              return;
229           }
230      }
231    else
232      {
233         ERR("OP %x is from an illegal class.", op);
234         return;
235      }
236
237    if (!klass->chain)
238      {
239         klass->chain = calloc(klass->class_id, sizeof(*klass->chain));
240      }
241
242    size_t idx1 = DICH_CHAIN1(op) - 1;
243    Dich_Chain1 *chain1 = &klass->chain[idx1];
244    _dich_chain_alloc(chain1, num_ops);
245    chain1->funcs[DICH_CHAIN_LAST(op)].func = func;
246    chain1->funcs[DICH_CHAIN_LAST(op)].src = klass;
247 }
248
249 static inline void
250 _dich_func_clean_all(Eo_Class *klass)
251 {
252    size_t i;
253    Dich_Chain1 *chain1 = klass->chain;
254
255    if (!chain1)
256       return;
257
258    for (i = 0 ; i < klass->class_id ; i++, chain1++)
259      {
260         if (chain1->funcs)
261            free(chain1->funcs);
262      }
263    free(klass->chain);
264    klass->chain = NULL;
265 }
266
267 /* END OF DICH */
268
269 static const Eo_Op_Description noop_desc =
270         EO_OP_DESCRIPTION(EO_NOOP, "", "No operation.");
271
272 static const Eo_Op_Description *
273 _eo_op_id_desc_get(Eo_Op op)
274 {
275    const Eo_Class *klass = OP_CLASS_GET(op);
276    Eo_Op sub_id = OP_SUB_ID_GET(op);
277
278    if (op == EO_NOOP)
279       return &noop_desc;
280
281    if (klass && (sub_id < klass->desc->ops.count))
282       return klass->desc->ops.descs + sub_id;
283
284    return NULL;
285 }
286
287 static const char *
288 _eo_op_id_name_get(Eo_Op op)
289 {
290    const Eo_Op_Description *desc = _eo_op_id_desc_get(op);
291    return (desc) ? desc->name : NULL;
292 }
293
294 static inline void
295 _eo_kls_itr_init(Eo *obj, Eo_Op op, Eo_Kls_Itr *prev_state)
296 {
297    prev_state->op = obj->mro_itr.op;
298    prev_state->kls_itr = obj->mro_itr.kls_itr;
299
300    /* If we are in a constructor/destructor or we changed an op - init. */
301    if ((op == EO_NOOP) || (obj->mro_itr.op != op))
302      {
303         obj->mro_itr.op = op;
304         obj->mro_itr.kls_itr = obj->klass->mro;
305      }
306 }
307
308 static inline void
309 _eo_kls_itr_end(Eo *obj, Eo_Kls_Itr *prev_state)
310 {
311    if (obj->mro_itr.op != prev_state->op)
312      {
313         obj->mro_itr.op = prev_state->op;
314         obj->mro_itr.kls_itr = prev_state->kls_itr;
315      }
316 }
317
318 static inline const Eo_Class *
319 _eo_kls_itr_get(Eo *obj)
320 {
321    return (obj->mro_itr.kls_itr) ? *(obj->mro_itr.kls_itr) : NULL;
322 }
323
324 static inline const Eo_Class *
325 _eo_kls_itr_next(Eo *obj, Eo_Op op)
326 {
327    if (obj->mro_itr.op != op)
328      {
329         Eo_Op node_op = obj->mro_itr.op;
330         ERR("Called with op %d ('%s') while expecting: %d ('%s'). This probaly means you called eo_*_super functions from a wrong place.",
331               op, _eo_op_id_name_get(op),
332               node_op, _eo_op_id_name_get(node_op));
333         return NULL;
334      }
335
336    const Eo_Class **kls_itr = obj->mro_itr.kls_itr;
337    if (*kls_itr)
338      {
339         if (op != EO_NOOP)
340           {
341              const op_type_funcs *fsrc = _dich_func_get(*kls_itr, op);
342
343              while (*kls_itr && (*(kls_itr++) != fsrc->src))
344                 ;
345           }
346         else
347           {
348              kls_itr++;
349           }
350
351         obj->mro_itr.kls_itr = kls_itr;
352         return *kls_itr;
353      }
354    else
355      {
356         return NULL;
357      }
358 }
359
360 static inline Eina_Bool
361 _eo_kls_itr_reached_end(const Eo *obj)
362 {
363    const Eo_Class **kls_itr = obj->mro_itr.kls_itr;
364    return !(*kls_itr && *(kls_itr + 1));
365 }
366
367 static Eina_Bool
368 _eo_op_internal(Eo *obj, Eina_Bool constant, Eo_Op op, va_list *p_list)
369 {
370    const Eo_Class *klass;
371    Eina_Bool ret = EINA_FALSE;
372
373    const Eo_Op_Description *op_desc = _eo_op_id_desc_get(op);
374
375    if (op_desc &&
376          ((constant == EINA_TRUE) && (op_desc->constant == EINA_FALSE)))
377      {
378         ERR("Tried calling non-const or non-existant op '%s' (%d) from a const (query) function.", (op_desc) ? op_desc->name : NULL, op);
379         return EINA_FALSE;
380      }
381
382    Eo_Kls_Itr prev_state;
383    _eo_kls_itr_init(obj, op, &prev_state);
384    klass = _eo_kls_itr_get(obj);
385    if (klass)
386      {
387         const op_type_funcs *func = _dich_func_get(klass, op);
388
389         if (func && func->func)
390           {
391              func->func(obj, _eo_data_get(obj, func->src), p_list);
392              ret = EINA_TRUE;
393              goto end;
394           }
395      }
396
397    /* Try composite objects */
398      {
399         Eina_List *itr;
400         Eo *emb_obj;
401         EINA_LIST_FOREACH(obj->composite_objects, itr, emb_obj)
402           {
403              if (_eo_op_internal(emb_obj, constant, op, p_list))
404                {
405                   ret = EINA_TRUE;
406                   goto end;
407                }
408           }
409      }
410
411 end:
412    _eo_kls_itr_end(obj, &prev_state);
413    return ret;
414 }
415
416 EAPI Eina_Bool
417 eo_do_internal(Eo *obj, Eina_Bool constant, ...)
418 {
419    Eina_Bool ret = EINA_TRUE;
420    Eo_Op op = EO_NOOP;
421    va_list p_list;
422
423    EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, EINA_FALSE);
424
425    _eo_ref(obj);
426
427    va_start(p_list, constant);
428
429    op = va_arg(p_list, Eo_Op);
430    while (op)
431      {
432         if (!_eo_op_internal(obj, constant, op, &p_list))
433           {
434              const Eo_Class *op_klass = OP_CLASS_GET(op);
435              const char *_dom_name = (op_klass) ? op_klass->desc->name : NULL;
436              ERR("Can't find func for op %x ('%s' of domain '%s') for class '%s'. Aborting.",
437                    op, _eo_op_id_name_get(op), _dom_name,
438                    obj->klass->desc->name);
439              ret = EINA_FALSE;
440              break;
441           }
442         op = va_arg(p_list, Eo_Op);
443      }
444
445    va_end(p_list);
446
447    _eo_unref(obj);
448    return ret;
449 }
450
451 EAPI Eina_Bool
452 eo_do_super_internal(Eo *obj, Eina_Bool constant, Eo_Op op, ...)
453 {
454    const Eo_Class *obj_klass;
455    Eina_Bool ret = EINA_TRUE;
456    va_list p_list;
457    EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, EINA_FALSE);
458
459    /* Advance the kls itr. */
460    obj_klass = _eo_kls_itr_next(obj, op);
461
462    if (obj->mro_itr.op != op)
463       return EINA_FALSE;
464
465    va_start(p_list, op);
466    if (!_eo_op_internal(obj, constant, op, &p_list))
467      {
468         const Eo_Class *op_klass = OP_CLASS_GET(op);
469         const char *_dom_name = (op_klass) ? op_klass->desc->name : NULL;
470         ERR("Can't find func for op %x ('%s' of domain '%s') for class '%s'. Aborting.",
471               op, _eo_op_id_name_get(op), _dom_name,
472               (obj_klass) ? obj_klass->desc->name : NULL);
473         ret = EINA_FALSE;
474      }
475    va_end(p_list);
476
477    return ret;
478 }
479
480 EAPI const Eo_Class *
481 eo_class_get(const Eo *obj)
482 {
483    EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, EINA_FALSE);
484
485    return obj->klass;
486 }
487
488 EAPI const char *
489 eo_class_name_get(const Eo_Class *klass)
490 {
491    EO_MAGIC_RETURN_VAL(klass, EO_CLASS_EINA_MAGIC, NULL);
492
493    return klass->desc->name;
494 }
495
496 static void
497 _eo_class_base_op_init(Eo_Class *klass)
498 {
499    const Eo_Class_Description *desc = klass->desc;
500    if (!desc || !desc->ops.base_op_id)
501       return;
502
503    /* FIXME: Depends on values defined above! */
504    *(desc->ops.base_op_id) = klass->class_id << OP_CLASS_OFFSET;
505 }
506
507 #ifndef NDEBUG
508 static Eina_Bool
509 _eo_class_mro_has(const Eo_Class *klass, const Eo_Class *find)
510 {
511    const Eo_Class **itr;
512    for (itr = klass->mro ; *itr ; itr++)
513      {
514         if (*itr == find)
515           {
516              return EINA_TRUE;
517           }
518      }
519
520    return EINA_FALSE;
521 }
522 #endif
523
524 static Eina_List *
525 _eo_class_mro_add(Eina_List *mro, const Eo_Class *klass)
526 {
527    Eina_List *extn_pos = NULL;
528    Eina_Bool check_consistency = !mro;
529    if (!klass)
530       return mro;
531
532    mro = eina_list_append(mro, klass);
533
534    /* Recursively add extenions. */
535      {
536         Eo_Extension_Node *extn;
537         EINA_INLIST_FOREACH(klass->extensions, extn)
538           {
539              mro = _eo_class_mro_add(mro, extn->klass);
540              /* Not possible: if (!mro) return NULL; */
541
542              if (check_consistency)
543                {
544                   extn_pos = eina_list_append(extn_pos, eina_list_last(mro));
545                }
546           }
547      }
548
549    /* Check if we can create a consistent mro. We only do it for the class
550     * we are working on (i.e no parents). */
551    if (check_consistency)
552      {
553         Eo_Extension_Node *extn;
554
555         Eina_List *itr = extn_pos;
556         EINA_INLIST_FOREACH(klass->extensions, extn)
557           {
558              /* Get the first one after the extension. */
559              Eina_List *extn_list = eina_list_next(eina_list_data_get(itr));
560
561              /* If we found the extension again. */
562              if (eina_list_data_find_list(extn_list, extn->klass))
563                {
564                   eina_list_free(mro);
565                   ERR("Cannot create a consistent method resolution order for class '%s' because of '%s'.", klass->desc->name, extn->klass->desc->name);
566                   return NULL;
567                }
568
569              itr = eina_list_next(itr);
570           }
571      }
572
573
574    mro = _eo_class_mro_add(mro, klass->parent);
575
576    return mro;
577 }
578
579 static Eina_Bool
580 _eo_class_mro_init(Eo_Class *klass)
581 {
582    Eina_List *mro = NULL;
583
584    DBG("Started creating MRO for class '%s'", klass->desc->name);
585    mro = _eo_class_mro_add(mro, klass);
586
587    if (!mro)
588       return EINA_FALSE;
589
590    /* Remove duplicates and make them the right order. */
591      {
592         Eina_List *itr1, *itr2, *itr2n;
593
594         itr1 = eina_list_last(mro);
595         while (itr1)
596           {
597              itr2 = eina_list_prev(itr1);
598
599              while (itr2)
600                {
601                   itr2n = eina_list_prev(itr2);
602
603                   if (eina_list_data_get(itr1) == eina_list_data_get(itr2))
604                     {
605                        mro = eina_list_remove_list(mro, itr2);
606                     }
607
608                   itr2 = itr2n;
609                }
610
611              itr1 = eina_list_prev(itr1);
612           }
613      }
614
615    /* Copy the mro and free the list. */
616      {
617         const Eo_Class *kls_itr;
618         const Eo_Class **mro_itr;
619         klass->mro = calloc(sizeof(*klass->mro), eina_list_count(mro) + 1);
620
621         mro_itr = klass->mro;
622
623         EINA_LIST_FREE(mro, kls_itr)
624           {
625              *(mro_itr++) = kls_itr;
626
627              DBG("Added '%s' to MRO", kls_itr->desc->name);
628           }
629         *(mro_itr) = NULL;
630      }
631
632    DBG("Finished creating MRO for class '%s'", klass->desc->name);
633
634    return EINA_TRUE;
635 }
636
637 static void
638 _eo_class_constructor(Eo_Class *klass)
639 {
640    if (klass->constructed)
641       return;
642
643    klass->constructed = EINA_TRUE;
644
645    if (klass->desc->class_constructor)
646       klass->desc->class_constructor(klass);
647 }
648
649 EAPI void
650 eo_class_funcs_set(Eo_Class *klass, const Eo_Op_Func_Description *func_descs)
651 {
652    EO_MAGIC_RETURN(klass, EO_CLASS_EINA_MAGIC);
653
654    const Eo_Op_Func_Description *itr;
655    itr = func_descs;
656    if (itr)
657      {
658         for ( ; itr->op != 0 ; itr++)
659           {
660              const Eo_Op_Description *op_desc = _eo_op_id_desc_get(itr->op);
661
662              if (EINA_LIKELY(!op_desc || (itr->constant == op_desc->constant)))
663                {
664                   _dich_func_set(klass, itr->op, itr->func);
665                }
666              else
667                {
668                   ERR("Set function's constant property (%d) is different than the one in the op description (%d) for op '%s' in class '%s'.", itr->constant, op_desc->constant, op_desc->name, klass->desc->name);
669                }
670           }
671      }
672 }
673
674 static void
675 eo_class_free(Eo_Class *klass)
676 {
677    if (klass->constructed)
678      {
679         if (klass->desc->class_destructor)
680            klass->desc->class_destructor(klass);
681
682         _dich_func_clean_all(klass);
683      }
684
685      {
686         Eina_Inlist *itrn;
687         Eo_Extension_Node *extn = NULL;
688         EINA_INLIST_FOREACH_SAFE(klass->extensions, itrn, extn)
689           {
690              free(extn);
691           }
692      }
693
694    if (klass->mro)
695       free(klass->mro);
696
697    if (klass->extn_data_off)
698       free(klass->extn_data_off);
699
700    free(klass);
701 }
702
703 /* DEVCHECK */
704 static Eina_Bool
705 _eo_class_check_op_descs(const Eo_Class *klass)
706 {
707    const Eo_Class_Description *desc = klass->desc;
708    const Eo_Op_Description *itr;
709    size_t i;
710
711    if (desc->ops.count > 0)
712      {
713         if (!desc->ops.base_op_id)
714           {
715              ERR("Class '%s' has a non-zero ops count, but base_id is NULL.",
716                    desc->name);
717              return EINA_FALSE;
718           }
719
720         if (!desc->ops.descs)
721           {
722              ERR("Class '%s' has a non-zero ops count, but there are no descs.",
723                    desc->name);
724              return EINA_FALSE;
725           }
726      }
727
728    itr = desc->ops.descs;
729    for (i = 0 ; i < desc->ops.count ; i++, itr++)
730      {
731         if (itr->sub_op != i)
732           {
733              if (itr->name)
734                {
735                   ERR("Wrong order in Ops description for class '%s'. Expected %d and got %d", desc->name, i, itr->sub_op);
736                }
737              else
738                {
739                   ERR("Found too few Ops description for class '%s'. Expected %d descriptions, but found %d.", desc->name, desc->ops.count, i);
740                }
741              return EINA_FALSE;
742           }
743      }
744
745    if (itr && itr->name)
746      {
747         ERR("Found extra Ops description for class '%s'. Expected %d descriptions, but found more.", desc->name, desc->ops.count);
748         return EINA_FALSE;
749      }
750
751    return EINA_TRUE;
752 }
753
754 EAPI const Eo_Class *
755 eo_class_new(const Eo_Class_Description *desc, const Eo_Class *parent, ...)
756 {
757    Eo_Class *klass;
758    va_list p_list;
759
760    if (parent && !EINA_MAGIC_CHECK(parent, EO_CLASS_EINA_MAGIC))
761      {
762         EINA_MAGIC_FAIL(parent, EO_CLASS_EINA_MAGIC);
763         return NULL;
764      }
765
766    va_start(p_list, parent);
767
768    EINA_SAFETY_ON_NULL_RETURN_VAL(desc, NULL);
769    EINA_SAFETY_ON_NULL_RETURN_VAL(desc->name, NULL);
770
771    /* Check restrictions on Interface types. */
772    if (desc->type == EO_CLASS_TYPE_INTERFACE)
773      {
774         EINA_SAFETY_ON_FALSE_RETURN_VAL(!desc->constructor, NULL);
775         EINA_SAFETY_ON_FALSE_RETURN_VAL(!desc->destructor, NULL);
776         EINA_SAFETY_ON_FALSE_RETURN_VAL(!desc->class_constructor, NULL);
777         EINA_SAFETY_ON_FALSE_RETURN_VAL(!desc->class_destructor, NULL);
778         EINA_SAFETY_ON_FALSE_RETURN_VAL(!desc->data_size, NULL);
779      }
780
781    klass = calloc(1, sizeof(Eo_Class));
782    klass->parent = parent;
783
784    /* Handle class extensions */
785      {
786         Eo_Class *extn = NULL;
787
788         extn = va_arg(p_list, Eo_Class *);
789         while (extn)
790           {
791              switch (extn->desc->type)
792                {
793                 case EO_CLASS_TYPE_REGULAR:
794                 case EO_CLASS_TYPE_REGULAR_NO_INSTANT:
795                    /* Use it like an interface. */
796                 case EO_CLASS_TYPE_INTERFACE:
797                    break;
798                 case EO_CLASS_TYPE_MIXIN:
799                      {
800                         Eo_Extension_Node *node = calloc(1, sizeof(*node));
801                         node->klass = extn;
802                         klass->extensions =
803                            eina_inlist_append(klass->extensions,
804                                  EINA_INLIST_GET(node));
805                      }
806                    break;
807                }
808
809              extn = va_arg(p_list, Eo_Class *);
810           }
811      }
812
813    klass->desc = desc;
814
815    /* Handle the inheritance */
816    if (klass->parent)
817      {
818         /* Verify the inheritance is allowed. */
819         switch (klass->desc->type)
820           {
821            case EO_CLASS_TYPE_REGULAR:
822            case EO_CLASS_TYPE_REGULAR_NO_INSTANT:
823               if ((klass->parent->desc->type != EO_CLASS_TYPE_REGULAR) &&
824                     (klass->parent->desc->type != EO_CLASS_TYPE_REGULAR_NO_INSTANT))
825                 {
826                    ERR("Regular classes ('%s') aren't allowed to inherit from non-regular classes ('%s').", klass->desc->name, klass->parent->desc->name);
827                    goto cleanup;
828                 }
829               break;
830            case EO_CLASS_TYPE_INTERFACE:
831            case EO_CLASS_TYPE_MIXIN:
832               if ((klass->parent->desc->type != EO_CLASS_TYPE_INTERFACE) &&
833                     (klass->parent->desc->type != EO_CLASS_TYPE_MIXIN))
834                 {
835                    ERR("Non-regular classes ('%s') aren't allowed to inherit from regular classes ('%s').", klass->desc->name, klass->parent->desc->name);
836                    goto cleanup;
837                 }
838               break;
839           }
840
841
842         /* Update the current offset. */
843         /* FIXME: Make sure this alignment is enough. */
844         klass->data_offset = klass->parent->data_offset +
845            EO_ALIGN_SIZE(klass->parent->desc->data_size);
846      }
847
848    if (!_eo_class_check_op_descs(klass))
849      {
850         goto cleanup;
851      }
852
853    if (!_eo_class_mro_init(klass))
854      {
855         goto cleanup;
856      }
857
858    /* create MIXIN offset table. */
859      {
860         const Eo_Class **mro_itr = klass->mro;
861         Eo_Extension_Data_Offset *extn_data_itr;
862         size_t extn_num = 0;
863         size_t extn_data_off = klass->data_offset +
864            EO_ALIGN_SIZE(klass->desc->data_size);
865
866         /* FIXME: Make faster... */
867         while (*mro_itr)
868           {
869              if (((*mro_itr)->desc->type == EO_CLASS_TYPE_MIXIN) &&
870                    ((*mro_itr)->desc->data_size > 0))
871                {
872                   extn_num++;
873                }
874              mro_itr++;
875           }
876
877         klass->extn_data_off = calloc(extn_num + 1,
878               sizeof(*klass->extn_data_off));
879
880         extn_data_itr = klass->extn_data_off;
881         mro_itr = klass->mro;
882         while (*mro_itr)
883           {
884              if (((*mro_itr)->desc->type == EO_CLASS_TYPE_MIXIN) &&
885                    ((*mro_itr)->desc->data_size > 0))
886                {
887                   extn_data_itr->klass = *mro_itr;
888                   extn_data_itr->offset = extn_data_off;
889
890                   extn_data_off += EO_ALIGN_SIZE(extn_data_itr->klass->desc->data_size);
891                   extn_data_itr++;
892                }
893              mro_itr++;
894           }
895
896         klass->extn_data_size = extn_data_off;
897      }
898
899    eina_lock_take(&_eo_class_creation_lock);
900    klass->class_id = ++_eo_classes_last_id;
901      {
902         /* FIXME: Handle errors. */
903         Eo_Class **tmp;
904         tmp = realloc(_eo_classes, _eo_classes_last_id * sizeof(*_eo_classes));
905         _eo_classes = tmp;
906         _eo_classes[klass->class_id - 1] = klass;
907      }
908    eina_lock_release(&_eo_class_creation_lock);
909
910    EINA_MAGIC_SET(klass, EO_CLASS_EINA_MAGIC);
911
912    /* Flatten the function array */
913      {
914         const Eo_Class **mro_itr = klass->mro;
915         for (  ; *mro_itr ; mro_itr++)
916            ;
917
918         for ( mro_itr-- ; mro_itr >= klass->mro ; mro_itr--)
919           {
920              _dich_copy_all(klass, *mro_itr);
921           }
922      }
923
924    _eo_class_base_op_init(klass);
925
926    _eo_class_constructor(klass);
927
928    va_end(p_list);
929
930    return klass;
931
932 cleanup:
933    eo_class_free(klass);
934    return NULL;
935 }
936
937 EAPI Eo *
938 eo_add(const Eo_Class *klass, Eo *parent)
939 {
940    EO_MAGIC_RETURN_VAL(klass, EO_CLASS_EINA_MAGIC, NULL);
941
942    if (parent) EO_MAGIC_RETURN_VAL(parent, EO_EINA_MAGIC, NULL);
943
944    if (EINA_UNLIKELY(klass->desc->type != EO_CLASS_TYPE_REGULAR))
945      {
946         ERR("Class '%s' is not instantiate-able. Aborting.", klass->desc->name);
947         return NULL;
948      }
949
950    Eo *obj = calloc(1, EO_ALIGN_SIZE(sizeof(*obj)) +
951          (klass->data_offset + EO_ALIGN_SIZE(klass->desc->data_size)) +
952          klass->extn_data_size);
953    obj->klass = klass;
954    obj->parent = parent;
955
956    obj->refcount++;
957
958    Eo_Kls_Itr prev_state;
959
960    _eo_kls_itr_init(obj, EO_NOOP, &prev_state);
961    eo_constructor_error_unset(obj);
962
963    EINA_MAGIC_SET(obj, EO_EINA_MAGIC);
964    _eo_ref(obj);
965    _eo_constructor(obj, klass);
966
967    if (EINA_UNLIKELY(eo_constructor_error_get(obj)))
968      {
969         ERR("Type '%s' - One of the object constructors have failed.", klass->desc->name);
970         goto fail;
971      }
972
973    if (EINA_UNLIKELY(!_eo_kls_itr_reached_end(obj)))
974      {
975         ERR("Type '%s' - Not all of the object constructors have been executed.", klass->desc->name);
976         goto fail;
977      }
978    _eo_kls_itr_end(obj, &prev_state);
979    _eo_unref(obj);
980
981    return obj;
982
983 fail:
984    _eo_kls_itr_end(obj, &prev_state);
985    /* Unref twice, once for the ref above, and once for the basic object ref. */
986    _eo_unref(obj);
987    _eo_unref(obj);
988    return NULL;
989 }
990
991 typedef struct
992 {
993    EINA_INLIST;
994    const Eo *ref_obj;
995    const char *file;
996    int line;
997 } Eo_Xref_Node;
998
999 EAPI Eo *
1000 eo_xref_internal(Eo *obj, const Eo *ref_obj, const char *file, int line)
1001 {
1002    EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, obj);
1003
1004    _eo_ref(obj);
1005
1006 #ifndef NDEBUG
1007    Eo_Xref_Node *xref = calloc(1, sizeof(*xref));
1008    xref->ref_obj = ref_obj;
1009    xref->file = file;
1010    xref->line = line;
1011
1012    /* FIXME: Make it sorted. */
1013    obj->xrefs = eina_inlist_prepend(obj->xrefs, EINA_INLIST_GET(xref));
1014 #else
1015    (void) ref_obj;
1016    (void) file;
1017    (void) line;
1018 #endif
1019
1020    return obj;
1021 }
1022
1023 EAPI void
1024 eo_xunref(Eo *obj, const Eo *ref_obj)
1025 {
1026    EO_MAGIC_RETURN(obj, EO_EINA_MAGIC);
1027 #ifndef NDEBUG
1028    Eo_Xref_Node *xref = NULL;
1029    EINA_INLIST_FOREACH(obj->xrefs, xref)
1030      {
1031         if (xref->ref_obj == ref_obj)
1032            break;
1033      }
1034
1035    if (xref)
1036      {
1037         obj->xrefs = eina_inlist_remove(obj->xrefs, EINA_INLIST_GET(xref));
1038         free(xref);
1039      }
1040    else
1041      {
1042         ERR("ref_obj (%p) does not reference obj (%p). Aborting unref.", ref_obj, obj);
1043         return;
1044      }
1045 #else
1046    (void) ref_obj;
1047 #endif
1048    _eo_unref(obj);
1049 }
1050
1051 static inline Eo *
1052 _eo_ref(Eo *obj)
1053 {
1054    obj->refcount++;
1055    return obj;
1056 }
1057
1058 EAPI Eo *
1059 eo_ref(Eo *obj)
1060 {
1061    EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, obj);
1062
1063    return _eo_ref(obj);
1064 }
1065
1066 static void
1067 _eo_del_internal(Eo *obj)
1068 {
1069    if (obj->del)
1070       return;
1071    /* We need that for the event callbacks that may ref/unref. */
1072    obj->refcount++;
1073
1074    eo_event_callback_call(obj, EO_EV_DEL, NULL);
1075    obj->del = EINA_TRUE;
1076
1077    const Eo_Class *klass = eo_class_get(obj);
1078    Eo_Kls_Itr prev_state;
1079
1080    _eo_kls_itr_init(obj, EO_NOOP, &prev_state);
1081    eo_constructor_error_unset(obj);
1082    _eo_destructor(obj, klass);
1083    if (eo_constructor_error_get(obj))
1084      {
1085         ERR("Type '%s' - One of the object destructors have failed.", klass->desc->name);
1086      }
1087
1088    if (!_eo_kls_itr_reached_end(obj))
1089      {
1090         ERR("Type '%s' - Not all of the object destructors have been executed.", klass->desc->name);
1091      }
1092    _eo_kls_itr_end(obj, &prev_state);
1093    /*FIXME: add eo_class_unref(klass) ? - just to clear the caches. */
1094
1095    Eina_List *itr, *itr_n;
1096    Eo *emb_obj;
1097    EINA_LIST_FOREACH_SAFE(obj->composite_objects, itr, itr_n, emb_obj)
1098      {
1099         eo_composite_object_detach(obj, emb_obj);
1100      }
1101
1102    obj->refcount--;
1103 }
1104
1105 static inline void
1106 _eo_unref(Eo *obj)
1107 {
1108    if (--(obj->refcount) == 0)
1109      {
1110         _eo_del_internal(obj);
1111         /* We need that for the event callbacks that may ref/unref. */
1112         obj->refcount++;
1113
1114         eo_event_callback_call(obj, EO_EV_FREE, NULL);
1115
1116         obj->refcount--;
1117
1118 #ifndef NDEBUG
1119    /* If for some reason it's not empty, clear it. */
1120    while (obj->xrefs)
1121      {
1122         WRN("obj->xrefs is not empty, possibly a bug, please report. - An error will be reported for each xref in the stack.");
1123         Eina_Inlist *nitr = obj->xrefs->next;
1124         free(EINA_INLIST_CONTAINER_GET(obj->xrefs, Eo_Xref_Node));
1125         obj->xrefs = nitr;
1126      }
1127 #endif
1128
1129         _eo_callback_remove_all(obj);
1130
1131         free(obj);
1132      }
1133 }
1134
1135 EAPI void
1136 eo_unref(Eo *obj)
1137 {
1138    EO_MAGIC_RETURN(obj, EO_EINA_MAGIC);
1139
1140    _eo_unref(obj);
1141 }
1142
1143 EAPI int
1144 eo_ref_get(const Eo *obj)
1145 {
1146    EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, 0);
1147
1148    return obj->refcount;
1149 }
1150
1151 EAPI void
1152 eo_del(Eo *obj)
1153 {
1154    EO_MAGIC_RETURN(obj, EO_EINA_MAGIC);
1155
1156    _eo_del_internal(obj);
1157    _eo_unref(obj);
1158 }
1159
1160 EAPI Eo *
1161 eo_parent_get(const Eo *obj)
1162 {
1163    EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, NULL);
1164
1165    return obj->parent;
1166 }
1167
1168 EAPI void
1169 eo_constructor_error_set(Eo *obj)
1170 {
1171    EO_MAGIC_RETURN(obj, EO_EINA_MAGIC);
1172
1173    obj->construct_error = EINA_TRUE;
1174 }
1175
1176 static void
1177 eo_constructor_error_unset(Eo *obj)
1178 {
1179    obj->construct_error = EINA_FALSE;
1180 }
1181
1182 EAPI Eina_Bool
1183 eo_constructor_error_get(const Eo *obj)
1184 {
1185    EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, EINA_TRUE);
1186
1187    return obj->construct_error;
1188 }
1189
1190 static inline void
1191 _eo_constructor_default(Eo *obj)
1192 {
1193    eo_constructor_super(obj);
1194 }
1195
1196 static inline void
1197 _eo_destructor_default(Eo *obj)
1198 {
1199    eo_destructor_super(obj);
1200 }
1201
1202 static void
1203 _eo_constructor(Eo *obj, const Eo_Class *klass)
1204 {
1205    if (!klass)
1206       return;
1207
1208    if (klass->desc->constructor)
1209       klass->desc->constructor(obj, _eo_data_get(obj, klass));
1210    else
1211       _eo_constructor_default(obj);
1212 }
1213
1214 static void
1215 _eo_destructor(Eo *obj, const Eo_Class *klass)
1216 {
1217    if (!klass)
1218       return;
1219
1220    if (klass->desc->destructor)
1221       klass->desc->destructor(obj, _eo_data_get(obj, klass));
1222    else
1223       _eo_destructor_default(obj);
1224 }
1225
1226 EAPI void
1227 eo_constructor_super(Eo *obj)
1228 {
1229    EO_MAGIC_RETURN(obj, EO_EINA_MAGIC);
1230
1231    _eo_constructor(obj, _eo_kls_itr_next(obj, EO_NOOP));
1232 }
1233
1234 EAPI void
1235 eo_destructor_super(Eo *obj)
1236 {
1237    EO_MAGIC_RETURN(obj, EO_EINA_MAGIC);
1238
1239    _eo_destructor(obj, _eo_kls_itr_next(obj, EO_NOOP));
1240 }
1241
1242 static inline void *
1243 _eo_data_get(const Eo *obj, const Eo_Class *klass)
1244 {
1245    if (EINA_LIKELY(klass->desc->data_size > 0))
1246      {
1247         if (EINA_UNLIKELY(klass->desc->type == EO_CLASS_TYPE_MIXIN))
1248           {
1249              Eo_Extension_Data_Offset *doff_itr =
1250                 eo_class_get(obj)->extn_data_off;
1251
1252              if (!doff_itr)
1253                 return NULL;
1254
1255              while (doff_itr->klass)
1256                {
1257                   if (doff_itr->klass == klass)
1258                      return ((char *) obj) + EO_ALIGN_SIZE(sizeof(*obj)) +
1259                            doff_itr->offset;
1260                   doff_itr++;
1261                }
1262           }
1263         else
1264           {
1265           return ((char *) obj) + EO_ALIGN_SIZE(sizeof(*obj)) +
1266              klass->data_offset;
1267           }
1268      }
1269
1270    return NULL;
1271 }
1272
1273 EAPI void *
1274 eo_data_get(const Eo *obj, const Eo_Class *klass)
1275 {
1276    void *ret;
1277    EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, NULL);
1278
1279 #ifndef NDEBUG
1280    if (!_eo_class_mro_has(obj->klass, klass))
1281      {
1282         ERR("Tried getting data of class '%s' from object of class '%s', but the former is not a direct inheritance of the latter.", klass->desc->name, obj->klass->desc->name);
1283         return NULL;
1284      }
1285 #endif
1286
1287    ret = _eo_data_get(obj, klass);
1288
1289    if (!ret && (klass->desc->data_size == 0))
1290      {
1291         ERR("Tried getting data of class '%s', but it has none..", klass->desc->name);
1292      }
1293
1294    return ret;
1295 }
1296
1297 EAPI Eina_Bool
1298 eo_init(void)
1299 {
1300    const char *log_dom = "eo";
1301    if (_eo_init_count++ > 0)
1302       return EINA_TRUE;
1303
1304    eina_init();
1305
1306    _eo_classes = NULL;
1307    _eo_classes_last_id = 0;
1308    _eo_log_dom = eina_log_domain_register(log_dom, EINA_COLOR_LIGHTBLUE);
1309    if (_eo_log_dom < 0)
1310      {
1311         EINA_LOG_ERR("Could not register log domain: %s", log_dom);
1312         return EINA_FALSE;
1313      }
1314
1315    if (!eina_lock_new(&_eo_class_creation_lock))
1316      {
1317         EINA_LOG_ERR("Could not init lock.");
1318         return EINA_FALSE;
1319      }
1320
1321    eina_magic_string_static_set(EO_EINA_MAGIC, EO_EINA_MAGIC_STR);
1322    eina_magic_string_static_set(EO_CLASS_EINA_MAGIC,
1323          EO_CLASS_EINA_MAGIC_STR);
1324
1325    return EINA_TRUE;
1326 }
1327
1328 EAPI Eina_Bool
1329 eo_shutdown(void)
1330 {
1331    size_t i;
1332    Eo_Class **cls_itr = _eo_classes;
1333
1334    if (--_eo_init_count > 0)
1335       return EINA_TRUE;
1336
1337    for (i = 0 ; i < _eo_classes_last_id ; i++, cls_itr++)
1338      {
1339         if (*cls_itr)
1340            eo_class_free(*cls_itr);
1341      }
1342
1343    if (_eo_classes)
1344       free(_eo_classes);
1345
1346    eina_lock_free(&_eo_class_creation_lock);
1347
1348    eina_log_domain_unregister(_eo_log_dom);
1349    _eo_log_dom = -1;
1350
1351    eina_shutdown();
1352    return EINA_TRUE;
1353 }
1354
1355 EAPI void
1356 eo_composite_object_attach(Eo *obj, Eo *emb_obj)
1357 {
1358    EO_MAGIC_RETURN(obj, EO_EINA_MAGIC);
1359    EO_MAGIC_RETURN(emb_obj, EO_EINA_MAGIC);
1360
1361    eo_xref(emb_obj, obj);
1362    obj->composite_objects = eina_list_prepend(obj->composite_objects, emb_obj);
1363 }
1364
1365 EAPI void
1366 eo_composite_object_detach(Eo *obj, Eo *emb_obj)
1367 {
1368    EO_MAGIC_RETURN(obj, EO_EINA_MAGIC);
1369    EO_MAGIC_RETURN(emb_obj, EO_EINA_MAGIC);
1370
1371    obj->composite_objects = eina_list_remove(obj->composite_objects, emb_obj);
1372    eo_xunref(emb_obj, obj);
1373 }
1374
1375 EAPI Eina_Bool
1376 eo_composite_is(Eo *emb_obj)
1377 {
1378    if (!EINA_MAGIC_CHECK(emb_obj, EO_EINA_MAGIC))
1379      {
1380         EINA_MAGIC_FAIL(emb_obj, EO_EINA_MAGIC);
1381         return EINA_FALSE;
1382      }
1383
1384    Eo *obj = eo_parent_get(emb_obj);
1385    Eina_List *itr;
1386    Eo *tmp;
1387
1388    if (!obj)
1389       return EINA_FALSE;
1390
1391    EINA_LIST_FOREACH(obj->composite_objects, itr, tmp)
1392      {
1393         if (tmp == emb_obj)
1394            return EINA_TRUE;
1395      }
1396
1397    return EINA_FALSE;
1398 }
1399
1400 /* Callbacks */
1401 struct _Eo_Callback_Description
1402 {
1403    EINA_INLIST;
1404    const Eo_Event_Description *event;
1405    Eo_Event_Cb func;
1406    void *func_data;
1407    Eo_Callback_Priority priority;
1408    Eina_Bool delete_me : 1;
1409 };
1410
1411 /* Actually remove, doesn't care about walking list, or delete_me */
1412 static void
1413 _eo_callback_remove(Eo *obj, Eo_Callback_Description *cb)
1414 {
1415    obj->callbacks = eina_inlist_remove(obj->callbacks,
1416          EINA_INLIST_GET(cb));
1417    free(cb);
1418 }
1419
1420 /* Actually remove, doesn't care about walking list, or delete_me */
1421 static void
1422 _eo_callback_remove_all(Eo *obj)
1423 {
1424    Eina_Inlist *initr;
1425    Eo_Callback_Description *cb = NULL;
1426    EINA_INLIST_FOREACH_SAFE(obj->callbacks, initr, cb)
1427      {
1428         _eo_callback_remove(obj, cb);
1429      }
1430 }
1431
1432 static void
1433 _eo_callbacks_clear(Eo *obj)
1434 {
1435    Eina_Inlist *itn;
1436    Eo_Callback_Description *cb = NULL;
1437
1438    /* Abort if we are currently walking the list. */
1439    if (obj->walking_list > 0)
1440       return;
1441
1442    EINA_INLIST_FOREACH_SAFE(obj->callbacks, itn, cb)
1443      {
1444         if (cb->delete_me)
1445           {
1446              _eo_callback_remove(obj, cb);
1447           }
1448      }
1449 }
1450
1451 static int
1452 _callback_priority_cmp(const void *_a, const void *_b)
1453 {
1454    const Eo_Callback_Description *a, *b;
1455    a = (const Eo_Callback_Description *) _a;
1456    b = (const Eo_Callback_Description *) _b;
1457    if (a->priority < b->priority)
1458       return -1;
1459    else
1460       return 1;
1461 }
1462
1463 EAPI Eina_Bool
1464 eo_event_callback_priority_add(Eo *obj,
1465       const Eo_Event_Description *desc,
1466       Eo_Callback_Priority priority,
1467       Eo_Event_Cb func,
1468       const void *data)
1469 {
1470    EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, EINA_FALSE);
1471
1472    Eo_Callback_Description *cb = calloc(1, sizeof(*cb));
1473    cb->event = desc;
1474    cb->func = func;
1475    cb->func_data = (void *) data;
1476    cb->priority = priority;
1477    obj->callbacks = eina_inlist_sorted_insert(obj->callbacks,
1478          EINA_INLIST_GET(cb), _callback_priority_cmp);
1479
1480    eo_event_callback_call(obj, EO_EV_CALLBACK_ADD, desc);
1481
1482    return EINA_TRUE;
1483 }
1484
1485 EAPI void *
1486 eo_event_callback_del_lazy(Eo *obj, const Eo_Event_Description *desc, Eo_Event_Cb func)
1487 {
1488    EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, NULL);
1489
1490    void *ret = NULL;
1491    Eo_Callback_Description *cb;
1492    EINA_INLIST_FOREACH(obj->callbacks, cb)
1493      {
1494         if ((cb->event == desc) && (cb->func == func))
1495           {
1496              void *data;
1497
1498              data = cb->func_data;
1499              cb->delete_me = EINA_TRUE;
1500              _eo_callbacks_clear(obj);
1501              ret = data;
1502              goto found;
1503           }
1504      }
1505
1506    return NULL;
1507
1508 found:
1509    eo_event_callback_call(obj, EO_EV_CALLBACK_DEL, desc);
1510    return ret;
1511 }
1512
1513 EAPI void *
1514 eo_event_callback_del(Eo *obj, const Eo_Event_Description *desc, Eo_Event_Cb func, const void *user_data)
1515 {
1516    EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, NULL);
1517
1518    void *ret = NULL;
1519    Eo_Callback_Description *cb;
1520    EINA_INLIST_FOREACH(obj->callbacks, cb)
1521      {
1522         if ((cb->event == desc) && (cb->func == func) &&
1523               (cb->func_data == user_data))
1524           {
1525              void *data;
1526
1527              data = cb->func_data;
1528              cb->delete_me = EINA_TRUE;
1529              _eo_callbacks_clear(obj);
1530              ret = data;
1531              goto found;
1532           }
1533      }
1534
1535    return NULL;
1536
1537 found:
1538    eo_event_callback_call(obj, EO_EV_CALLBACK_DEL, desc);
1539    return ret;
1540 }
1541
1542 EAPI Eina_Bool
1543 eo_event_callback_call(Eo *obj, const Eo_Event_Description *desc,
1544       const void *event_info)
1545 {
1546    EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, EINA_FALSE);
1547
1548    Eina_Bool ret = EINA_TRUE;
1549    Eo_Callback_Description *cb;
1550
1551    _eo_ref(obj);
1552    obj->walking_list++;
1553
1554    EINA_INLIST_FOREACH(obj->callbacks, cb)
1555      {
1556         if (!cb->delete_me && (cb->event == desc))
1557           {
1558              /* Abort callback calling if the func says so. */
1559              if (!cb->func((void *) cb->func_data, obj, desc,
1560                       (void *) event_info))
1561                {
1562                   ret = EINA_FALSE;
1563                   break;
1564                }
1565           }
1566         if (obj->del)
1567           break;
1568      }
1569    obj->walking_list--;
1570    _eo_callbacks_clear(obj);
1571    _eo_unref(obj);
1572
1573    return ret;
1574 }
1575
1576 static Eina_Bool
1577 _eo_event_forwarder_callback(void *data, Eo *obj, const Eo_Event_Description *desc, void *event_info)
1578 {
1579    (void) obj;
1580    Eo *new_obj = (Eo *) data;
1581    return eo_event_callback_call(new_obj, desc, event_info);
1582 }
1583
1584 /* FIXME: Change default priority? Maybe call later? */
1585 EAPI Eina_Bool
1586 eo_event_callback_forwarder_add(Eo *obj, const Eo_Event_Description *desc, Eo *new_obj)
1587 {
1588    EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, EINA_FALSE);
1589    EO_MAGIC_RETURN_VAL(new_obj, EO_EINA_MAGIC, EINA_FALSE);
1590
1591    return eo_event_callback_add(obj, desc, _eo_event_forwarder_callback, new_obj);
1592 }
1593
1594 EAPI Eina_Bool
1595 eo_event_callback_forwarder_del(Eo *obj, const Eo_Event_Description *desc, Eo *new_obj)
1596 {
1597    EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, EINA_FALSE);
1598    EO_MAGIC_RETURN_VAL(new_obj, EO_EINA_MAGIC, EINA_FALSE);
1599
1600    eo_event_callback_del(obj, desc, _eo_event_forwarder_callback, new_obj);
1601    return EINA_TRUE;
1602 }
1603