add helper ecore_evas_object_associate.
authorbarbieri <barbieri@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Thu, 23 Oct 2008 01:00:16 +0000 (01:00 +0000)
committerbarbieri <barbieri@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Thu, 23 Oct 2008 01:00:16 +0000 (01:00 +0000)
We usually want to create an Ecore_Evas and attach an object to it, be
it the background, your smart object that will manage the scene (ie:
edje) and this is replicated everywhere. Not anymore!

ecore_evas_new() and ecore_evas_object_associate() will behave much
like regular toolkits "window-new()" and "window-main-child-add()",
actually it was based on elm_win.c and hopefully we can remove that,
or most of that code and replace with this helper.

I'll add an Evas smart object to handle stacks of objects, that is, it
will be a clipped smart object that on resize it will resize every
child to the same size. This means we can associate this stack object
and add a background and then your stuff on top of it.

git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/ecore@37010 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

src/lib/ecore_evas/Ecore_Evas.h
src/lib/ecore_evas/Makefile.am
src/lib/ecore_evas/ecore_evas.c
src/lib/ecore_evas/ecore_evas_private.h
src/lib/ecore_evas/ecore_evas_util.c [new file with mode: 0644]

index 60d64a1..e0a9e68 100644 (file)
@@ -92,6 +92,13 @@ typedef enum _Ecore_Evas_Avoid_Damage_Type
    ECORE_EVAS_AVOID_DAMAGE_BUILT_IN = 2
 } Ecore_Evas_Avoid_Damage_Type;
 
+typedef enum _Ecore_Evas_Object_Associate_Flags
+{
+  ECORE_EVAS_OBJECT_ASSOCIATE_BASE  = 0,
+  ECORE_EVAS_OBJECT_ASSOCIATE_STACK = 1 << 0,
+  ECORE_EVAS_OBJECT_ASSOCIATE_LAYER = 1 << 1
+} Ecore_Evas_Object_Associate_Flags;
+
 #ifndef _ECORE_X_H
 #define _ECORE_X_WINDOW_PREDEF
 typedef unsigned int Ecore_X_Window;
