The problem that e17 couldn't move/resize window when the window fetch the rotation...
[platform/core/uifw/e17.git] / src / bin / e_object.c
1 #include "e.h"
2
3 /* yes - i know. glibc specific... but i like being able to do my own */
4 /* backtraces! NB: you need CFLAGS="-rdynamic -g" LDFLAGS="-rdynamic -g" */
5 #ifdef OBJECT_PARANOIA_CHECK
6
7 /* local subsystem functions */
8 static void _e_object_segv(int sig);
9
10 /* local subsystem globals */
11 static sigjmp_buf _e_object_segv_buf;
12 #endif
13
14 /* externally accessible functions */
15 EAPI void *
16 e_object_alloc(int size, int type, E_Object_Cleanup_Func cleanup_func)
17 {
18    E_Object *obj;
19
20    obj = calloc(1, size);
21    if (!obj) return NULL;
22    obj->magic = E_OBJECT_MAGIC;
23    obj->type = type;
24    obj->references   = 1;
25    obj->cleanup_func = cleanup_func;
26    return obj;
27 }
28
29 EAPI void
30 e_object_del(E_Object *obj)
31 {
32    E_OBJECT_CHECK(obj);
33    if (obj->deleted) return;
34    obj->deleted = 1;
35    if (obj->del_att_func) obj->del_att_func(obj);
36    if (obj->del_func) obj->del_func(obj);
37    e_object_unref(obj);
38 }
39
40 EAPI int
41 e_object_is_del(E_Object *obj)
42 {
43    E_OBJECT_CHECK_RETURN(obj, 1);
44    return obj->deleted;
45 }
46
47 EAPI void
48 e_object_del_func_set(E_Object *obj, E_Object_Cleanup_Func del_func)
49 {
50    E_OBJECT_CHECK(obj);
51    obj->del_func = del_func;
52 }
53
54 EAPI void
55 e_object_type_set(E_Object *obj, int type)
56 {
57    E_OBJECT_CHECK(obj);
58    obj->type = type;
59 }
60
61 EAPI void
62 e_object_free(E_Object *obj)
63 {
64    E_OBJECT_CHECK(obj);
65    if (obj->free_att_func) obj->free_att_func(obj);
66    obj->free_att_func = NULL;
67    obj->walking_list++;
68    while (obj->del_fn_list)
69      {
70         E_Object_Delfn *dfn = (E_Object_Delfn *)obj->del_fn_list;
71         if (!dfn->delete_me) dfn->func(dfn->data, obj);
72         obj->del_fn_list = eina_inlist_remove(obj->del_fn_list,
73                                               EINA_INLIST_GET(dfn));
74         free(dfn);
75      }
76    obj->walking_list--;
77    if (obj->references) return;
78    /*
79     * FIXME:
80     * although this is good - if during cleanup the cleanup func calls
81     * other generic funcs to do cleanups on the same object... we get bitching.
82     * disable for now (the final free of the struct should probably happen after
83     * the cleanup func and be done by the object system - set the magic after
84     * cleanup :)
85     */
86 #if 0
87    obj->magic = E_OBJECT_MAGIC_FREED;
88 #endif
89    obj->cleanup_func(obj);
90 }
91
92 EAPI int
93 e_object_ref(E_Object *obj)
94 {
95    E_OBJECT_CHECK_RETURN(obj, -1);
96    obj->references++;
97    return obj->references;
98 }
99
100 EAPI int
101 e_object_unref(E_Object *obj)
102 {
103    int ref;
104
105    E_OBJECT_CHECK_RETURN(obj, -1);
106    if (!obj->references) return 0;
107    obj->references--;
108    ref = obj->references;
109    if (obj->references == 0) e_object_free(obj);
110    return ref;
111 }
112
113 EAPI int
114 e_object_ref_get(E_Object *obj)
115 {
116    E_OBJECT_CHECK_RETURN(obj, 0);
117    return obj->references;
118 }
119
120 #if 0
121 EAPI void
122 e_bt(void)
123 {
124    int i, trace_num;
125    void *trace[128];
126    char **messages = NULL;
127    trace_num = backtrace(trace, 128);
128    messages = backtrace_symbols(trace, trace_num);
129    if (messages)
130      {
131         for (i = 1; i < trace_num; i++)
132           {
133              int j;
134
135              for (j = 1; j < i; j++) putchar(' ');
136              printf("%s\n", messages[i]);
137           }
138         free(messages);
139      }
140 }
141 #endif
142
143 EAPI int
144 e_object_error(E_Object *obj)
145 {
146 #ifdef OBJECT_PARANOIA_CHECK
147    char buf[4096];
148    char bt[8192];
149    void *trace[128];
150    char **messages = NULL;
151    int i, trace_num;
152
153    /* fetch stacktrace */
154    trace_num = backtrace(trace, 128);
155    messages = backtrace_symbols(trace, trace_num);
156
157    /* build stacktrace */
158    bt[0] = 0;
159    if (messages)
160      {
161         for (i = 1; i < trace_num; i++)
162           {
163              strcat(bt, messages[i]);
164              strcat(bt, "\n");
165           }
166         free(messages);
167      }
168    /* if NULL obj then dump stacktrace */
169    if (!obj)
170      {
171         snprintf(buf, sizeof(buf),
172                  "Object is NULL.\n"
173                  "%s",
174                  bt);
175      }
176    /* if obj pointer is non NULL, actually try an access and see if we segv */
177    else if (obj)
178      {
179         struct sigaction act, oact;
180         int magic = 0, segv = 0;
181
182         /* setup segv handler */
183         act.sa_handler = _e_object_segv;
184         act.sa_flags   = SA_RESETHAND;
185         sigemptyset(&act.sa_mask);
186         sigaction(SIGSEGV, &act, &oact);
187         /* set a longjump to be within this if statement. only called if we */
188         /* segfault */
189         if (sigsetjmp(_e_object_segv_buf, 1))
190           {
191              sigaction(SIGSEGV, &oact, NULL);
192              segv = 1;
193           }
194         else
195           {
196              /* try access magic value */
197              magic = obj->magic;
198              /* if pointer is bogus we'd segv and so jump to the if () above */
199              /* contents, and thus reset segv handler and set segv flag. */
200              /* if not we just continue moving along here and reset handler */
201              sigaction(SIGSEGV, &oact, NULL);
202           }
203         /* if we segfaulted above... */
204         if (segv)
205           snprintf(buf, sizeof(buf),
206                    "Object [%p] is an invalid/garbage pointer.\n"
207                    "Segfault successfully avoided.\n"
208                    "%s",
209                    obj,
210                    bt);
211         else
212           {
213              /* valid ram then... if we freed this object before */
214              if (magic == E_OBJECT_MAGIC_FREED)
215                snprintf(buf, sizeof(buf),
216                         "Object [%p] is already freed.\n"
217                         "%s",
218                         obj,
219                         bt);
220              /* garbage magic value - pointer to non object */
221              else if (magic != E_OBJECT_MAGIC)
222                snprintf(buf, sizeof(buf),
223                         "Object [%p] has garbage magic (%x).\n"
224                         "%s",
225                         obj, magic,
226                         bt);
227              else if (obj->references < 0)
228                snprintf(buf, sizeof(buf),
229                         "Object [%p] has negative references (%i).\n"
230                         "%s",
231                         obj, obj->references,
232                         bt);
233              else if (obj->references > 100)
234                snprintf(buf, sizeof(buf),
235                         "Object [%p] has unusually high reference count (%i).\n"
236                         "%s",
237                         obj, obj->references,
238                         bt);
239              /* it's all ok! */
240              else
241                {
242                   return 0;
243                }
244           }
245      }
246    /* display actual error message */
247    e_error_message_show("%s", buf);
248    return 1;
249 #else
250    if (!obj)
251      {
252         fprintf(stderr, "ERROR: Object is NULL. Add break point at %s:%d\n",
253                 __FILE__, __LINE__);
254         return 1;
255      }
256    return 0;
257 #endif
258 }
259
260 EAPI void
261 e_object_data_set(E_Object *obj, const void *data)
262 {
263    E_OBJECT_CHECK(obj);
264    obj->data = (void*)data;
265 }
266
267 EAPI void *
268 e_object_data_get(E_Object *obj)
269 {
270    E_OBJECT_CHECK_RETURN(obj, NULL);
271    return obj->data;
272 }
273
274 EAPI void
275 e_object_free_attach_func_set(E_Object *obj, E_Object_Cleanup_Func func)
276 {
277    E_OBJECT_CHECK(obj);
278    obj->free_att_func = func;
279 }
280
281 EAPI void
282 e_object_del_attach_func_set(E_Object *obj, E_Object_Cleanup_Func func)
283 {
284    E_OBJECT_CHECK(obj);
285    obj->del_att_func = func;
286 }
287
288 EAPI void
289 e_object_delfn_clear(E_Object *obj)
290 {
291    E_OBJECT_CHECK(obj);
292    while (obj->del_fn_list)
293      {
294         E_Object_Delfn *dfn = (E_Object_Delfn *)obj->del_fn_list;
295         if (obj->walking_list)
296           dfn->delete_me = 1;
297         else
298           {
299              obj->del_fn_list = eina_inlist_remove(obj->del_fn_list,
300                                                    EINA_INLIST_GET(dfn));
301              free(dfn);
302           }
303      }
304 }
305
306 EAPI E_Object_Delfn *
307 e_object_delfn_add(E_Object *obj, void (*func) (void *data, void *obj), void *data)
308 {
309    E_Object_Delfn *dfn;
310    E_OBJECT_CHECK_RETURN(obj, NULL);
311    dfn = calloc(1, sizeof(E_Object_Delfn));
312    if (!dfn) return NULL;
313    dfn->func = func;
314    dfn->data = data;
315    obj->del_fn_list = eina_inlist_append(obj->del_fn_list, EINA_INLIST_GET(dfn));
316    return dfn;
317 }
318
319 EAPI void
320 e_object_delfn_del(E_Object *obj, E_Object_Delfn *dfn)
321 {
322    E_OBJECT_CHECK(obj);
323    if (obj->walking_list)
324      {
325         dfn->delete_me = 1;
326         return;
327      }
328    obj->del_fn_list = eina_inlist_remove(obj->del_fn_list, EINA_INLIST_GET(dfn));
329    free(dfn);
330 }
331
332 /*
333 void
334 e_object_breadcrumb_add(E_Object *obj, char *crumb)
335 {
336    E_OBJECT_CHECK(obj);
337    obj->crumbs = eina_list_append(obj->crumbs, strdup(crumb));
338 }
339
340 void
341 e_object_breadcrumb_del(E_Object *obj, char *crumb)
342 {
343    Eina_List *l;
344    char *key;
345
346    E_OBJECT_CHECK(obj);
347    EINA_LIST_FOREACH(obj->crumbs, l, key)
348      {
349         if (!strcmp(crumb, key))
350           {
351              free(key);
352              obj->crumbs = eina_list_remove_list(obj->crumbs, l);
353              return;
354           }
355      }
356 }
357
358 void
359 e_object_breadcrumb_debug(E_Object *obj)
360 {
361    Eina_List *l;
362    char *key;
363
364    E_OBJECT_CHECK(obj);
365    EINA_LISt_FOREACH(obj->crumbs, l, key)
366      printf("CRUMB: %s\n", key);
367 }
368 */
369
370 #ifdef OBJECT_PARANOIA_CHECK
371 /* local subsystem functions */
372 static void
373 _e_object_segv(int sig)
374 {
375    siglongjmp(_e_object_segv_buf, 1);
376 }
377 #endif