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