@@ -240,6 +247,7 @@ EAPI void        ecore_evas_callback_mouse_in_set(Ecore_Evas *ee, void (*func) (
 EAPI void        ecore_evas_callback_mouse_out_set(Ecore_Evas *ee, void (*func) (Ecore_Evas *ee));
 EAPI void        ecore_evas_callback_pre_render_set(Ecore_Evas *ee, void (*func) (Ecore_Evas *ee));
 EAPI void        ecore_evas_callback_post_render_set(Ecore_Evas *ee, void (*func) (Ecore_Evas *ee));
+EAPI void        ecore_evas_callback_pre_free_set(Ecore_Evas *ee, void (*func) (Ecore_Evas *ee));
 EAPI Evas       *ecore_evas_get(Ecore_Evas *ee);
 EAPI void        ecore_evas_move(Ecore_Evas *ee, int x, int y);
 EAPI void        ecore_evas_managed_move(Ecore_Evas *ee, int x, int y);
@@ -297,6 +305,10 @@ EAPI void        ecore_evas_ignore_events_set(Ecore_Evas *ee, int ignore);
 EAPI int         ecore_evas_ignore_events_get(Ecore_Evas *ee);
 EAPI void       *ecore_evas_window_get(Ecore_Evas *ee);
 
+
+  EAPI int         ecore_evas_object_associate(Ecore_Evas *ee, Evas_Object *obj, Ecore_Evas_Object_Associate_Flags flags);
+EAPI int         ecore_evas_object_dissociate(Ecore_Evas *ee, Evas_Object *obj);
+
 #ifdef __cplusplus
 }
 #endif
index 5443338..f46fb28 100644 (file)
@@ -82,6 +82,7 @@ Ecore_Evas.h
 
 libecore_evas_la_SOURCES = \
 ecore_evas.c \
+ecore_evas_util.c \
 ecore_evas_x.c \
 ecore_evas_fb.c \
 ecore_evas_buffer.c \
index a74b639..4a45aed 100644 (file)
@@ -1011,6 +1011,26 @@ ecore_evas_callback_post_render_set(Ecore_Evas *ee, void (*func) (Ecore_Evas *ee
 }
 
 /**
+ * Set a callback for Ecore_Evas pre-free event.
+ * @param ee The Ecore_Evas to set callbacks on
+ * @param func The function to call
+ *
+ * A call to this function will set a callback on an Ecore_Evas, causing
+ * @p func to be called just before the instance @p ee is freed.
+ */
+EAPI void
+ecore_evas_callback_pre_free_set(Ecore_Evas *ee, void (*func) (Ecore_Evas *ee))
+{
+   if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+     {
+       ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+                        "ecore_evas_callback_pre_free_set");
+       return;
+     }
+   ee->func.fn_pre_free = func;
+}
+
+/**
  * Get an Ecore_Evas's Evas
  * @param ee The Ecore_Evas whose Evas you wish to get
  * @return The Evas wrapped by @p ee
@@ -2361,6 +2381,7 @@ _ecore_evas_fps_debug_rendertime_add(double t)
 void
 _ecore_evas_free(Ecore_Evas *ee)
 {
+   if (ee->func.fn_pre_free) ee->func.fn_pre_free(ee);
    ECORE_MAGIC_SET(ee, ECORE_MAGIC_NONE);
    while (ee->sub_ecore_evas)
      {
index 64e8ca7..cc22212 100644 (file)
@@ -288,6 +288,7 @@ struct _Ecore_Evas
       void          (*fn_mouse_out) (Ecore_Evas *ee);
       void          (*fn_pre_render) (Ecore_Evas *ee);
       void          (*fn_post_render) (Ecore_Evas *ee);
+      void          (*fn_pre_free) (Ecore_Evas *ee);
    } func;
 
    Ecore_Evas_Engine engine;
diff --git a/src/lib/ecore_evas/ecore_evas_util.c b/src/lib/ecore_evas/ecore_evas_util.c
new file mode 100644 (file)
index 0000000..593ac6c
--- /dev/null
@@ -0,0 +1,413 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "Ecore.h"
+#include "ecore_private.h"
+#include "ecore_evas_private.h"
+#include "Ecore_Evas.h"
+
+
+static const char ASSOCIATE_KEY[] = "__Ecore_Evas_Associate";
+
+static void _ecore_evas_object_associate(Ecore_Evas *ee, Evas_Object *obj, Ecore_Evas_Object_Associate_Flags flags);
+static void _ecore_evas_object_dissociate(Ecore_Evas *ee, Evas_Object *obj);
+
+
+static Evas_Object *
+_ecore_evas_associate_get(Ecore_Evas *ee)
+{
+   return ecore_evas_data_get(ee, ASSOCIATE_KEY);
+}
+
+static void
+_ecore_evas_associate_set(Ecore_Evas *ee, Evas_Object *obj)
+{
+   ecore_evas_data_set(ee, ASSOCIATE_KEY, obj);
+}
+
+static void
+_ecore_evas_associate_del(Ecore_Evas *ee)
+{
+   ecore_evas_data_set(ee, ASSOCIATE_KEY, NULL);
+}
+
+static Ecore_Evas *
+_evas_object_associate_get(Evas_Object *obj)
+{
+   return evas_object_data_get(obj, ASSOCIATE_KEY);
+}
+
+static void
+_evas_object_associate_set(Evas_Object *obj, Ecore_Evas *ee)
+{
+   evas_object_data_set(obj, ASSOCIATE_KEY, ee);
+}
+
+static void
+_evas_object_associate_del(Evas_Object *obj)
+{
+   evas_object_data_del(obj, ASSOCIATE_KEY);
+}
+
+/** Associated Events: ******************************************************/
+
+/* Interceptors Callbacks */
+
+static void
+_ecore_evas_obj_intercept_move(void *data, Evas_Object *obj, Evas_Coord x, Evas_Coord y)
+{
+   Ecore_Evas *ee = data;
+   // FIXME: account for frame
+   ecore_evas_move(ee, x, y);
+}
+
+static void
+_ecore_evas_obj_intercept_raise(void *data, Evas_Object *obj)
+{
+   Ecore_Evas *ee = data;
+   ecore_evas_raise(ee);
+}
+
+static void
+_ecore_evas_obj_intercept_lower(void *data, Evas_Object *obj)
+{
+   Ecore_Evas *ee = data;
+   ecore_evas_lower(ee);
+}
+
+static void
+_ecore_evas_obj_intercept_stack_above(void *data, Evas_Object *obj, Evas_Object *above)
+{
+   fprintf(stderr, "TODO: %s\n", __FUNCTION__);
+}
+
+static void
+_ecore_evas_obj_intercept_stack_below(void *data, Evas_Object *obj, Evas_Object *below)
+{
+   fprintf(stderr, "TODO: %s\n", __FUNCTION__);
+}
+
+static void
+_ecore_evas_obj_intercept_layer_set(void *data, Evas_Object *obj, int l)
+{
+   Ecore_Evas *ee = data;
+   ecore_evas_layer_set(ee, l);
+}
+
+/* Event Callbacks */
+
+static void
+_ecore_evas_obj_callback_show(void *data, Evas *e, Evas_Object *obj, void *event_info)
+{
+   Ecore_Evas *ee = data;
+   ecore_evas_show(ee);
+}
+
+static void
+_ecore_evas_obj_callback_hide(void *data, Evas *e, Evas_Object *obj, void *event_info)
+{
+   Ecore_Evas *ee = data;
+   ecore_evas_hide(ee);
+}
+
+static void
+_ecore_evas_obj_callback_resize(void *data, Evas *e, Evas_Object *obj, void *event_info)
+{
+   Ecore_Evas *ee = data;
+   Evas_Coord ow, oh, w, h;
+
+   evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
+   ecore_evas_geometry_get(ee, NULL, NULL, &w, &h);
+   if ((w != ow) || (h != oh)) /* avoid recursion on ecore_evas_resize side */
+     ecore_evas_resize(ee, ow, oh);
+}
+
+static void
+_ecore_evas_obj_callback_changed_size_hints(void *data, Evas *e, Evas_Object *obj, void *event_info)
+{
+   Ecore_Evas *ee = data;
+   Evas_Coord w, h;
+
+   evas_object_size_hint_min_get(obj, &w, &h);
+   ecore_evas_size_min_set(ee, w, h);
+
+   evas_object_size_hint_max_get(obj, &w, &h);
+   if (w < 1) w = -1;
+   if (h < 1) h = -1;
+   ecore_evas_size_max_set(ee, w, h);
+}
+
+static void
+_ecore_evas_obj_callback_del(void *data, Evas *e, Evas_Object *obj, void *event_info)
+{
+   Ecore_Evas *ee = data;
+   _ecore_evas_object_dissociate(ee, obj);
+   ecore_evas_free(ee);
+}
+
+static void
+_ecore_evas_delete_request(Ecore_Evas *ee)
+{
+   Evas_Object *obj = _ecore_evas_associate_get(ee);
+   _ecore_evas_object_dissociate(ee, obj);
+   evas_object_del(obj);
+   ecore_evas_free(ee);
+}
+
+static void
+_ecore_evas_destroy(Ecore_Evas *ee)
+{
+   Evas_Object *obj = _ecore_evas_associate_get(ee);
+   if (!obj)
+     return;
+   _ecore_evas_object_dissociate(ee, obj);
+   evas_object_del(obj);
+}
+
+static void
+_ecore_evas_resize(Ecore_Evas *ee)
+{
+   Evas_Object *obj = _ecore_evas_associate_get(ee);
+   Evas_Coord w, h;
+   ecore_evas_geometry_get(ee, NULL, NULL, &w, &h);
+   evas_object_resize(obj, w, h);
+}
+
+static void
+_ecore_evas_pre_free(Ecore_Evas *ee)
+{
+   Evas_Object *obj = _ecore_evas_associate_get(ee);
+   if (!obj)
+     return;
+   _ecore_evas_object_dissociate(ee, obj);
+   evas_object_del(obj);
+}
+
+static int
+_ecore_evas_object_evas_check(const char *function, const Ecore_Evas *ee, const Evas_Object *obj)
+{
+   const char *name, *type;
+   Evas *e;
+
+   e = evas_object_evas_get(obj);
+   if (e == ee->evas)
+     return 1;
+
+   name = evas_object_name_get(obj);
+   type = evas_object_type_get(obj);
+
+   fprintf(stderr,
+          "ERROR: %s(): object %p (name=\"%s\", type=\"%s\") evas "
+          "is not the same as this Ecore_Evas evas: %p != %p\n",
+          function, obj,
+          name ? name : "", type ? type : "", e, ee->evas);
+   fflush(stderr);
+   if (getenv("ECORE_ERROR_ABORT")) abort();
+
+   return 0;
+}
+
+/**
+ * Associate the given object to this ecore evas.
+ *
+ * Association means that operations on one will affect the other, for
+ * example moving the object will move the window, resize the object will
+ * also affect the ecore evas window, hide and show applies as well.
+ *
+ * This is meant to simplify development, since you often need to associate
+ * these events with your "base" objects, background or bottom-most object.
+ *
+ * Be aware that some methods might not be what you would like, deleting
+ * either the window or the object will delete the other. If you want to
+ * change that behavior, let's say to hide window when it's closed, you
+ * must use ecore_evas_callback_delete_request_set() and set your own code,
+ * like ecore_evas_hide(). Just remember that if you override delete_request
+ * and still want to delete the window/object, you must do that yourself.
+ *
+ * Since we now define delete_request, deleting windows will not quit
+ * main loop, if you wish to do so, you should listen for EVAS_CALLBACK_FREE
+ * on the object, that way you get notified and you can call
+ * ecore_main_loop_quit().
+ *
+ * Flags can be OR'ed of:
+ *   - ECORE_EVAS_OBJECT_ASSOCIATE_BASE (or 0): to listen to basic events
+ *     like delete, resize and move, but no stacking or layer are used.
+ *   - ECORE_EVAS_OBJECT_ASSOCIATE_STACK: stacking operations will act
+ *     on the Ecore_Evas, not the object. So evas_object_raise() will
+ *     call ecore_evas_raise(). Relative operations (stack_above, stack_below)
+ *     are still not implemented.
+ *   - ECORE_EVAS_OBJECT_ASSOCIATE_LAYER: stacking operations will act
+ *     on the Ecore_Evas, not the object. So evas_object_layer_set() will
+ *     call ecore_evas_layer_set().
+ *
+ * @param ee The Ecore_Evas to associate to @a obj
+ * @param obj The object to associate to @a ee
+ * @return 1 on success, 0 otherwise.
+ */
+EAPI int
+ecore_evas_object_associate(Ecore_Evas *ee, Evas_Object *obj, Ecore_Evas_Object_Associate_Flags flags)
+{
+   Ecore_Evas *old_ee;
+   Evas_Object *old_obj;
+
+   if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+   {
+      ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, __FUNCTION__);
+      return 0;
+   }
+
+   CHECK_PARAM_POINTER_RETURN("obj", obj, 0);
+   if (!_ecore_evas_object_evas_check(__FUNCTION__, ee, obj))
+     return 0;
+
+   old_ee = _evas_object_associate_get(obj);;
+   if (old_ee)
+     ecore_evas_object_dissociate(old_ee, obj);
+
+   old_obj = _ecore_evas_associate_get(ee);
+   if (old_obj)
+     ecore_evas_object_dissociate(ee, old_obj);
+
+   _ecore_evas_object_associate(ee, obj, flags);
+   return 1;
+}
+
+/**
+ * Cancel the association set with ecore_evas_object_associate().
+ *
+ * @param ee The Ecore_Evas to dissociate from @a obj
+ * @param obj The object to dissociate from @a ee
+ * @return 1 on success, 0 otherwise.
+ */
+EAPI int
+ecore_evas_object_dissociate(Ecore_Evas *ee, Evas_Object *obj)
+{
+   Ecore_Evas *old_ee;
+   Evas_Object *old_obj;
+
+   if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+   {
+      ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, __FUNCTION__);
+      return 0;
+   }
+
+   CHECK_PARAM_POINTER_RETURN("obj", obj, 0);
+   old_ee = _evas_object_associate_get(obj);
+   if (ee != old_ee) {
+      fprintf(stderr, "ERROR: trying to dissociate object that is not using "
+             "this Ecore_Evas: %p != %p\n", ee, old_ee);
+      return 0;
+   }
+
+   old_obj = _ecore_evas_associate_get(ee);
+   if (old_obj != obj) {
+      fprintf(stderr, "ERROR: trying to dissociate object that is not being "
+             "used by this Ecore_Evas: %p != %p\n", old_obj, obj);
+      return 0;
+   }
+
+   _ecore_evas_object_dissociate(ee, obj);
+
+   return 1;
+}
+
+static void
+_ecore_evas_object_associate(Ecore_Evas *ee, Evas_Object *obj, Ecore_Evas_Object_Associate_Flags flags)
+{
+   evas_object_event_callback_add
+     (obj, EVAS_CALLBACK_SHOW,
+      _ecore_evas_obj_callback_show, ee);
+   evas_object_event_callback_add
+     (obj, EVAS_CALLBACK_HIDE,
+      _ecore_evas_obj_callback_hide, ee);
+   evas_object_event_callback_add
+     (obj, EVAS_CALLBACK_RESIZE,
+      _ecore_evas_obj_callback_resize, ee);
+   evas_object_event_callback_add
+     (obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
+      _ecore_evas_obj_callback_changed_size_hints, ee);
+   evas_object_event_callback_add
+     (obj, EVAS_CALLBACK_DEL, _ecore_evas_obj_callback_del, ee);
+
+   evas_object_intercept_move_callback_add
+     (obj, _ecore_evas_obj_intercept_move, ee);
+
+   if (flags & ECORE_EVAS_OBJECT_ASSOCIATE_STACK)
+   {
+      evas_object_intercept_raise_callback_add
+       (obj, _ecore_evas_obj_intercept_raise, ee);
+      evas_object_intercept_lower_callback_add
+       (obj, _ecore_evas_obj_intercept_lower, ee);
+      evas_object_intercept_stack_above_callback_add
+       (obj, _ecore_evas_obj_intercept_stack_above, ee);
+      evas_object_intercept_stack_below_callback_add
+       (obj, _ecore_evas_obj_intercept_stack_below, ee);
+   }
+
+   if (flags & ECORE_EVAS_OBJECT_ASSOCIATE_LAYER)
+     evas_object_intercept_layer_set_callback_add
+       (obj, _ecore_evas_obj_intercept_layer_set, ee);
+
+   ecore_evas_callback_delete_request_set(ee, _ecore_evas_delete_request);
+   ecore_evas_callback_destroy_set(ee, _ecore_evas_destroy);
+   ecore_evas_callback_resize_set(ee, _ecore_evas_resize);
+   ecore_evas_callback_pre_free_set(ee, _ecore_evas_pre_free);
+
+   _evas_object_associate_set(obj, ee);
+   _ecore_evas_associate_set(ee, obj);
+}
+
+static void
+_ecore_evas_object_dissociate(Ecore_Evas *ee, Evas_Object *obj)
+{
+   evas_object_event_callback_del_full
+     (obj, EVAS_CALLBACK_SHOW,
+      _ecore_evas_obj_callback_show, ee);
+   evas_object_event_callback_del_full
+     (obj, EVAS_CALLBACK_HIDE,
+      _ecore_evas_obj_callback_hide, ee);
+   evas_object_event_callback_del_full
+     (obj, EVAS_CALLBACK_RESIZE,
+      _ecore_evas_obj_callback_resize, ee);
+   evas_object_event_callback_del_full
+     (obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
+      _ecore_evas_obj_callback_changed_size_hints, ee);
+   evas_object_event_callback_del_full
+     (obj, EVAS_CALLBACK_DEL, _ecore_evas_obj_callback_del, ee);
+
+   evas_object_intercept_move_callback_del
+     (obj, _ecore_evas_obj_intercept_move);
+
+   evas_object_intercept_raise_callback_del
+     (obj, _ecore_evas_obj_intercept_raise);
+   evas_object_intercept_lower_callback_del
+     (obj, _ecore_evas_obj_intercept_lower);
+   evas_object_intercept_stack_above_callback_del
+     (obj, _ecore_evas_obj_intercept_stack_above);
+   evas_object_intercept_stack_below_callback_del
+     (obj, _ecore_evas_obj_intercept_stack_below);
+
+   evas_object_intercept_layer_set_callback_del
+     (obj, _ecore_evas_obj_intercept_layer_set);
+
+   if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+   {
+      ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, __FUNCTION__);
+   }
+   else
+   {
+      if (ee->func.fn_delete_request == _ecore_evas_delete_request)
+       ecore_evas_callback_delete_request_set(ee, NULL);
+      if (ee->func.fn_destroy == _ecore_evas_destroy)
+       ecore_evas_callback_destroy_set(ee, NULL);
+      if (ee->func.fn_resize == _ecore_evas_resize)
+       ecore_evas_callback_resize_set(ee, NULL);
+      if (ee->func.fn_pre_free == _ecore_evas_pre_free)
+       ecore_evas_callback_pre_free_set(ee, NULL);
+
+      _ecore_evas_associate_del(ee);
+   }
+
+   _evas_object_associate_del(obj);
+}