evas: make evas_object_smart_type_check more resilient.
[profile/ivi/evas.git] / src / lib / canvas / evas_object_smart.c
1 #include "evas_common.h"
2 #include "evas_private.h"
3
4 typedef struct _Evas_Object_Smart      Evas_Object_Smart;
5 typedef struct _Evas_Smart_Callback    Evas_Smart_Callback;
6
7 struct _Evas_Object_Smart
8 {
9    DATA32            magic;
10    void             *engine_data;
11    void             *data;
12    Eina_List        *callbacks;
13    Eina_Inlist      *contained;
14    Evas_Smart_Cb_Description_Array callbacks_descriptions;
15    int               walking_list;
16    int               member_count;
17    Eina_Bool         deletions_waiting : 1;
18    Eina_Bool         need_recalculate : 1;
19    Eina_Bool         update_boundingbox_needed : 1;
20 };
21
22 struct _Evas_Smart_Callback
23 {
24    const char *event;
25    Evas_Smart_Cb func;
26    void *func_data;
27    Evas_Callback_Priority priority;
28    char  delete_me : 1;
29 };
30
31 /* private methods for smart objects */
32 static void evas_object_smart_callbacks_clear(Evas_Object *obj);
33 static void evas_object_smart_init(Evas_Object *obj);
34 static void *evas_object_smart_new(void);
35 static void evas_object_smart_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y);
36 static void evas_object_smart_free(Evas_Object *obj);
37 static void evas_object_smart_render_pre(Evas_Object *obj);
38 static void evas_object_smart_render_post(Evas_Object *obj);
39
40 static unsigned int evas_object_smart_id_get(Evas_Object *obj);
41 static unsigned int evas_object_smart_visual_id_get(Evas_Object *obj);
42 static void *evas_object_smart_engine_data_get(Evas_Object *obj);
43
44 static const Evas_Object_Func object_func =
45 {
46    /* methods (compulsory) */
47    evas_object_smart_free,
48    evas_object_smart_render,
49    evas_object_smart_render_pre,
50    evas_object_smart_render_post,
51    evas_object_smart_id_get,
52    evas_object_smart_visual_id_get,
53    evas_object_smart_engine_data_get,
54    /* these are optional. NULL = nothing */
55    NULL,
56    NULL,
57    NULL,
58    NULL,
59    NULL,
60    NULL,
61    NULL,
62    NULL,
63    NULL,
64    NULL,
65    NULL,
66    NULL,
67    NULL
68 };
69
70 EVAS_MEMPOOL(_mp_obj);
71 EVAS_MEMPOOL(_mp_cb);
72
73 /* public funcs */
74 EAPI void
75 evas_object_smart_data_set(Evas_Object *obj, void *data)
76 {
77    Evas_Object_Smart *o;
78
79    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
80    return;
81    MAGIC_CHECK_END();
82    o = (Evas_Object_Smart *)(obj->object_data);
83    MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART);
84    return;
85    MAGIC_CHECK_END();
86    o->data = data;
87 }
88
89 EAPI void *
90 evas_object_smart_data_get(const Evas_Object *obj)
91 {
92    Evas_Object_Smart *o;
93
94    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
95    return NULL;
96    MAGIC_CHECK_END();
97    o = (Evas_Object_Smart *)(obj->object_data);
98    if (!o) return NULL;
99    if (o->magic != MAGIC_OBJ_SMART) return NULL;
100    return o->data;
101 }
102
103 EAPI const void *
104 evas_object_smart_interface_get(const Evas_Object *obj,
105                                 const char *name)
106 {
107    unsigned int i;
108    Evas_Smart *s;
109
110    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
111    return NULL;
112    MAGIC_CHECK_END();
113
114    s = evas_object_smart_smart_get(obj);
115
116    for (i = 0; i < s->interfaces.size; i++)
117      {
118         const Evas_Smart_Interface *iface;
119
120         iface = s->interfaces.array[i];
121
122         if (iface->name == name)
123           return iface;
124      }
125
126    return NULL;
127 }
128
129 EAPI void *
130 evas_object_smart_interface_data_get(const Evas_Object *obj,
131                                      const Evas_Smart_Interface *iface)
132 {
133    unsigned int i;
134    Evas_Smart *s;
135
136    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
137    return NULL;
138    MAGIC_CHECK_END();
139
140    s = evas_object_smart_smart_get(obj);
141
142    for (i = 0; i < s->interfaces.size; i++)
143      {
144         if (iface == s->interfaces.array[i])
145           return obj->interface_privates[i];
146      }
147
148    return NULL;
149 }
150
151 EAPI Evas_Smart *
152 evas_object_smart_smart_get(const Evas_Object *obj)
153 {
154    Evas_Object_Smart *o;
155
156    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
157    return NULL;
158    MAGIC_CHECK_END();
159    o = (Evas_Object_Smart *)(obj->object_data);
160    MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART);
161    return NULL;
162    MAGIC_CHECK_END();
163    return obj->smart.smart;
164 }
165
166 EAPI void
167 evas_object_smart_member_add(Evas_Object *obj, Evas_Object *smart_obj)
168 {
169    Evas_Object_Smart *o;
170
171    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
172    return;
173    MAGIC_CHECK_END();
174    MAGIC_CHECK(smart_obj, Evas_Object, MAGIC_OBJ);
175    return;
176    MAGIC_CHECK_END();
177    o = (Evas_Object_Smart *)(smart_obj->object_data);
178    MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART);
179    return;
180    MAGIC_CHECK_END();
181
182    if (obj->delete_me)
183      {
184         CRIT("Adding deleted object %p to smart obj %p", obj, smart_obj);
185         abort();
186         return;
187      }
188    if (smart_obj->delete_me)
189      {
190         CRIT("Adding object %p to deleted smart obj %p", obj, smart_obj);
191         abort();
192         return;
193      }
194    if (!smart_obj->layer)
195      {
196         CRIT("No evas surface associated with smart object (%p)", smart_obj);
197         abort();
198         return;
199      }
200    if ((obj->layer && smart_obj->layer) &&
201        (obj->layer->evas != smart_obj->layer->evas))
202      {
203         CRIT("Adding object %p from Evas (%p) from another Evas (%p)", obj, obj->layer->evas, smart_obj->layer->evas);
204         abort();
205         return;
206      }
207
208    if (obj->smart.parent == smart_obj) return;
209
210    if (obj->smart.parent) evas_object_smart_member_del(obj);
211
212    o->member_count++;
213    evas_object_release(obj, 1);
214    obj->layer = smart_obj->layer;
215    obj->cur.layer = obj->layer->layer;
216    obj->layer->usage++;
217    obj->smart.parent = smart_obj;
218    o->contained = eina_inlist_append(o->contained, EINA_INLIST_GET(obj));
219    evas_object_smart_member_cache_invalidate(obj, EINA_TRUE, EINA_TRUE);
220    obj->restack = 1;
221    evas_object_change(obj);
222    evas_object_mapped_clip_across_mark(obj);
223    if (smart_obj->smart.smart->smart_class->member_add)
224      smart_obj->smart.smart->smart_class->member_add(smart_obj, obj);
225    evas_object_update_bounding_box(obj);
226 }
227
228 EAPI void
229 evas_object_smart_member_del(Evas_Object *obj)
230 {
231    Evas_Object_Smart *o;
232    Evas_Object *smart_obj;
233
234    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
235    return;
236    MAGIC_CHECK_END();
237
238    if (!obj->smart.parent) return;
239
240    smart_obj = obj->smart.parent;
241    if (smart_obj->smart.smart->smart_class->member_del)
242      smart_obj->smart.smart->smart_class->member_del(smart_obj, obj);
243
244    o = (Evas_Object_Smart *)(obj->smart.parent->object_data);
245    o->contained = eina_inlist_remove(o->contained, EINA_INLIST_GET(obj));
246    o->member_count--;
247    obj->smart.parent = NULL;
248    evas_object_smart_member_cache_invalidate(obj, EINA_TRUE, EINA_TRUE);
249    obj->layer->usage--;
250    obj->cur.layer = obj->layer->layer;
251    evas_object_inject(obj, obj->layer->evas);
252    obj->restack = 1;
253    evas_object_change(obj);
254    evas_object_mapped_clip_across_mark(obj);
255 }
256
257 EAPI Evas_Object *
258 evas_object_smart_parent_get(const Evas_Object *obj)
259 {
260    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
261    return NULL;
262    MAGIC_CHECK_END();
263
264    return obj->smart.parent;
265 }
266
267 EAPI Eina_Bool
268 evas_object_smart_type_check(const Evas_Object *obj, const char *type)
269 {
270    const Evas_Smart_Class *sc;
271
272    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
273    return EINA_FALSE;
274    MAGIC_CHECK_END();
275
276    EINA_SAFETY_ON_FALSE_RETURN_VAL(type, EINA_FALSE);
277
278    if (!obj->smart.smart)
279      return EINA_FALSE;
280    sc = obj->smart.smart->smart_class;
281    while (sc)
282      {
283         if (!strcmp(sc->name, type))
284           return EINA_TRUE;
285         sc = sc->parent;
286      }
287
288    return EINA_FALSE;
289 }
290
291 EAPI Eina_Bool
292 evas_object_smart_type_check_ptr(const Evas_Object *obj, const char *type)
293 {
294    const Evas_Smart_Class *sc;
295
296    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
297    return EINA_FALSE;
298    MAGIC_CHECK_END();
299
300    EINA_SAFETY_ON_FALSE_RETURN_VAL(type, EINA_FALSE);
301
302    if (!obj->smart.smart)
303      return EINA_FALSE;
304    sc = obj->smart.smart->smart_class;
305    while (sc)
306      {
307         if (sc->name == type)
308           return EINA_TRUE;
309         sc = sc->parent;
310      }
311
312    return EINA_FALSE;
313 }
314
315 EAPI Eina_List *
316 evas_object_smart_members_get(const Evas_Object *obj)
317 {
318    Evas_Object_Smart *o;
319    Eina_List *members;
320    Eina_Inlist *member;
321
322    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
323    return NULL;
324    MAGIC_CHECK_END();
325    if (!obj->smart.smart) return NULL;
326    o = (Evas_Object_Smart *)(obj->object_data);
327    MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART);
328    return NULL;
329    MAGIC_CHECK_END();
330
331    members = NULL;
332    for (member = o->contained; member; member = member->next)
333      members = eina_list_append(members, member);
334
335    return members;
336 }
337
338 const Eina_Inlist *
339 evas_object_smart_members_get_direct(const Evas_Object *obj)
340 {
341    Evas_Object_Smart *o;
342
343    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
344    return NULL;
345    MAGIC_CHECK_END();
346    if (!obj->smart.smart) return NULL;
347    o = (Evas_Object_Smart *)(obj->object_data);
348    MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART);
349    return NULL;
350    MAGIC_CHECK_END();
351    return o->contained;
352 }
353
354 void
355 _evas_object_smart_members_all_del(Evas_Object *obj)
356 {
357    Evas_Object_Smart *o = (Evas_Object_Smart *)(obj->object_data);
358    Evas_Object *memobj;
359    Eina_Inlist *itrn;
360    EINA_INLIST_FOREACH_SAFE(o->contained, itrn, memobj)
361      {
362         evas_object_del((Evas_Object *) memobj);
363      }
364 }
365
366 static void
367 _evas_smart_class_ifaces_private_data_alloc(Evas_Object *obj,
368                                             Evas_Smart *s)
369 {
370    unsigned int i, total_priv_sz = 0;
371    const Evas_Smart_Class *sc;
372    unsigned char *ptr;
373
374    /* get total size of interfaces private data */
375    for (sc = s->smart_class; sc; sc = sc->parent)
376      {
377         const Evas_Smart_Interface **ifaces_array = sc->interfaces;
378         if (!ifaces_array) continue;
379
380         while (*ifaces_array)
381           {
382              const Evas_Smart_Interface *iface = *ifaces_array;
383
384              if (!iface->name) break;
385
386              if (iface->private_size > 0)
387                {
388                   unsigned int size = iface->private_size;
389
390                   if (size % sizeof(void *) != 0)
391                     size += sizeof(void *) - (size % sizeof(void *));
392                   total_priv_sz += size;
393                }
394
395              ifaces_array++;
396           }
397      }
398
399    obj->interface_privates = malloc
400        (s->interfaces.size * sizeof(void *) + total_priv_sz);
401    if (!obj->interface_privates)
402      {
403         ERR("malloc failed!");
404         return;
405      }
406
407    /* make private data array ptrs point to right places, WHICH LIE ON
408     * THE SAME STRUCT, AFTER THE # OF INTERFACES COUNT */
409    ptr = (unsigned char *)(obj->interface_privates + s->interfaces.size);
410    for (i = 0; i < s->interfaces.size; i++)
411      {
412         unsigned int size;
413
414         size = s->interfaces.array[i]->private_size;
415
416         if (size == 0)
417           {
418              obj->interface_privates[i] = NULL;
419              continue;
420           }
421
422         obj->interface_privates[i] = ptr;
423         memset(ptr, 0, size);
424
425         if (size % sizeof(void *) != 0)
426           size += sizeof(void *) - (size % sizeof(void *));
427         ptr += size;
428      }
429 }
430
431 EAPI Evas_Object *
432 evas_object_smart_add(Evas *e, Evas_Smart *s)
433 {
434    Evas_Object *obj;
435    unsigned int i;
436
437    MAGIC_CHECK(e, Evas, MAGIC_EVAS);
438    return NULL;
439    MAGIC_CHECK_END();
440    MAGIC_CHECK(s, Evas_Smart, MAGIC_SMART);
441    return NULL;
442    MAGIC_CHECK_END();
443
444    obj = evas_object_new(e);
445    if (!obj) return NULL;
446    obj->smart.smart = s;
447    obj->type = s->smart_class->name;
448    evas_object_smart_init(obj);
449    evas_object_inject(obj, e);
450
451    evas_object_smart_use(s);
452
453    _evas_smart_class_ifaces_private_data_alloc(obj, s);
454
455    for (i = 0; i < s->interfaces.size; i++)
456      {
457         const Evas_Smart_Interface *iface;
458
459         iface = s->interfaces.array[i];
460         if (iface->add)
461           {
462              if (!iface->add(obj))
463                {
464                   ERR("failed to create interface %s\n", iface->name);
465                   evas_object_del(obj);
466                   return NULL;
467                }
468           }
469      }
470
471    if (s->smart_class->add) s->smart_class->add(obj);
472
473    return obj;
474 }
475
476 static int
477 _callback_priority_cmp(const void *_a, const void *_b)
478 {
479    const Evas_Smart_Callback *a, *b;
480    a = (const Evas_Smart_Callback *) _a;
481    b = (const Evas_Smart_Callback *) _b;
482    if (a->priority < b->priority)
483       return -1;
484    else
485       return 1;
486 }
487
488 EAPI void
489 evas_object_smart_callback_add(Evas_Object *obj, const char *event, Evas_Smart_Cb func, const void *data)
490 {
491    evas_object_smart_callback_priority_add(obj, event,
492          EVAS_CALLBACK_PRIORITY_DEFAULT, func, data);
493 }
494
495 EAPI void
496 evas_object_smart_callback_priority_add(Evas_Object *obj, const char *event, Evas_Callback_Priority priority, Evas_Smart_Cb func, const void *data)
497 {
498    Evas_Object_Smart *o;
499    Evas_Smart_Callback *cb;
500
501    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
502    return;
503    MAGIC_CHECK_END();
504    o = (Evas_Object_Smart *)(obj->object_data);
505    MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART);
506    return;
507    MAGIC_CHECK_END();
508    if (!event) return;
509    if (!func) return;
510    EVAS_MEMPOOL_INIT(_mp_cb, "evas_smart_callback", Evas_Smart_Callback, 32, );
511    cb = EVAS_MEMPOOL_ALLOC(_mp_cb, Evas_Smart_Callback);
512    if (!cb) return;
513    EVAS_MEMPOOL_PREP(_mp_cb, cb, Evas_Smart_Callback);
514    cb->event = eina_stringshare_add(event);
515    cb->func = func;
516    cb->func_data = (void *)data;
517    cb->priority = priority;
518    o->callbacks = eina_list_sorted_insert(o->callbacks, _callback_priority_cmp,
519          cb);
520 }
521
522 EAPI void *
523 evas_object_smart_callback_del(Evas_Object *obj, const char *event, Evas_Smart_Cb func)
524 {
525    Evas_Object_Smart *o;
526    Eina_List *l;
527    Evas_Smart_Callback *cb;
528
529    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
530    return NULL;
531    MAGIC_CHECK_END();
532    o = (Evas_Object_Smart *)(obj->object_data);
533    MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART);
534    return NULL;
535    MAGIC_CHECK_END();
536    if (!event) return NULL;
537    EINA_LIST_FOREACH(o->callbacks, l, cb)
538      {
539         if ((!strcmp(cb->event, event)) && (cb->func == func))
540           {
541              void *data;
542
543              data = cb->func_data;
544              cb->delete_me = 1;
545              o->deletions_waiting = 1;
546              evas_object_smart_callbacks_clear(obj);
547              return data;
548           }
549      }
550    return NULL;
551 }
552
553 EAPI void *
554 evas_object_smart_callback_del_full(Evas_Object *obj, const char *event, Evas_Smart_Cb func, const void *data)
555 {
556    Evas_Object_Smart *o;
557    Eina_List *l;
558    Evas_Smart_Callback *cb;
559
560    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
561    return NULL;
562    MAGIC_CHECK_END();
563    o = (Evas_Object_Smart *)(obj->object_data);
564    MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART);
565    return NULL;
566    MAGIC_CHECK_END();
567    if (!event) return NULL;
568    EINA_LIST_FOREACH(o->callbacks, l, cb)
569      {
570         if ((!strcmp(cb->event, event)) && (cb->func == func) && (cb->func_data == data))
571           {
572              void *ret;
573
574              ret = cb->func_data;
575              cb->delete_me = 1;
576              o->deletions_waiting = 1;
577              evas_object_smart_callbacks_clear(obj);
578              return ret;
579           }
580      }
581    return NULL;
582 }
583
584 EAPI void
585 evas_object_smart_callback_call(Evas_Object *obj, const char *event, void *event_info)
586 {
587    Evas_Object_Smart *o;
588    Eina_List *l;
589    Evas_Smart_Callback *cb;
590    const char *strshare;
591
592    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
593    return;
594    MAGIC_CHECK_END();
595    o = (Evas_Object_Smart *)(obj->object_data);
596    MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART);
597    return;
598    MAGIC_CHECK_END();
599    if (!event) return;
600    if (obj->delete_me) return;
601    o->walking_list++;
602    strshare = eina_stringshare_add(event);
603    EINA_LIST_FOREACH(o->callbacks, l, cb)
604      {
605         if (!cb->delete_me)
606           {
607              if (cb->event == strshare)
608                cb->func(cb->func_data, obj, event_info);
609           }
610         if (obj->delete_me)
611           break;
612      }
613    eina_stringshare_del(strshare);
614    o->walking_list--;
615    evas_object_smart_callbacks_clear(obj);
616 }
617
618 EAPI Eina_Bool
619 evas_object_smart_callbacks_descriptions_set(Evas_Object *obj, const Evas_Smart_Cb_Description *descriptions)
620 {
621    const Evas_Smart_Cb_Description *d;
622    Evas_Object_Smart *o;
623    unsigned int i, count = 0;
624
625    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
626    return EINA_FALSE;
627    MAGIC_CHECK_END();
628    o = (Evas_Object_Smart *)(obj->object_data);
629    MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART);
630    return EINA_FALSE;
631    MAGIC_CHECK_END();
632
633    if ((!descriptions) || (!descriptions->name))
634      {
635         evas_smart_cb_descriptions_resize(&o->callbacks_descriptions, 0);
636         return EINA_TRUE;
637      }
638
639    for (count = 0, d = descriptions; d->name; d++)
640      count++;
641
642    evas_smart_cb_descriptions_resize(&o->callbacks_descriptions, count);
643    if (count == 0) return EINA_TRUE;
644
645    for (i = 0, d = descriptions; i < count; d++, i++)
646      o->callbacks_descriptions.array[i] = d;
647
648    evas_smart_cb_descriptions_fix(&o->callbacks_descriptions);
649
650    return EINA_TRUE;
651 }
652
653 EAPI void
654 evas_object_smart_callbacks_descriptions_get(const Evas_Object *obj, const Evas_Smart_Cb_Description ***class_descriptions, unsigned int *class_count, const Evas_Smart_Cb_Description ***instance_descriptions, unsigned int *instance_count)
655 {
656    Evas_Object_Smart *o;
657
658    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
659    if (class_descriptions) *class_descriptions = NULL;
660    if (class_count) *class_count = 0;
661    if (instance_descriptions) *instance_descriptions = NULL;
662    if (instance_count) *instance_count = 0;
663    return;
664    MAGIC_CHECK_END();
665    o = (Evas_Object_Smart *)(obj->object_data);
666    MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART);
667    if (class_descriptions) *class_descriptions = NULL;
668    if (class_count) *class_count = 0;
669    if (instance_descriptions) *instance_descriptions = NULL;
670    if (instance_count) *instance_count = 0;
671    return;
672    MAGIC_CHECK_END();
673
674    if (class_descriptions)
675      *class_descriptions = obj->smart.smart->callbacks.array;
676    if (class_count)
677      *class_count = obj->smart.smart->callbacks.size;
678
679    if (instance_descriptions)
680      *instance_descriptions = o->callbacks_descriptions.array;
681    if (instance_count)
682      *instance_count = o->callbacks_descriptions.size;
683 }
684
685 EAPI void
686 evas_object_smart_callback_description_find(const Evas_Object *obj, const char *name, const Evas_Smart_Cb_Description **class_description, const Evas_Smart_Cb_Description **instance_description)
687 {
688    Evas_Object_Smart *o;
689
690    if (!name)
691      {
692         if (class_description) *class_description = NULL;
693         if (instance_description) *instance_description = NULL;
694         return;
695      }
696
697    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
698    if (class_description) *class_description = NULL;
699    if (instance_description) *instance_description = NULL;
700    return;
701    MAGIC_CHECK_END();
702    o = (Evas_Object_Smart *)(obj->object_data);
703    MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART);
704    if (class_description) *class_description = NULL;
705    if (instance_description) *instance_description = NULL;
706    return;
707    MAGIC_CHECK_END();
708
709    if (class_description)
710      *class_description = evas_smart_cb_description_find
711         (&obj->smart.smart->callbacks, name);
712
713    if (instance_description)
714      *instance_description = evas_smart_cb_description_find
715         (&o->callbacks_descriptions, name);
716 }
717
718 EAPI void
719 evas_object_smart_need_recalculate_set(Evas_Object *obj, Eina_Bool value)
720 {
721    Evas_Object_Smart *o;
722    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
723    return;
724    MAGIC_CHECK_END();
725    o = obj->object_data;
726    MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART);
727    return;
728    MAGIC_CHECK_END();
729
730    // XXX: do i need this?
731    if (obj->delete_me) return;
732
733    /* remove this entry from calc_list or processed list */
734    if (eina_clist_element_is_linked(&obj->calc_entry))
735      eina_clist_remove(&obj->calc_entry);
736
737    value = !!value;
738    if (value)
739      eina_clist_add_tail(&obj->layer->evas->calc_list, &obj->calc_entry);
740    else
741      eina_clist_add_tail(&obj->layer->evas->calc_done, &obj->calc_entry);
742
743    if (o->need_recalculate == value) return;
744
745    if (obj->recalculate_cycle > 254)
746      {
747         ERR("Object %p is not stable during recalc loop", obj);
748         return;
749      }
750    if (obj->layer->evas->in_smart_calc) obj->recalculate_cycle++;
751    o->need_recalculate = value;
752 }
753
754 EAPI Eina_Bool
755 evas_object_smart_need_recalculate_get(const Evas_Object *obj)
756 {
757    Evas_Object_Smart *o;
758    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
759    return EINA_FALSE;
760    MAGIC_CHECK_END();
761    o = obj->object_data;
762    MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART);
763    return EINA_FALSE;
764    MAGIC_CHECK_END();
765
766    return o->need_recalculate;
767 }
768
769 EAPI void
770 evas_object_smart_calculate(Evas_Object *obj)
771 {
772    Evas_Object_Smart *o;
773    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
774    return;
775    MAGIC_CHECK_END();
776    o = obj->object_data;
777    MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART);
778    return;
779    MAGIC_CHECK_END();
780
781    if (!obj->smart.smart->smart_class->calculate)
782      return;
783
784    o->need_recalculate = 0;
785    obj->smart.smart->smart_class->calculate(obj);
786 }
787
788 EAPI void
789 evas_smart_objects_calculate(Evas *e)
790 {
791    MAGIC_CHECK(e, Evas, MAGIC_EVAS);
792    return;
793    MAGIC_CHECK_END();
794    evas_call_smarts_calculate(e);
795 }
796
797 EAPI int
798 evas_smart_objects_calculate_count_get(const Evas *e)
799 {
800    MAGIC_CHECK(e, Evas, MAGIC_EVAS);
801    return 0;
802    MAGIC_CHECK_END();
803    return e->smart_calc_count;
804 }
805
806 /**
807  * Call calculate() on all smart objects that need_recalculate.
808  *
809  * @internal
810  */
811 void
812 evas_call_smarts_calculate(Evas *e)
813 {
814    Eina_Clist *elem;
815    Evas_Object *obj;
816
817 //   printf("+CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALC-----------v\n");
818    evas_event_freeze(e);
819    e->in_smart_calc++;
820
821    while (NULL != (elem = eina_clist_head(&e->calc_list)))
822      {
823         Evas_Object_Smart *o;
824
825         /* move the item to the processed list */
826         obj = EINA_CLIST_ENTRY(elem, Evas_Object, calc_entry);
827         eina_clist_remove(&obj->calc_entry);
828         if (obj->delete_me) continue;
829         eina_clist_add_tail(&e->calc_done, &obj->calc_entry);
830
831         o = obj->object_data;
832
833         if (o->need_recalculate)
834           {
835              o->need_recalculate = 0;
836              obj->smart.smart->smart_class->calculate(obj);
837           }
838      }
839
840    while (NULL != (elem = eina_clist_head(&e->calc_done)))
841      {
842         obj = EINA_CLIST_ENTRY(elem, Evas_Object, calc_entry);
843         obj->recalculate_cycle = 0;
844         eina_clist_remove(&obj->calc_entry);
845      }
846
847    e->in_smart_calc--;
848    if (e->in_smart_calc == 0) e->smart_calc_count++;
849    evas_event_thaw(e);
850    evas_event_thaw_eval(e);
851 }
852
853 EAPI void
854 evas_object_smart_changed(Evas_Object *obj)
855 {
856    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
857    return;
858    MAGIC_CHECK_END();
859    evas_object_change(obj);
860    evas_object_smart_need_recalculate_set(obj, 1);
861 }
862
863 /* internal calls */
864 static void
865 evas_object_smart_callbacks_clear(Evas_Object *obj)
866 {
867    Evas_Object_Smart *o;
868    Eina_List *l;
869    Evas_Smart_Callback *cb;
870
871    o = (Evas_Object_Smart *)(obj->object_data);
872
873    if (o->walking_list) return;
874    if (!o->deletions_waiting) return;
875    for (l = o->callbacks; l;)
876      {
877         cb = eina_list_data_get(l);
878         l = eina_list_next(l);
879         if (cb->delete_me)
880           {
881              o->callbacks = eina_list_remove(o->callbacks, cb);
882              if (cb->event) eina_stringshare_del(cb->event);
883              EVAS_MEMPOOL_FREE(_mp_cb, cb);
884           }
885      }
886 }
887
888 void
889 evas_object_smart_del(Evas_Object *obj)
890 {
891    Evas_Smart *s;
892    unsigned int i;
893
894    if (obj->delete_me) return;
895    s = obj->smart.smart;
896
897    if ((s) && (s->smart_class->del)) s->smart_class->del(obj);
898    if (obj->smart.parent) evas_object_smart_member_del(obj);
899
900    for (i = 0; i < s->interfaces.size; i++)
901      {
902         const Evas_Smart_Interface *iface;
903
904         iface = s->interfaces.array[i];
905         if (iface->del) iface->del(obj);
906      }
907
908    free(obj->interface_privates);
909    obj->interface_privates = NULL;
910
911    if (s) evas_object_smart_unuse(s);
912 }
913
914 void
915 evas_object_smart_cleanup(Evas_Object *obj)
916 {
917    Evas_Object_Smart *o;
918
919    if (obj->smart.parent)
920      evas_object_smart_member_del(obj);
921
922    o = (Evas_Object_Smart *)(obj->object_data);
923    if (o->magic == MAGIC_OBJ_SMART)
924      {
925         if (obj->calc_entry.next)
926           eina_clist_remove(&obj->calc_entry);
927
928         while (o->contained)
929            evas_object_smart_member_del((Evas_Object *)o->contained);
930
931         while (o->callbacks)
932           {
933              Evas_Smart_Callback *cb = o->callbacks->data;
934              o->callbacks = eina_list_remove(o->callbacks, cb);
935              if (cb->event) eina_stringshare_del(cb->event);
936              EVAS_MEMPOOL_FREE(_mp_cb, cb);
937           }
938
939         evas_smart_cb_descriptions_resize(&o->callbacks_descriptions, 0);
940         o->data = NULL;
941      }
942
943    obj->smart.parent = NULL;
944    obj->smart.smart = NULL;
945 }
946
947 void
948 evas_object_smart_member_cache_invalidate(Evas_Object *obj,
949                                           Eina_Bool pass_events,
950                                           Eina_Bool freeze_events)
951 {
952    Evas_Object_Smart *o;
953    Evas_Object *member;
954
955    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
956    return;
957    MAGIC_CHECK_END();
958
959    if (pass_events)
960      obj->parent_cache.pass_events_valid = EINA_FALSE;
961    if (freeze_events)
962      obj->parent_cache.freeze_events_valid = EINA_FALSE;
963
964    o = obj->object_data;
965    if (o->magic != MAGIC_OBJ_SMART) return;
966
967    EINA_INLIST_FOREACH(o->contained, member)
968      evas_object_smart_member_cache_invalidate(member,
969                                                pass_events,
970                                                freeze_events);
971 }
972
973 void
974 evas_object_smart_member_raise(Evas_Object *member)
975 {
976    Evas_Object_Smart *o;
977
978    o = (Evas_Object_Smart *)(member->smart.parent->object_data);
979    o->contained = eina_inlist_demote(o->contained, EINA_INLIST_GET(member));
980 }
981
982 void
983 evas_object_smart_member_lower(Evas_Object *member)
984 {
985    Evas_Object_Smart *o;
986
987    o = (Evas_Object_Smart *)(member->smart.parent->object_data);
988    o->contained = eina_inlist_promote(o->contained, EINA_INLIST_GET(member));
989 }
990
991 void
992 evas_object_smart_member_stack_above(Evas_Object *member, Evas_Object *other)
993 {
994    Evas_Object_Smart *o;
995
996    o = (Evas_Object_Smart *)(member->smart.parent->object_data);
997    o->contained = eina_inlist_remove(o->contained, EINA_INLIST_GET(member));
998    o->contained = eina_inlist_append_relative(o->contained, EINA_INLIST_GET(member), EINA_INLIST_GET(other));
999 }
1000
1001 void
1002 evas_object_smart_member_stack_below(Evas_Object *member, Evas_Object *other)
1003 {
1004    Evas_Object_Smart *o;
1005
1006    o = (Evas_Object_Smart *)(member->smart.parent->object_data);
1007    o->contained = eina_inlist_remove(o->contained, EINA_INLIST_GET(member));
1008    o->contained = eina_inlist_prepend_relative(o->contained, EINA_INLIST_GET(member), EINA_INLIST_GET(other));
1009 }
1010
1011 void
1012 evas_object_smart_need_bounding_box_update(Evas_Object *obj)
1013 {
1014    Evas_Object_Smart *o;
1015
1016    o = (Evas_Object_Smart *)(obj->object_data);
1017
1018    if (o->update_boundingbox_needed) return ;
1019    o->update_boundingbox_needed = EINA_TRUE;
1020
1021    if (obj->smart.parent) evas_object_smart_need_bounding_box_update(obj->smart.parent);
1022 }
1023
1024 void
1025 evas_object_smart_bouding_box_update(Evas_Object *obj)
1026 {
1027    Eina_Inlist *list;
1028    Evas_Object *o;
1029    Evas_Object_Smart *os;
1030    Evas_Coord minx;
1031    Evas_Coord miny;
1032    Evas_Coord maxw = 0;
1033    Evas_Coord maxh = 0;
1034
1035    os = (Evas_Object_Smart *)(obj->object_data);
1036
1037    if (!os->update_boundingbox_needed) return ;
1038    os->update_boundingbox_needed = EINA_FALSE;
1039
1040    minx = obj->layer->evas->output.w;
1041    miny = obj->layer->evas->output.h;
1042
1043    list = os->contained;
1044    EINA_INLIST_FOREACH(list, o)
1045      {
1046         Evas_Coord tx;
1047         Evas_Coord ty;
1048         Evas_Coord tw;
1049         Evas_Coord th;
1050
1051         if (o == obj) continue ;
1052         if (o->clip.clipees || o->is_static_clip) continue ;
1053
1054         if (o->smart.smart)
1055           {
1056              evas_object_smart_bouding_box_update(o);
1057
1058              tx = o->cur.bounding_box.x;
1059              ty = o->cur.bounding_box.y;
1060              tw = o->cur.bounding_box.x + o->cur.bounding_box.w;
1061              th = o->cur.bounding_box.y + o->cur.bounding_box.h;
1062           }
1063         else
1064           {
1065              tx = o->cur.geometry.x;
1066              ty = o->cur.geometry.y;
1067              tw = o->cur.geometry.x + o->cur.geometry.w;
1068              th = o->cur.geometry.y + o->cur.geometry.h;
1069           }
1070
1071         if (tx < minx) minx = tx;
1072         if (ty < miny) miny = ty;
1073         if (tw > maxw) maxw = tw;
1074         if (th > maxh) maxh = th;
1075      }
1076
1077    if (minx != obj->cur.bounding_box.x)
1078      {
1079         obj->cur.bounding_box.w += obj->cur.bounding_box.x - minx;
1080         obj->cur.bounding_box.x = minx;
1081      }
1082
1083    if (miny != obj->cur.bounding_box.y)
1084      {
1085         obj->cur.bounding_box.h += obj->cur.bounding_box.y - miny;
1086         obj->cur.bounding_box.y = miny;
1087      }
1088
1089    if (maxw != obj->cur.bounding_box.x + obj->cur.bounding_box.w)
1090      {
1091         obj->cur.bounding_box.w = maxw - obj->cur.bounding_box.x;
1092      }
1093
1094    if (maxh != obj->cur.bounding_box.y + obj->cur.bounding_box.h)
1095      {
1096         obj->cur.bounding_box.h = maxh - obj->cur.bounding_box.y;
1097      }
1098 }
1099
1100 /* all nice and private */
1101 static void
1102 evas_object_smart_init(Evas_Object *obj)
1103 {
1104    /* alloc smart obj, setup methods and default values */
1105    obj->object_data = evas_object_smart_new();
1106    /* set up default settings for this kind of object */
1107    obj->cur.color.r = 255;
1108    obj->cur.color.g = 255;
1109    obj->cur.color.b = 255;
1110    obj->cur.color.a = 255;
1111    obj->cur.geometry.x = 0;
1112    obj->cur.geometry.y = 0;
1113    obj->cur.geometry.w = 0;
1114    obj->cur.geometry.h = 0;
1115    obj->cur.layer = 0;
1116    /* set up object-specific settings */
1117    obj->prev = obj->cur;
1118    /* set up methods (compulsory) */
1119    obj->func = &object_func;
1120 }
1121
1122 static void *
1123 evas_object_smart_new(void)
1124 {
1125    Evas_Object_Smart *o;
1126
1127    /* alloc obj private data */
1128    EVAS_MEMPOOL_INIT(_mp_obj, "evas_object_smart", Evas_Object_Smart, 32, NULL);
1129    o = EVAS_MEMPOOL_ALLOC(_mp_obj, Evas_Object_Smart);
1130    if (!o) return NULL;
1131    EVAS_MEMPOOL_PREP(_mp_obj, o, Evas_Object_Smart);
1132    o->magic = MAGIC_OBJ_SMART;
1133    return o;
1134 }
1135
1136 static void
1137 evas_object_smart_free(Evas_Object *obj)
1138 {
1139    Evas_Object_Smart *o;
1140
1141    /* frees private object data. very simple here */
1142    o = (Evas_Object_Smart *)(obj->object_data);
1143    MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART);
1144    return;
1145    MAGIC_CHECK_END();
1146    /* free obj */
1147    o->magic = 0;
1148    EVAS_MEMPOOL_FREE(_mp_obj, o);
1149 }
1150
1151 static void
1152 evas_object_smart_render(Evas_Object *obj __UNUSED__, void *output __UNUSED__, void *context __UNUSED__, void *surface __UNUSED__, int x __UNUSED__, int y __UNUSED__)
1153 {
1154    return;
1155 }
1156
1157 static void
1158 evas_object_smart_render_pre(Evas_Object *obj)
1159 {
1160    Evas *e;
1161
1162    if (obj->pre_render_done) return;
1163    if (!obj->child_has_map && !obj->cur.cached_surface)
1164      {
1165 #if 0
1166         Evas_Object_Smart *o;
1167
1168         fprintf(stderr, "");
1169         o = (Evas_Object_Smart *)(obj->object_data);
1170         if (/* o->member_count > 1 && */
1171             obj->cur.bounding_box.w == obj->prev.bounding_box.w &&
1172             obj->cur.bounding_box.h == obj->prev.bounding_box.h &&
1173             (obj->cur.bounding_box.x != obj->prev.bounding_box.x ||
1174              obj->cur.bounding_box.y != obj->prev.bounding_box.y))
1175           {
1176              Eina_Bool cache_map = EINA_FALSE;
1177
1178              /* Check parent speed */
1179              /* - same speed => do not map this object */
1180              /* - different speed => map this object */
1181              /* - if parent is mapped then map this object */
1182
1183              if (!obj->smart.parent || obj->smart.parent->child_has_map)
1184                {
1185                   cache_map = EINA_TRUE;
1186                }
1187              else
1188                {
1189                   if (_evas_render_has_map(obj->smart.parent))
1190                     {
1191                        cache_map = EINA_TRUE;
1192                     }
1193                   else
1194                     {
1195                        int speed_x, speed_y;
1196                        int speed_px, speed_py;
1197
1198                        speed_x = obj->cur.geometry.x - obj->prev.geometry.x;
1199                        speed_y = obj->cur.geometry.y - obj->prev.geometry.y;
1200
1201                        speed_px = obj->smart.parent->cur.geometry.x - obj->smart.parent->prev.geometry.x;
1202                        speed_py = obj->smart.parent->cur.geometry.y - obj->smart.parent->prev.geometry.y;
1203
1204                        /* speed_x = obj->cur.bounding_box.x - obj->prev.bounding_box.x; */
1205                        /* speed_y = obj->cur.bounding_box.y - obj->prev.bounding_box.y; */
1206
1207                        /* speed_px = obj->smart.parent->cur.bounding_box.x - obj->smart.parent->prev.bounding_box.x; */
1208                        /* speed_py = obj->smart.parent->cur.bounding_box.y - obj->smart.parent->prev.bounding_box.y; */
1209
1210                        fprintf(stderr, "speed: '%s',%p (%i, %i) vs '%s',%p (%i, %i)\n",
1211                                evas_object_type_get(obj), obj, speed_x, speed_y,
1212                                evas_object_type_get(obj->smart.parent), obj->smart.parent, speed_px, speed_py);
1213
1214                        if (speed_x != speed_px || speed_y != speed_py)
1215                          cache_map = EINA_TRUE;
1216                     }
1217                }
1218
1219              if (cache_map)
1220                fprintf(stderr, "Wouhou, I can detect moving smart object (%s, %p [%i, %i, %i, %i] < %s, %p [%i, %i, %i, %i])\n",
1221                        evas_object_type_get(obj), obj,
1222                        obj->cur.bounding_box.x - obj->prev.bounding_box.x,
1223                        obj->cur.bounding_box.y - obj->prev.bounding_box.y,
1224                        obj->cur.bounding_box.w, obj->cur.bounding_box.h,
1225                        evas_object_type_get(obj->smart.parent), obj->smart.parent,
1226                        obj->smart.parent->cur.bounding_box.x - obj->smart.parent->prev.bounding_box.x,
1227                        obj->smart.parent->cur.bounding_box.y - obj->smart.parent->prev.bounding_box.y,
1228                        obj->smart.parent->cur.bounding_box.w, obj->smart.parent->cur.bounding_box.h);
1229
1230              obj->cur.cached_surface = cache_map;
1231           }
1232 #endif
1233      }
1234
1235    e = obj->layer->evas;
1236
1237    if (obj->changed_map)
1238      {
1239        evas_object_render_pre_prev_cur_add(&e->clip_changes, obj);
1240      }
1241
1242    obj->pre_render_done = EINA_TRUE;
1243 }
1244
1245 static void
1246 evas_object_smart_render_post(Evas_Object *obj)
1247 {
1248    evas_object_cur_prev(obj);
1249 }
1250
1251 static unsigned int evas_object_smart_id_get(Evas_Object *obj)
1252 {
1253    Evas_Object_Smart *o;
1254
1255    o = (Evas_Object_Smart *)(obj->object_data);
1256    if (!o) return 0;
1257    return MAGIC_OBJ_SMART;
1258 }
1259
1260 static unsigned int evas_object_smart_visual_id_get(Evas_Object *obj)
1261 {
1262    Evas_Object_Smart *o;
1263
1264    o = (Evas_Object_Smart *)(obj->object_data);
1265    if (!o) return 0;
1266    return MAGIC_OBJ_CONTAINER;
1267 }
1268
1269 static void *evas_object_smart_engine_data_get(Evas_Object *obj)
1270 {
1271    Evas_Object_Smart *o;
1272
1273    o = (Evas_Object_Smart *)(obj->object_data);
1274    if (!o) return NULL;
1275    return o->engine_data;
1276 }