1 #include "evas_common_private.h"
2 #include "evas_private.h"
3 
4 
5 static void _evas_smart_class_callbacks_create(Evas_Smart *s);
6 static void _evas_smart_class_interfaces_create(Evas_Smart *s);
7 
8 /* all public */
9 
10 EAPI void
evas_smart_free(Evas_Smart * s)11 evas_smart_free(Evas_Smart *s)
12 {
13    MAGIC_CHECK(s, Evas_Smart, MAGIC_SMART);
14    return;
15    MAGIC_CHECK_END();
16    s->delete_me = 1;
17    if (s->usage > 0) return;
18    if (s->class_allocated) free((void *)s->smart_class);
19    free(s->callbacks.array);
20    free(s->interfaces.array);
21 
22    free(s);
23 }
24 
25 EAPI Evas_Smart *
evas_smart_class_new(const Evas_Smart_Class * sc)26 evas_smart_class_new(const Evas_Smart_Class *sc)
27 {
28    Evas_Smart *s;
29 
30    if (!sc) return NULL;
31 
32    /* api does not match abi! for now refuse as we only have 1 version */
33    if (sc->version != EVAS_SMART_CLASS_VERSION) return NULL;
34 
35    s = calloc(1, sizeof(Evas_Smart));
36    if (!s) return NULL;
37 
38    s->magic = MAGIC_SMART;
39 
40    s->smart_class = sc;
41    _evas_smart_class_callbacks_create(s);
42    _evas_smart_class_interfaces_create(s);
43 
44    return s;
45 }
46 
47 EAPI const Evas_Smart_Class *
evas_smart_class_get(const Evas_Smart * s)48 evas_smart_class_get(const Evas_Smart *s)
49 {
50    MAGIC_CHECK(s, Evas_Smart, MAGIC_SMART);
51    return NULL;
52    MAGIC_CHECK_END();
53    return s->smart_class;
54 }
55 
56 EAPI void *
evas_smart_data_get(const Evas_Smart * s)57 evas_smart_data_get(const Evas_Smart *s)
58 {
59    MAGIC_CHECK(s, Evas_Smart, MAGIC_SMART);
60    return NULL;
61    MAGIC_CHECK_END();
62    return (void *)s->smart_class->data;
63 }
64 
65 EAPI const Evas_Smart_Cb_Description **
evas_smart_callbacks_descriptions_get(const Evas_Smart * s,unsigned int * count)66 evas_smart_callbacks_descriptions_get(const Evas_Smart *s, unsigned int *count)
67 {
68    MAGIC_CHECK(s, Evas_Smart, MAGIC_SMART);
69    if (count) *count = 0;
70    return NULL;
71    MAGIC_CHECK_END();
72 
73    if (count) *count = s->callbacks.size;
74    return s->callbacks.array;
75 }
76 
77 EAPI const Evas_Smart_Cb_Description *
evas_smart_callback_description_find(const Evas_Smart * s,const char * name)78 evas_smart_callback_description_find(const Evas_Smart *s, const char *name)
79 {
80    if (!name) return NULL;
81    MAGIC_CHECK(s, Evas_Smart, MAGIC_SMART);
82    return NULL;
83    MAGIC_CHECK_END();
84    return evas_smart_cb_description_find(&s->callbacks, name);
85 }
86 
87 EAPI Eina_Bool
evas_smart_class_inherit_full(Evas_Smart_Class * sc,const Evas_Smart_Class * parent_sc,unsigned int parent_sc_size)88 evas_smart_class_inherit_full(Evas_Smart_Class *sc, const Evas_Smart_Class *parent_sc, unsigned int parent_sc_size)
89 {
90    unsigned int off;
91 
92    /* api does not match abi! for now refuse as we only have 1 version */
93    if (parent_sc->version != EVAS_SMART_CLASS_VERSION) return EINA_FALSE;
94 
95 #define _CP(m) sc->m = parent_sc->m
96    _CP(add);
97    _CP(del);
98    _CP(move);
99    _CP(resize);
100    _CP(show);
101    _CP(hide);
102    _CP(color_set);
103    _CP(clip_set);
104    _CP(clip_unset);
105    _CP(calculate);
106    _CP(member_add);
107    _CP(member_del);
108 #undef _CP
109 
110    sc->parent = parent_sc;
111 
112    off = sizeof(Evas_Smart_Class);
113    if (parent_sc_size == off) return EINA_TRUE;
114 
115    memcpy(((char *)sc) + off, ((char *)parent_sc) + off, parent_sc_size - off);
116    return EINA_TRUE;
117 }
118 
119 EAPI int
evas_smart_usage_get(const Evas_Smart * s)120 evas_smart_usage_get(const Evas_Smart *s)
121 {
122    MAGIC_CHECK(s, Evas_Smart, MAGIC_SMART);
123    return 0;
124    MAGIC_CHECK_END();
125    return s->usage;
126 }
127 
128 
129 /* internal funcs */
130 void
evas_object_smart_use(Evas_Smart * s)131 evas_object_smart_use(Evas_Smart *s)
132 {
133    s->usage++;
134 }
135 
136 void
evas_object_smart_unuse(Evas_Smart * s)137 evas_object_smart_unuse(Evas_Smart *s)
138 {
139    s->usage--;
140    if ((s->usage <= 0) && (s->delete_me)) evas_smart_free(s);
141 }
142 
143 Eina_Bool
evas_smart_cb_descriptions_resize(Evas_Smart_Cb_Description_Array * a,unsigned int size)144 evas_smart_cb_descriptions_resize(Evas_Smart_Cb_Description_Array *a, unsigned int size)
145 {
146    void *tmp;
147 
148    if (size == a->size)
149      return EINA_TRUE;
150 
151    if (size == EINA_FALSE)
152      {
153         free(a->array);
154         a->array = NULL;
155         a->size = 0;
156         return EINA_TRUE;
157      }
158 
159    tmp = realloc(a->array, (size + 1) * sizeof(Evas_Smart_Cb_Description *));
160    if (tmp)
161      {
162         a->array = tmp;
163         a->size = size;
164         a->array[size] = NULL;
165         return EINA_TRUE;
166      }
167    else
168      {
169         ERR("realloc failed!");
170         return EINA_FALSE;
171      }
172 }
173 
174 static int
_evas_smart_cb_description_cmp_sort(const void * p1,const void * p2)175 _evas_smart_cb_description_cmp_sort(const void *p1, const void *p2)
176 {
177    const Evas_Smart_Cb_Description **a = (const Evas_Smart_Cb_Description **)p1;
178    const Evas_Smart_Cb_Description **b = (const Evas_Smart_Cb_Description **)p2;
179    return strcmp((*a)->name, (*b)->name);
180 }
181 
182 void
evas_smart_cb_descriptions_fix(Evas_Smart_Cb_Description_Array * a)183 evas_smart_cb_descriptions_fix(Evas_Smart_Cb_Description_Array *a)
184 {
185    unsigned int i, j;
186 
187    if (!a)
188      {
189         ERR("no array to fix!");
190         return;
191      }
192 
193    qsort(a->array, a->size, sizeof(Evas_Smart_Cb_Description *),
194          _evas_smart_cb_description_cmp_sort);
195 
196    DBG("%u callbacks", a->size);
197    if (a->size)
198      DBG("%s [type=%s]", a->array[0]->name, a->array[0]->type);
199 
200    for (i = 0, j = 1; j < a->size; j++)
201      {
202         const Evas_Smart_Cb_Description *cur, *prev;
203 
204         cur = a->array[j];
205         prev = a->array[i];
206 
207         DBG("%s [type=%s]", cur->name, cur->type);
208 
209         if (strcmp(cur->name, prev->name) != 0)
210           {
211              i++;
212              if (i != j)
213                a->array[i] = a->array[j];
214           }
215         else
216           {
217              if (strcmp(cur->type, prev->type) == 0)
218                WRN("duplicated smart callback description"
219                    " with name '%s' and type '%s'", cur->name, cur->type);
220              else
221                ERR("callback descriptions named '%s' differ"
222                    " in type, keeping '%s', ignoring '%s'",
223                    cur->name, prev->type, cur->type);
224           }
225      }
226 
227    evas_smart_cb_descriptions_resize(a, i + 1);
228 }
229 
230 static void
_evas_smart_class_callbacks_create(Evas_Smart * s)231 _evas_smart_class_callbacks_create(Evas_Smart *s)
232 {
233    const Evas_Smart_Class *sc;
234    unsigned int n = 0;
235 
236    for (sc = s->smart_class; sc; sc = sc->parent)
237      {
238         const Evas_Smart_Cb_Description *d;
239         for (d = sc->callbacks; d && d->name; d++)
240           n++;
241      }
242 
243    if (n == 0) return;
244    if (!evas_smart_cb_descriptions_resize(&s->callbacks, n)) return;
245    s->callbacks.size = n;
246    for (n = 0, sc = s->smart_class; sc; sc = sc->parent)
247      {
248         const Evas_Smart_Cb_Description *d;
249         for (d = sc->callbacks; d && d->name; d++)
250           s->callbacks.array[n++] = d;
251      }
252    evas_smart_cb_descriptions_fix(&s->callbacks);
253 }
254 
255 static void
_evas_smart_class_interfaces_create(Evas_Smart * s)256 _evas_smart_class_interfaces_create(Evas_Smart *s)
257 {
258    unsigned int i;
259    const Evas_Smart_Class *sc;
260 
261    /* get number of interfaces on the smart */
262    for (i = 0, sc = s->smart_class; sc; sc = sc->parent)
263      {
264         const Evas_Smart_Interface **ifaces_array = sc->interfaces;
265         if (!ifaces_array) continue;
266 
267         while (*ifaces_array)
268           {
269              const Evas_Smart_Interface *iface = *ifaces_array;
270 
271              if (!iface->name) break;
272 
273              i++;
274 
275              if (iface->private_size > 0)
276                {
277                   unsigned int size = iface->private_size;
278 
279                   if (size % sizeof(void *) != 0)
280                     size += sizeof(void *) - (size % sizeof(void *));
281                }
282 
283              ifaces_array++;
284           }
285      }
286 
287    if (!i) return;
288 
289    s->interfaces.array = malloc(i * sizeof(Evas_Smart_Interface *));
290    if (!s->interfaces.array)
291      {
292         ERR("malloc failed!");
293         return;
294      }
295 
296    s->interfaces.size = i;
297 
298    for (i = 0, sc = s->smart_class; sc; sc = sc->parent)
299      {
300         const Evas_Smart_Interface **ifaces_array = sc->interfaces;
301         if (!ifaces_array) continue;
302 
303         while (*ifaces_array)
304           {
305              const Evas_Smart_Interface *iface = *ifaces_array;
306 
307              if (!iface->name) break;
308 
309              s->interfaces.array[i++] = iface;
310              ifaces_array++;
311           }
312      }
313 }
314 
315 static int
_evas_smart_cb_description_cmp_search(const void * p1,const void * p2)316 _evas_smart_cb_description_cmp_search(const void *p1, const void *p2)
317 {
318    const char *name = p1;
319    const Evas_Smart_Cb_Description **v = (const Evas_Smart_Cb_Description **)p2;
320    /* speed up string shares searches (same pointers) */
321    if (name == (*v)->name) return 0;
322    return strcmp(name, (*v)->name);
323 }
324 
325 const Evas_Smart_Cb_Description *
evas_smart_cb_description_find(const Evas_Smart_Cb_Description_Array * a,const char * name)326 evas_smart_cb_description_find(const Evas_Smart_Cb_Description_Array *a, const char *name)
327 {
328    const Evas_Smart_Cb_Description **found = NULL;
329 
330    if (!a->array) return NULL;
331    found = bsearch(name, a->array, a->size, sizeof(Evas_Smart_Cb_Description *),
332                    _evas_smart_cb_description_cmp_search);
333 
334    return found ? (*found) : NULL;
335 }
336