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