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