Eo: Added a new magic type to mark already deleted objects.
[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         /* We need that for the event callbacks that may ref/unref. */
1114         obj->refcount++;
1115
1116         eo_event_callback_call(obj, EO_EV_FREE, NULL);
1117
1118         obj->refcount--;
1119
1120 #ifndef NDEBUG
1121    /* If for some reason it's not empty, clear it. */
1122    while (obj->xrefs)
1123      {
1124         WRN("obj->xrefs is not empty, possibly a bug, please report. - An error will be reported for each xref in the stack.");
1125         Eina_Inlist *nitr = obj->xrefs->next;
1126         free(EINA_INLIST_CONTAINER_GET(obj->xrefs, Eo_Xref_Node));
1127         obj->xrefs = nitr;
1128      }
1129 #endif
1130
1131         _eo_callback_remove_all(obj);
1132
1133         EINA_MAGIC_SET(obj, EO_DELETED_EINA_MAGIC);
1134         free(obj);
1135      }
1136 }
1137
1138 EAPI void
1139 eo_unref(Eo *obj)
1140 {
1141    EO_MAGIC_RETURN(obj, EO_EINA_MAGIC);
1142
1143    _eo_unref(obj);
1144 }
1145
1146 EAPI int
1147 eo_ref_get(const Eo *obj)
1148 {
1149    EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, 0);
1150
1151    return obj->refcount;
1152 }
1153
1154 EAPI void
1155 eo_del(Eo *obj)
1156 {
1157    EO_MAGIC_RETURN(obj, EO_EINA_MAGIC);
1158
1159    _eo_del_internal(obj);
1160    _eo_unref(obj);
1161 }
1162
1163 EAPI Eo *
1164 eo_parent_get(const Eo *obj)
1165 {
1166    EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, NULL);
1167
1168    return obj->parent;
1169 }
1170
1171 EAPI void
1172 eo_constructor_error_set(Eo *obj)
1173 {
1174    EO_MAGIC_RETURN(obj, EO_EINA_MAGIC);
1175
1176    obj->construct_error = EINA_TRUE;
1177 }
1178
1179 static void
1180 eo_constructor_error_unset(Eo *obj)
1181 {
1182    obj->construct_error = EINA_FALSE;
1183 }
1184
1185 EAPI Eina_Bool
1186 eo_constructor_error_get(const Eo *obj)
1187 {
1188    EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, EINA_TRUE);
1189
1190    return obj->construct_error;
1191 }
1192
1193 static inline void
1194 _eo_constructor_default(Eo *obj)
1195 {
1196    eo_constructor_super(obj);
1197 }
1198
1199 static inline void
1200 _eo_destructor_default(Eo *obj)
1201 {
1202    eo_destructor_super(obj);
1203 }
1204
1205 static void
1206 _eo_constructor(Eo *obj, const Eo_Class *klass)
1207 {
1208    if (!klass)
1209       return;
1210
1211    if (klass->desc->constructor)
1212       klass->desc->constructor(obj, _eo_data_get(obj, klass));
1213    else
1214       _eo_constructor_default(obj);
1215 }
1216
1217 static void
1218 _eo_destructor(Eo *obj, const Eo_Class *klass)
1219 {
1220    if (!klass)
1221       return;
1222
1223    if (klass->desc->destructor)
1224       klass->desc->destructor(obj, _eo_data_get(obj, klass));
1225    else
1226       _eo_destructor_default(obj);
1227 }
1228
1229 EAPI void
1230 eo_constructor_super(Eo *obj)
1231 {
1232    EO_MAGIC_RETURN(obj, EO_EINA_MAGIC);
1233
1234    _eo_constructor(obj, _eo_kls_itr_next(obj, EO_NOOP));
1235 }
1236
1237 EAPI void
1238 eo_destructor_super(Eo *obj)
1239 {
1240    EO_MAGIC_RETURN(obj, EO_EINA_MAGIC);
1241
1242    _eo_destructor(obj, _eo_kls_itr_next(obj, EO_NOOP));
1243 }
1244
1245 static inline void *
1246 _eo_data_get(const Eo *obj, const Eo_Class *klass)
1247 {
1248    if (EINA_LIKELY(klass->desc->data_size > 0))
1249      {
1250         if (EINA_UNLIKELY(klass->desc->type == EO_CLASS_TYPE_MIXIN))
1251           {
1252              Eo_Extension_Data_Offset *doff_itr =
1253                 eo_class_get(obj)->extn_data_off;
1254
1255              if (!doff_itr)
1256                 return NULL;
1257
1258              while (doff_itr->klass)
1259                {
1260                   if (doff_itr->klass == klass)
1261                      return ((char *) obj) + EO_ALIGN_SIZE(sizeof(*obj)) +
1262                            doff_itr->offset;
1263                   doff_itr++;
1264                }
1265           }
1266         else
1267           {
1268           return ((char *) obj) + EO_ALIGN_SIZE(sizeof(*obj)) +
1269              klass->data_offset;
1270           }
1271      }
1272
1273    return NULL;
1274 }
1275
1276 EAPI void *
1277 eo_data_get(const Eo *obj, const Eo_Class *klass)
1278 {
1279    void *ret;
1280    EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, NULL);
1281
1282 #ifndef NDEBUG
1283    if (!_eo_class_mro_has(obj->klass, klass))
1284      {
1285         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);
1286         return NULL;
1287      }
1288 #endif
1289
1290    ret = _eo_data_get(obj, klass);
1291
1292    if (!ret && (klass->desc->data_size == 0))
1293      {
1294         ERR("Tried getting data of class '%s', but it has none..", klass->desc->name);
1295      }
1296
1297    return ret;
1298 }
1299
1300 EAPI Eina_Bool
1301 eo_init(void)
1302 {
1303    const char *log_dom = "eo";
1304    if (_eo_init_count++ > 0)
1305       return EINA_TRUE;
1306
1307    eina_init();
1308
1309    _eo_classes = NULL;
1310    _eo_classes_last_id = 0;
1311    _eo_log_dom = eina_log_domain_register(log_dom, EINA_COLOR_LIGHTBLUE);
1312    if (_eo_log_dom < 0)
1313      {
1314         EINA_LOG_ERR("Could not register log domain: %s", log_dom);
1315         return EINA_FALSE;
1316      }
1317
1318    if (!eina_lock_new(&_eo_class_creation_lock))
1319      {
1320         EINA_LOG_ERR("Could not init lock.");
1321         return EINA_FALSE;
1322      }
1323
1324    eina_magic_string_static_set(EO_EINA_MAGIC, EO_EINA_MAGIC_STR);
1325    eina_magic_string_static_set(EO_DELETED_EINA_MAGIC,
1326          EO_DELETED_EINA_MAGIC_STR);
1327    eina_magic_string_static_set(EO_CLASS_EINA_MAGIC,
1328          EO_CLASS_EINA_MAGIC_STR);
1329
1330    return EINA_TRUE;
1331 }
1332
1333 EAPI Eina_Bool
1334 eo_shutdown(void)
1335 {
1336    size_t i;
1337    Eo_Class **cls_itr = _eo_classes;
1338
1339    if (--_eo_init_count > 0)
1340       return EINA_TRUE;
1341
1342    for (i = 0 ; i < _eo_classes_last_id ; i++, cls_itr++)
1343      {
1344         if (*cls_itr)
1345            eo_class_free(*cls_itr);
1346      }
1347
1348    if (_eo_classes)
1349       free(_eo_classes);
1350
1351    eina_lock_free(&_eo_class_creation_lock);
1352
1353    eina_log_domain_unregister(_eo_log_dom);
1354    _eo_log_dom = -1;
1355
1356    eina_shutdown();
1357    return EINA_TRUE;
1358 }
1359
1360 EAPI void
1361 eo_composite_object_attach(Eo *obj, Eo *emb_obj)
1362 {
1363    EO_MAGIC_RETURN(obj, EO_EINA_MAGIC);
1364    EO_MAGIC_RETURN(emb_obj, EO_EINA_MAGIC);
1365
1366    eo_xref(emb_obj, obj);
1367    obj->composite_objects = eina_list_prepend(obj->composite_objects, emb_obj);
1368 }
1369
1370 EAPI void
1371 eo_composite_object_detach(Eo *obj, Eo *emb_obj)
1372 {
1373    EO_MAGIC_RETURN(obj, EO_EINA_MAGIC);
1374    EO_MAGIC_RETURN(emb_obj, EO_EINA_MAGIC);
1375
1376    obj->composite_objects = eina_list_remove(obj->composite_objects, emb_obj);
1377    eo_xunref(emb_obj, obj);
1378 }
1379
1380 EAPI Eina_Bool
1381 eo_composite_is(Eo *emb_obj)
1382 {
1383    if (!EINA_MAGIC_CHECK(emb_obj, EO_EINA_MAGIC))
1384      {
1385         EINA_MAGIC_FAIL(emb_obj, EO_EINA_MAGIC);
1386         return EINA_FALSE;
1387      }
1388
1389    Eo *obj = eo_parent_get(emb_obj);
1390    Eina_List *itr;
1391    Eo *tmp;
1392
1393    if (!obj)
1394       return EINA_FALSE;
1395
1396    EINA_LIST_FOREACH(obj->composite_objects, itr, tmp)
1397      {
1398         if (tmp == emb_obj)
1399            return EINA_TRUE;
1400      }
1401
1402    return EINA_FALSE;
1403 }
1404
1405 /* Callbacks */
1406 struct _Eo_Callback_Description
1407 {
1408    EINA_INLIST;
1409    const Eo_Event_Description *event;
1410    Eo_Event_Cb func;
1411    void *func_data;
1412    Eo_Callback_Priority priority;
1413    Eina_Bool delete_me : 1;
1414 };
1415
1416 /* Actually remove, doesn't care about walking list, or delete_me */
1417 static void
1418 _eo_callback_remove(Eo *obj, Eo_Callback_Description *cb)
1419 {
1420    obj->callbacks = eina_inlist_remove(obj->callbacks,
1421          EINA_INLIST_GET(cb));
1422    free(cb);
1423 }
1424
1425 /* Actually remove, doesn't care about walking list, or delete_me */
1426 static void
1427 _eo_callback_remove_all(Eo *obj)
1428 {
1429    Eina_Inlist *initr;
1430    Eo_Callback_Description *cb = NULL;
1431    EINA_INLIST_FOREACH_SAFE(obj->callbacks, initr, cb)
1432      {
1433         _eo_callback_remove(obj, cb);
1434      }
1435 }
1436
1437 static void
1438 _eo_callbacks_clear(Eo *obj)
1439 {
1440    Eina_Inlist *itn;
1441    Eo_Callback_Description *cb = NULL;
1442
1443    /* Abort if we are currently walking the list. */
1444    if (obj->walking_list > 0)
1445       return;
1446
1447    EINA_INLIST_FOREACH_SAFE(obj->callbacks, itn, cb)
1448      {
1449         if (cb->delete_me)
1450           {
1451              _eo_callback_remove(obj, cb);
1452           }
1453      }
1454 }
1455
1456 static int
1457 _callback_priority_cmp(const void *_a, const void *_b)
1458 {
1459    const Eo_Callback_Description *a, *b;
1460    a = (const Eo_Callback_Description *) _a;
1461    b = (const Eo_Callback_Description *) _b;
1462    if (a->priority < b->priority)
1463       return -1;
1464    else
1465       return 1;
1466 }
1467
1468 EAPI Eina_Bool
1469 eo_event_callback_priority_add(Eo *obj,
1470       const Eo_Event_Description *desc,
1471       Eo_Callback_Priority priority,
1472       Eo_Event_Cb func,
1473       const void *data)
1474 {
1475    EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, EINA_FALSE);
1476
1477    Eo_Callback_Description *cb = calloc(1, sizeof(*cb));
1478    cb->event = desc;
1479    cb->func = func;
1480    cb->func_data = (void *) data;
1481    cb->priority = priority;
1482    obj->callbacks = eina_inlist_sorted_insert(obj->callbacks,
1483          EINA_INLIST_GET(cb), _callback_priority_cmp);
1484
1485    eo_event_callback_call(obj, EO_EV_CALLBACK_ADD, desc);
1486
1487    return EINA_TRUE;
1488 }
1489
1490 EAPI void *
1491 eo_event_callback_del_lazy(Eo *obj, const Eo_Event_Description *desc, Eo_Event_Cb func)
1492 {
1493    EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, NULL);
1494
1495    void *ret = NULL;
1496    Eo_Callback_Description *cb;
1497    EINA_INLIST_FOREACH(obj->callbacks, cb)
1498      {
1499         if ((cb->event == desc) && (cb->func == func))
1500           {
1501              void *data;
1502
1503              data = cb->func_data;
1504              cb->delete_me = EINA_TRUE;
1505              _eo_callbacks_clear(obj);
1506              ret = data;
1507              goto found;
1508           }
1509      }
1510
1511    return NULL;
1512
1513 found:
1514    eo_event_callback_call(obj, EO_EV_CALLBACK_DEL, desc);
1515    return ret;
1516 }
1517
1518 EAPI void *
1519 eo_event_callback_del(Eo *obj, const Eo_Event_Description *desc, Eo_Event_Cb func, const void *user_data)
1520 {
1521    EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, NULL);
1522
1523    void *ret = NULL;
1524    Eo_Callback_Description *cb;
1525    EINA_INLIST_FOREACH(obj->callbacks, cb)
1526      {
1527         if ((cb->event == desc) && (cb->func == func) &&
1528               (cb->func_data == user_data))
1529           {
1530              void *data;
1531
1532              data = cb->func_data;
1533              cb->delete_me = EINA_TRUE;
1534              _eo_callbacks_clear(obj);
1535              ret = data;
1536              goto found;
1537           }
1538      }
1539
1540    return NULL;
1541
1542 found:
1543    eo_event_callback_call(obj, EO_EV_CALLBACK_DEL, desc);
1544    return ret;
1545 }
1546
1547 EAPI Eina_Bool
1548 eo_event_callback_call(Eo *obj, const Eo_Event_Description *desc,
1549       const void *event_info)
1550 {
1551    EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, EINA_FALSE);
1552
1553    Eina_Bool ret = EINA_TRUE;
1554    Eo_Callback_Description *cb;
1555
1556    _eo_ref(obj);
1557    obj->walking_list++;
1558
1559    EINA_INLIST_FOREACH(obj->callbacks, cb)
1560      {
1561         if (!cb->delete_me && (cb->event == desc))
1562           {
1563              /* Abort callback calling if the func says so. */
1564              if (!cb->func((void *) cb->func_data, obj, desc,
1565                       (void *) event_info))
1566                {
1567                   ret = EINA_FALSE;
1568                   break;
1569                }
1570           }
1571         if (obj->del)
1572           break;
1573      }
1574    obj->walking_list--;
1575    _eo_callbacks_clear(obj);
1576    _eo_unref(obj);
1577
1578    return ret;
1579 }
1580
1581 static Eina_Bool
1582 _eo_event_forwarder_callback(void *data, Eo *obj, const Eo_Event_Description *desc, void *event_info)
1583 {
1584    (void) obj;
1585    Eo *new_obj = (Eo *) data;
1586    return eo_event_callback_call(new_obj, desc, event_info);
1587 }
1588
1589 /* FIXME: Change default priority? Maybe call later? */
1590 EAPI Eina_Bool
1591 eo_event_callback_forwarder_add(Eo *obj, const Eo_Event_Description *desc, Eo *new_obj)
1592 {
1593    EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, EINA_FALSE);
1594    EO_MAGIC_RETURN_VAL(new_obj, EO_EINA_MAGIC, EINA_FALSE);
1595
1596    return eo_event_callback_add(obj, desc, _eo_event_forwarder_callback, new_obj);
1597 }
1598
1599 EAPI Eina_Bool
1600 eo_event_callback_forwarder_del(Eo *obj, const Eo_Event_Description *desc, Eo *new_obj)
1601 {
1602    EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, EINA_FALSE);
1603    EO_MAGIC_RETURN_VAL(new_obj, EO_EINA_MAGIC, EINA_FALSE);
1604
1605    eo_event_callback_del(obj, desc, _eo_event_forwarder_callback, new_obj);
1606    return EINA_TRUE;
1607 }
1608