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