svn update: 48958 (latest:48959)
[framework/uifw/ecore.git] / src / lib / ecore_evas / ecore_evas_util.c
1 /*
2  * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
3  */
4
5 #ifdef HAVE_CONFIG_H
6 # include <config.h>
7 #endif
8
9 #include <string.h>
10
11 #include <Ecore.h>
12 #include "ecore_private.h"
13
14 #include "ecore_evas_private.h"
15 #include "Ecore_Evas.h"
16
17 static const char ASSOCIATE_KEY[] = "__Ecore_Evas_Associate";
18
19 static void _ecore_evas_object_associate(Ecore_Evas *ee, Evas_Object *obj, Ecore_Evas_Object_Associate_Flags flags);
20 static void _ecore_evas_object_dissociate(Ecore_Evas *ee, Evas_Object *obj);
21
22
23 static Evas_Object *
24 _ecore_evas_associate_get(const Ecore_Evas *ee)
25 {
26    return ecore_evas_data_get(ee, ASSOCIATE_KEY);
27 }
28
29 static void
30 _ecore_evas_associate_set(Ecore_Evas *ee, Evas_Object *obj)
31 {
32    ecore_evas_data_set(ee, ASSOCIATE_KEY, obj);
33 }
34
35 static void
36 _ecore_evas_associate_del(Ecore_Evas *ee)
37 {
38    ecore_evas_data_set(ee, ASSOCIATE_KEY, NULL);
39 }
40
41 static Ecore_Evas *
42 _evas_object_associate_get(const Evas_Object *obj)
43 {
44    return evas_object_data_get(obj, ASSOCIATE_KEY);
45 }
46
47 static void
48 _evas_object_associate_set(Evas_Object *obj, Ecore_Evas *ee)
49 {
50    evas_object_data_set(obj, ASSOCIATE_KEY, ee);
51 }
52
53 static void
54 _evas_object_associate_del(Evas_Object *obj)
55 {
56    evas_object_data_del(obj, ASSOCIATE_KEY);
57 }
58
59 /** Associated Events: ******************************************************/
60
61 /* Interceptors Callbacks */
62
63 static void
64 _ecore_evas_obj_intercept_move(void *data, Evas_Object *obj __UNUSED__, Evas_Coord x, Evas_Coord y)
65 {
66    Ecore_Evas *ee = data;
67    // FIXME: account for frame
68    ecore_evas_move(ee, x, y);
69 }
70
71 static void
72 _ecore_evas_obj_intercept_raise(void *data, Evas_Object *obj __UNUSED__)
73 {
74    Ecore_Evas *ee = data;
75    ecore_evas_raise(ee);
76 }
77
78 static void
79 _ecore_evas_obj_intercept_lower(void *data, Evas_Object *obj __UNUSED__)
80 {
81    Ecore_Evas *ee = data;
82    ecore_evas_lower(ee);
83 }
84
85 static void
86 _ecore_evas_obj_intercept_stack_above(void *data __UNUSED__, Evas_Object *obj __UNUSED__, Evas_Object *above __UNUSED__)
87 {
88    INF("TODO: %s", __FUNCTION__);
89 }
90
91 static void
92 _ecore_evas_obj_intercept_stack_below(void *data __UNUSED__, Evas_Object *obj __UNUSED__, Evas_Object *below __UNUSED__)
93 {
94    INF("TODO: %s", __FUNCTION__);
95 }
96
97 static void
98 _ecore_evas_obj_intercept_layer_set(void *data, Evas_Object *obj __UNUSED__, int l)
99 {
100    Ecore_Evas *ee = data;
101    ecore_evas_layer_set(ee, l);
102 }
103
104 /* Event Callbacks */
105
106 static void
107 _ecore_evas_obj_callback_show(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
108 {
109    Ecore_Evas *ee = data;
110    ecore_evas_show(ee);
111 }
112
113 static void
114 _ecore_evas_obj_callback_hide(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
115 {
116    Ecore_Evas *ee = data;
117    ecore_evas_hide(ee);
118 }
119
120 static void
121 _ecore_evas_obj_callback_resize(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
122 {
123    Ecore_Evas *ee = data;
124    Evas_Coord ow, oh, w, h;
125
126    evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
127    ecore_evas_geometry_get(ee, NULL, NULL, &w, &h);
128    if ((w != ow) || (h != oh)) /* avoid recursion on ecore_evas_resize side */
129      ecore_evas_resize(ee, ow, oh);
130 }
131
132 static void
133 _ecore_evas_obj_callback_changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
134 {
135    Ecore_Evas *ee = data;
136    Evas_Coord w, h;
137
138    evas_object_size_hint_min_get(obj, &w, &h);
139    ecore_evas_size_min_set(ee, w, h);
140
141    evas_object_size_hint_max_get(obj, &w, &h);
142    if (w < 1) w = -1;
143    if (h < 1) h = -1;
144    ecore_evas_size_max_set(ee, w, h);
145 }
146
147 static void
148 _ecore_evas_obj_callback_del(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
149 {
150    Ecore_Evas *ee = data;
151    _ecore_evas_object_dissociate(ee, obj);
152    ecore_evas_free(ee);
153 }
154
155 static void
156 _ecore_evas_obj_callback_del_dissociate(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
157 {
158    Ecore_Evas *ee = data;
159    _ecore_evas_object_dissociate(ee, obj);
160 }
161
162 static void
163 _ecore_evas_delete_request(Ecore_Evas *ee)
164 {
165    Evas_Object *obj = _ecore_evas_associate_get(ee);
166    _ecore_evas_object_dissociate(ee, obj);
167    evas_object_del(obj);
168    ecore_evas_free(ee);
169 }
170
171 static void
172 _ecore_evas_destroy(Ecore_Evas *ee)
173 {
174    Evas_Object *obj = _ecore_evas_associate_get(ee);
175    if (!obj)
176      return;
177    _ecore_evas_object_dissociate(ee, obj);
178    evas_object_del(obj);
179 }
180
181 static void
182 _ecore_evas_resize(Ecore_Evas *ee)
183 {
184    Evas_Object *obj = _ecore_evas_associate_get(ee);
185    Evas_Coord w, h;
186    ecore_evas_geometry_get(ee, NULL, NULL, &w, &h);
187    evas_object_resize(obj, w, h);
188 }
189
190 static void
191 _ecore_evas_pre_free(Ecore_Evas *ee)
192 {
193    Evas_Object *obj = _ecore_evas_associate_get(ee);
194    if (!obj)
195      return;
196    _ecore_evas_object_dissociate(ee, obj);
197    evas_object_del(obj);
198 }
199
200 static int
201 _ecore_evas_object_evas_check(const char *function, const Ecore_Evas *ee, const Evas_Object *obj)
202 {
203    const char *name, *type;
204    Evas *e;
205
206    e = evas_object_evas_get(obj);
207    if (e == ee->evas)
208      return 1;
209
210    name = evas_object_name_get(obj);
211    type = evas_object_type_get(obj);
212
213    ERR("ERROR: %s(): object %p (name=\"%s\", type=\"%s\") evas "
214        "is not the same as this Ecore_Evas evas: %p != %p",
215        function, obj,
216        name ? name : "", type ? type : "", e, ee->evas);
217    fflush(stderr);
218    if (getenv("ECORE_ERROR_ABORT")) abort();
219
220    return 0;
221 }
222
223 /**
224  * Associate the given object to this ecore evas.
225  *
226  * Association means that operations on one will affect the other, for
227  * example moving the object will move the window, resize the object will
228  * also affect the ecore evas window, hide and show applies as well.
229  *
230  * This is meant to simplify development, since you often need to associate
231  * these events with your "base" objects, background or bottom-most object.
232  *
233  * Be aware that some methods might not be what you would like, deleting
234  * either the window or the object will delete the other. If you want to
235  * change that behavior, let's say to hide window when it's closed, you
236  * must use ecore_evas_callback_delete_request_set() and set your own code,
237  * like ecore_evas_hide(). Just remember that if you override delete_request
238  * and still want to delete the window/object, you must do that yourself.
239  *
240  * Since we now define delete_request, deleting windows will not quit
241  * main loop, if you wish to do so, you should listen for EVAS_CALLBACK_FREE
242  * on the object, that way you get notified and you can call
243  * ecore_main_loop_quit().
244  *
245  * Flags can be OR'ed of:
246  *   - ECORE_EVAS_OBJECT_ASSOCIATE_BASE (or 0): to listen to basic events
247  *     like delete, resize and move, but no stacking or layer are used.
248  *   - ECORE_EVAS_OBJECT_ASSOCIATE_STACK: stacking operations will act
249  *     on the Ecore_Evas, not the object. So evas_object_raise() will
250  *     call ecore_evas_raise(). Relative operations (stack_above, stack_below)
251  *     are still not implemented.
252  *   - ECORE_EVAS_OBJECT_ASSOCIATE_LAYER: stacking operations will act
253  *     on the Ecore_Evas, not the object. So evas_object_layer_set() will
254  *     call ecore_evas_layer_set().
255  *   - ECORE_EVAS_OBJECT_ASSOCIATE_DEL: the object delete will delete the
256  *     ecore_evas as well as delete_requests on the ecore_evas will delete
257  *     etc.
258  *
259  * @param ee The Ecore_Evas to associate to @a obj
260  * @param obj The object to associate to @a ee
261  * @param flags The association flags.
262  * @return 1 on success, 0 otherwise.
263  */
264 EAPI int
265 ecore_evas_object_associate(Ecore_Evas *ee, Evas_Object *obj, Ecore_Evas_Object_Associate_Flags flags)
266 {
267    Ecore_Evas *old_ee;
268    Evas_Object *old_obj;
269
270    if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
271    {
272       ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, __FUNCTION__);
273       return 0;
274    }
275
276    CHECK_PARAM_POINTER_RETURN("obj", obj, 0);
277    if (!_ecore_evas_object_evas_check(__FUNCTION__, ee, obj))
278      return 0;
279
280    old_ee = _evas_object_associate_get(obj);;
281    if (old_ee)
282      ecore_evas_object_dissociate(old_ee, obj);
283
284    old_obj = _ecore_evas_associate_get(ee);
285    if (old_obj)
286      ecore_evas_object_dissociate(ee, old_obj);
287
288    _ecore_evas_object_associate(ee, obj, flags);
289    return 1;
290 }
291
292 /**
293  * Cancel the association set with ecore_evas_object_associate().
294  *
295  * @param ee The Ecore_Evas to dissociate from @a obj
296  * @param obj The object to dissociate from @a ee
297  * @return 1 on success, 0 otherwise.
298  */
299 EAPI int
300 ecore_evas_object_dissociate(Ecore_Evas *ee, Evas_Object *obj)
301 {
302    Ecore_Evas *old_ee;
303    Evas_Object *old_obj;
304
305    if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
306    {
307       ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, __FUNCTION__);
308       return 0;
309    }
310
311    CHECK_PARAM_POINTER_RETURN("obj", obj, 0);
312    old_ee = _evas_object_associate_get(obj);
313    if (ee != old_ee) {
314       ERR("ERROR: trying to dissociate object that is not using "
315           "this Ecore_Evas: %p != %p", ee, old_ee);
316       return 0;
317    }
318
319    old_obj = _ecore_evas_associate_get(ee);
320    if (old_obj != obj) {
321       ERR("ERROR: trying to dissociate object that is not being "
322           "used by this Ecore_Evas: %p != %p", old_obj, obj);
323       return 0;
324    }
325
326    _ecore_evas_object_dissociate(ee, obj);
327
328    return 1;
329 }
330
331 EAPI Evas_Object *
332 ecore_evas_object_associate_get(const Ecore_Evas *ee)
333 {
334    if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
335    {
336       ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, __FUNCTION__);
337       return NULL;
338    }
339    return _ecore_evas_associate_get(ee);
340 }
341
342 static void
343 _ecore_evas_object_associate(Ecore_Evas *ee, Evas_Object *obj, Ecore_Evas_Object_Associate_Flags flags)
344 {
345    evas_object_event_callback_add
346      (obj, EVAS_CALLBACK_SHOW,
347       _ecore_evas_obj_callback_show, ee);
348    evas_object_event_callback_add
349      (obj, EVAS_CALLBACK_HIDE,
350       _ecore_evas_obj_callback_hide, ee);
351    evas_object_event_callback_add
352      (obj, EVAS_CALLBACK_RESIZE,
353       _ecore_evas_obj_callback_resize, ee);
354    evas_object_event_callback_add
355      (obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
356       _ecore_evas_obj_callback_changed_size_hints, ee);
357    if (flags & ECORE_EVAS_OBJECT_ASSOCIATE_DEL)
358      evas_object_event_callback_add
359        (obj, EVAS_CALLBACK_DEL, _ecore_evas_obj_callback_del, ee);
360    else
361      evas_object_event_callback_add
362        (obj, EVAS_CALLBACK_DEL, _ecore_evas_obj_callback_del_dissociate, ee);
363
364    evas_object_intercept_move_callback_add
365      (obj, _ecore_evas_obj_intercept_move, ee);
366
367    if (flags & ECORE_EVAS_OBJECT_ASSOCIATE_STACK)
368      {
369         evas_object_intercept_raise_callback_add
370           (obj, _ecore_evas_obj_intercept_raise, ee);
371         evas_object_intercept_lower_callback_add
372           (obj, _ecore_evas_obj_intercept_lower, ee);
373         evas_object_intercept_stack_above_callback_add
374           (obj, _ecore_evas_obj_intercept_stack_above, ee);
375         evas_object_intercept_stack_below_callback_add
376           (obj, _ecore_evas_obj_intercept_stack_below, ee);
377      }
378
379    if (flags & ECORE_EVAS_OBJECT_ASSOCIATE_LAYER)
380      evas_object_intercept_layer_set_callback_add
381        (obj, _ecore_evas_obj_intercept_layer_set, ee);
382
383    if (flags & ECORE_EVAS_OBJECT_ASSOCIATE_DEL)
384      {
385         ecore_evas_callback_delete_request_set(ee, _ecore_evas_delete_request);
386         ecore_evas_callback_destroy_set(ee, _ecore_evas_destroy);
387      }
388    ecore_evas_callback_pre_free_set(ee, _ecore_evas_pre_free);
389    ecore_evas_callback_resize_set(ee, _ecore_evas_resize);
390
391    _evas_object_associate_set(obj, ee);
392    _ecore_evas_associate_set(ee, obj);
393 }
394
395 static void
396 _ecore_evas_object_dissociate(Ecore_Evas *ee, Evas_Object *obj)
397 {
398    evas_object_event_callback_del_full
399      (obj, EVAS_CALLBACK_SHOW,
400       _ecore_evas_obj_callback_show, ee);
401    evas_object_event_callback_del_full
402      (obj, EVAS_CALLBACK_HIDE,
403       _ecore_evas_obj_callback_hide, ee);
404    evas_object_event_callback_del_full
405      (obj, EVAS_CALLBACK_RESIZE,
406       _ecore_evas_obj_callback_resize, ee);
407    evas_object_event_callback_del_full
408      (obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
409       _ecore_evas_obj_callback_changed_size_hints, ee);
410    evas_object_event_callback_del_full
411      (obj, EVAS_CALLBACK_DEL, _ecore_evas_obj_callback_del, ee);
412    evas_object_event_callback_del_full
413      (obj, EVAS_CALLBACK_DEL, _ecore_evas_obj_callback_del_dissociate, ee);
414
415    evas_object_intercept_move_callback_del
416      (obj, _ecore_evas_obj_intercept_move);
417
418    evas_object_intercept_raise_callback_del
419      (obj, _ecore_evas_obj_intercept_raise);
420    evas_object_intercept_lower_callback_del
421      (obj, _ecore_evas_obj_intercept_lower);
422    evas_object_intercept_stack_above_callback_del
423      (obj, _ecore_evas_obj_intercept_stack_above);
424    evas_object_intercept_stack_below_callback_del
425      (obj, _ecore_evas_obj_intercept_stack_below);
426
427    evas_object_intercept_layer_set_callback_del
428      (obj, _ecore_evas_obj_intercept_layer_set);
429
430    if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
431    {
432       ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, __FUNCTION__);
433    }
434    else
435    {
436       if (ee->func.fn_delete_request == _ecore_evas_delete_request)
437         ecore_evas_callback_delete_request_set(ee, NULL);
438       if (ee->func.fn_destroy == _ecore_evas_destroy)
439         ecore_evas_callback_destroy_set(ee, NULL);
440       if (ee->func.fn_resize == _ecore_evas_resize)
441         ecore_evas_callback_resize_set(ee, NULL);
442       if (ee->func.fn_pre_free == _ecore_evas_pre_free)
443         ecore_evas_callback_pre_free_set(ee, NULL);
444
445       _ecore_evas_associate_del(ee);
446    }
447
448    _evas_object_associate_del(obj);
449 }
450
451 /**
452  * Helper ecore_getopt callback to list available Ecore_Evas engines.
453  *
454  * This will list all available engines except buffer, this is useful
455  * for applications to let user choose how they should create windows
456  * with ecore_evas_new().
457  *
458  * @c callback_data value is used as @c FILE* and says where to output
459  * messages, by default it is @c stdout. You can specify this value
460  * with ECORE_GETOPT_CALLBACK_FULL() or ECORE_GETOPT_CALLBACK_ARGS().
461  *
462  * If there is a boolean storage provided, then it is marked with 1
463  * when this option is executed.
464  */
465 unsigned char
466 ecore_getopt_callback_ecore_evas_list_engines(const Ecore_Getopt *parser __UNUSED__, const Ecore_Getopt_Desc *desc __UNUSED__, const char *str __UNUSED__, void *data, Ecore_Getopt_Value *storage)
467 {
468    Eina_List  *lst, *n;
469    const char *engine;
470    FILE *fp = data;
471
472    if (!fp)
473      fp = stdout;
474
475    lst = ecore_evas_engines_get();
476
477    fputs("supported engines:\n", fp);
478    EINA_LIST_FOREACH(lst, n, engine)
479      if (strcmp(engine, "buffer") != 0)
480        fprintf(fp, "\t%s\n", engine);
481
482    ecore_evas_engines_free(lst);
483
484    if (storage->boolp)
485      *storage->boolp = 1;
486
487    return 1;
488 }