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