1 #define EFL_CANVAS_GROUP_PROTECTED
2 
3 #include "eo_internal.h"
4 #include "evas_common_private.h"
5 #include "evas_private.h"
6 
7 #define MY_CLASS EFL_CANVAS_GROUP_CLASS
8 
9 #define MY_CLASS_NAME "Evas_Smart"
10 #define MY_CLASS_NAME_LEGACY "Evas_Object_Smart"
11 
12 #define EVAS_OBJECT_SMART_GET_OR_RETURN(eo_obj, ...) \
13    Evas_Smart_Data *o = efl_data_scope_safe_get(eo_obj, MY_CLASS); \
14    do { if (!o) { ERR("calling smart object API on non-smart object!"); return __VA_ARGS__; } } while (0)
15 
16 extern Eina_Hash* signals_hash_table;
17 
18 static Eina_Hash *_evas_smart_class_names_hash_table = NULL;
19 
20 struct _Evas_Smart_Data
21 {
22    struct {
23       Eina_Rectangle bounding_box;
24    } cur, prev;
25    Evas_Object      *object;
26    Evas_Object      *filter_img;
27    void             *engine_data;
28    void             *data;
29    Eina_Inlist      *callbacks;
30    Eina_Inlist      *contained; /** list of smart member objects */
31 
32    void             *render_cache;
33   /* ptr array + data blob holding all interfaces private data for
34    * this object */
35    void            **interface_privates;
36    Eina_Clist        calc_entry;
37 
38    Evas_Smart_Cb_Description_Array callbacks_descriptions;
39 
40    int               x, y;
41    int               walking_list;
42    int               member_count; /** number of smart member objects */
43 
44    unsigned short    recalculate_cycle;
45 
46    Evas_BiDi_Direction paragraph_direction : 2;
47    Eina_Bool         inherit_paragraph_direction : 1;
48    Eina_Bool         deletions_waiting : 1;
49    Eina_Bool         need_recalculate : 1;
50    Eina_Bool         update_boundingbox_needed : 1;
51    Eina_Bool         group_del_called : 1;
52    Eina_Bool         clipped : 1; /* If true, smart clipped */
53    Eina_Bool         data_nofree : 1; /* If true, do NOT free the data */
54    Eina_Bool         constructed : 1; /* constructor finished */
55    Eina_Bool         cb_move : 1; /* has "move" cb added */
56    Eina_Bool         cb_resize : 1; /* has "resize" cb added */
57    Eina_Bool         cb_restack : 1; /* has "restack" cb added */
58    Eina_Bool         cb_member_added : 1; /* has "member,added" cb added */
59    Eina_Bool         cb_member_removed : 1; /* has "member,removed" cb added */
60 };
61 
62 typedef struct
63 {
64    EINA_INLIST;
65    Evas_Smart_Cb func;
66    void *data;
67    const Efl_Event_Description *event;
68 } _eo_evas_smart_cb_info;
69 
70 
71 typedef struct _Evas_Object_Smart_Iterator Evas_Object_Smart_Iterator;
72 struct _Evas_Object_Smart_Iterator
73 {
74    Eina_Iterator iterator;
75 
76    const Eina_Inlist *current;
77    Evas_Object *parent;
78 };
79 
80 static void
_eo_evas_smart_cb(void * data,const Efl_Event * event)81 _eo_evas_smart_cb(void *data, const Efl_Event *event)
82 {
83    _eo_evas_smart_cb_info *info = data;
84    if (info->func) info->func(info->data, event->object, event->info);
85 }
86 
87 /* private methods for smart objects */
88 static void evas_object_smart_render(Evas_Object *eo_obj,
89                                      Evas_Object_Protected_Data *obj,
90                                      void *type_private_data,
91                                      void *engine, void *output, void *context, void *surface,
92                                      int x, int y, Eina_Bool do_async);
93 static void evas_object_smart_render_pre(Evas_Object *eo_obj,
94 					 Evas_Object_Protected_Data *obj,
95 					 void *type_private_data);
96 static void evas_object_smart_render_post(Evas_Object *eo_obj,
97 					  Evas_Object_Protected_Data *obj,
98 					  void *type_private_data);
99 
100 static void *evas_object_smart_engine_data_get(Evas_Object *eo_obj);
101 static void _efl_canvas_group_group_paragraph_direction_set_internal(Eo *eo_obj,
102                                                                 Evas_BiDi_Direction dir);
103 
104 static const Evas_Object_Func object_func =
105 {
106    /* methods (compulsory) */
107    NULL,
108    evas_object_smart_render,
109    evas_object_smart_render_pre,
110    evas_object_smart_render_post,
111    evas_object_smart_engine_data_get,
112    /* these are optional. NULL = nothing */
113    NULL,
114    NULL,
115    NULL,
116    NULL,
117    NULL,
118    NULL,
119    NULL,
120    NULL,
121    NULL,
122    NULL,
123    NULL   // render_prepare
124 };
125 
126 /* helpers */
127 static inline Evas_Object *
_smart_clipper_get(Evas_Smart_Data * o)128 _smart_clipper_get(Evas_Smart_Data *o)
129 {
130    Evas_Object_Smart_Clipped_Data *cso = o->clipped ? o->data : NULL;
131    return cso ? cso->clipper : NULL;
132 }
133 
134 /* public funcs */
135 EAPI void
evas_object_smart_data_set(Evas_Object * eo_obj,void * data)136 evas_object_smart_data_set(Evas_Object *eo_obj, void *data)
137 {
138    EVAS_OBJECT_SMART_GET_OR_RETURN(eo_obj);
139    if (o->data != data)
140      {
141         if (o->data && !o->data_nofree)
142           free(o->data);
143         o->data = data;
144         o->data_nofree = EINA_TRUE;
145      }
146 }
147 
148 EAPI void *
evas_object_smart_data_get(const Evas_Object * eo_obj)149 evas_object_smart_data_get(const Evas_Object *eo_obj)
150 {
151    EVAS_OBJECT_SMART_GET_OR_RETURN(eo_obj, NULL);
152    return o->data;
153 }
154 
155 EAPI const void *
evas_object_smart_interface_get(const Evas_Object * eo_obj,const char * name)156 evas_object_smart_interface_get(const Evas_Object *eo_obj,
157                                 const char *name)
158 {
159    Evas_Smart *s;
160    unsigned int i;
161 
162    EVAS_OBJECT_SMART_GET_OR_RETURN(eo_obj, NULL);
163    s = evas_object_smart_smart_get(eo_obj);
164    if (!s) return NULL;
165 
166    for (i = 0; i < s->interfaces.size; i++)
167      {
168         const Evas_Smart_Interface *iface;
169 
170         iface = s->interfaces.array[i];
171 
172         if (iface->name == name)
173           return iface;
174      }
175 
176    return NULL;
177 }
178 
179 EAPI void *
evas_object_smart_interface_data_get(const Evas_Object * eo_obj,const Evas_Smart_Interface * iface)180 evas_object_smart_interface_data_get(const Evas_Object *eo_obj,
181                                      const Evas_Smart_Interface *iface)
182 {
183    unsigned int i;
184    Evas_Smart *s;
185 
186    EVAS_OBJECT_SMART_GET_OR_RETURN(eo_obj, NULL);
187    s = evas_object_smart_smart_get(eo_obj);
188    if (!s) return NULL;
189 
190    if (s)
191      {
192         for (i = 0; i < s->interfaces.size; i++)
193           {
194              if (iface == s->interfaces.array[i])
195                 return o->interface_privates[i];
196           }
197      }
198 
199    return NULL;
200 }
201 
202 EAPI Evas_Smart*
evas_object_smart_smart_get(const Efl_Canvas_Group * eo_obj)203 evas_object_smart_smart_get(const Efl_Canvas_Group *eo_obj)
204 {
205    Evas_Object_Protected_Data *obj = EVAS_OBJ_GET_OR_RETURN(eo_obj, NULL);
206    return obj->smart.smart;
207 }
208 
209 EAPI void
evas_object_smart_member_add(Evas_Object * eo_obj,Evas_Object * smart_obj)210 evas_object_smart_member_add(Evas_Object *eo_obj, Evas_Object *smart_obj)
211 {
212    efl_canvas_group_member_add(smart_obj, eo_obj);
213 }
214 
215 static void
_evas_object_smart_member_cache_invalidate(Evas_Object_Protected_Data * obj,Evas_Smart_Data * sd)216 _evas_object_smart_member_cache_invalidate(Evas_Object_Protected_Data *obj, Evas_Smart_Data *sd)
217 {
218    Evas_Object_Protected_Data *member;
219    Evas_Smart_Data *msd;
220 
221    obj->parent_cache.pass_events_valid = EINA_FALSE;
222    obj->parent_cache.freeze_events_valid = EINA_FALSE;
223    obj->parent_cache.src_invisible_valid = EINA_FALSE;
224    if (!sd) return;
225 
226    EINA_INLIST_FOREACH(sd->contained, member)
227      {
228         if (member->is_smart)
229           msd = efl_data_scope_get(member->object, MY_CLASS);
230         else msd = NULL;
231         _evas_object_smart_member_cache_invalidate(member, msd);
232      }
233 }
234 
235 EOLIAN static void
_efl_canvas_group_group_member_add(Eo * smart_obj,Evas_Smart_Data * o,Evas_Object * eo_obj)236 _efl_canvas_group_group_member_add(Eo *smart_obj, Evas_Smart_Data *o, Evas_Object *eo_obj)
237 {
238 
239    Evas_Object_Protected_Data *obj = efl_data_scope_safe_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
240    Evas_Object_Protected_Data *smart = efl_data_scope_get(smart_obj, EFL_CANVAS_OBJECT_CLASS);
241    Evas_Smart_Data *member_o = NULL;
242 
243    if ((!obj) || (!smart)) return;
244    if (obj->delete_me)
245      {
246         CRI("Adding deleted object %p to smart obj %p", eo_obj, smart_obj);
247         return;
248      }
249    if (smart->delete_me)
250      {
251         CRI("Adding object %p to deleted smart obj %p", eo_obj, smart_obj);
252         return;
253      }
254    if (!smart->layer)
255      {
256         CRI("No evas surface associated with smart object (%p)", smart_obj);
257         return;
258      }
259    if ((obj->layer && smart->layer) &&
260        (obj->layer->evas != smart->layer->evas))
261      {
262         CRI("Adding object %p from Evas (%p) from another Evas (%p)", eo_obj, obj->layer->evas, smart->layer->evas);
263         return;
264      }
265 
266    if (obj->smart.parent == smart_obj) return;
267 
268    evas_object_async_block(obj);
269    if (obj->smart.parent) evas_object_smart_member_del(eo_obj);
270 
271    if (obj->layer != smart->layer)
272      {
273         if (obj->in_layer)
274           evas_object_release(eo_obj, obj, 1);
275         else if (obj->layer && ((--obj->layer->usage) == 0))
276           evas_layer_del(obj->layer);
277      }
278    else if (obj->in_layer)
279      {
280         evas_object_release(eo_obj, obj, 1);
281      }
282    obj->layer = smart->layer;
283    obj->layer->usage++;
284    if (obj->layer->layer != obj->cur->layer)
285      {
286         EINA_COW_STATE_WRITE_BEGIN(obj, state_write, cur)
287           state_write->layer = obj->layer->layer;
288         EINA_COW_STATE_WRITE_END(obj, state_write, cur);
289      }
290 
291    o->member_count++;
292    obj->smart.parent = smart_obj;
293    obj->smart.parent_data = o;
294    obj->smart.parent_object_data = smart;
295    o->contained = eina_inlist_append(o->contained, EINA_INLIST_GET(obj));
296 
297    if (obj->is_smart) member_o = efl_data_scope_get(eo_obj, MY_CLASS);
298    _evas_object_smart_member_cache_invalidate(obj, member_o);
299    obj->restack = 1;
300 
301    if (obj->is_smart)
302      {
303         if ((member_o->inherit_paragraph_direction) &&
304             (member_o->paragraph_direction != o->paragraph_direction))
305           {
306              member_o->paragraph_direction = o->paragraph_direction;
307              _efl_canvas_group_group_paragraph_direction_set_internal(eo_obj, o->paragraph_direction);
308           }
309      }
310 
311    if (!smart->is_frame_top && (smart->is_frame != obj->is_frame))
312      efl_canvas_object_is_frame_object_set(eo_obj, smart->is_frame);
313 
314    if (o->clipped)
315      {
316         Evas_Object *clipper = _smart_clipper_get(o);
317         Eina_Bool had_clippees = evas_object_clipees_has(clipper);
318 
319         if (EINA_UNLIKELY(!clipper && !o->constructed))
320           {
321              _evas_object_smart_clipped_init(smart_obj);
322              clipper = _smart_clipper_get(o);
323           }
324 
325         if (clipper != eo_obj)
326           {
327              EINA_SAFETY_ON_NULL_RETURN(clipper);
328              efl_canvas_object_clipper_set(eo_obj, clipper);
329              if (!had_clippees && smart->cur->visible)
330                efl_gfx_entity_visible_set(clipper, 1);
331           }
332      }
333 
334    evas_object_change(eo_obj, obj);
335    evas_object_mapped_clip_across_mark(eo_obj, obj);
336    if (smart->smart.smart && smart->smart.smart->smart_class->member_add)
337      smart->smart.smart->smart_class->member_add(smart_obj, eo_obj);
338    evas_object_update_bounding_box(eo_obj, obj, member_o);
339    if (o->cb_member_added)
340      efl_event_callback_call(smart_obj, EFL_CANVAS_GROUP_EVENT_MEMBER_ADDED, eo_obj);
341 }
342 
343 EAPI void
evas_object_smart_member_del(Evas_Object * eo_obj)344 evas_object_smart_member_del(Evas_Object *eo_obj)
345 {
346    Evas_Object_Protected_Data *obj;
347 
348    if (!eo_obj) return ;
349    obj = efl_data_scope_safe_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
350    if (!obj) return;
351    if (!obj->smart.parent) return;
352    Evas_Object *smart_obj = obj->smart.parent;
353    efl_canvas_group_member_remove(smart_obj, eo_obj);
354 }
355 
356 EOLIAN static void
_efl_canvas_group_group_member_remove(Eo * smart_obj,Evas_Smart_Data * sd,Evas_Object * eo_obj)357 _efl_canvas_group_group_member_remove(Eo *smart_obj, Evas_Smart_Data *sd, Evas_Object *eo_obj)
358 {
359    Evas_Object_Protected_Data *obj = efl_data_scope_safe_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
360    Evas_Object_Protected_Data *smart;
361    Evas_Smart_Data *member_o = NULL, *o;
362 
363    if (!obj || !obj->smart.parent) return;
364 
365    evas_object_async_block(obj);
366 
367    if (sd->cb_member_removed)
368      efl_event_callback_call(smart_obj, EFL_CANVAS_GROUP_EVENT_MEMBER_REMOVED, eo_obj);
369 
370    smart = efl_data_scope_get(smart_obj, EFL_CANVAS_OBJECT_CLASS);
371    if (smart->smart.smart && smart->smart.smart->smart_class->member_del)
372      smart->smart.smart->smart_class->member_del(smart_obj, eo_obj);
373 
374    o = efl_data_scope_get(smart_obj, MY_CLASS);
375 
376    if (o->clipped)
377      {
378         Evas_Object *clipper = _smart_clipper_get(o);
379 
380         EINA_SAFETY_ON_NULL_RETURN(clipper);
381         efl_canvas_object_clipper_set(eo_obj, NULL);
382         if (!evas_object_clipees_has(clipper))
383           efl_gfx_entity_visible_set(clipper, 0);
384      }
385 
386    o->contained = eina_inlist_remove(o->contained, EINA_INLIST_GET(obj));
387    o->member_count--;
388    obj->smart.parent = NULL;
389 
390    if (obj->is_smart) member_o = efl_data_scope_get(eo_obj, MY_CLASS);
391    _evas_object_smart_member_cache_invalidate(obj, member_o);
392 
393    if (obj->layer->layer != obj->cur->layer)
394      {
395         EINA_COW_STATE_WRITE_BEGIN(obj, state_write, cur)
396           state_write->layer = obj->layer->layer;
397         EINA_COW_STATE_WRITE_END(obj, state_write, cur);
398      }
399 
400    if (obj->is_smart)
401      {
402         if ((member_o->inherit_paragraph_direction) &&
403             (member_o->paragraph_direction != EVAS_BIDI_DIRECTION_NEUTRAL))
404           {
405              member_o->paragraph_direction = EVAS_BIDI_DIRECTION_NEUTRAL;
406              _efl_canvas_group_group_paragraph_direction_set_internal(eo_obj, EVAS_BIDI_DIRECTION_NEUTRAL);
407           }
408      }
409 
410    if (EINA_UNLIKELY(obj->in_layer))
411      {
412         ERR("Invalid internal state of object %p (child marked as being a"
413             "top-level object)!", obj->object);
414         evas_object_release(obj->object, obj, 1);
415      }
416    else
417      {
418         // Layer usage shouldn't reach 0 here (as parent is still in layer)
419         obj->layer->usage--;
420      }
421    /* layer may be destroyed in evas_object_release() call */
422    if (obj->layer)
423      evas_object_inject(eo_obj, obj, obj->layer->evas->evas);
424    obj->restack = 1;
425    evas_object_change(eo_obj, obj);
426    evas_object_mapped_clip_across_mark(eo_obj, obj);
427 }
428 
429 EAPI Eina_Bool
evas_object_smart_type_check(const Evas_Object * eo_obj,const char * type)430 evas_object_smart_type_check(const Evas_Object *eo_obj, const char *type)
431 {
432    const Evas_Smart_Class *sc;
433    Efl_Class *klass;
434    Eina_Bool type_check = EINA_FALSE;
435 
436    Evas_Object_Protected_Data *obj = EVAS_OBJ_GET_OR_RETURN(eo_obj, EINA_FALSE);
437 
438    klass = eina_hash_find(_evas_smart_class_names_hash_table, type);
439    if (klass) type_check = efl_isa(eo_obj, klass);
440 
441    /* Backward compatibility - walk over smart classes and compare type */
442    if (EINA_FALSE == type_check)
443      {
444         if (obj->smart.smart)
445           {
446              sc = obj->smart.smart->smart_class;
447              while (sc)
448                {
449                   if (!strcmp(sc->name, type)) return EINA_TRUE;
450                   sc = sc->parent;
451                }
452           }
453      }
454 
455    return type_check;
456 }
457 
458 EAPI Eina_Bool
evas_object_smart_type_check_ptr(const Eo * eo_obj,const char * type)459 evas_object_smart_type_check_ptr(const Eo *eo_obj, const char* type)
460 {
461    Efl_Class *klass;
462    const Evas_Smart_Class *sc;
463    Eina_Bool type_check = EINA_FALSE;
464 
465    Evas_Object_Protected_Data *obj = EVAS_OBJ_GET_OR_RETURN(eo_obj, EINA_FALSE);
466 
467    klass = eina_hash_find(_evas_smart_class_names_hash_table, type);
468    if (klass) type_check = efl_isa(eo_obj, klass);
469 
470    /* Backward compatibility - walk over smart classes and compare type */
471    if (EINA_FALSE == type_check)
472      {
473         if (obj->smart.smart)
474           {
475              sc = obj->smart.smart->smart_class;
476              while (sc)
477                {
478                   if (sc->name == type) return EINA_TRUE;
479                   sc = sc->parent;
480                }
481           }
482      }
483 
484    return type_check;
485 }
486 
487 EAPI void
evas_smart_legacy_type_register(const char * type,const Efl_Class * klass)488 evas_smart_legacy_type_register(const char *type, const Efl_Class *klass)
489 {
490    eina_hash_set(_evas_smart_class_names_hash_table, type, klass);
491 }
492 
493 static Eina_Bool
_efl_canvas_group_group_iterator_next(Evas_Object_Smart_Iterator * it,void ** data)494 _efl_canvas_group_group_iterator_next(Evas_Object_Smart_Iterator *it, void **data)
495 {
496    Evas_Object *eo;
497 
498    if (!it->current) return EINA_FALSE;
499 
500    eo = ((const Evas_Object_Protected_Data*)(it->current))->object;
501    if (data) *data = eo;
502 
503    it->current = it->current->next;
504 
505    return EINA_TRUE;
506 }
507 
508 static Evas_Object *
_efl_canvas_group_group_iterator_get_container(Evas_Object_Smart_Iterator * it)509 _efl_canvas_group_group_iterator_get_container(Evas_Object_Smart_Iterator *it)
510 {
511    return it->parent;
512 }
513 
514 static void
_efl_canvas_group_group_iterator_free(Evas_Object_Smart_Iterator * it)515 _efl_canvas_group_group_iterator_free(Evas_Object_Smart_Iterator *it)
516 {
517    efl_unref(it->parent);
518    free(it);
519 }
520 
521 // Should we have an efl_children_iterator_new API and just inherit from it ?
522 // No, because each hierarchy is different (Eo, Smart, Widget) -- jpeg
523 EOLIAN static Eina_Iterator*
_efl_canvas_group_group_members_iterate(const Eo * eo_obj,Evas_Smart_Data * priv)524 _efl_canvas_group_group_members_iterate(const Eo *eo_obj, Evas_Smart_Data *priv)
525 {
526    Evas_Object_Smart_Iterator *it;
527    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
528 
529    if (!priv->contained) return NULL;
530 
531    evas_object_async_block(obj);
532    it = calloc(1, sizeof(Evas_Object_Smart_Iterator));
533    if (!it) return NULL;
534 
535    EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
536    it->parent = efl_ref(eo_obj);
537    it->current = priv->contained;
538 
539    it->iterator.next = FUNC_ITERATOR_NEXT(_efl_canvas_group_group_iterator_next);
540    it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_efl_canvas_group_group_iterator_get_container);
541    it->iterator.free = FUNC_ITERATOR_FREE(_efl_canvas_group_group_iterator_free);
542 
543    return &it->iterator;
544 }
545 
546 EOLIAN static Eina_Bool
_efl_canvas_group_group_member_is(const Eo * eo_obj,Evas_Smart_Data * pd EINA_UNUSED,const Eo * sub_obj)547 _efl_canvas_group_group_member_is(const Eo *eo_obj, Evas_Smart_Data *pd EINA_UNUSED, const Eo *sub_obj)
548 {
549    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
550    Evas_Object_Protected_Data *sub = efl_data_scope_safe_get(sub_obj, EFL_CANVAS_OBJECT_CLASS);
551 
552    evas_object_async_block(obj);
553 
554    if (!sub) return EINA_FALSE;
555    return (sub->smart.parent == eo_obj);
556 }
557 
558 EAPI Eina_List*
evas_object_smart_members_get(const Evas_Object * eo_obj)559 evas_object_smart_members_get(const Evas_Object *eo_obj)
560 {
561    EVAS_OBJECT_SMART_GET_OR_RETURN(eo_obj, NULL);
562    Eina_List *members = NULL;
563    Eina_Inlist *member;
564 
565    for (member = o->contained; member; member = member->next)
566      members = eina_list_append(members, ((Evas_Object_Protected_Data *)member)->object);
567 
568    return members;
569 }
570 
571 void
evas_object_smart_render_cache_clear(Evas_Object * eo_obj)572 evas_object_smart_render_cache_clear(Evas_Object *eo_obj)
573 {
574    Evas_Smart_Data *o = efl_data_scope_get(eo_obj, MY_CLASS);
575    if (!o) return;
576    if (!o->render_cache) return;
577    evas_render_object_render_cache_free(eo_obj, o->render_cache);
578    o->render_cache = NULL;
579 }
580 
581 void *
evas_object_smart_render_cache_get(const Evas_Object * eo_obj)582 evas_object_smart_render_cache_get(const Evas_Object *eo_obj)
583 {
584    Evas_Smart_Data *o = efl_data_scope_get(eo_obj, MY_CLASS);
585    if (!o) return NULL;
586    return o->render_cache;
587 }
588 
589 void
evas_object_smart_render_cache_set(Evas_Object * eo_obj,void * data)590 evas_object_smart_render_cache_set(Evas_Object *eo_obj, void *data)
591 {
592    Evas_Smart_Data *o = efl_data_scope_get(eo_obj, MY_CLASS);
593    if (!o) return;
594    o->render_cache = data;
595 }
596 
597 const Eina_Inlist *
evas_object_smart_members_get_direct(const Evas_Object * eo_obj)598 evas_object_smart_members_get_direct(const Evas_Object *eo_obj)
599 {
600    Evas_Smart_Data *o = efl_data_scope_get(eo_obj, MY_CLASS);
601    if (!o) return NULL;
602    return o->contained;
603 }
604 
605 static void
_efl_canvas_group_group_members_all_del_internal(Evas_Smart_Data * o)606 _efl_canvas_group_group_members_all_del_internal(Evas_Smart_Data *o)
607 {
608    Evas_Object *clipper;
609    Evas_Object_Protected_Data *memobj;
610    Eina_Inlist *itrn;
611 
612    clipper = _smart_clipper_get(o);
613    if (clipper)
614      {
615         EINA_INLIST_FOREACH_SAFE(o->contained, itrn, memobj)
616           {
617              if (memobj->object != clipper)
618                _evas_wrap_del(&memobj->object, memobj);
619           }
620         _evas_wrap_del(&clipper, efl_data_scope_get(clipper, EFL_CANVAS_OBJECT_CLASS));
621      }
622 
623    o->group_del_called = EINA_TRUE;
624 }
625 
626 void
_efl_canvas_group_group_members_all_del(Evas_Object * eo_obj)627 _efl_canvas_group_group_members_all_del(Evas_Object *eo_obj)
628 {
629    Evas_Smart_Data *o = efl_data_scope_get(eo_obj, MY_CLASS);
630    _efl_canvas_group_group_members_all_del_internal(o);
631 }
632 
633 static void
_evas_smart_class_ifaces_private_data_alloc(Evas_Object * eo_obj,Evas_Smart * s)634 _evas_smart_class_ifaces_private_data_alloc(Evas_Object *eo_obj,
635                                             Evas_Smart *s)
636 {
637    Evas_Smart_Data *obj;
638    const Evas_Smart_Class *sc;
639    unsigned char *ptr;
640    unsigned int i, total_priv_sz = 0;
641 
642    /* get total size of interfaces private data */
643    for (sc = s->smart_class; sc; sc = sc->parent)
644      {
645         const Evas_Smart_Interface **ifaces_array = sc->interfaces;
646         if (!ifaces_array) continue;
647 
648         while (*ifaces_array)
649           {
650              const Evas_Smart_Interface *iface = *ifaces_array;
651 
652              if (!iface->name) break;
653 
654              if (iface->private_size > 0)
655                {
656                   unsigned int size = iface->private_size;
657 
658                   if (size % sizeof(void *) != 0)
659                     size += sizeof(void *) - (size % sizeof(void *));
660                   total_priv_sz += size;
661                }
662 
663              ifaces_array++;
664           }
665      }
666 
667    if (!s->interfaces.size && !total_priv_sz) return;
668 
669    obj = efl_data_scope_get(eo_obj, MY_CLASS);
670    obj->interface_privates = malloc(s->interfaces.size * sizeof(void *) + total_priv_sz);
671    if (!obj->interface_privates)
672      {
673         ERR("malloc failed!");
674         return;
675      }
676 
677    /* make private data array ptrs point to right places, WHICH LIE ON
678     * THE SAME STRUCT, AFTER THE # OF INTERFACES COUNT */
679    ptr = (unsigned char *)(obj->interface_privates + s->interfaces.size);
680    for (i = 0; i < s->interfaces.size; i++)
681      {
682         unsigned int size;
683 
684         size = s->interfaces.array[i]->private_size;
685 
686         if (size == 0)
687           {
688              obj->interface_privates[i] = NULL;
689              continue;
690           }
691 
692         obj->interface_privates[i] = ptr;
693         memset(ptr, 0, size);
694 
695         if (size % sizeof(void *) != 0)
696           size += sizeof(void *) - (size % sizeof(void *));
697         ptr += size;
698      }
699 }
700 
701 EAPI Evas_Object *
evas_object_smart_add(Evas * eo_e,Evas_Smart * s)702 evas_object_smart_add(Evas *eo_e, Evas_Smart *s)
703 {
704    Evas_Object *eo_obj;
705 
706    eo_e = evas_find(eo_e);
707    EINA_SAFETY_ON_FALSE_RETURN_VAL(efl_isa(eo_e, EVAS_CANVAS_CLASS), NULL);
708    eo_obj = efl_add(MY_CLASS, eo_e, efl_canvas_object_legacy_ctor(efl_added));
709    evas_object_smart_attach(eo_obj, s);
710    return eo_obj;
711 }
712 
713 EOLIAN static Eo *
_efl_canvas_group_efl_object_constructor(Eo * eo_obj,Evas_Smart_Data * sd)714 _efl_canvas_group_efl_object_constructor(Eo *eo_obj, Evas_Smart_Data *sd)
715 {
716    Evas_Object_Protected_Data *obj;
717 
718    sd->object = eo_obj;
719    sd->inherit_paragraph_direction = EINA_TRUE;
720 
721    eo_obj = efl_constructor(efl_super(eo_obj, MY_CLASS));
722    EINA_SAFETY_ON_NULL_RETURN_VAL(eo_obj, NULL);
723 
724    obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
725    obj->is_smart = EINA_TRUE;
726    obj->func = &object_func;
727    obj->private_data = efl_data_ref(eo_obj, MY_CLASS);
728    if (sd->clipped && !sd->data)
729      _evas_object_smart_clipped_init(eo_obj);
730 
731    efl_canvas_object_type_set(eo_obj, MY_CLASS_NAME_LEGACY);
732    efl_canvas_group_add(eo_obj);
733 
734    sd->constructed = EINA_TRUE;
735    return eo_obj;
736 }
737 
738 EOLIAN static void
_efl_canvas_group_efl_object_destructor(Eo * eo_obj,Evas_Smart_Data * o)739 _efl_canvas_group_efl_object_destructor(Eo *eo_obj, Evas_Smart_Data *o)
740 {
741    efl_destructor(efl_super(eo_obj, MY_CLASS));
742    if (o->data && !o->data_nofree)
743      free(o->data);
744    if (!o->group_del_called)
745      {
746         ERR("efl_canvas_group_del() was not called on this object: %p (%s)",
747             eo_obj, efl_class_name_get(eo_obj));
748      }
749 }
750 
751 EOLIAN static void
_efl_canvas_group_efl_object_debug_name_override(Eo * eo_obj,Evas_Smart_Data * o,Eina_Strbuf * sb)752 _efl_canvas_group_efl_object_debug_name_override(Eo *eo_obj, Evas_Smart_Data *o, Eina_Strbuf *sb)
753 {
754    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
755    const char *smart_class = NULL;
756 
757    if (obj->smart.smart && obj->smart.smart->smart_class)
758      smart_class = obj->smart.smart->smart_class->name;
759 
760    efl_debug_name_override(efl_super(eo_obj, MY_CLASS), sb);
761    if (smart_class)
762      {
763         eina_strbuf_append_printf(sb, ":children=%d:smart_class=%s",
764                                   eina_inlist_count(o->contained), smart_class);
765      }
766    else
767      {
768         eina_strbuf_append_printf(sb, ":children=%d", eina_inlist_count(o->contained));
769      }
770 }
771 
772 static inline void
_evas_object_smart_move_relative_internal(Evas_Smart_Data * o,Evas_Coord dx,Evas_Coord dy)773 _evas_object_smart_move_relative_internal(Evas_Smart_Data *o, Evas_Coord dx, Evas_Coord dy)
774 {
775    Evas_Object_Protected_Data *child;
776 
777    EINA_INLIST_FOREACH(o->contained, child)
778      {
779         Evas_Coord orig_x, orig_y;
780 
781         if (child->delete_me) continue;
782         if (child->is_static_clip) continue;
783         orig_x = child->cur->geometry.x;
784         orig_y = child->cur->geometry.y;
785         evas_object_move(child->object, orig_x + dx, orig_y + dy);
786      }
787 }
788 
789 EAPI void
evas_object_smart_move_children_relative(Eo * eo_obj,Evas_Coord dx,Evas_Coord dy)790 evas_object_smart_move_children_relative(Eo *eo_obj, Evas_Coord dx, Evas_Coord dy)
791 {
792    EVAS_OBJECT_SMART_GET_OR_RETURN(eo_obj);
793 
794    if ((dx == 0) && (dy == 0)) return;
795    _evas_object_smart_move_relative_internal(o, dx, dy);
796 }
797 
798 void
_evas_object_smart_clipped_smart_move_internal(Evas_Object * eo_obj,Evas_Coord x,Evas_Coord y)799 _evas_object_smart_clipped_smart_move_internal(Evas_Object *eo_obj, Evas_Coord x, Evas_Coord y)
800 {
801    Evas_Smart_Data *o = efl_data_scope_get(eo_obj, MY_CLASS);
802    Evas_Coord orig_x, orig_y;
803 
804    orig_x = o->x;
805    orig_y = o->y;
806    o->x = x;
807    o->y = y;
808    _evas_object_smart_move_relative_internal(o, x - orig_x, y - orig_y);
809 }
810 
811 void
_evas_object_smart_clipped_init(Evas_Object * eo_obj)812 _evas_object_smart_clipped_init(Evas_Object *eo_obj)
813 {
814    EVAS_OBJECT_SMART_GET_OR_RETURN(eo_obj);
815    Evas_Object_Smart_Clipped_Data *cso;
816    Evas_Object *clipper;
817 
818    // user may realloc this... (legacy only!)
819    cso = o->data;
820    if (!cso)
821      {
822         cso = calloc(1, sizeof(*cso));
823         o->data = cso;
824         o->data_nofree = EINA_FALSE;
825      }
826 
827    cso->evas = evas_object_evas_get(eo_obj);
828    clipper = evas_object_rectangle_add(cso->evas);
829    evas_object_static_clip_set(clipper, 1);
830    cso->clipper = clipper;
831    o->clipped = 0;
832    evas_object_smart_member_add(clipper, eo_obj);
833    o->clipped = 1;
834    evas_object_color_set(cso->clipper, 255, 255, 255, 255);
835    evas_object_move(cso->clipper, -100000, -100000);
836    evas_object_resize(cso->clipper, 200000, 200000);
837    evas_object_pass_events_set(cso->clipper, 1);
838    evas_object_hide(cso->clipper); /* show when have something clipped to it */
839    efl_canvas_object_no_render_set(cso->clipper, 1);
840 }
841 
842 EOLIAN static void
_efl_canvas_group_group_add(Eo * eo_obj EINA_UNUSED,Evas_Smart_Data * o EINA_UNUSED)843 _efl_canvas_group_group_add(Eo *eo_obj EINA_UNUSED, Evas_Smart_Data *o EINA_UNUSED)
844 {
845 }
846 
847 EOLIAN static void
_efl_canvas_group_group_del(Eo * eo_obj EINA_UNUSED,Evas_Smart_Data * o)848 _efl_canvas_group_group_del(Eo *eo_obj EINA_UNUSED, Evas_Smart_Data *o)
849 {
850    if (o->clipped)
851      {
852         _efl_canvas_group_group_members_all_del_internal(o);
853      }
854    o->group_del_called = EINA_TRUE;
855 }
856 
857 EOLIAN static void
_efl_canvas_group_efl_canvas_object_no_render_set(Eo * eo_obj,Evas_Smart_Data * o,Eina_Bool enable)858 _efl_canvas_group_efl_canvas_object_no_render_set(Eo *eo_obj, Evas_Smart_Data *o, Eina_Bool enable)
859 {
860    Evas_Object_Protected_Data *obj2;
861    Eo *clipper;
862 
863    enable = !!enable;
864    if (efl_canvas_object_no_render_get(eo_obj) == enable) return;
865 
866    efl_canvas_object_no_render_set(efl_super(eo_obj, MY_CLASS), enable);
867 
868    clipper = (o->clipped) ? _smart_clipper_get(o) : NULL;
869    EINA_INLIST_FOREACH(o->contained, obj2)
870      {
871         if (obj2->object != clipper)
872           efl_canvas_object_no_render_set(obj2->object, enable);
873      }
874 }
875 
876 EOLIAN static void
_efl_canvas_group_efl_gfx_color_color_set(Eo * eo_obj,Evas_Smart_Data * o,int r,int g,int b,int a)877 _efl_canvas_group_efl_gfx_color_color_set(Eo *eo_obj, Evas_Smart_Data *o, int r, int g, int b, int a)
878 {
879    if (_evas_object_intercept_call(eo_obj, EVAS_OBJECT_INTERCEPT_CB_COLOR_SET, 0, r, g, b, a))
880      return;
881 
882    efl_gfx_color_set(efl_super(eo_obj, MY_CLASS), r, g, b, a);
883 
884    if (o->clipped)
885      {
886         Evas_Object *clipper = _smart_clipper_get(o);
887         EINA_SAFETY_ON_NULL_RETURN(clipper);
888 
889         efl_gfx_color_set(clipper, r, g, b, a);
890         // Note: Legacy impl (and Widget) didn't call super in this case...
891      }
892 }
893 
894 EOLIAN static void
_efl_canvas_group_efl_gfx_entity_visible_set(Eo * eo_obj,Evas_Smart_Data * o,Eina_Bool vis)895 _efl_canvas_group_efl_gfx_entity_visible_set(Eo *eo_obj, Evas_Smart_Data *o, Eina_Bool vis)
896 {
897    if (_evas_object_intercept_call(eo_obj, EVAS_OBJECT_INTERCEPT_CB_VISIBLE, 0, vis))
898      return;
899 
900    efl_gfx_entity_visible_set(efl_super(eo_obj, MY_CLASS), vis);
901 
902    if (o->clipped)
903      {
904         Evas_Object *clipper = _smart_clipper_get(o);
905         EINA_SAFETY_ON_NULL_RETURN(clipper);
906 
907         // note: maybe this is not necessary with no_render set on the clipper
908         if (vis && !evas_object_clipees_has(clipper))
909           return;
910 
911         efl_gfx_entity_visible_set(clipper, vis);
912      }
913 
914    if (o->filter_img)
915       efl_gfx_entity_visible_set(o->filter_img, vis);
916 }
917 
918 EOLIAN static void
_efl_canvas_group_efl_gfx_entity_position_set(Eo * eo_obj,Evas_Smart_Data * o,Eina_Position2D pos)919 _efl_canvas_group_efl_gfx_entity_position_set(Eo *eo_obj, Evas_Smart_Data *o, Eina_Position2D pos)
920 {
921    Eina_Bool is_overridden;
922    Evas_Object_Protected_Data *obj = EVAS_OBJ_GET_OR_RETURN(eo_obj);
923 
924    if (_evas_object_intercept_call(eo_obj, EVAS_OBJECT_INTERCEPT_CB_MOVE, 0, pos.x, pos.y))
925      return;
926 
927    is_overridden = (obj->is_smart && obj->smart.smart &&
928                     obj->smart.smart->smart_class->move !=
929                     (void *)evas_object_smart_clipped_smart_move);
930 
931    if (o->clipped && !is_overridden)
932      _evas_object_smart_clipped_smart_move_internal(eo_obj, pos.x, pos.y);
933    efl_gfx_entity_position_set(efl_super(eo_obj, MY_CLASS), pos);
934    if (o->filter_img) efl_gfx_entity_position_set(o->filter_img, pos);
935 }
936 
937 EOLIAN static void
_efl_canvas_group_efl_gfx_entity_size_set(Eo * obj,Evas_Smart_Data * o,Eina_Size2D size)938 _efl_canvas_group_efl_gfx_entity_size_set(Eo *obj, Evas_Smart_Data *o, Eina_Size2D size)
939 {
940    if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_RESIZE, 0, size.w, size.h))
941      return;
942 
943    efl_gfx_entity_size_set(efl_super(obj, MY_CLASS), size);
944    if (o->filter_img) efl_gfx_entity_size_set(o->filter_img, size);
945 }
946 
947 EOLIAN static void
_efl_canvas_group_efl_gfx_filter_filter_program_set(Eo * eo_obj,Evas_Smart_Data * o,const char * code,const char * name)948 _efl_canvas_group_efl_gfx_filter_filter_program_set(Eo *eo_obj, Evas_Smart_Data *o,
949                                                     const char *code, const char *name)
950 {
951    Evas_Object_Protected_Data *obj, *fobj;
952    obj = EVAS_OBJ_GET_OR_RETURN(eo_obj);
953 
954    if (!code && !name)
955      {
956         if (o->filter_img)
957           {
958              evas_object_del(o->filter_img);
959              o->filter_img = NULL;
960           }
961         return;
962      }
963 
964    if (o->filter_img)
965      {
966         efl_gfx_filter_program_set(o->filter_img, code, name);
967         return;
968      }
969 
970    o->filter_img = efl_add(EFL_CANVAS_PROXY_CLASS, eo_obj,
971                            efl_gfx_fill_auto_set(efl_added, EINA_TRUE),
972                            efl_canvas_group_member_add(obj->object, efl_added),
973                            efl_canvas_proxy_source_events_set(efl_added, EINA_TRUE),
974                            efl_canvas_proxy_source_set(efl_added, eo_obj),
975                            evas_object_repeat_events_set(efl_added, EINA_TRUE),
976                            efl_gfx_filter_program_set(efl_added, code, name),
977                            efl_gfx_entity_geometry_set(efl_added, (Eina_Rect)obj->cur->geometry),
978                            efl_gfx_entity_visible_set(efl_added, obj->cur->visible));
979 
980    fobj = efl_data_scope_get(o->filter_img, EFL_CANVAS_OBJECT_CLASS);
981    if (!fobj) return;
982    fobj->is_filter_object = EINA_TRUE;
983 }
984 
985 EOLIAN static void
_efl_canvas_group_efl_canvas_object_clipper_set(Eo * eo_obj,Evas_Smart_Data * o,Evas_Object * clip)986 _efl_canvas_group_efl_canvas_object_clipper_set(Eo *eo_obj, Evas_Smart_Data *o, Evas_Object *clip)
987 {
988    EINA_SAFETY_ON_FALSE_RETURN(!clip || efl_isa(clip, EFL_CANVAS_OBJECT_CLASS));
989    if (_evas_object_intercept_call(eo_obj, EVAS_OBJECT_INTERCEPT_CB_CLIP_SET, 0, clip))
990      return;
991 
992    efl_canvas_object_clipper_set(efl_super(eo_obj, MY_CLASS), clip);
993 
994    if (o->clipped)
995      {
996         Evas_Object *clipper = _smart_clipper_get(o);
997         EINA_SAFETY_ON_NULL_RETURN(clipper);
998 
999         efl_canvas_object_clipper_set(clipper, clip);
1000      }
1001 }
1002 
1003 void
evas_object_smart_attach(Evas_Object * eo_obj,Evas_Smart * s)1004 evas_object_smart_attach(Evas_Object *eo_obj, Evas_Smart *s)
1005 {
1006    Evas_Object_Protected_Data *obj = EVAS_OBJ_GET_OR_RETURN(eo_obj);
1007    unsigned int i;
1008 
1009    MAGIC_CHECK(s, Evas_Smart, MAGIC_SMART);
1010    return;
1011    MAGIC_CHECK_END();
1012 
1013    obj->smart.smart = s;
1014    obj->type = s->smart_class->name;
1015    evas_object_smart_use(s);
1016 
1017    _evas_smart_class_ifaces_private_data_alloc(eo_obj, s);
1018 
1019    for (i = 0; i < s->interfaces.size; i++)
1020      {
1021         const Evas_Smart_Interface *iface;
1022 
1023         iface = s->interfaces.array[i];
1024         if (iface->add)
1025           {
1026              if (!iface->add(eo_obj))
1027                {
1028                   ERR("failed to create interface %s\n", iface->name);
1029                   evas_object_del(eo_obj);
1030                   return;
1031                }
1032           }
1033      }
1034 
1035    //efl_canvas_group_add(eo_obj);
1036    if (s->smart_class->add) s->smart_class->add(eo_obj);
1037 }
1038 
1039 EAPI void
evas_object_smart_callback_add(Evas_Object * eo_obj,const char * event,Evas_Smart_Cb func,const void * data)1040 evas_object_smart_callback_add(Evas_Object *eo_obj, const char *event, Evas_Smart_Cb func, const void *data)
1041 {
1042    evas_object_smart_callback_priority_add(eo_obj, event,
1043          EVAS_CALLBACK_PRIORITY_DEFAULT, func, data);
1044 }
1045 
1046 static void
_smart_cb_check(Evas_Smart_Data * o,const char * event)1047 _smart_cb_check(Evas_Smart_Data *o, const char *event)
1048 {
1049    if (!o->cb_move)
1050      {
1051         if (eina_streq(event, "move"))
1052           {
1053              o->cb_move = EINA_TRUE;
1054              return;
1055           }
1056      }
1057    if (!o->cb_resize)
1058      {
1059         if (eina_streq(event, "resize"))
1060           {
1061              o->cb_resize = EINA_TRUE;
1062              return;
1063           }
1064      }
1065    if (!o->cb_restack)
1066      {
1067         if (eina_streq(event, "restack"))
1068           {
1069              o->cb_restack = EINA_TRUE;
1070              return;
1071           }
1072      }
1073 }
1074 
1075 EAPI void
evas_object_smart_callback_priority_add(Evas_Object * eo_obj,const char * event,Evas_Callback_Priority priority,Evas_Smart_Cb func,const void * data)1076 evas_object_smart_callback_priority_add(Evas_Object *eo_obj, const char *event, Evas_Callback_Priority priority, Evas_Smart_Cb func, const void *data)
1077 {
1078    EVAS_OBJECT_SMART_GET_OR_RETURN(eo_obj);
1079 
1080    if (!event) return;
1081    if (!func) return;
1082 
1083    const Efl_Event_Description *eo_desc = efl_object_legacy_only_event_description_get(event);
1084    _eo_evas_smart_cb_info *cb_info = calloc(1, sizeof(*cb_info));
1085    cb_info->func = func;
1086    cb_info->data = (void *)data;
1087    cb_info->event = eo_desc;
1088    _smart_cb_check(o, event);
1089 
1090    o->callbacks = eina_inlist_append(o->callbacks,
1091         EINA_INLIST_GET(cb_info));
1092 
1093    efl_event_callback_priority_add(eo_obj, eo_desc, priority, _eo_evas_smart_cb, cb_info);
1094 }
1095 
1096 EAPI void *
evas_object_smart_callback_del(Evas_Object * eo_obj,const char * event,Evas_Smart_Cb func)1097 evas_object_smart_callback_del(Evas_Object *eo_obj, const char *event, Evas_Smart_Cb func)
1098 {
1099    _eo_evas_smart_cb_info *info;
1100 
1101    EVAS_OBJECT_SMART_GET_OR_RETURN(eo_obj, NULL);
1102 
1103    if (!event) return NULL;
1104 
1105    const Efl_Event_Description *eo_desc = efl_object_legacy_only_event_description_get(event);
1106 
1107    EINA_INLIST_FOREACH(o->callbacks, info)
1108      {
1109         if ((info->func == func) && (info->event == eo_desc))
1110           {
1111              void *tmp = info->data;
1112              efl_event_callback_del(eo_obj, eo_desc, _eo_evas_smart_cb, info);
1113 
1114              o->callbacks =
1115                 eina_inlist_remove(o->callbacks, EINA_INLIST_GET(info));
1116              free(info);
1117              return tmp;
1118           }
1119      }
1120    return NULL;
1121 }
1122 
1123 EAPI void *
evas_object_smart_callback_del_full(Evas_Object * eo_obj,const char * event,Evas_Smart_Cb func,const void * data)1124 evas_object_smart_callback_del_full(Evas_Object *eo_obj, const char *event, Evas_Smart_Cb func, const void *data)
1125 {
1126    _eo_evas_smart_cb_info *info;
1127 
1128    EVAS_OBJECT_SMART_GET_OR_RETURN(eo_obj, NULL);
1129 
1130    if (!event) return NULL;
1131 
1132    const Efl_Event_Description *eo_desc = efl_object_legacy_only_event_description_get(event);
1133 
1134    EINA_INLIST_FOREACH(o->callbacks, info)
1135      {
1136         if ((info->func == func) && (info->event == eo_desc) && (info->data == data))
1137           {
1138              void *tmp = info->data;
1139              efl_event_callback_del(eo_obj, eo_desc, _eo_evas_smart_cb, info);
1140 
1141              o->callbacks =
1142                 eina_inlist_remove(o->callbacks, EINA_INLIST_GET(info));
1143              free(info);
1144              return tmp;
1145           }
1146      }
1147    return NULL;
1148 }
1149 
1150 EAPI void
evas_object_smart_callback_call(Evas_Object * eo_obj,const char * event,void * event_info)1151 evas_object_smart_callback_call(Evas_Object *eo_obj, const char *event, void *event_info)
1152 {
1153    MAGIC_CHECK(eo_obj, Evas_Object, MAGIC_OBJ);
1154    return;
1155    MAGIC_CHECK_END();
1156 
1157    if (!event) return;
1158    const Efl_Event_Description *eo_desc = efl_object_legacy_only_event_description_get(event);
1159    efl_event_callback_legacy_call(eo_obj, eo_desc, event_info);
1160 }
1161 
1162 void
_evas_object_smart_callback_call_internal(Evas_Object * eo_obj,const Efl_Event_Description * efl_event_desc)1163 _evas_object_smart_callback_call_internal(Evas_Object *eo_obj, const Efl_Event_Description *efl_event_desc)
1164 {
1165    const char *event = NULL;
1166    EVAS_OBJECT_SMART_GET_OR_RETURN(eo_obj);
1167 
1168    if (efl_event_desc == EFL_GFX_ENTITY_EVENT_POSITION_CHANGED)
1169      {
1170         if (!o->cb_move) return;
1171         event = "move";
1172      }
1173    else if (efl_event_desc == EFL_GFX_ENTITY_EVENT_SIZE_CHANGED)
1174      {
1175         if (!o->cb_resize) return;
1176         event = "resize";
1177      }
1178    else if (efl_event_desc == EFL_GFX_ENTITY_EVENT_STACKING_CHANGED)
1179      {
1180         if (!o->cb_restack) return;
1181         event = "restack";
1182      }
1183    else //invalidate
1184      return;
1185    const Efl_Event_Description *eo_desc = efl_object_legacy_only_event_description_get(event);
1186    efl_event_callback_legacy_call(eo_obj, eo_desc, NULL);
1187 }
1188 
1189 EAPI Eina_Bool
evas_object_smart_callbacks_descriptions_set(Eo * eo_obj,const Evas_Smart_Cb_Description * descriptions)1190 evas_object_smart_callbacks_descriptions_set(Eo *eo_obj, const Evas_Smart_Cb_Description *descriptions)
1191 {
1192    EVAS_OBJECT_SMART_GET_OR_RETURN(eo_obj, EINA_FALSE);
1193    const Evas_Smart_Cb_Description *d;
1194    unsigned int i, count = 0;
1195 
1196    if ((!descriptions) || (!descriptions->name))
1197      {
1198         evas_smart_cb_descriptions_resize(&o->callbacks_descriptions, 0);
1199         return EINA_TRUE;
1200      }
1201 
1202    for (count = 0, d = descriptions; d->name; d++)
1203      count++;
1204 
1205    evas_smart_cb_descriptions_resize(&o->callbacks_descriptions, count);
1206    if (count == 0) return EINA_TRUE;
1207 
1208    for (i = 0, d = descriptions; i < count; d++, i++)
1209      o->callbacks_descriptions.array[i] = d;
1210 
1211    evas_smart_cb_descriptions_fix(&o->callbacks_descriptions);
1212 
1213    return EINA_TRUE;
1214 }
1215 
1216 EAPI void
evas_object_smart_callbacks_descriptions_get(const Eo * eo_obj,const Evas_Smart_Cb_Description *** class_descriptions,unsigned int * class_count,const Evas_Smart_Cb_Description *** instance_descriptions,unsigned int * instance_count)1217 evas_object_smart_callbacks_descriptions_get(const Eo *eo_obj, const Evas_Smart_Cb_Description ***class_descriptions, unsigned int *class_count, const Evas_Smart_Cb_Description ***instance_descriptions, unsigned int *instance_count)
1218 {
1219    EVAS_OBJECT_SMART_GET_OR_RETURN(eo_obj);
1220    if (class_descriptions) *class_descriptions = NULL;
1221    if (class_count) *class_count = 0;
1222 
1223    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
1224    if (obj->smart.smart && class_descriptions)
1225       *class_descriptions = obj->smart.smart->callbacks.array;
1226    if (obj->smart.smart && class_count)
1227      *class_count = obj->smart.smart->callbacks.size;
1228 
1229    if (instance_descriptions)
1230      *instance_descriptions = o->callbacks_descriptions.array;
1231    if (instance_count)
1232      *instance_count = o->callbacks_descriptions.size;
1233 }
1234 
1235 EAPI void
evas_object_smart_callback_description_find(const Eo * eo_obj,const char * name,const Evas_Smart_Cb_Description ** class_description,const Evas_Smart_Cb_Description ** instance_description)1236 evas_object_smart_callback_description_find(const Eo *eo_obj, const char *name, const Evas_Smart_Cb_Description **class_description, const Evas_Smart_Cb_Description **instance_description)
1237 {
1238    EVAS_OBJECT_SMART_GET_OR_RETURN(eo_obj);
1239 
1240    if (!name)
1241      {
1242         if (class_description) *class_description = NULL;
1243         if (instance_description) *instance_description = NULL;
1244         return;
1245      }
1246 
1247    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
1248    if (class_description)
1249      *class_description = evas_smart_cb_description_find
1250         (&obj->smart.smart->callbacks, name);
1251 
1252    if (instance_description)
1253      *instance_description = evas_smart_cb_description_find
1254         (&o->callbacks_descriptions, name);
1255 }
1256 
1257 EOLIAN static void
_efl_canvas_group_group_need_recalculate_set(Eo * eo_obj,Evas_Smart_Data * o,Eina_Bool value)1258 _efl_canvas_group_group_need_recalculate_set(Eo *eo_obj, Evas_Smart_Data *o, Eina_Bool value)
1259 {
1260    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
1261 
1262    // XXX: do i need this?
1263    if (!obj || !obj->layer || obj->delete_me) return;
1264 
1265    evas_object_async_block(obj);
1266    /* remove this entry from calc_list or processed list */
1267    if (eina_clist_element_is_linked(&o->calc_entry))
1268      eina_clist_remove(&o->calc_entry);
1269 
1270    value = !!value;
1271    if (value)
1272      eina_clist_add_tail(&obj->layer->evas->calc_list, &o->calc_entry);
1273    else
1274      eina_clist_add_tail(&obj->layer->evas->calc_done, &o->calc_entry);
1275 
1276    if (o->need_recalculate == value) return;
1277 
1278    if (o->recalculate_cycle > 16382)
1279      {
1280         ERR("Object %p is not stable during recalc loop", eo_obj);
1281         return;
1282      }
1283    if (obj->layer->evas->in_smart_calc) o->recalculate_cycle++;
1284    o->need_recalculate = value;
1285 }
1286 
1287 EOLIAN static Eina_Bool
_efl_canvas_group_group_need_recalculate_get(const Eo * eo_obj EINA_UNUSED,Evas_Smart_Data * o)1288 _efl_canvas_group_group_need_recalculate_get(const Eo *eo_obj EINA_UNUSED, Evas_Smart_Data *o)
1289 {
1290    return o->need_recalculate;
1291 }
1292 
1293 EOLIAN static void
_efl_canvas_group_group_calculate(Eo * eo_obj,Evas_Smart_Data * o)1294 _efl_canvas_group_group_calculate(Eo *eo_obj, Evas_Smart_Data *o)
1295 {
1296    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
1297 
1298    if (!obj->smart.smart || !obj->smart.smart->smart_class->calculate)
1299      return;
1300 
1301    evas_object_async_block(obj);
1302    o->need_recalculate = 0;
1303    obj->smart.smart->smart_class->calculate(eo_obj);
1304 }
1305 
1306 /**
1307  * Call calculate() on all smart objects that need_recalculate.
1308  *
1309  * @internal
1310  */
1311 void
evas_call_smarts_calculate(Evas * eo_e)1312 evas_call_smarts_calculate(Evas *eo_e)
1313 {
1314    Evas_Smart_Data *o;
1315    Eina_Clist *elem;
1316    Evas_Public_Data *e = efl_data_scope_get(eo_e, EVAS_CANVAS_CLASS);
1317 
1318    evas_canvas_async_block(e);
1319    evas_event_freeze(eo_e);
1320    e->in_smart_calc++;
1321 
1322    while (NULL != (elem = eina_clist_head(&e->calc_list)))
1323      {
1324         Evas_Object_Protected_Data *obj;
1325 
1326         /* move the item to the processed list */
1327         o = EINA_CLIST_ENTRY(elem, Evas_Smart_Data, calc_entry);
1328         eina_clist_remove(&o->calc_entry);
1329         obj = efl_data_scope_get(o->object, EFL_CANVAS_OBJECT_CLASS);
1330 
1331         if (obj->delete_me) continue;
1332         eina_clist_add_tail(&e->calc_done, &o->calc_entry);
1333 
1334         if (o->need_recalculate)
1335           {
1336              o->need_recalculate = 0;
1337 	     if (obj->smart.smart && obj->smart.smart->smart_class->calculate)
1338                obj->smart.smart->smart_class->calculate(obj->object);
1339              else
1340                efl_canvas_group_calculate(obj->object);
1341           }
1342      }
1343 
1344    while (NULL != (elem = eina_clist_head(&e->calc_done)))
1345      {
1346         o = EINA_CLIST_ENTRY(elem, Evas_Smart_Data, calc_entry);
1347         o->recalculate_cycle = 0;
1348         eina_clist_remove(&o->calc_entry);
1349      }
1350 
1351    e->in_smart_calc--;
1352    if (e->in_smart_calc == 0) e->smart_calc_count++;
1353    evas_event_thaw(eo_e);
1354    evas_event_thaw_eval(eo_e);
1355 }
1356 
1357 EOLIAN static void
_efl_canvas_group_group_change(Eo * eo_obj,Evas_Smart_Data * o EINA_UNUSED)1358 _efl_canvas_group_group_change(Eo *eo_obj, Evas_Smart_Data *o EINA_UNUSED)
1359 {
1360    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
1361    evas_object_async_block(obj);
1362    evas_object_change(eo_obj, obj);
1363    efl_canvas_group_need_recalculate_set(eo_obj, 1);
1364 }
1365 
1366 Eina_Bool
evas_object_smart_changed_get(Evas_Object_Protected_Data * obj)1367 evas_object_smart_changed_get(Evas_Object_Protected_Data *obj)
1368 {
1369    Eina_Bool has_map = EINA_FALSE;
1370 
1371    /* If object is invisible, it's meaningless to figure out changed state
1372       for rendering. */
1373 
1374    //a. Object itself visibility
1375    if (obj->no_render || (!obj->prev->visible && !obj->cur->visible) ||
1376        ((obj->prev->color.a == 0) && (obj->cur->color.a == 0)))
1377      return EINA_FALSE;
1378 
1379    //b. Object clipper visibility
1380    if ((obj->prev->clipper && obj->cur->clipper) &&
1381        ((!obj->prev->clipper->cur->visible &&
1382          !obj->cur->clipper->cur->visible) ||
1383         ((obj->prev->clipper->cur->color.a == 0) &&
1384          (obj->cur->clipper->cur->color.a == 0))))
1385      return EINA_FALSE;
1386 
1387    if (!obj->clip.clipees)
1388      {
1389         has_map = _evas_render_has_map(obj) && !_evas_render_can_map(obj);
1390         if (obj->changed && !obj->is_smart && !has_map) return EINA_TRUE;
1391 
1392         if (has_map)
1393           {
1394              if ((obj->need_surface_clear && obj->changed && !obj->is_smart) ||
1395                  ((obj->changed_pchange) && (obj->changed_map)))
1396                return EINA_TRUE;
1397           }
1398      }
1399 
1400    if (obj->is_smart)
1401      {
1402         Evas_Object_Protected_Data *o2;
1403 
1404         EINA_INLIST_FOREACH(evas_object_smart_members_get_direct(obj->object), o2)
1405           if (evas_object_smart_changed_get(o2)) return EINA_TRUE;
1406      }
1407 
1408    return EINA_FALSE;
1409 }
1410 
1411 void
evas_object_smart_del(Evas_Object * eo_obj)1412 evas_object_smart_del(Evas_Object *eo_obj)
1413 {
1414    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
1415    Evas_Smart_Data *sobj;
1416    Evas_Smart *s;
1417    unsigned int i;
1418 
1419    if (obj->delete_me) return;
1420 
1421    sobj = efl_data_scope_get(eo_obj, MY_CLASS);
1422    s = obj->smart.smart;
1423    if (s && s->smart_class->del)
1424      {
1425         s->smart_class->del(eo_obj);
1426         //this is legacy, this will never be called..., smart things dont have inheritance
1427         sobj->group_del_called = EINA_TRUE;
1428      }
1429    else
1430       efl_canvas_group_del(eo_obj);
1431    if (obj->smart.parent) evas_object_smart_member_del(eo_obj);
1432 
1433    if (s)
1434      {
1435         for (i = 0; i < s->interfaces.size; i++)
1436           {
1437              const Evas_Smart_Interface *iface;
1438 
1439              iface = s->interfaces.array[i];
1440              if (iface->del) iface->del(eo_obj);
1441           }
1442      }
1443 
1444    free(sobj->interface_privates);
1445    sobj->interface_privates = NULL;
1446 
1447    if (s) evas_object_smart_unuse(s);
1448 }
1449 
1450 void
evas_object_update_bounding_box(Evas_Object * eo_obj EINA_UNUSED,Evas_Object_Protected_Data * obj,Evas_Smart_Data * s)1451 evas_object_update_bounding_box(Evas_Object *eo_obj EINA_UNUSED, Evas_Object_Protected_Data *obj, Evas_Smart_Data *s)
1452 {
1453    Eina_Bool propagate = EINA_FALSE;
1454    Eina_Bool computeminmax = EINA_FALSE;
1455    Evas_Coord x, y, w, h;
1456    Evas_Coord px, py, pw, ph;
1457    Eina_Bool noclip;
1458 
1459    if (!obj->smart.parent) return;
1460 
1461    if (obj->child_has_map) return; /* Disable bounding box computation for this object and its parent */
1462    /* We could also remove object that are not visible from the bounding box, use the clipping information
1463       to reduce the bounding of the object they are clipping, but for the moment this will do it's jobs */
1464    noclip = !(obj->clip.clipees || obj->is_static_clip);
1465 
1466    if (obj->is_smart)
1467      {
1468         if (!s) s = obj->private_data;
1469 
1470         x = s->cur.bounding_box.x;
1471         y = s->cur.bounding_box.y;
1472         w = s->cur.bounding_box.w;
1473         h = s->cur.bounding_box.h;
1474         px = s->prev.bounding_box.x;
1475         py = s->prev.bounding_box.y;
1476         pw = s->prev.bounding_box.w;
1477         ph = s->prev.bounding_box.h;
1478      }
1479    else
1480      {
1481         x = obj->cur->geometry.x;
1482         y = obj->cur->geometry.y;
1483         w = obj->cur->geometry.w;
1484         h = obj->cur->geometry.h;
1485         px = obj->prev->geometry.x;
1486         py = obj->prev->geometry.y;
1487         pw = obj->prev->geometry.w;
1488         ph = obj->prev->geometry.h;
1489      }
1490 
1491    /* We are not yet trying to find the smallest bounding box, but we want to find a good approximation quickly.
1492     * That's why we initialiaze min and max search to geometry of the parent object.
1493     */
1494    Evas_Object_Protected_Data *smart_obj = obj->smart.parent_object_data;
1495    Evas_Smart_Data *smart_parent = obj->smart.parent_data;
1496    if (!smart_parent || !smart_obj) return;
1497 
1498    if (smart_obj->cur->valid_bounding_box)
1499      {
1500         /* Update left limit */
1501         if (noclip && x < smart_parent->cur.bounding_box.x)
1502           {
1503              smart_parent->cur.bounding_box.w += smart_parent->cur.bounding_box.x - x;
1504              smart_parent->cur.bounding_box.x = x;
1505 
1506              propagate = EINA_TRUE;
1507           }
1508         else if ((px == smart_parent->prev.bounding_box.x &&
1509                   x > smart_parent->cur.bounding_box.x)
1510                  || (!noclip && x == smart_parent->cur.bounding_box.x))
1511           {
1512              computeminmax = EINA_TRUE;
1513           }
1514 
1515         /* Update top limit */
1516         if (noclip && y < smart_parent->cur.bounding_box.y)
1517           {
1518              smart_parent->cur.bounding_box.h += smart_parent->cur.bounding_box.y - y;
1519              smart_parent->cur.bounding_box.y = y;
1520 
1521              propagate = EINA_TRUE;
1522           }
1523         else if ((py == smart_parent->prev.bounding_box.y &&
1524                   y  > smart_parent->cur.bounding_box.y)
1525                  || (!noclip && y == smart_parent->cur.bounding_box.y))
1526           {
1527              computeminmax = EINA_TRUE;
1528           }
1529 
1530         /* Update right limit */
1531         if (noclip && x + w > smart_parent->cur.bounding_box.x + smart_parent->cur.bounding_box.w)
1532           {
1533              smart_parent->cur.bounding_box.w = x + w - smart_parent->cur.bounding_box.x;
1534              propagate = EINA_TRUE;
1535           }
1536         else if ((px + pw == smart_parent->prev.bounding_box.x + smart_parent->prev.bounding_box.w &&
1537                   x + w < smart_parent->cur.bounding_box.x + smart_parent->cur.bounding_box.w)
1538                  || (!noclip && x + w == smart_parent->cur.bounding_box.x + smart_parent->cur.bounding_box.w))
1539           {
1540              computeminmax = EINA_TRUE;
1541           }
1542 
1543         /* Update bottom limit */
1544         if (noclip && y + h > smart_parent->cur.bounding_box.y + smart_parent->cur.bounding_box.h)
1545           {
1546              smart_parent->cur.bounding_box.h = y + h - smart_parent->cur.bounding_box.y;
1547 
1548              propagate = EINA_TRUE;
1549           }
1550         else if ((py + ph == smart_parent->prev.bounding_box.y + smart_parent->prev.bounding_box.h &&
1551                   y + h < smart_parent->cur.bounding_box.y + smart_parent->cur.bounding_box.h) ||
1552                  (!noclip && y + h == smart_parent->cur.bounding_box.y + smart_parent->cur.bounding_box.h))
1553           {
1554              computeminmax = EINA_TRUE;
1555           }
1556 
1557         if (computeminmax)
1558           {
1559              evas_object_smart_need_bounding_box_update(obj->smart.parent_data,
1560                                                         obj->smart.parent_object_data);
1561           }
1562      }
1563    else
1564      {
1565         if (noclip)
1566           {
1567              smart_parent->cur.bounding_box.x = x;
1568              smart_parent->cur.bounding_box.y = y;
1569              smart_parent->cur.bounding_box.w = w;
1570              smart_parent->cur.bounding_box.h = h;
1571 
1572              EINA_COW_STATE_WRITE_BEGIN(smart_obj, smart_write, cur)
1573                smart_write->valid_bounding_box = EINA_TRUE;
1574              EINA_COW_STATE_WRITE_END(smart_obj, smart_write, cur);
1575 
1576              propagate = EINA_TRUE;
1577           }
1578      }
1579 
1580    if (propagate)
1581      evas_object_update_bounding_box(obj->smart.parent, smart_obj, smart_parent);
1582 }
1583 
1584 void
evas_object_smart_bounding_box_get(Evas_Object_Protected_Data * obj,Eina_Rectangle * cur_bounding_box,Eina_Rectangle * prev_bounding_box)1585 evas_object_smart_bounding_box_get(Evas_Object_Protected_Data *obj,
1586                                    Eina_Rectangle *cur_bounding_box,
1587                                    Eina_Rectangle *prev_bounding_box)
1588 {
1589    Evas_Smart_Data *s = obj->private_data;
1590 
1591    if (cur_bounding_box) memcpy(cur_bounding_box,
1592                                 &s->cur.bounding_box,
1593                                 sizeof (*cur_bounding_box));
1594    if (prev_bounding_box) memcpy(prev_bounding_box,
1595                                  &s->prev.bounding_box,
1596                                  sizeof (*prev_bounding_box));
1597 }
1598 
1599 void
evas_object_smart_cleanup(Evas_Object * eo_obj)1600 evas_object_smart_cleanup(Evas_Object *eo_obj)
1601 {
1602    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
1603 
1604    if (obj->smart.parent)
1605      evas_object_smart_member_del(eo_obj);
1606 
1607    if (obj->is_smart)
1608      {
1609         Evas_Smart_Data *o = efl_data_scope_get(eo_obj, MY_CLASS);
1610         if (o->calc_entry.next)
1611           eina_clist_remove(&o->calc_entry);
1612 
1613         if (o->render_cache)
1614           {
1615              evas_render_object_render_cache_free(eo_obj, o->render_cache);
1616              o->render_cache = NULL;
1617           }
1618 
1619         while (o->contained)
1620           {
1621              Evas_Object_Protected_Data *contained =
1622                (Evas_Object_Protected_Data *)o->contained;
1623              Evas_Object *contained_obj = contained->object;
1624 
1625              if (!contained_obj)
1626                {
1627                   ERR("Found an undefined object %p in %s.", contained, efl_debug_name_get(eo_obj));
1628                   o->contained = eina_inlist_remove
1629                     (o->contained, EINA_INLIST_GET(contained));
1630                }
1631              else if (contained->smart.parent != eo_obj)
1632                {
1633                   Evas_Layer *lay = obj->layer;
1634 
1635                   ERR("This is bad - object %p in child list for %p has parent %p", contained_obj, eo_obj, contained->smart.parent);
1636                   o->contained = eina_inlist_remove
1637                     (o->contained, EINA_INLIST_GET(contained));
1638                   if (lay)
1639                     {
1640                        // this SHOULD be eina_inlist_append() BUT seemingly
1641                        // if we call this this object gets magically added
1642                        // back to o->contained above NOT lay->objects. this
1643                        // is utterly bizarre and the only explanation i
1644                        // can come up with right now is a compiler bug.
1645                        lay->objects = (Evas_Object_Protected_Data *)
1646                          eina_inlist_prepend(EINA_INLIST_GET(lay->objects),
1647                                              EINA_INLIST_GET(contained));
1648                        if (contained->layer != lay)
1649                          {
1650                             if (contained->layer) contained->layer->usage--;
1651                             contained->layer = lay;
1652                             contained->in_layer = 1;
1653                             lay->usage++;
1654                          }
1655                     }
1656                }
1657              else evas_object_smart_member_del(contained_obj);
1658           }
1659 
1660         while (o->callbacks)
1661           {
1662              _eo_evas_smart_cb_info *info = (_eo_evas_smart_cb_info *)o->callbacks;
1663              efl_event_callback_del(eo_obj, info->event, _eo_evas_smart_cb, info);
1664              o->callbacks = eina_inlist_remove(o->callbacks, EINA_INLIST_GET(info));
1665              free(info);
1666           }
1667 
1668         if (o->render_cache)
1669           {
1670              evas_render_object_render_cache_free(eo_obj, o->render_cache);
1671              o->render_cache = NULL;
1672           }
1673 
1674         evas_smart_cb_descriptions_resize(&o->callbacks_descriptions, 0);
1675         if (o->data) evas_object_smart_data_set(eo_obj, NULL);
1676      }
1677 
1678    obj->smart.parent = NULL;
1679    obj->smart.smart = NULL;
1680 }
1681 
1682 void
evas_object_smart_member_cache_invalidate(Evas_Object * eo_obj,Eina_Bool pass_events,Eina_Bool freeze_events,Eina_Bool source_invisible)1683 evas_object_smart_member_cache_invalidate(Evas_Object *eo_obj,
1684                                           Eina_Bool pass_events,
1685                                           Eina_Bool freeze_events,
1686                                           Eina_Bool source_invisible)
1687 {
1688    MAGIC_CHECK(eo_obj, Evas_Object, MAGIC_OBJ);
1689    return;
1690    MAGIC_CHECK_END();
1691 
1692    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
1693    Evas_Object_Protected_Data *member;
1694 
1695    if (pass_events)
1696      obj->parent_cache.pass_events_valid = EINA_FALSE;
1697    if (freeze_events)
1698      obj->parent_cache.freeze_events_valid = EINA_FALSE;
1699    if (source_invisible)
1700      obj->parent_cache.src_invisible_valid = EINA_FALSE;
1701 
1702    if (!obj->is_smart) return;
1703    Evas_Smart_Data *o = efl_data_scope_get(eo_obj, MY_CLASS);
1704    EINA_INLIST_FOREACH(o->contained, member)
1705      {
1706         Evas_Object *eo_member = member->object;
1707         evas_object_smart_member_cache_invalidate(eo_member, pass_events,
1708                                                   freeze_events,
1709                                                   source_invisible);
1710      }
1711 }
1712 
1713 void
evas_object_smart_member_raise(Evas_Object * eo_member)1714 evas_object_smart_member_raise(Evas_Object *eo_member)
1715 {
1716    Evas_Smart_Data *o;
1717    Evas_Object_Protected_Data *member = efl_data_scope_get(eo_member, EFL_CANVAS_OBJECT_CLASS);
1718    o = efl_data_scope_get(member->smart.parent, MY_CLASS);
1719    o->contained = eina_inlist_demote(o->contained, EINA_INLIST_GET(member));
1720 }
1721 
1722 void
evas_object_smart_member_lower(Evas_Object * eo_member)1723 evas_object_smart_member_lower(Evas_Object *eo_member)
1724 {
1725    Evas_Smart_Data *o;
1726    Evas_Object_Protected_Data *member = efl_data_scope_get(eo_member, EFL_CANVAS_OBJECT_CLASS);
1727    o = efl_data_scope_get(member->smart.parent, MY_CLASS);
1728    o->contained = eina_inlist_promote(o->contained, EINA_INLIST_GET(member));
1729 }
1730 
1731 void
evas_object_smart_member_stack_above(Evas_Object * eo_member,Evas_Object * eo_other)1732 evas_object_smart_member_stack_above(Evas_Object *eo_member, Evas_Object *eo_other)
1733 {
1734    Evas_Smart_Data *o;
1735    Evas_Object_Protected_Data *member = efl_data_scope_get(eo_member, EFL_CANVAS_OBJECT_CLASS);
1736    Evas_Object_Protected_Data *other = efl_data_scope_get(eo_other, EFL_CANVAS_OBJECT_CLASS);
1737    o = efl_data_scope_get(member->smart.parent, MY_CLASS);
1738    o->contained = eina_inlist_remove(o->contained, EINA_INLIST_GET(member));
1739    o->contained = eina_inlist_append_relative(o->contained, EINA_INLIST_GET(member), EINA_INLIST_GET(other));
1740 }
1741 
1742 void
evas_object_smart_member_stack_below(Evas_Object * eo_member,Evas_Object * eo_other)1743 evas_object_smart_member_stack_below(Evas_Object *eo_member, Evas_Object *eo_other)
1744 {
1745    Evas_Smart_Data *o;
1746    Evas_Object_Protected_Data *member = efl_data_scope_get(eo_member, EFL_CANVAS_OBJECT_CLASS);
1747    Evas_Object_Protected_Data *other = efl_data_scope_get(eo_other, EFL_CANVAS_OBJECT_CLASS);
1748    o = efl_data_scope_get(member->smart.parent, MY_CLASS);
1749    o->contained = eina_inlist_remove(o->contained, EINA_INLIST_GET(member));
1750    o->contained = eina_inlist_prepend_relative(o->contained, EINA_INLIST_GET(member), EINA_INLIST_GET(other));
1751 }
1752 
1753 void
evas_object_smart_need_bounding_box_update(Evas_Smart_Data * o,Evas_Object_Protected_Data * obj)1754 evas_object_smart_need_bounding_box_update(Evas_Smart_Data *o, Evas_Object_Protected_Data *obj)
1755 {
1756    if (o->update_boundingbox_needed) return;
1757    o->update_boundingbox_needed = EINA_TRUE;
1758    if (!obj->cur->cache.clip.dirty)
1759      {
1760         EINA_COW_STATE_WRITE_BEGIN(obj, state_write, cur)
1761           state_write->cache.clip.dirty = EINA_TRUE;
1762         EINA_COW_STATE_WRITE_END(obj, state_write, cur);
1763      }
1764 
1765    if (obj->smart.parent)
1766      evas_object_smart_need_bounding_box_update(obj->smart.parent_data,
1767                                                 obj->smart.parent_object_data);
1768 }
1769 
1770 void
evas_object_smart_bounding_box_update(Evas_Object_Protected_Data * obj)1771 evas_object_smart_bounding_box_update(Evas_Object_Protected_Data *obj)
1772 {
1773    Evas_Smart_Data *os;
1774    Eina_Inlist *list;
1775    Evas_Object_Protected_Data *o;
1776    Evas_Coord minx = 0x7fffffff;
1777    Evas_Coord miny = 0x7fffffff;
1778    Evas_Coord maxx = 0x80000000;
1779    Evas_Coord maxy = 0x80000000;
1780    Evas_Coord tx1, ty1, tx2, ty2;
1781    Eina_Bool none = EINA_TRUE;
1782 
1783    os = obj->private_data;
1784 
1785    if (!os->update_boundingbox_needed) return;
1786    os->update_boundingbox_needed = EINA_FALSE;
1787 
1788    list = os->contained;
1789    EINA_INLIST_FOREACH(list, o)
1790      {
1791         if (o == obj) continue ;
1792         if (o->clip.clipees || o->is_static_clip) continue ;
1793         if (!o->cur->visible) continue;
1794 
1795         none = EINA_FALSE;
1796 
1797         if (o->is_smart)
1798           {
1799              Evas_Smart_Data *s = o->private_data;
1800 
1801              evas_object_smart_bounding_box_update(o);
1802 
1803              tx1 = s->cur.bounding_box.x;
1804              ty1 = s->cur.bounding_box.y;
1805              tx2 = tx1 + s->cur.bounding_box.w;
1806              ty2 = ty1 + s->cur.bounding_box.h;
1807           }
1808         else
1809           {
1810              tx1 = o->cur->geometry.x;
1811              ty1 = o->cur->geometry.y;
1812              tx2 = tx1 + o->cur->geometry.w;
1813              ty2 = ty1 + o->cur->geometry.h;
1814           }
1815 
1816         if (tx1 < minx) minx = tx1;
1817         if (ty1 < miny) miny = ty1;
1818         if (tx2 > maxx) maxx = tx2;
1819         if (ty2 > maxy) maxy = ty2;
1820      }
1821    if (none)
1822      {
1823         minx = obj->cur->geometry.x;
1824         miny = obj->cur->geometry.y;
1825         maxx = obj->cur->geometry.x + obj->cur->geometry.w;
1826         maxy = obj->cur->geometry.y + obj->cur->geometry.h;
1827      }
1828 
1829    os->cur.bounding_box.x = minx;
1830    os->cur.bounding_box.y = miny;
1831    os->cur.bounding_box.w = maxx - minx;
1832    os->cur.bounding_box.h = maxy - miny;
1833 
1834    EINA_COW_STATE_WRITE_BEGIN(obj, state_write, cur)
1835      {
1836         state_write->cache.clip.dirty = EINA_TRUE;
1837      }
1838    EINA_COW_STATE_WRITE_END(obj, state_write, cur);
1839    evas_object_clip_recalc(obj);
1840    if (obj->cur->clipper) evas_object_clip_recalc(obj->cur->clipper);
1841 }
1842 
1843 /* all nice and private */
1844 static void
evas_object_smart_render(Evas_Object * eo_obj EINA_UNUSED,Evas_Object_Protected_Data * obj EINA_UNUSED,void * type_private_data EINA_UNUSED,void * engine EINA_UNUSED,void * output EINA_UNUSED,void * context EINA_UNUSED,void * surface EINA_UNUSED,int x EINA_UNUSED,int y EINA_UNUSED,Eina_Bool do_async EINA_UNUSED)1845 evas_object_smart_render(Evas_Object *eo_obj EINA_UNUSED, Evas_Object_Protected_Data *obj EINA_UNUSED,  void *type_private_data EINA_UNUSED, void *engine EINA_UNUSED, void *output EINA_UNUSED, void *context EINA_UNUSED, void *surface EINA_UNUSED, int x EINA_UNUSED, int y EINA_UNUSED, Eina_Bool do_async EINA_UNUSED)
1846 {
1847    return;
1848 }
1849 
1850 static void
evas_object_smart_render_pre(Evas_Object * eo_obj,Evas_Object_Protected_Data * obj,void * type_private_data EINA_UNUSED)1851 evas_object_smart_render_pre(Evas_Object *eo_obj,
1852 			     Evas_Object_Protected_Data *obj,
1853 			     void *type_private_data EINA_UNUSED)
1854 {
1855    if (obj->pre_render_done) return;
1856 
1857    if (obj->changed_map || obj->changed_src_visible)
1858      evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes,
1859                                          eo_obj, obj);
1860 
1861    obj->pre_render_done = EINA_TRUE;
1862 }
1863 
1864 static void
evas_object_smart_render_post(Evas_Object * eo_obj EINA_UNUSED,Evas_Object_Protected_Data * obj,void * type_private_data)1865 evas_object_smart_render_post(Evas_Object *eo_obj EINA_UNUSED, Evas_Object_Protected_Data *obj, void *type_private_data)
1866 {
1867    Evas_Smart_Data *o = type_private_data;
1868    evas_object_cur_prev(obj);
1869    o->prev = o->cur;
1870 }
1871 
evas_object_smart_engine_data_get(Evas_Object * eo_obj)1872 static void *evas_object_smart_engine_data_get(Evas_Object *eo_obj)
1873 {
1874    Evas_Smart_Data *o = efl_data_scope_get(eo_obj, MY_CLASS);
1875    if (!o) return NULL;
1876    return o->engine_data;
1877 }
1878 
1879 static void
_efl_canvas_group_class_constructor(Efl_Class * klass EINA_UNUSED)1880 _efl_canvas_group_class_constructor(Efl_Class *klass EINA_UNUSED)
1881 {
1882    _evas_smart_class_names_hash_table = eina_hash_string_small_new(NULL);
1883    evas_smart_legacy_type_register(MY_CLASS_NAME_LEGACY, klass);
1884 }
1885 
1886 static void
_efl_canvas_group_class_destructor(Efl_Class * klass EINA_UNUSED)1887 _efl_canvas_group_class_destructor(Efl_Class *klass EINA_UNUSED)
1888 {
1889    eina_hash_free(_evas_smart_class_names_hash_table);
1890 }
1891 
1892 static void
_efl_canvas_group_group_paragraph_direction_set_internal(Eo * eo_obj,Evas_BiDi_Direction dir)1893 _efl_canvas_group_group_paragraph_direction_set_internal(Eo *eo_obj,
1894                                                     Evas_BiDi_Direction dir)
1895 {
1896    Evas_Object_Protected_Data *o;
1897    Evas_Smart_Data *member_o;
1898 
1899    EINA_INLIST_FOREACH(evas_object_smart_members_get_direct(eo_obj), o)
1900      {
1901         evas_object_change(o->object, o);
1902 
1903         if (o->is_smart)
1904           {
1905              member_o = efl_data_scope_get(o->object, MY_CLASS);
1906 
1907              if ((member_o->inherit_paragraph_direction) &&
1908                  (member_o->paragraph_direction != dir))
1909                {
1910                   member_o->paragraph_direction = dir;
1911                   _efl_canvas_group_group_paragraph_direction_set_internal(o->object, dir);
1912                }
1913           }
1914      }
1915 }
1916 
1917 EOLIAN static void
_efl_canvas_group_efl_canvas_object_paragraph_direction_set(Eo * eo_obj,Evas_Smart_Data * o,Efl_Text_Bidirectional_Type dir)1918 _efl_canvas_group_efl_canvas_object_paragraph_direction_set(Eo *eo_obj, Evas_Smart_Data *o,
1919                                                             Efl_Text_Bidirectional_Type dir)
1920 {
1921    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
1922    Evas_Smart_Data *parent;
1923 
1924    if ((!(o->inherit_paragraph_direction) && (o->paragraph_direction == (Evas_BiDi_Direction)dir)) ||
1925        (o->inherit_paragraph_direction && ((Evas_BiDi_Direction)dir == EVAS_BIDI_DIRECTION_INHERIT)))
1926      return;
1927 
1928    if (dir == (Efl_Text_Bidirectional_Type)EVAS_BIDI_DIRECTION_INHERIT)
1929      {
1930         o->inherit_paragraph_direction = EINA_TRUE;
1931         Evas_BiDi_Direction parent_dir = EVAS_BIDI_DIRECTION_NEUTRAL;
1932 
1933         if (obj->smart.parent)
1934           {
1935              parent = efl_data_scope_get(obj->smart.parent, MY_CLASS);
1936 
1937              if (parent)
1938                parent_dir = parent->paragraph_direction;
1939           }
1940 
1941         if (parent_dir != o->paragraph_direction)
1942           {
1943              o->paragraph_direction = parent_dir;
1944              evas_object_change(eo_obj, obj);
1945           }
1946      }
1947    else
1948      {
1949         o->inherit_paragraph_direction = EINA_FALSE;
1950         o->paragraph_direction = dir;
1951         evas_object_change(eo_obj, obj);
1952      }
1953 
1954    _efl_canvas_group_group_paragraph_direction_set_internal(eo_obj, o->paragraph_direction);
1955 }
1956 
1957 EOLIAN static Efl_Text_Bidirectional_Type
_efl_canvas_group_efl_canvas_object_paragraph_direction_get(const Eo * eo_obj EINA_UNUSED,Evas_Smart_Data * o)1958 _efl_canvas_group_efl_canvas_object_paragraph_direction_get(const Eo *eo_obj EINA_UNUSED, Evas_Smart_Data *o)
1959 {
1960    return (Efl_Text_Bidirectional_Type)o->paragraph_direction;
1961 }
1962 
1963 EOLIAN static const Eo *
_efl_canvas_group_group_clipper_get(const Eo * eo_obj EINA_UNUSED,Evas_Smart_Data * o)1964 _efl_canvas_group_group_clipper_get(const Eo *eo_obj EINA_UNUSED, Evas_Smart_Data *o)
1965 {
1966    // NOTE: This may be NULL until all EO smart objects are clipped!
1967    return _smart_clipper_get(o);
1968 }
1969 
1970 /* Internal EO */
1971 static void
_efl_canvas_group_group_clipped_set(Eo * eo_obj EINA_UNUSED,Evas_Smart_Data * sd,Eina_Bool clipped)1972 _efl_canvas_group_group_clipped_set(Eo *eo_obj EINA_UNUSED, Evas_Smart_Data *sd, Eina_Bool clipped)
1973 {
1974    // We must call this function BEFORE the constructor (yes, it's hacky)
1975    EINA_SAFETY_ON_FALSE_RETURN(!sd->object);
1976    sd->clipped = !!clipped;
1977 }
1978 
1979 /* Internal EO APIs */
1980 EOLIAN static Eina_Bool
_efl_canvas_group_efl_object_event_callback_priority_add(Eo * obj,Evas_Smart_Data * sd,const Efl_Event_Description * desc,Efl_Callback_Priority priority,Efl_Event_Cb func,const void * user_data)1981 _efl_canvas_group_efl_object_event_callback_priority_add(Eo *obj, Evas_Smart_Data *sd, const Efl_Event_Description *desc, Efl_Callback_Priority priority, Efl_Event_Cb func, const void *user_data)
1982 {
1983   if (desc == EFL_CANVAS_GROUP_EVENT_MEMBER_ADDED)
1984     {
1985        sd->cb_member_added = EINA_TRUE;
1986     }
1987   else if (desc == EFL_CANVAS_GROUP_EVENT_MEMBER_REMOVED)
1988     {
1989        sd->cb_member_added = EINA_TRUE;
1990     }
1991 
1992   return efl_event_callback_priority_add(efl_super(obj, MY_CLASS), desc, priority, func, user_data);
1993 }
1994 
1995 EOLIAN static Eina_Bool
_efl_canvas_group_efl_object_event_callback_array_priority_add(Eo * obj,Evas_Smart_Data * sd,const Efl_Callback_Array_Item * array,Efl_Callback_Priority priority,const void * user_data)1996 _efl_canvas_group_efl_object_event_callback_array_priority_add(Eo *obj, Evas_Smart_Data *sd, const Efl_Callback_Array_Item *array, Efl_Callback_Priority priority, const void *user_data)
1997 {
1998    for (int i = 0; array[i].desc; ++i)
1999      {
2000         if (array[i].desc == EFL_CANVAS_GROUP_EVENT_MEMBER_ADDED)
2001           {
2002              sd->cb_member_added = EINA_TRUE;
2003           }
2004         else if (array[i].desc == EFL_CANVAS_GROUP_EVENT_MEMBER_REMOVED)
2005           {
2006              sd->cb_member_removed = EINA_TRUE;
2007           }
2008      }
2009    return efl_event_callback_array_priority_add(efl_super(obj, MY_CLASS), array, priority, user_data);
2010 }
2011 EOAPI EFL_VOID_FUNC_BODY(efl_canvas_group_add)
2012 EOAPI EFL_VOID_FUNC_BODY(efl_canvas_group_del)
2013 EOAPI EFL_VOID_FUNC_BODYV(efl_canvas_group_clipped_set, EFL_FUNC_CALL(enable), Eina_Bool enable)
2014 
2015 #define EFL_CANVAS_GROUP_EXTRA_OPS \
2016    EFL_OBJECT_OP_FUNC(efl_canvas_group_add, _efl_canvas_group_group_add), \
2017    EFL_OBJECT_OP_FUNC(efl_canvas_group_del, _efl_canvas_group_group_del), \
2018    EFL_OBJECT_OP_FUNC(efl_event_callback_priority_add, _efl_canvas_group_efl_object_event_callback_priority_add), \
2019    EFL_OBJECT_OP_FUNC(efl_event_callback_array_priority_add, _efl_canvas_group_efl_object_event_callback_array_priority_add), \
2020    EFL_OBJECT_OP_FUNC(efl_canvas_group_clipped_set, _efl_canvas_group_group_clipped_set)
2021 
2022 #include "canvas/efl_canvas_group.eo.c"
2023 #include "canvas/efl_canvas_group_eo.legacy.c"
2024